From 35dd9874bf6138ab290c7f58020fcdc88f508805 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:16 -0400 Subject: [PATCH 01/73] drm/nouveau: Clean up nv50_head_atomic_check_mode() and fix blankus calculation drm_mode_set_crtcinfo() does compensation for interlace and doublescan timing effects already, so do it first and use the compensated figures instead of the constant "vscan / ilace" terms that we had before. And then it turns out that the hardware model for how the timing parameters are configured is basically the standard model, but starting one clock before the sync pulse rather than at the start of the display area, which lets us drastically simplify the overall timing calculations (verifying the changes by algebraic operations is left as an exercise for the reader). Finally, there were a couple of issues with the computation of m->v.blankus that are addressed here. Interlaced modes would generate a negative intermediate result. Double scan modes would generate an overestimate rather than an underestimate. And when enabling frame-packing modes, a rather extreme overestimate would be generated. Fixed, by using the timings as adjusted for the CRTC to find the length of the vertical blanking period instead of mixing adjusted and pre-adjustment timing parameters. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 44 ++++++++++++++------------ 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 775c10015dbe..83eee1f00336 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2036,34 +2036,37 @@ static void nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { struct drm_display_mode *mode = &asyh->state.adjusted_mode; - u32 ilace = (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 2 : 1; - u32 vscan = (mode->flags & DRM_MODE_FLAG_DBLSCAN) ? 2 : 1; - u32 hbackp = mode->htotal - mode->hsync_end; - u32 vbackp = (mode->vtotal - mode->vsync_end) * vscan / ilace; - u32 hfrontp = mode->hsync_start - mode->hdisplay; - u32 vfrontp = (mode->vsync_start - mode->vdisplay) * vscan / ilace; - u32 blankus; struct nv50_head_mode *m = &asyh->mode; + u32 blankus; - m->h.active = mode->htotal; - m->h.synce = mode->hsync_end - mode->hsync_start - 1; - m->h.blanke = m->h.synce + hbackp; - m->h.blanks = mode->htotal - hfrontp - 1; + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); - m->v.active = mode->vtotal * vscan / ilace; - m->v.synce = ((mode->vsync_end - mode->vsync_start) * vscan / ilace) - 1; - m->v.blanke = m->v.synce + vbackp; - m->v.blanks = m->v.active - vfrontp - 1; + /* + * DRM modes are defined in terms of a repeating interval + * starting with the active display area. The hardware modes + * are defined in terms of a repeating interval starting one + * unit (pixel or line) into the sync pulse. So, add bias. + */ + + m->h.active = mode->crtc_htotal; + m->h.synce = mode->crtc_hsync_end - mode->crtc_hsync_start - 1; + m->h.blanke = mode->crtc_hblank_end - mode->crtc_hsync_start - 1; + m->h.blanks = m->h.blanke + mode->crtc_hdisplay; + + m->v.active = mode->crtc_vtotal; + m->v.synce = mode->crtc_vsync_end - mode->crtc_vsync_start - 1; + m->v.blanke = mode->crtc_vblank_end - mode->crtc_vsync_start - 1; + m->v.blanks = m->v.blanke + mode->crtc_vdisplay; /*XXX: Safe underestimate, even "0" works */ - blankus = (m->v.active - mode->vdisplay - 2) * m->h.active; + blankus = (m->v.active - mode->crtc_vdisplay - 2) * m->h.active; blankus *= 1000; - blankus /= mode->clock; + blankus /= mode->crtc_clock; m->v.blankus = blankus; if (mode->flags & DRM_MODE_FLAG_INTERLACE) { - m->v.blank2e = m->v.active + m->v.synce + vbackp; - m->v.blank2s = m->v.blank2e + (mode->vdisplay * vscan / ilace); + m->v.blank2e = m->v.active + m->v.blanke; + m->v.blank2s = m->v.blank2e + mode->crtc_vdisplay; m->v.active = (m->v.active * 2) + 1; m->interlace = true; } else { @@ -2071,9 +2074,8 @@ nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) m->v.blank2s = 1; m->interlace = false; } - m->clock = mode->clock; + m->clock = mode->crtc_clock; - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); asyh->set.mode = true; } From 31fe2c200262a512255340d6f9493d51e06a8207 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:17 -0400 Subject: [PATCH 02/73] drm/nouveau/disp/g84-: Extend NVKM HDMI power control method to set InfoFrames The nouveau driver, in the Linux 3.7 days, used to try and set the AVI InfoFrame based on the selected display mode. These days, it uses a fixed set of InfoFrames. Start to correct that, by providing a mechanism whereby InfoFrame data may be passed to the NVKM functions that do the actual configuration. At this point, only establish the new parameters and their parsing, don't actually use the data anywhere yet (since it's not supplied anywhere). Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 4 +++- drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c | 9 ++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c | 9 ++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c | 9 ++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c | 9 ++++++++- 5 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index ae49dfd1f97b..9d46ebac58a2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -76,7 +76,9 @@ struct nv50_disp_sor_hdmi_pwr_v0 { __u8 state; __u8 max_ac_packet; __u8 rekey; - __u8 pad04[4]; + __u8 avi_infoframe_length; + __u8 vendor_infoframe_length; + __u8 pad06[2]; }; struct nv50_disp_sor_lvds_script_v0 { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 1c4256e8cbd6..77e5f5a2f3fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -40,7 +40,7 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) int ret = -ENOSYS; nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, @@ -54,6 +54,13 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) } else return ret; + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) > size) + return -ENOSYS; + else if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) < size) + return -E2BIG; + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index 632f02da1382..66ee88356e4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -40,7 +40,7 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) int ret = -ENOSYS; nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, @@ -53,6 +53,13 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) } else return ret; + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) > size) + return -ENOSYS; + else if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) < size) + return -E2BIG; + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index 4e8067d511d7..3c8c26a44f56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -41,7 +41,7 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) int ret = -ENOSYS; nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, @@ -54,6 +54,13 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) } else return ret; + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) > size) + return -ENOSYS; + else if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) < size) + return -E2BIG; + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index f1afc16494b6..8ed00dbf9dc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -41,7 +41,7 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) int ret = -ENOSYS; nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " "max_ac_packet %d rekey %d\n", args->v0.version, args->v0.state, @@ -55,6 +55,13 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) } else return ret; + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) > size) + return -ENOSYS; + else if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) < size) + return -E2BIG; + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); From 34fd3e5d8c5f6bdcc2245084036680a4bfc23370 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:18 -0400 Subject: [PATCH 03/73] drm/nouveau: Pass mode-dependent AVI and Vendor HDMI InfoFrames to NVKM Now that we have mechanism by which to pass mode-dependent HDMI InfoFrames to the low-level hardware driver, it is incumbent upon us to do so. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nv50_display.c | 30 +++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 83eee1f00336..0f817a6b1650 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -23,6 +23,7 @@ */ #include +#include #include #include @@ -31,6 +32,7 @@ #include #include #include +#include #include #include @@ -2710,6 +2712,7 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) struct { struct nv50_disp_mthd_v1 base; struct nv50_disp_sor_hdmi_pwr_v0 pwr; + u8 infoframes[2 * 17]; /* two frames, up to 17 bytes each */ } args = { .base.version = 1, .base.method = NV50_DISP_MTHD_V1_SOR_HDMI_PWR, @@ -2721,17 +2724,42 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct drm_display_mode *mode) }; struct nouveau_connector *nv_connector; u32 max_ac_packet; + union hdmi_infoframe avi_frame; + union hdmi_infoframe vendor_frame; + int ret; + int size; nv_connector = nouveau_encoder_connector_get(nv_encoder); if (!drm_detect_hdmi_monitor(nv_connector->edid)) return; + ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, mode); + if (!ret) { + /* We have an AVI InfoFrame, populate it to the display */ + args.pwr.avi_infoframe_length + = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17); + } + + ret = drm_hdmi_vendor_infoframe_from_display_mode(&vendor_frame.vendor.hdmi, mode); + if (!ret) { + /* We have a Vendor InfoFrame, populate it to the display */ + args.pwr.vendor_infoframe_length + = hdmi_infoframe_pack(&vendor_frame, + args.infoframes + + args.pwr.avi_infoframe_length, + 17); + } + max_ac_packet = mode->htotal - mode->hdisplay; max_ac_packet -= args.pwr.rekey; max_ac_packet -= 18; /* constant from tegra */ args.pwr.max_ac_packet = max_ac_packet / 32; - nvif_mthd(disp->disp, 0, &args, sizeof(args)); + size = sizeof(args.base) + + sizeof(args.pwr) + + args.pwr.avi_infoframe_length + + args.pwr.vendor_infoframe_length; + nvif_mthd(disp->disp, 0, &args, size); nv50_audio_enable(encoder, mode); } From f60213c0ee93ffb89a64bad9a5db52e854530b1d Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:19 -0400 Subject: [PATCH 04/73] drm/nouveau/disp: Add mechanism to convert HDMI InfoFrames to hardware format HDMI InfoFrames are passed to NVKM as bags of bytes, but the hardware needs them to be packed into words. Rather than having four (or more) copies of the packing logic introduce a single copy now, in a central place. We currently need these for AVI and Vendor InfoFrames, but we may also expect to need them for Audio InfoFrames at some point. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 1 + .../nouveau/nvkm/engine/disp/hdmi_infoframe.c | 66 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 11 ++++ 3 files changed, 78 insertions(+) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index fa05d16ae948..65ae870f147e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -29,6 +29,7 @@ nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/hdagt215.o nvkm-y += nvkm/engine/disp/hdagf119.o +nvkm-y += nvkm/engine/disp/hdmi_infoframe.o nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o nvkm-y += nvkm/engine/disp/hdmigf119.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c new file mode 100644 index 000000000000..e04f2e8137d2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c @@ -0,0 +1,66 @@ +#include "nv50.h" + +void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame, + u8 *raw_frame, ssize_t len) +{ + u32 header = 0; + u32 subpack0_low = 0; + u32 subpack0_high = 0; + u32 subpack1_low = 0; + u32 subpack1_high = 0; + + switch (len) { + /* + * "When in doubt, use brute force." + * -- Ken Thompson. + */ + default: + /* + * We presume that no valid frame is longer than 17 + * octets, including header... And truncate to that + * if it's longer. + */ + case 17: + subpack1_high = (raw_frame[16] << 16); + case 16: + subpack1_high |= (raw_frame[15] << 8); + case 15: + subpack1_high |= raw_frame[14]; + case 14: + subpack1_low = (raw_frame[13] << 24); + case 13: + subpack1_low |= (raw_frame[12] << 16); + case 12: + subpack1_low |= (raw_frame[11] << 8); + case 11: + subpack1_low |= raw_frame[10]; + case 10: + subpack0_high = (raw_frame[9] << 16); + case 9: + subpack0_high |= (raw_frame[8] << 8); + case 8: + subpack0_high |= raw_frame[7]; + case 7: + subpack0_low = (raw_frame[6] << 24); + case 6: + subpack0_low |= (raw_frame[5] << 16); + case 5: + subpack0_low |= (raw_frame[4] << 8); + case 4: + subpack0_low |= raw_frame[3]; + case 3: + header = (raw_frame[2] << 16); + case 2: + header |= (raw_frame[1] << 8); + case 1: + header |= raw_frame[0]; + case 0: + break; + } + + packed_frame->header = header; + packed_frame->subpack0_low = subpack0_low; + packed_frame->subpack0_high = subpack0_high; + packed_frame->subpack1_low = subpack1_low; + packed_frame->subpack1_high = subpack1_high; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 1e1de6bfe85a..37ec2a1032ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -40,6 +40,17 @@ int nv50_dac_sense(NV50_DISP_MTHD_V1); int gt215_hda_eld(NV50_DISP_MTHD_V1); int gf119_hda_eld(NV50_DISP_MTHD_V1); +struct packed_hdmi_infoframe { + u32 header; + u32 subpack0_low; + u32 subpack0_high; + u32 subpack1_low; + u32 subpack1_high; +}; + +void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame, + u8 *raw_frame, ssize_t len); + int g84_hdmi_ctrl(NV50_DISP_MTHD_V1); int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); From a45f7908b3ac4691d9abba5fc480ba0f718db3ea Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:20 -0400 Subject: [PATCH 05/73] drm/nouveau/disp/g84-gt200: Use supplied HDMI InfoFrames Now that we have the InfoFrame data being provided, for the most part, program the hardware to use it. While we're here, and since the functionality will come in handy for supporting 3D stereoscopy, implement setting the Vendor ("generic"?) InfoFrame. Also don't enable any AVI or Vendor InfoFrame that is not provided, and disable the Vendor InfoFrame when disabling the output. Ignore the Audio InfoFrame: We don't supply it, and altering HDMI audio semantics (for better or worse) on this hardware is out of scope for me at this time. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 77e5f5a2f3fa..139344eb5b72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -36,6 +36,8 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; + struct packed_hdmi_infoframe avi_infoframe; + struct packed_hdmi_infoframe vendor_infoframe; u32 ctrl; int ret = -ENOSYS; @@ -61,8 +63,17 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) + args->v0.vendor_infoframe_length) < size) return -E2BIG; + pack_hdmi_infoframe(&avi_infoframe, + data, + args->v0.avi_infoframe_length); + + pack_hdmi_infoframe(&vendor_infoframe, + data + args->v0.avi_infoframe_length, + args->v0.vendor_infoframe_length); + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); return 0; @@ -70,12 +81,14 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) /* AVI InfoFrame */ nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); - nvkm_wr32(device, 0x616528 + hoff, 0x000d0282); - nvkm_wr32(device, 0x61652c + hoff, 0x0000006f); - nvkm_wr32(device, 0x616530 + hoff, 0x00000000); - nvkm_wr32(device, 0x616534 + hoff, 0x00000000); - nvkm_wr32(device, 0x616538 + hoff, 0x00000000); - nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); + if (args->v0.avi_infoframe_length) { + nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header); + nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low); + nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high); + nvkm_wr32(device, 0x616534 + hoff, avi_infoframe.subpack1_low); + nvkm_wr32(device, 0x616538 + hoff, avi_infoframe.subpack1_high); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); + } /* Audio InfoFrame */ nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); @@ -84,6 +97,18 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) nvkm_wr32(device, 0x616510 + hoff, 0x00000000); nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001); + /* Vendor InfoFrame */ + nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000); + if (args->v0.vendor_infoframe_length) { + nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header); + nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low); + nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high); + /* Is there a second (or up to fourth?) set of subpack registers here? */ + /* nvkm_wr32(device, 0x616550 + hoff, vendor_infoframe->subpack1_low); */ + /* nvkm_wr32(device, 0x616554 + hoff, vendor_infoframe->subpack1_high); */ + nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010001); + } + nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ From ba32836879c32b027adacf0bad4a5c62f22d2173 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:21 -0400 Subject: [PATCH 06/73] drm/nouveau/disp/gt215: Use supplied HDMI InfoFrames Now that we have the InfoFrame data being provided, for the most part, program the hardware to use it. While we're here, and since the functionality will come in handy for supporting 3D stereoscopy, implement setting the Vendor ("generic") InfoFrame. Also don't enable any AVI or Vendor InfoFrame that is not provided, and disable the Vendor InfoFrame when disabling the output. Ignore the Audio InfoFrame: We don't supply it, and altering HDMI audio semantics (for better or worse) on this hardware is out of scope for me at this time. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 37 ++++++++++++++++--- 1 file changed, 31 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index 8ed00dbf9dc1..257f7c72d566 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -37,6 +37,8 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; + struct packed_hdmi_infoframe avi_infoframe; + struct packed_hdmi_infoframe vendor_infoframe; u32 ctrl; int ret = -ENOSYS; @@ -62,8 +64,17 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) + args->v0.vendor_infoframe_length) < size) return -E2BIG; + pack_hdmi_infoframe(&avi_infoframe, + data, + args->v0.avi_infoframe_length); + + pack_hdmi_infoframe(&vendor_infoframe, + data + args->v0.avi_infoframe_length, + args->v0.vendor_infoframe_length); + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x61c53c + soff, 0x00000001, 0x00000000); nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); return 0; @@ -71,12 +82,14 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) /* AVI InfoFrame */ nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); - nvkm_wr32(device, 0x61c528 + soff, 0x000d0282); - nvkm_wr32(device, 0x61c52c + soff, 0x0000006f); - nvkm_wr32(device, 0x61c530 + soff, 0x00000000); - nvkm_wr32(device, 0x61c534 + soff, 0x00000000); - nvkm_wr32(device, 0x61c538 + soff, 0x00000000); - nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); + if (args->v0.avi_infoframe_length) { + nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header); + nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low); + nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high); + nvkm_wr32(device, 0x61c534 + soff, avi_infoframe.subpack1_low); + nvkm_wr32(device, 0x61c538 + soff, avi_infoframe.subpack1_high); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); + } /* Audio InfoFrame */ nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); @@ -85,6 +98,18 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) nvkm_wr32(device, 0x61c510 + soff, 0x00000000); nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001); + /* Vendor InfoFrame */ + nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000); + if (args->v0.vendor_infoframe_length) { + nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header); + nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low); + nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high); + /* Is there a second (or up to fourth?) set of subpack registers here? */ + /* nvkm_wr32(device, 0x61c550 + soff, vendor_infoframe.subpack1_low); */ + /* nvkm_wr32(device, 0x61c554 + soff, vendor_infoframe.subpack1_high); */ + nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010001); + } + nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ From 2709b275c5d7ad01ae08cad004587f479aa3ea95 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:22 -0400 Subject: [PATCH 07/73] drm/nouveau/disp/gf119: Use supplied HDMI InfoFrames Now that we have the InfoFrame data being provided, for the most part, program the hardware to use it. While we're here, and since the functionality will come in handy for supporting 3D stereoscopy, implement setting the Vendor ("generic"?) InfoFrame. Also don't enable any InfoFrame that is not provided, and disable the Vendor InfoFrame when disabling the output. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/hdmigf119.c | 40 ++++++++++++++++--- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index 66ee88356e4e..d80e86c12ee9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -36,6 +36,8 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; + struct packed_hdmi_infoframe avi_infoframe; + struct packed_hdmi_infoframe vendor_infoframe; u32 ctrl; int ret = -ENOSYS; @@ -60,8 +62,17 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) + args->v0.vendor_infoframe_length) < size) return -E2BIG; + pack_hdmi_infoframe(&avi_infoframe, + data, + args->v0.avi_infoframe_length); + + pack_hdmi_infoframe(&vendor_infoframe, + data + args->v0.avi_infoframe_length, + args->v0.vendor_infoframe_length); + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); return 0; @@ -69,12 +80,29 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) /* AVI InfoFrame */ nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); - nvkm_wr32(device, 0x61671c + hoff, 0x000d0282); - nvkm_wr32(device, 0x616720 + hoff, 0x0000006f); - nvkm_wr32(device, 0x616724 + hoff, 0x00000000); - nvkm_wr32(device, 0x616728 + hoff, 0x00000000); - nvkm_wr32(device, 0x61672c + hoff, 0x00000000); - nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); + if (args->v0.avi_infoframe_length) { + nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header); + nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low); + nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high); + nvkm_wr32(device, 0x616728 + hoff, avi_infoframe.subpack1_low); + nvkm_wr32(device, 0x61672c + hoff, avi_infoframe.subpack1_high); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); + } + + /* GENERIC(?) / Vendor InfoFrame? */ + nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000); + if (args->v0.vendor_infoframe_length) { + /* + * These appear to be the audio infoframe registers, + * but no other set of infoframe registers has yet + * been found. + */ + nvkm_wr32(device, 0x616738 + hoff, vendor_infoframe.header); + nvkm_wr32(device, 0x61673c + hoff, vendor_infoframe.subpack0_low); + nvkm_wr32(device, 0x616740 + hoff, vendor_infoframe.subpack0_high); + /* Is there a second (or further?) set of subpack registers here? */ + nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000001); + } /* ??? InfoFrame? */ nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); From a8970743502f6e52297fca4181ae524041119106 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:23 -0400 Subject: [PATCH 08/73] drm/nouveau/disp/gk104-: Use supplied HDMI InfoFrames Now that we have the InfoFrame data being provided, for the most part, program the hardware to use it. While we're here, and since the functionality will come in handy for supporting 3D stereoscopy, implement setting the Vendor ("generic"?) InfoFrame. Also don't enable any InfoFrame that is not provided, and disable the Vendor InfoFrame when disabling the output. Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index 3c8c26a44f56..99d27314b511 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -37,6 +37,8 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) union { struct nv50_disp_sor_hdmi_pwr_v0 v0; } *args = data; + struct packed_hdmi_infoframe avi_infoframe; + struct packed_hdmi_infoframe vendor_infoframe; u32 ctrl; int ret = -ENOSYS; @@ -61,8 +63,17 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) + args->v0.vendor_infoframe_length) < size) return -E2BIG; + pack_hdmi_infoframe(&avi_infoframe, + data, + args->v0.avi_infoframe_length); + + pack_hdmi_infoframe(&vendor_infoframe, + data + args->v0.avi_infoframe_length, + args->v0.vendor_infoframe_length); + if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000000); nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; @@ -70,12 +81,25 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) /* AVI InfoFrame */ nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); - nvkm_wr32(device, 0x690008 + hdmi, 0x000d0282); - nvkm_wr32(device, 0x69000c + hdmi, 0x0000006f); - nvkm_wr32(device, 0x690010 + hdmi, 0x00000000); - nvkm_wr32(device, 0x690014 + hdmi, 0x00000000); - nvkm_wr32(device, 0x690018 + hdmi, 0x00000000); - nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); + if (args->v0.avi_infoframe_length) { + nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header); + nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low); + nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high); + nvkm_wr32(device, 0x690014 + hdmi, avi_infoframe.subpack1_low); + nvkm_wr32(device, 0x690018 + hdmi, avi_infoframe.subpack1_high); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); + } + + /* GENERIC(?) / Vendor InfoFrame? */ + nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000); + if (args->v0.vendor_infoframe_length) { + nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header); + nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low); + nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high); + /* Is there a second (or further?) set of subpack registers here? */ + nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000001); + } + /* ??? InfoFrame? */ nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); From 37aa2243ff4985c0bdf309bf951f2cdd680fbe5c Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:24 -0400 Subject: [PATCH 09/73] drm/nouveau: Handle frame-packing mode geometry and timing effects Frame-packing modes add an extra vtotal raster lines to each frame above and beyond what the basic mode description calls for. Account for this during scaler configuration (possibly a bit of a hack), during CRTC configuration (clearly not a hack), and when checking that a mode is valid for a given connector (cribbed from the i915 driver). Signed-off-by: Alastair Bridgewater Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_connector.c | 3 +++ drivers/gpu/drm/nouveau/nv50_display.c | 21 ++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index f802bcd94457..9a91e79158be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1045,6 +1045,9 @@ nouveau_connector_mode_valid(struct drm_connector *connector, return MODE_BAD; } + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + clock *= 2; + if (clock < min_clock) return MODE_CLOCK_LOW; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 0f817a6b1650..36d0cf891eea 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1967,6 +1967,7 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh, struct drm_display_mode *umode = &asyh->state.mode; int mode = asyc->scaler.mode; struct edid *edid; + int umode_vdisplay, omode_hdisplay, omode_vdisplay; if (connector->edid_blob_ptr) edid = (struct edid *)connector->edid_blob_ptr->data; @@ -1981,12 +1982,18 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh, mode = DRM_MODE_SCALE_FULLSCREEN; } + /* For the user-specified mode, we must ignore doublescan and + * the like, but honor frame packing. + */ + umode_vdisplay = umode->vdisplay; + if ((umode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING) + umode_vdisplay += umode->vtotal; asyh->view.iW = umode->hdisplay; - asyh->view.iH = umode->vdisplay; - asyh->view.oW = omode->hdisplay; - asyh->view.oH = omode->vdisplay; - if (omode->flags & DRM_MODE_FLAG_DBLSCAN) - asyh->view.oH *= 2; + asyh->view.iH = umode_vdisplay; + /* For the output mode, we can just use the stock helper. */ + drm_mode_get_hv_timing(omode, &omode_hdisplay, &omode_vdisplay); + asyh->view.oW = omode_hdisplay; + asyh->view.oH = omode_vdisplay; /* Add overscan compensation if necessary, will keep the aspect * ratio the same as the backend mode unless overridden by the @@ -2016,7 +2023,7 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh, switch (mode) { case DRM_MODE_SCALE_CENTER: asyh->view.oW = min((u16)umode->hdisplay, asyh->view.oW); - asyh->view.oH = min((u16)umode->vdisplay, asyh->view.oH); + asyh->view.oH = min((u16)umode_vdisplay, asyh->view.oH); /* fall-through */ case DRM_MODE_SCALE_ASPECT: if (asyh->view.oH < asyh->view.oW) { @@ -2041,7 +2048,7 @@ nv50_head_atomic_check_mode(struct nv50_head *head, struct nv50_head_atom *asyh) struct nv50_head_mode *m = &asyh->mode; u32 blankus; - drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); + drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V | CRTC_STEREO_DOUBLE); /* * DRM modes are defined in terms of a repeating interval From 0f18d2765ab1ab9530e1b80dc1bc247c8b13cef7 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:25 -0400 Subject: [PATCH 10/73] drm/nouveau: Enable stereoscopic 3D output over HDMI Enable stereoscopic output for HDMI and DisplayPort connectors on NV50+ (G80+) hardware. We do not enable stereoscopy on older hardware in case there is some older board that still has HDMI output but for which we have no logic for setting the Vendor InfoFrame. With this, I get an obvious 3D output when using the "testdisplay" program from intel-gpu-tools with the "-3" parameter and outputting to a 3D-capable HDMI display, for all available 3D modes (be they TB, SBSH, or FP) on all four G80+ DISPs. Signed-off-by: Alastair Bridgewater --- drivers/gpu/drm/nouveau/nouveau_connector.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 9a91e79158be..147b22163f9f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1324,6 +1324,13 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } + /* HDMI 3D support */ + if ((disp->disp.oclass >= G82_DISP) + && ((type == DRM_MODE_CONNECTOR_DisplayPort) + || (type == DRM_MODE_CONNECTOR_eDP) + || (type == DRM_MODE_CONNECTOR_HDMIA))) + connector->stereo_allowed = true; + /* defaults, will get overridden in detect() */ connector->interlace_allowed = false; connector->doublescan_allowed = false; From c0cd04700f5c88145602b35c24e9128767a4ad69 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 23 Apr 2017 10:36:31 +0200 Subject: [PATCH 11/73] drm/nouveau/bios/volt: Parse min and max for Version 0x40 This is according to what we have in nvbios. Fixes "ERROR: Can't get value of subfeature in0_min: Can't read" errors in sensors for some GPUs. Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c index a7797a9e9cbc..7143ea4611aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c @@ -93,9 +93,9 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, info->step = nvbios_rd16(bios, volt + 0x08); info->vidmask = nvbios_rd08(bios, volt + 0x0b); info->ranged = true; /* XXX: find the flag byte */ - /*XXX*/ - info->min = 0; - info->max = info->base; + info->min = min(info->base, + info->base + info->step * info->vidmask); + info->max = nvbios_rd32(bios, volt + 0x0e); break; case 0x50: info->min = nvbios_rd32(bios, volt + 0x0a); From 4dc33b12229fc540dc69b0d4aced60672bab142d Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 23 Apr 2017 20:06:37 +0200 Subject: [PATCH 12/73] drm/nouveau/bios/iccsense: rails for power sensors have a mask of 0xf8 for version 0x10 I only saw those values inside the vbios: 0xff, 0xfd, 0xfc, 0xfa for valid rails. No idea what the lower value does, but at least we get power readings on a lot of Fermi GPUs with that. v2: add missing parentheses Signed-off-by: Karol Herbst Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c index 3953d11844ea..23caef8df17f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/iccsense.c @@ -87,7 +87,10 @@ nvbios_iccsense_parse(struct nvkm_bios *bios, struct nvbios_iccsense *iccsense) switch(ver) { case 0x10: - rail->mode = nvbios_rd08(bios, entry + 0x1); + if ((nvbios_rd08(bios, entry + 0x1) & 0xf8) == 0xf8) + rail->mode = 1; + else + rail->mode = 0; rail->extdev_id = nvbios_rd08(bios, entry + 0x2); res_start = 0x3; break; From 7eaf1198a9aaa9c31c9270e370088d8a79c149ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 11 May 2017 17:29:58 +1000 Subject: [PATCH 13/73] drm/nouveau/tmr: remove nvkm_timer_alarm_cancel() nvkm_timer_alarm() already handles this as part of protecting against callers passing in no timeout value. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c | 9 --------- 6 files changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index 820a4805916f..ff0709652f80 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -26,7 +26,6 @@ struct nvkm_timer { u64 nvkm_timer_read(struct nvkm_timer *); void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *); -void nvkm_timer_alarm_cancel(struct nvkm_timer *, struct nvkm_alarm *); /* Delay based on GPU time (ie. PTIMER). * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 9ca0db796cbe..978aae3c1001 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -158,7 +158,7 @@ static void gk20a_pmu_fini(struct nvkm_pmu *pmu) { struct gk20a_pmu *gpmu = gk20a_pmu(pmu); - nvkm_timer_alarm_cancel(pmu->subdev.device->timer, &gpmu->alarm); + nvkm_timer_alarm(pmu->subdev.device->timer, 0, &gpmu->alarm); nvkm_falcon_put(pmu->falcon, &pmu->subdev); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index be691a7b972f..952a7cb0a59a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -116,7 +116,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) switch (mode) { case NVKM_THERM_CTRL_MANUAL: - nvkm_timer_alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm(tmr, 0, &therm->alarm); duty = nvkm_therm_fan_get(therm); if (duty < 0) duty = 100; @@ -142,7 +142,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) break; case NVKM_THERM_CTRL_NONE: default: - nvkm_timer_alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm(tmr, 0, &therm->alarm); poll = false; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index e2feccec25f5..f8fa43c8a7d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -215,7 +215,7 @@ nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - nvkm_timer_alarm_cancel(tmr, &therm->fan->alarm); + nvkm_timer_alarm(tmr, 0, &therm->fan->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index 9a79e91fdfdc..e93b2410c38b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -220,7 +220,7 @@ nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - nvkm_timer_alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); + nvkm_timer_alarm(tmr, 0, &therm->sensor.therm_poll_alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index 2437f7d41ca2..36de23d12ae4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -105,15 +105,6 @@ nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm) spin_unlock_irqrestore(&tmr->lock, flags); } -void -nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm) -{ - unsigned long flags; - spin_lock_irqsave(&tmr->lock, flags); - list_del_init(&alarm->head); - spin_unlock_irqrestore(&tmr->lock, flags); -} - static void nvkm_timer_intr(struct nvkm_subdev *subdev) { From 4bb4a7466af6d96d4fc8471336eb738d13c2471c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 14/73] drm/nouveau/bios/init: rename nvbios_init() to nvbios_devinit() Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index 4dc1c8af840c..98aa9ece0dc5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -17,5 +17,5 @@ struct nvbios_init { }; int nvbios_exec(struct nvbios_init *); -int nvbios_init(struct nvkm_subdev *, bool execute); +int nvbios_post(struct nvkm_subdev *, bool execute); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 38ed09fd3d2f..1d5f29a5c07c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -2290,7 +2290,7 @@ nvbios_exec(struct nvbios_init *init) } int -nvbios_init(struct nvkm_subdev *subdev, bool execute) +nvbios_post(struct nvkm_subdev *subdev, bool execute) { struct nvkm_bios *bios = subdev->device->bios; int ret = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index c8d455346fcd..158977f8a6e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -393,7 +393,7 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) int nv04_devinit_post(struct nvkm_devinit *init, bool execute) { - return nvbios_init(&init->subdev, execute); + return nvbios_post(&init->subdev, execute); } void From 5b0e787ad599a8e6803daf743dfc4642018ba469 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 15/73] drm/nouveau/bios/init: remove internal use of nvbios_init.bios We already have a subdev pointer, from which we can locate the device's BIOS subdev. No need for a separate pointer. Structure/callers not updated yet, as I want to batch more changes and only touch the callers once. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 166 +++++++++--------- 1 file changed, 84 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 1d5f29a5c07c..1894b2490651 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -119,7 +119,7 @@ init_crtc(struct nvbios_init *init) static u8 init_conn(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; struct nvbios_connE connE; u8 ver, hdr; u32 conn; @@ -141,7 +141,7 @@ init_conn(struct nvbios_init *init) static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { - struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; + struct nvkm_devinit *devinit = init->subdev->device->devinit; /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO @@ -154,7 +154,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) /* GF8+ display scripts need register addresses mangled a bit to * select a specific CRTC/OR */ - if (init->bios->subdev.device->card_type >= NV_50) { + if (init->subdev->device->card_type >= NV_50) { if (reg & 0x80000000) { reg += init_crtc(init) * 0x800; reg &= ~0x80000000; @@ -179,7 +179,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) static u32 init_rd32(struct nvbios_init *init, u32 reg) { - struct nvkm_device *device = init->bios->subdev.device; + struct nvkm_device *device = init->subdev->device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) return nvkm_rd32(device, reg); @@ -189,7 +189,7 @@ init_rd32(struct nvbios_init *init, u32 reg) static void init_wr32(struct nvbios_init *init, u32 reg, u32 val) { - struct nvkm_device *device = init->bios->subdev.device; + struct nvkm_device *device = init->subdev->device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) nvkm_wr32(device, reg, val); @@ -198,7 +198,7 @@ init_wr32(struct nvbios_init *init, u32 reg, u32 val) static u32 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) { - struct nvkm_device *device = init->bios->subdev.device; + struct nvkm_device *device = init->subdev->device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) { u32 tmp = nvkm_rd32(device, reg); @@ -260,7 +260,7 @@ init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) static struct i2c_adapter * init_i2c(struct nvbios_init *init, int index) { - struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + struct nvkm_i2c *i2c = init->subdev->device->i2c; struct nvkm_i2c_bus *bus; if (index == 0xff) { @@ -300,7 +300,7 @@ init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) static struct nvkm_i2c_aux * init_aux(struct nvbios_init *init) { - struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + struct nvkm_i2c *i2c = init->subdev->device->i2c; if (!init->outp) { if (init_exec(init)) error("script needs output for aux\n"); @@ -341,7 +341,7 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) static void init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) { - struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; + struct nvkm_devinit *devinit = init->subdev->device->devinit; if (init_exec(init)) { int ret = nvkm_devinit_pll_set(devinit, id, freq); if (ret) @@ -374,7 +374,7 @@ init_table(struct nvkm_bios *bios, u16 *len) static u16 init_table_(struct nvbios_init *init, u16 offset, const char *name) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 len, data = init_table(bios, &len); if (data) { if (len >= offset + 2) { @@ -406,7 +406,7 @@ init_table_(struct nvbios_init *init, u16 offset, const char *name) static u16 init_script(struct nvkm_bios *bios, int index) { - struct nvbios_init init = { .bios = bios }; + struct nvbios_init init = { .subdev = &bios->subdev }; u16 bmp_ver = bmp_version(bios), data; if (bmp_ver && bmp_ver < 0x0510) { @@ -436,7 +436,7 @@ init_unknown_script(struct nvkm_bios *bios) static u8 init_ram_restrict_group_count(struct nvbios_init *init) { - return nvbios_ramcfg_count(init->bios); + return nvbios_ramcfg_count(init->subdev->device->bios); } static u8 @@ -450,7 +450,7 @@ init_ram_restrict(struct nvbios_init *init) * Preserving the non-caching behaviour on earlier chipsets just * in case *not* re-reading the strap causes similar breakage. */ - if (!init->ramcfg || init->bios->version.major < 0x70) + if (!init->ramcfg || init->subdev->device->bios->version.major < 0x70) init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev); return (init->ramcfg & 0x7fffffff); } @@ -458,7 +458,7 @@ init_ram_restrict(struct nvbios_init *init) static u8 init_xlat_(struct nvbios_init *init, u8 index, u8 offset) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 table = init_xlat_table(init); if (table) { u16 data = nvbios_rd16(bios, table + (index * 2)); @@ -476,7 +476,7 @@ init_xlat_(struct nvbios_init *init, u8 index, u8 offset) static bool init_condition_met(struct nvbios_init *init, u8 cond) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 table = init_condition_table(init); if (table) { u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0); @@ -492,7 +492,7 @@ init_condition_met(struct nvbios_init *init, u8 cond) static bool init_io_condition_met(struct nvbios_init *init, u8 cond) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 table = init_io_condition_table(init); if (table) { u16 port = nvbios_rd16(bios, table + (cond * 5) + 0); @@ -509,7 +509,7 @@ init_io_condition_met(struct nvbios_init *init, u8 cond) static bool init_io_flag_condition_met(struct nvbios_init *init, u8 cond) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 table = init_io_flag_condition_table(init); if (table) { u16 port = nvbios_rd16(bios, table + (cond * 9) + 0); @@ -580,7 +580,8 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds) static void init_reserved(struct nvbios_init *init) { - u8 opcode = nvbios_rd08(init->bios, init->offset); + struct nvkm_bios *bios = init->subdev->device->bios; + u8 opcode = nvbios_rd08(bios, init->offset); u8 length, i; switch (opcode) { @@ -594,7 +595,7 @@ init_reserved(struct nvbios_init *init) trace("RESERVED 0x%02x\t", opcode); for (i = 1; i < length; i++) - cont(" 0x%02x", nvbios_rd08(init->bios, init->offset + i)); + cont(" 0x%02x", nvbios_rd08(bios, init->offset + i)); cont("\n"); init->offset += length; } @@ -617,7 +618,7 @@ init_done(struct nvbios_init *init) static void init_io_restrict_prog(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 index = nvbios_rd08(bios, init->offset + 3); u8 mask = nvbios_rd08(bios, init->offset + 4); @@ -654,7 +655,7 @@ init_io_restrict_prog(struct nvbios_init *init) static void init_repeat(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 count = nvbios_rd08(bios, init->offset + 1); u16 repeat = init->repeat; @@ -680,7 +681,7 @@ init_repeat(struct nvbios_init *init) static void init_io_restrict_pll(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 index = nvbios_rd08(bios, init->offset + 3); u8 mask = nvbios_rd08(bios, init->offset + 4); @@ -736,7 +737,7 @@ init_end_repeat(struct nvbios_init *init) static void init_copy(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u8 shift = nvbios_rd08(bios, init->offset + 5); u8 smask = nvbios_rd08(bios, init->offset + 6); @@ -775,7 +776,7 @@ init_not(struct nvbios_init *init) static void init_io_flag_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_FLAG_CONDITION\t0x%02x\n", cond); @@ -792,7 +793,7 @@ init_io_flag_condition(struct nvbios_init *init) static void init_generic_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; struct nvbios_dpout info; u8 cond = nvbios_rd08(bios, init->offset + 1); u8 size = nvbios_rd08(bios, init->offset + 2); @@ -841,7 +842,7 @@ init_generic_condition(struct nvbios_init *init) static void init_io_mask_or(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -860,7 +861,7 @@ init_io_mask_or(struct nvbios_init *init) static void init_io_or(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -879,7 +880,7 @@ init_io_or(struct nvbios_init *init) static void init_andn_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 mask = nvbios_rd32(bios, init->offset + 5); @@ -896,7 +897,7 @@ init_andn_reg(struct nvbios_init *init) static void init_or_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 mask = nvbios_rd32(bios, init->offset + 5); @@ -913,7 +914,7 @@ init_or_reg(struct nvbios_init *init) static void init_idx_addr_latched(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 creg = nvbios_rd32(bios, init->offset + 1); u32 dreg = nvbios_rd32(bios, init->offset + 5); u32 mask = nvbios_rd32(bios, init->offset + 9); @@ -943,7 +944,7 @@ init_idx_addr_latched(struct nvbios_init *init) static void init_io_restrict_pll2(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 index = nvbios_rd08(bios, init->offset + 3); u8 mask = nvbios_rd08(bios, init->offset + 4); @@ -978,7 +979,7 @@ init_io_restrict_pll2(struct nvbios_init *init) static void init_pll2(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 freq = nvbios_rd32(bios, init->offset + 5); @@ -995,7 +996,7 @@ init_pll2(struct nvbios_init *init) static void init_i2c_byte(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; u8 count = nvbios_rd08(bios, init->offset + 3); @@ -1026,7 +1027,7 @@ init_i2c_byte(struct nvbios_init *init) static void init_zm_i2c_byte(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; u8 count = nvbios_rd08(bios, init->offset + 3); @@ -1052,7 +1053,7 @@ init_zm_i2c_byte(struct nvbios_init *init) static void init_zm_i2c(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; u8 count = nvbios_rd08(bios, init->offset + 3); @@ -1086,7 +1087,7 @@ init_zm_i2c(struct nvbios_init *init) static void init_tmds(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 tmds = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2); u8 mask = nvbios_rd08(bios, init->offset + 3); @@ -1112,7 +1113,7 @@ init_tmds(struct nvbios_init *init) static void init_zm_tmds_group(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 tmds = nvbios_rd08(bios, init->offset + 1); u8 count = nvbios_rd08(bios, init->offset + 2); u32 reg = init_tmds_reg(init, tmds); @@ -1139,7 +1140,7 @@ init_zm_tmds_group(struct nvbios_init *init) static void init_cr_idx_adr_latch(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 addr0 = nvbios_rd08(bios, init->offset + 1); u8 addr1 = nvbios_rd08(bios, init->offset + 2); u8 base = nvbios_rd08(bios, init->offset + 3); @@ -1169,7 +1170,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init) static void init_cr(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 addr = nvbios_rd08(bios, init->offset + 1); u8 mask = nvbios_rd08(bios, init->offset + 2); u8 data = nvbios_rd08(bios, init->offset + 3); @@ -1189,7 +1190,7 @@ init_cr(struct nvbios_init *init) static void init_zm_cr(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 addr = nvbios_rd08(bios, init->offset + 1); u8 data = nvbios_rd08(bios, init->offset + 2); @@ -1206,7 +1207,7 @@ init_zm_cr(struct nvbios_init *init) static void init_zm_cr_group(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 count = nvbios_rd08(bios, init->offset + 1); trace("ZM_CR_GROUP\n"); @@ -1230,7 +1231,7 @@ init_zm_cr_group(struct nvbios_init *init) static void init_condition_time(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 cond = nvbios_rd08(bios, init->offset + 1); u8 retry = nvbios_rd08(bios, init->offset + 2); u8 wait = min((u16)retry * 50, 100); @@ -1257,7 +1258,7 @@ init_condition_time(struct nvbios_init *init) static void init_ltime(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 msec = nvbios_rd16(bios, init->offset + 1); trace("LTIME\t0x%04x\n", msec); @@ -1274,7 +1275,7 @@ init_ltime(struct nvbios_init *init) static void init_zm_reg_sequence(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 base = nvbios_rd32(bios, init->offset + 1); u8 count = nvbios_rd08(bios, init->offset + 5); @@ -1299,7 +1300,7 @@ init_zm_reg_sequence(struct nvbios_init *init) static void init_pll_indirect(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u16 addr = nvbios_rd16(bios, init->offset + 5); u32 freq = (u32)nvbios_rd16(bios, addr) * 1000; @@ -1318,7 +1319,7 @@ init_pll_indirect(struct nvbios_init *init) static void init_zm_reg_indirect(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u16 addr = nvbios_rd16(bios, init->offset + 5); u32 data = nvbios_rd32(bios, addr); @@ -1337,7 +1338,7 @@ init_zm_reg_indirect(struct nvbios_init *init) static void init_sub_direct(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 addr = nvbios_rd16(bios, init->offset + 1); u16 save; @@ -1363,7 +1364,7 @@ init_sub_direct(struct nvbios_init *init) static void init_jump(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 offset = nvbios_rd16(bios, init->offset + 1); trace("JUMP\t0x%04x\n", offset); @@ -1381,7 +1382,7 @@ init_jump(struct nvbios_init *init) static void init_i2c_if(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2); u8 reg = nvbios_rd08(bios, init->offset + 3); @@ -1408,7 +1409,7 @@ init_i2c_if(struct nvbios_init *init) static void init_copy_nv_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 sreg = nvbios_rd32(bios, init->offset + 1); u8 shift = nvbios_rd08(bios, init->offset + 5); u32 smask = nvbios_rd32(bios, init->offset + 6); @@ -1434,7 +1435,7 @@ init_copy_nv_reg(struct nvbios_init *init) static void init_zm_index_io(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 index = nvbios_rd08(bios, init->offset + 3); u8 data = nvbios_rd08(bios, init->offset + 4); @@ -1452,7 +1453,7 @@ init_zm_index_io(struct nvbios_init *init) static void init_compute_mem(struct nvbios_init *init) { - struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; + struct nvkm_devinit *devinit = init->subdev->device->devinit; trace("COMPUTE_MEM\n"); init->offset += 1; @@ -1470,7 +1471,7 @@ init_compute_mem(struct nvbios_init *init) static void init_reset(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 data1 = nvbios_rd32(bios, init->offset + 5); u32 data2 = nvbios_rd32(bios, init->offset + 9); @@ -1497,7 +1498,7 @@ init_reset(struct nvbios_init *init) static u16 init_configure_mem_clk(struct nvbios_init *init) { - u16 mdata = bmp_mem_init_table(init->bios); + u16 mdata = bmp_mem_init_table(init->subdev->device->bios); if (mdata) mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66; return mdata; @@ -1506,7 +1507,7 @@ init_configure_mem_clk(struct nvbios_init *init) static void init_configure_mem(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 mdata, sdata; u32 addr, data; @@ -1556,7 +1557,7 @@ init_configure_mem(struct nvbios_init *init) static void init_configure_clk(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 mdata, clock; trace("CONFIGURE_CLK\n"); @@ -1590,7 +1591,7 @@ init_configure_clk(struct nvbios_init *init) static void init_configure_preinit(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 strap; trace("CONFIGURE_PREINIT\n"); @@ -1616,7 +1617,7 @@ init_configure_preinit(struct nvbios_init *init) static void init_io(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 mask = nvbios_rd16(bios, init->offset + 3); u8 data = nvbios_rd16(bios, init->offset + 4); @@ -1656,7 +1657,7 @@ init_io(struct nvbios_init *init) static void init_sub(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u16 addr, save; @@ -1683,7 +1684,7 @@ init_sub(struct nvbios_init *init) static void init_ram_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 mask = nvbios_rd08(bios, init->offset + 1); u8 value = nvbios_rd08(bios, init->offset + 2); @@ -1702,7 +1703,7 @@ init_ram_condition(struct nvbios_init *init) static void init_nv_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 mask = nvbios_rd32(bios, init->offset + 5); u32 data = nvbios_rd32(bios, init->offset + 9); @@ -1720,7 +1721,7 @@ init_nv_reg(struct nvbios_init *init) static void init_macro(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 macro = nvbios_rd08(bios, init->offset + 1); u16 table; @@ -1756,7 +1757,7 @@ init_resume(struct nvbios_init *init) static void init_strap_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 mask = nvbios_rd32(bios, init->offset + 1); u32 value = nvbios_rd32(bios, init->offset + 5); @@ -1774,7 +1775,7 @@ init_strap_condition(struct nvbios_init *init) static void init_time(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 usec = nvbios_rd16(bios, init->offset + 1); trace("TIME\t0x%04x\n", usec); @@ -1795,7 +1796,7 @@ init_time(struct nvbios_init *init) static void init_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 cond = nvbios_rd08(bios, init->offset + 1); trace("CONDITION\t0x%02x\n", cond); @@ -1812,7 +1813,7 @@ init_condition(struct nvbios_init *init) static void init_io_condition(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_CONDITION\t0x%02x\n", cond); @@ -1829,7 +1830,7 @@ init_io_condition(struct nvbios_init *init) static void init_zm_reg16(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u16 data = nvbios_rd16(bios, init->offset + 5); @@ -1846,7 +1847,7 @@ init_zm_reg16(struct nvbios_init *init) static void init_index_io(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u16 port = nvbios_rd16(bios, init->offset + 1); u8 index = nvbios_rd16(bios, init->offset + 3); u8 mask = nvbios_rd08(bios, init->offset + 4); @@ -1868,7 +1869,7 @@ init_index_io(struct nvbios_init *init) static void init_pll(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 reg = nvbios_rd32(bios, init->offset + 1); u32 freq = nvbios_rd16(bios, init->offset + 5) * 10; @@ -1885,7 +1886,7 @@ init_pll(struct nvbios_init *init) static void init_zm_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u32 data = nvbios_rd32(bios, init->offset + 5); @@ -1905,7 +1906,7 @@ init_zm_reg(struct nvbios_init *init) static void init_ram_restrict_pll(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 type = nvbios_rd08(bios, init->offset + 1); u8 count = init_ram_restrict_group_count(init); u8 strap = init_ram_restrict(init); @@ -1935,7 +1936,7 @@ init_ram_restrict_pll(struct nvbios_init *init) static void init_gpio(struct nvbios_init *init) { - struct nvkm_gpio *gpio = init->bios->subdev.device->gpio; + struct nvkm_gpio *gpio = init->subdev->device->gpio; trace("GPIO\n"); init->offset += 1; @@ -1951,7 +1952,7 @@ init_gpio(struct nvbios_init *init) static void init_ram_restrict_zm_reg_group(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u8 incr = nvbios_rd08(bios, init->offset + 5); u8 num = nvbios_rd08(bios, init->offset + 6); @@ -1989,7 +1990,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) static void init_copy_zm_reg(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 sreg = nvbios_rd32(bios, init->offset + 1); u32 dreg = nvbios_rd32(bios, init->offset + 5); @@ -2006,7 +2007,7 @@ init_copy_zm_reg(struct nvbios_init *init) static void init_zm_reg_group(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u8 count = nvbios_rd08(bios, init->offset + 5); @@ -2028,7 +2029,7 @@ init_zm_reg_group(struct nvbios_init *init) static void init_xlat(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 saddr = nvbios_rd32(bios, init->offset + 1); u8 sshift = nvbios_rd08(bios, init->offset + 5); u8 smask = nvbios_rd08(bios, init->offset + 6); @@ -2056,7 +2057,7 @@ init_xlat(struct nvbios_init *init) static void init_zm_mask_add(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u32 mask = nvbios_rd32(bios, init->offset + 5); u32 add = nvbios_rd32(bios, init->offset + 9); @@ -2077,7 +2078,7 @@ init_zm_mask_add(struct nvbios_init *init) static void init_auxch(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u8 count = nvbios_rd08(bios, init->offset + 5); @@ -2101,7 +2102,7 @@ init_auxch(struct nvbios_init *init) static void init_zm_auxch(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u32 addr = nvbios_rd32(bios, init->offset + 1); u8 count = nvbios_rd08(bios, init->offset + 5); @@ -2123,7 +2124,7 @@ init_zm_auxch(struct nvbios_init *init) static void init_i2c_long_if(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; u8 index = nvbios_rd08(bios, init->offset + 1); u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; u8 reglo = nvbios_rd08(bios, init->offset + 3); @@ -2162,7 +2163,7 @@ init_i2c_long_if(struct nvbios_init *init) static void init_gpio_ne(struct nvbios_init *init) { - struct nvkm_bios *bios = init->bios; + struct nvkm_bios *bios = init->subdev->device->bios; struct nvkm_gpio *gpio = bios->subdev.device->gpio; struct dcb_gpio_func func; u8 count = nvbios_rd08(bios, init->offset + 1); @@ -2275,9 +2276,10 @@ static struct nvbios_init_opcode { int nvbios_exec(struct nvbios_init *init) { + struct nvkm_bios *bios = init->subdev->device->bios; init->nested++; while (init->offset) { - u8 opcode = nvbios_rd08(init->bios, init->offset); + u8 opcode = nvbios_rd08(bios, init->offset); if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) { error("unknown opcode 0x%02x\n", opcode); return -EINVAL; From 2195a22f6dd9f413c952b81dd228db606e32c67c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 16/73] drm/nouveau/bios/init: rename 'crtc' to 'head' Compatibility temporarily in place until all callers have been updated. Signed-off-by: Ben Skeggs --- .../nouveau/include/nvkm/subdev/bios/init.h | 6 ++++- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 26 +++++++++---------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index 98aa9ece0dc5..53b3b4cd77d7 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -5,8 +5,12 @@ struct nvbios_init { struct nvkm_subdev *subdev; struct nvkm_bios *bios; u16 offset; + struct dcb_output *outp; - int crtc; + union { + int head; + int crtc; + }; /* internal state used during parsing */ u8 execute; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 1894b2490651..e177457084a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -106,12 +106,12 @@ init_link(struct nvbios_init *init) } static inline int -init_crtc(struct nvbios_init *init) +init_head(struct nvbios_init *init) { if (init_exec(init)) { - if (init->crtc >= 0) - return init->crtc; - error("script needs crtc\n"); + if (init->head >= 0) + return init->head; + error("script needs head\n"); } return 0; } @@ -156,7 +156,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) */ if (init->subdev->device->card_type >= NV_50) { if (reg & 0x80000000) { - reg += init_crtc(init) * 0x800; + reg += init_head(init) * 0x800; reg &= ~0x80000000; } @@ -212,7 +212,7 @@ static u8 init_rdport(struct nvbios_init *init, u16 port) { if (init_exec(init)) - return nvkm_rdport(init->subdev->device, init->crtc, port); + return nvkm_rdport(init->subdev->device, init->head, port); return 0x00; } @@ -220,7 +220,7 @@ static void init_wrport(struct nvbios_init *init, u16 port, u8 value) { if (init_exec(init)) - nvkm_wrport(init->subdev->device, init->crtc, port, value); + nvkm_wrport(init->subdev->device, init->head, port, value); } static u8 @@ -228,7 +228,7 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index) { struct nvkm_subdev *subdev = init->subdev; if (init_exec(init)) { - int head = init->crtc < 0 ? 0 : init->crtc; + int head = init->head < 0 ? 0 : init->head; return nvkm_rdvgai(subdev->device, head, port, index); } return 0x00; @@ -242,18 +242,18 @@ init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) /* force head 0 for updates to cr44, it only exists on first head */ if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44) - init->crtc = 0; + init->head = 0; } if (init_exec(init)) { - int head = init->crtc < 0 ? 0 : init->crtc; + int head = init->head < 0 ? 0 : init->head; nvkm_wrvgai(device, head, port, index, value); } /* select head 1 if cr44 write selected it */ if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44 && value == 3) - init->crtc = 1; + init->head = 1; } } @@ -2307,7 +2307,7 @@ nvbios_post(struct nvkm_subdev *subdev, bool execute) .bios = bios, .offset = data, .outp = NULL, - .crtc = -1, + .head = -1, .execute = execute ? 1 : 0, }; @@ -2323,7 +2323,7 @@ nvbios_post(struct nvkm_subdev *subdev, bool execute) .bios = bios, .offset = data, .outp = NULL, - .crtc = -1, + .head = -1, .execute = execute ? 1 : 0, }; From ca9c2d5b28b4d5aa1d229950b88f7c559eee4164 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 17/73] drm/nouveau/bios/init: bump script offset to 32-bits No (known) case yet, but other tables have been moving beyond 16-bits, so we may as well be prepared. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index 53b3b4cd77d7..ad5d993f7805 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -4,7 +4,7 @@ struct nvbios_init { struct nvkm_subdev *subdev; struct nvkm_bios *bios; - u16 offset; + u32 offset; struct dcb_output *outp; union { @@ -15,8 +15,8 @@ struct nvbios_init { /* internal state used during parsing */ u8 execute; u32 nested; - u16 repeat; - u16 repend; + u32 repeat; + u32 repend; u32 ramcfg; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index e177457084a7..249d018ee32c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -37,7 +37,7 @@ #include #define bioslog(lvl, fmt, args...) do { \ - nvkm_printk(init->subdev, lvl, info, "0x%04x[%c]: "fmt, \ + nvkm_printk(init->subdev, lvl, info, "0x%08x[%c]: "fmt, \ init->offset, init_exec(init) ? \ '0' + (init->nested - 1) : ' ', ##args); \ } while(0) From b88afa43967578741e3b258c80e01969fddd5fe6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 18/73] drm/nouveau/bios/init: add or/link args separate from output path As of DCB 4.1, these are not the same thing. Compatibility temporarily in place until callers have been updated. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/bios/init.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index ad5d993f7805..84d9e588af4d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -7,6 +7,8 @@ struct nvbios_init { u32 offset; struct dcb_output *outp; + int or; + int link; union { int head; int crtc; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 249d018ee32c..b1256aba2fdb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -87,8 +87,8 @@ static inline int init_or(struct nvbios_init *init) { if (init_exec(init)) { - if (init->outp) - return ffs(init->outp->or) - 1; + if (init->or >= 0) + return init->or; error("script needs OR!!\n"); } return 0; @@ -98,8 +98,8 @@ static inline int init_link(struct nvbios_init *init) { if (init_exec(init)) { - if (init->outp) - return !(init->outp->sorconf.link & 1); + if (init->link) + return init->link == 2; error("script needs OR link\n"); } return 0; @@ -2277,6 +2277,12 @@ int nvbios_exec(struct nvbios_init *init) { struct nvkm_bios *bios = init->subdev->device->bios; + + if (init->bios) { + init->or = init->outp ? ffs(init->outp->or) - 1 : -1; + init->link = init->outp ? init->outp->sorconf.link : 0; + } + init->nested++; while (init->offset) { u8 opcode = nvbios_rd08(bios, init->offset); From 74bcb2e98a3cac5456c9d3bc38c64963d61e481e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 19/73] drm/nouveau/bios/init: add a new devinit script interpreter entry-point This will ensure unspecified args are easily identified. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/bios/init.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index 84d9e588af4d..c7383e1f0966 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -22,6 +22,19 @@ struct nvbios_init { u32 ramcfg; }; +#define nvbios_init(s,o,ARGS...) ({ \ + struct nvbios_init init = { \ + .subdev = (s), \ + .offset = (o), \ + .or = -1, \ + .link = 0, \ + .head = -1, \ + .execute = 1, \ + }; \ + ARGS \ + nvbios_exec(&init); \ +}) int nvbios_exec(struct nvbios_init *); + int nvbios_post(struct nvkm_subdev *, bool execute); #endif From 28c62976a8a7de7cbdc6908ec0d575cef3cfe288 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 20/73] drm/nouveau/devinit: use new devinit script interpreter entry-point Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 26 +++++-------------- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 15 ++++------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index b1256aba2fdb..2095f43e16ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -2308,32 +2308,18 @@ nvbios_post(struct nvkm_subdev *subdev, bool execute) if (execute) nvkm_debug(subdev, "running init tables\n"); while (!ret && (data = (init_script(bios, ++i)))) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = NULL, - .head = -1, - .execute = execute ? 1 : 0, - }; - - ret = nvbios_exec(&init); + ret = nvbios_init(subdev, data, + init.execute = execute ? 1 : 0; + ); } /* the vbios parser will run this right after the normal init * tables, whereas the binary driver appears to run it later. */ if (!ret && (data = init_unknown_script(bios))) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = NULL, - .head = -1, - .execute = execute ? 1 : 0, - }; - - ret = nvbios_exec(&init); + ret = nvbios_init(subdev, data, + init.execute = execute ? 1 : 0; + ); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 59362f8dee22..d7947c4391dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -137,16 +137,11 @@ nv50_devinit_init(struct nvkm_devinit *base) while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { - struct nvbios_init exec = { - .subdev = subdev, - .bios = bios, - .offset = info.script[0], - .outp = &outp, - .crtc = -1, - .execute = 1, - }; - - nvbios_exec(&exec); + nvbios_init(subdev, info.script[0], + init.outp = &outp; + init.or = ffs(outp.or) - 1; + init.link = outp.sorconf.link == 2; + ); } i++; } From 4fdc6ba32eba1b90a39a65e19dacb67329f8c0e5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 21/73] drm/nouveau/fb/ram/nv40-: use new devinit script interpreter entry-point Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 7 +------ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c | 7 +------ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 12 ++---------- 3 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index f6c00791722c..75814f15eb53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1424,12 +1424,7 @@ gk104_ram_init(struct nvkm_ram *ram) for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4); - nvbios_exec(&(struct nvbios_init) { - .subdev = subdev, - .bios = bios, - .offset = nvbios_rd32(bios, data), - .execute = 1, - }); + nvbios_init(subdev, nvbios_rd32(bios, data)); } } nvkm_mask(device, 0x10f65c, 0x000000f0, save); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c index cac70047ad5a..df8a87333b67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgp100.c @@ -59,12 +59,7 @@ gp100_ram_init(struct nvkm_ram *ram) for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { nvkm_mask(device, 0x9a065c, 0x000000f0, i << 4); - nvbios_exec(&(struct nvbios_init) { - .subdev = subdev, - .bios = bios, - .offset = nvbios_rd32(bios, data), - .execute = 1, - }); + nvbios_init(subdev, nvbios_rd32(bios, data)); } } nvkm_mask(device, 0x9a065c, 0x000000f0, save); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 56f8cffc2560..70c63535d56b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -150,16 +150,8 @@ nv40_ram_prog(struct nvkm_ram *base) udelay(100); /* execute memory reset script from vbios */ - if (!bit_entry(bios, 'M', &M)) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = nvbios_rd16(bios, M.offset + 0x00), - .execute = 1, - }; - - nvbios_exec(&init); - } + if (!bit_entry(bios, 'M', &M)) + nvbios_init(subdev, nvbios_rd16(bios, M.offset + 0x00)); /* make sure we're in vblank (hopefully the same one as before), and * then re-enable crtc memory access From 639d72e24295748e37b45b1935145028423922e3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 22/73] drm/nouveau/kms/nv04: use new devinit script interpreter entry-point Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/disp.h | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index bea4543554ba..74a8795c2c2b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -169,18 +169,10 @@ static inline void nouveau_bios_run_init_table(struct drm_device *dev, u16 table, struct dcb_output *outp, int crtc) { - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_bios *bios = nvxx_bios(&drm->client.device); - struct nvbios_init init = { - .subdev = &bios->subdev, - .bios = bios, - .offset = table, - .outp = outp, - .crtc = crtc, - .execute = 1, - }; - - nvbios_exec(&init); + nvbios_init(&nvxx_bios(&nouveau_drm(dev)->client.device)->subdev, table, + init.outp = outp; + init.head = crtc; + ); } #endif From af85389c614ae04970c0eea7a5c50fb889c8a480 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 23/73] drm/nouveau/disp: shuffle functions around Upcoming changes to split OR from output path drastically change the placement of various operations. In order to make the real changes clearer, do the moving around part ahead of time. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 11 +- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 80 +-- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 637 ++++++++++++++++++ .../nvkm/engine/disp/{dport.h => dp.h} | 72 +- .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 401 ----------- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 2 +- .../engine/disp/{hdmi_infoframe.c => hdmi.c} | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/hdmi.h | 15 + .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 2 +- .../drm/nouveau/nvkm/engine/disp/hdmigf119.c | 2 +- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 2 +- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 372 ++++------ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 22 +- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.c | 282 -------- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 76 --- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 71 +- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 195 +++++- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 73 +- .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 1 - .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 65 +- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 24 +- 33 files changed, 1186 insertions(+), 1246 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c rename drivers/gpu/drm/nouveau/nvkm/engine/disp/{dport.h => dp.h} (72%) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c rename drivers/gpu/drm/nouveau/nvkm/engine/disp/{hdmi_infoframe.c => hdmi.c} (98%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 65ae870f147e..cbc7f673a5de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -12,9 +12,8 @@ nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm200.o nvkm-y += nvkm/engine/disp/gp100.o nvkm-y += nvkm/engine/disp/gp102.o +nvkm-y += nvkm/engine/disp/vga.o -nvkm-y += nvkm/engine/disp/outp.o -nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o @@ -22,20 +21,20 @@ nvkm-y += nvkm/engine/disp/sorg94.o nvkm-y += nvkm/engine/disp/sorgf119.o nvkm-y += nvkm/engine/disp/sorgm107.o nvkm-y += nvkm/engine/disp/sorgm200.o -nvkm-y += nvkm/engine/disp/dport.o -nvkm-y += nvkm/engine/disp/conn.o +nvkm-y += nvkm/engine/disp/outp.o +nvkm-y += nvkm/engine/disp/dp.o nvkm-y += nvkm/engine/disp/hdagt215.o nvkm-y += nvkm/engine/disp/hdagf119.o -nvkm-y += nvkm/engine/disp/hdmi_infoframe.o +nvkm-y += nvkm/engine/disp/hdmi.o nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o nvkm-y += nvkm/engine/disp/hdmigf119.o nvkm-y += nvkm/engine/disp/hdmigk104.o -nvkm-y += nvkm/engine/disp/vga.o +nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/rootnv04.o nvkm-y += nvkm/engine/disp/rootnv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index c9b78b8f9c87..e8dabedea5dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -30,40 +30,16 @@ #include #include +static const struct nvkm_output_func +nv50_dac_output_func = { +}; + int -nv50_dac_power(NV50_DISP_MTHD_V1) +nv50_dac_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 doff = outp->or * 0x800; - union { - struct nv50_disp_dac_pwr_v0 v0; - } *args = data; - u32 stat; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp dac pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " - "vsync %d hsync %d\n", - args->v0.version, args->v0.state, args->v0.data, - args->v0.vsync, args->v0.hsync); - stat = 0x00000040 * !args->v0.state; - stat |= 0x00000010 * !args->v0.data; - stat |= 0x00000004 * !args->v0.vsync; - stat |= 0x00000001 * !args->v0.hsync; - } else - return ret; - - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) - break; - ); - return 0; + return nvkm_output_new_(&nv50_dac_output_func, disp, + index, dcbE, poutp); } int @@ -113,14 +89,38 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) return 0; } -static const struct nvkm_output_func -nv50_dac_output_func = { -}; - int -nv50_dac_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) +nv50_dac_power(NV50_DISP_MTHD_V1) { - return nvkm_output_new_(&nv50_dac_output_func, disp, - index, dcbE, poutp); + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 doff = outp->or * 0x800; + union { + struct nv50_disp_dac_pwr_v0 v0; + } *args = data; + u32 stat; + int ret = -ENOSYS; + + nvif_ioctl(object, "disp dac pwr size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " + "vsync %d hsync %d\n", + args->v0.version, args->v0.state, args->v0.data, + args->v0.vsync, args->v0.hsync); + stat = 0x00000040 * !args->v0.state; + stat |= 0x00000010 * !args->v0.data; + stat |= 0x00000004 * !args->v0.vsync; + stat |= 0x00000001 * !args->v0.hsync; + } else + return ret; + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c new file mode 100644 index 000000000000..1a3c460bcfe9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -0,0 +1,637 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "dp.h" +#include "conn.h" +#include "nv50.h" + +#include +#include +#include + +#include + +struct lt_state { + struct nvkm_output_dp *outp; + int link_nr; + u32 link_bw; + u8 stat[6]; + u8 conf[4]; + bool pc2; + u8 pc2stat; + u8 pc2conf[2]; +}; + +static int +nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) +{ + struct nvkm_output_dp *outp = lt->outp; + int ret; + + if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) + mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); + else + udelay(delay); + + ret = nvkm_rdaux(outp->aux, DPCD_LS02, lt->stat, 6); + if (ret) + return ret; + + if (pc) { + ret = nvkm_rdaux(outp->aux, DPCD_LS0C, <->pc2stat, 1); + if (ret) + lt->pc2stat = 0x00; + OUTP_DBG(&outp->base, "status %6ph pc2 %02x", + lt->stat, lt->pc2stat); + } else { + OUTP_DBG(&outp->base, "status %6ph", lt->stat); + } + + return 0; +} + +static int +nvkm_dp_train_drive(struct lt_state *lt, bool pc) +{ + struct nvkm_output_dp *outp = lt->outp; + int ret, i; + + for (i = 0; i < lt->link_nr; i++) { + u8 lane = (lt->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; + u8 lpc2 = (lt->pc2stat >> (i * 2)) & 0x3; + u8 lpre = (lane & 0x0c) >> 2; + u8 lvsw = (lane & 0x03) >> 0; + u8 hivs = 3 - lpre; + u8 hipe = 3; + u8 hipc = 3; + + if (lpc2 >= hipc) + lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED; + if (lpre >= hipe) { + lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */ + lvsw = hivs = 3 - (lpre & 3); + } else + if (lvsw >= hivs) { + lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED; + } + + lt->conf[i] = (lpre << 3) | lvsw; + lt->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); + + OUTP_DBG(&outp->base, "config lane %d %02x %02x", + i, lt->conf[i], lpc2); + outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + } + + ret = nvkm_wraux(outp->aux, DPCD_LC03(0), lt->conf, 4); + if (ret) + return ret; + + if (pc) { + ret = nvkm_wraux(outp->aux, DPCD_LC0F, lt->pc2conf, 2); + if (ret) + return ret; + } + + return 0; +} + +static void +nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) +{ + struct nvkm_output_dp *outp = lt->outp; + u8 sink_tp; + + OUTP_DBG(&outp->base, "training pattern %d", pattern); + outp->func->pattern(outp, pattern); + + nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); + sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; + sink_tp |= pattern; + nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1); +} + +static int +nvkm_dp_train_eq(struct lt_state *lt) +{ + struct nvkm_output_dp *outp = lt->outp; + bool eq_done = false, cr_done = true; + int tries = 0, i; + + if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) + nvkm_dp_train_pattern(lt, 3); + else + nvkm_dp_train_pattern(lt, 2); + + do { + if ((tries && + nvkm_dp_train_drive(lt, lt->pc2)) || + nvkm_dp_train_sense(lt, lt->pc2, 400)) + break; + + eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); + for (i = 0; i < lt->link_nr && eq_done; i++) { + u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; + if (!(lane & DPCD_LS02_LANE0_CR_DONE)) + cr_done = false; + if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || + !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) + eq_done = false; + } + } while (!eq_done && cr_done && ++tries <= 5); + + return eq_done ? 0 : -1; +} + +static int +nvkm_dp_train_cr(struct lt_state *lt) +{ + bool cr_done = false, abort = false; + int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; + int tries = 0, i; + + nvkm_dp_train_pattern(lt, 1); + + do { + if (nvkm_dp_train_drive(lt, false) || + nvkm_dp_train_sense(lt, false, 100)) + break; + + cr_done = true; + for (i = 0; i < lt->link_nr; i++) { + u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; + if (!(lane & DPCD_LS02_LANE0_CR_DONE)) { + cr_done = false; + if (lt->conf[i] & DPCD_LC03_MAX_SWING_REACHED) + abort = true; + break; + } + } + + if ((lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) { + voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; + tries = 0; + } + } while (!cr_done && !abort && ++tries < 5); + + return cr_done ? 0 : -1; +} + +static int +nvkm_dp_train_links(struct lt_state *lt) +{ + struct nvkm_output_dp *outp = lt->outp; + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; + struct nvbios_init init = { + .subdev = subdev, + .bios = bios, + .offset = 0x0000, + .outp = &outp->base.info, + .crtc = -1, + .execute = 1, + }; + u32 lnkcmp; + u8 sink[2]; + int ret; + + OUTP_DBG(&outp->base, "%d lanes at %d KB/s", lt->link_nr, lt->link_bw); + + /* Intersect misc. capabilities of the OR and sink. */ + if (disp->engine.subdev.device->chipset < 0xd0) + outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; + lt->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; + + /* Set desired link configuration on the source. */ + if ((lnkcmp = lt->outp->info.lnkcmp)) { + if (outp->version < 0x30) { + while ((lt->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) + lnkcmp += 4; + init.offset = nvbios_rd16(bios, lnkcmp + 2); + } else { + while ((lt->link_bw / 27000) < nvbios_rd08(bios, lnkcmp)) + lnkcmp += 3; + init.offset = nvbios_rd16(bios, lnkcmp + 1); + } + + nvbios_exec(&init); + } + + ret = outp->func->lnk_ctl(outp, lt->link_nr, lt->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); + if (ret) { + if (ret < 0) + OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); + return ret; + } + + outp->func->lnk_pwr(outp, lt->link_nr); + + /* Set desired link configuration on the sink. */ + sink[0] = lt->link_bw / 27000; + sink[1] = lt->link_nr; + if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) + sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; + + return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); +} + +static void +nvkm_dp_train_fini(struct lt_state *lt) +{ + struct nvkm_output_dp *outp = lt->outp; + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvbios_init init = { + .subdev = subdev, + .bios = subdev->device->bios, + .outp = &outp->base.info, + .crtc = -1, + .execute = 1, + }; + + /* Execute AfterLinkTraining script from DP Info table. */ + init.offset = outp->info.script[1], + nvbios_exec(&init); +} + +static void +nvkm_dp_train_init(struct lt_state *lt, bool spread) +{ + struct nvkm_output_dp *outp = lt->outp; + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvbios_init init = { + .subdev = subdev, + .bios = subdev->device->bios, + .outp = &outp->base.info, + .crtc = -1, + .execute = 1, + }; + + /* Execute EnableSpread/DisableSpread script from DP Info table. */ + if (spread) + init.offset = outp->info.script[2]; + else + init.offset = outp->info.script[3]; + nvbios_exec(&init); + + /* Execute BeforeLinkTraining script from DP info table. */ + init.offset = outp->info.script[0]; + nvbios_exec(&init); +} + +static const struct dp_rates { + u32 rate; + u8 bw; + u8 nr; +} nvkm_dp_rates[] = { + { 2160000, 0x14, 4 }, + { 1080000, 0x0a, 4 }, + { 1080000, 0x14, 2 }, + { 648000, 0x06, 4 }, + { 540000, 0x0a, 2 }, + { 540000, 0x14, 1 }, + { 324000, 0x06, 2 }, + { 270000, 0x0a, 1 }, + { 162000, 0x06, 1 }, + {} +}; + +static void +nvkm_dp_train(struct nvkm_output_dp *outp) +{ + struct nv50_disp *disp = nv50_disp(outp->base.disp); + const struct dp_rates *cfg = nvkm_dp_rates - 1; + struct lt_state lt = { + .outp = outp, + }; + u8 pwr; + int ret; + + if (!outp->base.info.location && disp->func->sor.magic) + disp->func->sor.magic(&outp->base); + + if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { + outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; + outp->dpcd[2] |= outp->base.info.dpconf.link_nr; + } + if (outp->dpcd[1] > outp->base.info.dpconf.link_bw) + outp->dpcd[1] = outp->base.info.dpconf.link_bw; + + /* Ensure sink is not in a low-power state. */ + if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) { + if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { + pwr &= ~DPCD_SC00_SET_POWER; + pwr |= DPCD_SC00_SET_POWER_D0; + nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1); + } + } + + /* Link training. */ + nvkm_dp_train_init(<, outp->dpcd[3] & 0x01); + while (ret = -EIO, (++cfg)->rate) { + /* Skip configurations not supported by both OR and sink. */ + while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || + cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE])) + cfg++; + lt.link_bw = cfg->bw * 27000; + lt.link_nr = cfg->nr; + + /* Program selected link configuration. */ + ret = nvkm_dp_train_links(<); + if (ret == 0) { + /* Attempt to train the link in this configuration. */ + memset(lt.stat, 0x00, sizeof(lt.stat)); + if (!nvkm_dp_train_cr(<) && + !nvkm_dp_train_eq(<)) + break; + } else + if (ret) { + /* nvkm_dp_train_links() handled training, or + * we failed to communicate with the sink. + */ + break; + } + } + nvkm_dp_train_pattern(<, 0); + nvkm_dp_train_fini(<); + if (ret < 0) + OUTP_ERR(&outp->base, "link training failed"); + + OUTP_DBG(&outp->base, "training complete"); + atomic_set(&outp->lt.done, 1); +} + +int +nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) +{ + struct nvkm_output_dp *outp = nvkm_output_dp(base); + bool retrain = true; + u8 link[2], stat[3]; + u32 linkrate; + int ret, i; + + mutex_lock(&outp->mutex); + + /* check that the link is trained at a high enough rate */ + ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); + if (ret) { + OUTP_DBG(&outp->base, + "failed to read link config, assuming no sink"); + goto done; + } + + linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET); + linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ + datarate = (datarate + 9) / 10; /* -> decakilobits */ + if (linkrate < datarate) { + OUTP_DBG(&outp->base, "link not trained at sufficient rate"); + goto done; + } + + /* check that link is still trained */ + ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); + if (ret) { + OUTP_DBG(&outp->base, + "failed to read link status, assuming no sink"); + goto done; + } + + if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { + for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) { + u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; + if (!(lane & DPCD_LS02_LANE0_CR_DONE) || + !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || + !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { + OUTP_DBG(&outp->base, + "lane %d not equalised", lane); + goto done; + } + } + retrain = false; + } else { + OUTP_DBG(&outp->base, "no inter-lane alignment"); + } + +done: + if (retrain || !atomic_read(&outp->lt.done)) { + /* no sink, but still need to configure source */ + if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { + outp->dpcd[DPCD_RC01_MAX_LINK_RATE] = + outp->base.info.dpconf.link_bw; + outp->dpcd[DPCD_RC02] = + outp->base.info.dpconf.link_nr; + } + nvkm_dp_train(outp); + } + + mutex_unlock(&outp->mutex); + return ret; +} + +static void +nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) +{ + struct nvkm_i2c_aux *aux = outp->aux; + + if (enable) { + if (!outp->present) { + OUTP_DBG(&outp->base, "aux power -> always"); + nvkm_i2c_aux_monitor(aux, true); + outp->present = true; + } + + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, + sizeof(outp->dpcd))) { + nvkm_output_dp_train(&outp->base, 0); + return; + } + } + + if (outp->present) { + OUTP_DBG(&outp->base, "aux power -> demand"); + nvkm_i2c_aux_monitor(aux, false); + outp->present = false; + } + + atomic_set(&outp->lt.done, 0); +} + +static int +nvkm_output_dp_hpd(struct nvkm_notify *notify) +{ + const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; + struct nvif_notify_conn_rep_v0 rep = {}; + + OUTP_DBG(&outp->base, "HPD: %d", line->mask); + nvkm_output_dp_enable(outp, true); + + if (line->mask & NVKM_I2C_UNPLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; + if (line->mask & NVKM_I2C_PLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; + + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; +} + +static int +nvkm_output_dp_irq(struct nvkm_notify *notify) +{ + const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; + struct nvif_notify_conn_rep_v0 rep = { + .mask = NVIF_NOTIFY_CONN_V0_IRQ, + }; + + OUTP_DBG(&outp->base, "IRQ: %d", line->mask); + nvkm_output_dp_train(&outp->base, 0); + + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; +} + +static void +nvkm_output_dp_fini(struct nvkm_output *base) +{ + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->hpd); + nvkm_notify_put(&outp->irq); + nvkm_output_dp_enable(outp, false); +} + +static void +nvkm_output_dp_init(struct nvkm_output *base) +{ + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->base.conn->hpd); + nvkm_output_dp_enable(outp, true); + nvkm_notify_get(&outp->irq); + nvkm_notify_get(&outp->hpd); +} + +static void * +nvkm_output_dp_dtor(struct nvkm_output *base) +{ + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_fini(&outp->hpd); + nvkm_notify_fini(&outp->irq); + return outp; +} + +static const struct nvkm_output_func +nvkm_output_dp_func = { + .dtor = nvkm_output_dp_dtor, + .init = nvkm_output_dp_init, + .fini = nvkm_output_dp_fini, +}; + +int +nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) +{ + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; + u8 hdr, cnt, len; + u32 data; + int ret; + + nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); + outp->func = func; + outp->aux = aux; + if (!outp->aux) { + OUTP_ERR(&outp->base, "no aux"); + return -ENODEV; + } + + /* bios data is not optional */ + data = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, &outp->version, + &hdr, &cnt, &len, &outp->info); + if (!data) { + OUTP_ERR(&outp->base, "no bios dp data"); + return -ENODEV; + } + + OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", + outp->version, hdr, cnt, len); + + /* link maintenance */ + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_IRQ, + .port = outp->aux->id, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->irq); + if (ret) { + OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); + return ret; + } + + mutex_init(&outp->mutex); + atomic_set(&outp->lt.done, 0); + + /* hotplug detect, replaces gpio-based mechanism with aux events */ + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, + &(struct nvkm_i2c_ntfy_req) { + .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, + .port = outp->aux->id, + }, + sizeof(struct nvkm_i2c_ntfy_req), + sizeof(struct nvkm_i2c_ntfy_rep), + &outp->hpd); + if (ret) { + OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); + return ret; + } + + return 0; +} + +int +nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); + struct nvkm_output_dp *outp; + + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; + + return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h similarity index 72% rename from drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h rename to drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index baf1dd9ff975..b0c0c6263477 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -1,6 +1,70 @@ -#ifndef __NVKM_DISP_DPORT_H__ -#define __NVKM_DISP_DPORT_H__ -struct nvkm_output_dp; +#ifndef __NVKM_DISP_OUTP_DP_H__ +#define __NVKM_DISP_OUTP_DP_H__ +#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) +#include "outp.h" + +#include +#include +#include + +struct nvkm_output_dp { + const struct nvkm_output_dp_func *func; + struct nvkm_output base; + + struct nvbios_dpout info; + u8 version; + + struct nvkm_i2c_aux *aux; + + struct nvkm_notify irq; + struct nvkm_notify hpd; + bool present; + u8 dpcd[16]; + + struct mutex mutex; + struct { + atomic_t done; + bool mst; + } lt; +}; + +struct nvkm_output_dp_func { + int (*pattern)(struct nvkm_output_dp *, int); + int (*lnk_pwr)(struct nvkm_output_dp *, int nr); + int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); + int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); + void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, + u8 num_slots, u16 pbn, u16 aligned_pbn); +}; + +int nvkm_output_dp_train(struct nvkm_output *, u32 rate); + +int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_i2c_aux *, + struct nvkm_output_dp *); +int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, + struct nvkm_output **); + +int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); + +int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); +int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int); +void gf119_sor_dp_vcpi(struct nvkm_output_dp *, int, u8, u8, u16, u16); + +int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int gm107_sor_dp_pattern(struct nvkm_output_dp *, int); + +int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); /* DPCD Receiver Capabilities */ #define DPCD_RC00_DPCD_REV 0x00000 @@ -76,6 +140,4 @@ struct nvkm_output_dp; #define DPCD_SC00_SET_POWER 0x03 #define DPCD_SC00_SET_POWER_D0 0x01 #define DPCD_SC00_SET_POWER_D3 0x03 - -void nvkm_dp_train(struct nvkm_output_dp *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c deleted file mode 100644 index 4a93ceb850ac..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright 2013 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "dport.h" -#include "outpdp.h" -#include "nv50.h" - -#include -#include -#include - -#include - -/****************************************************************************** - * link training - *****************************************************************************/ -struct dp_state { - struct nvkm_output_dp *outp; - int link_nr; - u32 link_bw; - u8 stat[6]; - u8 conf[4]; - bool pc2; - u8 pc2stat; - u8 pc2conf[2]; -}; - -static int -dp_set_link_config(struct dp_state *dp) -{ - struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = outp->base.disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = 0x0000, - .outp = &outp->base.info, - .crtc = -1, - .execute = 1, - }; - u32 lnkcmp; - u8 sink[2]; - int ret; - - OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw); - - /* set desired link configuration on the source */ - if ((lnkcmp = dp->outp->info.lnkcmp)) { - if (outp->version < 0x30) { - while ((dp->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) - lnkcmp += 4; - init.offset = nvbios_rd16(bios, lnkcmp + 2); - } else { - while ((dp->link_bw / 27000) < nvbios_rd08(bios, lnkcmp)) - lnkcmp += 3; - init.offset = nvbios_rd16(bios, lnkcmp + 1); - } - - nvbios_exec(&init); - } - - ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, - outp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); - if (ret) { - if (ret < 0) - OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); - return ret; - } - - outp->func->lnk_pwr(outp, dp->link_nr); - - /* set desired link configuration on the sink */ - sink[0] = dp->link_bw / 27000; - sink[1] = dp->link_nr; - if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) - sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - - return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); -} - -static void -dp_set_training_pattern(struct dp_state *dp, u8 pattern) -{ - struct nvkm_output_dp *outp = dp->outp; - u8 sink_tp; - - OUTP_DBG(&outp->base, "training pattern %d", pattern); - outp->func->pattern(outp, pattern); - - nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); - sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; - sink_tp |= pattern; - nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1); -} - -static int -dp_link_train_commit(struct dp_state *dp, bool pc) -{ - struct nvkm_output_dp *outp = dp->outp; - int ret, i; - - for (i = 0; i < dp->link_nr; i++) { - u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; - u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3; - u8 lpre = (lane & 0x0c) >> 2; - u8 lvsw = (lane & 0x03) >> 0; - u8 hivs = 3 - lpre; - u8 hipe = 3; - u8 hipc = 3; - - if (lpc2 >= hipc) - lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED; - if (lpre >= hipe) { - lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */ - lvsw = hivs = 3 - (lpre & 3); - } else - if (lvsw >= hivs) { - lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED; - } - - dp->conf[i] = (lpre << 3) | lvsw; - dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); - - OUTP_DBG(&outp->base, "config lane %d %02x %02x", - i, dp->conf[i], lpc2); - outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); - } - - ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4); - if (ret) - return ret; - - if (pc) { - ret = nvkm_wraux(outp->aux, DPCD_LC0F, dp->pc2conf, 2); - if (ret) - return ret; - } - - return 0; -} - -static int -dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) -{ - struct nvkm_output_dp *outp = dp->outp; - int ret; - - if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) - mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); - else - udelay(delay); - - ret = nvkm_rdaux(outp->aux, DPCD_LS02, dp->stat, 6); - if (ret) - return ret; - - if (pc) { - ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1); - if (ret) - dp->pc2stat = 0x00; - OUTP_DBG(&outp->base, "status %6ph pc2 %02x", - dp->stat, dp->pc2stat); - } else { - OUTP_DBG(&outp->base, "status %6ph", dp->stat); - } - - return 0; -} - -static int -dp_link_train_cr(struct dp_state *dp) -{ - bool cr_done = false, abort = false; - int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; - int tries = 0, i; - - dp_set_training_pattern(dp, 1); - - do { - if (dp_link_train_commit(dp, false) || - dp_link_train_update(dp, false, 100)) - break; - - cr_done = true; - for (i = 0; i < dp->link_nr; i++) { - u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; - if (!(lane & DPCD_LS02_LANE0_CR_DONE)) { - cr_done = false; - if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED) - abort = true; - break; - } - } - - if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) { - voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; - tries = 0; - } - } while (!cr_done && !abort && ++tries < 5); - - return cr_done ? 0 : -1; -} - -static int -dp_link_train_eq(struct dp_state *dp) -{ - struct nvkm_output_dp *outp = dp->outp; - bool eq_done = false, cr_done = true; - int tries = 0, i; - - if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) - dp_set_training_pattern(dp, 3); - else - dp_set_training_pattern(dp, 2); - - do { - if ((tries && - dp_link_train_commit(dp, dp->pc2)) || - dp_link_train_update(dp, dp->pc2, 400)) - break; - - eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); - for (i = 0; i < dp->link_nr && eq_done; i++) { - u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; - if (!(lane & DPCD_LS02_LANE0_CR_DONE)) - cr_done = false; - if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || - !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) - eq_done = false; - } - } while (!eq_done && cr_done && ++tries <= 5); - - return eq_done ? 0 : -1; -} - -static void -dp_link_train_init(struct dp_state *dp, bool spread) -{ - struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = outp->base.disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->base.info, - .crtc = -1, - .execute = 1, - }; - - /* set desired spread */ - if (spread) - init.offset = outp->info.script[2]; - else - init.offset = outp->info.script[3]; - nvbios_exec(&init); - - /* pre-train script */ - init.offset = outp->info.script[0]; - nvbios_exec(&init); -} - -static void -dp_link_train_fini(struct dp_state *dp) -{ - struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = outp->base.disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->base.info, - .crtc = -1, - .execute = 1, - }; - - /* post-train script */ - init.offset = outp->info.script[1], - nvbios_exec(&init); -} - -static const struct dp_rates { - u32 rate; - u8 bw; - u8 nr; -} nvkm_dp_rates[] = { - { 2160000, 0x14, 4 }, - { 1080000, 0x0a, 4 }, - { 1080000, 0x14, 2 }, - { 648000, 0x06, 4 }, - { 540000, 0x0a, 2 }, - { 540000, 0x14, 1 }, - { 324000, 0x06, 2 }, - { 270000, 0x0a, 1 }, - { 162000, 0x06, 1 }, - {} -}; - -void -nvkm_dp_train(struct nvkm_output_dp *outp) -{ - struct nv50_disp *disp = nv50_disp(outp->base.disp); - const struct dp_rates *cfg = nvkm_dp_rates; - struct dp_state _dp = { - .outp = outp, - }, *dp = &_dp; - u32 datarate = 0; - u8 pwr; - int ret; - - if (!outp->base.info.location && disp->func->sor.magic) - disp->func->sor.magic(&outp->base); - - /* bring capabilities within encoder limits */ - if (disp->base.engine.subdev.device->chipset < 0xd0) - outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; - if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { - outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; - outp->dpcd[2] |= outp->base.info.dpconf.link_nr; - } - if (outp->dpcd[1] > outp->base.info.dpconf.link_bw) - outp->dpcd[1] = outp->base.info.dpconf.link_bw; - dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; - - /* restrict link config to the lowest required rate, if requested */ - if (datarate) { - datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */ - while (cfg[1].rate >= datarate) - cfg++; - } - cfg--; - - /* ensure sink is not in a low-power state */ - if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) { - if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { - pwr &= ~DPCD_SC00_SET_POWER; - pwr |= DPCD_SC00_SET_POWER_D0; - nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1); - } - } - - /* enable down-spreading and execute pre-train script from vbios */ - dp_link_train_init(dp, outp->dpcd[3] & 0x01); - - while (ret = -EIO, (++cfg)->rate) { - /* select next configuration supported by encoder and sink */ - while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || - cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE])) - cfg++; - dp->link_bw = cfg->bw * 27000; - dp->link_nr = cfg->nr; - - /* program selected link configuration */ - ret = dp_set_link_config(dp); - if (ret == 0) { - /* attempt to train the link at this configuration */ - memset(dp->stat, 0x00, sizeof(dp->stat)); - if (!dp_link_train_cr(dp) && - !dp_link_train_eq(dp)) - break; - } else - if (ret) { - /* dp_set_link_config() handled training, or - * we failed to communicate with the sink. - */ - break; - } - } - - /* finish link training and execute post-train script from vbios */ - dp_set_training_pattern(dp, 0); - if (ret < 0) - OUTP_ERR(&outp->base, "link training failed"); - - dp_link_train_fini(dp); - - OUTP_DBG(&outp->base, "training complete"); - atomic_set(&outp->lt.done, 1); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 3e3e592cd09f..0db964764ced 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -28,7 +28,7 @@ static const struct nv50_disp_func g84_disp = { .intr = nv50_disp_intr, .uevent = &nv50_disp_chan_uevent, - .super = nv50_disp_intr_supervisor, + .super = nv50_disp_super, .root = &g84_disp_root_oclass, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 7a7af3b478f8..3f3cdbc3363a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -28,7 +28,7 @@ static const struct nv50_disp_func g94_disp = { .intr = nv50_disp_intr, .uevent = &nv50_disp_chan_uevent, - .super = nv50_disp_intr_supervisor, + .super = nv50_disp_super, .root = &g94_disp_root_oclass, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 7b346ccc38b7..8d1e535af208 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -358,7 +358,7 @@ gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) } void -gf119_disp_intr_supervisor(struct work_struct *work) +gf119_disp_super(struct work_struct *work) { struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); @@ -510,7 +510,7 @@ gf119_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gf119_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 37f145cf30d7..ec14cef92de5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -29,7 +29,7 @@ gk104_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gk104_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index e14ac946608c..88f977660e41 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -29,7 +29,7 @@ gk110_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gk110_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 2f2437cc5891..5d7a2f42a4f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -29,7 +29,7 @@ gm107_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gm107_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 9f368d4ee61e..54fa9ebe346b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -29,7 +29,7 @@ gm200_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gm200_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 4f81bf31435e..6f4e56d82421 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -29,7 +29,7 @@ gp100_disp = { .intr = gf119_disp_intr, .intr_error = gf119_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index f5d613f82709..54b97e1dce0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -55,7 +55,7 @@ gp102_disp = { .intr = gf119_disp_intr, .intr_error = gp102_disp_intr_error, .uevent = &gf119_disp_chan_uevent, - .super = gf119_disp_intr_supervisor, + .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 6bc3bf096001..da6c395050de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -28,7 +28,7 @@ static const struct nv50_disp_func gt200_disp = { .intr = nv50_disp_intr, .uevent = &nv50_disp_chan_uevent, - .super = nv50_disp_intr_supervisor, + .super = nv50_disp_super, .root = >200_disp_root_oclass, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 94026288ab4d..1f475cf284e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -28,7 +28,7 @@ static const struct nv50_disp_func gt215_disp = { .intr = nv50_disp_intr, .uevent = &nv50_disp_chan_uevent, - .super = nv50_disp_intr_supervisor, + .super = nv50_disp_super, .root = >215_disp_root_oclass, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c similarity index 98% rename from drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c rename to drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c index e04f2e8137d2..e82c68f18444 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.c @@ -1,4 +1,4 @@ -#include "nv50.h" +#include "hdmi.h" void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame, u8 *raw_frame, ssize_t len) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h new file mode 100644 index 000000000000..35a825192264 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_DISP_HDMI_H__ +#define __NVKM_DISP_HDMI_H__ +#include "nv50.h" + +struct packed_hdmi_infoframe { + u32 header; + u32 subpack0_low; + u32 subpack0_high; + u32 subpack1_low; + u32 subpack1_high; +}; + +void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame, + u8 *raw_frame, ssize_t len); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 139344eb5b72..f25d8c7fba67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "hdmi.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index d80e86c12ee9..8dc6a79c8141 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "hdmi.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index 99d27314b511..1be2ecb1ebbc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "hdmi.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index 257f7c72d566..16c63fe05539 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "hdmi.h" #include "outp.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 0db8efbf1c2e..025cc0d7feb3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -175,55 +175,6 @@ nv50_disp_vblank_init(struct nv50_disp *disp, int head) nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); } -static const struct nvkm_enum -nv50_disp_intr_error_type[] = { - { 3, "ILLEGAL_MTHD" }, - { 4, "INVALID_VALUE" }, - { 5, "INVALID_STATE" }, - { 7, "INVALID_HANDLE" }, - {} -}; - -static const struct nvkm_enum -nv50_disp_intr_error_code[] = { - { 0x00, "" }, - {} -}; - -static void -nv50_disp_intr_error(struct nv50_disp *disp, int chid) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); - u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); - u32 code = (addr & 0x00ff0000) >> 16; - u32 type = (addr & 0x00007000) >> 12; - u32 mthd = (addr & 0x00000ffc); - const struct nvkm_enum *ec, *et; - - et = nvkm_enum_find(nv50_disp_intr_error_type, type); - ec = nvkm_enum_find(nv50_disp_intr_error_code, code); - - nvkm_error(subdev, - "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n", - type, et ? et->name : "", code, ec ? ec->name : "", - chid, mthd, data); - - if (chid < ARRAY_SIZE(disp->chan)) { - switch (mthd) { - case 0x0080: - nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); - break; - default: - break; - } - } - - nvkm_wr32(device, 0x610020, 0x00010000 << chid); - nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000); -} - static struct nvkm_output * exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -426,182 +377,46 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -static bool -nv50_disp_dptmds_war(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x94: - case 0x96: - case 0x98: - return true; - default: - break; - } - return false; -} - -static bool -nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) +/* If programming a TMDS output on a SOR that can also be configured for + * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. + * + * It looks like the VBIOS TMDS scripts make an attempt at this, however, + * the VBIOS scripts on at least one board I have only switch it off on + * link 0, causing a blank display if the output has previously been + * programmed for DisplayPort. + */ +static void +nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, + struct dcb_output *outp) { struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; - if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { - switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { - case 0x00000000: - case 0x00030000: - return true; - default: - break; - } - } - return false; + struct nvkm_bios *bios = device->bios; + const int link = !(outp->sorconf.link & 1); + const int or = ffs(outp->or) - 1; + const u32 loff = (or * 0x800) + (link * 0x80); + const u16 mask = (outp->sorconf.link << 6) | outp->or; + struct dcb_output match; + u8 ver, hdr; + if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) + nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); } static void -nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) +nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) { struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; - - if (!nv50_disp_dptmds_war_needed(disp, outp)) - return; - - nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000); - nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000); - nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001); - - nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000); - nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000); - nvkm_usec(device, 400, NVKM_DELAY); - nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000); - nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000); - - if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) { - u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); - u32 pu_pc = seqctl & 0x0000000f; - nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000); - } -} - -static void -nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; - u32 sorpwr; - - if (!nv50_disp_dptmds_war_needed(disp, outp)) - return; - - sorpwr = nvkm_rd32(device, 0x61c004 + soff); - if (sorpwr & 0x00000001) { - u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); - u32 pd_pc = (seqctl & 0x00000f00) >> 8; - u32 pu_pc = seqctl & 0x0000000f; - - nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000); - - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) - break; - ); - nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) - break; - ); - - nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000); - nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000); - } - - nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000); - nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000); - - if (sorpwr & 0x00000001) { - nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); - } -} - -static void -nv50_disp_update_sppll1(struct nv50_disp *disp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - bool used = false; - int sor; - - if (!nv50_disp_dptmds_war(device)) - return; - - for (sor = 0; sor < disp->func->sor.nr; sor++) { - u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800)); - switch (clksor & 0x03000000) { - case 0x02000000: - case 0x03000000: - used = true; - break; - default: - break; - } - } - - if (used) - return; - - nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); -} - -static void -nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) -{ - exec_script(disp, head, 1); -} - -static void -nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_output *outp = exec_script(disp, head, 2); - - /* the binary driver does this outside of the supervisor handling - * (after the third supervisor from a detach). we (currently?) - * allow both detach/attach to happen in the same set of - * supervisor interrupts, so it would make sense to execute this - * (full power down?) script after all the detach phases of the - * supervisor handling. like with training if needed from the - * second supervisor, nvidia doesn't do this, so who knows if it's - * entirely safe, but it does appear to work.. - * - * without this script being run, on some configurations i've - * seen, switching from DP to TMDS on a DP connector may result - * in a blank screen (SOR_PWR off/on can restore it) - */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - nvkm_notify_put(&outpdp->irq); - nvbios_exec(&init); - atomic_set(&outpdp->lt.done, 0); - } -} - -static void -nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_devinit *devinit = device->devinit; + struct nvkm_output *outp; u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - if (pclk) - nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); + u32 conf; + + outp = exec_clkcmp(disp, head, 1, pclk, &conf); + if (!outp) + return; + + if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) + nv50_disp_intr_unk40_0_tmds(disp, &outp->info); + nv50_disp_dptmds_war_3(disp, &outp->info); } static void @@ -810,50 +625,60 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) nv50_disp_dptmds_war_2(disp, &outp->info); } -/* If programming a TMDS output on a SOR that can also be configured for - * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. - * - * It looks like the VBIOS TMDS scripts make an attempt at this, however, - * the VBIOS scripts on at least one board I have only switch it off on - * link 0, causing a blank display if the output has previously been - * programmed for DisplayPort. - */ static void -nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, - struct dcb_output *outp) +nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) { struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const int link = !(outp->sorconf.link & 1); - const int or = ffs(outp->or) - 1; - const u32 loff = (or * 0x800) + (link * 0x80); - const u16 mask = (outp->sorconf.link << 6) | outp->or; - struct dcb_output match; - u8 ver, hdr; - - if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) - nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; + if (pclk) + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); } static void -nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) +nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) { - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - u32 conf; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_output *outp = exec_script(disp, head, 2); - outp = exec_clkcmp(disp, head, 1, pclk, &conf); - if (!outp) - return; + /* the binary driver does this outside of the supervisor handling + * (after the third supervisor from a detach). we (currently?) + * allow both detach/attach to happen in the same set of + * supervisor interrupts, so it would make sense to execute this + * (full power down?) script after all the detach phases of the + * supervisor handling. like with training if needed from the + * second supervisor, nvidia doesn't do this, so who knows if it's + * entirely safe, but it does appear to work.. + * + * without this script being run, on some configurations i've + * seen, switching from DP to TMDS on a DP connector may result + * in a blank screen (SOR_PWR off/on can restore it) + */ + if (outp && outp->info.type == DCB_OUTPUT_DP) { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + struct nvbios_init init = { + .subdev = subdev, + .bios = subdev->device->bios, + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; - if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) - nv50_disp_intr_unk40_0_tmds(disp, &outp->info); - nv50_disp_dptmds_war_3(disp, &outp->info); + nvkm_notify_put(&outpdp->irq); + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } +} + +static void +nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) +{ + exec_script(disp, head, 1); } void -nv50_disp_intr_supervisor(struct work_struct *work) +nv50_disp_super(struct work_struct *work) { struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); @@ -903,6 +728,55 @@ nv50_disp_intr_supervisor(struct work_struct *work) nvkm_wr32(device, 0x610030, 0x80000000); } +static const struct nvkm_enum +nv50_disp_intr_error_type[] = { + { 3, "ILLEGAL_MTHD" }, + { 4, "INVALID_VALUE" }, + { 5, "INVALID_STATE" }, + { 7, "INVALID_HANDLE" }, + {} +}; + +static const struct nvkm_enum +nv50_disp_intr_error_code[] = { + { 0x00, "" }, + {} +}; + +static void +nv50_disp_intr_error(struct nv50_disp *disp, int chid) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); + u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); + u32 code = (addr & 0x00ff0000) >> 16; + u32 type = (addr & 0x00007000) >> 12; + u32 mthd = (addr & 0x00000ffc); + const struct nvkm_enum *ec, *et; + + et = nvkm_enum_find(nv50_disp_intr_error_type, type); + ec = nvkm_enum_find(nv50_disp_intr_error_code, code); + + nvkm_error(subdev, + "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n", + type, et ? et->name : "", code, ec ? ec->name : "", + chid, mthd, data); + + if (chid < ARRAY_SIZE(disp->chan)) { + switch (mthd) { + case 0x0080: + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); + break; + default: + break; + } + } + + nvkm_wr32(device, 0x610020, 0x00010000 << chid); + nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000); +} + void nv50_disp_intr(struct nv50_disp *disp) { @@ -943,7 +817,7 @@ static const struct nv50_disp_func nv50_disp = { .intr = nv50_disp_intr, .uevent = &nv50_disp_chan_uevent, - .super = nv50_disp_intr_supervisor, + .super = nv50_disp_super, .root = &nv50_disp_root_oclass, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 37ec2a1032ef..4fa82f48429b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -2,8 +2,7 @@ #define __NV50_DISP_H__ #define nv50_disp(p) container_of((p), struct nv50_disp, base) #include "priv.h" -struct nvkm_output; -struct nvkm_output_dp; +#include "dp.h" #define NV50_DISP_MTHD_ struct nvkm_object *object, \ struct nv50_disp *disp, void *data, u32 size @@ -40,17 +39,6 @@ int nv50_dac_sense(NV50_DISP_MTHD_V1); int gt215_hda_eld(NV50_DISP_MTHD_V1); int gf119_hda_eld(NV50_DISP_MTHD_V1); -struct packed_hdmi_infoframe { - u32 header; - u32 subpack0_low; - u32 subpack0_high; - u32 subpack1_low; - u32 subpack1_high; -}; - -void pack_hdmi_infoframe(struct packed_hdmi_infoframe *packed_frame, - u8 *raw_frame, ssize_t len); - int g84_hdmi_ctrl(NV50_DISP_MTHD_V1); int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); @@ -120,11 +108,15 @@ struct nv50_disp_func { void nv50_disp_vblank_init(struct nv50_disp *, int); void nv50_disp_vblank_fini(struct nv50_disp *, int); void nv50_disp_intr(struct nv50_disp *); -void nv50_disp_intr_supervisor(struct work_struct *); +void nv50_disp_super(struct work_struct *); void gf119_disp_vblank_init(struct nv50_disp *, int); void gf119_disp_vblank_fini(struct nv50_disp *, int); void gf119_disp_intr(struct nv50_disp *); -void gf119_disp_intr_supervisor(struct work_struct *); +void gf119_disp_super(struct work_struct *); void gf119_disp_intr_error(struct nv50_disp *, int); + +void nv50_disp_dptmds_war_2(struct nv50_disp *, struct dcb_output *); +void nv50_disp_dptmds_war_3(struct nv50_disp *, struct dcb_output *); +void nv50_disp_update_sppll1(struct nv50_disp *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c deleted file mode 100644 index de36f73b14dc..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2014 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "outpdp.h" -#include "conn.h" -#include "dport.h" -#include "priv.h" - -#include - -#include - -int -nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) -{ - struct nvkm_output_dp *outp = nvkm_output_dp(base); - bool retrain = true; - u8 link[2], stat[3]; - u32 linkrate; - int ret, i; - - mutex_lock(&outp->mutex); - - /* check that the link is trained at a high enough rate */ - ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); - if (ret) { - OUTP_DBG(&outp->base, - "failed to read link config, assuming no sink"); - goto done; - } - - linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET); - linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ - datarate = (datarate + 9) / 10; /* -> decakilobits */ - if (linkrate < datarate) { - OUTP_DBG(&outp->base, "link not trained at sufficient rate"); - goto done; - } - - /* check that link is still trained */ - ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); - if (ret) { - OUTP_DBG(&outp->base, - "failed to read link status, assuming no sink"); - goto done; - } - - if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { - for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) { - u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; - if (!(lane & DPCD_LS02_LANE0_CR_DONE) || - !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || - !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - OUTP_DBG(&outp->base, - "lane %d not equalised", lane); - goto done; - } - } - retrain = false; - } else { - OUTP_DBG(&outp->base, "no inter-lane alignment"); - } - -done: - if (retrain || !atomic_read(&outp->lt.done)) { - /* no sink, but still need to configure source */ - if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { - outp->dpcd[DPCD_RC01_MAX_LINK_RATE] = - outp->base.info.dpconf.link_bw; - outp->dpcd[DPCD_RC02] = - outp->base.info.dpconf.link_nr; - } - nvkm_dp_train(outp); - } - - mutex_unlock(&outp->mutex); - return ret; -} - -static void -nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) -{ - struct nvkm_i2c_aux *aux = outp->aux; - - if (enable) { - if (!outp->present) { - OUTP_DBG(&outp->base, "aux power -> always"); - nvkm_i2c_aux_monitor(aux, true); - outp->present = true; - } - - if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, - sizeof(outp->dpcd))) { - nvkm_output_dp_train(&outp->base, 0); - return; - } - } - - if (outp->present) { - OUTP_DBG(&outp->base, "aux power -> demand"); - nvkm_i2c_aux_monitor(aux, false); - outp->present = false; - } - - atomic_set(&outp->lt.done, 0); -} - -static int -nvkm_output_dp_hpd(struct nvkm_notify *notify) -{ - const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); - struct nvkm_connector *conn = outp->base.conn; - struct nvkm_disp *disp = outp->base.disp; - struct nvif_notify_conn_rep_v0 rep = {}; - - OUTP_DBG(&outp->base, "HPD: %d", line->mask); - nvkm_output_dp_enable(outp, true); - - if (line->mask & NVKM_I2C_UNPLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; - if (line->mask & NVKM_I2C_PLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; - - nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; -} - -static int -nvkm_output_dp_irq(struct nvkm_notify *notify) -{ - const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); - struct nvkm_connector *conn = outp->base.conn; - struct nvkm_disp *disp = outp->base.disp; - struct nvif_notify_conn_rep_v0 rep = { - .mask = NVIF_NOTIFY_CONN_V0_IRQ, - }; - - OUTP_DBG(&outp->base, "IRQ: %d", line->mask); - nvkm_output_dp_train(&outp->base, 0); - - nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; -} - -static void -nvkm_output_dp_fini(struct nvkm_output *base) -{ - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_put(&outp->hpd); - nvkm_notify_put(&outp->irq); - nvkm_output_dp_enable(outp, false); -} - -static void -nvkm_output_dp_init(struct nvkm_output *base) -{ - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_put(&outp->base.conn->hpd); - nvkm_output_dp_enable(outp, true); - nvkm_notify_get(&outp->irq); - nvkm_notify_get(&outp->hpd); -} - -static void * -nvkm_output_dp_dtor(struct nvkm_output *base) -{ - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_fini(&outp->hpd); - nvkm_notify_fini(&outp->irq); - return outp; -} - -static const struct nvkm_output_func -nvkm_output_dp_func = { - .dtor = nvkm_output_dp_dtor, - .init = nvkm_output_dp_init, - .fini = nvkm_output_dp_fini, -}; - -int -nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) -{ - struct nvkm_device *device = disp->engine.subdev.device; - struct nvkm_bios *bios = device->bios; - struct nvkm_i2c *i2c = device->i2c; - u8 hdr, cnt, len; - u32 data; - int ret; - - nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); - outp->func = func; - outp->aux = aux; - if (!outp->aux) { - OUTP_ERR(&outp->base, "no aux"); - return -ENODEV; - } - - /* bios data is not optional */ - data = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, &outp->version, - &hdr, &cnt, &len, &outp->info); - if (!data) { - OUTP_ERR(&outp->base, "no bios dp data"); - return -ENODEV; - } - - OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", - outp->version, hdr, cnt, len); - - /* link maintenance */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, - &(struct nvkm_i2c_ntfy_req) { - .mask = NVKM_I2C_IRQ, - .port = outp->aux->id, - }, - sizeof(struct nvkm_i2c_ntfy_req), - sizeof(struct nvkm_i2c_ntfy_rep), - &outp->irq); - if (ret) { - OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); - return ret; - } - - mutex_init(&outp->mutex); - atomic_set(&outp->lt.done, 0); - - /* hotplug detect, replaces gpio-based mechanism with aux events */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, - &(struct nvkm_i2c_ntfy_req) { - .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - .port = outp->aux->id, - }, - sizeof(struct nvkm_i2c_ntfy_req), - sizeof(struct nvkm_i2c_ntfy_rep), - &outp->hpd); - if (ret) { - OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); - return ret; - } - - return 0; -} - -int -nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) -{ - struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); - struct nvkm_output_dp *outp; - - if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) - return -ENOMEM; - *poutp = &outp->base; - - return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h deleted file mode 100644 index 3c83a561cd88..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __NVKM_DISP_OUTP_DP_H__ -#define __NVKM_DISP_OUTP_DP_H__ -#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) -#ifndef MSG -#define MSG(l,f,a...) \ - nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f, \ - outp->base.index, outp->base.info.hasht, \ - outp->base.info.hashm, ##a) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif -#include "outp.h" - -#include -#include -#include - -struct nvkm_output_dp { - const struct nvkm_output_dp_func *func; - struct nvkm_output base; - - struct nvbios_dpout info; - u8 version; - - struct nvkm_i2c_aux *aux; - - struct nvkm_notify irq; - struct nvkm_notify hpd; - bool present; - u8 dpcd[16]; - - struct mutex mutex; - struct { - atomic_t done; - bool mst; - } lt; -}; - -struct nvkm_output_dp_func { - int (*pattern)(struct nvkm_output_dp *, int); - int (*lnk_pwr)(struct nvkm_output_dp *, int nr); - int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); - int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); - void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, - u8 num_slots, u16 pbn, u16 aligned_pbn); -}; - -int nvkm_output_dp_train(struct nvkm_output *, u32 rate); - -int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_i2c_aux *, - struct nvkm_output_dp *); -int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, - int index, struct dcb_output *, - struct nvkm_output **); - -int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - -int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); - -int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); -int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int); -void gf119_sor_dp_vcpi(struct nvkm_output_dp *, int, u8, u8, u16, u16); - -int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int gm107_sor_dp_pattern(struct nvkm_output_dp *, int); - -int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 6c532eadba17..e7bfe8612cd6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,7 +21,6 @@ * * Authors: Ben Skeggs */ -#include "outpdp.h" #include "nv50.h" #include @@ -31,41 +30,6 @@ #include #include -int -nv50_pior_power(NV50_DISP_MTHD_V1) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp pior pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else - return ret; - - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - disp->pior.type[outp->or] = type; - return 0; -} - /****************************************************************************** * TMDS *****************************************************************************/ @@ -129,3 +93,38 @@ nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, index, dcbE, aux, outp); } + +int +nv50_pior_power(NV50_DISP_MTHD_V1) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_pior_pwr_v0 v0; + } *args = data; + u32 ctrl, type; + int ret = -ENOSYS; + + nvif_ioctl(object, "disp pior pwr size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); + if (args->v0.type > 0x0f) + return -EINVAL; + ctrl = !!args->v0.state; + type = args->v0.type; + } else + return ret; + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + disp->pior.type[outp->or] = type; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index c2452957fc57..e143fc7bc15f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -2,7 +2,6 @@ #define __NVKM_DISP_PRIV_H__ #include #include "outp.h" -#include "outpdp.h" int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 627b9ee1ddd2..732dda513752 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" #include @@ -54,6 +53,40 @@ g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) return g94[lane]; } +static int +g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) +{ + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + const u32 shift = g94_sor_dp_lane_map(device, ln); + const u32 loff = g94_sor_loff(outp); + u32 addr, data[3]; + u8 ver, hdr, cnt, len; + struct nvbios_dpout info; + struct nvbios_dpcfg ocfg; + + addr = nvbios_dpout_match(bios, outp->base.info.hasht, + outp->base.info.hashm, + &ver, &hdr, &cnt, &len, &info); + if (!addr) + return -ENODEV; + + addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, + &ver, &hdr, &cnt, &len, &ocfg); + if (!addr) + return -EINVAL; + + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); + if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) + data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); + return 0; +} + static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { @@ -103,40 +136,6 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) return 0; } -static int -g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(device, ln); - const u32 loff = g94_sor_loff(outp); - u32 addr, data[3]; - u8 ver, hdr, cnt, len; - struct nvbios_dpout info; - struct nvbios_dpcfg ocfg; - - addr = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); - if (!addr) - return -ENODEV; - - addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); - if (!addr) - return -EINVAL; - - data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nvkm_rd32(device, 0x61c130 + loff); - if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nvkm_wr32(device, 0x61c130 + loff, data[2]); - return 0; -} - static const struct nvkm_output_dp_func g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, @@ -151,3 +150,129 @@ g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, { return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); } + +static bool +nv50_disp_dptmds_war(struct nvkm_device *device) +{ + switch (device->chipset) { + case 0x94: + case 0x96: + case 0x98: + return true; + default: + break; + } + return false; +} + +static bool +nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { + switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { + case 0x00000000: + case 0x00030000: + return true; + default: + break; + } + } + return false; + +} + +void +nv50_disp_update_sppll1(struct nv50_disp *disp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + bool used = false; + int sor; + + if (!nv50_disp_dptmds_war(device)) + return; + + for (sor = 0; sor < disp->func->sor.nr; sor++) { + u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800)); + switch (clksor & 0x03000000) { + case 0x02000000: + case 0x03000000: + used = true; + break; + default: + break; + } + } + + if (used) + return; + + nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); +} + +void +nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + u32 sorpwr; + + if (!nv50_disp_dptmds_war_needed(disp, outp)) + return; + + sorpwr = nvkm_rd32(device, 0x61c004 + soff); + if (sorpwr & 0x00000001) { + u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); + u32 pd_pc = (seqctl & 0x00000f00) >> 8; + u32 pu_pc = seqctl & 0x0000000f; + + nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x1f008000); + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); + + nvkm_wr32(device, 0x61c040 + soff + pd_pc * 4, 0x00002000); + nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f000000); + } + + nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x00000000); + + if (sorpwr & 0x00000001) { + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); + } +} + +void +nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = __ffs(outp->or) * 0x800; + + if (!nv50_disp_dptmds_war_needed(disp, outp)) + return; + + nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000); + nvkm_mask(device, 0x614300 + soff, 0x03000000, 0x03000000); + nvkm_mask(device, 0x61c10c + soff, 0x00000001, 0x00000001); + + nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x00000000); + nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x14000000); + nvkm_usec(device, 400, NVKM_DELAY); + nvkm_mask(device, 0x61c008 + soff, 0xff000000, 0x00000000); + nvkm_mask(device, 0x61c00c + soff, 0x0f000000, 0x01000000); + + if (nvkm_rd32(device, 0x61c004 + soff) & 0x00000001) { + u32 seqctl = nvkm_rd32(device, 0x61c030 + soff); + u32 pu_pc = seqctl & 0x0000000f; + nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000); + } +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 6ffdaa65aa77..dcdb0faaa87a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -22,7 +22,17 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" + +void +gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, + u8 slot_nr, u16 pbn, u16 aligned) +{ + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 hoff = head * 0x800; + + nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot); + nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn); +} static inline u32 gf119_sor_soff(struct nvkm_output_dp *outp) @@ -36,36 +46,6 @@ gf119_sor_loff(struct nvkm_output_dp *outp) return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } -static int -gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gf119_sor_soff(outp); - nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); - return 0; -} - -int -gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gf119_sor_soff(outp); - const u32 loff = gf119_sor_loff(outp); - u32 dpctrl = 0x00000000; - u32 clksor = 0x00000000; - - clksor |= bw << 18; - dpctrl |= ((1 << nr) - 1) << 16; - if (outp->lt.mst) - dpctrl |= 0x40000000; - if (ef) - dpctrl |= 0x00004000; - - nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); - nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl); - return 0; -} - int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) @@ -103,15 +83,34 @@ gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -void -gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, - u8 slot_nr, u16 pbn, u16 aligned) +static int +gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 hoff = head * 0x800; + const u32 soff = gf119_sor_soff(outp); + nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); + return 0; +} - nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot); - nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn); +int +gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +{ + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 soff = gf119_sor_soff(outp); + const u32 loff = gf119_sor_loff(outp); + u32 dpctrl = 0x00000000; + u32 clksor = 0x00000000; + + clksor |= bw << 18; + dpctrl |= ((1 << nr) - 1) << 16; + if (outp->lt.mst) + dpctrl |= 0x40000000; + if (ef) + dpctrl |= 0x00004000; + + nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); + nvkm_mask(device, 0x61c10c + loff, 0x401f4000, dpctrl); + return 0; } static const struct nvkm_output_dp_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 4cf8ad4d18ab..7fcaf0378e81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" int gm107_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 81b788fa61be..82b1f64b83b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" #include @@ -38,44 +37,12 @@ gm200_sor_loff(struct nvkm_output_dp *outp) return gm200_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } -void -gm200_sor_magic(struct nvkm_output *outp) -{ - struct nvkm_device *device = outp->disp->engine.subdev.device; - const u32 soff = outp->or * 0x100; - const u32 data = outp->or + 1; - if (outp->info.sorconf.link & 1) - nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data); - if (outp->info.sorconf.link & 2) - nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); -} - static inline u32 gm200_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { return lane * 0x08; } -static int -gm200_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gm200_sor_soff(outp); - const u32 loff = gm200_sor_loff(outp); - u32 mask = 0, i; - - for (i = 0; i < nr; i++) - mask |= 1 << (gm200_sor_dp_lane_map(device, i) >> 3); - - nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); - nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) - break; - ); - return 0; -} - static int gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) @@ -114,6 +81,26 @@ gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } +static int +gm200_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +{ + struct nvkm_device *device = outp->base.disp->engine.subdev.device; + const u32 soff = gm200_sor_soff(outp); + const u32 loff = gm200_sor_loff(outp); + u32 mask = 0, i; + + for (i = 0; i < nr; i++) + mask |= 1 << (gm200_sor_dp_lane_map(device, i) >> 3); + + nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); + nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) + break; + ); + return 0; +} + static const struct nvkm_output_dp_func gm200_sor_dp_func = { .pattern = gm107_sor_dp_pattern, @@ -129,3 +116,15 @@ gm200_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, { return nvkm_output_dp_new_(&gm200_sor_dp_func, disp, index, dcbE, poutp); } + +void +gm200_sor_magic(struct nvkm_output *outp) +{ + struct nvkm_device *device = outp->disp->engine.subdev.device; + const u32 soff = outp->or * 0x100; + const u32 data = outp->or + 1; + if (outp->info.sorconf.link & 1) + nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + if (outp->info.sorconf.link & 2) + nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 53596bed3c36..83f44170ddd3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -30,6 +30,18 @@ #include #include +static const struct nvkm_output_func +nv50_sor_output_func = { +}; + +int +nv50_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_sor_output_func, disp, + index, dcbE, poutp); +} + int nv50_sor_power(NV50_DISP_MTHD_V1) { @@ -65,15 +77,3 @@ nv50_sor_power(NV50_DISP_MTHD_V1) ); return 0; } - -static const struct nvkm_output_func -nv50_sor_output_func = { -}; - -int -nv50_sor_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_new_(&nv50_sor_output_func, disp, - index, dcbE, poutp); -} From d7ce92e27303082f00cf0976d673f4cc0a5f1c5f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 24/73] drm/nouveau/disp: rename nvkm_output to nvkm_outp This isn't technically "output", but, "display/output path". Not all users of nvkm_output have been changed here. The remaining ones belong to code that's disappearing in upcoming commits. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 22 ++++++------- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 20 +++++------ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 33 +++++++++++-------- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 3 +- 5 files changed, 42 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 1efe91b1e22b..53309214718b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -96,7 +96,7 @@ nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size, union { struct nvif_notify_conn_req_v0 v0; } *req = data; - struct nvkm_output *outp; + struct nvkm_outp *outp; int ret = -ENOSYS; if (!(ret = nvif_unpack(ret, &data, &size, req->v0, 0, 0, false))) { @@ -211,10 +211,10 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) { struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; - struct nvkm_output *outp; + struct nvkm_outp *outp; list_for_each_entry(outp, &disp->outp, head) { - nvkm_output_fini(outp); + nvkm_outp_fini(outp); } list_for_each_entry(conn, &disp->conn, head) { @@ -229,14 +229,14 @@ nvkm_disp_init(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; - struct nvkm_output *outp; + struct nvkm_outp *outp; list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_init(conn); } list_for_each_entry(outp, &disp->outp, head) { - nvkm_output_init(outp); + nvkm_outp_init(outp); } return 0; @@ -247,7 +247,7 @@ nvkm_disp_dtor(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; - struct nvkm_output *outp; + struct nvkm_outp *outp; void *data = disp; if (disp->func->dtor) @@ -259,7 +259,7 @@ nvkm_disp_dtor(struct nvkm_engine *engine) while (!list_empty(&disp->outp)) { outp = list_first_entry(&disp->outp, typeof(*outp), head); list_del(&outp->head); - nvkm_output_del(&outp); + nvkm_outp_del(&outp); } while (!list_empty(&disp->conn)) { @@ -285,7 +285,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, int index, int heads, struct nvkm_disp *disp) { struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp, *outt, *pair; + struct nvkm_outp *outp, *outt, *pair; struct nvkm_connector *conn; struct nvbios_connE connE; struct dcb_output dcbE; @@ -307,7 +307,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { const struct nvkm_disp_func_outp *outps; int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); + struct nvkm_outp **); if (dcbE.type == DCB_OUTPUT_UNUSED) continue; @@ -350,7 +350,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, } nvkm_error(&disp->engine.subdev, "failed to create output %d\n", i); - nvkm_output_del(&outp); + nvkm_outp_del(&outp); continue; } @@ -411,7 +411,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, outp->index, ret); nvkm_connector_del(&outp->conn); list_del(&outp->head); - nvkm_output_del(&outp); + nvkm_outp_del(&outp); continue; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 1a3c460bcfe9..35d9f0fc3fe8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -566,7 +566,7 @@ nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, u32 data; int ret; - nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); + nvkm_outp_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); outp->func = func; outp->aux = aux; if (!outp->aux) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index bbe5ec0dedb2..f030ff51d076 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -28,23 +28,23 @@ #include void -nvkm_output_fini(struct nvkm_output *outp) +nvkm_outp_fini(struct nvkm_outp *outp) { if (outp->func->fini) outp->func->fini(outp); } void -nvkm_output_init(struct nvkm_output *outp) +nvkm_outp_init(struct nvkm_outp *outp) { if (outp->func->init) outp->func->init(outp); } void -nvkm_output_del(struct nvkm_output **poutp) +nvkm_outp_del(struct nvkm_outp **poutp) { - struct nvkm_output *outp = *poutp; + struct nvkm_outp *outp = *poutp; if (outp && !WARN_ON(!outp->func)) { if (outp->func->dtor) *poutp = outp->func->dtor(outp); @@ -54,8 +54,8 @@ nvkm_output_del(struct nvkm_output **poutp) } void -nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, - int index, struct dcb_output *dcbE, struct nvkm_output *outp) +nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, + int index, struct dcb_output *dcbE, struct nvkm_outp *outp) { struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; @@ -75,13 +75,13 @@ nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, } int -nvkm_output_new_(const struct nvkm_output_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) +nvkm_outp_new_(const struct nvkm_outp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_outp **poutp) { if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) return -ENOMEM; - nvkm_output_ctor(func, disp, index, dcbE, *poutp); + nvkm_outp_ctor(func, disp, index, dcbE, *poutp); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 07727198d7ce..b3e3030d6ef4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -5,8 +5,8 @@ #include #include -struct nvkm_output { - const struct nvkm_output_func *func; +struct nvkm_outp { + const struct nvkm_outp_func *func; struct nvkm_disp *disp; int index; struct dcb_output info; @@ -19,19 +19,24 @@ struct nvkm_output { struct nvkm_connector *conn; }; -struct nvkm_output_func { - void *(*dtor)(struct nvkm_output *); - void (*init)(struct nvkm_output *); - void (*fini)(struct nvkm_output *); +void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_outp *); +void nvkm_outp_del(struct nvkm_outp **); +void nvkm_outp_init(struct nvkm_outp *); +void nvkm_outp_fini(struct nvkm_outp *); + +struct nvkm_outp_func { + void *(*dtor)(struct nvkm_outp *); + void (*init)(struct nvkm_outp *); + void (*fini)(struct nvkm_outp *); }; -void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_output *); -int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_output **); -void nvkm_output_del(struct nvkm_output **); -void nvkm_output_init(struct nvkm_output *); -void nvkm_output_fini(struct nvkm_output *); +#define nvkm_output nvkm_outp +#define nvkm_output_func nvkm_outp_func +#define nvkm_output_new_ nvkm_outp_new_ + +int nvkm_outp_new_(const struct nvkm_outp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output **); int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); @@ -45,7 +50,7 @@ u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); void gm200_sor_magic(struct nvkm_output *outp); #define OUTP_MSG(o,l,f,a...) do { \ - struct nvkm_output *_outp = (o); \ + struct nvkm_outp *_outp = (o); \ nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \ } while(0) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index e70dc6a9ff7d..2e73aeb86070 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -76,8 +76,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) struct nv50_disp_root *root = nv50_disp_root(object); struct nv50_disp *disp = root->disp; const struct nv50_disp_func *func = disp->func; - struct nvkm_output *outp = NULL; - struct nvkm_output *temp; + struct nvkm_outp *temp, *outp = NULL; u16 type, mask = 0; int head, ret = -ENOSYS; From f3e70d2991df5591263f2e9f83e74cc047462240 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 25/73] drm/nouveau/disp: rename nvkm_output_dp to nvkm_dp Not all users of nvkm_output_dp have been changed here. The remaining ones belong to code that's disappearing in upcoming commits. This also modifies the debug level of some messages. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 325 +++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 31 +- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 13 +- 3 files changed, 181 insertions(+), 188 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 35d9f0fc3fe8..8a68761edc49 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -32,7 +32,7 @@ #include struct lt_state { - struct nvkm_output_dp *outp; + struct nvkm_dp *dp; int link_nr; u32 link_bw; u8 stat[6]; @@ -45,26 +45,26 @@ struct lt_state { static int nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) { - struct nvkm_output_dp *outp = lt->outp; + struct nvkm_dp *dp = lt->dp; int ret; - if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) - mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); + if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) + mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); else udelay(delay); - ret = nvkm_rdaux(outp->aux, DPCD_LS02, lt->stat, 6); + ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6); if (ret) return ret; if (pc) { - ret = nvkm_rdaux(outp->aux, DPCD_LS0C, <->pc2stat, 1); + ret = nvkm_rdaux(dp->aux, DPCD_LS0C, <->pc2stat, 1); if (ret) lt->pc2stat = 0x00; - OUTP_DBG(&outp->base, "status %6ph pc2 %02x", - lt->stat, lt->pc2stat); + OUTP_TRACE(&dp->outp, "status %6ph pc2 %02x", + lt->stat, lt->pc2stat); } else { - OUTP_DBG(&outp->base, "status %6ph", lt->stat); + OUTP_TRACE(&dp->outp, "status %6ph", lt->stat); } return 0; @@ -73,7 +73,7 @@ nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) static int nvkm_dp_train_drive(struct lt_state *lt, bool pc) { - struct nvkm_output_dp *outp = lt->outp; + struct nvkm_dp *dp = lt->dp; int ret, i; for (i = 0; i < lt->link_nr; i++) { @@ -98,17 +98,17 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) lt->conf[i] = (lpre << 3) | lvsw; lt->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); - OUTP_DBG(&outp->base, "config lane %d %02x %02x", - i, lt->conf[i], lpc2); - outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", + i, lt->conf[i], lpc2); + dp->func->drv_ctl(dp, i, lvsw & 3, lpre & 3, lpc2 & 3); } - ret = nvkm_wraux(outp->aux, DPCD_LC03(0), lt->conf, 4); + ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4); if (ret) return ret; if (pc) { - ret = nvkm_wraux(outp->aux, DPCD_LC0F, lt->pc2conf, 2); + ret = nvkm_wraux(dp->aux, DPCD_LC0F, lt->pc2conf, 2); if (ret) return ret; } @@ -119,26 +119,25 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) static void nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) { - struct nvkm_output_dp *outp = lt->outp; + struct nvkm_dp *dp = lt->dp; u8 sink_tp; - OUTP_DBG(&outp->base, "training pattern %d", pattern); - outp->func->pattern(outp, pattern); + OUTP_TRACE(&dp->outp, "training pattern %d", pattern); + dp->func->pattern(dp, pattern); - nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); + nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; - nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1); + nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); } static int nvkm_dp_train_eq(struct lt_state *lt) { - struct nvkm_output_dp *outp = lt->outp; bool eq_done = false, cr_done = true; int tries = 0, i; - if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) + if (lt->dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) nvkm_dp_train_pattern(lt, 3); else nvkm_dp_train_pattern(lt, 2); @@ -200,15 +199,15 @@ nvkm_dp_train_cr(struct lt_state *lt) static int nvkm_dp_train_links(struct lt_state *lt) { - struct nvkm_output_dp *outp = lt->outp; - struct nvkm_disp *disp = outp->base.disp; + struct nvkm_dp *dp = lt->dp; + struct nvkm_disp *disp = dp->outp.disp; struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvkm_bios *bios = subdev->device->bios; struct nvbios_init init = { .subdev = subdev, .bios = bios, .offset = 0x0000, - .outp = &outp->base.info, + .outp = &dp->outp.info, .crtc = -1, .execute = 1, }; @@ -216,16 +215,16 @@ nvkm_dp_train_links(struct lt_state *lt) u8 sink[2]; int ret; - OUTP_DBG(&outp->base, "%d lanes at %d KB/s", lt->link_nr, lt->link_bw); + OUTP_DBG(&dp->outp, "%d lanes at %d KB/s", lt->link_nr, lt->link_bw); /* Intersect misc. capabilities of the OR and sink. */ if (disp->engine.subdev.device->chipset < 0xd0) - outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; - lt->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; + dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; + lt->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; /* Set desired link configuration on the source. */ - if ((lnkcmp = lt->outp->info.lnkcmp)) { - if (outp->version < 0x30) { + if ((lnkcmp = lt->dp->info.lnkcmp)) { + if (dp->version < 0x30) { while ((lt->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; init.offset = nvbios_rd16(bios, lnkcmp + 2); @@ -238,68 +237,66 @@ nvkm_dp_train_links(struct lt_state *lt) nvbios_exec(&init); } - ret = outp->func->lnk_ctl(outp, lt->link_nr, lt->link_bw / 27000, - outp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = dp->func->lnk_ctl(dp, lt->link_nr, lt->link_bw / 27000, + dp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) - OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); + OUTP_ERR(&dp->outp, "lnk_ctl failed with %d", ret); return ret; } - outp->func->lnk_pwr(outp, lt->link_nr); + dp->func->lnk_pwr(dp, lt->link_nr); /* Set desired link configuration on the sink. */ sink[0] = lt->link_bw / 27000; sink[1] = lt->link_nr; - if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) + if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); + return nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); } static void nvkm_dp_train_fini(struct lt_state *lt) { - struct nvkm_output_dp *outp = lt->outp; - struct nvkm_disp *disp = outp->base.disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_dp *dp = lt->dp; + struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; struct nvbios_init init = { .subdev = subdev, .bios = subdev->device->bios, - .outp = &outp->base.info, + .outp = &dp->outp.info, .crtc = -1, .execute = 1, }; /* Execute AfterLinkTraining script from DP Info table. */ - init.offset = outp->info.script[1], + init.offset = dp->info.script[1], nvbios_exec(&init); } static void nvkm_dp_train_init(struct lt_state *lt, bool spread) { - struct nvkm_output_dp *outp = lt->outp; - struct nvkm_disp *disp = outp->base.disp; - struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_dp *dp = lt->dp; + struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; struct nvbios_init init = { .subdev = subdev, .bios = subdev->device->bios, - .outp = &outp->base.info, + .outp = &dp->outp.info, .crtc = -1, .execute = 1, }; /* Execute EnableSpread/DisableSpread script from DP Info table. */ if (spread) - init.offset = outp->info.script[2]; + init.offset = dp->info.script[2]; else - init.offset = outp->info.script[3]; + init.offset = dp->info.script[3]; nvbios_exec(&init); - /* Execute BeforeLinkTraining script from DP info table. */ - init.offset = outp->info.script[0]; + /* Execute BeforeLinkTraining script from DP Info table. */ + init.offset = dp->info.script[0]; nvbios_exec(&init); } @@ -321,41 +318,41 @@ static const struct dp_rates { }; static void -nvkm_dp_train(struct nvkm_output_dp *outp) +nvkm_dp_train(struct nvkm_dp *dp) { - struct nv50_disp *disp = nv50_disp(outp->base.disp); + struct nv50_disp *disp = nv50_disp(dp->outp.disp); const struct dp_rates *cfg = nvkm_dp_rates - 1; struct lt_state lt = { - .outp = outp, + .dp = dp, }; u8 pwr; int ret; - if (!outp->base.info.location && disp->func->sor.magic) - disp->func->sor.magic(&outp->base); + if (!dp->outp.info.location && disp->func->sor.magic) + disp->func->sor.magic(&dp->outp); - if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { - outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; - outp->dpcd[2] |= outp->base.info.dpconf.link_nr; + if ((dp->dpcd[2] & 0x1f) > dp->outp.info.dpconf.link_nr) { + dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; + dp->dpcd[2] |= dp->outp.info.dpconf.link_nr; } - if (outp->dpcd[1] > outp->base.info.dpconf.link_bw) - outp->dpcd[1] = outp->base.info.dpconf.link_bw; + if (dp->dpcd[1] > dp->outp.info.dpconf.link_bw) + dp->dpcd[1] = dp->outp.info.dpconf.link_bw; /* Ensure sink is not in a low-power state. */ - if (!nvkm_rdaux(outp->aux, DPCD_SC00, &pwr, 1)) { + if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { pwr &= ~DPCD_SC00_SET_POWER; pwr |= DPCD_SC00_SET_POWER_D0; - nvkm_wraux(outp->aux, DPCD_SC00, &pwr, 1); + nvkm_wraux(dp->aux, DPCD_SC00, &pwr, 1); } } /* Link training. */ - nvkm_dp_train_init(<, outp->dpcd[3] & 0x01); + nvkm_dp_train_init(<, dp->dpcd[3] & 0x01); while (ret = -EIO, (++cfg)->rate) { /* Skip configurations not supported by both OR and sink. */ - while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || - cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE])) + while (cfg->nr > (dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || + cfg->bw > (dp->dpcd[DPCD_RC01_MAX_LINK_RATE])) cfg++; lt.link_bw = cfg->bw * 27000; lt.link_nr = cfg->nr; @@ -379,27 +376,27 @@ nvkm_dp_train(struct nvkm_output_dp *outp) nvkm_dp_train_pattern(<, 0); nvkm_dp_train_fini(<); if (ret < 0) - OUTP_ERR(&outp->base, "link training failed"); + OUTP_ERR(&dp->outp, "training failed"); - OUTP_DBG(&outp->base, "training complete"); - atomic_set(&outp->lt.done, 1); + OUTP_DBG(&dp->outp, "training done"); + atomic_set(&dp->lt.done, 1); } int -nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) +nvkm_output_dp_train(struct nvkm_outp *outp, u32 datarate) { - struct nvkm_output_dp *outp = nvkm_output_dp(base); + struct nvkm_dp *dp = nvkm_dp(outp); bool retrain = true; u8 link[2], stat[3]; u32 linkrate; int ret, i; - mutex_lock(&outp->mutex); + mutex_lock(&dp->mutex); /* check that the link is trained at a high enough rate */ - ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); + ret = nvkm_rdaux(dp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { - OUTP_DBG(&outp->base, + OUTP_DBG(&dp->outp, "failed to read link config, assuming no sink"); goto done; } @@ -408,14 +405,14 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ datarate = (datarate + 9) / 10; /* -> decakilobits */ if (linkrate < datarate) { - OUTP_DBG(&outp->base, "link not trained at sufficient rate"); + OUTP_DBG(&dp->outp, "link not trained at sufficient rate"); goto done; } /* check that link is still trained */ - ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); + ret = nvkm_rdaux(dp->aux, DPCD_LS02, stat, 3); if (ret) { - OUTP_DBG(&outp->base, + OUTP_DBG(&dp->outp, "failed to read link status, assuming no sink"); goto done; } @@ -426,71 +423,71 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate) if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - OUTP_DBG(&outp->base, + OUTP_DBG(&dp->outp, "lane %d not equalised", lane); goto done; } } retrain = false; } else { - OUTP_DBG(&outp->base, "no inter-lane alignment"); + OUTP_DBG(&dp->outp, "no inter-lane alignment"); } done: - if (retrain || !atomic_read(&outp->lt.done)) { + if (retrain || !atomic_read(&dp->lt.done)) { /* no sink, but still need to configure source */ - if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { - outp->dpcd[DPCD_RC01_MAX_LINK_RATE] = - outp->base.info.dpconf.link_bw; - outp->dpcd[DPCD_RC02] = - outp->base.info.dpconf.link_nr; + if (dp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { + dp->dpcd[DPCD_RC01_MAX_LINK_RATE] = + dp->outp.info.dpconf.link_bw; + dp->dpcd[DPCD_RC02] = + dp->outp.info.dpconf.link_nr; } - nvkm_dp_train(outp); + nvkm_dp_train(dp); } - mutex_unlock(&outp->mutex); + mutex_unlock(&dp->mutex); return ret; } static void -nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) +nvkm_dp_enable(struct nvkm_dp *dp, bool enable) { - struct nvkm_i2c_aux *aux = outp->aux; + struct nvkm_i2c_aux *aux = dp->aux; if (enable) { - if (!outp->present) { - OUTP_DBG(&outp->base, "aux power -> always"); + if (!dp->present) { + OUTP_DBG(&dp->outp, "aux power -> always"); nvkm_i2c_aux_monitor(aux, true); - outp->present = true; + dp->present = true; } - if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, - sizeof(outp->dpcd))) { - nvkm_output_dp_train(&outp->base, 0); + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, + sizeof(dp->dpcd))) { + nvkm_output_dp_train(&dp->outp, 0); return; } } - if (outp->present) { - OUTP_DBG(&outp->base, "aux power -> demand"); + if (dp->present) { + OUTP_DBG(&dp->outp, "aux power -> demand"); nvkm_i2c_aux_monitor(aux, false); - outp->present = false; + dp->present = false; } - atomic_set(&outp->lt.done, 0); + atomic_set(&dp->lt.done, 0); } static int -nvkm_output_dp_hpd(struct nvkm_notify *notify) +nvkm_dp_hpd(struct nvkm_notify *notify) { const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); - struct nvkm_connector *conn = outp->base.conn; - struct nvkm_disp *disp = outp->base.disp; + struct nvkm_dp *dp = container_of(notify, typeof(*dp), hpd); + struct nvkm_connector *conn = dp->outp.conn; + struct nvkm_disp *disp = dp->outp.disp; struct nvif_notify_conn_rep_v0 rep = {}; - OUTP_DBG(&outp->base, "HPD: %d", line->mask); - nvkm_output_dp_enable(outp, true); + OUTP_DBG(&dp->outp, "HPD: %d", line->mask); + nvkm_dp_enable(dp, true); if (line->mask & NVKM_I2C_UNPLUG) rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; @@ -502,62 +499,61 @@ nvkm_output_dp_hpd(struct nvkm_notify *notify) } static int -nvkm_output_dp_irq(struct nvkm_notify *notify) +nvkm_dp_irq(struct nvkm_notify *notify) { const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); - struct nvkm_connector *conn = outp->base.conn; - struct nvkm_disp *disp = outp->base.disp; + struct nvkm_dp *dp = container_of(notify, typeof(*dp), irq); + struct nvkm_connector *conn = dp->outp.conn; + struct nvkm_disp *disp = dp->outp.disp; struct nvif_notify_conn_rep_v0 rep = { .mask = NVIF_NOTIFY_CONN_V0_IRQ, }; - OUTP_DBG(&outp->base, "IRQ: %d", line->mask); - nvkm_output_dp_train(&outp->base, 0); + OUTP_DBG(&dp->outp, "IRQ: %d", line->mask); + nvkm_output_dp_train(&dp->outp, 0); nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); return NVKM_NOTIFY_KEEP; } static void -nvkm_output_dp_fini(struct nvkm_output *base) +nvkm_dp_fini(struct nvkm_outp *outp) { - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_put(&outp->hpd); - nvkm_notify_put(&outp->irq); - nvkm_output_dp_enable(outp, false); + struct nvkm_dp *dp = nvkm_dp(outp); + nvkm_notify_put(&dp->hpd); + nvkm_notify_put(&dp->irq); + nvkm_dp_enable(dp, false); } static void -nvkm_output_dp_init(struct nvkm_output *base) +nvkm_dp_init(struct nvkm_outp *outp) { - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_put(&outp->base.conn->hpd); - nvkm_output_dp_enable(outp, true); - nvkm_notify_get(&outp->irq); - nvkm_notify_get(&outp->hpd); + struct nvkm_dp *dp = nvkm_dp(outp); + nvkm_notify_put(&dp->outp.conn->hpd); + nvkm_dp_enable(dp, true); + nvkm_notify_get(&dp->irq); + nvkm_notify_get(&dp->hpd); } static void * -nvkm_output_dp_dtor(struct nvkm_output *base) +nvkm_dp_dtor(struct nvkm_outp *outp) { - struct nvkm_output_dp *outp = nvkm_output_dp(base); - nvkm_notify_fini(&outp->hpd); - nvkm_notify_fini(&outp->irq); - return outp; + struct nvkm_dp *dp = nvkm_dp(outp); + nvkm_notify_fini(&dp->hpd); + nvkm_notify_fini(&dp->irq); + return dp; } -static const struct nvkm_output_func -nvkm_output_dp_func = { - .dtor = nvkm_output_dp_dtor, - .init = nvkm_output_dp_init, - .fini = nvkm_output_dp_fini, +static const struct nvkm_outp_func +nvkm_dp_func = { + .dtor = nvkm_dp_dtor, + .init = nvkm_dp_init, + .fini = nvkm_dp_fini, }; -int -nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) +static int +nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_i2c_aux *aux, struct nvkm_dp *dp) { struct nvkm_device *device = disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; @@ -566,54 +562,53 @@ nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, u32 data; int ret; - nvkm_outp_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); - outp->func = func; - outp->aux = aux; - if (!outp->aux) { - OUTP_ERR(&outp->base, "no aux"); + nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp); + dp->aux = aux; + if (!dp->aux) { + OUTP_ERR(&dp->outp, "no aux"); return -ENODEV; } /* bios data is not optional */ - data = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, &outp->version, - &hdr, &cnt, &len, &outp->info); + data = nvbios_dpout_match(bios, dp->outp.info.hasht, + dp->outp.info.hashm, &dp->version, + &hdr, &cnt, &len, &dp->info); if (!data) { - OUTP_ERR(&outp->base, "no bios dp data"); + OUTP_ERR(&dp->outp, "no bios dp data"); return -ENODEV; } - OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", - outp->version, hdr, cnt, len); + OUTP_DBG(&dp->outp, "bios dp %02x %02x %02x %02x", + dp->version, hdr, cnt, len); /* link maintenance */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_irq, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_IRQ, - .port = outp->aux->id, + .port = dp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), - &outp->irq); + &dp->irq); if (ret) { - OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); + OUTP_ERR(&dp->outp, "error monitoring aux irq: %d", ret); return ret; } - mutex_init(&outp->mutex); - atomic_set(&outp->lt.done, 0); + mutex_init(&dp->mutex); + atomic_set(&dp->lt.done, 0); /* hotplug detect, replaces gpio-based mechanism with aux events */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, + ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - .port = outp->aux->id, + .port = dp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), - &outp->hpd); + &dp->hpd); if (ret) { - OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); + OUTP_ERR(&dp->outp, "error monitoring aux hpd: %d", ret); return ret; } @@ -623,15 +618,21 @@ nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, int nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) + struct nvkm_outp **poutp) { struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); - struct nvkm_output_dp *outp; + struct nvkm_i2c_aux *aux; + struct nvkm_dp *dp; - if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + if (dcbE->location == 0) + aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_CCB(dcbE->i2c_index)); + else + aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); + + if (!(dp = kzalloc(sizeof(*dp), GFP_KERNEL))) return -ENOMEM; - *poutp = &outp->base; + dp->func = func; + *poutp = &dp->outp; - return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); + return nvkm_dp_ctor(disp, index, dcbE, aux, dp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index b0c0c6263477..65d6b478eb56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -1,15 +1,18 @@ -#ifndef __NVKM_DISP_OUTP_DP_H__ -#define __NVKM_DISP_OUTP_DP_H__ -#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) +#ifndef __NVKM_DISP_DP_H__ +#define __NVKM_DISP_DP_H__ +#define nvkm_dp(p) container_of((p), struct nvkm_dp, outp) #include "outp.h" #include #include #include -struct nvkm_output_dp { +struct nvkm_dp { const struct nvkm_output_dp_func *func; - struct nvkm_output base; + union { + struct nvkm_outp base; + struct nvkm_outp outp; + }; struct nvbios_dpout info; u8 version; @@ -28,6 +31,8 @@ struct nvkm_output_dp { } lt; }; +#define nvkm_output_dp nvkm_dp + struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); int (*lnk_pwr)(struct nvkm_output_dp *, int nr); @@ -39,29 +44,25 @@ struct nvkm_output_dp_func { int nvkm_output_dp_train(struct nvkm_output *, u32 rate); -int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_i2c_aux *, - struct nvkm_output_dp *); int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, - int index, struct dcb_output *, - struct nvkm_output **); + int index, struct dcb_output *, struct nvkm_output **); int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); +int g94_sor_dp_lnk_pwr(struct nvkm_dp *, int); int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); -int gf119_sor_dp_drv_ctl(struct nvkm_output_dp *, int, int, int, int); -void gf119_sor_dp_vcpi(struct nvkm_output_dp *, int, u8, u8, u16, u16); +int gf119_sor_dp_lnk_ctl(struct nvkm_dp *, int, int, bool); +int gf119_sor_dp_drv_ctl(struct nvkm_dp *, int, int, int, int); +void gf119_sor_dp_vcpi(struct nvkm_dp *, int, u8, u8, u16, u16); int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gm107_sor_dp_pattern(struct nvkm_output_dp *, int); +int gm107_sor_dp_pattern(struct nvkm_dp *, int); int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index e7bfe8612cd6..cf85f8324ad4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -81,17 +81,8 @@ int nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct nvkm_output **poutp) { - struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - struct nvkm_i2c_aux *aux = - nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); - struct nvkm_output_dp *outp; - - if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) - return -ENOMEM; - *poutp = &outp->base; - - return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, - index, dcbE, aux, outp); + return nvkm_output_dp_new_(&nv50_pior_output_dp_func, disp, + index, dcbE, poutp); } int From 981a8162e2f8282c90f6523324bb51720699bc6a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 26/73] drm/nouveau/disp: s/nvkm_connector/nvkm_conn/ Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 18 +++++++------- .../gpu/drm/nouveau/nvkm/engine/disp/conn.c | 24 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/disp/conn.h | 14 +++++------ drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 4 ++-- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 +- 5 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 53309214718b..34dc165394e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -210,7 +210,7 @@ static int nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_connector *conn; + struct nvkm_conn *conn; struct nvkm_outp *outp; list_for_each_entry(outp, &disp->outp, head) { @@ -218,7 +218,7 @@ nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) } list_for_each_entry(conn, &disp->conn, head) { - nvkm_connector_fini(conn); + nvkm_conn_fini(conn); } return 0; @@ -228,11 +228,11 @@ static int nvkm_disp_init(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_connector *conn; + struct nvkm_conn *conn; struct nvkm_outp *outp; list_for_each_entry(conn, &disp->conn, head) { - nvkm_connector_init(conn); + nvkm_conn_init(conn); } list_for_each_entry(outp, &disp->outp, head) { @@ -246,7 +246,7 @@ static void * nvkm_disp_dtor(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_connector *conn; + struct nvkm_conn *conn; struct nvkm_outp *outp; void *data = disp; @@ -265,7 +265,7 @@ nvkm_disp_dtor(struct nvkm_engine *engine) while (!list_empty(&disp->conn)) { conn = list_first_entry(&disp->conn, typeof(*conn), head); list_del(&conn->head); - nvkm_connector_del(&conn); + nvkm_conn_del(&conn); } return data; @@ -286,7 +286,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, { struct nvkm_bios *bios = device->bios; struct nvkm_outp *outp, *outt, *pair; - struct nvkm_connector *conn; + struct nvkm_conn *conn; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; @@ -404,12 +404,12 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, continue; /* apparently we need to create a new one! */ - ret = nvkm_connector_new(disp, i, &connE, &outp->conn); + ret = nvkm_conn_new(disp, i, &connE, &outp->conn); if (ret) { nvkm_error(&disp->engine.subdev, "failed to create output %d conn: %d\n", outp->index, ret); - nvkm_connector_del(&outp->conn); + nvkm_conn_del(&outp->conn); list_del(&outp->head); nvkm_outp_del(&outp); continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index c6910d644a3d..febc5c274488 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -30,9 +30,9 @@ #include static int -nvkm_connector_hpd(struct nvkm_notify *notify) +nvkm_conn_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); + struct nvkm_conn *conn = container_of(notify, typeof(*conn), hpd); struct nvkm_disp *disp = conn->disp; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; const struct nvkm_gpio_ntfy_rep *line = notify->data; @@ -52,21 +52,21 @@ nvkm_connector_hpd(struct nvkm_notify *notify) } void -nvkm_connector_fini(struct nvkm_connector *conn) +nvkm_conn_fini(struct nvkm_conn *conn) { nvkm_notify_put(&conn->hpd); } void -nvkm_connector_init(struct nvkm_connector *conn) +nvkm_conn_init(struct nvkm_conn *conn) { nvkm_notify_get(&conn->hpd); } void -nvkm_connector_del(struct nvkm_connector **pconn) +nvkm_conn_del(struct nvkm_conn **pconn) { - struct nvkm_connector *conn = *pconn; + struct nvkm_conn *conn = *pconn; if (conn) { nvkm_notify_fini(&conn->hpd); kfree(*pconn); @@ -75,8 +75,8 @@ nvkm_connector_del(struct nvkm_connector **pconn) } static void -nvkm_connector_ctor(struct nvkm_disp *disp, int index, - struct nvbios_connE *info, struct nvkm_connector *conn) +nvkm_conn_ctor(struct nvkm_disp *disp, int index, struct nvbios_connE *info, + struct nvkm_conn *conn) { static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; @@ -105,7 +105,7 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index, return; } - ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, + ret = nvkm_notify_init(NULL, &gpio->event, nvkm_conn_hpd, true, &(struct nvkm_gpio_ntfy_req) { .mask = NVKM_GPIO_TOGGLED, .line = func.line, @@ -122,11 +122,11 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index, } int -nvkm_connector_new(struct nvkm_disp *disp, int index, - struct nvbios_connE *info, struct nvkm_connector **pconn) +nvkm_conn_new(struct nvkm_disp *disp, int index, struct nvbios_connE *info, + struct nvkm_conn **pconn) { if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) return -ENOMEM; - nvkm_connector_ctor(disp, index, info, *pconn); + nvkm_conn_ctor(disp, index, info, *pconn); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index ed32fe7f1864..de962b7b026d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -6,7 +6,7 @@ #include #include -struct nvkm_connector { +struct nvkm_conn { struct nvkm_disp *disp; int index; struct nvbios_connE info; @@ -16,14 +16,14 @@ struct nvkm_connector { struct list_head head; }; -int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, - struct nvkm_connector **); -void nvkm_connector_del(struct nvkm_connector **); -void nvkm_connector_init(struct nvkm_connector *); -void nvkm_connector_fini(struct nvkm_connector *); +int nvkm_conn_new(struct nvkm_disp *, int index, struct nvbios_connE *, + struct nvkm_conn **); +void nvkm_conn_del(struct nvkm_conn **); +void nvkm_conn_init(struct nvkm_conn *); +void nvkm_conn_fini(struct nvkm_conn *); #define CONN_MSG(c,l,f,a...) do { \ - struct nvkm_connector *_conn = (c); \ + struct nvkm_conn *_conn = (c); \ nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ _conn->index, _conn->info.location, _conn->info.type, ##a); \ } while(0) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 8a68761edc49..d62e93bb0f70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -482,7 +482,7 @@ nvkm_dp_hpd(struct nvkm_notify *notify) { const struct nvkm_i2c_ntfy_rep *line = notify->data; struct nvkm_dp *dp = container_of(notify, typeof(*dp), hpd); - struct nvkm_connector *conn = dp->outp.conn; + struct nvkm_conn *conn = dp->outp.conn; struct nvkm_disp *disp = dp->outp.disp; struct nvif_notify_conn_rep_v0 rep = {}; @@ -503,7 +503,7 @@ nvkm_dp_irq(struct nvkm_notify *notify) { const struct nvkm_i2c_ntfy_rep *line = notify->data; struct nvkm_dp *dp = container_of(notify, typeof(*dp), irq); - struct nvkm_connector *conn = dp->outp.conn; + struct nvkm_conn *conn = dp->outp.conn; struct nvkm_disp *disp = dp->outp.disp; struct nvif_notify_conn_rep_v0 rep = { .mask = NVIF_NOTIFY_CONN_V0_IRQ, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index b3e3030d6ef4..682fc99c9351 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -16,7 +16,7 @@ struct nvkm_outp { int or; struct list_head head; - struct nvkm_connector *conn; + struct nvkm_conn *conn; }; void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, From 4b2b42f8e910c65aceb8b2d12fe392a7b7955449 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 27/73] drm/nouveau/disp: delay output path / connector construction until oneinit() This is to allow hw-specific code to instantiate output resources first, so we can cull unsupported output paths based on them. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 130 +++++++++--------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 970ae753968a..f17200ed3c72 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -8,7 +8,9 @@ struct nvkm_disp { const struct nvkm_disp_func *func; struct nvkm_engine engine; - struct nvkm_oproxy *client; + struct { + int nr; + } head; struct list_head outp; struct list_head conn; @@ -16,9 +18,7 @@ struct nvkm_disp { struct nvkm_event hpd; struct nvkm_event vblank; - struct { - int nr; - } head; + struct nvkm_oproxy *client; }; int nv04_disp_new(struct nvkm_device *, int, struct nvkm_disp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 34dc165394e1..3e02a94c3072 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -242,49 +242,11 @@ nvkm_disp_init(struct nvkm_engine *engine) return 0; } -static void * -nvkm_disp_dtor(struct nvkm_engine *engine) +static int +nvkm_disp_oneinit(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_conn *conn; - struct nvkm_outp *outp; - void *data = disp; - - if (disp->func->dtor) - data = disp->func->dtor(disp); - - nvkm_event_fini(&disp->vblank); - nvkm_event_fini(&disp->hpd); - - while (!list_empty(&disp->outp)) { - outp = list_first_entry(&disp->outp, typeof(*outp), head); - list_del(&outp->head); - nvkm_outp_del(&outp); - } - - while (!list_empty(&disp->conn)) { - conn = list_first_entry(&disp->conn, typeof(*conn), head); - list_del(&conn->head); - nvkm_conn_del(&conn); - } - - return data; -} - -static const struct nvkm_engine_func -nvkm_disp = { - .dtor = nvkm_disp_dtor, - .init = nvkm_disp_init, - .fini = nvkm_disp_fini, - .intr = nvkm_disp_intr, - .base.sclass = nvkm_disp_class_get, -}; - -int -nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, - int index, int heads, struct nvkm_disp *disp) -{ - struct nvkm_bios *bios = device->bios; + struct nvkm_bios *bios = disp->engine.subdev.device->bios; struct nvkm_outp *outp, *outt, *pair; struct nvkm_conn *conn; struct nvbios_connE connE; @@ -293,16 +255,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, u32 data; int ret, i; - INIT_LIST_HEAD(&disp->outp); - INIT_LIST_HEAD(&disp->conn); - disp->func = func; - disp->head.nr = heads; - - ret = nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine); - if (ret) - return ret; - - /* create output objects for each display path in the vbios */ + /* Create output path objects for each VBIOS display path. */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { const struct nvkm_disp_func_outp *outps; @@ -349,7 +302,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, continue; } nvkm_error(&disp->engine.subdev, - "failed to create output %d\n", i); + "failed to create outp %d\n", i); nvkm_outp_del(&outp); continue; } @@ -358,18 +311,18 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, hpd = max(hpd, (u8)(dcbE.connector + 1)); } - /* create connector objects based on the outputs we support */ + /* Create connector objects based on available output paths. */ list_for_each_entry_safe(outp, outt, &disp->outp, head) { - /* bios data *should* give us the most useful information */ + /* VBIOS data *should* give us the most useful information. */ data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); - /* no bios connector data... */ + /* No bios connector data... */ if (!data) { - /* heuristic: anything with the same ccb index is + /* Heuristic: anything with the same ccb index is * considered to be on the same connector, any * output path without an associated ccb entry will - * be put on its own connector + * be put on its own connector. */ int ccb_index = outp->info.i2c_index; if (ccb_index != 0xf) { @@ -381,7 +334,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, } } - /* connector shared with another output path */ + /* Connector shared with another output path. */ if (outp->conn) continue; @@ -392,7 +345,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, i = outp->info.connector; } - /* check that we haven't already created this connector */ + /* Check that we haven't already created this connector. */ list_for_each_entry(conn, &disp->conn, head) { if (conn->index == outp->info.connector) { outp->conn = conn; @@ -403,11 +356,11 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, if (outp->conn) continue; - /* apparently we need to create a new one! */ + /* Apparently we need to create a new one! */ ret = nvkm_conn_new(disp, i, &connE, &outp->conn); if (ret) { nvkm_error(&disp->engine.subdev, - "failed to create output %d conn: %d\n", + "failed to create outp %d conn: %d\n", outp->index, ret); nvkm_conn_del(&outp->conn); list_del(&outp->head); @@ -422,11 +375,58 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, if (ret) return ret; - ret = nvkm_event_init(&nvkm_disp_vblank_func, 1, heads, &disp->vblank); - if (ret) - return ret; + return nvkm_event_init(&nvkm_disp_vblank_func, 1, + disp->head.nr, &disp->vblank); +} - return 0; +static void * +nvkm_disp_dtor(struct nvkm_engine *engine) +{ + struct nvkm_disp *disp = nvkm_disp(engine); + struct nvkm_conn *conn; + struct nvkm_outp *outp; + void *data = disp; + + if (disp->func->dtor) + data = disp->func->dtor(disp); + + nvkm_event_fini(&disp->vblank); + nvkm_event_fini(&disp->hpd); + + while (!list_empty(&disp->conn)) { + conn = list_first_entry(&disp->conn, typeof(*conn), head); + list_del(&conn->head); + nvkm_conn_del(&conn); + } + + while (!list_empty(&disp->outp)) { + outp = list_first_entry(&disp->outp, typeof(*outp), head); + list_del(&outp->head); + nvkm_outp_del(&outp); + } + + return data; +} + +static const struct nvkm_engine_func +nvkm_disp = { + .dtor = nvkm_disp_dtor, + .oneinit = nvkm_disp_oneinit, + .init = nvkm_disp_init, + .fini = nvkm_disp_fini, + .intr = nvkm_disp_intr, + .base.sclass = nvkm_disp_class_get, +}; + +int +nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp *disp) +{ + disp->func = func; + disp->head.nr = heads; + INIT_LIST_HEAD(&disp->outp); + INIT_LIST_HEAD(&disp->conn); + return nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine); } int From a1c930789aa51b928f804c9186f9821efd070ce1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: [PATCH 28/73] drm/nouveau/disp: introduce object to track per-head functions/state Primarily intended as a way to pass per-head state around during supervisor handling, and share logic between NV50/GF119. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 5 ++ .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 23 +++++-- .../drm/nouveau/nvkm/engine/disp/basenv50.c | 3 +- .../drm/nouveau/nvkm/engine/disp/cursnv50.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 69 ++++++++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/head.c | 62 +++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/head.h | 30 ++++++++ .../drm/nouveau/nvkm/engine/disp/headgf119.c | 34 +++++++++ .../drm/nouveau/nvkm/engine/disp/headnv04.c | 34 +++++++++ .../drm/nouveau/nvkm/engine/disp/headnv50.c | 34 +++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 15 +++- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 46 ++++++++----- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + .../drm/nouveau/nvkm/engine/disp/oimmnv50.c | 3 +- .../drm/nouveau/nvkm/engine/disp/ovlynv50.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 4 +- .../drm/nouveau/nvkm/engine/disp/rootgf119.c | 23 ++++--- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 22 +++--- 29 files changed, 351 insertions(+), 88 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index f17200ed3c72..a0892d6d9841 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -8,10 +8,7 @@ struct nvkm_disp { const struct nvkm_disp_func *func; struct nvkm_engine engine; - struct { - int nr; - } head; - + struct list_head head; struct list_head outp; struct list_head conn; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index cbc7f673a5de..7062929260bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -14,6 +14,11 @@ nvkm-y += nvkm/engine/disp/gp100.o nvkm-y += nvkm/engine/disp/gp102.o nvkm-y += nvkm/engine/disp/vga.o +nvkm-y += nvkm/engine/disp/head.o +nvkm-y += nvkm/engine/disp/headnv04.o +nvkm-y += nvkm/engine/disp/headnv50.o +nvkm-y += nvkm/engine/disp/headgf119.o + nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 3e02a94c3072..8489d0246cb3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -23,6 +23,7 @@ */ #include "priv.h" #include "conn.h" +#include "head.h" #include "outp.h" #include @@ -249,6 +250,7 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) struct nvkm_bios *bios = disp->engine.subdev.device->bios; struct nvkm_outp *outp, *outt, *pair; struct nvkm_conn *conn; + struct nvkm_head *head; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; @@ -375,8 +377,11 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) if (ret) return ret; - return nvkm_event_init(&nvkm_disp_vblank_func, 1, - disp->head.nr, &disp->vblank); + i = 0; + list_for_each_entry(head, &disp->head, head) + i = max(i, head->id + 1); + + return nvkm_event_init(&nvkm_disp_vblank_func, 1, i, &disp->vblank); } static void * @@ -405,6 +410,12 @@ nvkm_disp_dtor(struct nvkm_engine *engine) nvkm_outp_del(&outp); } + while (!list_empty(&disp->head)) { + struct nvkm_head *head = + list_first_entry(&disp->head, typeof(*head), head); + nvkm_head_del(&head); + } + return data; } @@ -420,10 +431,10 @@ nvkm_disp = { int nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, - int index, int heads, struct nvkm_disp *disp) + int index, struct nvkm_disp *disp) { disp->func = func; - disp->head.nr = heads; + INIT_LIST_HEAD(&disp->head); INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); return nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine); @@ -431,9 +442,9 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, int nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, - int index, int heads, struct nvkm_disp **pdisp) + int index, struct nvkm_disp **pdisp) { if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) return -ENOMEM; - return nvkm_disp_ctor(func, device, index, heads, *pdisp); + return nvkm_disp_ctor(func, device, index, *pdisp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c index 83f152300ec0..f1d6b820d482 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -50,7 +51,7 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp base channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c index 82ff82d8c1ab..ab51121b7982 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -48,7 +49,7 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func, if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp cursor vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 0db964764ced..0de04221da48 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ g84_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &g84_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 3f3cdbc3363a..8010d381bc7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ g94_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &g94_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 8d1e535af208..59bf3f950eea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -364,55 +365,55 @@ gf119_disp_super(struct work_struct *work) container_of(work, struct nv50_disp, supervisor); struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 mask[4]; - int head; nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); - for (head = 0; head < disp->base.head.nr; head++) { - mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); - nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); + list_for_each_entry(head, &disp->base.head, head) { + mask[head->id] = nvkm_rd32(device, 0x6101d4 + (head->id * 0x800)); + HEAD_DBG(head, "%08x", mask[head->id]); } if (disp->super & 0x00000001) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); - gf119_disp_intr_unk1_0(disp, head); + nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head->id); + gf119_disp_intr_unk1_0(disp, head->id); } } else if (disp->super & 0x00000002) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); - gf119_disp_intr_unk2_0(disp, head); + nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); + gf119_disp_intr_unk2_0(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00010000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00010000)) continue; - nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); - gf119_disp_intr_unk2_1(disp, head); + nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head->id); + gf119_disp_intr_unk2_1(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); - gf119_disp_intr_unk2_2(disp, head); + nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head->id); + gf119_disp_intr_unk2_2(disp, head->id); } } else if (disp->super & 0x00000004) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(mask[head] & 0x00001000)) + list_for_each_entry(head, &disp->base.head, head) { + if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); - gf119_disp_intr_unk4_0(disp, head); + nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head->id); + gf119_disp_intr_unk4_0(disp, head->id); } } - for (head = 0; head < disp->base.head.nr; head++) - nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); + list_for_each_entry(head, &disp->base.head, head) + nvkm_wr32(device, 0x6101d4 + (head->id * 0x800), 0x00000000); nvkm_wr32(device, 0x6101d0, 0x80000000); } @@ -447,8 +448,8 @@ gf119_disp_intr(struct nv50_disp *disp) { struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 intr = nvkm_rd32(device, 0x610088); - int i; if (intr & 0x00000001) { u32 stat = nvkm_rd32(device, 0x61008c); @@ -485,14 +486,15 @@ gf119_disp_intr(struct nv50_disp *disp) intr &= ~0x00100000; } - for (i = 0; i < disp->base.head.nr; i++) { - u32 mask = 0x01000000 << i; + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + u32 mask = 0x01000000 << head->id; if (mask & intr) { - u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); + u32 stat = nvkm_rd32(device, 0x6100bc + hoff); if (stat & 0x00000001) - nvkm_disp_vblank(&disp->base, i); - nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); - nvkm_rd32(device, 0x6100c0 + (i * 0x800)); + nvkm_disp_vblank(&disp->base, head->id); + nvkm_mask(device, 0x6100bc + hoff, 0, 0); + nvkm_rd32(device, 0x6100c0 + hoff); } } } @@ -512,6 +514,7 @@ gf119_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gf119_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index ec14cef92de5..89561496570b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gk104_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gk104_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 88f977660e41..9400d2ad79b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gk110_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gk110_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 5d7a2f42a4f0..b7570fb0fb1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gm107_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gm107_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 54fa9ebe346b..b3e52080d4b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gm200_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gm200_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 6f4e56d82421..3d1c65ff5620 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -31,6 +32,7 @@ gp100_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gp100_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 54b97e1dce0b..fac8e88fd2d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static void @@ -57,6 +58,7 @@ gp102_disp = { .uevent = &gf119_disp_chan_uevent, .super = gf119_disp_super, .root = &gp102_disp_root_oclass, + .head.new = gf119_head_new, .head.vblank_init = gf119_disp_vblank_init, .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index da6c395050de..a0e7c3c78e97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ gt200_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = >200_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 1f475cf284e3..5f8a8d855673 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -30,6 +31,7 @@ gt215_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = >215_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c new file mode 100644 index 000000000000..67020933f4ff --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +struct nvkm_head * +nvkm_head_find(struct nvkm_disp *disp, int id) +{ + struct nvkm_head *head; + list_for_each_entry(head, &disp->head, head) { + if (head->id == id) + return head; + } + return NULL; +} + +void +nvkm_head_del(struct nvkm_head **phead) +{ + struct nvkm_head *head = *phead; + if (head) { + HEAD_DBG(head, "dtor"); + list_del(&head->head); + kfree(*phead); + *phead = NULL; + } +} + +int +nvkm_head_new_(const struct nvkm_head_func *func, + struct nvkm_disp *disp, int id) +{ + struct nvkm_head *head; + if (!(head = kzalloc(sizeof(*head), GFP_KERNEL))) + return -ENOMEM; + head->func = func; + head->disp = disp; + head->id = id; + list_add_tail(&head->head, &disp->head); + HEAD_DBG(head, "ctor"); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h new file mode 100644 index 000000000000..a8ae6cbc0ff1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -0,0 +1,30 @@ +#ifndef __NVKM_DISP_HEAD_H__ +#define __NVKM_DISP_HEAD_H__ +#include "priv.h" + +struct nvkm_head { + const struct nvkm_head_func *func; + struct nvkm_disp *disp; + int id; + + struct list_head head; +}; + +int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id); +void nvkm_head_del(struct nvkm_head **); +struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); + +struct nvkm_head_func { +}; + +#define HEAD_MSG(h,l,f,a...) do { \ + struct nvkm_head *_h = (h); \ + nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \ +} while(0) +#define HEAD_WARN(h,f,a...) HEAD_MSG((h), warn, f, ##a) +#define HEAD_DBG(h,f,a...) HEAD_MSG((h), debug, f, ##a) + +int nv04_head_new(struct nvkm_disp *, int id); +int nv50_head_new(struct nvkm_disp *, int id); +int gf119_head_new(struct nvkm_disp *, int id); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c new file mode 100644 index 000000000000..062fa07e1ece --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +gf119_head = { +}; + +int +gf119_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&gf119_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c new file mode 100644 index 000000000000..f581327f695c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +nv04_head = { +}; + +int +nv04_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&nv04_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c new file mode 100644 index 000000000000..e48865c91046 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -0,0 +1,34 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "head.h" + +static const struct nvkm_head_func +nv50_head = { +}; + +int +nv50_head_new(struct nvkm_disp *disp, int id) +{ + return nvkm_head_new_(&nv50_head, disp, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 67254ce6f83f..978e3ad488d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "head.h" static const struct nvkm_disp_oclass * nv04_disp_root(struct nvkm_disp *disp) @@ -81,5 +82,17 @@ nv04_disp = { int nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - return nvkm_disp_new_(&nv04_disp, device, index, 2, pdisp); + int ret, i; + + ret = nvkm_disp_new_(&nv04_disp, device, index, pdisp); + if (ret) + return ret; + + for (i = 0; i < 2; i++) { + ret = nv04_head_new(*pdisp, i); + if (ret) + return ret; + } + + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 025cc0d7feb3..9787a4cc4cce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -146,7 +147,7 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, int index, int heads, struct nvkm_disp **pdisp) { struct nv50_disp *disp; - int ret; + int ret, i; if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) return -ENOMEM; @@ -154,10 +155,16 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, disp->func = func; *pdisp = &disp->base; - ret = nvkm_disp_ctor(&nv50_disp_, device, index, heads, &disp->base); + ret = nvkm_disp_ctor(&nv50_disp_, device, index, &disp->base); if (ret) return ret; + for (i = 0; func->head.new && i < heads; i++) { + ret = func->head.new(&disp->base, i); + if (ret) + return ret; + } + return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } @@ -684,43 +691,43 @@ nv50_disp_super(struct work_struct *work) container_of(work, struct nv50_disp, supervisor); struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_head *head; u32 super = nvkm_rd32(device, 0x610030); - int head; nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); if (disp->super & 0x00000010) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000020 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000020 << head->id))) continue; - if (!(super & (0x00000080 << head))) + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk10_0(disp, head); + nv50_disp_intr_unk10_0(disp, head->id); } } else if (disp->super & 0x00000020) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_0(disp, head); + nv50_disp_intr_unk20_0(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000200 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000200 << head->id))) continue; - nv50_disp_intr_unk20_1(disp, head); + nv50_disp_intr_unk20_1(disp, head->id); } - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_2(disp, head); + nv50_disp_intr_unk20_2(disp, head->id); } } else if (disp->super & 0x00000040) { - for (head = 0; head < disp->base.head.nr; head++) { - if (!(super & (0x00000080 << head))) + list_for_each_entry(head, &disp->base.head, head) { + if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk40_0(disp, head); + nv50_disp_intr_unk40_0(disp, head->id); } nv50_disp_update_sppll1(disp); } @@ -819,6 +826,7 @@ nv50_disp = { .uevent = &nv50_disp_chan_uevent, .super = nv50_disp_super, .root = &nv50_disp_root_oclass, + .head.new = nv50_head_new, .head.vblank_init = nv50_disp_vblank_init, .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 4fa82f48429b..0361f0c2ba1a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -75,6 +75,7 @@ struct nv50_disp_func { const struct nvkm_disp_oclass *root; struct { + int (*new)(struct nvkm_disp *, int id); void (*vblank_init)(struct nv50_disp *, int head); void (*vblank_fini)(struct nv50_disp *, int head); int (*scanoutpos)(NV50_DISP_MTHD_V0); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c index 07540f3d32dc..f3b0fa2c5924 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -48,7 +49,7 @@ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c index 2a49c46425cd..9ebaaa6e9e33 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "head.h" #include "rootnv50.h" #include @@ -50,7 +51,7 @@ nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp overlay channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->base.head.nr) + if (!nvkm_head_find(&disp->base, args->v0.head)) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index e143fc7bc15f..4bb05a09a60b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -4,9 +4,9 @@ #include "outp.h" int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, - int index, int heads, struct nvkm_disp *); + int index, struct nvkm_disp *); int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, - int index, int heads, struct nvkm_disp **); + int index, struct nvkm_disp **); void nvkm_disp_vblank(struct nvkm_disp *, int head); struct nvkm_disp_func_outp { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c index 335d88823c22..f1159dd4db87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "rootnv50.h" +#include "head.h" #include "dmacnv50.h" #include @@ -78,6 +79,7 @@ int gf119_disp_root_init(struct nv50_disp_root *root) { struct nv50_disp *disp = root->disp; + struct nvkm_head *head; struct nvkm_device *device = disp->base.engine.subdev.device; u32 tmp; int i; @@ -88,13 +90,14 @@ gf119_disp_root_init(struct nv50_disp_root *root) */ /* ... CRTC caps */ - for (i = 0; i < disp->base.head.nr; i++) { - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + tmp = nvkm_rd32(device, 0x616104 + hoff); + nvkm_wr32(device, 0x6101b4 + hoff, tmp); + tmp = nvkm_rd32(device, 0x616108 + hoff); + nvkm_wr32(device, 0x6101b8 + hoff, tmp); + tmp = nvkm_rd32(device, 0x61610c + hoff); + nvkm_wr32(device, 0x6101bc + hoff, tmp); } /* ... DAC caps */ @@ -134,8 +137,10 @@ gf119_disp_root_init(struct nv50_disp_root *root) * * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ - for (i = 0; i < disp->base.head.nr; i++) - nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + list_for_each_entry(head, &disp->base.head, head) { + const u32 hoff = head->id * 0x800; + nvkm_mask(device, 0x616308 + hoff, 0x00000111, 0x00000010); + } return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 2e73aeb86070..b5df4e8ddbfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -23,6 +23,7 @@ */ #include "rootnv50.h" #include "dmacnv50.h" +#include "head.h" #include #include @@ -102,7 +103,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } else return ret; - if (head < 0 || head >= disp->base.head.nr) + if (!nvkm_head_find(&disp->base, head)) return -ENXIO; if (mask) { @@ -351,6 +352,7 @@ int nv50_disp_root_init(struct nv50_disp_root *root) { struct nv50_disp *disp = root->disp; + struct nvkm_head *head; struct nvkm_device *device = disp->base.engine.subdev.device; u32 tmp; int i; @@ -363,15 +365,15 @@ nv50_disp_root_init(struct nv50_disp_root *root) nvkm_wr32(device, 0x610184, tmp); /* ... CRTC caps */ - for (i = 0; i < disp->base.head.nr; i++) { - tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); - nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); + list_for_each_entry(head, &disp->base.head, head) { + tmp = nvkm_rd32(device, 0x616100 + (head->id * 0x800)); + nvkm_wr32(device, 0x610190 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616104 + (head->id * 0x800)); + nvkm_wr32(device, 0x610194 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616108 + (head->id * 0x800)); + nvkm_wr32(device, 0x610198 + (head->id * 0x10), tmp); + tmp = nvkm_rd32(device, 0x61610c + (head->id * 0x800)); + nvkm_wr32(device, 0x61019c + (head->id * 0x10), tmp); } /* ... DAC caps */ From 14187b007e646c0dbf0813d22f7733cf6eebc099 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 29/73] drm/nouveau/disp: move vblank_{get,put} methods into nvkm_head Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 12 ++++--- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 16 ---------- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/head.h | 2 ++ .../drm/nouveau/nvkm/engine/disp/headgf119.c | 18 +++++++++++ .../drm/nouveau/nvkm/engine/disp/headnv04.c | 16 ++++++++++ .../drm/nouveau/nvkm/engine/disp/headnv50.c | 16 ++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 16 ---------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 32 ------------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 6 ---- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 5 --- 20 files changed, 60 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 8489d0246cb3..1c655c18097e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -38,17 +38,21 @@ #include static void -nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int head) +nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int id) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - disp->func->head.vblank_fini(disp, head); + struct nvkm_head *head = nvkm_head_find(disp, id); + if (head) + head->func->vblank_put(head); } static void -nvkm_disp_vblank_init(struct nvkm_event *event, int type, int head) +nvkm_disp_vblank_init(struct nvkm_event *event, int type, int id) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - disp->func->head.vblank_init(disp, head); + struct nvkm_head *head = nvkm_head_find(disp, id); + if (head) + head->func->vblank_get(head); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 0de04221da48..1b74072e28fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -32,8 +32,6 @@ g84_disp = { .super = nv50_disp_super, .root = &g84_disp_root_oclass, .head.new = nv50_head_new, - .head.vblank_init = nv50_disp_vblank_init, - .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 8010d381bc7d..38a5d165c11c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -32,8 +32,6 @@ g94_disp = { .super = nv50_disp_super, .root = &g94_disp_root_oclass, .head.new = nv50_head_new, - .head.vblank_init = nv50_disp_vblank_init, - .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 59bf3f950eea..e9cf53e918af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -31,20 +31,6 @@ #include #include -void -gf119_disp_vblank_init(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); -} - -void -gf119_disp_vblank_fini(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); -} - static struct nvkm_output * exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -515,8 +501,6 @@ gf119_disp = { .super = gf119_disp_super, .root = &gf119_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 89561496570b..3dd530298a28 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -33,8 +33,6 @@ gk104_disp = { .super = gf119_disp_super, .root = &gk104_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 9400d2ad79b9..8c4cabec036d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -33,8 +33,6 @@ gk110_disp = { .super = gf119_disp_super, .root = &gk110_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index b7570fb0fb1f..dfb32c14558e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -33,8 +33,6 @@ gm107_disp = { .super = gf119_disp_super, .root = &gm107_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index b3e52080d4b7..97ca9434e1f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -33,8 +33,6 @@ gm200_disp = { .super = gf119_disp_super, .root = &gm200_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 3d1c65ff5620..e0d5ed423f19 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -33,8 +33,6 @@ gp100_disp = { .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index fac8e88fd2d1..56eeee4dd634 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -59,8 +59,6 @@ gp102_disp = { .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.new = gf119_head_new, - .head.vblank_init = gf119_disp_vblank_init, - .head.vblank_fini = gf119_disp_vblank_fini, .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index a0e7c3c78e97..fa8eea41dfa2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -32,8 +32,6 @@ gt200_disp = { .super = nv50_disp_super, .root = >200_disp_root_oclass, .head.new = nv50_head_new, - .head.vblank_init = nv50_disp_vblank_init, - .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 5f8a8d855673..b211757910e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -32,8 +32,6 @@ gt215_disp = { .super = nv50_disp_super, .root = >215_disp_root_oclass, .head.new = nv50_head_new, - .head.vblank_init = nv50_disp_vblank_init, - .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index a8ae6cbc0ff1..68866a7fba01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -15,6 +15,8 @@ void nvkm_head_del(struct nvkm_head **); struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); struct nvkm_head_func { + void (*vblank_get)(struct nvkm_head *); + void (*vblank_put)(struct nvkm_head *); }; #define HEAD_MSG(h,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index 062fa07e1ece..8ac76445b07a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -23,8 +23,26 @@ */ #include "head.h" +static void +gf119_head_vblank_put(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = head->id * 0x800; + nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000000); +} + +static void +gf119_head_vblank_get(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = head->id * 0x800; + nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000001); +} + static const struct nvkm_head_func gf119_head = { + .vblank_get = gf119_head_vblank_get, + .vblank_put = gf119_head_vblank_put, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c index f581327f695c..d8d6fbef88ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c @@ -23,8 +23,24 @@ */ #include "head.h" +static void +nv04_head_vblank_put(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000000); +} + +static void +nv04_head_vblank_get(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000001); +} + static const struct nvkm_head_func nv04_head = { + .vblank_get = nv04_head_vblank_get, + .vblank_put = nv04_head_vblank_put, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c index e48865c91046..b3aaa68c0daa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -23,8 +23,24 @@ */ #include "head.h" +static void +nv50_head_vblank_put(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head->id), 0); +} + +static void +nv50_head_vblank_get(struct nvkm_head *head) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head->id), (4 << head->id)); +} + static const struct nvkm_head_func nv50_head = { + .vblank_get = nv50_head_vblank_get, + .vblank_put = nv50_head_vblank_put, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 978e3ad488d9..b780ba1a3bc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -30,20 +30,6 @@ nv04_disp_root(struct nvkm_disp *disp) return &nv04_disp_root_oclass; } -static void -nv04_disp_vblank_init(struct nvkm_disp *disp, int head) -{ - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000001); -} - -static void -nv04_disp_vblank_fini(struct nvkm_disp *disp, int head) -{ - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000000); -} - static void nv04_disp_intr(struct nvkm_disp *disp) { @@ -75,8 +61,6 @@ static const struct nvkm_disp_func nv04_disp = { .intr = nv04_disp_intr, .root = nv04_disp_root, - .head.vblank_init = nv04_disp_vblank_init, - .head.vblank_fini = nv04_disp_vblank_fini, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 9787a4cc4cce..6f2314d5dac1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -98,20 +98,6 @@ nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index, return -ENODEV; } -static void -nv50_disp_vblank_fini_(struct nvkm_disp *base, int head) -{ - struct nv50_disp *disp = nv50_disp(base); - disp->func->head.vblank_fini(disp, head); -} - -static void -nv50_disp_vblank_init_(struct nvkm_disp *base, int head) -{ - struct nv50_disp *disp = nv50_disp(base); - disp->func->head.vblank_init(disp, head); -} - static void nv50_disp_intr_(struct nvkm_disp *base) { @@ -138,8 +124,6 @@ nv50_disp_ = { .outp.internal.dp = nv50_disp_outp_internal_dp_, .outp.external.tmds = nv50_disp_outp_external_tmds_, .outp.external.dp = nv50_disp_outp_external_dp_, - .head.vblank_init = nv50_disp_vblank_init_, - .head.vblank_fini = nv50_disp_vblank_fini_, }; int @@ -168,20 +152,6 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } -void -nv50_disp_vblank_fini(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x61002c, (4 << head), 0); -} - -void -nv50_disp_vblank_init(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); -} - static struct nvkm_output * exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -827,8 +797,6 @@ nv50_disp = { .super = nv50_disp_super, .root = &nv50_disp_root_oclass, .head.new = nv50_head_new, - .head.vblank_init = nv50_disp_vblank_init, - .head.vblank_fini = nv50_disp_vblank_fini, .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 0361f0c2ba1a..5047e719dc58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -76,8 +76,6 @@ struct nv50_disp_func { struct { int (*new)(struct nvkm_disp *, int id); - void (*vblank_init)(struct nv50_disp *, int head); - void (*vblank_fini)(struct nv50_disp *, int head); int (*scanoutpos)(NV50_DISP_MTHD_V0); } head; @@ -106,13 +104,9 @@ struct nv50_disp_func { } pior; }; -void nv50_disp_vblank_init(struct nv50_disp *, int); -void nv50_disp_vblank_fini(struct nv50_disp *, int); void nv50_disp_intr(struct nv50_disp *); void nv50_disp_super(struct work_struct *); -void gf119_disp_vblank_init(struct nv50_disp *, int); -void gf119_disp_vblank_fini(struct nv50_disp *, int); void gf119_disp_intr(struct nv50_disp *); void gf119_disp_super(struct work_struct *); void gf119_disp_intr_error(struct nv50_disp *, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 4bb05a09a60b..e8dcae14a9ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -28,11 +28,6 @@ struct nvkm_disp_func { const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); - struct { - void (*vblank_init)(struct nvkm_disp *, int head); - void (*vblank_fini)(struct nvkm_disp *, int head); - } head; - struct { const struct nvkm_disp_func_outp internal; const struct nvkm_disp_func_outp external; From 57b2d73be275f853066aaf5cc33f6c59a94260b2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 30/73] drm/nouveau/disp: common implementation of scanoutpos method in nvkm_head Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/head.c | 43 +++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/head.h | 17 +++++ .../drm/nouveau/nvkm/engine/disp/headgf119.c | 23 +++++++ .../drm/nouveau/nvkm/engine/disp/headnv04.c | 24 +++++++ .../drm/nouveau/nvkm/engine/disp/headnv50.c | 33 ++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 6 -- .../drm/nouveau/nvkm/engine/disp/rootgf119.c | 37 ----------- .../drm/nouveau/nvkm/engine/disp/rootnv04.c | 54 ++-------------- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 62 +++++-------------- 21 files changed, 161 insertions(+), 150 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 1b74072e28fe..bdaec4e4cb60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -32,7 +32,6 @@ g84_disp = { .super = nv50_disp_super, .root = &g84_disp_root_oclass, .head.new = nv50_head_new, - .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 38a5d165c11c..12e4984e5393 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -32,7 +32,6 @@ g94_disp = { .super = nv50_disp_super, .root = &g94_disp_root_oclass, .head.new = nv50_head_new, - .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index e9cf53e918af..d353d29f2ad4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -501,7 +501,6 @@ gf119_disp = { .super = gf119_disp_super, .root = &gf119_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 3dd530298a28..a83684c2c129 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -33,7 +33,6 @@ gk104_disp = { .super = gf119_disp_super, .root = &gk104_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 8c4cabec036d..72a2fc0183b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -33,7 +33,6 @@ gk110_disp = { .super = gf119_disp_super, .root = &gk110_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index dfb32c14558e..b6658e22b207 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -33,7 +33,6 @@ gm107_disp = { .super = gf119_disp_super, .root = &gm107_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 97ca9434e1f3..e0ea05350dfb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -33,7 +33,6 @@ gm200_disp = { .super = gf119_disp_super, .root = &gm200_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index e0d5ed423f19..90ea05f98699 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -33,7 +33,6 @@ gp100_disp = { .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 56eeee4dd634..722a057bc9ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -59,7 +59,6 @@ gp102_disp = { .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.new = gf119_head_new, - .head.scanoutpos = gf119_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index fa8eea41dfa2..a5710ea0b244 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -32,7 +32,6 @@ gt200_disp = { .super = nv50_disp_super, .root = >200_disp_root_oclass, .head.new = nv50_head_new, - .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index b211757910e2..3c100fc617a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -32,7 +32,6 @@ gt215_disp = { .super = nv50_disp_super, .root = >215_disp_root_oclass, .head.new = nv50_head_new, - .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c index 67020933f4ff..5c557f3e6c2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.c @@ -23,6 +23,11 @@ */ #include "head.h" +#include + +#include +#include + struct nvkm_head * nvkm_head_find(struct nvkm_disp *disp, int id) { @@ -34,6 +39,44 @@ nvkm_head_find(struct nvkm_disp *disp, int id) return NULL; } +int +nvkm_head_mthd_scanoutpos(struct nvkm_object *object, + struct nvkm_head *head, void *data, u32 size) +{ + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret = -ENOSYS; + + nvif_ioctl(object, "head scanoutpos size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + nvif_ioctl(object, "head scanoutpos vers %d\n", + args->v0.version); + + head->func->state(head, &head->arm); + args->v0.vtotal = head->arm.vtotal; + args->v0.vblanks = head->arm.vblanks; + args->v0.vblanke = head->arm.vblanke; + args->v0.htotal = head->arm.htotal; + args->v0.hblanks = head->arm.hblanks; + args->v0.hblanke = head->arm.hblanke; + + /* We don't support reading htotal/vtotal on pre-NV50 VGA, + * so we have to give up and trigger the timestamping + * fallback in the drm core. + */ + if (!args->v0.vtotal || !args->v0.htotal) + return -ENOTSUPP; + + args->v0.time[0] = ktime_to_ns(ktime_get()); + head->func->rgpos(head, &args->v0.hline, &args->v0.vline); + args->v0.time[1] = ktime_to_ns(ktime_get()); + } else + return ret; + + return 0; +} + void nvkm_head_del(struct nvkm_head **phead) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index 68866a7fba01..94f5cb7596a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -8,17 +8,34 @@ struct nvkm_head { int id; struct list_head head; + + struct nvkm_head_state { + u16 htotal; + u16 hsynce; + u16 hblanke; + u16 hblanks; + u16 vtotal; + u16 vsynce; + u16 vblanke; + u16 vblanks; + } arm, asy; }; int nvkm_head_new_(const struct nvkm_head_func *, struct nvkm_disp *, int id); void nvkm_head_del(struct nvkm_head **); +int nvkm_head_mthd_scanoutpos(struct nvkm_object *, + struct nvkm_head *, void *, u32); struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); struct nvkm_head_func { + void (*state)(struct nvkm_head *, struct nvkm_head_state *); + void (*rgpos)(struct nvkm_head *, u16 *hline, u16 *vline); void (*vblank_get)(struct nvkm_head *); void (*vblank_put)(struct nvkm_head *); }; +void nv50_head_rgpos(struct nvkm_head *, u16 *, u16 *); + #define HEAD_MSG(h,l,f,a...) do { \ struct nvkm_head *_h = (h); \ nvkm_##l(&_h->disp->engine.subdev, "head-%d: "f"\n", _h->id, ##a); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index 8ac76445b07a..8e7acc57d31d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -39,8 +39,31 @@ gf119_head_vblank_get(struct nvkm_head *head) nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000001); } +static void +gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = (state == &head->asy) * 0x20000 + head->id * 0x300; + u32 data; + + data = nvkm_rd32(device, 0x640414 + hoff); + state->vtotal = (data & 0xffff0000) >> 16; + state->htotal = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x640418 + hoff); + state->vsynce = (data & 0xffff0000) >> 16; + state->hsynce = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x64041c + hoff); + state->vblanke = (data & 0xffff0000) >> 16; + state->hblanke = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x640420 + hoff); + state->vblanks = (data & 0xffff0000) >> 16; + state->hblanks = (data & 0x0000ffff); +} + static const struct nvkm_head_func gf119_head = { + .state = gf119_head_state, + .rgpos = nv50_head_rgpos, .vblank_get = gf119_head_vblank_get, .vblank_put = gf119_head_vblank_put, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c index d8d6fbef88ae..dcf459282aa1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv04.c @@ -37,8 +37,32 @@ nv04_head_vblank_get(struct nvkm_head *head) nvkm_wr32(device, 0x600140 + (head->id * 0x2000) , 0x00000001); } +static void +nv04_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + u32 data = nvkm_rd32(device, 0x600868 + (head->id * 0x2000)); + *hline = (data & 0xffff0000) >> 16; + *vline = (data & 0x0000ffff); +} + +static void +nv04_head_state(struct nvkm_head *head, struct nvkm_head_state *state) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = head->id * 0x0200; + state->vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0x0000ffff; + state->vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0x0000ffff; + state->vblanke = state->vtotal - 1; + state->hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0x0000ffff; + state->htotal = nvkm_rd32(device, 0x680824 + hoff) & 0x0000ffff; + state->hblanke = state->htotal - 1; +} + static const struct nvkm_head_func nv04_head = { + .state = nv04_head_state, + .rgpos = nv04_head_rgpos, .vblank_get = nv04_head_vblank_get, .vblank_put = nv04_head_vblank_put, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c index b3aaa68c0daa..3cccda2cb09e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -37,8 +37,41 @@ nv50_head_vblank_get(struct nvkm_head *head) nvkm_mask(device, 0x61002c, (4 << head->id), (4 << head->id)); } +void +nv50_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = head->id * 0x800; + /* vline read locks hline. */ + *vline = nvkm_rd32(device, 0x616340 + hoff) & 0x0000ffff; + *hline = nvkm_rd32(device, 0x616344 + hoff) & 0x0000ffff; +} + +static void +nv50_head_state(struct nvkm_head *head, struct nvkm_head_state *state) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + const u32 hoff = head->id * 0x540 + (state == &head->arm) * 4; + u32 data; + + data = nvkm_rd32(device, 0x610ae8 + hoff); + state->vblanke = (data & 0xffff0000) >> 16; + state->hblanke = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x610af0 + hoff); + state->vblanks = (data & 0xffff0000) >> 16; + state->hblanks = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x610af8 + hoff); + state->vtotal = (data & 0xffff0000) >> 16; + state->htotal = (data & 0x0000ffff); + data = nvkm_rd32(device, 0x610b00 + hoff); + state->vsynce = (data & 0xffff0000) >> 16; + state->hsynce = (data & 0x0000ffff); +} + static const struct nvkm_head_func nv50_head = { + .state = nv50_head_state, + .rgpos = nv50_head_rgpos, .vblank_get = nv50_head_vblank_get, .vblank_put = nv50_head_vblank_put, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 6f2314d5dac1..aa7ed87825e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -797,7 +797,6 @@ nv50_disp = { .super = nv50_disp_super, .root = &nv50_disp_root_oclass, .head.new = nv50_head_new, - .head.scanoutpos = nv50_disp_root_scanoutpos, .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 5047e719dc58..42c2dd83fe56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -6,7 +6,6 @@ #define NV50_DISP_MTHD_ struct nvkm_object *object, \ struct nv50_disp *disp, void *data, u32 size -#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head #define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp struct nv50_disp { @@ -29,10 +28,6 @@ struct nv50_disp { struct nv50_disp_chan *chan[17]; }; -int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); - -int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); - int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1); @@ -76,7 +71,6 @@ struct nv50_disp_func { struct { int (*new)(struct nvkm_disp *, int id); - int (*scanoutpos)(NV50_DISP_MTHD_V0); } head; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c index f1159dd4db87..333c8424b413 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -25,47 +25,10 @@ #include "head.h" #include "dmacnv50.h" -#include #include #include #include -#include -#include - -int -gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); - const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); - const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); - union { - struct nv50_disp_scanoutpos_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} void gf119_disp_root_fini(struct nv50_disp_root *root) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c index f535f43231e2..7f3e2554a83d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c @@ -23,6 +23,7 @@ */ #define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object) #include "priv.h" +#include "head.h" #include @@ -35,50 +36,6 @@ struct nv04_disp_root { struct nvkm_disp *disp; }; -static int -nv04_disp_scanoutpos(struct nv04_disp_root *root, - void *data, u32 size, int head) -{ - struct nvkm_device *device = root->disp->engine.subdev.device; - struct nvkm_object *object = &root->object; - const u32 hoff = head * 0x2000; - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - u32 line; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; - args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; - args->v0.vblanke = args->v0.vtotal - 1; - - args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff; - args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff; - args->v0.hblanke = args->v0.htotal - 1; - - /* - * If output is vga instead of digital then vtotal/htotal is - * invalid so we have to give up and trigger the timestamping - * fallback in the drm core. - */ - if (!args->v0.vtotal || !args->v0.htotal) - return -ENOTSUPP; - - args->v0.time[0] = ktime_to_ns(ktime_get()); - line = nvkm_rd32(device, 0x600868 + hoff); - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = (line & 0xffff0000) >> 16; - args->v0.vline = (line & 0x0000ffff); - } else - return ret; - - return 0; -} - static int nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { @@ -86,23 +43,24 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) union { struct nv04_disp_mthd_v0 v0; } *args = data; - int head, ret = -ENOSYS; + struct nvkm_head *head; + int id, ret = -ENOSYS; nvif_ioctl(object, "disp mthd size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; - head = args->v0.head; + id = args->v0.head; } else return ret; - if (head < 0 || head >= 2) + if (!(head = nvkm_head_find(root->disp, id))) return -ENXIO; switch (mthd) { case NV04_DISP_SCANOUTPOS: - return nv04_disp_scanoutpos(root, data, size, head); + return nvkm_head_mthd_scanoutpos(object, head, data, size); default: break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index b5df4e8ddbfd..609bfae9acbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -33,40 +33,6 @@ #include #include -int -nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540)); - const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540)); - const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540)); - union { - struct nv50_disp_scanoutpos_v0 v0; - } *args = data; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} - static int nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) { @@ -78,8 +44,9 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) struct nv50_disp *disp = root->disp; const struct nv50_disp_func *func = disp->func; struct nvkm_outp *temp, *outp = NULL; + struct nvkm_head *head; u16 type, mask = 0; - int head, ret = -ENOSYS; + int hidx, ret = -ENOSYS; if (mthd != NV50_DISP_MTHD) return -EINVAL; @@ -89,7 +56,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; - head = args->v0.head; + hidx = args->v0.head; } else if (!(ret = nvif_unpack(ret, &data, &size, args->v1, 1, 1, true))) { nvif_ioctl(object, "disp mthd vers %d mthd %02x " @@ -99,11 +66,11 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) mthd = args->v1.method; type = args->v1.hasht; mask = args->v1.hashm; - head = ffs((mask >> 8) & 0x0f) - 1; + hidx = ffs((mask >> 8) & 0x0f) - 1; } else return ret; - if (!nvkm_head_find(&disp->base, head)) + if (!(head = nvkm_head_find(&disp->base, hidx))) return -ENXIO; if (mask) { @@ -119,27 +86,28 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } switch (mthd) { - case NV50_DISP_SCANOUTPOS: - return func->head.scanoutpos(object, disp, data, size, head); + case NV50_DISP_SCANOUTPOS: { + return nvkm_head_mthd_scanoutpos(object, head, data, size); + } default: break; } switch (mthd * !!outp) { case NV50_DISP_MTHD_V1_DAC_PWR: - return func->dac.power(object, disp, data, size, head, outp); + return func->dac.power(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_DAC_LOAD: - return func->dac.sense(object, disp, data, size, head, outp); + return func->dac.sense(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_SOR_PWR: - return func->sor.power(object, disp, data, size, head, outp); + return func->sor.power(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_SOR_HDA_ELD: if (!func->sor.hda_eld) return -ENODEV; - return func->sor.hda_eld(object, disp, data, size, head, outp); + return func->sor.hda_eld(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: if (!func->sor.hdmi) return -ENODEV; - return func->sor.hdmi(object, disp, data, size, head, outp); + return func->sor.hdmi(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { union { struct nv50_disp_sor_lvds_script_v0 v0; @@ -215,7 +183,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) args->v0.aligned_pbn); if (!outpdp->func->vcpi) return -ENODEV; - outpdp->func->vcpi(outpdp, head, args->v0.start_slot, + outpdp->func->vcpi(outpdp, hidx, args->v0.start_slot, args->v0.num_slots, args->v0.pbn, args->v0.aligned_pbn); return 0; @@ -226,7 +194,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) case NV50_DISP_MTHD_V1_PIOR_PWR: if (!func->pior.power) return -ENODEV; - return func->pior.power(object, disp, data, size, head, outp); + return func->pior.power(object, disp, data, size, hidx, outp); default: break; } From 78f1ad6f655847411b36bda2b2acbd0648a03d5c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 31/73] drm/nouveau/disp: introduce input/output resource abstraction In order to properly support the SOR -> SOR + pad macro separation that occurred with GM20x GPUs, we need to separate OR handling out of the output path code. This will be used as the base to support ORs (DAC, SOR, PIOR). Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 8 +++ .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 11 +++ .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 4 ++ .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 4 ++ .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 3 + .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 4 ++ .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 4 ++ .../gpu/drm/nouveau/nvkm/engine/disp/ior.c | 72 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 43 +++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 22 ++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 3 + .../drm/nouveau/nvkm/engine/disp/piornv50.c | 11 +++ .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 11 +++ .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 11 +++ .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 11 +++ .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 11 +++ .../drm/nouveau/nvkm/engine/disp/sornv50.c | 11 +++ 25 files changed, 262 insertions(+), 8 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index a0892d6d9841..6d68596ecfc2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -9,6 +9,7 @@ struct nvkm_disp { struct nvkm_engine engine; struct list_head head; + struct list_head ior; struct list_head outp; struct list_head conn; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 7062929260bc..5bcdc1162fd5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -19,6 +19,7 @@ nvkm-y += nvkm/engine/disp/headnv04.o nvkm-y += nvkm/engine/disp/headnv50.o nvkm-y += nvkm/engine/disp/headgf119.o +nvkm-y += nvkm/engine/disp/ior.o nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 1c655c18097e..24d2f325cbc5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -24,6 +24,7 @@ #include "priv.h" #include "conn.h" #include "head.h" +#include "ior.h" #include "outp.h" #include @@ -414,6 +415,12 @@ nvkm_disp_dtor(struct nvkm_engine *engine) nvkm_outp_del(&outp); } + while (!list_empty(&disp->ior)) { + struct nvkm_ior *ior = + list_first_entry(&disp->ior, typeof(*ior), head); + nvkm_ior_del(&ior); + } + while (!list_empty(&disp->head)) { struct nvkm_head *head = list_first_entry(&disp->head, typeof(*head), head); @@ -439,6 +446,7 @@ nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, { disp->func = func; INIT_LIST_HEAD(&disp->head); + INIT_LIST_HEAD(&disp->ior); INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); return nvkm_engine_ctor(&nvkm_disp, device, index, true, &disp->engine); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index e8dabedea5dc..5e2dbd5de511 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" #include "outp.h" @@ -124,3 +125,13 @@ nv50_dac_power(NV50_DISP_MTHD_V1) ); return 0; } + +static const struct nvkm_ior_func +nv50_dac = { +}; + +int +nv50_dac_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&nv50_dac, disp, DAC, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index bdaec4e4cb60..b8aae872f873 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,12 +39,15 @@ g84_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, + .sor.new = nv50_sor_new, .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, .pior.nr = 3, + .pior.new = nv50_pior_new, .pior.power = nv50_pior_power, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 12e4984e5393..4a959de0d616 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -39,12 +40,15 @@ g94_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = g94_sor_new, .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, .pior.nr = 3, + .pior.new = nv50_pior_new, .pior.power = nv50_pior_power, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index d353d29f2ad4..1a9958c2e73c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" #include @@ -506,9 +507,11 @@ gf119_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gf119_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gf119_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index a83684c2c129..aeaaf4280d04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,9 +39,11 @@ gk104_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gf119_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 72a2fc0183b3..90080c423bdc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,9 +39,11 @@ gk110_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gf119_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index b6658e22b207..12ad91b4f36c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,9 +39,11 @@ gm107_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm107_sor_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gm107_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index e0ea05350dfb..e62488f97546 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,9 +39,11 @@ gm200_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm200_sor_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gm200_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 90ea05f98699..f7ba3366024a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -33,14 +34,11 @@ gp100_disp = { .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm200_sor_dp_new, - .dac.nr = 3, - .dac.power = nv50_dac_power, - .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gm200_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 722a057bc9ff..80010f2c94b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static void @@ -59,14 +60,11 @@ gp102_disp = { .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm200_sor_dp_new, - .dac.nr = 3, - .dac.power = nv50_dac_power, - .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = gm200_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index a5710ea0b244..15a2f3ce3e9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -38,12 +39,15 @@ gt200_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, + .sor.new = nv50_sor_new, .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, .pior.nr = 3, + .pior.new = nv50_pior_new, .pior.power = nv50_pior_power, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 3c100fc617a6..e5ceba9e2ab9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" static const struct nv50_disp_func @@ -39,13 +40,16 @@ gt215_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, + .sor.new = g94_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gt215_hda_eld, .sor.hdmi = gt215_hdmi_ctrl, .pior.nr = 3, + .pior.new = nv50_pior_new, .pior.power = nv50_pior_power, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c new file mode 100644 index 000000000000..a475ea56795c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.c @@ -0,0 +1,72 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ +#include "ior.h" + +static const char * +nvkm_ior_name[] = { + [DAC] = "DAC", + [SOR] = "SOR", + [PIOR] = "PIOR", +}; + +struct nvkm_ior * +nvkm_ior_find(struct nvkm_disp *disp, enum nvkm_ior_type type, int id) +{ + struct nvkm_ior *ior; + list_for_each_entry(ior, &disp->ior, head) { + if (ior->type == type && (id < 0 || ior->id == id)) + return ior; + } + return NULL; +} + +void +nvkm_ior_del(struct nvkm_ior **pior) +{ + struct nvkm_ior *ior = *pior; + if (ior) { + IOR_DBG(ior, "dtor"); + list_del(&ior->head); + kfree(*pior); + *pior = NULL; + } +} + +int +nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, + enum nvkm_ior_type type, int id) +{ + struct nvkm_ior *ior; + if (!(ior = kzalloc(sizeof(*ior), GFP_KERNEL))) + return -ENOMEM; + ior->func = func; + ior->disp = disp; + ior->type = type; + ior->id = id; + snprintf(ior->name, sizeof(ior->name), "%s-%d", + nvkm_ior_name[ior->type], ior->id); + list_add_tail(&ior->head, &disp->ior); + IOR_DBG(ior, "ctor"); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h new file mode 100644 index 000000000000..05857fd415d1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -0,0 +1,43 @@ +#ifndef __NVKM_DISP_IOR_H__ +#define __NVKM_DISP_IOR_H__ +#include "priv.h" + +struct nvkm_ior { + const struct nvkm_ior_func *func; + struct nvkm_disp *disp; + enum nvkm_ior_type { + DAC, + SOR, + PIOR, + } type; + int id; + char name[8]; + + struct list_head head; +}; + +struct nvkm_ior_func { +}; + +int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, + enum nvkm_ior_type type, int id); +void nvkm_ior_del(struct nvkm_ior **); +struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id); + +#define IOR_MSG(i,l,f,a...) do { \ + struct nvkm_ior *_ior = (i); \ + nvkm_##l(&_ior->disp->engine.subdev, "%s: "f, _ior->name, ##a); \ +} while(0) +#define IOR_WARN(i,f,a...) IOR_MSG((i), warn, f, ##a) +#define IOR_DBG(i,f,a...) IOR_MSG((i), debug, f, ##a) + +int nv50_dac_new(struct nvkm_disp *, int); + +int nv50_pior_new(struct nvkm_disp *, int); + +int nv50_sor_new(struct nvkm_disp *, int); +int g94_sor_new(struct nvkm_disp *, int); +int gf119_sor_new(struct nvkm_disp *, int); +int gm107_sor_new(struct nvkm_disp *, int); +int gm200_sor_new(struct nvkm_disp *, int); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index aa7ed87825e5..bd67335d5466 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -23,6 +23,7 @@ */ #include "nv50.h" #include "head.h" +#include "ior.h" #include "rootnv50.h" #include @@ -149,6 +150,24 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, return ret; } + for (i = 0; func->dac.new && i < func->dac.nr; i++) { + ret = func->dac.new(&disp->base, i); + if (ret) + return ret; + } + + for (i = 0; func->pior.new && i < func->pior.nr; i++) { + ret = func->pior.new(&disp->base, i); + if (ret) + return ret; + } + + for (i = 0; func->sor.new && i < func->sor.nr; i++) { + ret = func->sor.new(&disp->base, i); + if (ret) + return ret; + } + return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } @@ -803,11 +822,14 @@ nv50_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, + .dac.new = nv50_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, + .sor.new = nv50_sor_new, .sor.power = nv50_sor_power, .pior.nr = 3, + .pior.new = nv50_pior_new, .pior.power = nv50_pior_power, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 42c2dd83fe56..06249f62747c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -80,12 +80,14 @@ struct nv50_disp_func { struct { int nr; + int (*new)(struct nvkm_disp *, int id); int (*power)(NV50_DISP_MTHD_V1); int (*sense)(NV50_DISP_MTHD_V1); } dac; struct { int nr; + int (*new)(struct nvkm_disp *, int id); int (*power)(NV50_DISP_MTHD_V1); int (*hda_eld)(NV50_DISP_MTHD_V1); int (*hdmi)(NV50_DISP_MTHD_V1); @@ -94,6 +96,7 @@ struct nv50_disp_func { struct { int nr; + int (*new)(struct nvkm_disp *, int id); int (*power)(NV50_DISP_MTHD_V1); } pior; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index cf85f8324ad4..f81ba52c8c19 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" #include @@ -119,3 +120,13 @@ nv50_pior_power(NV50_DISP_MTHD_V1) disp->pior.type[outp->or] = type; return 0; } + +static const struct nvkm_ior_func +nv50_pior = { +}; + +int +nv50_pior_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&nv50_pior, disp, PIOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 732dda513752..87b097327e29 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" #include @@ -276,3 +277,13 @@ nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) nvkm_wr32(device, 0x61c040 + soff + pu_pc * 4, 0x1f008000); } } + +static const struct nvkm_ior_func +g94_sor = { +}; + +int +g94_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&g94_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index dcdb0faaa87a..6ad8af038eae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" void @@ -128,3 +129,13 @@ gf119_sor_dp_new(struct nvkm_disp *disp, int index, { return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); } + +static const struct nvkm_ior_func +gf119_sor = { +}; + +int +gf119_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&gf119_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 7fcaf0378e81..590d66002c58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" int @@ -51,3 +52,13 @@ gm107_sor_dp_new(struct nvkm_disp *disp, int index, { return nvkm_output_dp_new_(&gm107_sor_dp_func, disp, index, dcbE, poutp); } + +static const struct nvkm_ior_func +gm107_sor = { +}; + +int +gm107_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&gm107_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 82b1f64b83b6..df3917cb1cb9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" #include @@ -128,3 +129,13 @@ gm200_sor_magic(struct nvkm_output *outp) if (outp->info.sorconf.link & 2) nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); } + +static const struct nvkm_ior_func +gm200_sor = { +}; + +int +gm200_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&gm200_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 83f44170ddd3..fb43307466cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#include "ior.h" #include "nv50.h" #include "outp.h" @@ -77,3 +78,13 @@ nv50_sor_power(NV50_DISP_MTHD_V1) ); return 0; } + +static const struct nvkm_ior_func +nv50_sor = { +}; + +int +nv50_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&nv50_sor, disp, SOR, id); +} From b3c9c0226c69a8d8e8a4505432f8bbf7188ad348 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 32/73] drm/nouveau/disp: fork off some new hw-specific implementations Upcoming commits make supervisor handling share code between the NV50 and GF119 implementations. Because of this, and a few other cleanups, we need to allow some additional customisation. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 2 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 8 +++ .../drm/nouveau/nvkm/engine/disp/dacgf119.c | 32 ++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 6 ++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c | 57 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 58 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 32 ++++++++++ .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 32 ++++++++++ .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 32 ++++++++++ .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 32 ++++++++++ .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 32 ++++++++++ 20 files changed, 336 insertions(+), 13 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 6d68596ecfc2..05f9c13ab8c3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -24,7 +24,9 @@ int nv50_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int g84_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gt200_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int g94_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int mcp77_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gt215_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int mcp89_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gf119_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **); int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b690bc12a5b7..7bdc7a5ae723 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1257,7 +1257,7 @@ nvaa_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, - .disp = g94_disp_new, + .disp = mcp77_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = gt200_gr_new, @@ -1289,7 +1289,7 @@ nvac_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, - .disp = g94_disp_new, + .disp = mcp77_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = mcp79_gr_new, @@ -1323,7 +1323,7 @@ nvaf_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gt215_ce_new, - .disp = gt215_disp_new, + .disp = mcp89_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = mcp89_gr_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 5bcdc1162fd5..48ce6699183e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -4,7 +4,9 @@ nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/g84.o nvkm-y += nvkm/engine/disp/g94.o nvkm-y += nvkm/engine/disp/gt200.o +nvkm-y += nvkm/engine/disp/mcp77.o nvkm-y += nvkm/engine/disp/gt215.o +nvkm-y += nvkm/engine/disp/mcp89.o nvkm-y += nvkm/engine/disp/gf119.o nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o @@ -21,10 +23,16 @@ nvkm-y += nvkm/engine/disp/headgf119.o nvkm-y += nvkm/engine/disp/ior.o nvkm-y += nvkm/engine/disp/dacnv50.o +nvkm-y += nvkm/engine/disp/dacgf119.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o +nvkm-y += nvkm/engine/disp/sorg84.o nvkm-y += nvkm/engine/disp/sorg94.o +nvkm-y += nvkm/engine/disp/sormcp77.o +nvkm-y += nvkm/engine/disp/sorgt215.o +nvkm-y += nvkm/engine/disp/sormcp89.o nvkm-y += nvkm/engine/disp/sorgf119.o +nvkm-y += nvkm/engine/disp/sorgk104.o nvkm-y += nvkm/engine/disp/sorgm107.o nvkm-y += nvkm/engine/disp/sorgm200.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c new file mode 100644 index 000000000000..03a5bace661b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +gf119_dac = { +}; + +int +gf119_dac_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&gf119_dac, disp, DAC, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index b8aae872f873..dc2a602718cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -43,7 +43,7 @@ g84_disp = { .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, - .sor.new = nv50_sor_new, + .sor.new = g84_sor_new, .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, .pior.nr = 3, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 1a9958c2e73c..50dd13596939 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -507,7 +507,7 @@ gf119_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, - .dac.new = nv50_dac_new, + .dac.new = gf119_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index aeaaf4280d04..3c3a327095fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -39,11 +39,11 @@ gk104_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, - .dac.new = nv50_dac_new, + .dac.new = gf119_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, - .sor.new = gf119_sor_new, + .sor.new = gk104_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 90080c423bdc..84f774ae5f7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -39,11 +39,11 @@ gk110_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, - .dac.new = nv50_dac_new, + .dac.new = gf119_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, - .sor.new = gf119_sor_new, + .sor.new = gk104_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 12ad91b4f36c..4e43fcdc2c7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -39,7 +39,7 @@ gm107_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm107_sor_dp_new, .dac.nr = 3, - .dac.new = nv50_dac_new, + .dac.new = gf119_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index e62488f97546..90cdc95c71ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -39,7 +39,7 @@ gm200_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm200_sor_dp_new, .dac.nr = 3, - .dac.new = nv50_dac_new, + .dac.new = gf119_dac_new, .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 15a2f3ce3e9c..3e9399be4d86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -43,7 +43,7 @@ gt200_disp = { .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, - .sor.new = nv50_sor_new, + .sor.new = g84_sor_new, .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, .pior.nr = 3, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index e5ceba9e2ab9..7c7ad97a4849 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -44,7 +44,7 @@ gt215_disp = { .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, - .sor.new = g94_sor_new, + .sor.new = gt215_sor_new, .sor.power = nv50_sor_power, .sor.hda_eld = gt215_hda_eld, .sor.hdmi = gt215_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 05857fd415d1..2abba07ae632 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -32,12 +32,18 @@ struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id); #define IOR_DBG(i,f,a...) IOR_MSG((i), debug, f, ##a) int nv50_dac_new(struct nvkm_disp *, int); +int gf119_dac_new(struct nvkm_disp *, int); int nv50_pior_new(struct nvkm_disp *, int); int nv50_sor_new(struct nvkm_disp *, int); +int g84_sor_new(struct nvkm_disp *, int); int g94_sor_new(struct nvkm_disp *, int); +int mcp77_sor_new(struct nvkm_disp *, int); +int gt215_sor_new(struct nvkm_disp *, int); +int mcp89_sor_new(struct nvkm_disp *, int); int gf119_sor_new(struct nvkm_disp *, int); +int gk104_sor_new(struct nvkm_disp *, int); int gm107_sor_new(struct nvkm_disp *, int); int gm200_sor_new(struct nvkm_disp *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c new file mode 100644 index 000000000000..f8710425ea54 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nv50.h" +#include "head.h" +#include "ior.h" +#include "rootnv50.h" + +static const struct nv50_disp_func +mcp77_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_super, + .root = &g94_disp_root_oclass, + .head.new = nv50_head_new, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.new = nv50_dac_new, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.new = mcp77_sor_new, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.new = nv50_pior_new, + .pior.power = nv50_pior_power, +}; + +int +mcp77_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return nv50_disp_new_(&mcp77_disp, device, index, 2, pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c new file mode 100644 index 000000000000..e417d1dbe4ce --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -0,0 +1,58 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "nv50.h" +#include "head.h" +#include "ior.h" +#include "rootnv50.h" + +static const struct nv50_disp_func +mcp89_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_super, + .root = >215_disp_root_oclass, + .head.new = nv50_head_new, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.new = nv50_dac_new, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.new = mcp89_sor_new, + .sor.power = nv50_sor_power, + .sor.hda_eld = gt215_hda_eld, + .sor.hdmi = gt215_hdmi_ctrl, + .pior.nr = 3, + .pior.new = nv50_pior_new, + .pior.power = nv50_pior_power, +}; + +int +mcp89_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) +{ + return nv50_disp_new_(&mcp89_disp, device, index, 2, pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c new file mode 100644 index 000000000000..427e04c602e8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +g84_sor = { +}; + +int +g84_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&g84_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c new file mode 100644 index 000000000000..a1946eca85ed --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +gk104_sor = { +}; + +int +gk104_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&gk104_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c new file mode 100644 index 000000000000..dc209826156e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +gt215_sor = { +}; + +int +gt215_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(>215_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c new file mode 100644 index 000000000000..09d42240510a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +mcp77_sor = { +}; + +int +mcp77_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&mcp77_sor, disp, SOR, id); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c new file mode 100644 index 000000000000..f8fba6caad33 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include "ior.h" + +static const struct nvkm_ior_func +mcp89_sor = { +}; + +int +mcp89_sor_new(struct nvkm_disp *disp, int id) +{ + return nvkm_ior_new_(&mcp89_sor, disp, SOR, id); +} From 01a976376b6e57838f223dd2d2639597efd92db4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 33/73] drm/nouveau/disp: identity-map display paths to output resources This essentially replicates our current behaviour in a way that's compatible with the new model that's emerging, so that we're able to start porting the hw-specific functions to it. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 10 +++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 74 ++++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 8 +- 4 files changed, 89 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index d62e93bb0f70..601fa625e440 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -562,7 +562,10 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, u32 data; int ret; - nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp); + ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp); + if (ret) + return ret; + dp->aux = aux; if (!dp->aux) { OUTP_ERR(&dp->outp, "no aux"); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 2abba07ae632..a8d80eb8d893 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -14,6 +14,16 @@ struct nvkm_ior { char name[8]; struct list_head head; + + struct nvkm_ior_state { + enum nvkm_ior_proto { + CRT, + TMDS, + LVDS, + DP, + UNKNOWN + } proto:3; + } arm, asy; }; struct nvkm_ior_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index f030ff51d076..895a84ca1501 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,11 +22,41 @@ * Authors: Ben Skeggs */ #include "outp.h" +#include "ior.h" #include #include #include +static enum nvkm_ior_proto +nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type) +{ + switch (outp->info.location) { + case 0: + switch (outp->info.type) { + case DCB_OUTPUT_ANALOG: *type = DAC; return CRT; + case DCB_OUTPUT_TMDS : *type = SOR; return TMDS; + case DCB_OUTPUT_LVDS : *type = SOR; return LVDS; + case DCB_OUTPUT_DP : *type = SOR; return DP; + default: + break; + } + break; + case 1: + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: *type = PIOR; return TMDS; + case DCB_OUTPUT_DP : *type = PIOR; return TMDS; /* not a bug */ + default: + break; + } + break; + default: + break; + } + WARN_ON(1); + return UNKNOWN; +} + void nvkm_outp_fini(struct nvkm_outp *outp) { @@ -34,9 +64,38 @@ nvkm_outp_fini(struct nvkm_outp *outp) outp->func->fini(outp); } +static void +nvkm_outp_init_route(struct nvkm_output *outp) +{ + struct nvkm_disp *disp = outp->disp; + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; + struct nvkm_ior *ior; + int id; + + proto = nvkm_outp_xlat(outp, &type); + if (proto == UNKNOWN) + return; + + /* Determine the specific OR, if any, this device is attached to. */ + if (1) { + /* Prior to DCB 4.1, this is hardwired like so. */ + id = ffs(outp->info.or) - 1; + } + + ior = nvkm_ior_find(disp, type, id); + if (!ior) { + WARN_ON(1); + return; + } + + outp->ior = ior; +} + void nvkm_outp_init(struct nvkm_outp *outp) { + nvkm_outp_init_route(outp); if (outp->func->init) outp->func->init(outp); } @@ -53,11 +112,13 @@ nvkm_outp_del(struct nvkm_outp **poutp) } } -void +int nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct nvkm_outp *outp) { struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; outp->func = func; outp->disp = disp; @@ -72,6 +133,13 @@ nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, outp->info.type >= 2 ? outp->info.sorconf.link : 0, outp->info.connector, outp->info.i2c_index, outp->info.bus, outp->info.heads); + + /* Cull output paths we can't map to an output resource. */ + proto = nvkm_outp_xlat(outp, &type); + if (proto == UNKNOWN) + return -ENODEV; + + return 0; } int @@ -81,7 +149,5 @@ nvkm_outp_new_(const struct nvkm_outp_func *func, { if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) return -ENOMEM; - - nvkm_outp_ctor(func, disp, index, dcbE, *poutp); - return 0; + return nvkm_outp_ctor(func, disp, index, dcbE, *poutp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 682fc99c9351..e48251c37822 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -11,16 +11,18 @@ struct nvkm_outp { int index; struct dcb_output info; - // whatever (if anything) is pointed at by the dcb device entry struct nvkm_i2c_bus *i2c; int or; struct list_head head; struct nvkm_conn *conn; + + /* Assembly state. */ + struct nvkm_ior *ior; }; -void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_outp *); +int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_outp *); void nvkm_outp_del(struct nvkm_outp **); void nvkm_outp_init(struct nvkm_outp *); void nvkm_outp_fini(struct nvkm_outp *); From 02d786ccbc7eaaef6ef8380b9d450ef0f4362133 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 34/73] drm/nouveau/disp/dp: remove DP_PWR method This hasn't been used since atomic. We may want to re-implement "fast" DPMS at some point, but for now, this just gets in the way. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 7 ------ .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 24 ------------------- 2 files changed, 31 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index 9d46ebac58a2..22304cc99f39 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -33,7 +33,6 @@ struct nv50_disp_mthd_v1 { #define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 -#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24 #define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 #define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26 #define NV50_DISP_MTHD_V1_PIOR_PWR 0x30 @@ -88,12 +87,6 @@ struct nv50_disp_sor_lvds_script_v0 { __u8 pad04[4]; }; -struct nv50_disp_sor_dp_pwr_v0 { - __u8 version; - __u8 state; - __u8 pad02[6]; -}; - struct nv50_disp_sor_dp_mst_link_v0 { __u8 version; __u8 state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 609bfae9acbb..b817cb511f35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -124,30 +124,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return ret; } break; - case NV50_DISP_MTHD_V1_SOR_DP_PWR: { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - union { - struct nv50_disp_sor_dp_pwr_v0 v0; - } *args = data; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor dp pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n", - args->v0.version, args->v0.state); - if (args->v0.state == 0) { - nvkm_notify_put(&outpdp->irq); - outpdp->func->lnk_pwr(outpdp, 0); - atomic_set(&outpdp->lt.done, 0); - return 0; - } else - if (args->v0.state != 0) { - nvkm_output_dp_train(&outpdp->base, 0); - return 0; - } - } else - return ret; - } - break; case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: { struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); union { From 75eefe95ee7565c695d1e736005876d18742537f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 35/73] drm/nouveau/disp/dp: store current link configuration in nvkm_ior We care about this information outside of link training. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 66 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 8 +++ 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 601fa625e440..94c861a3f999 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -23,6 +23,7 @@ */ #include "dp.h" #include "conn.h" +#include "ior.h" #include "nv50.h" #include @@ -33,8 +34,6 @@ struct lt_state { struct nvkm_dp *dp; - int link_nr; - u32 link_bw; u8 stat[6]; u8 conf[4]; bool pc2; @@ -76,7 +75,7 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) struct nvkm_dp *dp = lt->dp; int ret, i; - for (i = 0; i < lt->link_nr; i++) { + for (i = 0; i < dp->outp.ior->dp.nr; i++) { u8 lane = (lt->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; u8 lpc2 = (lt->pc2stat >> (i * 2)) & 0x3; u8 lpre = (lane & 0x0c) >> 2; @@ -137,7 +136,7 @@ nvkm_dp_train_eq(struct lt_state *lt) bool eq_done = false, cr_done = true; int tries = 0, i; - if (lt->dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED) + if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) nvkm_dp_train_pattern(lt, 3); else nvkm_dp_train_pattern(lt, 2); @@ -149,7 +148,7 @@ nvkm_dp_train_eq(struct lt_state *lt) break; eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); - for (i = 0; i < lt->link_nr && eq_done; i++) { + for (i = 0; i < lt->dp->outp.ior->dp.nr && eq_done; i++) { u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; if (!(lane & DPCD_LS02_LANE0_CR_DONE)) cr_done = false; @@ -177,7 +176,7 @@ nvkm_dp_train_cr(struct lt_state *lt) break; cr_done = true; - for (i = 0; i < lt->link_nr; i++) { + for (i = 0; i < lt->dp->outp.ior->dp.nr; i++) { u8 lane = (lt->stat[i >> 1] >> ((i & 1) * 4)) & 0xf; if (!(lane & DPCD_LS02_LANE0_CR_DONE)) { cr_done = false; @@ -200,6 +199,7 @@ static int nvkm_dp_train_links(struct lt_state *lt) { struct nvkm_dp *dp = lt->dp; + struct nvkm_ior *ior = dp->outp.ior; struct nvkm_disp *disp = dp->outp.disp; struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvkm_bios *bios = subdev->device->bios; @@ -215,7 +215,8 @@ nvkm_dp_train_links(struct lt_state *lt) u8 sink[2]; int ret; - OUTP_DBG(&dp->outp, "%d lanes at %d KB/s", lt->link_nr, lt->link_bw); + OUTP_DBG(&dp->outp, "training %d x %d MB/s", + ior->dp.nr, ior->dp.bw * 27); /* Intersect misc. capabilities of the OR and sink. */ if (disp->engine.subdev.device->chipset < 0xd0) @@ -225,11 +226,11 @@ nvkm_dp_train_links(struct lt_state *lt) /* Set desired link configuration on the source. */ if ((lnkcmp = lt->dp->info.lnkcmp)) { if (dp->version < 0x30) { - while ((lt->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) + while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; init.offset = nvbios_rd16(bios, lnkcmp + 2); } else { - while ((lt->link_bw / 27000) < nvbios_rd08(bios, lnkcmp)) + while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) lnkcmp += 3; init.offset = nvbios_rd16(bios, lnkcmp + 1); } @@ -237,21 +238,19 @@ nvkm_dp_train_links(struct lt_state *lt) nvbios_exec(&init); } - ret = dp->func->lnk_ctl(dp, lt->link_nr, lt->link_bw / 27000, - dp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = dp->func->lnk_ctl(dp, ior->dp.nr, ior->dp.bw, ior->dp.ef); if (ret) { if (ret < 0) OUTP_ERR(&dp->outp, "lnk_ctl failed with %d", ret); return ret; } - dp->func->lnk_pwr(dp, lt->link_nr); + dp->func->lnk_pwr(dp, ior->dp.nr); /* Set desired link configuration on the sink. */ - sink[0] = lt->link_bw / 27000; - sink[1] = lt->link_nr; - if (dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) + sink[0] = ior->dp.bw; + sink[1] = ior->dp.nr; + if (ior->dp.ef) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; return nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); @@ -276,7 +275,7 @@ nvkm_dp_train_fini(struct lt_state *lt) } static void -nvkm_dp_train_init(struct lt_state *lt, bool spread) +nvkm_dp_train_init(struct lt_state *lt) { struct nvkm_dp *dp = lt->dp; struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; @@ -289,7 +288,7 @@ nvkm_dp_train_init(struct lt_state *lt, bool spread) }; /* Execute EnableSpread/DisableSpread script from DP Info table. */ - if (spread) + if (dp->dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) init.offset = dp->info.script[2]; else init.offset = dp->info.script[3]; @@ -321,7 +320,12 @@ static void nvkm_dp_train(struct nvkm_dp *dp) { struct nv50_disp *disp = nv50_disp(dp->outp.disp); - const struct dp_rates *cfg = nvkm_dp_rates - 1; + struct nvkm_ior *ior = dp->outp.ior; + const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; + const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; + const u8 outp_nr = dp->outp.info.dpconf.link_nr; + const u8 outp_bw = dp->outp.info.dpconf.link_bw; + const struct dp_rates *cfg; struct lt_state lt = { .dp = dp, }; @@ -331,13 +335,6 @@ nvkm_dp_train(struct nvkm_dp *dp) if (!dp->outp.info.location && disp->func->sor.magic) disp->func->sor.magic(&dp->outp); - if ((dp->dpcd[2] & 0x1f) > dp->outp.info.dpconf.link_nr) { - dp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; - dp->dpcd[2] |= dp->outp.info.dpconf.link_nr; - } - if (dp->dpcd[1] > dp->outp.info.dpconf.link_bw) - dp->dpcd[1] = dp->outp.info.dpconf.link_bw; - /* Ensure sink is not in a low-power state. */ if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { @@ -348,14 +345,17 @@ nvkm_dp_train(struct nvkm_dp *dp) } /* Link training. */ - nvkm_dp_train_init(<, dp->dpcd[3] & 0x01); - while (ret = -EIO, (++cfg)->rate) { + nvkm_dp_train_init(<); + for (ret = -EINVAL, cfg = nvkm_dp_rates; cfg->rate; cfg++) { /* Skip configurations not supported by both OR and sink. */ - while (cfg->nr > (dp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) || - cfg->bw > (dp->dpcd[DPCD_RC01_MAX_LINK_RATE])) - cfg++; - lt.link_bw = cfg->bw * 27000; - lt.link_nr = cfg->nr; + if (cfg[1].rate && + (cfg->nr > outp_nr || cfg->bw > outp_bw || + cfg->nr > sink_nr || cfg->bw > sink_bw)) + continue; + ior->dp.mst = dp->lt.mst; + ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; + ior->dp.bw = cfg->bw; + ior->dp.nr = cfg->nr; /* Program selected link configuration. */ ret = nvkm_dp_train_links(<); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index a8d80eb8d893..fd33eed68a2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -24,6 +24,14 @@ struct nvkm_ior { UNKNOWN } proto:3; } arm, asy; + + /* Armed DP state. */ + struct { + bool mst; + bool ef; + u8 nr; + u8 bw; + } dp; }; struct nvkm_ior_func { From 4423c743ef961153d274f3ec0704672ba979419c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 36/73] drm/nouveau/disp/dp: no need for lt_state except during manual link training This struct doesn't hold link configuration data anymore, so we can limit its use to internal DP training (anx9805 handles training for external DP). Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 55 ++++++++----------- 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 94c861a3f999..2b3aca044975 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -196,9 +196,8 @@ nvkm_dp_train_cr(struct lt_state *lt) } static int -nvkm_dp_train_links(struct lt_state *lt) +nvkm_dp_train_links(struct nvkm_dp *dp) { - struct nvkm_dp *dp = lt->dp; struct nvkm_ior *ior = dp->outp.ior; struct nvkm_disp *disp = dp->outp.disp; struct nvkm_subdev *subdev = &disp->engine.subdev; @@ -211,6 +210,9 @@ nvkm_dp_train_links(struct lt_state *lt) .crtc = -1, .execute = 1, }; + struct lt_state lt = { + .dp = dp, + }; u32 lnkcmp; u8 sink[2]; int ret; @@ -220,11 +222,11 @@ nvkm_dp_train_links(struct lt_state *lt) /* Intersect misc. capabilities of the OR and sink. */ if (disp->engine.subdev.device->chipset < 0xd0) - dp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; - lt->pc2 = dp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED; + dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; + lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; /* Set desired link configuration on the source. */ - if ((lnkcmp = lt->dp->info.lnkcmp)) { + if ((lnkcmp = lt.dp->info.lnkcmp)) { if (dp->version < 0x30) { while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; @@ -253,13 +255,22 @@ nvkm_dp_train_links(struct lt_state *lt) if (ior->dp.ef) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - return nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); + ret = nvkm_wraux(dp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); + if (ret) + return ret; + + /* Attempt to train the link in this configuration. */ + memset(lt.stat, 0x00, sizeof(lt.stat)); + ret = nvkm_dp_train_cr(<); + if (ret == 0) + ret = nvkm_dp_train_eq(<); + nvkm_dp_train_pattern(<, 0); + return ret; } static void -nvkm_dp_train_fini(struct lt_state *lt) +nvkm_dp_train_fini(struct nvkm_dp *dp) { - struct nvkm_dp *dp = lt->dp; struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; struct nvbios_init init = { .subdev = subdev, @@ -275,9 +286,8 @@ nvkm_dp_train_fini(struct lt_state *lt) } static void -nvkm_dp_train_init(struct lt_state *lt) +nvkm_dp_train_init(struct nvkm_dp *dp) { - struct nvkm_dp *dp = lt->dp; struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; struct nvbios_init init = { .subdev = subdev, @@ -326,9 +336,6 @@ nvkm_dp_train(struct nvkm_dp *dp) const u8 outp_nr = dp->outp.info.dpconf.link_nr; const u8 outp_bw = dp->outp.info.dpconf.link_bw; const struct dp_rates *cfg; - struct lt_state lt = { - .dp = dp, - }; u8 pwr; int ret; @@ -345,8 +352,8 @@ nvkm_dp_train(struct nvkm_dp *dp) } /* Link training. */ - nvkm_dp_train_init(<); - for (ret = -EINVAL, cfg = nvkm_dp_rates; cfg->rate; cfg++) { + nvkm_dp_train_init(dp); + for (ret = -EINVAL, cfg = nvkm_dp_rates; ret < 0 && cfg->rate; cfg++) { /* Skip configurations not supported by both OR and sink. */ if (cfg[1].rate && (cfg->nr > outp_nr || cfg->bw > outp_bw || @@ -358,23 +365,9 @@ nvkm_dp_train(struct nvkm_dp *dp) ior->dp.nr = cfg->nr; /* Program selected link configuration. */ - ret = nvkm_dp_train_links(<); - if (ret == 0) { - /* Attempt to train the link in this configuration. */ - memset(lt.stat, 0x00, sizeof(lt.stat)); - if (!nvkm_dp_train_cr(<) && - !nvkm_dp_train_eq(<)) - break; - } else - if (ret) { - /* nvkm_dp_train_links() handled training, or - * we failed to communicate with the sink. - */ - break; - } + ret = nvkm_dp_train_links(dp); } - nvkm_dp_train_pattern(<, 0); - nvkm_dp_train_fini(<); + nvkm_dp_train_fini(dp); if (ret < 0) OUTP_ERR(&dp->outp, "training failed"); From fafa8b5c9f7426cef6b9b52b8582a867edbc7a06 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 37/73] drm/nouveau/disp/dp: use cached link configuration when checking link status Saves some trips across the aux channel. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 2b3aca044975..4941643dd8fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -326,7 +326,7 @@ static const struct dp_rates { {} }; -static void +static int nvkm_dp_train(struct nvkm_dp *dp) { struct nv50_disp *disp = nv50_disp(dp->outp.disp); @@ -370,39 +370,34 @@ nvkm_dp_train(struct nvkm_dp *dp) nvkm_dp_train_fini(dp); if (ret < 0) OUTP_ERR(&dp->outp, "training failed"); - - OUTP_DBG(&dp->outp, "training done"); + else + OUTP_DBG(&dp->outp, "training done"); atomic_set(&dp->lt.done, 1); + return ret; } int -nvkm_output_dp_train(struct nvkm_outp *outp, u32 datarate) +nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps) { struct nvkm_dp *dp = nvkm_dp(outp); + struct nvkm_ior *ior = dp->outp.ior; bool retrain = true; - u8 link[2], stat[3]; - u32 linkrate; + u32 linkKBps; + u32 dataKBps; + u8 stat[3]; int ret, i; mutex_lock(&dp->mutex); - /* check that the link is trained at a high enough rate */ - ret = nvkm_rdaux(dp->aux, DPCD_LC00_LINK_BW_SET, link, 2); - if (ret) { - OUTP_DBG(&dp->outp, - "failed to read link config, assuming no sink"); + /* Check that link configuration meets current requirements. */ + linkKBps = ior->dp.bw * 27000 * ior->dp.nr; + dataKBps = DIV_ROUND_UP(datakbps, 8); + if (linkKBps < dataKBps) { + OUTP_DBG(&dp->outp, "link requirements changed"); goto done; } - linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET); - linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ - datarate = (datarate + 9) / 10; /* -> decakilobits */ - if (linkrate < datarate) { - OUTP_DBG(&dp->outp, "link not trained at sufficient rate"); - goto done; - } - - /* check that link is still trained */ + /* Check that link is still trained. */ ret = nvkm_rdaux(dp->aux, DPCD_LS02, stat, 3); if (ret) { OUTP_DBG(&dp->outp, @@ -411,7 +406,7 @@ nvkm_output_dp_train(struct nvkm_outp *outp, u32 datarate) } if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) { - for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) { + for (i = 0; i < ior->dp.nr; i++) { u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f; if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || @@ -435,7 +430,7 @@ done: dp->dpcd[DPCD_RC02] = dp->outp.info.dpconf.link_nr; } - nvkm_dp_train(dp); + ret = nvkm_dp_train(dp); } mutex_unlock(&dp->mutex); From 49f2b376df7f9235ccbed1e90f0ec93040001a9b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 38/73] drm/nouveau/disp/dp: determine a failsafe link training rate The aim here is to protect the OR against locking up when something unexpected happens (such as the display disappearing during modeset, or the DD misbehaving). Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 4941643dd8fa..090567d94876 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -327,7 +327,7 @@ static const struct dp_rates { }; static int -nvkm_dp_train(struct nvkm_dp *dp) +nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) { struct nv50_disp *disp = nv50_disp(dp->outp.disp); struct nvkm_ior *ior = dp->outp.ior; @@ -335,13 +335,34 @@ nvkm_dp_train(struct nvkm_dp *dp) const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; const u8 outp_nr = dp->outp.info.dpconf.link_nr; const u8 outp_bw = dp->outp.info.dpconf.link_bw; - const struct dp_rates *cfg; + const struct dp_rates *failsafe = NULL, *cfg; + int ret = -EINVAL; u8 pwr; - int ret; if (!dp->outp.info.location && disp->func->sor.magic) disp->func->sor.magic(&dp->outp); + /* Find the lowest configuration of the OR that can support + * the required link rate. + * + * We will refuse to program the OR to lower rates, even if + * link training fails at higher rates (or even if the sink + * can't support the rate at all, though the DD is supposed + * to prevent such situations from happening). + * + * Attempting to do so can cause the entire display to hang, + * and it's better to have a failed modeset than that. + */ + for (cfg = nvkm_dp_rates; cfg->rate; cfg++) { + if (cfg->nr <= outp_nr && cfg->nr <= outp_bw) + failsafe = cfg; + if (failsafe && cfg[1].rate < dataKBps) + break; + } + + if (WARN_ON(!failsafe)) + return ret; + /* Ensure sink is not in a low-power state. */ if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { @@ -352,13 +373,17 @@ nvkm_dp_train(struct nvkm_dp *dp) } /* Link training. */ + OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)", + failsafe->nr, failsafe->bw * 27); nvkm_dp_train_init(dp); - for (ret = -EINVAL, cfg = nvkm_dp_rates; ret < 0 && cfg->rate; cfg++) { + for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) { /* Skip configurations not supported by both OR and sink. */ - if (cfg[1].rate && - (cfg->nr > outp_nr || cfg->bw > outp_bw || - cfg->nr > sink_nr || cfg->bw > sink_bw)) - continue; + if ((cfg->nr > outp_nr || cfg->bw > outp_bw || + cfg->nr > sink_nr || cfg->bw > sink_bw)) { + if (cfg != failsafe) + continue; + OUTP_ERR(&dp->outp, "link rate unsupported by sink"); + } ior->dp.mst = dp->lt.mst; ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; ior->dp.bw = cfg->bw; @@ -422,17 +447,8 @@ nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps) } done: - if (retrain || !atomic_read(&dp->lt.done)) { - /* no sink, but still need to configure source */ - if (dp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) { - dp->dpcd[DPCD_RC01_MAX_LINK_RATE] = - dp->outp.info.dpconf.link_bw; - dp->dpcd[DPCD_RC02] = - dp->outp.info.dpconf.link_nr; - } - ret = nvkm_dp_train(dp); - } - + if (retrain || !atomic_read(&dp->lt.done)) + ret = nvkm_dp_train(dp, dataKBps); mutex_unlock(&dp->mutex); return ret; } From 22e008f90d546507d57bdac92030cece73ded09a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 39/73] drm/nouveau/disp/dp: only check for re-train when the link is active An upcoming commit will limit link training to only when the sink is meant to be displaying an image. We still need IRQs enabled even when the link isn't trained (for MST messages), but don't want to train the link unnecessarily. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 51 ++++--------------- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 3 +- 4 files changed, 13 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 090567d94876..a67192ad5cf3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -491,7 +491,13 @@ nvkm_dp_hpd(struct nvkm_notify *notify) struct nvif_notify_conn_rep_v0 rep = {}; OUTP_DBG(&dp->outp, "HPD: %d", line->mask); - nvkm_dp_enable(dp, true); + if (line->mask & NVKM_I2C_IRQ) { + if (atomic_read(&dp->lt.done)) + nvkm_output_dp_train(&dp->outp, 0); + rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ; + } else { + nvkm_dp_enable(dp, true); + } if (line->mask & NVKM_I2C_UNPLUG) rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; @@ -502,30 +508,11 @@ nvkm_dp_hpd(struct nvkm_notify *notify) return NVKM_NOTIFY_KEEP; } -static int -nvkm_dp_irq(struct nvkm_notify *notify) -{ - const struct nvkm_i2c_ntfy_rep *line = notify->data; - struct nvkm_dp *dp = container_of(notify, typeof(*dp), irq); - struct nvkm_conn *conn = dp->outp.conn; - struct nvkm_disp *disp = dp->outp.disp; - struct nvif_notify_conn_rep_v0 rep = { - .mask = NVIF_NOTIFY_CONN_V0_IRQ, - }; - - OUTP_DBG(&dp->outp, "IRQ: %d", line->mask); - nvkm_output_dp_train(&dp->outp, 0); - - nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; -} - static void nvkm_dp_fini(struct nvkm_outp *outp) { struct nvkm_dp *dp = nvkm_dp(outp); nvkm_notify_put(&dp->hpd); - nvkm_notify_put(&dp->irq); nvkm_dp_enable(dp, false); } @@ -535,7 +522,6 @@ nvkm_dp_init(struct nvkm_outp *outp) struct nvkm_dp *dp = nvkm_dp(outp); nvkm_notify_put(&dp->outp.conn->hpd); nvkm_dp_enable(dp, true); - nvkm_notify_get(&dp->irq); nvkm_notify_get(&dp->hpd); } @@ -544,7 +530,6 @@ nvkm_dp_dtor(struct nvkm_outp *outp) { struct nvkm_dp *dp = nvkm_dp(outp); nvkm_notify_fini(&dp->hpd); - nvkm_notify_fini(&dp->irq); return dp; } @@ -588,27 +573,11 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, OUTP_DBG(&dp->outp, "bios dp %02x %02x %02x %02x", dp->version, hdr, cnt, len); - /* link maintenance */ - ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_irq, true, - &(struct nvkm_i2c_ntfy_req) { - .mask = NVKM_I2C_IRQ, - .port = dp->aux->id, - }, - sizeof(struct nvkm_i2c_ntfy_req), - sizeof(struct nvkm_i2c_ntfy_rep), - &dp->irq); - if (ret) { - OUTP_ERR(&dp->outp, "error monitoring aux irq: %d", ret); - return ret; - } - - mutex_init(&dp->mutex); - atomic_set(&dp->lt.done, 0); - /* hotplug detect, replaces gpio-based mechanism with aux events */ ret = nvkm_notify_init(NULL, &i2c->event, nvkm_dp_hpd, true, &(struct nvkm_i2c_ntfy_req) { - .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, + .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG | + NVKM_I2C_IRQ, .port = dp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), @@ -619,6 +588,8 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, return ret; } + mutex_init(&dp->mutex); + atomic_set(&dp->lt.done, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 65d6b478eb56..9d18aed75b10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -19,7 +19,6 @@ struct nvkm_dp { struct nvkm_i2c_aux *aux; - struct nvkm_notify irq; struct nvkm_notify hpd; bool present; u8 dpcd[16]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 50dd13596939..94eb6b29e14c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -201,9 +201,8 @@ gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) .execute = 1, }; - nvkm_notify_put(&outpdp->irq); - nvbios_exec(&init); atomic_set(&outpdp->lt.done, 0); + nvbios_exec(&init); } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index bd67335d5466..acc663061ceb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -661,9 +661,8 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) .execute = 1, }; - nvkm_notify_put(&outpdp->irq); - nvbios_exec(&init); atomic_set(&outpdp->lt.done, 0); + nvbios_exec(&init); } } From 7d0a01a6dec9737d24be5ac223e73a0725eac8a0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 40/73] drm/nouveau/disp/dp: train link only when actively displaying an image This essentially (unless the link becomes unstable and needs to be re-trained) gives us a single entry-point to link training, during supervisor handling, where we can ensure all routing is up to date. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 8 ++------ 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index a67192ad5cf3..f3b255027c11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -417,7 +417,9 @@ nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps) /* Check that link configuration meets current requirements. */ linkKBps = ior->dp.bw * 27000 * ior->dp.nr; dataKBps = DIV_ROUND_UP(datakbps, 8); - if (linkKBps < dataKBps) { + OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d", + dataKBps, linkKBps, ior->dp.mst, dp->lt.mst); + if (linkKBps < dataKBps || ior->dp.mst != dp->lt.mst) { OUTP_DBG(&dp->outp, "link requirements changed"); goto done; } @@ -466,10 +468,8 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) } if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, - sizeof(dp->dpcd))) { - nvkm_output_dp_train(&dp->outp, 0); + sizeof(dp->dpcd))) return; - } } if (dp->present) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index b817cb511f35..9cf1365f5261 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -125,7 +125,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_SOR_DP_MST_LINK: { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + struct nvkm_dp *dp = nvkm_dp(outp); union { struct nv50_disp_sor_dp_mst_link_v0 v0; } *args = data; @@ -134,11 +134,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { nvif_ioctl(object, "disp sor dp mst link vers %d state %d\n", args->v0.version, args->v0.state); - if (outpdp->lt.mst != !!args->v0.state) { - outpdp->lt.mst = !!args->v0.state; - atomic_set(&outpdp->lt.done, 0); - nvkm_output_dp_train(&outpdp->base, 0); - } + dp->lt.mst = !!args->v0.state; return 0; } else return ret; From 3607bfd398204ddb11f63c09b1cc608adf85f96c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 41/73] drm/nouveau/disp/nv50-: execute supervisor on its own workqueue Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 94eb6b29e14c..2ffbb995f134 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -459,7 +459,7 @@ gf119_disp_intr(struct nv50_disp *disp) u32 stat = nvkm_rd32(device, 0x6100ac); if (stat & 0x00000007) { disp->super = (stat & 0x00000007); - schedule_work(&disp->supervisor); + queue_work(disp->wq, &disp->supervisor); nvkm_wr32(device, 0x6100ac, disp->super); stat &= ~0x00000007; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index acc663061ceb..21bdf301d37e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -111,6 +111,8 @@ nv50_disp_dtor_(struct nvkm_disp *base) { struct nv50_disp *disp = nv50_disp(base); nvkm_event_fini(&disp->uevent); + if (disp->wq) + destroy_workqueue(disp->wq); return disp; } @@ -136,7 +138,6 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) return -ENOMEM; - INIT_WORK(&disp->supervisor, func->super); disp->func = func; *pdisp = &disp->base; @@ -144,6 +145,11 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, if (ret) return ret; + disp->wq = create_singlethread_workqueue("nvkm-disp"); + if (!disp->wq) + return -ENOMEM; + INIT_WORK(&disp->supervisor, func->super); + for (i = 0; func->head.new && i < heads; i++) { ret = func->head.new(&disp->base, i); if (ret) @@ -803,7 +809,7 @@ nv50_disp_intr(struct nv50_disp *disp) if (intr1 & 0x00000070) { disp->super = (intr1 & 0x00000070); - schedule_work(&disp->supervisor); + queue_work(disp->wq, &disp->supervisor); nvkm_wr32(device, 0x610024, disp->super); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 06249f62747c..fe7ef0abef6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -12,6 +12,7 @@ struct nv50_disp { const struct nv50_disp_func *func; struct nvkm_disp base; + struct workqueue_struct *wq; struct work_struct supervisor; u32 super; From 29c0ca7389ce8e259516d14397890bfe0ab462c8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 42/73] drm/nouveau/disp/nv50-: fetch head/OR state at beginning of supervisor This data will be used by essentially every part of the supervisor handling process. Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/dacgf119.c | 19 +++++++++++++++ .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 19 +++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 9 +++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 18 ++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 2 ++ .../drm/nouveau/nvkm/engine/disp/piornv50.c | 20 ++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 24 +++++++++++++++++++ .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 24 +++++++++++++++++++ .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + .../drm/nouveau/nvkm/engine/disp/sornv50.c | 22 +++++++++++++++++ 17 files changed, 165 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c index 03a5bace661b..546fb6c99ab1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -21,8 +21,27 @@ */ #include "ior.h" +static void +gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 coff = (state == &dac->asy) * 0x20000 + dac->id * 0x20; + u32 ctrl = nvkm_rd32(device, 0x640180 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = CRT; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x0000000f; +} + static const struct nvkm_ior_func gf119_dac = { + .state = gf119_dac_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 5e2dbd5de511..6598252888ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -126,8 +126,27 @@ nv50_dac_power(NV50_DISP_MTHD_V1) return 0; } +static void +nv50_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 coff = dac->id * 8 + (state == &dac->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610b58 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = CRT; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; +} + static const struct nvkm_ior_func nv50_dac = { + .state = nv50_dac_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 2ffbb995f134..a030a2820709 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -362,6 +362,7 @@ gf119_disp_super(struct work_struct *work) if (disp->super & 0x00000001) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); + nv50_disp_super_1(disp); list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index fd33eed68a2e..ef9d23a3b77b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -16,6 +16,8 @@ struct nvkm_ior { struct list_head head; struct nvkm_ior_state { + unsigned rgdiv; + unsigned proto_evo:4; enum nvkm_ior_proto { CRT, TMDS, @@ -23,6 +25,8 @@ struct nvkm_ior { DP, UNKNOWN } proto:3; + unsigned link:2; + unsigned head:4; } arm, asy; /* Armed DP state. */ @@ -35,6 +39,7 @@ struct nvkm_ior { }; struct nvkm_ior_func { + void (*state)(struct nvkm_ior *, struct nvkm_ior_state *); }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, @@ -42,6 +47,10 @@ int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, void nvkm_ior_del(struct nvkm_ior **); struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id); +void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); + #define IOR_MSG(i,l,f,a...) do { \ struct nvkm_ior *_ior = (i); \ nvkm_##l(&_ior->disp->engine.subdev, "%s: "f, _ior->name, ##a); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 21bdf301d37e..99a94a65b1a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -678,6 +678,23 @@ nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) exec_script(disp, head, 1); } +void +nv50_disp_super_1(struct nv50_disp *disp) +{ + struct nvkm_head *head; + struct nvkm_ior *ior; + + list_for_each_entry(head, &disp->base.head, head) { + head->func->state(head, &head->arm); + head->func->state(head, &head->asy); + } + + list_for_each_entry(ior, &disp->base.ior, head) { + ior->func->state(ior, &ior->arm); + ior->func->state(ior, &ior->asy); + } +} + void nv50_disp_super(struct work_struct *work) { @@ -692,6 +709,7 @@ nv50_disp_super(struct work_struct *work) if (disp->super & 0x00000010) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); + nv50_disp_super_1(disp); list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000020 << head->id))) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index fe7ef0abef6e..0b1ea0b9394d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -29,6 +29,8 @@ struct nv50_disp { struct nv50_disp_chan *chan[17]; }; +void nv50_disp_super_1(struct nv50_disp *); + int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index f81ba52c8c19..73ec6d4ae554 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -121,8 +121,28 @@ nv50_pior_power(NV50_DISP_MTHD_V1) return 0; } +static void +nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 coff = pior->id * 8 + (state == &pior->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610b80 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + state->rgdiv = 1; + switch (state->proto_evo) { + case 0: state->proto = TMDS; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; +} + static const struct nvkm_ior_func nv50_pior = { + .state = nv50_pior_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c index 427e04c602e8..5b467f0ca36c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -23,6 +23,7 @@ static const struct nvkm_ior_func g84_sor = { + .state = nv50_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 87b097327e29..89dd16590470 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -278,8 +278,32 @@ nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) } } +void +g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 coff = sor->id * 8 + (state == &sor->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610794 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = LVDS; state->link = 1; break; + case 1: state->proto = TMDS; state->link = 1; break; + case 2: state->proto = TMDS; state->link = 2; break; + case 5: state->proto = TMDS; state->link = 3; break; + case 8: state->proto = DP; state->link = 1; break; + case 9: state->proto = DP; state->link = 2; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; +} + static const struct nvkm_ior_func g94_sor = { + .state = g94_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 6ad8af038eae..56ff9d92b14e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -130,8 +130,32 @@ gf119_sor_dp_new(struct nvkm_disp *disp, int index, return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); } +void +gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 coff = (state == &sor->asy) * 0x20000 + sor->id * 0x20; + u32 ctrl = nvkm_rd32(device, 0x640200 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = LVDS; state->link = 1; break; + case 1: state->proto = TMDS; state->link = 1; break; + case 2: state->proto = TMDS; state->link = 2; break; + case 5: state->proto = TMDS; state->link = 3; break; + case 8: state->proto = DP; state->link = 1; break; + case 9: state->proto = DP; state->link = 2; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x0000000f; +} + static const struct nvkm_ior_func gf119_sor = { + .state = gf119_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index a1946eca85ed..e1d1fd25720b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -23,6 +23,7 @@ static const struct nvkm_ior_func gk104_sor = { + .state = gf119_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 590d66002c58..96317c461b3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -55,6 +55,7 @@ gm107_sor_dp_new(struct nvkm_disp *disp, int index, static const struct nvkm_ior_func gm107_sor = { + .state = gf119_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index df3917cb1cb9..cc4bea30bb9b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -132,6 +132,7 @@ gm200_sor_magic(struct nvkm_output *outp) static const struct nvkm_ior_func gm200_sor = { + .state = gf119_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index dc209826156e..87d1c9ce4e7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -23,6 +23,7 @@ static const struct nvkm_ior_func gt215_sor = { + .state = g94_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 09d42240510a..78ddffab7a93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -23,6 +23,7 @@ static const struct nvkm_ior_func mcp77_sor = { + .state = g94_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index f8fba6caad33..97433c17db71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -23,6 +23,7 @@ static const struct nvkm_ior_func mcp89_sor = { + .state = g94_sor_state, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index fb43307466cd..a1327e8fead1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -79,8 +79,30 @@ nv50_sor_power(NV50_DISP_MTHD_V1) return 0; } +void +nv50_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 coff = sor->id * 8 + (state == &sor->arm) * 4; + u32 ctrl = nvkm_rd32(device, 0x610b70 + coff); + + state->proto_evo = (ctrl & 0x00000f00) >> 8; + switch (state->proto_evo) { + case 0: state->proto = LVDS; state->link = 1; break; + case 1: state->proto = TMDS; state->link = 1; break; + case 2: state->proto = TMDS; state->link = 2; break; + case 5: state->proto = TMDS; state->link = 3; break; + default: + state->proto = UNKNOWN; + break; + } + + state->head = ctrl & 0x00000003; +} + static const struct nvkm_ior_func nv50_sor = { + .state = nv50_sor_state, }; int From 9c5753bc708da0c2c544fcfe1e94afb399c2b3f6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 43/73] drm/nouveau/disp/nv50-: port OR power state control to nvkm_ior Also removes the user-facing methods to these controls, as they're not currently utilised by the DD anyway. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 25 ------ drivers/gpu/drm/nouveau/nv50_display.c | 76 +------------------ .../drm/nouveau/nvkm/engine/disp/dacgf119.c | 1 + .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 50 +++++------- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 12 +++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 9 +-- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 7 -- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 54 +++++-------- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 25 +++--- .../gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + .../drm/nouveau/nvkm/engine/disp/sornv50.c | 49 +++++------- 32 files changed, 108 insertions(+), 257 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index 22304cc99f39..e3f5659295e2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -27,30 +27,18 @@ struct nv50_disp_scanoutpos_v0 { struct nv50_disp_mthd_v1 { __u8 version; -#define NV50_DISP_MTHD_V1_DAC_PWR 0x10 #define NV50_DISP_MTHD_V1_DAC_LOAD 0x11 -#define NV50_DISP_MTHD_V1_SOR_PWR 0x20 #define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 #define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23 #define NV50_DISP_MTHD_V1_SOR_DP_MST_LINK 0x25 #define NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI 0x26 -#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30 __u8 method; __u16 hasht; __u16 hashm; __u8 pad06[2]; }; -struct nv50_disp_dac_pwr_v0 { - __u8 version; - __u8 state; - __u8 data; - __u8 vsync; - __u8 hsync; - __u8 pad05[3]; -}; - struct nv50_disp_dac_load_v0 { __u8 version; __u8 load; @@ -58,12 +46,6 @@ struct nv50_disp_dac_load_v0 { __u32 data; }; -struct nv50_disp_sor_pwr_v0 { - __u8 version; - __u8 state; - __u8 pad02[6]; -}; - struct nv50_disp_sor_hda_eld_v0 { __u8 version; __u8 pad01[7]; @@ -101,11 +83,4 @@ struct nv50_disp_sor_dp_mst_vcpi_v0 { __u16 pbn; __u16 aligned_pbn; }; - -struct nv50_disp_pior_pwr_v0 { - __u8 version; - __u8 state; - __u8 type; - __u8 pad03[5]; -}; #endif diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 36d0cf891eea..e6cc1d843c92 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2459,30 +2459,6 @@ nv50_outp_atomic_check(struct drm_encoder *encoder, /****************************************************************************** * DAC *****************************************************************************/ -static void -nv50_dac_dpms(struct drm_encoder *encoder, int mode) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_dac_pwr_v0 pwr; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_DAC_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - .pwr.state = 1, - .pwr.data = 1, - .pwr.vsync = (mode != DRM_MODE_DPMS_SUSPEND && - mode != DRM_MODE_DPMS_OFF), - .pwr.hsync = (mode != DRM_MODE_DPMS_STANDBY && - mode != DRM_MODE_DPMS_OFF), - }; - - nvif_mthd(disp->disp, 0, &args, sizeof(args)); -} - static void nv50_dac_disable(struct drm_encoder *encoder) { @@ -2584,7 +2560,6 @@ nv50_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) static const struct drm_encoder_helper_funcs nv50_dac_help = { - .dpms = nv50_dac_dpms, .atomic_check = nv50_outp_atomic_check, .enable = nv50_dac_enable, .disable = nv50_dac_disable, @@ -3405,25 +3380,6 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max, /****************************************************************************** * SOR *****************************************************************************/ -static void -nv50_sor_dpms(struct drm_encoder *encoder, int mode) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_sor_pwr_v0 pwr; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_SOR_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - .pwr.state = mode == DRM_MODE_DPMS_ON, - }; - - nvif_mthd(disp->disp, 0, &args, sizeof(args)); -} - static void nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head, struct drm_display_mode *mode, u8 proto, u8 depth) @@ -3602,7 +3558,6 @@ nv50_sor_enable(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs nv50_sor_help = { - .dpms = nv50_sor_dpms, .atomic_check = nv50_outp_atomic_check, .enable = nv50_sor_enable, .disable = nv50_sor_disable, @@ -3686,26 +3641,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) /****************************************************************************** * PIOR *****************************************************************************/ -static void -nv50_pior_dpms(struct drm_encoder *encoder, int mode) -{ - struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - struct nv50_disp *disp = nv50_disp(encoder->dev); - struct { - struct nv50_disp_mthd_v1 base; - struct nv50_disp_pior_pwr_v0 pwr; - } args = { - .base.version = 1, - .base.method = NV50_DISP_MTHD_V1_PIOR_PWR, - .base.hasht = nv_encoder->dcb->hasht, - .base.hashm = nv_encoder->dcb->hashm, - .pwr.state = mode == DRM_MODE_DPMS_ON, - .pwr.type = nv_encoder->dcb->type, - }; - - nvif_mthd(disp->disp, 0, &args, sizeof(args)); -} - static int nv50_pior_atomic_check(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -3790,7 +3725,6 @@ nv50_pior_enable(struct drm_encoder *encoder) static const struct drm_encoder_helper_funcs nv50_pior_help = { - .dpms = nv50_pior_dpms, .atomic_check = nv50_pior_atomic_check, .enable = nv50_pior_enable, .disable = nv50_pior_disable, @@ -4355,14 +4289,8 @@ nv50_display_init(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) { - const struct drm_encoder_helper_funcs *help; - struct nouveau_encoder *nv_encoder; - - nv_encoder = nouveau_encoder(encoder); - help = encoder->helper_private; - if (help && help->dpms) - help->dpms(encoder, DRM_MODE_DPMS_ON); - + struct nouveau_encoder *nv_encoder = + nouveau_encoder(encoder); nv50_mstm_init(nv_encoder->dp.mstm); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c index 546fb6c99ab1..2ef07c0fcc2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -42,6 +42,7 @@ gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state) static const struct nvkm_ior_func gf119_dac = { .state = gf119_dac_state, + .power = nv50_dac_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 6598252888ee..48fbf8c34a53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -90,40 +90,31 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) return 0; } -int -nv50_dac_power(NV50_DISP_MTHD_V1) +static void +nv50_dac_power_wait(struct nvkm_device *device, const u32 doff) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 doff = outp->or * 0x800; - union { - struct nv50_disp_dac_pwr_v0 v0; - } *args = data; - u32 stat; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp dac pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " - "vsync %d hsync %d\n", - args->v0.version, args->v0.state, args->v0.data, - args->v0.vsync, args->v0.hsync); - stat = 0x00000040 * !args->v0.state; - stat |= 0x00000010 * !args->v0.data; - stat |= 0x00000004 * !args->v0.vsync; - stat |= 0x00000001 * !args->v0.hsync; - } else - return ret; - nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) break; ); - nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) - break; - ); - return 0; +} + +void +nv50_dac_power(struct nvkm_ior *dac, bool normal, bool pu, + bool data, bool vsync, bool hsync) +{ + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 doff = nv50_ior_base(dac); + const u32 shift = normal ? 0 : 16; + const u32 state = 0x80000000 | (0x00000040 * ! pu | + 0x00000010 * ! data | + 0x00000004 * ! vsync | + 0x00000001 * ! hsync) << shift; + const u32 field = 0xc0000000 | (0x00000055 << shift); + + nv50_dac_power_wait(device, doff); + nvkm_mask(device, 0x61a004 + doff, field, state); + nv50_dac_power_wait(device, doff); } static void @@ -147,6 +138,7 @@ nv50_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state) static const struct nvkm_ior_func nv50_dac = { .state = nv50_dac_state, + .power = nv50_dac_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index dc2a602718cc..aa713b24a606 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -40,15 +40,11 @@ g84_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, .sor.new = g84_sor_new, - .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 4a959de0d616..5c6c8640bab1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -41,15 +41,11 @@ g94_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = g94_sor_new, - .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index a030a2820709..05fdbdb1df50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -508,11 +508,9 @@ gf119_disp = { .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, .dac.new = gf119_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gf119_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gf119_hdmi_ctrl, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 3c3a327095fb..efbbbff0b93f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -40,11 +40,9 @@ gk104_disp = { .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, .dac.new = gf119_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gk104_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 84f774ae5f7e..bca825373dc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -40,11 +40,9 @@ gk110_disp = { .outp.internal.dp = gf119_sor_dp_new, .dac.nr = 3, .dac.new = gf119_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gk104_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 4e43fcdc2c7c..90fc36e96335 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -40,11 +40,9 @@ gm107_disp = { .outp.internal.dp = gm107_sor_dp_new, .dac.nr = 3, .dac.new = gf119_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gm107_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 90cdc95c71ed..2e0f81e75124 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -40,11 +40,9 @@ gm200_disp = { .outp.internal.dp = gm200_sor_dp_new, .dac.nr = 3, .dac.new = gf119_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index f7ba3366024a..4b6a60d646cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -39,7 +39,6 @@ gp100_disp = { .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 80010f2c94b2..26f745bf4bef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -65,7 +65,6 @@ gp102_disp = { .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gf119_hda_eld, .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 3e9399be4d86..a41909e8ab1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -40,15 +40,11 @@ gt200_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 2, .sor.new = g84_sor_new, - .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 7c7ad97a4849..230e43ded8eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -41,16 +41,12 @@ gt215_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = gt215_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gt215_hda_eld, .sor.hdmi = gt215_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index ef9d23a3b77b..9dd526cfe2a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -40,6 +40,8 @@ struct nvkm_ior { struct nvkm_ior_func { void (*state)(struct nvkm_ior *, struct nvkm_ior_state *); + void (*power)(struct nvkm_ior *, bool normal, bool pu, + bool data, bool vsync, bool hsync); }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, @@ -47,7 +49,17 @@ int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, void nvkm_ior_del(struct nvkm_ior **); struct nvkm_ior *nvkm_ior_find(struct nvkm_disp *, enum nvkm_ior_type, int id); +static inline u32 +nv50_ior_base(struct nvkm_ior *ior) +{ + return ior->id * 0x800; +} + +void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool); + void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); + void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c index f8710425ea54..ee8c2324a351 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -39,15 +39,11 @@ mcp77_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = mcp77_sor_new, - .sor.power = nv50_sor_power, .sor.hdmi = g84_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index e417d1dbe4ce..6dccb3d2c8dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -39,16 +39,12 @@ mcp89_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, .sor.nr = 4, .sor.new = mcp89_sor_new, - .sor.power = nv50_sor_power, .sor.hda_eld = gt215_hda_eld, .sor.hdmi = gt215_hdmi_ctrl, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 99a94a65b1a3..f8986299dc54 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -846,14 +846,9 @@ nv50_disp = { .outp.external.dp = nv50_pior_dp_new, .dac.nr = 3, .dac.new = nv50_dac_new, - .dac.power = nv50_dac_power, .dac.sense = nv50_dac_sense, - .sor.nr = 2, - .sor.new = nv50_sor_new, - .sor.power = nv50_sor_power, - .pior.nr = 3, - .pior.new = nv50_pior_new, - .pior.power = nv50_pior_power, + .sor = { .nr = 2, .new = nv50_sor_new }, + .pior = { .nr = 3, .new = nv50_pior_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 0b1ea0b9394d..66180585df2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -31,7 +31,6 @@ struct nv50_disp { void nv50_disp_super_1(struct nv50_disp *); -int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1); int gt215_hda_eld(NV50_DISP_MTHD_V1); @@ -42,9 +41,6 @@ int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); -int nv50_sor_power(NV50_DISP_MTHD_V1); -int nv50_pior_power(NV50_DISP_MTHD_V1); - int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, @@ -84,14 +80,12 @@ struct nv50_disp_func { struct { int nr; int (*new)(struct nvkm_disp *, int id); - int (*power)(NV50_DISP_MTHD_V1); int (*sense)(NV50_DISP_MTHD_V1); } dac; struct { int nr; int (*new)(struct nvkm_disp *, int id); - int (*power)(NV50_DISP_MTHD_V1); int (*hda_eld)(NV50_DISP_MTHD_V1); int (*hdmi)(NV50_DISP_MTHD_V1); void (*magic)(struct nvkm_output *); @@ -100,7 +94,6 @@ struct nv50_disp_func { struct { int nr; int (*new)(struct nvkm_disp *, int id); - int (*power)(NV50_DISP_MTHD_V1); } pior; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 73ec6d4ae554..486050d4692e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -22,15 +22,11 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" +#include "dp.h" -#include #include #include -#include -#include - /****************************************************************************** * TMDS *****************************************************************************/ @@ -86,39 +82,28 @@ nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, index, dcbE, poutp); } -int -nv50_pior_power(NV50_DISP_MTHD_V1) +static void +nv50_pior_power_wait(struct nvkm_device *device, u32 poff) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp pior pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else - return ret; - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + if (!(nvkm_rd32(device, 0x61e004 + poff) & 0x80000000)) break; ); - nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - disp->pior.type[outp->or] = type; - return 0; +} + +static void +nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu, + bool data, bool vsync, bool hsync) +{ + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 poff = nv50_ior_base(pior); + const u32 shift = normal ? 0 : 16; + const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift; + const u32 field = 0x80000000 | (0x00000101 << shift); + + nv50_pior_power_wait(device, poff); + nvkm_mask(device, 0x61e004 + poff, field, state); + nv50_pior_power_wait(device, poff); } static void @@ -143,6 +128,7 @@ nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) static const struct nvkm_ior_func nv50_pior = { .state = nv50_pior_state, + .power = nv50_pior_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 9cf1365f5261..3f02e37f30bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -24,6 +24,7 @@ #include "rootnv50.h" #include "dmacnv50.h" #include "head.h" +#include "ior.h" #include #include @@ -94,12 +95,8 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } switch (mthd * !!outp) { - case NV50_DISP_MTHD_V1_DAC_PWR: - return func->dac.power(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_DAC_LOAD: return func->dac.sense(object, disp, data, size, hidx, outp); - case NV50_DISP_MTHD_V1_SOR_PWR: - return func->sor.power(object, disp, data, size, hidx, outp); case NV50_DISP_MTHD_V1_SOR_HDA_ELD: if (!func->sor.hda_eld) return -ENODEV; @@ -163,10 +160,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return ret; } break; - case NV50_DISP_MTHD_V1_PIOR_PWR: - if (!func->pior.power) - return -ENODEV; - return func->pior.power(object, disp, data, size, hidx, outp); default: break; } @@ -231,7 +224,21 @@ static int nv50_disp_root_init_(struct nvkm_object *object) { struct nv50_disp_root *root = nv50_disp_root(object); - return root->func->init(root); + struct nvkm_ior *ior; + int ret; + + ret = root->func->init(root); + if (ret) + return ret; + + /* Set 'normal' (ie. when it's attached to a head) state for + * each output resource to 'fully enabled'. + */ + list_for_each_entry(ior, &root->disp->base.ior, head) { + ior->func->power(ior, true, true, true, true, true); + } + + return 0; } static void * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c index 5b467f0ca36c..bb0f503ee989 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -24,6 +24,7 @@ static const struct nvkm_ior_func g84_sor = { .state = nv50_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 89dd16590470..3175bb3031b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -304,6 +304,7 @@ g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) static const struct nvkm_ior_func g94_sor = { .state = g94_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 56ff9d92b14e..dcab72a52964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -156,6 +156,7 @@ gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) static const struct nvkm_ior_func gf119_sor = { .state = gf119_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index e1d1fd25720b..ac7a5944487a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -24,6 +24,7 @@ static const struct nvkm_ior_func gk104_sor = { .state = gf119_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 96317c461b3c..8bca4dca1e11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -56,6 +56,7 @@ gm107_sor_dp_new(struct nvkm_disp *disp, int index, static const struct nvkm_ior_func gm107_sor = { .state = gf119_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index cc4bea30bb9b..0a4b9b967904 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -133,6 +133,7 @@ gm200_sor_magic(struct nvkm_output *outp) static const struct nvkm_ior_func gm200_sor = { .state = gf119_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 87d1c9ce4e7f..bec04ad40494 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -24,6 +24,7 @@ static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 78ddffab7a93..fc14e48fe84b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -24,6 +24,7 @@ static const struct nvkm_ior_func mcp77_sor = { .state = g94_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 97433c17db71..37c1dacb7d67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -24,6 +24,7 @@ static const struct nvkm_ior_func mcp89_sor = { .state = g94_sor_state, + .power = nv50_sor_power, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index a1327e8fead1..543b6d0ee74c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -22,15 +22,10 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" #include "outp.h" -#include #include -#include -#include - static const struct nvkm_output_func nv50_sor_output_func = { }; @@ -43,40 +38,33 @@ nv50_sor_output_new(struct nvkm_disp *disp, int index, index, dcbE, poutp); } -int -nv50_sor_power(NV50_DISP_MTHD_V1) +static void +nv50_sor_power_wait(struct nvkm_device *device, u32 soff) { - struct nvkm_device *device = disp->base.engine.subdev.device; - union { - struct nv50_disp_sor_pwr_v0 v0; - } *args = data; - const u32 soff = outp->or * 0x800; - u32 stat; - int ret = -ENOSYS; - - nvif_ioctl(object, "disp sor pwr size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp sor pwr vers %d state %d\n", - args->v0.version, args->v0.state); - stat = !!args->v0.state; - } else - return ret; - - - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) break; ); +} + +void +nv50_sor_power(struct nvkm_ior *sor, bool normal, bool pu, + bool data, bool vsync, bool hsync) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 shift = normal ? 0 : 16; + const u32 state = 0x80000000 | (0x00000001 * !!pu) << shift; + const u32 field = 0x80000000 | (0x00000001 << shift); + + nv50_sor_power_wait(device, soff); + nvkm_mask(device, 0x61c004 + soff, field, state); + nv50_sor_power_wait(device, soff); + nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) break; ); - return 0; } void @@ -103,6 +91,7 @@ nv50_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) static const struct nvkm_ior_func nv50_sor = { .state = nv50_sor_state, + .power = nv50_sor_power, }; int From 0df182466265d39591d742839f1014f93b7cbd02 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 44/73] drm/nouveau/disp/nv50-: port OR manual sink detection to nvkm_ior Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/dacgf119.c | 1 + .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 45 +++---------------- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 + .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 3 -- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 19 +++++++- 17 files changed, 39 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c index 2ef07c0fcc2d..7d2d929eec16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -43,6 +43,7 @@ static const struct nvkm_ior_func gf119_dac = { .state = gf119_dac_state, .power = nv50_dac_power, + .sense = nv50_dac_sense, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 48fbf8c34a53..0e51e144c1bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -22,15 +22,10 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" #include "outp.h" -#include #include -#include -#include - static const struct nvkm_output_func nv50_dac_output_func = { }; @@ -44,50 +39,23 @@ nv50_dac_output_new(struct nvkm_disp *disp, int index, } int -nv50_dac_sense(NV50_DISP_MTHD_V1) +nv50_dac_sense(struct nvkm_ior *dac, u32 loadval) { - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - union { - struct nv50_disp_dac_load_v0 v0; - } *args = data; - const u32 doff = outp->or * 0x800; - u32 loadval; - int ret = -ENOSYS; + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 doff = nv50_ior_base(dac); - nvif_ioctl(object, "disp dac load size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(object, "disp dac load vers %d data %08x\n", - args->v0.version, args->v0.data); - if (args->v0.data & 0xfff00000) - return -EINVAL; - loadval = args->v0.data; - } else - return ret; - - nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) - break; - ); + dac->func->power(dac, false, true, false, false, false); nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval); mdelay(9); udelay(500); loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000); - nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) - break; - ); - - nvkm_debug(subdev, "DAC%d sense: %08x\n", outp->or, loadval); + dac->func->power(dac, false, false, false, false, false); if (!(loadval & 0x80000000)) return -ETIMEDOUT; - args->v0.load = (loadval & 0x38000000) >> 27; - return 0; + return (loadval & 0x38000000) >> 27; } static void @@ -139,6 +107,7 @@ static const struct nvkm_ior_func nv50_dac = { .state = nv50_dac_state, .power = nv50_dac_power, + .sense = nv50_dac_sense, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index aa713b24a606..3e110108272c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -38,9 +38,7 @@ g84_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 2, .sor.new = g84_sor_new, .sor.hdmi = g84_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 5c6c8640bab1..ac9cd335e4f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -39,9 +39,7 @@ g94_disp = { .outp.internal.dp = g94_sor_dp_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 4, .sor.new = g94_sor_new, .sor.hdmi = g84_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 05fdbdb1df50..76972e009f36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -506,9 +506,7 @@ gf119_disp = { .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, - .dac.nr = 3, - .dac.new = gf119_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gf119_sor_new, .sor.hda_eld = gf119_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index efbbbff0b93f..2f84b1b5a469 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -38,9 +38,7 @@ gk104_disp = { .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, - .dac.nr = 3, - .dac.new = gf119_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gk104_sor_new, .sor.hda_eld = gf119_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index bca825373dc1..abf50b20b88c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -38,9 +38,7 @@ gk110_disp = { .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, - .dac.nr = 3, - .dac.new = gf119_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gk104_sor_new, .sor.hda_eld = gf119_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 90fc36e96335..0923ca4b42b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -38,9 +38,7 @@ gm107_disp = { .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm107_sor_dp_new, - .dac.nr = 3, - .dac.new = gf119_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gm107_sor_new, .sor.hda_eld = gf119_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 2e0f81e75124..cc83734e321b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -38,9 +38,7 @@ gm200_disp = { .outp.internal.tmds = nv50_sor_output_new, .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm200_sor_dp_new, - .dac.nr = 3, - .dac.new = gf119_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gm200_sor_new, .sor.hda_eld = gf119_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index a41909e8ab1f..f9d43768acba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -38,9 +38,7 @@ gt200_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 2, .sor.new = g84_sor_new, .sor.hdmi = g84_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 230e43ded8eb..6c75a975bf45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -39,9 +39,7 @@ gt215_disp = { .outp.internal.dp = g94_sor_dp_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 4, .sor.new = gt215_sor_new, .sor.hda_eld = gt215_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 9dd526cfe2a2..ea80e7fd7d23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -42,6 +42,7 @@ struct nvkm_ior_func { void (*state)(struct nvkm_ior *, struct nvkm_ior_state *); void (*power)(struct nvkm_ior *, bool normal, bool pu, bool data, bool vsync, bool hsync); + int (*sense)(struct nvkm_ior *, u32 loadval); }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, @@ -56,6 +57,7 @@ nv50_ior_base(struct nvkm_ior *ior) } void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool); +int nv50_dac_sense(struct nvkm_ior *, u32); void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c index ee8c2324a351..d707d8f4c0f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -37,9 +37,7 @@ mcp77_disp = { .outp.internal.dp = g94_sor_dp_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 4, .sor.new = mcp77_sor_new, .sor.hdmi = g84_hdmi_ctrl, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index 6dccb3d2c8dc..24f46705f616 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -37,9 +37,7 @@ mcp89_disp = { .outp.internal.dp = g94_sor_dp_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor.nr = 4, .sor.new = mcp89_sor_new, .sor.hda_eld = gt215_hda_eld, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index f8986299dc54..ae570f65e097 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -844,9 +844,7 @@ nv50_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, - .dac.nr = 3, - .dac.new = nv50_dac_new, - .dac.sense = nv50_dac_sense, + .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 2, .new = nv50_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 66180585df2a..263c3a7f9d88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -31,8 +31,6 @@ struct nv50_disp { void nv50_disp_super_1(struct nv50_disp *); -int nv50_dac_sense(NV50_DISP_MTHD_V1); - int gt215_hda_eld(NV50_DISP_MTHD_V1); int gf119_hda_eld(NV50_DISP_MTHD_V1); @@ -80,7 +78,6 @@ struct nv50_disp_func { struct { int nr; int (*new)(struct nvkm_disp *, int id); - int (*sense)(NV50_DISP_MTHD_V1); } dac; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 3f02e37f30bb..7ebea3e14e18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -95,8 +95,23 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } switch (mthd * !!outp) { - case NV50_DISP_MTHD_V1_DAC_LOAD: - return func->dac.sense(object, disp, data, size, hidx, outp); + case NV50_DISP_MTHD_V1_DAC_LOAD: { + union { + struct nv50_disp_dac_load_v0 v0; + } *args = data; + int ret = -ENOSYS; + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + if (args->v0.data & 0xfff00000) + return -EINVAL; + ret = outp->ior->func->sense(outp->ior, args->v0.data); + if (ret < 0) + return ret; + args->v0.load = ret; + return 0; + } else + return ret; + } + break; case NV50_DISP_MTHD_V1_SOR_HDA_ELD: if (!func->sor.hda_eld) return -ENODEV; From 797b2fb81b506d4ad30aa34e5c81c0a541d398cd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 45/73] drm/nouveau/disp/g84-: port OR HDMI control to nvkm_ior Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/hdmi.h | 2 +- .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 61 +++++------------- .../drm/nouveau/nvkm/engine/disp/hdmigf119.c | 59 ++++-------------- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 61 +++++------------- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 62 +++++-------------- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 11 ++++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 6 -- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 42 ++++++++++++- .../gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 3 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 3 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 3 + 29 files changed, 134 insertions(+), 219 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 3e110108272c..50fbe1cb6653 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -39,9 +39,7 @@ g84_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 2, - .sor.new = g84_sor_new, - .sor.hdmi = g84_hdmi_ctrl, + .sor = { .nr = 2, .new = g84_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index ac9cd335e4f3..8cc2a8c03fc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -40,9 +40,7 @@ g94_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 4, - .sor.new = g94_sor_new, - .sor.hdmi = g84_hdmi_ctrl, + .sor = { .nr = 4, .new = g94_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 76972e009f36..d4df1983f769 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -510,7 +510,6 @@ gf119_disp = { .sor.nr = 4, .sor.new = gf119_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gf119_hdmi_ctrl, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 2f84b1b5a469..4d22d87c4620 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -42,7 +42,6 @@ gk104_disp = { .sor.nr = 4, .sor.new = gk104_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index abf50b20b88c..adc2a2257438 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -42,7 +42,6 @@ gk110_disp = { .sor.nr = 4, .sor.new = gk104_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 0923ca4b42b6..116b99b51359 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -42,7 +42,6 @@ gm107_disp = { .sor.nr = 4, .sor.new = gm107_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index cc83734e321b..ffdb5a412821 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -42,7 +42,6 @@ gm200_disp = { .sor.nr = 4, .sor.new = gm200_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index 4b6a60d646cc..bd5ab596877b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -40,7 +40,6 @@ gp100_disp = { .sor.nr = 4, .sor.new = gm200_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 26f745bf4bef..4875d4822d42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -66,7 +66,6 @@ gp102_disp = { .sor.nr = 4, .sor.new = gm200_sor_new, .sor.hda_eld = gf119_hda_eld, - .sor.hdmi = gk104_hdmi_ctrl, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index f9d43768acba..387f57bc517b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -39,9 +39,7 @@ gt200_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 2, - .sor.new = g84_sor_new, - .sor.hdmi = g84_hdmi_ctrl, + .sor = { .nr = 2, .new = g84_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 6c75a975bf45..4edd37124536 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -43,7 +43,6 @@ gt215_disp = { .sor.nr = 4, .sor.new = gt215_sor_new, .sor.hda_eld = gt215_hda_eld, - .sor.hdmi = gt215_hdmi_ctrl, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h index 35a825192264..528f5621a496 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmi.h @@ -1,6 +1,6 @@ #ifndef __NVKM_DISP_HDMI_H__ #define __NVKM_DISP_HDMI_H__ -#include "nv50.h" +#include "ior.h" struct packed_hdmi_infoframe { u32 header; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index f25d8c7fba67..661410f9b457 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -23,65 +23,33 @@ */ #include "hdmi.h" -#include - -#include -#include - -int -g84_hdmi_ctrl(NV50_DISP_MTHD_V1) +void +g84_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, + u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 hoff = (head * 0x800); - union { - struct nv50_disp_sor_hdmi_pwr_v0 v0; - } *args = data; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 ctrl = 0x40000000 * enable | + 0x1f000000 /* ??? */ | + max_ac_packet << 16 | + rekey; + const u32 hoff = head * 0x800; struct packed_hdmi_infoframe avi_infoframe; struct packed_hdmi_infoframe vendor_infoframe; - u32 ctrl; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); - if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) - return -EINVAL; - ctrl = 0x40000000 * !!args->v0.state; - ctrl |= args->v0.max_ac_packet << 16; - ctrl |= args->v0.rekey; - ctrl |= 0x1f000000; /* ??? */ - } else - return ret; - - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) > size) - return -ENOSYS; - else if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) < size) - return -E2BIG; - - pack_hdmi_infoframe(&avi_infoframe, - data, - args->v0.avi_infoframe_length); - - pack_hdmi_infoframe(&vendor_infoframe, - data + args->v0.avi_infoframe_length, - args->v0.vendor_infoframe_length); + pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); + pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x61653c + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); - return 0; + return; } /* AVI InfoFrame */ nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); - if (args->v0.avi_infoframe_length) { + if (avi_size) { nvkm_wr32(device, 0x616528 + hoff, avi_infoframe.header); nvkm_wr32(device, 0x61652c + hoff, avi_infoframe.subpack0_low); nvkm_wr32(device, 0x616530 + hoff, avi_infoframe.subpack0_high); @@ -99,7 +67,7 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) /* Vendor InfoFrame */ nvkm_mask(device, 0x61653c + hoff, 0x00010001, 0x00010000); - if (args->v0.vendor_infoframe_length) { + if (vendor_size) { nvkm_wr32(device, 0x616544 + hoff, vendor_infoframe.header); nvkm_wr32(device, 0x616548 + hoff, vendor_infoframe.subpack0_low); nvkm_wr32(device, 0x61654c + hoff, vendor_infoframe.subpack0_high); @@ -120,5 +88,4 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) /* HDMI_CTRL */ nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl); - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index 8dc6a79c8141..6cac0e72b4cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -23,64 +23,32 @@ */ #include "hdmi.h" -#include - -#include -#include - -int -gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) +void +gf119_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, + u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 hoff = (head * 0x800); - union { - struct nv50_disp_sor_hdmi_pwr_v0 v0; - } *args = data; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 ctrl = 0x40000000 * enable | + max_ac_packet << 16 | + rekey; + const u32 hoff = head * 0x800; struct packed_hdmi_infoframe avi_infoframe; struct packed_hdmi_infoframe vendor_infoframe; - u32 ctrl; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); - if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) - return -EINVAL; - ctrl = 0x40000000 * !!args->v0.state; - ctrl |= args->v0.max_ac_packet << 16; - ctrl |= args->v0.rekey; - } else - return ret; - - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) > size) - return -ENOSYS; - else if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) < size) - return -E2BIG; - - pack_hdmi_infoframe(&avi_infoframe, - data, - args->v0.avi_infoframe_length); - - pack_hdmi_infoframe(&vendor_infoframe, - data + args->v0.avi_infoframe_length, - args->v0.vendor_infoframe_length); + pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); + pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x616730 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); - return 0; + return; } /* AVI InfoFrame */ nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); - if (args->v0.avi_infoframe_length) { + if (avi_size) { nvkm_wr32(device, 0x61671c + hoff, avi_infoframe.header); nvkm_wr32(device, 0x616720 + hoff, avi_infoframe.subpack0_low); nvkm_wr32(device, 0x616724 + hoff, avi_infoframe.subpack0_high); @@ -91,7 +59,7 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) /* GENERIC(?) / Vendor InfoFrame? */ nvkm_mask(device, 0x616730 + hoff, 0x00010001, 0x00010000); - if (args->v0.vendor_infoframe_length) { + if (vendor_size) { /* * These appear to be the audio infoframe registers, * but no other set of infoframe registers has yet @@ -111,5 +79,4 @@ gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) /* HDMI_CTRL */ nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index 1be2ecb1ebbc..ed0a6100d76b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -23,65 +23,33 @@ */ #include "hdmi.h" -#include - -#include -#include - -int -gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) +void +gk104_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, + u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 hoff = (head * 0x800); - const u32 hdmi = (head * 0x400); - union { - struct nv50_disp_sor_hdmi_pwr_v0 v0; - } *args = data; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 ctrl = 0x40000000 * enable | + max_ac_packet << 16 | + rekey; + const u32 hoff = head * 0x800; + const u32 hdmi = head * 0x400; struct packed_hdmi_infoframe avi_infoframe; struct packed_hdmi_infoframe vendor_infoframe; - u32 ctrl; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); - if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) - return -EINVAL; - ctrl = 0x40000000 * !!args->v0.state; - ctrl |= args->v0.max_ac_packet << 16; - ctrl |= args->v0.rekey; - } else - return ret; - - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) > size) - return -ENOSYS; - else if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) < size) - return -E2BIG; - - pack_hdmi_infoframe(&avi_infoframe, - data, - args->v0.avi_infoframe_length); - - pack_hdmi_infoframe(&vendor_infoframe, - data + args->v0.avi_infoframe_length, - args->v0.vendor_infoframe_length); + pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); + pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); nvkm_mask(device, 0x690100 + hdmi, 0x00000001, 0x00000000); nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); - return 0; + return; } /* AVI InfoFrame */ nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); - if (args->v0.avi_infoframe_length) { + if (avi_size) { nvkm_wr32(device, 0x690008 + hdmi, avi_infoframe.header); nvkm_wr32(device, 0x69000c + hdmi, avi_infoframe.subpack0_low); nvkm_wr32(device, 0x690010 + hdmi, avi_infoframe.subpack0_high); @@ -92,7 +60,7 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) /* GENERIC(?) / Vendor InfoFrame? */ nvkm_mask(device, 0x690100 + hdmi, 0x00010001, 0x00000000); - if (args->v0.vendor_infoframe_length) { + if (vendor_size) { nvkm_wr32(device, 0x690108 + hdmi, vendor_infoframe.header); nvkm_wr32(device, 0x69010c + hdmi, vendor_infoframe.subpack0_low); nvkm_wr32(device, 0x690110 + hdmi, vendor_infoframe.subpack0_high); @@ -111,5 +79,4 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) /* HDMI_CTRL */ nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index 16c63fe05539..0993d223bb9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -22,67 +22,34 @@ * Authors: Ben Skeggs */ #include "hdmi.h" -#include "outp.h" -#include - -#include -#include - -int -gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) +void +gt215_hdmi_ctrl(struct nvkm_ior *ior, int head, bool enable, u8 max_ac_packet, + u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_sor_hdmi_pwr_v0 v0; - } *args = data; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 ctrl = 0x40000000 * enable | + 0x1f000000 /* ??? */ | + max_ac_packet << 16 | + rekey; + const u32 soff = nv50_ior_base(ior); struct packed_hdmi_infoframe avi_infoframe; struct packed_hdmi_infoframe vendor_infoframe; - u32 ctrl; - int ret = -ENOSYS; - nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); - if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) - return -EINVAL; - ctrl = 0x40000000 * !!args->v0.state; - ctrl |= args->v0.max_ac_packet << 16; - ctrl |= args->v0.rekey; - ctrl |= 0x1f000000; /* ??? */ - } else - return ret; - - if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) > size) - return -ENOSYS; - else if ((args->v0.avi_infoframe_length - + args->v0.vendor_infoframe_length) < size) - return -E2BIG; - - pack_hdmi_infoframe(&avi_infoframe, - data, - args->v0.avi_infoframe_length); - - pack_hdmi_infoframe(&vendor_infoframe, - data + args->v0.avi_infoframe_length, - args->v0.vendor_infoframe_length); + pack_hdmi_infoframe(&avi_infoframe, avi, avi_size); + pack_hdmi_infoframe(&vendor_infoframe, vendor, vendor_size); if (!(ctrl & 0x40000000)) { nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); nvkm_mask(device, 0x61c53c + soff, 0x00000001, 0x00000000); nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); - return 0; + return; } /* AVI InfoFrame */ nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); - if (args->v0.avi_infoframe_length) { + if (avi_size) { nvkm_wr32(device, 0x61c528 + soff, avi_infoframe.header); nvkm_wr32(device, 0x61c52c + soff, avi_infoframe.subpack0_low); nvkm_wr32(device, 0x61c530 + soff, avi_infoframe.subpack0_high); @@ -100,7 +67,7 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) /* Vendor InfoFrame */ nvkm_mask(device, 0x61c53c + soff, 0x00010001, 0x00010000); - if (args->v0.vendor_infoframe_length) { + if (vendor_size) { nvkm_wr32(device, 0x61c544 + soff, vendor_infoframe.header); nvkm_wr32(device, 0x61c548 + soff, vendor_infoframe.subpack0_low); nvkm_wr32(device, 0x61c54c + soff, vendor_infoframe.subpack0_high); @@ -121,5 +88,4 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) /* HDMI_CTRL */ nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl); - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index ea80e7fd7d23..0b5115dac4d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -43,6 +43,12 @@ struct nvkm_ior_func { void (*power)(struct nvkm_ior *, bool normal, bool pu, bool data, bool vsync, bool hsync); int (*sense)(struct nvkm_ior *, u32 loadval); + + struct { + void (*ctrl)(struct nvkm_ior *, int head, bool enable, + u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size, + u8 *vendor, u8 vendor_size); + } hdmi; }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, @@ -65,6 +71,11 @@ void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +void gk104_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); + #define IOR_MSG(i,l,f,a...) do { \ struct nvkm_ior *_ior = (i); \ nvkm_##l(&_ior->disp->engine.subdev, "%s: "f, _ior->name, ##a); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c index d707d8f4c0f0..4f4e4e68de33 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -38,9 +38,7 @@ mcp77_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 4, - .sor.new = mcp77_sor_new, - .sor.hdmi = g84_hdmi_ctrl, + .sor = { .nr = 4, .new = mcp77_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index 24f46705f616..11ec2960c9ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -41,7 +41,6 @@ mcp89_disp = { .sor.nr = 4, .sor.new = mcp89_sor_new, .sor.hda_eld = gt215_hda_eld, - .sor.hdmi = gt215_hdmi_ctrl, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 263c3a7f9d88..aa7b0739d874 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -34,11 +34,6 @@ void nv50_disp_super_1(struct nv50_disp *); int gt215_hda_eld(NV50_DISP_MTHD_V1); int gf119_hda_eld(NV50_DISP_MTHD_V1); -int g84_hdmi_ctrl(NV50_DISP_MTHD_V1); -int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); -int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); -int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); - int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, @@ -84,7 +79,6 @@ struct nv50_disp_func { int nr; int (*new)(struct nvkm_disp *, int id); int (*hda_eld)(NV50_DISP_MTHD_V1); - int (*hdmi)(NV50_DISP_MTHD_V1); void (*magic)(struct nvkm_output *); } sor; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 7ebea3e14e18..a81928de6dcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -116,10 +116,46 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) if (!func->sor.hda_eld) return -ENODEV; return func->sor.hda_eld(object, disp, data, size, hidx, outp); - case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: - if (!func->sor.hdmi) + case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: { + union { + struct nv50_disp_sor_hdmi_pwr_v0 v0; + } *args = data; + u8 *vendor, vendor_size; + u8 *avi, avi_size; + int ret = -ENOSYS; + + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); + if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) + return -EINVAL; + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) > size) + return -EINVAL; + else + if ((args->v0.avi_infoframe_length + + args->v0.vendor_infoframe_length) < size) + return -E2BIG; + avi = data; + avi_size = args->v0.avi_infoframe_length; + vendor = avi + avi_size; + vendor_size = args->v0.vendor_infoframe_length; + } else + return ret; + + if (!outp->ior->func->hdmi.ctrl) return -ENODEV; - return func->sor.hdmi(object, disp, data, size, hidx, outp); + + outp->ior->func->hdmi.ctrl(outp->ior, hidx, args->v0.state, + args->v0.max_ac_packet, + args->v0.rekey, avi, avi_size, + vendor, vendor_size); + return 0; + } + break; case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { union { struct nv50_disp_sor_lvds_script_v0 v0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c index bb0f503ee989..8913b5f58103 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -25,6 +25,9 @@ static const struct nvkm_ior_func g84_sor = { .state = nv50_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = g84_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index dcab72a52964..c3ce42e7a12e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -157,6 +157,9 @@ static const struct nvkm_ior_func gf119_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gf119_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index ac7a5944487a..9f71f9438c6a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -25,6 +25,9 @@ static const struct nvkm_ior_func gk104_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gk104_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 8bca4dca1e11..acffeff59a70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -57,6 +57,9 @@ static const struct nvkm_ior_func gm107_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gk104_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 0a4b9b967904..c8773d058073 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -134,6 +134,9 @@ static const struct nvkm_ior_func gm200_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gk104_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index bec04ad40494..7036eeeace57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -25,6 +25,9 @@ static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gt215_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index fc14e48fe84b..a074a4733ca0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -25,6 +25,9 @@ static const struct nvkm_ior_func mcp77_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = g84_hdmi_ctrl, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 37c1dacb7d67..56cf11ff0659 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -25,6 +25,9 @@ static const struct nvkm_ior_func mcp89_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .hdmi = { + .ctrl = gt215_hdmi_ctrl, + }, }; int From 333781045d84628417efa161d37256331abef64b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 46/73] drm/nouveau/disp/g94-: port OR DP lane mapping to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 4 ++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 12 ++++-------- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 5 ++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c | 3 +++ 9 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 0b5115dac4d6..f40819ead320 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -49,6 +49,10 @@ struct nvkm_ior_func { u8 max_ac_packet, u8 rekey, u8 *avi, u8 avi_size, u8 *vendor, u8 vendor_size); } hdmi; + + struct { + u8 lanes[4]; + } dp; }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 3175bb3031b5..3bcd31adecd8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -44,14 +44,7 @@ g94_sor_loff(struct nvkm_output_dp *outp) u32 g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { - static const u8 gm100[] = { 0, 8, 16, 24 }; - static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ - static const u8 g94[] = { 16, 8, 0, 24 }; - if (device->chipset >= 0x110) - return gm100[lane]; - if (device->chipset == 0xaf) - return mcp89[lane]; - return g94[lane]; + return nvkm_ior_find(device->disp, SOR, -1)->func->dp.lanes[lane] * 8; } static int @@ -305,6 +298,9 @@ static const struct nvkm_ior_func g94_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .dp = { + .lanes = { 2, 1, 0, 3}, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index c3ce42e7a12e..c97c178be3dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -160,6 +160,9 @@ gf119_sor = { .hdmi = { .ctrl = gf119_hdmi_ctrl, }, + .dp = { + .lanes = { 2, 1, 0, 3 }, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 9f71f9438c6a..6d85a285e47b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -28,6 +28,9 @@ gk104_sor = { .hdmi = { .ctrl = gk104_hdmi_ctrl, }, + .dp = { + .lanes = { 2, 1, 0, 3 }, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index acffeff59a70..bb055cd91b2f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -60,6 +60,9 @@ gm107_sor = { .hdmi = { .ctrl = gk104_hdmi_ctrl, }, + .dp = { + .lanes = { 0, 1, 2, 3 }, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index c8773d058073..11fed49fa9b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -41,7 +41,7 @@ gm200_sor_loff(struct nvkm_output_dp *outp) static inline u32 gm200_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { - return lane * 0x08; + return nvkm_ior_find(device->disp, SOR, -1)->func->dp.lanes[lane] * 8; } static int @@ -137,6 +137,9 @@ gm200_sor = { .hdmi = { .ctrl = gk104_hdmi_ctrl, }, + .dp = { + .lanes = { 0, 1, 2, 3 }, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 7036eeeace57..221255228e04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -28,6 +28,9 @@ gt215_sor = { .hdmi = { .ctrl = gt215_hdmi_ctrl, }, + .dp = { + .lanes = { 2, 1, 0, 3 }, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index a074a4733ca0..a771d10f253b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -28,6 +28,9 @@ mcp77_sor = { .hdmi = { .ctrl = g84_hdmi_ctrl, }, + .dp = { + .lanes = { 2, 1, 0, 3}, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 56cf11ff0659..aece6bec5ecf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -28,6 +28,9 @@ mcp89_sor = { .hdmi = { .ctrl = gt215_hdmi_ctrl, }, + .dp = { + .lanes = { 3, 2, 1, 0 }, + }, }; int From 7dc0bac4aabb62a91543a29782ce12955708bfe2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 47/73] drm/nouveau/disp/g94-: port OR DP link setup to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 10 ++++++---- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 2 -- drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 11 +++++++++++ .../drm/nouveau/nvkm/engine/disp/piornv50.c | 10 ++++++---- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 18 +++++++++--------- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 18 +++++++++--------- .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 2 +- .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 2 +- .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + 12 files changed, 47 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index f3b255027c11..979563434da8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -240,11 +240,13 @@ nvkm_dp_train_links(struct nvkm_dp *dp) nvbios_exec(&init); } - ret = dp->func->lnk_ctl(dp, ior->dp.nr, ior->dp.bw, ior->dp.ef); + ret = ior->func->dp.links(ior, dp->aux); if (ret) { - if (ret < 0) - OUTP_ERR(&dp->outp, "lnk_ctl failed with %d", ret); - return ret; + if (ret < 0) { + OUTP_ERR(&dp->outp, "train failed with %d", ret); + return ret; + } + return 0; } dp->func->lnk_pwr(dp, ior->dp.nr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 9d18aed75b10..ae61e8f1a1b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -35,7 +35,6 @@ struct nvkm_dp { struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); int (*lnk_pwr)(struct nvkm_output_dp *, int nr); - int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); @@ -55,7 +54,6 @@ int g94_sor_dp_lnk_pwr(struct nvkm_dp *, int); int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gf119_sor_dp_lnk_ctl(struct nvkm_dp *, int, int, bool); int gf119_sor_dp_drv_ctl(struct nvkm_dp *, int, int, int, int); void gf119_sor_dp_vcpi(struct nvkm_dp *, int, u8, u8, u16, u16); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index f40819ead320..680180dde0dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -1,6 +1,7 @@ #ifndef __NVKM_DISP_IOR_H__ #define __NVKM_DISP_IOR_H__ #include "priv.h" +struct nvkm_i2c_aux; struct nvkm_ior { const struct nvkm_ior_func *func; @@ -52,6 +53,7 @@ struct nvkm_ior_func { struct { u8 lanes[4]; + int (*links)(struct nvkm_ior *, struct nvkm_i2c_aux *); } dp; }; @@ -69,11 +71,20 @@ nv50_ior_base(struct nvkm_ior *ior) void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool); int nv50_dac_sense(struct nvkm_ior *, u32); +static inline u32 +nv50_sor_link(struct nvkm_ior *ior) +{ + return nv50_ior_base(ior) + ((ior->asy.link == 2) * 0x80); +} + void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); + void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 486050d4692e..d366deef241e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -58,10 +58,10 @@ nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) } static int -nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, - int nr, int bw, bool ef) +nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) { - int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); + int ret = nvkm_i2c_aux_lnk_ctl(aux, pior->dp.nr, pior->dp.bw, + pior->dp.ef); if (ret) return ret; return 1; @@ -71,7 +71,6 @@ static const struct nvkm_output_dp_func nv50_pior_output_dp_func = { .pattern = nv50_pior_output_dp_pattern, .lnk_pwr = nv50_pior_output_dp_lnk_pwr, - .lnk_ctl = nv50_pior_output_dp_lnk_ctl, }; int @@ -129,6 +128,9 @@ static const struct nvkm_ior_func nv50_pior = { .state = nv50_pior_state, .power = nv50_pior_power, + .dp = { + .links = nv50_pior_dp_links, + }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 3bcd31adecd8..38d6148d8b11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -110,19 +110,19 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) return 0; } -static int -g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +int +g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = g94_sor_soff(outp); - const u32 loff = g94_sor_loff(outp); + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 loff = nv50_sor_link(sor); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; - dpctrl |= ((1 << nr) - 1) << 16; - if (ef) + dpctrl |= ((1 << sor->dp.nr) - 1) << 16; + if (sor->dp.ef) dpctrl |= 0x00004000; - if (bw > 0x06) + if (sor->dp.bw > 0x06) clksor |= 0x00040000; nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor); @@ -134,7 +134,6 @@ static const struct nvkm_output_dp_func g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, - .lnk_ctl = g94_sor_dp_lnk_ctl, .drv_ctl = g94_sor_dp_drv_ctl, }; @@ -300,6 +299,7 @@ g94_sor = { .power = nv50_sor_power, .dp = { .lanes = { 2, 1, 0, 3}, + .links = g94_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index c97c178be3dc..38f13ef6f97a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -94,19 +94,19 @@ gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) } int -gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gf119_sor_soff(outp); - const u32 loff = gf119_sor_loff(outp); + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 loff = nv50_sor_link(sor); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; - clksor |= bw << 18; - dpctrl |= ((1 << nr) - 1) << 16; - if (outp->lt.mst) + clksor |= sor->dp.bw << 18; + dpctrl |= ((1 << sor->dp.nr) - 1) << 16; + if (sor->dp.mst) dpctrl |= 0x40000000; - if (ef) + if (sor->dp.ef) dpctrl |= 0x00004000; nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); @@ -118,7 +118,6 @@ static const struct nvkm_output_dp_func gf119_sor_dp_func = { .pattern = gf119_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, - .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -162,6 +161,7 @@ gf119_sor = { }, .dp = { .lanes = { 2, 1, 0, 3 }, + .links = gf119_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 6d85a285e47b..2dca1e391219 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -30,6 +30,7 @@ gk104_sor = { }, .dp = { .lanes = { 2, 1, 0, 3 }, + .links = gf119_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index bb055cd91b2f..9d1732257e4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -41,7 +41,6 @@ static const struct nvkm_output_dp_func gm107_sor_dp_func = { .pattern = gm107_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, - .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -62,6 +61,7 @@ gm107_sor = { }, .dp = { .lanes = { 0, 1, 2, 3 }, + .links = gf119_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 11fed49fa9b6..f3072c2d9bea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -106,7 +106,6 @@ static const struct nvkm_output_dp_func gm200_sor_dp_func = { .pattern = gm107_sor_dp_pattern, .lnk_pwr = gm200_sor_dp_lnk_pwr, - .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gm200_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -139,6 +138,7 @@ gm200_sor = { }, .dp = { .lanes = { 0, 1, 2, 3 }, + .links = gf119_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 221255228e04..059d88145f47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -30,6 +30,7 @@ gt215_sor = { }, .dp = { .lanes = { 2, 1, 0, 3 }, + .links = g94_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index a771d10f253b..051670322d04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -30,6 +30,7 @@ mcp77_sor = { }, .dp = { .lanes = { 2, 1, 0, 3}, + .links = g94_sor_dp_links, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index aece6bec5ecf..0afdceb203d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -30,6 +30,7 @@ mcp89_sor = { }, .dp = { .lanes = { 3, 2, 1, 0 }, + .links = g94_sor_dp_links, }, }; From a3e81117ce0bcec293352558613e35065659da10 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 48/73] drm/nouveau/disp/g94-: port OR DP link power control to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 2 -- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 ++ .../drm/nouveau/nvkm/engine/disp/piornv50.c | 7 ------ .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 15 ++++++------ .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 2 +- .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 2 +- .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 24 +------------------ .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + 12 files changed, 17 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 979563434da8..545d4ccedffe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -249,7 +249,7 @@ nvkm_dp_train_links(struct nvkm_dp *dp) return 0; } - dp->func->lnk_pwr(dp, ior->dp.nr); + ior->func->dp.power(ior, ior->dp.nr); /* Set desired link configuration on the sink. */ sink[0] = ior->dp.bw; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index ae61e8f1a1b9..c96959aa5d0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -34,7 +34,6 @@ struct nvkm_dp { struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); - int (*lnk_pwr)(struct nvkm_output_dp *, int nr); int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); @@ -50,7 +49,6 @@ int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int g94_sor_dp_lnk_pwr(struct nvkm_dp *, int); int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 680180dde0dd..3b660a2fc7cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -54,6 +54,7 @@ struct nvkm_ior_func { struct { u8 lanes[4]; int (*links)(struct nvkm_ior *, struct nvkm_i2c_aux *); + void (*power)(struct nvkm_ior *, int nr); } dp; }; @@ -82,6 +83,7 @@ void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); +void g94_sor_dp_power(struct nvkm_ior *, int); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index d366deef241e..5e87c08f809e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -51,12 +51,6 @@ nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) return 0; } -static int -nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) -{ - return 0; -} - static int nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) { @@ -70,7 +64,6 @@ nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func nv50_pior_output_dp_func = { .pattern = nv50_pior_output_dp_pattern, - .lnk_pwr = nv50_pior_output_dp_lnk_pwr, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 38d6148d8b11..569ed247bc1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -90,16 +90,16 @@ g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) return 0; } -int -g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +void +g94_sor_dp_power(struct nvkm_ior *sor, int nr) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = g94_sor_soff(outp); - const u32 loff = g94_sor_loff(outp); + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 loff = nv50_sor_link(sor); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3); + mask |= 1 << sor->func->dp.lanes[i]; nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); @@ -107,7 +107,6 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) break; ); - return 0; } int @@ -133,7 +132,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, - .lnk_pwr = g94_sor_dp_lnk_pwr, .drv_ctl = g94_sor_dp_drv_ctl, }; @@ -300,6 +298,7 @@ g94_sor = { .dp = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 38f13ef6f97a..d45fd094fc63 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -117,7 +117,6 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func gf119_sor_dp_func = { .pattern = gf119_sor_dp_pattern, - .lnk_pwr = g94_sor_dp_lnk_pwr, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -162,6 +161,7 @@ gf119_sor = { .dp = { .lanes = { 2, 1, 0, 3 }, .links = gf119_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 2dca1e391219..4d376fd7d3d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -31,6 +31,7 @@ gk104_sor = { .dp = { .lanes = { 2, 1, 0, 3 }, .links = gf119_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 9d1732257e4a..642d3c4ed26a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -40,7 +40,6 @@ gm107_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) static const struct nvkm_output_dp_func gm107_sor_dp_func = { .pattern = gm107_sor_dp_pattern, - .lnk_pwr = g94_sor_dp_lnk_pwr, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -62,6 +61,7 @@ gm107_sor = { .dp = { .lanes = { 0, 1, 2, 3 }, .links = gf119_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index f3072c2d9bea..b7083e99a7df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -24,8 +24,6 @@ #include "ior.h" #include "nv50.h" -#include - static inline u32 gm200_sor_soff(struct nvkm_output_dp *outp) { @@ -82,30 +80,9 @@ gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -static int -gm200_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gm200_sor_soff(outp); - const u32 loff = gm200_sor_loff(outp); - u32 mask = 0, i; - - for (i = 0; i < nr; i++) - mask |= 1 << (gm200_sor_dp_lane_map(device, i) >> 3); - - nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); - nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) - break; - ); - return 0; -} - static const struct nvkm_output_dp_func gm200_sor_dp_func = { .pattern = gm107_sor_dp_pattern, - .lnk_pwr = gm200_sor_dp_lnk_pwr, .drv_ctl = gm200_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -139,6 +116,7 @@ gm200_sor = { .dp = { .lanes = { 0, 1, 2, 3 }, .links = gf119_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 059d88145f47..4e5f6591e50b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -31,6 +31,7 @@ gt215_sor = { .dp = { .lanes = { 2, 1, 0, 3 }, .links = g94_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 051670322d04..6868f0758718 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -31,6 +31,7 @@ mcp77_sor = { .dp = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, + .power = g94_sor_dp_power, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 0afdceb203d5..c2b7de0b29dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -31,6 +31,7 @@ mcp89_sor = { .dp = { .lanes = { 3, 2, 1, 0 }, .links = g94_sor_dp_links, + .power = g94_sor_dp_power, }, }; From a1de2b522fef9fd725f2edb6989af68b8749acf5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 49/73] drm/nouveau/disp/g94-: port OR DP training pattern control to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 2 -- drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 5 +++++ drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c | 7 ------- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 11 +++++------ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 11 +++++------ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 13 ++++++------- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + 12 files changed, 27 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 545d4ccedffe..fecaa03eeb94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -122,7 +122,7 @@ nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) u8 sink_tp; OUTP_TRACE(&dp->outp, "training pattern %d", pattern); - dp->func->pattern(dp, pattern); + dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern); nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index c96959aa5d0e..2bda157984ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -33,7 +33,6 @@ struct nvkm_dp { #define nvkm_output_dp nvkm_dp struct nvkm_output_dp_func { - int (*pattern)(struct nvkm_output_dp *, int); int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); @@ -57,7 +56,6 @@ void gf119_sor_dp_vcpi(struct nvkm_dp *, int, u8, u8, u16, u16); int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gm107_sor_dp_pattern(struct nvkm_dp *, int); int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 3b660a2fc7cb..f88875dc22b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -55,6 +55,7 @@ struct nvkm_ior_func { u8 lanes[4]; int (*links)(struct nvkm_ior *, struct nvkm_i2c_aux *); void (*power)(struct nvkm_ior *, int nr); + void (*pattern)(struct nvkm_ior *, int pattern); } dp; }; @@ -84,9 +85,13 @@ void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void g94_sor_dp_power(struct nvkm_ior *, int); +void g94_sor_dp_pattern(struct nvkm_ior *, int); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); +void gf119_sor_dp_pattern(struct nvkm_ior *, int); + +void gm107_sor_dp_pattern(struct nvkm_ior *, int); void g84_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 5e87c08f809e..a3c4386a5a90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -45,12 +45,6 @@ nv50_pior_output_new(struct nvkm_disp *disp, int index, /****************************************************************************** * DisplayPort *****************************************************************************/ -static int -nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) -{ - return 0; -} - static int nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) { @@ -63,7 +57,6 @@ nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func nv50_pior_output_dp_func = { - .pattern = nv50_pior_output_dp_pattern, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 569ed247bc1c..5b45c3ee4e59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -81,13 +81,12 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) return 0; } -static int -g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) +void +g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 loff = g94_sor_loff(outp); + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); - return 0; } void @@ -131,7 +130,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func g94_sor_dp_func = { - .pattern = g94_sor_dp_pattern, .drv_ctl = g94_sor_dp_drv_ctl, }; @@ -299,6 +297,7 @@ g94_sor = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, .power = g94_sor_dp_power, + .pattern = g94_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index d45fd094fc63..60a269ed2e0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -84,13 +84,12 @@ gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -static int -gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) +void +gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gf119_sor_soff(outp); + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); - return 0; } int @@ -116,7 +115,6 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func gf119_sor_dp_func = { - .pattern = gf119_sor_dp_pattern, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -162,6 +160,7 @@ gf119_sor = { .lanes = { 2, 1, 0, 3 }, .links = gf119_sor_dp_links, .power = g94_sor_dp_power, + .pattern = gf119_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 4d376fd7d3d2..fc6ac2ee25a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -32,6 +32,7 @@ gk104_sor = { .lanes = { 2, 1, 0, 3 }, .links = gf119_sor_dp_links, .power = g94_sor_dp_power, + .pattern = gf119_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 642d3c4ed26a..ae82f595f459 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -24,22 +24,20 @@ #include "ior.h" #include "nv50.h" -int -gm107_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) +void +gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = outp->base.or * 0x800; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); const u32 data = 0x01010101 * pattern; - if (outp->base.info.sorconf.link & 1) + if (sor->asy.link & 1) nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); else nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); - return 0; } static const struct nvkm_output_dp_func gm107_sor_dp_func = { - .pattern = gm107_sor_dp_pattern, .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -62,6 +60,7 @@ gm107_sor = { .lanes = { 0, 1, 2, 3 }, .links = gf119_sor_dp_links, .power = g94_sor_dp_power, + .pattern = gm107_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index b7083e99a7df..2d32bcc8aa8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -82,7 +82,6 @@ gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, static const struct nvkm_output_dp_func gm200_sor_dp_func = { - .pattern = gm107_sor_dp_pattern, .drv_ctl = gm200_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -117,6 +116,7 @@ gm200_sor = { .lanes = { 0, 1, 2, 3 }, .links = gf119_sor_dp_links, .power = g94_sor_dp_power, + .pattern = gm107_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 4e5f6591e50b..7dc8393a22b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -32,6 +32,7 @@ gt215_sor = { .lanes = { 2, 1, 0, 3 }, .links = g94_sor_dp_links, .power = g94_sor_dp_power, + .pattern = g94_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 6868f0758718..737aa7bf07a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -32,6 +32,7 @@ mcp77_sor = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, .power = g94_sor_dp_power, + .pattern = g94_sor_dp_pattern, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index c2b7de0b29dd..2719d305c8cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -32,6 +32,7 @@ mcp89_sor = { .lanes = { 3, 2, 1, 0 }, .links = g94_sor_dp_links, .power = g94_sor_dp_power, + .pattern = g94_sor_dp_pattern, }, }; From 7d1fede03c5880003a08ff080e6e41984902be46 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 50/73] drm/nouveau/disp/g94-: port OR DP drive setting control to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 24 +++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 4 ++ .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 - .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 59 ++++-------------- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 52 ++++------------ .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 2 +- .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 60 ++++--------------- .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 1 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 1 + 12 files changed, 66 insertions(+), 143 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index fecaa03eeb94..2d8f93323309 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -73,9 +73,15 @@ static int nvkm_dp_train_drive(struct lt_state *lt, bool pc) { struct nvkm_dp *dp = lt->dp; + struct nvkm_ior *ior = dp->outp.ior; + struct nvkm_bios *bios = ior->disp->engine.subdev.device->bios; + struct nvbios_dpout info; + struct nvbios_dpcfg ocfg; + u8 ver, hdr, cnt, len; + u32 data; int ret, i; - for (i = 0; i < dp->outp.ior->dp.nr; i++) { + for (i = 0; i < ior->dp.nr; i++) { u8 lane = (lt->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf; u8 lpc2 = (lt->pc2stat >> (i * 2)) & 0x3; u8 lpre = (lane & 0x0c) >> 2; @@ -99,7 +105,21 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", i, lt->conf[i], lpc2); - dp->func->drv_ctl(dp, i, lvsw & 3, lpre & 3, lpc2 & 3); + + data = nvbios_dpout_match(bios, dp->outp.info.hasht, + dp->outp.info.hashm, + &ver, &hdr, &cnt, &len, &info); + if (!data) + continue; + + data = nvbios_dpcfg_match(bios, data, lpc2 & 3, lvsw & 3, + lpre & 3, &ver, &hdr, &cnt, &len, + &ocfg); + if (!data) + continue; + + ior->func->dp.drive(ior, i, ocfg.pc, ocfg.dc, + ocfg.pe, ocfg.tx_pu); } ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 2bda157984ce..21f20bc92ae4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -33,7 +33,6 @@ struct nvkm_dp { #define nvkm_output_dp nvkm_dp struct nvkm_output_dp_func { - int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc); void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, u8 num_slots, u16 pbn, u16 aligned_pbn); }; @@ -51,7 +50,6 @@ int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gf119_sor_dp_drv_ctl(struct nvkm_dp *, int, int, int, int); void gf119_sor_dp_vcpi(struct nvkm_dp *, int, u8, u8, u16, u16); int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index f88875dc22b6..3295a6a23fb8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -56,6 +56,8 @@ struct nvkm_ior_func { int (*links)(struct nvkm_ior *, struct nvkm_i2c_aux *); void (*power)(struct nvkm_ior *, int nr); void (*pattern)(struct nvkm_ior *, int pattern); + void (*drive)(struct nvkm_ior *, int ln, int pc, + int dc, int pe, int tx_pu); } dp; }; @@ -86,10 +88,12 @@ void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void g94_sor_dp_power(struct nvkm_ior *, int); void g94_sor_dp_pattern(struct nvkm_ior *, int); +void g94_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void gf119_sor_dp_pattern(struct nvkm_ior *, int); +void gf119_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); void gm107_sor_dp_pattern(struct nvkm_ior *, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index e48251c37822..80d4a0d34f14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -47,8 +47,6 @@ int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); - void gm200_sor_magic(struct nvkm_output *outp); #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 5b45c3ee4e59..a4a4749d3c4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -26,59 +26,22 @@ #include -static inline u32 -g94_sor_soff(struct nvkm_output_dp *outp) +void +g94_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) { - return (ffs(outp->base.info.or) - 1) * 0x800; -} - -static inline u32 -g94_sor_loff(struct nvkm_output_dp *outp) -{ - return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; -} - -/******************************************************************************* - * DisplayPort - ******************************************************************************/ -u32 -g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) -{ - return nvkm_ior_find(device->disp, SOR, -1)->func->dp.lanes[lane] * 8; -} - -static int -g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(device, ln); - const u32 loff = g94_sor_loff(outp); - u32 addr, data[3]; - u8 ver, hdr, cnt, len; - struct nvbios_dpout info; - struct nvbios_dpcfg ocfg; - - addr = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); - if (!addr) - return -ENODEV; - - addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); - if (!addr) - return -EINVAL; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); + const u32 shift = sor->func->dp.lanes[ln] * 8; + u32 data[3]; data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); data[2] = nvkm_rd32(device, 0x61c130 + loff); - if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0) + data[2] = (data[2] & ~0x0000ff00) | (pu << 8); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift)); nvkm_wr32(device, 0x61c130 + loff, data[2]); - return 0; } void @@ -130,7 +93,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func g94_sor_dp_func = { - .drv_ctl = g94_sor_dp_drv_ctl, }; int @@ -298,6 +260,7 @@ g94_sor = { .links = g94_sor_dp_links, .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, + .drive = g94_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 60a269ed2e0d..48091e15c973 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -35,53 +35,24 @@ gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, nvkm_mask(device, 0x61658c + hoff, 0xffffffff, (aligned << 16) | pbn); } -static inline u32 -gf119_sor_soff(struct nvkm_output_dp *outp) +void +gf119_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) { - return (ffs(outp->base.info.or) - 1) * 0x800; -} - -static inline u32 -gf119_sor_loff(struct nvkm_output_dp *outp) -{ - return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; -} - -int -gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, - int ln, int vs, int pe, int pc) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(device, ln); - const u32 loff = gf119_sor_loff(outp); - u32 addr, data[4]; - u8 ver, hdr, cnt, len; - struct nvbios_dpout info; - struct nvbios_dpcfg ocfg; - - addr = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); - if (!addr) - return -ENODEV; - - addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); - if (!addr) - return -EINVAL; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); + const u32 shift = sor->func->dp.lanes[ln] * 8; + u32 data[4]; data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); data[2] = nvkm_rd32(device, 0x61c130 + loff); - if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + if ((data[2] & 0x0000ff00) < (pu << 8) || ln == 0) + data[2] = (data[2] & ~0x0000ff00) | (pu << 8); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift)); nvkm_wr32(device, 0x61c130 + loff, data[2]); data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); - nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); - return 0; + nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift)); } void @@ -115,7 +86,6 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func gf119_sor_dp_func = { - .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index fc6ac2ee25a5..55a5a56b3723 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -33,6 +33,7 @@ gk104_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, + .drive = gf119_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index ae82f595f459..40c7eff35a93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -38,7 +38,6 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) static const struct nvkm_output_dp_func gm107_sor_dp_func = { - .drv_ctl = gf119_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -61,6 +60,7 @@ gm107_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, + .drive = gf119_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 2d32bcc8aa8a..5efec0f480fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -24,65 +24,30 @@ #include "ior.h" #include "nv50.h" -static inline u32 -gm200_sor_soff(struct nvkm_output_dp *outp) +static void +gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) { - return (ffs(outp->base.info.or) - 1) * 0x800; -} + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); + const u32 shift = sor->func->dp.lanes[ln] * 8; + u32 data[4]; -static inline u32 -gm200_sor_loff(struct nvkm_output_dp *outp) -{ - return gm200_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; -} - -static inline u32 -gm200_sor_dp_lane_map(struct nvkm_device *device, u8 lane) -{ - return nvkm_ior_find(device->disp, SOR, -1)->func->dp.lanes[lane] * 8; -} - -static int -gm200_sor_dp_drv_ctl(struct nvkm_output_dp *outp, - int ln, int vs, int pe, int pc) -{ - struct nvkm_device *device = outp->base.disp->engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const u32 shift = gm200_sor_dp_lane_map(device, ln); - const u32 loff = gm200_sor_loff(outp); - u32 addr, data[4]; - u8 ver, hdr, cnt, len; - struct nvbios_dpout info; - struct nvbios_dpcfg ocfg; - - addr = nvbios_dpout_match(bios, outp->base.info.hasht, - outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); - if (!addr) - return -ENODEV; - - addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); - if (!addr) - return -EINVAL; - ocfg.tx_pu &= 0x0f; + pu &= 0x0f; data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); data[2] = nvkm_rd32(device, 0x61c130 + loff); - if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8); - nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + if ((data[2] & 0x00000f00) < (pu << 8) || ln == 0) + data[2] = (data[2] & ~0x00000f00) | (pu << 8); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (pe << shift)); nvkm_wr32(device, 0x61c130 + loff, data[2]); data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); - nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); - return 0; + nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift)); } static const struct nvkm_output_dp_func gm200_sor_dp_func = { - .drv_ctl = gm200_sor_dp_drv_ctl, .vcpi = gf119_sor_dp_vcpi, }; @@ -117,6 +82,7 @@ gm200_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, + .drive = gm200_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 7dc8393a22b6..eb084102baff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -33,6 +33,7 @@ gt215_sor = { .links = g94_sor_dp_links, .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, + .drive = g94_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 737aa7bf07a6..50d6c0d98e20 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -33,6 +33,7 @@ mcp77_sor = { .links = g94_sor_dp_links, .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, + .drive = g94_sor_dp_drive, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 2719d305c8cf..385c4d13c58e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -33,6 +33,7 @@ mcp89_sor = { .links = g94_sor_dp_links, .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, + .drive = g94_sor_dp_drive, }, }; From 409b9e54727e700ab8dd15a1e29226eda1e04cdb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 51/73] drm/nouveau/disp/gt215-: port HDA ELD controls to nvkm_ior Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 4 +- .../drm/nouveau/nvkm/engine/disp/hdagf119.c | 83 ++++++------------- .../drm/nouveau/nvkm/engine/disp/hdagt215.c | 76 ++++++----------- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 15 ++++ .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 8 -- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 36 +++++++- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 21 +++++ .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 5 ++ .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 5 ++ .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 5 ++ .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 21 +++++ .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 5 ++ 20 files changed, 166 insertions(+), 141 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index d4df1983f769..bb816f78230f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -507,9 +507,7 @@ gf119_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, - .sor.nr = 4, - .sor.new = gf119_sor_new, - .sor.hda_eld = gf119_hda_eld, + .sor = { .nr = 4, .new = gf119_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 4d22d87c4620..e45cc01aed1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -39,9 +39,7 @@ gk104_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, - .sor.nr = 4, - .sor.new = gk104_sor_new, - .sor.hda_eld = gf119_hda_eld, + .sor = { .nr = 4, .new = gk104_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index adc2a2257438..e0990ffd3f57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -39,9 +39,7 @@ gk110_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, - .sor.nr = 4, - .sor.new = gk104_sor_new, - .sor.hda_eld = gf119_hda_eld, + .sor = { .nr = 4, .new = gk104_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 116b99b51359..e42ab42b9dd1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -39,9 +39,7 @@ gm107_disp = { .outp.internal.lvds = nv50_sor_output_new, .outp.internal.dp = gm107_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, - .sor.nr = 4, - .sor.new = gm107_sor_new, - .sor.hda_eld = gf119_hda_eld, + .sor = { .nr = 4, .new = gm107_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index ffdb5a412821..287c00159481 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -41,7 +41,6 @@ gm200_disp = { .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.hda_eld = gf119_hda_eld, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index bd5ab596877b..c83883c0bd43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -39,7 +39,6 @@ gp100_disp = { .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.hda_eld = gf119_hda_eld, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 4875d4822d42..bac4d05a0015 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -65,7 +65,6 @@ gp102_disp = { .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, - .sor.hda_eld = gf119_hda_eld, .sor.magic = gm200_sor_magic, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 4edd37124536..0c761feca2d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -40,9 +40,7 @@ gt215_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 4, - .sor.new = gt215_sor_new, - .sor.hda_eld = gt215_hda_eld, + .sor = { .nr = 4, .new = gt215_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c index da6129b2b78f..0fa0ec0a1de0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c @@ -21,63 +21,34 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" -#include "outp.h" +#include "ior.h" -#include -#include -#include -#include - -#include -#include - -int -gf119_hda_eld(NV50_DISP_MTHD_V1) +void +gf119_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - union { - struct nv50_disp_sor_hda_eld_v0 v0; - } *args = data; - const u32 soff = outp->or * 0x030; - const u32 hoff = head * 0x800; - int ret = -ENOSYS, i; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = 0x030 * ior->id; + int i; - nvif_ioctl(object, "disp sor hda eld size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hda eld vers %d\n", - args->v0.version); - if (size > 0x60) - return -E2BIG; - } else - return ret; - - if (size && args->v0.data[0]) { - if (outp->info.type == DCB_OUTPUT_DP) { - nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001); - nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x616618 + hoff); - if (!(tmp & 0x80000000)) - break; - ); - } - nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); - for (i = 0; i < size; i++) - nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); - for (; i < 0x60; i++) - nvkm_wr32(device, 0x10ec00 + soff, (i << 8)); - nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000003); - } else { - if (outp->info.type == DCB_OUTPUT_DP) { - nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000); - nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x616618 + hoff); - if (!(tmp & 0x80000000)) - break; - ); - } - nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); - } - - return 0; + for (i = 0; i < size; i++) + nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | data[i]); + for (; i < 0x60; i++) + nvkm_wr32(device, 0x10ec00 + soff, (i << 8)); + nvkm_mask(device, 0x10ec10 + soff, 0x80000002, 0x80000002); +} + +void +gf119_hda_hpd(struct nvkm_ior *ior, int head, bool present) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 hoff = 0x800 * head; + u32 data = 0x80000000; + u32 mask = 0x80000001; + if (present) { + nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); + data |= 0x00000001; + } else { + mask |= 0x00000002; + } + nvkm_mask(device, 0x10ec10 + ior->id * 0x030, mask, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index f8f2f16c22a2..4509d2ba880e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -21,59 +21,31 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" -#include "outp.h" +#include "ior.h" -#include -#include - -#include -#include - -int -gt215_hda_eld(NV50_DISP_MTHD_V1) +void +gt215_hda_eld(struct nvkm_ior *ior, u8 *data, u8 size) { - struct nvkm_device *device = disp->base.engine.subdev.device; - union { - struct nv50_disp_sor_hda_eld_v0 v0; - } *args = data; - const u32 soff = outp->or * 0x800; - int ret = -ENOSYS, i; + struct nvkm_device *device = ior->disp->engine.subdev.device; + const u32 soff = ior->id * 0x800; + int i; - nvif_ioctl(object, "disp sor hda eld size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - nvif_ioctl(object, "disp sor hda eld vers %d\n", - args->v0.version); - if (size > 0x60) - return -E2BIG; - } else - return ret; - - if (size && args->v0.data[0]) { - if (outp->info.type == DCB_OUTPUT_DP) { - nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001); - nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); - if (!(tmp & 0x80000000)) - break; - ); - } - for (i = 0; i < size; i++) - nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]); - for (; i < 0x60; i++) - nvkm_wr32(device, 0x61c440 + soff, (i << 8)); - nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003); - } else { - if (outp->info.type == DCB_OUTPUT_DP) { - nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000); - nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); - if (!(tmp & 0x80000000)) - break; - ); - } - nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); - } - - return 0; + for (i = 0; i < size; i++) + nvkm_wr32(device, 0x61c440 + soff, (i << 8) | data[i]); + for (; i < 0x60; i++) + nvkm_wr32(device, 0x61c440 + soff, (i << 8)); + nvkm_mask(device, 0x61c448 + soff, 0x80000002, 0x80000002); +} + +void +gt215_hda_hpd(struct nvkm_ior *ior, int head, bool present) +{ + struct nvkm_device *device = ior->disp->engine.subdev.device; + u32 data = 0x80000000; + u32 mask = 0x80000001; + if (present) + data |= 0x00000001; + else + mask |= 0x00000002; + nvkm_mask(device, 0x61c448 + ior->id * 0x800, mask, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 3295a6a23fb8..0127474dc6c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -58,7 +58,13 @@ struct nvkm_ior_func { void (*pattern)(struct nvkm_ior *, int pattern); void (*drive)(struct nvkm_ior *, int ln, int pc, int dc, int pe, int tx_pu); + void (*audio)(struct nvkm_ior *, int head, bool enable); } dp; + + struct { + void (*hpd)(struct nvkm_ior *, int head, bool present); + void (*eld)(struct nvkm_ior *, u8 *data, u8 size); + } hda; }; int nvkm_ior_new_(const struct nvkm_ior_func *func, struct nvkm_disp *, @@ -90,10 +96,13 @@ void g94_sor_dp_power(struct nvkm_ior *, int); void g94_sor_dp_pattern(struct nvkm_ior *, int); void g94_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); +void gt215_sor_dp_audio(struct nvkm_ior *, int, bool); + void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void gf119_sor_dp_pattern(struct nvkm_ior *, int); void gf119_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); +void gf119_sor_dp_audio(struct nvkm_ior *, int, bool); void gm107_sor_dp_pattern(struct nvkm_ior *, int); @@ -102,6 +111,12 @@ void gt215_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); void gf119_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); void gk104_hdmi_ctrl(struct nvkm_ior *, int, bool, u8, u8, u8 *, u8 , u8 *, u8); +void gt215_hda_hpd(struct nvkm_ior *, int, bool); +void gt215_hda_eld(struct nvkm_ior *, u8 *, u8); + +void gf119_hda_hpd(struct nvkm_ior *, int, bool); +void gf119_hda_eld(struct nvkm_ior *, u8 *, u8); + #define IOR_MSG(i,l,f,a...) do { \ struct nvkm_ior *_ior = (i); \ nvkm_##l(&_ior->disp->engine.subdev, "%s: "f, _ior->name, ##a); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index 11ec2960c9ac..80e0f523f071 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -38,9 +38,7 @@ mcp89_disp = { .outp.external.tmds = nv50_pior_output_new, .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, - .sor.nr = 4, - .sor.new = mcp89_sor_new, - .sor.hda_eld = gt215_hda_eld, + .sor = { .nr = 4, .new = mcp89_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index aa7b0739d874..d00ce1da1637 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -4,10 +4,6 @@ #include "priv.h" #include "dp.h" -#define NV50_DISP_MTHD_ struct nvkm_object *object, \ - struct nv50_disp *disp, void *data, u32 size -#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp - struct nv50_disp { const struct nv50_disp_func *func; struct nvkm_disp base; @@ -31,9 +27,6 @@ struct nv50_disp { void nv50_disp_super_1(struct nv50_disp *); -int gt215_hda_eld(NV50_DISP_MTHD_V1); -int gf119_hda_eld(NV50_DISP_MTHD_V1); - int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, @@ -78,7 +71,6 @@ struct nv50_disp_func { struct { int nr; int (*new)(struct nvkm_disp *, int id); - int (*hda_eld)(NV50_DISP_MTHD_V1); void (*magic)(struct nvkm_output *); } sor; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index a81928de6dcd..d6371110f5a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -43,7 +43,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } *args = data; struct nv50_disp_root *root = nv50_disp_root(object); struct nv50_disp *disp = root->disp; - const struct nv50_disp_func *func = disp->func; struct nvkm_outp *temp, *outp = NULL; struct nvkm_head *head; u16 type, mask = 0; @@ -112,10 +111,39 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) return ret; } break; - case NV50_DISP_MTHD_V1_SOR_HDA_ELD: - if (!func->sor.hda_eld) + case NV50_DISP_MTHD_V1_SOR_HDA_ELD: { + union { + struct nv50_disp_sor_hda_eld_v0 v0; + } *args = data; + struct nvkm_ior *ior = outp->ior; + int ret = -ENOSYS; + + nvif_ioctl(object, "disp sor hda eld size %d\n", size); + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { + nvif_ioctl(object, "disp sor hda eld vers %d\n", + args->v0.version); + if (size > 0x60) + return -E2BIG; + } else + return ret; + + if (!ior->func->hda.hpd) return -ENODEV; - return func->sor.hda_eld(object, disp, data, size, hidx, outp); + + if (size && args->v0.data[0]) { + if (outp->info.type == DCB_OUTPUT_DP) + ior->func->dp.audio(ior, hidx, true); + ior->func->hda.hpd(ior, hidx, true); + ior->func->hda.eld(ior, data, size); + } else { + if (outp->info.type == DCB_OUTPUT_DP) + ior->func->dp.audio(ior, hidx, false); + ior->func->hda.hpd(ior, hidx, false); + } + + return 0; + } + break; case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: { union { struct nv50_disp_sor_hdmi_pwr_v0 v0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 48091e15c973..c3dbfd26ace8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -24,6 +24,22 @@ #include "ior.h" #include "nv50.h" +#include + +void +gf119_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 hoff = 0x800 * head; + const u32 data = 0x80000000 | (0x00000001 * enable); + const u32 mask = 0x8000000d; + nvkm_mask(device, 0x616618 + hoff, mask, data); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x616618 + hoff) & 0x80000000)) + break; + ); +} + void gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned) @@ -131,6 +147,11 @@ gf119_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, + .audio = gf119_sor_dp_audio, + }, + .hda = { + .hpd = gf119_hda_hpd, + .eld = gf119_hda_eld, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 55a5a56b3723..ee6bf54077a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -34,6 +34,11 @@ gk104_sor = { .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, .drive = gf119_sor_dp_drive, + .audio = gf119_sor_dp_audio, + }, + .hda = { + .hpd = gf119_hda_hpd, + .eld = gf119_hda_eld, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 40c7eff35a93..a6710758d7ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -61,6 +61,11 @@ gm107_sor = { .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, .drive = gf119_sor_dp_drive, + .audio = gf119_sor_dp_audio, + }, + .hda = { + .hpd = gf119_hda_hpd, + .eld = gf119_hda_eld, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 5efec0f480fa..3b152e116b88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -83,6 +83,11 @@ gm200_sor = { .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, .drive = gm200_sor_dp_drive, + .audio = gf119_sor_dp_audio, + }, + .hda = { + .hpd = gf119_hda_hpd, + .eld = gf119_hda_eld, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index eb084102baff..5e9126e832ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -21,6 +21,22 @@ */ #include "ior.h" +#include + +void +gt215_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + const u32 data = 0x80000000 | (0x00000001 * enable); + const u32 mask = 0x8000000d; + nvkm_mask(device, 0x61c1e0 + soff, mask, data); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c1e0 + soff) & 0x80000000)) + break; + ); +} + static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, @@ -34,6 +50,11 @@ gt215_sor = { .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, + .audio = gt215_sor_dp_audio, + }, + .hda = { + .hpd = gt215_hda_hpd, + .eld = gt215_hda_eld, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index 385c4d13c58e..dd76351d2ccb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -34,6 +34,11 @@ mcp89_sor = { .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, + .audio = gt215_sor_dp_audio, + }, + .hda = { + .hpd = gt215_hda_hpd, + .eld = gt215_hda_eld, }, }; From e8ccc96dd5f4baa1deb21b6d3b2c4a07bcf62254 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 52/73] drm/nouveau/disp/gf119-: port OR DP VCPI control to nvkm_ior Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 3 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c | 11 ++++++----- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 2 +- 7 files changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 21f20bc92ae4..edd416c62d3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -33,8 +33,6 @@ struct nvkm_dp { #define nvkm_output_dp nvkm_dp struct nvkm_output_dp_func { - void (*vcpi)(struct nvkm_output_dp *, int head, u8 start_slot, - u8 num_slots, u16 pbn, u16 aligned_pbn); }; int nvkm_output_dp_train(struct nvkm_output *, u32 rate); @@ -50,7 +48,6 @@ int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -void gf119_sor_dp_vcpi(struct nvkm_dp *, int, u8, u8, u16, u16); int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 0127474dc6c2..a43a924debfe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -58,6 +58,8 @@ struct nvkm_ior_func { void (*pattern)(struct nvkm_ior *, int pattern); void (*drive)(struct nvkm_ior *, int ln, int pc, int dc, int pe, int tx_pu); + void (*vcpi)(struct nvkm_ior *, int head, u8 slot, + u8 slot_nr, u16 pbn, u16 aligned); void (*audio)(struct nvkm_ior *, int head, bool enable); } dp; @@ -102,6 +104,7 @@ void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void gf119_sor_dp_pattern(struct nvkm_ior *, int); void gf119_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); +void gf119_sor_dp_vcpi(struct nvkm_ior *, int, u8, u8, u16, u16); void gf119_sor_dp_audio(struct nvkm_ior *, int, bool); void gm107_sor_dp_pattern(struct nvkm_ior *, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index d6371110f5a0..f3ebdd032b9b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -217,7 +217,6 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_SOR_DP_MST_VCPI: { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); union { struct nv50_disp_sor_dp_mst_vcpi_v0 v0; } *args = data; @@ -229,11 +228,13 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) args->v0.version, args->v0.start_slot, args->v0.num_slots, args->v0.pbn, args->v0.aligned_pbn); - if (!outpdp->func->vcpi) + if (!outp->ior->func->dp.vcpi) return -ENODEV; - outpdp->func->vcpi(outpdp, hidx, args->v0.start_slot, - args->v0.num_slots, args->v0.pbn, - args->v0.aligned_pbn); + outp->ior->func->dp.vcpi(outp->ior, hidx, + args->v0.start_slot, + args->v0.num_slots, + args->v0.pbn, + args->v0.aligned_pbn); return 0; } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index c3dbfd26ace8..b313beda00d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -41,10 +41,10 @@ gf119_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable) } void -gf119_sor_dp_vcpi(struct nvkm_output_dp *outp, int head, u8 slot, - u8 slot_nr, u16 pbn, u16 aligned) +gf119_sor_dp_vcpi(struct nvkm_ior *sor, int head, + u8 slot, u8 slot_nr, u16 pbn, u16 aligned) { - struct nvkm_device *device = outp->base.disp->engine.subdev.device; + struct nvkm_device *device = sor->disp->engine.subdev.device; const u32 hoff = head * 0x800; nvkm_mask(device, 0x616588 + hoff, 0x00003f3f, (slot_nr << 8) | slot); @@ -102,7 +102,6 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) static const struct nvkm_output_dp_func gf119_sor_dp_func = { - .vcpi = gf119_sor_dp_vcpi, }; int @@ -147,6 +146,7 @@ gf119_sor = { .links = gf119_sor_dp_links, .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, + .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, }, .hda = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index ee6bf54077a2..24fc026cd18d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -34,6 +34,7 @@ gk104_sor = { .power = g94_sor_dp_power, .pattern = gf119_sor_dp_pattern, .drive = gf119_sor_dp_drive, + .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, }, .hda = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index a6710758d7ed..77873874e178 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -38,7 +38,6 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) static const struct nvkm_output_dp_func gm107_sor_dp_func = { - .vcpi = gf119_sor_dp_vcpi, }; int @@ -61,6 +60,7 @@ gm107_sor = { .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, .drive = gf119_sor_dp_drive, + .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, }, .hda = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 3b152e116b88..9078ba271a12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -48,7 +48,6 @@ gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) static const struct nvkm_output_dp_func gm200_sor_dp_func = { - .vcpi = gf119_sor_dp_vcpi, }; int @@ -83,6 +82,7 @@ gm200_sor = { .power = g94_sor_dp_power, .pattern = gm107_sor_dp_pattern, .drive = gm200_sor_dp_drive, + .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, }, .hda = { From 3c66c87dc96b3113b5ee84604800c2aabbb48994 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 53/73] drm/nouveau/disp: remove hw-specific customisation of output paths All of the necessary hw-specific logic is now handled at the output resource level, so all of this can go away. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 54 ++++++--------- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 13 ---- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 10 ++- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 23 +------ .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 5 -- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 6 -- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 3 - .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 5 -- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 6 -- .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c | 6 -- .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c | 6 -- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 68 ------------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 18 ----- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 11 +-- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 12 +--- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 31 --------- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 18 ----- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 11 --- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 12 ---- .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 12 ---- .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 12 ---- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 13 ---- 28 files changed, 36 insertions(+), 342 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 24d2f325cbc5..c7c84d34d97e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -23,6 +23,7 @@ */ #include "priv.h" #include "conn.h" +#include "dp.h" #include "head.h" #include "ior.h" #include "outp.h" @@ -252,7 +253,8 @@ static int nvkm_disp_oneinit(struct nvkm_engine *engine) { struct nvkm_disp *disp = nvkm_disp(engine); - struct nvkm_bios *bios = disp->engine.subdev.device->bios; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_outp *outp, *outt, *pair; struct nvkm_conn *conn; struct nvkm_head *head; @@ -265,52 +267,38 @@ nvkm_disp_oneinit(struct nvkm_engine *engine) /* Create output path objects for each VBIOS display path. */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { - const struct nvkm_disp_func_outp *outps; - int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_outp **); - if (dcbE.type == DCB_OUTPUT_UNUSED) continue; if (dcbE.type == DCB_OUTPUT_EOL) break; outp = NULL; - switch (dcbE.location) { - case 0: outps = &disp->func->outp.internal; break; - case 1: outps = &disp->func->outp.external; break; - default: - nvkm_warn(&disp->engine.subdev, - "dcb %d locn %d unknown\n", i, dcbE.location); - continue; - } - switch (dcbE.type) { - case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; - case DCB_OUTPUT_TV : ctor = outps->tv ; break; - case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; - case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; - case DCB_OUTPUT_DP : ctor = outps->dp ; break; + case DCB_OUTPUT_ANALOG: + case DCB_OUTPUT_TV: + case DCB_OUTPUT_TMDS: + case DCB_OUTPUT_LVDS: + ret = nvkm_outp_new(disp, i, &dcbE, &outp); + break; + case DCB_OUTPUT_DP: + ret = nvkm_dp_new(disp, i, &dcbE, &outp); + break; default: - nvkm_warn(&disp->engine.subdev, - "dcb %d type %d unknown\n", i, dcbE.type); + nvkm_warn(subdev, "dcb %d type %d unknown\n", + i, dcbE.type); continue; } - if (ctor) - ret = ctor(disp, i, &dcbE, &outp); - else - ret = -ENODEV; - if (ret) { - if (ret == -ENODEV) { - nvkm_debug(&disp->engine.subdev, - "dcb %d %d/%d not supported\n", - i, dcbE.location, dcbE.type); + if (outp) { + if (ret != -ENODEV) + OUTP_ERR(outp, "ctor failed: %d", ret); + else + OUTP_DBG(outp, "not supported"); + nvkm_outp_del(&outp); continue; } - nvkm_error(&disp->engine.subdev, - "failed to create outp %d\n", i); - nvkm_outp_del(&outp); + nvkm_error(subdev, "failed to create outp %d\n", i); continue; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 0e51e144c1bd..64de64fdc9d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -22,22 +22,9 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "outp.h" #include -static const struct nvkm_output_func -nv50_dac_output_func = { -}; - -int -nv50_dac_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_new_(&nv50_dac_output_func, disp, - index, dcbE, poutp); -} - int nv50_dac_sense(struct nvkm_ior *dac, u32 loadval) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 2d8f93323309..b531890b1a6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -580,7 +580,7 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, dp->aux = aux; if (!dp->aux) { OUTP_ERR(&dp->outp, "no aux"); - return -ENODEV; + return -EINVAL; } /* bios data is not optional */ @@ -589,7 +589,7 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, &hdr, &cnt, &len, &dp->info); if (!data) { OUTP_ERR(&dp->outp, "no bios dp data"); - return -ENODEV; + return -EINVAL; } OUTP_DBG(&dp->outp, "bios dp %02x %02x %02x %02x", @@ -616,9 +616,8 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, } int -nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_outp **poutp) +nvkm_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_outp **poutp) { struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; struct nvkm_i2c_aux *aux; @@ -631,7 +630,6 @@ nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, if (!(dp = kzalloc(sizeof(*dp), GFP_KERNEL))) return -ENOMEM; - dp->func = func; *poutp = &dp->outp; return nvkm_dp_ctor(disp, index, dcbE, aux, dp); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index edd416c62d3e..34e58b70a394 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -8,7 +8,6 @@ #include struct nvkm_dp { - const struct nvkm_output_dp_func *func; union { struct nvkm_outp base; struct nvkm_outp outp; @@ -32,28 +31,10 @@ struct nvkm_dp { #define nvkm_output_dp nvkm_dp -struct nvkm_output_dp_func { -}; - int nvkm_output_dp_train(struct nvkm_output *, u32 rate); -int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_output **); - -int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - -int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - -int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - -int gm107_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - -int gm200_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); +int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_outp **); /* DPCD Receiver Capabilities */ #define DPCD_RC00_DPCD_REV 0x00000 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 50fbe1cb6653..842e1b72ee42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -33,11 +33,6 @@ g84_disp = { .super = nv50_disp_super, .root = &g84_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 2, .new = g84_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 8cc2a8c03fc6..d184e6ab8918 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -33,12 +33,6 @@ g94_disp = { .super = nv50_disp_super, .root = &g94_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = g94_sor_dp_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 4, .new = g94_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index bb816f78230f..c0d730af4c97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -502,10 +502,6 @@ gf119_disp = { .super = gf119_disp_super, .root = &gf119_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, .sor = { .nr = 4, .new = gf119_sor_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index e45cc01aed1c..e8fe9f315d64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -34,10 +34,6 @@ gk104_disp = { .super = gf119_disp_super, .root = &gk104_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, .sor = { .nr = 4, .new = gk104_sor_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index e0990ffd3f57..769687502e7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -34,10 +34,6 @@ gk110_disp = { .super = gf119_disp_super, .root = &gk110_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gf119_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, .sor = { .nr = 4, .new = gk104_sor_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index e42ab42b9dd1..ede70e5d188e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -34,10 +34,6 @@ gm107_disp = { .super = gf119_disp_super, .root = &gm107_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gm107_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, .sor = { .nr = 4, .new = gm107_sor_new }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index 287c00159481..ae0b97332e46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -34,10 +34,6 @@ gm200_disp = { .super = gf119_disp_super, .root = &gm200_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gm200_sor_dp_new, .dac = { .nr = 3, .new = gf119_dac_new }, .sor.nr = 4, .sor.new = gm200_sor_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index c83883c0bd43..c6fe7797a803 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -34,9 +34,6 @@ gp100_disp = { .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, .sor.magic = gm200_sor_magic, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index bac4d05a0015..279d125fe265 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -60,9 +60,6 @@ gp102_disp = { .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.new = gf119_head_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = gm200_sor_dp_new, .sor.nr = 4, .sor.new = gm200_sor_new, .sor.magic = gm200_sor_magic, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 387f57bc517b..bf00c4e3be3a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -33,11 +33,6 @@ gt200_disp = { .super = nv50_disp_super, .root = >200_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 2, .new = g84_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 0c761feca2d4..2cdd4d7a98d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -33,12 +33,6 @@ gt215_disp = { .super = nv50_disp_super, .root = >215_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = g94_sor_dp_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 4, .new = gt215_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c index 4f4e4e68de33..d7e0fbb12bf1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c @@ -31,12 +31,6 @@ mcp77_disp = { .super = nv50_disp_super, .root = &g94_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = g94_sor_dp_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 4, .new = mcp77_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c index 80e0f523f071..7b75c57c12ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c @@ -31,12 +31,6 @@ mcp89_disp = { .super = nv50_disp_super, .root = >215_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.internal.dp = g94_sor_dp_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 4, .new = mcp89_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index ae570f65e097..b7365b56ed19 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -42,63 +42,6 @@ nv50_disp_root_(struct nvkm_disp *base) return nv50_disp(base)->func->root; } -static int -nv50_disp_outp_internal_crt_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - return disp->func->outp.internal.crt(base, index, dcb, poutp); -} - -static int -nv50_disp_outp_internal_tmds_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, - struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - return disp->func->outp.internal.tmds(base, index, dcb, poutp); -} - -static int -nv50_disp_outp_internal_lvds_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, - struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - return disp->func->outp.internal.lvds(base, index, dcb, poutp); -} - -static int -nv50_disp_outp_internal_dp_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - if (disp->func->outp.internal.dp) - return disp->func->outp.internal.dp(base, index, dcb, poutp); - return -ENODEV; -} - -static int -nv50_disp_outp_external_tmds_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, - struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - if (disp->func->outp.external.tmds) - return disp->func->outp.external.tmds(base, index, dcb, poutp); - return -ENODEV; -} - -static int -nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index, - struct dcb_output *dcb, struct nvkm_output **poutp) -{ - struct nv50_disp *disp = nv50_disp(base); - if (disp->func->outp.external.dp) - return disp->func->outp.external.dp(base, index, dcb, poutp); - return -ENODEV; -} - static void nv50_disp_intr_(struct nvkm_disp *base) { @@ -121,12 +64,6 @@ nv50_disp_ = { .dtor = nv50_disp_dtor_, .intr = nv50_disp_intr_, .root = nv50_disp_root_, - .outp.internal.crt = nv50_disp_outp_internal_crt_, - .outp.internal.tmds = nv50_disp_outp_internal_tmds_, - .outp.internal.lvds = nv50_disp_outp_internal_lvds_, - .outp.internal.dp = nv50_disp_outp_internal_dp_, - .outp.external.tmds = nv50_disp_outp_external_tmds_, - .outp.external.dp = nv50_disp_outp_external_dp_, }; int @@ -839,11 +776,6 @@ nv50_disp = { .super = nv50_disp_super, .root = &nv50_disp_root_oclass, .head.new = nv50_head_new, - .outp.internal.crt = nv50_dac_output_new, - .outp.internal.tmds = nv50_sor_output_new, - .outp.internal.lvds = nv50_sor_output_new, - .outp.external.tmds = nv50_pior_output_new, - .outp.external.dp = nv50_pior_dp_new, .dac = { .nr = 3, .new = nv50_dac_new }, .sor = { .nr = 2, .new = nv50_sor_new }, .pior = { .nr = 3, .new = nv50_pior_new }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index d00ce1da1637..f87422de12b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -32,19 +32,6 @@ int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, struct nvkm_disp **); -struct nv50_disp_func_outp { - int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); -}; - struct nv50_disp_func { void (*intr)(struct nv50_disp *); void (*intr_error)(struct nv50_disp *, int chid); @@ -58,11 +45,6 @@ struct nv50_disp_func { int (*new)(struct nvkm_disp *, int id); } head; - struct { - const struct nv50_disp_func_outp internal; - const struct nv50_disp_func_outp external; - } outp; - struct { int nr; int (*new)(struct nvkm_disp *, int id); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 895a84ca1501..09e8ebbd4ee9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -142,12 +142,15 @@ nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp, return 0; } +static const struct nvkm_outp_func +nvkm_outp = { +}; + int -nvkm_outp_new_(const struct nvkm_outp_func *func, - struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_outp **poutp) +nvkm_outp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_outp **poutp) { if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) return -ENOMEM; - return nvkm_outp_ctor(func, disp, index, dcbE, *poutp); + return nvkm_outp_ctor(&nvkm_outp, disp, index, dcbE, *poutp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 80d4a0d34f14..785a920eaf74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -23,6 +23,8 @@ struct nvkm_outp { int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_outp *); +int nvkm_outp_new(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_outp **); void nvkm_outp_del(struct nvkm_outp **); void nvkm_outp_init(struct nvkm_outp *); void nvkm_outp_fini(struct nvkm_outp *); @@ -37,16 +39,6 @@ struct nvkm_outp_func { #define nvkm_output_func nvkm_outp_func #define nvkm_output_new_ nvkm_outp_new_ -int nvkm_outp_new_(const struct nvkm_outp_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_output **); - -int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); - void gm200_sor_magic(struct nvkm_output *outp); #define OUTP_MSG(o,l,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index a3c4386a5a90..f66beda1ae11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -22,29 +22,10 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "dp.h" #include #include -/****************************************************************************** - * TMDS - *****************************************************************************/ -static const struct nvkm_output_func -nv50_pior_output_func = { -}; - -int -nv50_pior_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_new_(&nv50_pior_output_func, disp, - index, dcbE, poutp); -} - -/****************************************************************************** - * DisplayPort - *****************************************************************************/ static int nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) { @@ -55,18 +36,6 @@ nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) return 1; } -static const struct nvkm_output_dp_func -nv50_pior_output_dp_func = { -}; - -int -nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) -{ - return nvkm_output_dp_new_(&nv50_pior_output_dp_func, disp, - index, dcbE, poutp); -} - static void nv50_pior_power_wait(struct nvkm_device *device, u32 poff) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index e8dcae14a9ae..5772f0094129 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -9,29 +9,11 @@ int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, int index, struct nvkm_disp **); void nvkm_disp_vblank(struct nvkm_disp *, int head); -struct nvkm_disp_func_outp { - int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); - int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, - struct nvkm_output **); -}; - struct nvkm_disp_func { void *(*dtor)(struct nvkm_disp *); void (*intr)(struct nvkm_disp *); const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); - - struct { - const struct nvkm_disp_func_outp internal; - const struct nvkm_disp_func_outp external; - } outp; }; int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index a4a4749d3c4b..bfc7b0e053a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -91,17 +91,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) return 0; } -static const struct nvkm_output_dp_func -g94_sor_dp_func = { -}; - -int -g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) -{ - return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); -} - static bool nv50_disp_dptmds_war(struct nvkm_device *device) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index b313beda00d7..d37cd037ee03 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" #include @@ -100,17 +99,6 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) return 0; } -static const struct nvkm_output_dp_func -gf119_sor_dp_func = { -}; - -int -gf119_sor_dp_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); -} - void gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index 77873874e178..e467f8eaf2ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" void gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) @@ -36,17 +35,6 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); } -static const struct nvkm_output_dp_func -gm107_sor_dp_func = { -}; - -int -gm107_sor_dp_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_dp_new_(&gm107_sor_dp_func, disp, index, dcbE, poutp); -} - static const struct nvkm_ior_func gm107_sor = { .state = gf119_sor_state, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 9078ba271a12..0ba7d03efa78 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" static void gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) @@ -46,17 +45,6 @@ gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift)); } -static const struct nvkm_output_dp_func -gm200_sor_dp_func = { -}; - -int -gm200_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, - struct nvkm_output **poutp) -{ - return nvkm_output_dp_new_(&gm200_sor_dp_func, disp, index, dcbE, poutp); -} - void gm200_sor_magic(struct nvkm_output *outp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 543b6d0ee74c..2ca600c744cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -22,22 +22,9 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "outp.h" #include -static const struct nvkm_output_func -nv50_sor_output_func = { -}; - -int -nv50_sor_output_new(struct nvkm_disp *disp, int index, - struct dcb_output *dcbE, struct nvkm_output **poutp) -{ - return nvkm_output_new_(&nv50_sor_output_func, disp, - index, dcbE, poutp); -} - static void nv50_sor_power_wait(struct nvkm_device *device, u32 soff) { From 6c22ea3747fd36409ce4a1e1a0cbac40f93e1e71 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 54/73] drm/nouveau/disp: introduce acquire/release display path methods These exist to give NVKM information on the set of display paths that the DD needs to be active at any given time. Previously, the supervisor attempted to determine this solely from OR state, but there's a few configurations where this information on its own isn't enough to determine the specific display paths in question: - ANX9805, where the PIOR protocol for both DP and TMDS is TMDS. - On a device using DCB Switched Outputs. - On GM20x and newer, with a crossbar between the SOR and macro links. After this commit, the DD tells NVKM *exactly* which display path it's attempting a modeset on. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/cl5070.h | 9 ++ drivers/gpu/drm/nouveau/nouveau_bios.c | 3 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 1 + drivers/gpu/drm/nouveau/nv50_display.c | 75 +++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 5 - .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 6 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 131 +++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 8 +- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 22 +++ .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 49 ++++++- 16 files changed, 287 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h index e3f5659295e2..542d95145a67 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl5070.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl5070.h @@ -27,6 +27,8 @@ struct nv50_disp_scanoutpos_v0 { struct nv50_disp_mthd_v1 { __u8 version; +#define NV50_DISP_MTHD_V1_ACQUIRE 0x01 +#define NV50_DISP_MTHD_V1_RELEASE 0x02 #define NV50_DISP_MTHD_V1_DAC_LOAD 0x11 #define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21 #define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22 @@ -39,6 +41,13 @@ struct nv50_disp_mthd_v1 { __u8 pad06[2]; }; +struct nv50_disp_acquire_v0 { + __u8 version; + __u8 or; + __u8 link; + __u8 pad03[5]; +}; + struct nv50_disp_dac_load_v0 { __u8 version; __u8 load; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 9a0772ad495a..b998c33af18a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1533,7 +1533,8 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, if (conf & 0x100000) entry->i2c_upper_default = true; - entry->hasht = (entry->location << 4) | entry->type; + entry->hasht = (entry->extdev << 8) | (entry->location << 4) | + entry->type; entry->hashm = (entry->heads << 8) | (link << 6) | entry->or; return true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index 198e5f27682f..e28d966946a1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -42,6 +42,7 @@ struct nouveau_encoder { struct dcb_output *dcb; int or; + int link; struct i2c_adapter *i2c; struct nvkm_i2c_aux *aux; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index e6cc1d843c92..e3132a2ce34d 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2403,6 +2403,51 @@ out: /****************************************************************************** * Output path helpers *****************************************************************************/ +static void +nv50_outp_release(struct nouveau_encoder *nv_encoder) +{ + struct nv50_disp *disp = nv50_disp(nv_encoder->base.base.dev); + struct { + struct nv50_disp_mthd_v1 base; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_RELEASE, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = nv_encoder->dcb->hashm, + }; + + nvif_mthd(disp->disp, 0, &args, sizeof(args)); + nv_encoder->or = -1; + nv_encoder->link = 0; +} + +static int +nv50_outp_acquire(struct nouveau_encoder *nv_encoder) +{ + struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); + struct nv50_disp *disp = nv50_disp(drm->dev); + struct { + struct nv50_disp_mthd_v1 base; + struct nv50_disp_acquire_v0 info; + } args = { + .base.version = 1, + .base.method = NV50_DISP_MTHD_V1_ACQUIRE, + .base.hasht = nv_encoder->dcb->hasht, + .base.hashm = nv_encoder->dcb->hashm, + }; + int ret; + + ret = nvif_mthd(disp->disp, 0, &args, sizeof(args)); + if (ret) { + NV_ERROR(drm, "error acquiring output path: %d\n", ret); + return ret; + } + + nv_encoder->or = args.info.or; + nv_encoder->link = args.info.link; + return 0; +} + static int nv50_outp_atomic_check_view(struct drm_encoder *encoder, struct drm_crtc_state *crtc_state, @@ -2482,6 +2527,7 @@ nv50_dac_disable(struct drm_encoder *encoder) } nv_encoder->crtc = NULL; + nv50_outp_release(nv_encoder); } static void @@ -2493,6 +2539,8 @@ nv50_dac_enable(struct drm_encoder *encoder) struct drm_display_mode *mode = &nv_crtc->base.state->adjusted_mode; u32 *push; + nv50_outp_acquire(nv_encoder); + push = evo_wait(mast, 8); if (push) { if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { @@ -2592,7 +2640,6 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) if (!nv_encoder) return -ENOMEM; nv_encoder->dcb = dcbe; - nv_encoder->or = ffs(dcbe->or) - 1; bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); if (bus) @@ -2759,6 +2806,8 @@ struct nv50_mstm { struct nv50_msto *msto[4]; bool modified; + bool disabled; + int links; }; struct nv50_mstc { @@ -2907,7 +2956,10 @@ nv50_msto_enable(struct drm_encoder *encoder) r = drm_dp_mst_allocate_vcpi(&mstm->mgr, mstc->port, mstc->pbn, slots); WARN_ON(!r); - if (mstm->outp->dcb->sorconf.link & 1) + if (!mstm->links++) + nv50_outp_acquire(mstm->outp); + + if (mstm->outp->link & 1) proto = 0x8; else proto = 0x9; @@ -2939,6 +2991,8 @@ nv50_msto_disable(struct drm_encoder *encoder) mstm->outp->update(mstm->outp, msto->head->base.index, NULL, 0, 0); mstm->modified = true; + if (!--mstm->links) + mstm->disabled = true; msto->disabled = true; } @@ -3154,6 +3208,12 @@ nv50_mstm_prepare(struct nv50_mstm *mstm) nv50_msto_prepare(msto); } } + + if (mstm->disabled) { + if (!mstm->links) + nv50_outp_release(mstm->outp); + mstm->disabled = false; + } } static void @@ -3452,6 +3512,7 @@ nv50_sor_disable(struct drm_encoder *encoder) nv_encoder->update(nv_encoder, nv_crtc->index, NULL, 0, 0); nv50_audio_disable(encoder, nv_crtc); nv50_hdmi_disable(&nv_encoder->base.base, nv_crtc); + nv50_outp_release(nv_encoder); } } @@ -3480,10 +3541,11 @@ nv50_sor_enable(struct drm_encoder *encoder) nv_connector = nouveau_encoder_connector_get(nv_encoder); nv_encoder->crtc = encoder->crtc; + nv50_outp_acquire(nv_encoder); switch (nv_encoder->dcb->type) { case DCB_OUTPUT_TMDS: - if (nv_encoder->dcb->sorconf.link & 1) { + if (nv_encoder->link & 1) { proto = 0x1; /* Only enable dual-link if: * - Need to (i.e. rate > 165MHz) @@ -3541,7 +3603,7 @@ nv50_sor_enable(struct drm_encoder *encoder) else depth = 0x6; - if (nv_encoder->dcb->sorconf.link & 1) + if (nv_encoder->link & 1) proto = 0x8; else proto = 0x9; @@ -3600,7 +3662,6 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) if (!nv_encoder) return -ENOMEM; nv_encoder->dcb = dcbe; - nv_encoder->or = ffs(dcbe->or) - 1; nv_encoder->update = nv50_sor_update; encoder = to_drm_encoder(nv_encoder); @@ -3673,6 +3734,7 @@ nv50_pior_disable(struct drm_encoder *encoder) } nv_encoder->crtc = NULL; + nv50_outp_release(nv_encoder); } static void @@ -3687,6 +3749,8 @@ nv50_pior_enable(struct drm_encoder *encoder) u8 proto, depth; u32 *push; + nv50_outp_acquire(nv_encoder); + nv_connector = nouveau_encoder_connector_get(nv_encoder); switch (nv_connector->base.display_info.bpc) { case 10: depth = 0x6; break; @@ -3774,7 +3838,6 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) if (!nv_encoder) return -ENOMEM; nv_encoder->dcb = dcbe; - nv_encoder->or = ffs(dcbe->or) - 1; nv_encoder->i2c = ddc; nv_encoder->aux = aux; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index b531890b1a6f..0f1c223cc7a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -24,7 +24,6 @@ #include "dp.h" #include "conn.h" #include "ior.h" -#include "nv50.h" #include #include @@ -351,7 +350,6 @@ static const struct dp_rates { static int nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) { - struct nv50_disp *disp = nv50_disp(dp->outp.disp); struct nvkm_ior *ior = dp->outp.ior; const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; @@ -361,9 +359,6 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) int ret = -EINVAL; u8 pwr; - if (!dp->outp.info.location && disp->func->sor.magic) - disp->func->sor.magic(&dp->outp); - /* Find the lowest configuration of the OR that can support * the required link rate. * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index c0d730af4c97..7a8dff7b8c95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -306,9 +306,6 @@ gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) if (nvkm_output_dp_train(outp, pclk)) OUTP_ERR(outp, "link not trained before attach"); - } else { - if (disp->func->sor.magic) - disp->func->sor.magic(outp); } exec_clkcmp(disp, head, 0, pclk, &conf); @@ -377,6 +374,7 @@ gf119_disp_super(struct work_struct *work) nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); gf119_disp_intr_unk2_0(disp, head->id); } + nvkm_outp_route(&disp->base); list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00010000)) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c index ae0b97332e46..292d3b5f9704 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c @@ -35,9 +35,7 @@ gm200_disp = { .root = &gm200_disp_root_oclass, .head.new = gf119_head_new, .dac = { .nr = 3, .new = gf119_dac_new }, - .sor.nr = 4, - .sor.new = gm200_sor_new, - .sor.magic = gm200_sor_magic, + .sor = { .nr = 4, .new = gm200_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c index c6fe7797a803..39eb98b2c3a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c @@ -34,9 +34,7 @@ gp100_disp = { .super = gf119_disp_super, .root = &gp100_disp_root_oclass, .head.new = gf119_head_new, - .sor.nr = 4, - .sor.new = gm200_sor_new, - .sor.magic = gm200_sor_magic, + .sor = { .nr = 4, .new = gm200_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c index 279d125fe265..91d70fe18275 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c @@ -60,9 +60,7 @@ gp102_disp = { .super = gf119_disp_super, .root = &gp102_disp_root_oclass, .head.new = gf119_head_new, - .sor.nr = 4, - .sor.new = gm200_sor_new, - .sor.magic = gm200_sor_magic, + .sor = { .nr = 4, .new = gm200_sor_new }, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index a43a924debfe..a2e38d4780b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -17,6 +17,7 @@ struct nvkm_ior { struct list_head head; struct nvkm_ior_state { + struct nvkm_outp *outp; unsigned rgdiv; unsigned proto_evo:4; enum nvkm_ior_proto { @@ -40,6 +41,11 @@ struct nvkm_ior { }; struct nvkm_ior_func { + struct { + int (*get)(struct nvkm_outp *, int *link); + void (*set)(struct nvkm_outp *, struct nvkm_ior *); + } route; + void (*state)(struct nvkm_ior *, struct nvkm_ior_state *); void (*power)(struct nvkm_ior *, bool normal, bool pu, bool data, bool vsync, bool hsync); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index b7365b56ed19..58d46cefe7b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -661,6 +661,7 @@ nv50_disp_super(struct work_struct *work) continue; nv50_disp_intr_unk20_0(disp, head->id); } + nvkm_outp_route(&disp->base); list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000200 << head->id))) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index f87422de12b3..65d445687038 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -53,7 +53,6 @@ struct nv50_disp_func { struct { int nr; int (*new)(struct nvkm_disp *, int id); - void (*magic)(struct nvkm_output *); } sor; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 09e8ebbd4ee9..ef201f1597c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -28,8 +28,35 @@ #include #include +void +nvkm_outp_route(struct nvkm_disp *disp) +{ + struct nvkm_outp *outp; + struct nvkm_ior *ior; + + list_for_each_entry(ior, &disp->ior, head) { + if ((outp = ior->arm.outp) && ior->arm.outp != ior->asy.outp) { + OUTP_DBG(outp, "release %s", ior->name); + if (ior->func->route.set) + ior->func->route.set(outp, NULL); + ior->arm.outp = NULL; + } + } + + list_for_each_entry(ior, &disp->ior, head) { + if ((outp = ior->asy.outp)) { + OUTP_DBG(outp, "acquire %s", ior->name); + if (ior->asy.outp != ior->arm.outp) { + if (ior->func->route.set) + ior->func->route.set(outp, ior); + ior->arm.outp = ior->asy.outp; + } + } + } +} + static enum nvkm_ior_proto -nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type) +nvkm_outp_xlat(struct nvkm_outp *outp, enum nvkm_ior_type *type) { switch (outp->info.location) { case 0: @@ -57,6 +84,75 @@ nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type) return UNKNOWN; } +void +nvkm_outp_release(struct nvkm_outp *outp, u8 user) +{ + struct nvkm_ior *ior = outp->ior; + OUTP_TRACE(outp, "release %02x &= %02x %p", outp->acquired, ~user, ior); + if (ior) { + outp->acquired &= ~user; + if (!outp->acquired) { + outp->ior->asy.outp = NULL; + outp->ior = NULL; + } + } +} + +static inline int +nvkm_outp_acquire_ior(struct nvkm_outp *outp, u8 user, struct nvkm_ior *ior) +{ + outp->ior = ior; + outp->ior->asy.outp = outp; + outp->ior->asy.link = outp->info.sorconf.link; + outp->acquired |= user; + return 0; +} + +int +nvkm_outp_acquire(struct nvkm_outp *outp, u8 user) +{ + struct nvkm_ior *ior = outp->ior; + enum nvkm_ior_proto proto; + enum nvkm_ior_type type; + + OUTP_TRACE(outp, "acquire %02x |= %02x %p", outp->acquired, user, ior); + if (ior) { + outp->acquired |= user; + return 0; + } + + /* Lookup a compatible, and unused, OR to assign to the device. */ + proto = nvkm_outp_xlat(outp, &type); + if (proto == UNKNOWN) + return -ENOSYS; + + /* First preference is to reuse the OR that is currently armed + * on HW, if any, in order to prevent unnecessary switching. + */ + list_for_each_entry(ior, &outp->disp->ior, head) { + if (!ior->asy.outp && ior->arm.outp == outp) + return nvkm_outp_acquire_ior(outp, user, ior); + } + + /* Failing that, a completely unused OR is the next best thing. */ + list_for_each_entry(ior, &outp->disp->ior, head) { + if (!ior->asy.outp && ior->type == type && !ior->arm.outp && + ior->id == __ffs(outp->info.or)) + return nvkm_outp_acquire_ior(outp, user, ior); + } + + /* Last resort is to assign an OR that's already active on HW, + * but will be released during the next modeset. + */ + list_for_each_entry(ior, &outp->disp->ior, head) { + if (!ior->asy.outp && ior->type == type && + ior->id == __ffs(outp->info.or)) + return nvkm_outp_acquire_ior(outp, user, ior); + } + + return -ENOSPC; +} + void nvkm_outp_fini(struct nvkm_outp *outp) { @@ -65,22 +161,36 @@ nvkm_outp_fini(struct nvkm_outp *outp) } static void -nvkm_outp_init_route(struct nvkm_output *outp) +nvkm_outp_init_route(struct nvkm_outp *outp) { struct nvkm_disp *disp = outp->disp; enum nvkm_ior_proto proto; enum nvkm_ior_type type; struct nvkm_ior *ior; - int id; + int id, link; + /* Find any OR from the class that is able to support this device. */ proto = nvkm_outp_xlat(outp, &type); if (proto == UNKNOWN) return; + ior = nvkm_ior_find(disp, type, -1); + if (!ior) { + WARN_ON(1); + return; + } + /* Determine the specific OR, if any, this device is attached to. */ - if (1) { + if (ior->func->route.get) { + id = ior->func->route.get(outp, &link); + if (id < 0) { + OUTP_DBG(outp, "no route"); + return; + } + } else { /* Prior to DCB 4.1, this is hardwired like so. */ - id = ffs(outp->info.or) - 1; + id = ffs(outp->info.or) - 1; + link = (ior->type == SOR) ? outp->info.sorconf.link : 0; } ior = nvkm_ior_find(disp, type, id); @@ -89,7 +199,16 @@ nvkm_outp_init_route(struct nvkm_output *outp) return; } - outp->ior = ior; + /* Determine if the OR is already configured for this device. */ + ior->func->state(ior, &ior->arm); + if (!ior->arm.head || ior->arm.proto != proto) { + OUTP_DBG(outp, "no heads (%x %d %d)", ior->arm.head, + ior->arm.proto, proto); + return; + } + + OUTP_DBG(outp, "on %s link %x", ior->name, ior->arm.link); + ior->arm.outp = outp; } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 785a920eaf74..106141eb3e32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -18,6 +18,9 @@ struct nvkm_outp { struct nvkm_conn *conn; /* Assembly state. */ +#define NVKM_OUTP_PRIV 1 +#define NVKM_OUTP_USER 2 + u8 acquired:2; struct nvkm_ior *ior; }; @@ -28,6 +31,9 @@ int nvkm_outp_new(struct nvkm_disp *, int index, struct dcb_output *, void nvkm_outp_del(struct nvkm_outp **); void nvkm_outp_init(struct nvkm_outp *); void nvkm_outp_fini(struct nvkm_outp *); +int nvkm_outp_acquire(struct nvkm_outp *, u8 user); +void nvkm_outp_release(struct nvkm_outp *, u8 user); +void nvkm_outp_route(struct nvkm_disp *); struct nvkm_outp_func { void *(*dtor)(struct nvkm_outp *); @@ -39,8 +45,6 @@ struct nvkm_outp_func { #define nvkm_output_func nvkm_outp_func #define nvkm_output_new_ nvkm_outp_new_ -void gm200_sor_magic(struct nvkm_output *outp); - #define OUTP_MSG(o,l,f,a...) do { \ struct nvkm_outp *_outp = (o); \ nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index f3ebdd032b9b..4c7b7090b1a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -94,6 +94,24 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } switch (mthd * !!outp) { + case NV50_DISP_MTHD_V1_ACQUIRE: { + union { + struct nv50_disp_acquire_v0 v0; + } *args = data; + int ret = -ENOSYS; + if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { + ret = nvkm_outp_acquire(outp, NVKM_OUTP_USER); + if (ret == 0) { + args->v0.or = outp->ior->id; + args->v0.link = outp->ior->asy.link; + } + } + return ret; + } + break; + case NV50_DISP_MTHD_V1_RELEASE: + nvkm_outp_release(outp, NVKM_OUTP_USER); + return 0; case NV50_DISP_MTHD_V1_DAC_LOAD: { union { struct nv50_disp_dac_load_v0 v0; @@ -102,7 +120,11 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { if (args->v0.data & 0xfff00000) return -EINVAL; + ret = nvkm_outp_acquire(outp, NVKM_OUTP_PRIV); + if (ret) + return ret; ret = outp->ior->func->sense(outp->ior, args->v0.data); + nvkm_outp_release(outp, NVKM_OUTP_PRIV); if (ret < 0) return ret; args->v0.load = ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 0ba7d03efa78..25528a15516b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -45,20 +45,55 @@ gm200_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) nvkm_wr32(device, 0x61c13c + loff, data[3] | (pc << shift)); } -void -gm200_sor_magic(struct nvkm_output *outp) +static void +gm200_sor_route_set(struct nvkm_outp *outp, struct nvkm_ior *ior) { struct nvkm_device *device = outp->disp->engine.subdev.device; - const u32 soff = outp->or * 0x100; - const u32 data = outp->or + 1; - if (outp->info.sorconf.link & 1) - nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + const u32 moff = __ffs(outp->info.or) * 0x100; + const u32 sor = ior ? ior->id + 1 : 0; + u32 link = ior ? (ior->asy.link == 2) : 0; + + if (outp->info.sorconf.link & 1) { + nvkm_mask(device, 0x612308 + moff, 0x0000001f, link << 4 | sor); + link++; + } + if (outp->info.sorconf.link & 2) - nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); + nvkm_mask(device, 0x612388 + moff, 0x0000001f, link << 4 | sor); +} + +static int +gm200_sor_route_get(struct nvkm_outp *outp, int *link) +{ + struct nvkm_device *device = outp->disp->engine.subdev.device; + const int sublinks = outp->info.sorconf.link; + int lnk[2], sor[2], m, s; + + for (*link = 0, m = __ffs(outp->info.or) * 2, s = 0; s < 2; m++, s++) { + if (sublinks & BIT(s)) { + u32 data = nvkm_rd32(device, 0x612308 + (m * 0x80)); + lnk[s] = (data & 0x00000010) >> 4; + sor[s] = (data & 0x0000000f); + if (!sor[s]) + return -1; + *link |= lnk[s]; + } + } + + if (sublinks == 3) { + if (sor[0] != sor[1] || WARN_ON(lnk[0] || !lnk[1])) + return -1; + } + + return ((sublinks & 1) ? sor[0] : sor[1]) - 1; } static const struct nvkm_ior_func gm200_sor = { + .route = { + .get = gm200_sor_route_get, + .set = gm200_sor_route_set, + }, .state = gf119_sor_state, .power = nv50_sor_power, .hdmi = { From 9648da5a71c25e17d14feb0d7dc9ee73319e8a24 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 55/73] drm/nouveau/disp/dp: determine link bandwidth requirements from head state Training/Untraining will be hooked up to the routing logic, which doesn't allow us to pass in a data rate. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 14 ++++++++-- .../gpu/drm/nouveau/nvkm/engine/disp/head.h | 6 +++++ .../drm/nouveau/nvkm/engine/disp/headgf119.c | 13 +++++++++ .../drm/nouveau/nvkm/engine/disp/headnv50.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 ++ .../drm/nouveau/nvkm/engine/disp/piornv50.c | 27 +++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 1 + 7 files changed, 62 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 0f1c223cc7a8..4ad31302aaf4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -23,6 +23,7 @@ */ #include "dp.h" #include "conn.h" +#include "head.h" #include "ior.h" #include @@ -419,19 +420,28 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) } int -nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps) +nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) { struct nvkm_dp *dp = nvkm_dp(outp); struct nvkm_ior *ior = dp->outp.ior; + struct nvkm_head *head; bool retrain = true; - u32 linkKBps; + u32 datakbps = 0; u32 dataKBps; + u32 linkKBps; u8 stat[3]; int ret, i; mutex_lock(&dp->mutex); /* Check that link configuration meets current requirements. */ + list_for_each_entry(head, &outp->disp->head, head) { + if (ior->asy.head & (1 << head->id)) { + u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000; + datakbps += khz * head->asy.or.depth; + } + } + linkKBps = ior->dp.bw * 27000 * ior->dp.nr; dataKBps = DIV_ROUND_UP(datakbps, 8); OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index 94f5cb7596a0..829a0a8cfb2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -18,6 +18,12 @@ struct nvkm_head { u16 vsynce; u16 vblanke; u16 vblanks; + u32 hz; + + /* Prior to GF119, these are set by the OR. */ + struct { + u8 depth; + } or; } arm, asy; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index 8e7acc57d31d..d2bd6bb4a621 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -58,6 +58,19 @@ gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state) data = nvkm_rd32(device, 0x640420 + hoff); state->vblanks = (data & 0xffff0000) >> 16; state->hblanks = (data & 0x0000ffff); + state->hz = nvkm_rd32(device, 0x640450 + hoff); + + data = nvkm_rd32(device, 0x640404 + hoff); + switch ((data & 0x000003c0) >> 6) { + case 6: state->or.depth = 30; break; + case 5: state->or.depth = 24; break; + case 2: state->or.depth = 18; break; + case 0: state->or.depth = 18; break; /*XXX: "default" */ + default: + state->or.depth = 18; + WARN_ON(1); + break; + } } static const struct nvkm_head_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c index 3cccda2cb09e..d4a9879f0d0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -66,6 +66,7 @@ nv50_head_state(struct nvkm_head *head, struct nvkm_head_state *state) data = nvkm_rd32(device, 0x610b00 + hoff); state->vsynce = (data & 0xffff0000) >> 16; state->hsynce = (data & 0x0000ffff); + state->hz = (nvkm_rd32(device, 0x610ad0 + hoff) & 0x003fffff) * 1000; } static const struct nvkm_head_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index a2e38d4780b1..3a6e01f5a0e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -89,6 +89,8 @@ nv50_ior_base(struct nvkm_ior *ior) void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool); int nv50_dac_sense(struct nvkm_ior *, u32); +void nv50_pior_depth(struct nvkm_ior *, struct nvkm_ior_state *, u32 ctrl); + static inline u32 nv50_sor_link(struct nvkm_ior *ior) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index f66beda1ae11..dc59c319377e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "ior.h" +#include "head.h" #include #include @@ -60,6 +61,31 @@ nv50_pior_power(struct nvkm_ior *pior, bool normal, bool pu, nv50_pior_power_wait(device, poff); } +void +nv50_pior_depth(struct nvkm_ior *ior, struct nvkm_ior_state *state, u32 ctrl) +{ + /* GF119 moves this information to per-head methods, which is + * a lot more convenient, and where our shared code expect it. + */ + if (state->head && state == &ior->asy) { + struct nvkm_head *head = + nvkm_head_find(ior->disp, __ffs(state->head)); + if (!WARN_ON(!head)) { + struct nvkm_head_state *state = &head->asy; + switch ((ctrl & 0x000f0000) >> 16) { + case 6: state->or.depth = 30; break; + case 5: state->or.depth = 24; break; + case 2: state->or.depth = 18; break; + case 0: state->or.depth = 18; break; /*XXX*/ + default: + state->or.depth = 18; + WARN_ON(1); + break; + } + } + } +} + static void nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) { @@ -77,6 +103,7 @@ nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state) } state->head = ctrl & 0x00000003; + nv50_pior_depth(pior, state, ctrl); } static const struct nvkm_ior_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index bfc7b0e053a4..5abf563b0e84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -238,6 +238,7 @@ g94_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) } state->head = ctrl & 0x00000003; + nv50_pior_depth(sor, state, ctrl); } static const struct nvkm_ior_func From 32a232c5144d754674f05de3c452af324fe13cac Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 56/73] drm/nouveau/disp/dp: use new devinit script interpreter entry-point Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 68 ++++++++----------- 1 file changed, 30 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 4ad31302aaf4..da5aa4683d16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -222,14 +222,6 @@ nvkm_dp_train_links(struct nvkm_dp *dp) struct nvkm_disp *disp = dp->outp.disp; struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvkm_bios *bios = subdev->device->bios; - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = 0x0000, - .outp = &dp->outp.info, - .crtc = -1, - .execute = 1, - }; struct lt_state lt = { .dp = dp, }; @@ -250,14 +242,18 @@ nvkm_dp_train_links(struct nvkm_dp *dp) if (dp->version < 0x30) { while ((ior->dp.bw * 2700) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; - init.offset = nvbios_rd16(bios, lnkcmp + 2); + lnkcmp = nvbios_rd16(bios, lnkcmp + 2); } else { while (ior->dp.bw < nvbios_rd08(bios, lnkcmp)) lnkcmp += 3; - init.offset = nvbios_rd16(bios, lnkcmp + 1); + lnkcmp = nvbios_rd16(bios, lnkcmp + 1); } - nvbios_exec(&init); + nvbios_init(subdev, lnkcmp, + init.outp = &dp->outp.info; + init.or = ior->id; + init.link = ior->asy.link; + ); } ret = ior->func->dp.links(ior, dp->aux); @@ -293,42 +289,38 @@ nvkm_dp_train_links(struct nvkm_dp *dp) static void nvkm_dp_train_fini(struct nvkm_dp *dp) { - struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &dp->outp.info, - .crtc = -1, - .execute = 1, - }; - /* Execute AfterLinkTraining script from DP Info table. */ - init.offset = dp->info.script[1], - nvbios_exec(&init); + nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[1], + init.outp = &dp->outp.info; + init.or = dp->outp.ior->id; + init.link = dp->outp.ior->asy.link; + ); } static void nvkm_dp_train_init(struct nvkm_dp *dp) { - struct nvkm_subdev *subdev = &dp->outp.disp->engine.subdev; - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &dp->outp.info, - .crtc = -1, - .execute = 1, - }; - /* Execute EnableSpread/DisableSpread script from DP Info table. */ - if (dp->dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) - init.offset = dp->info.script[2]; - else - init.offset = dp->info.script[3]; - nvbios_exec(&init); + if (dp->dpcd[DPCD_RC03] & DPCD_RC03_MAX_DOWNSPREAD) { + nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[2], + init.outp = &dp->outp.info; + init.or = dp->outp.ior->id; + init.link = dp->outp.ior->asy.link; + ); + } else { + nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[3], + init.outp = &dp->outp.info; + init.or = dp->outp.ior->id; + init.link = dp->outp.ior->asy.link; + ); + } /* Execute BeforeLinkTraining script from DP Info table. */ - init.offset = dp->info.script[0]; - nvbios_exec(&init); + nvbios_init(&dp->outp.disp->engine.subdev, dp->info.script[0], + init.outp = &dp->outp.info; + init.or = dp->outp.ior->id; + init.link = dp->outp.ior->asy.link; + ); } static const struct dp_rates { From 99a845a30f62b926818412f337ad15218fb121ba Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 57/73] drm/nouveau/disp/nv50-gt21x: remove workaround for dp->tmds hotplug issues This shouldn't have been needed ever since we started executing the DisableLT script when shutting down heads. Testing of the board this was originally written for seems to agree. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 58d46cefe7b1..c018dbdb121d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -316,31 +316,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -/* If programming a TMDS output on a SOR that can also be configured for - * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off. - * - * It looks like the VBIOS TMDS scripts make an attempt at this, however, - * the VBIOS scripts on at least one board I have only switch it off on - * link 0, causing a blank display if the output has previously been - * programmed for DisplayPort. - */ -static void -nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, - struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_bios *bios = device->bios; - const int link = !(outp->sorconf.link & 1); - const int or = ffs(outp->or) - 1; - const u32 loff = (or * 0x800) + (link * 0x80); - const u16 mask = (outp->sorconf.link << 6) | outp->or; - struct dcb_output match; - u8 ver, hdr; - - if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) - nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); -} - static void nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) { @@ -353,8 +328,6 @@ nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) if (!outp) return; - if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) - nv50_disp_intr_unk40_0_tmds(disp, &outp->info); nv50_disp_dptmds_war_3(disp, &outp->info); } From 327c5581d303183e9e56b50238034f419dcca3ce Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 58/73] drm/nouveau/disp/nv50-: implement a common supervisor 1.0 This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 9 +-- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 71 +++++++++++++++++-- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 2 + 3 files changed, 70 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 7a8dff7b8c95..e8bfb6ee89ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -176,12 +176,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -static void -gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head) -{ - exec_script(disp, head, 1); -} - static void gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) { @@ -363,8 +357,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head->id); - gf119_disp_intr_unk1_0(disp, head->id); + nv50_disp_super_1_0(disp, head); } } else if (disp->super & 0x00000002) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index c018dbdb121d..96d281568765 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -114,6 +114,60 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); } +static u32 +nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_outp *iedt) +{ + struct nvkm_bios *bios = head->disp->engine.subdev.device->bios; + const u8 l = ffs(outp->info.link); + const u16 t = outp->info.hasht; + const u16 m = (0x0100 << head->id) | (l << 6) | outp->info.or; + u32 data = nvbios_outp_match(bios, t, m, ver, hdr, cnt, len, iedt); + if (!data) + OUTP_DBG(outp, "missing IEDT for %04x:%04x", t, m); + return data; +} + +static void +nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id) +{ + struct nvkm_outp *outp = ior->arm.outp; + struct nvbios_outp iedt; + u8 ver, hdr, cnt, len; + u32 data; + + if (!outp) { + IOR_DBG(ior, "nothing attached"); + return; + } + + data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt); + if (!data) + return; + + nvbios_init(&head->disp->engine.subdev, iedt.script[id], + init.outp = &outp->info; + init.or = ior->id; + init.link = ior->arm.link; + init.head = head->id; + ); +} + +static struct nvkm_ior * +nv50_disp_super_ior_arm(struct nvkm_head *head) +{ + struct nvkm_ior *ior; + list_for_each_entry(ior, &head->disp->ior, head) { + if (ior->arm.head & (1 << head->id)) { + HEAD_DBG(head, "on %s", ior->name); + return ior; + } + } + HEAD_DBG(head, "nothing attached"); + return NULL; +} + static struct nvkm_output * exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -582,10 +636,19 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) } } -static void -nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) +void +nv50_disp_super_1_0(struct nv50_disp *disp, struct nvkm_head *head) { - exec_script(disp, head, 1); + struct nvkm_ior *ior; + + /* Determine which OR, if any, we're detaching from the head. */ + HEAD_DBG(head, "supervisor 1.0"); + ior = nv50_disp_super_ior_arm(head); + if (!ior) + return; + + /* Execute OffInt1 IED script. */ + nv50_disp_super_ied_off(head, ior, 1); } void @@ -625,7 +688,7 @@ nv50_disp_super(struct work_struct *work) continue; if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk10_0(disp, head->id); + nv50_disp_super_1_0(disp, head); } } else if (disp->super & 0x00000020) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 65d445687038..921ed0fa87f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -3,6 +3,7 @@ #define nv50_disp(p) container_of((p), struct nv50_disp, base) #include "priv.h" #include "dp.h" +struct nvkm_head; struct nv50_disp { const struct nv50_disp_func *func; @@ -26,6 +27,7 @@ struct nv50_disp { }; void nv50_disp_super_1(struct nv50_disp *); +void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); From d52e948c67b263d0ceb71d734673ff8b1d4b10ce Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 59/73] drm/nouveau/disp/nv50-: implement a common supervisor 2.0 This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 18 +++ .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 66 +---------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 108 +++--------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 + 5 files changed, 40 insertions(+), 154 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index da5aa4683d16..12e52529413c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -411,6 +411,23 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) return ret; } +static void +nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior) +{ + struct nvkm_dp *dp = nvkm_dp(outp); + + /* Prevent link from being retrained if sink sends an IRQ. */ + atomic_set(&dp->lt.done, 0); + ior->dp.nr = 0; + + /* Execute DisableLT script from DP Info Table. */ + nvbios_init(&ior->disp->engine.subdev, dp->info.script[4], + init.outp = &dp->outp.info; + init.or = ior->id; + init.link = ior->arm.link; + ); +} + int nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) { @@ -557,6 +574,7 @@ nvkm_dp_func = { .dtor = nvkm_dp_dtor, .init = nvkm_dp_init, .fini = nvkm_dp_fini, + .release = nvkm_dp_release, }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index e8bfb6ee89ae..986069f82d24 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -78,44 +78,6 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, return NULL; } -static struct nvkm_output * -exec_script(struct nv50_disp *disp, int head, int id) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { @@ -176,31 +138,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -static void -gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_output *outp = exec_script(disp, head, 2); - - /* see note in nv50_disp_intr_unk20_0() */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - if (!outpdp->lt.mst) { - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - atomic_set(&outpdp->lt.done, 0); - nvbios_exec(&init); - } - } -} - static void gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) { @@ -364,8 +301,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head->id); - gf119_disp_intr_unk2_0(disp, head->id); + nv50_disp_super_2_0(disp, head); } nvkm_outp_route(&disp->base); list_for_each_entry(head, &disp->base.head, head) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 96d281568765..6c51045e284a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -225,65 +225,6 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, return NULL; } -static struct nvkm_output * -exec_script(struct nv50_disp *disp, int head, int id) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - u32 reg; - int i; - - /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) - ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); - - /* SOR */ - if (!(ctrl & (1 << head))) { - if (device->chipset < 0x90 || - device->chipset == 0x92 || - device->chipset == 0xa0) { - reg = 0x610b74; - } else { - reg = 0x610798; - } - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) - ctrl = nvkm_rd32(device, reg + (i * 8)); - i += 4; - } - - /* PIOR */ - if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) - ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); - i += 8; - } - - if (!(ctrl & (1 << head))) - return NULL; - i--; - - outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { @@ -601,38 +542,27 @@ nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); } -static void -nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) +void +nv50_disp_super_2_0(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_output *outp = exec_script(disp, head, 2); + struct nvkm_outp *outp; + struct nvkm_ior *ior; - /* the binary driver does this outside of the supervisor handling - * (after the third supervisor from a detach). we (currently?) - * allow both detach/attach to happen in the same set of - * supervisor interrupts, so it would make sense to execute this - * (full power down?) script after all the detach phases of the - * supervisor handling. like with training if needed from the - * second supervisor, nvidia doesn't do this, so who knows if it's - * entirely safe, but it does appear to work.. - * - * without this script being run, on some configurations i've - * seen, switching from DP to TMDS on a DP connector may result - * in a blank screen (SOR_PWR off/on can restore it) + /* Determine which OR, if any, we're detaching from the head. */ + HEAD_DBG(head, "supervisor 2.0"); + ior = nv50_disp_super_ior_arm(head); + if (!ior) + return; + + /* Execute OffInt2 IED script. */ + nv50_disp_super_ied_off(head, ior, 2); + + /* If we're shutting down the OR's only active head, execute + * the output path's release function. */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - struct nvbios_init init = { - .subdev = subdev, - .bios = subdev->device->bios, - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - atomic_set(&outpdp->lt.done, 0); - nvbios_exec(&init); + if (ior->arm.head == (1 << head->id)) { + if ((outp = ior->arm.outp) && outp->func->release) + outp->func->release(outp, ior); } } @@ -695,7 +625,7 @@ nv50_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_0(disp, head->id); + nv50_disp_super_2_0(disp, head); } nvkm_outp_route(&disp->base); list_for_each_entry(head, &disp->base.head, head) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 921ed0fa87f3..f6bafe6dcaa4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -28,6 +28,7 @@ struct nv50_disp { void nv50_disp_super_1(struct nv50_disp *); void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 106141eb3e32..da4347e27e65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -39,6 +39,7 @@ struct nvkm_outp_func { void *(*dtor)(struct nvkm_outp *); void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); + void (*release)(struct nvkm_outp *, struct nvkm_ior *); }; #define nvkm_output nvkm_outp From 1f0c9eaf31bba3e1cac5534ba17602c115b76cf8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 60/73] drm/nouveau/disp/nv50-: implement a common supervisor 2.1 This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 15 ++------------- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 16 ++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 986069f82d24..d25b3b7f4fb8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -138,17 +138,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -static void -gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_devinit *devinit = device->devinit; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - if (pclk) - nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); - nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); -} - static void gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, struct dcb_output *outp) @@ -260,6 +249,7 @@ gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) } nvkm_mask(device, addr, 0x00000707, data); + nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); } static void @@ -307,8 +297,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00010000)) continue; - nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head->id); - gf119_disp_intr_unk2_1(disp, head->id); + nv50_disp_super_2_1(disp, head); } list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 6c51045e284a..ebe7657bf2af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -532,14 +532,14 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) nv50_disp_dptmds_war_2(disp, &outp->info); } -static void -nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) +void +nv50_disp_super_2_1(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_devinit *devinit = device->devinit; - u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - if (pclk) - nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); + struct nvkm_devinit *devinit = disp->base.engine.subdev.device->devinit; + u32 khz = head->asy.hz / 1000; + HEAD_DBG(head, "supervisor 2.1 - %d khz", khz); + if (khz) + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head->id, khz); } void @@ -631,7 +631,7 @@ nv50_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000200 << head->id))) continue; - nv50_disp_intr_unk20_1(disp, head->id); + nv50_disp_super_2_1(disp, head); } list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000080 << head->id))) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index f6bafe6dcaa4..310a568c3fdb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -29,6 +29,7 @@ struct nv50_disp { void nv50_disp_super_1(struct nv50_disp *); void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_2_1(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); From 8d7ef84d908877708001f3334dbf44e9d48fad57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 61/73] drm/nouveau/disp/nv50-: implement a common supervisor 2.2 This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/channv50.c | 1 + .../drm/nouveau/nvkm/engine/disp/dacgf119.c | 9 + .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 9 + drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c | 7 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h | 4 - .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 117 +------- .../gpu/drm/nouveau/nvkm/engine/disp/head.h | 1 + .../drm/nouveau/nvkm/engine/disp/headgf119.c | 8 + .../drm/nouveau/nvkm/engine/disp/headnv50.c | 8 + .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 13 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 251 ++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 1 + .../drm/nouveau/nvkm/engine/disp/piornv50.c | 9 + .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 61 ++++- .../drm/nouveau/nvkm/engine/disp/sorgf119.c | 33 +++ .../drm/nouveau/nvkm/engine/disp/sorgk104.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgm107.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgm200.c | 3 + .../drm/nouveau/nvkm/engine/disp/sorgt215.c | 4 + .../drm/nouveau/nvkm/engine/disp/sormcp77.c | 4 + .../drm/nouveau/nvkm/engine/disp/sormcp89.c | 4 + .../drm/nouveau/nvkm/engine/disp/sornv50.c | 10 + 25 files changed, 321 insertions(+), 246 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index 524a24eae1a0..0c0310498afd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -25,6 +25,7 @@ #include "rootnv50.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c index 7d2d929eec16..8392303b77ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -21,6 +21,14 @@ */ #include "ior.h" +static void +gf119_dac_clock(struct nvkm_ior *dac) +{ + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 doff = nv50_ior_base(dac); + nvkm_mask(device, 0x612280 + doff, 0x07070707, 0x00000000); +} + static void gf119_dac_state(struct nvkm_ior *dac, struct nvkm_ior_state *state) { @@ -44,6 +52,7 @@ gf119_dac = { .state = gf119_dac_state, .power = nv50_dac_power, .sense = nv50_dac_sense, + .clock = gf119_dac_clock, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 64de64fdc9d1..119cd02a2000 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -25,6 +25,14 @@ #include +static void +nv50_dac_clock(struct nvkm_ior *dac) +{ + struct nvkm_device *device = dac->disp->engine.subdev.device; + const u32 doff = nv50_ior_base(dac); + nvkm_mask(device, 0x614280 + doff, 0x07070707, 0x00000000); +} + int nv50_dac_sense(struct nvkm_ior *dac, u32 loadval) { @@ -95,6 +103,7 @@ nv50_dac = { .state = nv50_dac_state, .power = nv50_dac_power, .sense = nv50_dac_sense, + .clock = nv50_dac_clock, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 12e52529413c..7c5bed29ffef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -428,8 +428,8 @@ nvkm_dp_release(struct nvkm_outp *outp, struct nvkm_ior *ior) ); } -int -nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused) +static int +nvkm_dp_acquire(struct nvkm_outp *outp) { struct nvkm_dp *dp = nvkm_dp(outp); struct nvkm_ior *ior = dp->outp.ior; @@ -529,7 +529,7 @@ nvkm_dp_hpd(struct nvkm_notify *notify) OUTP_DBG(&dp->outp, "HPD: %d", line->mask); if (line->mask & NVKM_I2C_IRQ) { if (atomic_read(&dp->lt.done)) - nvkm_output_dp_train(&dp->outp, 0); + dp->outp.func->acquire(&dp->outp); rep.mask |= NVIF_NOTIFY_CONN_V0_IRQ; } else { nvkm_dp_enable(dp, true); @@ -574,6 +574,7 @@ nvkm_dp_func = { .dtor = nvkm_dp_dtor, .init = nvkm_dp_init, .fini = nvkm_dp_fini, + .acquire = nvkm_dp_acquire, .release = nvkm_dp_release, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 34e58b70a394..59173c290525 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -29,10 +29,6 @@ struct nvkm_dp { } lt; }; -#define nvkm_output_dp nvkm_dp - -int nvkm_output_dp_train(struct nvkm_output *, u32 rate); - int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_outp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index d25b3b7f4fb8..f4a05549f642 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -138,120 +138,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) return outp; } -static void -gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, - struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const int or = ffs(outp->or) - 1; - const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020)); - const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300)); - const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff; - const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff; - const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff; - const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; - const u32 hoff = (head * 0x800); - const u32 soff = ( or * 0x800); - const u32 loff = (link * 0x080) + soff; - const u32 symbol = 100000; - const u32 TU = 64; - u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); - u32 clksor = nvkm_rd32(device, 0x612300 + soff); - u32 datarate, link_nr, link_bw, bits; - u64 ratio, value; - - link_nr = hweight32(dpctrl & 0x000f0000); - link_bw = (clksor & 0x007c0000) >> 18; - link_bw *= 27000; - - /* symbols/hblank - algorithm taken from comments in tegra driver */ - value = vblanke + vactive - vblanks - 7; - value = value * link_bw; - do_div(value, pclk); - value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value); - - /* symbols/vblank - algorithm taken from comments in tegra driver */ - value = vblanks - vblanke - 25; - value = value * link_bw; - do_div(value, pclk); - value = value - ((36 / link_nr) + 3) - 1; - nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value); - - /* watermark */ - if ((conf & 0x3c0) == 0x180) bits = 30; - else if ((conf & 0x3c0) == 0x140) bits = 24; - else bits = 18; - datarate = (pclk * bits) / 8; - - ratio = datarate; - ratio *= symbol; - do_div(ratio, link_nr * link_bw); - - value = (symbol - ratio) * TU; - value *= ratio; - do_div(value, symbol); - do_div(value, symbol); - - value += 5; - value |= 0x08000000; - - nvkm_wr32(device, 0x616610 + hoff, value); -} - -static void -gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - u32 conf, addr, data; - - outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); - if (!outp) - return; - - /* see note in nv50_disp_intr_unk20_2() */ - if (outp->info.type == DCB_OUTPUT_DP) { - u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300)); - switch ((sync & 0x000003c0) >> 6) { - case 6: pclk = pclk * 30; break; - case 5: pclk = pclk * 24; break; - case 2: - default: - pclk = pclk * 18; - break; - } - - if (nvkm_output_dp_train(outp, pclk)) - OUTP_ERR(outp, "link not trained before attach"); - } - - exec_clkcmp(disp, head, 0, pclk, &conf); - - if (outp->info.type == DCB_OUTPUT_ANALOG) { - addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; - data = 0x00000000; - } else { - addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; - data = (conf & 0x0100) ? 0x00000101 : 0x00000000; - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - nvkm_mask(device, addr, 0x007c0000, 0x00280000); - break; - case DCB_OUTPUT_DP: - gf119_disp_intr_unk2_2_tu(disp, head, &outp->info); - break; - default: - break; - } - } - - nvkm_mask(device, addr, 0x00000707, data); - nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); -} - static void gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) { @@ -302,8 +188,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head->id); - gf119_disp_intr_unk2_2(disp, head->id); + nv50_disp_super_2_2(disp, head); } } else if (disp->super & 0x00000004) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h index 829a0a8cfb2e..b04c49d2eeeb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h @@ -36,6 +36,7 @@ struct nvkm_head *nvkm_head_find(struct nvkm_disp *, int id); struct nvkm_head_func { void (*state)(struct nvkm_head *, struct nvkm_head_state *); void (*rgpos)(struct nvkm_head *, u16 *hline, u16 *vline); + void (*rgclk)(struct nvkm_head *, int div); void (*vblank_get)(struct nvkm_head *); void (*vblank_put)(struct nvkm_head *); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c index d2bd6bb4a621..b33552757647 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c @@ -39,6 +39,13 @@ gf119_head_vblank_get(struct nvkm_head *head) nvkm_mask(device, 0x6100c0 + hoff, 0x00000001, 0x00000001); } +static void +gf119_head_rgclk(struct nvkm_head *head, int div) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_mask(device, 0x612200 + (head->id * 0x800), 0x0000000f, div); +} + static void gf119_head_state(struct nvkm_head *head, struct nvkm_head_state *state) { @@ -77,6 +84,7 @@ static const struct nvkm_head_func gf119_head = { .state = gf119_head_state, .rgpos = nv50_head_rgpos, + .rgclk = gf119_head_rgclk, .vblank_get = gf119_head_vblank_get, .vblank_put = gf119_head_vblank_put, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c index d4a9879f0d0a..c80d06d5168f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c @@ -37,6 +37,13 @@ nv50_head_vblank_get(struct nvkm_head *head) nvkm_mask(device, 0x61002c, (4 << head->id), (4 << head->id)); } +static void +nv50_head_rgclk(struct nvkm_head *head, int div) +{ + struct nvkm_device *device = head->disp->engine.subdev.device; + nvkm_mask(device, 0x614200 + (head->id * 0x800), 0x0000000f, div); +} + void nv50_head_rgpos(struct nvkm_head *head, u16 *hline, u16 *vline) { @@ -73,6 +80,7 @@ static const struct nvkm_head_func nv50_head = { .state = nv50_head_state, .rgpos = nv50_head_rgpos, + .rgclk = nv50_head_rgclk, .vblank_get = nv50_head_vblank_get, .vblank_put = nv50_head_vblank_put, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 3a6e01f5a0e5..d6bfaa53f96b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -50,6 +50,8 @@ struct nvkm_ior_func { void (*power)(struct nvkm_ior *, bool normal, bool pu, bool data, bool vsync, bool hsync); int (*sense)(struct nvkm_ior *, u32 loadval); + void (*clock)(struct nvkm_ior *); + void (*war_2)(struct nvkm_ior *); struct { void (*ctrl)(struct nvkm_ior *, int head, bool enable, @@ -67,6 +69,10 @@ struct nvkm_ior_func { void (*vcpi)(struct nvkm_ior *, int head, u8 slot, u8 slot_nr, u16 pbn, u16 aligned); void (*audio)(struct nvkm_ior *, int head, bool enable); + void (*audio_sym)(struct nvkm_ior *, int head, u16 h, u32 v); + void (*activesym)(struct nvkm_ior *, int head, + u8 TU, u8 VTUa, u8 VTUf, u8 VTUi); + void (*watermark)(struct nvkm_ior *, int head, u8 watermark); } dp; struct { @@ -99,21 +105,28 @@ nv50_sor_link(struct nvkm_ior *ior) void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); +void nv50_sor_clock(struct nvkm_ior *); void g94_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); int g94_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void g94_sor_dp_power(struct nvkm_ior *, int); void g94_sor_dp_pattern(struct nvkm_ior *, int); void g94_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); +void g94_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32); +void g94_sor_dp_activesym(struct nvkm_ior *, int, u8, u8, u8, u8); +void g94_sor_dp_watermark(struct nvkm_ior *, int, u8); void gt215_sor_dp_audio(struct nvkm_ior *, int, bool); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); +void gf119_sor_clock(struct nvkm_ior *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); void gf119_sor_dp_pattern(struct nvkm_ior *, int); void gf119_sor_dp_drive(struct nvkm_ior *, int, int, int, int, int); void gf119_sor_dp_vcpi(struct nvkm_ior *, int, u8, u8, u16, u16); void gf119_sor_dp_audio(struct nvkm_ior *, int, bool); +void gf119_sor_dp_audio_sym(struct nvkm_ior *, int, u16, u32); +void gf119_sor_dp_watermark(struct nvkm_ior *, int, u8); void gm107_sor_dp_pattern(struct nvkm_ior *, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index ebe7657bf2af..f21e0e92d6f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -129,6 +129,62 @@ nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp, return data; } +static void +nv50_disp_super_ied_on(struct nvkm_head *head, + struct nvkm_ior *ior, int id, u32 khz) +{ + struct nvkm_subdev *subdev = &head->disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; + struct nvkm_outp *outp = ior->asy.outp; + struct nvbios_ocfg iedtrs; + struct nvbios_outp iedt; + u8 ver, hdr, cnt, len, flags = 0x00; + u32 data; + + if (!outp) { + IOR_DBG(ior, "nothing to attach"); + return; + } + + /* Lookup IED table for the device. */ + data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt); + if (!data) + return; + + /* Lookup IEDT runtime settings for the current configuration. */ + if (ior->type == SOR) { + if (ior->asy.proto == LVDS) { + if (head->asy.or.depth == 24) + flags |= 0x02; + } + if (ior->asy.link == 3) + flags |= 0x01; + } + + data = nvbios_ocfg_match(bios, data, ior->asy.proto_evo, flags, + &ver, &hdr, &cnt, &len, &iedtrs); + if (!data) { + OUTP_DBG(outp, "missing IEDT RS for %02x:%02x", + ior->asy.proto_evo, flags); + return; + } + + /* Execute the OnInt[23] script for the current frequency. */ + data = nvbios_oclk_match(bios, iedtrs.clkcmp[id], khz); + if (!data) { + OUTP_DBG(outp, "missing IEDT RSS %d for %02x:%02x %d khz", + id, ior->asy.proto_evo, flags, khz); + return; + } + + nvbios_init(subdev, data, + init.outp = &outp->info; + init.or = ior->id; + init.link = ior->asy.link; + init.head = head->id; + ); +} + static void nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id) { @@ -154,6 +210,20 @@ nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id) ); } +static struct nvkm_ior * +nv50_disp_super_ior_asy(struct nvkm_head *head) +{ + struct nvkm_ior *ior; + list_for_each_entry(ior, &head->disp->ior, head) { + if (ior->asy.head & (1 << head->id)) { + HEAD_DBG(head, "to %s", ior->name); + return ior; + } + } + HEAD_DBG(head, "nothing to attach"); + return NULL; +} + static struct nvkm_ior * nv50_disp_super_ior_arm(struct nvkm_head *head) { @@ -327,58 +397,40 @@ nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) } static void -nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, - struct dcb_output *outp, u32 pclk) +nv50_disp_super_2_2_dp(struct nvkm_head *head, struct nvkm_ior *ior) { - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const int link = !(outp->sorconf.link & 1); - const int or = ffs(outp->or) - 1; - const u32 soff = ( or * 0x800); - const u32 loff = (link * 0x080) + soff; - const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8)); - const u32 symbol = 100000; - const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff; - const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff; - const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff; - u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); - u32 clksor = nvkm_rd32(device, 0x614300 + soff); + struct nvkm_subdev *subdev = &head->disp->engine.subdev; + const u32 khz = head->asy.hz / 1000; + const u32 linkKBps = ior->dp.bw * 27000; + const u32 symbol = 100000; int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int TU, VTUi, VTUf, VTUa; u64 link_data_rate, link_ratio, unk; u32 best_diff = 64 * symbol; - u32 link_nr, link_bw, bits; - u64 value; - - link_bw = (clksor & 0x000c0000) ? 270000 : 162000; - link_nr = hweight32(dpctrl & 0x000f0000); + u64 h, v; /* symbols/hblank - algorithm taken from comments in tegra driver */ - value = vblanke + vactive - vblanks - 7; - value = value * link_bw; - do_div(value, pclk); - value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value); + h = head->asy.hblanke + head->asy.htotal - head->asy.hblanks - 7; + h = h * linkKBps; + do_div(h, khz); + h = h - (3 * ior->dp.ef) - (12 / ior->dp.nr); /* symbols/vblank - algorithm taken from comments in tegra driver */ - value = vblanks - vblanke - 25; - value = value * link_bw; - do_div(value, pclk); - value = value - ((36 / link_nr) + 3) - 1; - nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value); + v = head->asy.vblanks - head->asy.vblanke - 25; + v = v * linkKBps; + do_div(v, khz); + v = v - ((36 / ior->dp.nr) + 3) - 1; + + ior->func->dp.audio_sym(ior, head->id, h, v); /* watermark / activesym */ - if ((ctrl & 0xf0000) == 0x60000) bits = 30; - else if ((ctrl & 0xf0000) == 0x50000) bits = 24; - else bits = 18; - - link_data_rate = (pclk * bits / 8) / link_nr; + link_data_rate = (khz * head->asy.or.depth / 8) / ior->dp.nr; /* calculate ratio of packed data rate to link symbol rate */ link_ratio = link_data_rate * symbol; - do_div(link_ratio, link_bw); + do_div(link_ratio, linkKBps); - for (TU = 64; TU >= 32; TU--) { + for (TU = 64; ior->func->dp.activesym && TU >= 32; TU--) { /* calculate average number of valid symbols in each TU */ u32 tu_valid = link_ratio * TU; u32 calc, diff; @@ -429,9 +481,15 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, } } - if (!bestTU) { - nvkm_error(subdev, "unable to find suitable dp config\n"); - return; + if (ior->func->dp.activesym) { + if (!bestTU) { + nvkm_error(subdev, "unable to determine dp config\n"); + return; + } + ior->func->dp.activesym(ior, head->id, bestTU, + bestVTUa, bestVTUf, bestVTUi); + } else { + bestTU = 64; } /* XXX close to vbios numbers, but not right */ @@ -441,102 +499,61 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, do_div(unk, symbol); unk += 6; - nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2); - nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | - bestVTUf << 16 | - bestVTUi << 8 | unk); + ior->func->dp.watermark(ior, head->id, unk); } -static void -nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) +void +nv50_disp_super_2_2(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - u32 hval, hreg = 0x614200 + (head * 0x800); - u32 oval, oreg; - u32 mask, conf; + const u32 khz = head->asy.hz / 1000; + struct nvkm_outp *outp; + struct nvkm_ior *ior; - outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); - if (!outp) + /* Determine which OR, if any, we're attaching from the head. */ + HEAD_DBG(head, "supervisor 2.2"); + ior = nv50_disp_super_ior_asy(head); + if (!ior) return; - /* we allow both encoder attach and detach operations to occur - * within a single supervisor (ie. modeset) sequence. the - * encoder detach scripts quite often switch off power to the - * lanes, which requires the link to be re-trained. + /* For some reason, NVIDIA decided not to: * - * this is not generally an issue as the sink "must" (heh) - * signal an irq when it's lost sync so the driver can - * re-train. + * A) Give dual-link LVDS a separate EVO protocol, like for TMDS. + * and + * B) Use SetControlOutputResource.PixelDepth on LVDS. * - * however, on some boards, if one does not configure at least - * the gpu side of the link *before* attaching, then various - * things can go horribly wrong (PDISP disappearing from mmio, - * third supervisor never happens, etc). - * - * the solution is simply to retrain here, if necessary. last - * i checked, the binary driver userspace does not appear to - * trigger this situation (it forces an UPDATE between steps). + * Override the values we usually read from HW with the same + * data we pass though an ioctl instead. */ - if (outp->info.type == DCB_OUTPUT_DP) { - u32 soff = (ffs(outp->info.or) - 1) * 0x08; - u32 ctrl, datarate; - - if (outp->info.location == 0) { - ctrl = nvkm_rd32(device, 0x610794 + soff); - soff = 1; - } else { - ctrl = nvkm_rd32(device, 0x610b80 + soff); - soff = 2; - } - - switch ((ctrl & 0x000f0000) >> 16) { - case 6: datarate = pclk * 30; break; - case 5: datarate = pclk * 24; break; - case 2: - default: - datarate = pclk * 18; - break; - } - - if (nvkm_output_dp_train(outp, datarate / soff)) - OUTP_ERR(outp, "link not trained before attach"); + if (ior->type == SOR && ior->asy.proto == LVDS) { + head->asy.or.depth = (disp->sor.lvdsconf & 0x0200) ? 24 : 18; + ior->asy.link = (disp->sor.lvdsconf & 0x0100) ? 3 : 1; } - exec_clkcmp(disp, head, 0, pclk, &conf); + /* Handle any link training, etc. */ + if ((outp = ior->asy.outp) && outp->func->acquire) + outp->func->acquire(outp); - if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { - oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; - oval = 0x00000000; - hval = 0x00000000; - mask = 0xffffffff; - } else - if (!outp->info.location) { - if (outp->info.type == DCB_OUTPUT_DP) - nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk); - oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; - oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; - hval = 0x00000000; - mask = 0x00000707; - } else { - oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800; - oval = 0x00000001; - hval = 0x00000001; - mask = 0x00000707; - } + /* Execute OnInt2 IED script. */ + nv50_disp_super_ied_on(head, ior, 0, khz); - nvkm_mask(device, hreg, 0x0000000f, hval); - nvkm_mask(device, oreg, mask, oval); + /* Program RG clock divider. */ + head->func->rgclk(head, ior->asy.rgdiv); - nv50_disp_dptmds_war_2(disp, &outp->info); + /* Mode-specific internal DP configuration. */ + if (ior->type == SOR && ior->asy.proto == DP) + nv50_disp_super_2_2_dp(head, ior); + + /* OR-specific handling. */ + ior->func->clock(ior); + if (ior->func->war_2) + ior->func->war_2(ior); } void nv50_disp_super_2_1(struct nv50_disp *disp, struct nvkm_head *head) { struct nvkm_devinit *devinit = disp->base.engine.subdev.device->devinit; - u32 khz = head->asy.hz / 1000; + const u32 khz = head->asy.hz / 1000; HEAD_DBG(head, "supervisor 2.1 - %d khz", khz); if (khz) nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head->id, khz); @@ -636,7 +653,7 @@ nv50_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk20_2(disp, head->id); + nv50_disp_super_2_2(disp, head); } } else if (disp->super & 0x00000040) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 310a568c3fdb..b6092b8b528a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -2,7 +2,6 @@ #define __NV50_DISP_H__ #define nv50_disp(p) container_of((p), struct nv50_disp, base) #include "priv.h" -#include "dp.h" struct nvkm_head; struct nv50_disp { @@ -30,6 +29,7 @@ void nv50_disp_super_1(struct nv50_disp *); void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_1(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_2_2(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index da4347e27e65..7655d9293911 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -39,6 +39,7 @@ struct nvkm_outp_func { void *(*dtor)(struct nvkm_outp *); void (*init)(struct nvkm_outp *); void (*fini)(struct nvkm_outp *); + int (*acquire)(struct nvkm_outp *); void (*release)(struct nvkm_outp *, struct nvkm_ior *); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index dc59c319377e..a1f24ef222c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -27,6 +27,14 @@ #include #include +static void +nv50_pior_clock(struct nvkm_ior *pior) +{ + struct nvkm_device *device = pior->disp->engine.subdev.device; + const u32 poff = nv50_ior_base(pior); + nvkm_mask(device, 0x614380 + poff, 0x00000707, 0x00000001); +} + static int nv50_pior_dp_links(struct nvkm_ior *pior, struct nvkm_i2c_aux *aux) { @@ -110,6 +118,7 @@ static const struct nvkm_ior_func nv50_pior = { .state = nv50_pior_state, .power = nv50_pior_power, + .clock = nv50_pior_clock, .dp = { .links = nv50_pior_dp_links, }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 4c7b7090b1a0..1208524aae14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -23,6 +23,7 @@ */ #include "rootnv50.h" #include "dmacnv50.h" +#include "dp.h" #include "head.h" #include "ior.h" diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c index 8913b5f58103..ec3a7db08118 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -25,6 +25,7 @@ static const struct nvkm_ior_func g84_sor = { .state = nv50_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, .hdmi = { .ctrl = g84_hdmi_ctrl, }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 5abf563b0e84..bdace3852b37 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -26,6 +26,35 @@ #include +void +g94_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); + nvkm_mask(device, 0x61c128 + loff, 0x0000003f, watermark); +} + +void +g94_sor_dp_activesym(struct nvkm_ior *sor, int head, + u8 TU, u8 VTUa, u8 VTUf, u8 VTUi) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 loff = nv50_sor_link(sor); + nvkm_mask(device, 0x61c10c + loff, 0x000001fc, TU << 2); + nvkm_mask(device, 0x61c128 + loff, 0x010f7f00, VTUa << 24 | + VTUf << 16 | + VTUi << 8); +} + +void +g94_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, h); + nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, v); +} + void g94_sor_dp_drive(struct nvkm_ior *sor, int ln, int pc, int dc, int pe, int pu) { @@ -123,6 +152,23 @@ nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) } +static bool +g94_sor_war_needed(struct nvkm_ior *sor) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); + if (sor->asy.proto == TMDS) { + switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { + case 0x00000000: + case 0x00030000: + return true; + default: + break; + } + } + return false; +} + void nv50_disp_update_sppll1(struct nv50_disp *disp) { @@ -191,13 +237,13 @@ nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) } } -void -nv50_disp_dptmds_war_2(struct nv50_disp *disp, struct dcb_output *outp) +static void +g94_sor_war_2(struct nvkm_ior *sor) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); - if (!nv50_disp_dptmds_war_needed(disp, outp)) + if (!g94_sor_war_needed(sor)) return; nvkm_mask(device, 0x00e840, 0x80000000, 0x80000000); @@ -245,12 +291,17 @@ static const struct nvkm_ior_func g94_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, + .war_2 = g94_sor_war_2, .dp = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, + .audio_sym = g94_sor_dp_audio_sym, + .activesym = g94_sor_dp_activesym, + .watermark = g94_sor_dp_watermark, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index d37cd037ee03..5f8306b00f71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -25,6 +25,23 @@ #include +void +gf119_sor_dp_watermark(struct nvkm_ior *sor, int head, u8 watermark) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 hoff = head * 0x800; + nvkm_mask(device, 0x616610 + hoff, 0x0800003f, 0x08000000 | watermark); +} + +void +gf119_sor_dp_audio_sym(struct nvkm_ior *sor, int head, u16 h, u32 v) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 hoff = head * 0x800; + nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, h); + nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, v); +} + void gf119_sor_dp_audio(struct nvkm_ior *sor, int head, bool enable) { @@ -99,6 +116,19 @@ gf119_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) return 0; } +void +gf119_sor_clock(struct nvkm_ior *sor) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const int div = sor->asy.link == 3; + const u32 soff = nv50_ior_base(sor); + if (sor->asy.proto == TMDS) { + /* NFI why, but this sets DP_LINK_BW_2_7 when using TMDS. */ + nvkm_mask(device, 0x612300 + soff, 0x007c0000, 0x0a << 18); + } + nvkm_mask(device, 0x612300 + soff, 0x00000707, (div << 8) | div); +} + void gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) { @@ -126,6 +156,7 @@ static const struct nvkm_ior_func gf119_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .clock = gf119_sor_clock, .hdmi = { .ctrl = gf119_hdmi_ctrl, }, @@ -136,6 +167,8 @@ gf119_sor = { .pattern = gf119_sor_dp_pattern, .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, + .audio_sym = gf119_sor_dp_audio_sym, + .watermark = gf119_sor_dp_watermark, }, .hda = { .hpd = gf119_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index 24fc026cd18d..b94090edaebf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -25,6 +25,7 @@ static const struct nvkm_ior_func gk104_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .clock = gf119_sor_clock, .hdmi = { .ctrl = gk104_hdmi_ctrl, }, @@ -36,6 +37,8 @@ gk104_sor = { .drive = gf119_sor_dp_drive, .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, + .audio_sym = gf119_sor_dp_audio_sym, + .watermark = gf119_sor_dp_watermark, }, .hda = { .hpd = gf119_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index e467f8eaf2ee..e6965dec09c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -39,6 +39,7 @@ static const struct nvkm_ior_func gm107_sor = { .state = gf119_sor_state, .power = nv50_sor_power, + .clock = gf119_sor_clock, .hdmi = { .ctrl = gk104_hdmi_ctrl, }, @@ -50,6 +51,8 @@ gm107_sor = { .drive = gf119_sor_dp_drive, .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, + .audio_sym = gf119_sor_dp_audio_sym, + .watermark = gf119_sor_dp_watermark, }, .hda = { .hpd = gf119_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 25528a15516b..8bc019b6ffab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -96,6 +96,7 @@ gm200_sor = { }, .state = gf119_sor_state, .power = nv50_sor_power, + .clock = gf119_sor_clock, .hdmi = { .ctrl = gk104_hdmi_ctrl, }, @@ -107,6 +108,8 @@ gm200_sor = { .drive = gm200_sor_dp_drive, .vcpi = gf119_sor_dp_vcpi, .audio = gf119_sor_dp_audio, + .audio_sym = gf119_sor_dp_audio_sym, + .watermark = gf119_sor_dp_watermark, }, .hda = { .hpd = gf119_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 5e9126e832ff..54d134d4ca1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -41,6 +41,7 @@ static const struct nvkm_ior_func gt215_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, .hdmi = { .ctrl = gt215_hdmi_ctrl, }, @@ -51,6 +52,9 @@ gt215_sor = { .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, .audio = gt215_sor_dp_audio, + .audio_sym = g94_sor_dp_audio_sym, + .activesym = g94_sor_dp_activesym, + .watermark = g94_sor_dp_watermark, }, .hda = { .hpd = gt215_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 50d6c0d98e20..8a70dd25b13a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -25,6 +25,7 @@ static const struct nvkm_ior_func mcp77_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, .hdmi = { .ctrl = g84_hdmi_ctrl, }, @@ -34,6 +35,9 @@ mcp77_sor = { .power = g94_sor_dp_power, .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, + .audio_sym = g94_sor_dp_audio_sym, + .activesym = g94_sor_dp_activesym, + .watermark = g94_sor_dp_watermark, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index dd76351d2ccb..eac9c5be9166 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -25,6 +25,7 @@ static const struct nvkm_ior_func mcp89_sor = { .state = g94_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, .hdmi = { .ctrl = gt215_hdmi_ctrl, }, @@ -35,6 +36,9 @@ mcp89_sor = { .pattern = g94_sor_dp_pattern, .drive = g94_sor_dp_drive, .audio = gt215_sor_dp_audio, + .audio_sym = g94_sor_dp_audio_sym, + .activesym = g94_sor_dp_activesym, + .watermark = g94_sor_dp_watermark, }, .hda = { .hpd = gt215_hda_hpd, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 2ca600c744cd..dbb303db3178 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -25,6 +25,15 @@ #include +void +nv50_sor_clock(struct nvkm_ior *sor) +{ + struct nvkm_device *device = sor->disp->engine.subdev.device; + const int div = sor->asy.link == 3; + const u32 soff = nv50_ior_base(sor); + nvkm_mask(device, 0x614300 + soff, 0x00000707, (div << 8) | div); +} + static void nv50_sor_power_wait(struct nvkm_device *device, u32 soff) { @@ -79,6 +88,7 @@ static const struct nvkm_ior_func nv50_sor = { .state = nv50_sor_state, .power = nv50_sor_power, + .clock = nv50_sor_clock, }; int From 0d93cd92bd616474da0c842bc4e88f6921da18f1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 62/73] drm/nouveau/disp/nv50-: implement a common supervisor 3.0 This makes use of all the additional routing and state added in previous commits, making it possible to deal with GM20x macro link routing, while also sharing code between the NV50 and GF119 implementations. Signed-off-by: Ben Skeggs --- .../nouveau/include/nvkm/subdev/bios/init.h | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 125 +------------ .../gpu/drm/nouveau/nvkm/engine/disp/ior.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 168 ++---------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 4 - .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 63 ++----- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 5 - 8 files changed, 35 insertions(+), 338 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index c7383e1f0966..06ab48052128 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -3,16 +3,12 @@ struct nvbios_init { struct nvkm_subdev *subdev; - struct nvkm_bios *bios; u32 offset; struct dcb_output *outp; int or; int link; - union { - int head; - int crtc; - }; + int head; /* internal state used during parsing */ u8 execute; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index f4a05549f642..d8765b57180b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -26,128 +26,6 @@ #include "ior.h" #include "rootnv50.h" -#include -#include -#include -#include -#include - -static struct nvkm_output * -exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_output *outp; - u16 mask, type; - - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else { - or -= 4; - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); - return NULL; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &disp->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, mask, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -static struct nvkm_output * -exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - *conf = (ctrl & 0x00000f00) >> 8; - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - if (*conf == 5) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf |= disp->sor.lvdsconf; - break; - default: - break; - } - - data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, - &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - u32 conf; - - exec_clkcmp(disp, head, 1, pclk, &conf); -} - void gf119_disp_super(struct work_struct *work) { @@ -195,8 +73,7 @@ gf119_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(mask[head->id] & 0x00001000)) continue; - nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head->id); - gf119_disp_intr_unk4_0(disp, head->id); + nv50_disp_super_3_0(disp, head); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index d6bfaa53f96b..1e11e25a41f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -52,6 +52,7 @@ struct nvkm_ior_func { int (*sense)(struct nvkm_ior *, u32 loadval); void (*clock)(struct nvkm_ior *); void (*war_2)(struct nvkm_ior *); + void (*war_3)(struct nvkm_ior *); struct { void (*ctrl)(struct nvkm_ior *, int head, bool enable, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index f21e0e92d6f1..0c570dbd3021 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -238,162 +238,23 @@ nv50_disp_super_ior_arm(struct nvkm_head *head) return NULL; } -static struct nvkm_output * -exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) +void +nv50_disp_super_3_0(struct nv50_disp *disp, struct nvkm_head *head) { - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_output *outp; - u16 mask, type; + struct nvkm_ior *ior; - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else - if (or < 8) { - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); - return NULL; - } - or -= 4; - } else { - or = or - 8; - type = 0x0010; - mask = 0; - switch (ctrl & 0x00000f00) { - case 0x00000000: type |= disp->pior.type[or]; break; - default: - nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl); - return NULL; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &disp->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, mask, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -static struct nvkm_output * -exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - u32 reg; - int i; - - /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) - ctrl = nvkm_rd32(device, 0x610b58 + (i * 8)); - - /* SOR */ - if (!(ctrl & (1 << head))) { - if (device->chipset < 0x90 || - device->chipset == 0x92 || - device->chipset == 0xa0) { - reg = 0x610b70; - } else { - reg = 0x610794; - } - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) - ctrl = nvkm_rd32(device, reg + (i * 8)); - i += 4; - } - - /* PIOR */ - if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) - ctrl = nvkm_rd32(device, 0x610b80 + (i * 8)); - i += 8; - } - - if (!(ctrl & (1 << head))) - return NULL; - i--; - - outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - *conf = (ctrl & 0x00000f00) >> 8; - if (outp->info.location == 0) { - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - if (*conf == 5) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf |= disp->sor.lvdsconf; - break; - default: - break; - } - } else { - *conf = (ctrl & 0x00000f00) >> 8; - pclk = pclk / 2; - } - - data = nvbios_ocfg_match(bios, data, *conf & 0xff, *conf >> 8, - &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = subdev, - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; - u32 conf; - - outp = exec_clkcmp(disp, head, 1, pclk, &conf); - if (!outp) + /* Determine which OR, if any, we're attaching to the head. */ + HEAD_DBG(head, "supervisor 3.0"); + ior = nv50_disp_super_ior_asy(head); + if (!ior) return; - nv50_disp_dptmds_war_3(disp, &outp->info); + /* Execute OnInt3 IED script. */ + nv50_disp_super_ied_on(head, ior, 1, head->asy.hz / 1000); + + /* OR-specific handling. */ + if (ior->func->war_3) + ior->func->war_3(ior); } static void @@ -660,9 +521,8 @@ nv50_disp_super(struct work_struct *work) list_for_each_entry(head, &disp->base.head, head) { if (!(super & (0x00000080 << head->id))) continue; - nv50_disp_intr_unk40_0(disp, head->id); + nv50_disp_super_3_0(disp, head); } - nv50_disp_update_sppll1(disp); } nvkm_wr32(device, 0x610030, 0x80000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index b6092b8b528a..19c635663399 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -30,6 +30,7 @@ void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_0(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_1(struct nv50_disp *, struct nvkm_head *); void nv50_disp_super_2_2(struct nv50_disp *, struct nvkm_head *); +void nv50_disp_super_3_0(struct nv50_disp *, struct nvkm_head *); int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, int index, int heads, struct nvkm_disp **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 7655d9293911..146d101d4891 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -43,10 +43,6 @@ struct nvkm_outp_func { void (*release)(struct nvkm_outp *, struct nvkm_ior *); }; -#define nvkm_output nvkm_outp -#define nvkm_output_func nvkm_outp_func -#define nvkm_output_new_ nvkm_outp_new_ - #define OUTP_MSG(o,l,f,a...) do { \ struct nvkm_outp *_outp = (o); \ nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index bdace3852b37..771a1abbdf15 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include "ior.h" -#include "nv50.h" #include @@ -120,38 +119,6 @@ g94_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) return 0; } -static bool -nv50_disp_dptmds_war(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x94: - case 0x96: - case 0x98: - return true; - default: - break; - } - return false; -} - -static bool -nv50_disp_dptmds_war_needed(struct nv50_disp *disp, struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; - if (nv50_disp_dptmds_war(device) && outp->type == DCB_OUTPUT_TMDS) { - switch (nvkm_rd32(device, 0x614300 + soff) & 0x00030000) { - case 0x00000000: - case 0x00030000: - return true; - default: - break; - } - } - return false; - -} - static bool g94_sor_war_needed(struct nvkm_ior *sor) { @@ -169,18 +136,19 @@ g94_sor_war_needed(struct nvkm_ior *sor) return false; } -void -nv50_disp_update_sppll1(struct nv50_disp *disp) +static void +g94_sor_war_update_sppll1(struct nvkm_disp *disp) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_ior *ior; bool used = false; - int sor; + u32 clksor; - if (!nv50_disp_dptmds_war(device)) - return; + list_for_each_entry(ior, &disp->ior, head) { + if (ior->type != SOR) + continue; - for (sor = 0; sor < disp->func->sor.nr; sor++) { - u32 clksor = nvkm_rd32(device, 0x614300 + (sor * 0x800)); + clksor = nvkm_rd32(device, 0x614300 + nv50_ior_base(ior)); switch (clksor & 0x03000000) { case 0x02000000: case 0x03000000: @@ -197,14 +165,14 @@ nv50_disp_update_sppll1(struct nv50_disp *disp) nvkm_mask(device, 0x00e840, 0x80000000, 0x00000000); } -void -nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) +static void +g94_sor_war_3(struct nvkm_ior *sor) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = __ffs(outp->or) * 0x800; + struct nvkm_device *device = sor->disp->engine.subdev.device; + const u32 soff = nv50_ior_base(sor); u32 sorpwr; - if (!nv50_disp_dptmds_war_needed(disp, outp)) + if (!g94_sor_war_needed(sor)) return; sorpwr = nvkm_rd32(device, 0x61c004 + soff); @@ -235,6 +203,8 @@ nv50_disp_dptmds_war_3(struct nv50_disp *disp, struct dcb_output *outp) if (sorpwr & 0x00000001) { nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000001); } + + g94_sor_war_update_sppll1(sor->disp); } static void @@ -293,6 +263,7 @@ g94_sor = { .power = nv50_sor_power, .clock = nv50_sor_clock, .war_2 = g94_sor_war_2, + .war_3 = g94_sor_war_3, .dp = { .lanes = { 2, 1, 0, 3}, .links = g94_sor_dp_links, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 2095f43e16ac..b58ee99f7bfc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -2278,11 +2278,6 @@ nvbios_exec(struct nvbios_init *init) { struct nvkm_bios *bios = init->subdev->device->bios; - if (init->bios) { - init->or = init->outp ? ffs(init->outp->or) - 1 : -1; - init->link = init->outp ? init->outp->sorconf.link : 0; - } - init->nested++; while (init->offset) { u8 opcode = nvbios_rd08(bios, init->offset); From 2863204c6208f8aabeeec163b9d9e827a3da0858 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:35 +1000 Subject: [PATCH 63/73] drm/nouveau/disp/gm200-: allow non-identity mapping of SOR <-> macro links Finally, everything should be in place to handle this. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index ef201f1597c7..85aff85394ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -137,7 +137,7 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user) /* Failing that, a completely unused OR is the next best thing. */ list_for_each_entry(ior, &outp->disp->ior, head) { if (!ior->asy.outp && ior->type == type && !ior->arm.outp && - ior->id == __ffs(outp->info.or)) + (ior->func->route.set || ior->id == __ffs(outp->info.or))) return nvkm_outp_acquire_ior(outp, user, ior); } @@ -146,7 +146,7 @@ nvkm_outp_acquire(struct nvkm_outp *outp, u8 user) */ list_for_each_entry(ior, &outp->disp->ior, head) { if (!ior->asy.outp && ior->type == type && - ior->id == __ffs(outp->info.or)) + (ior->func->route.set || ior->id == __ffs(outp->info.or))) return nvkm_outp_acquire_ior(outp, user, ior); } From 02e9722da85246c748894734961fbfe0e543c66d Mon Sep 17 00:00:00 2001 From: Oscar Salvador Date: Thu, 18 May 2017 23:24:34 +0200 Subject: [PATCH 64/73] drm/nouveau/hwmon: Add config for all sensors and their settings This is a preparation for the next patches. It just adds the sensors with their possible configurable settings and then fills the struct hwmon_channel_info with all this information. Signed-off-by: Oscar Salvador Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 23b1670c1c2f..24b40c5f0836 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -692,6 +692,78 @@ static const struct attribute_group hwmon_power_attrgroup = { static const struct attribute_group hwmon_power_caps_attrgroup = { .attrs = hwmon_power_caps_attributes, }; + +static const u32 nouveau_config_chip[] = { + HWMON_C_UPDATE_INTERVAL, + 0 +}; + +static const u32 nouveau_config_in[] = { + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_LABEL, + 0 +}; + +static const u32 nouveau_config_temp[] = { + HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST | + HWMON_T_CRIT | HWMON_T_CRIT_HYST | HWMON_T_EMERGENCY | + HWMON_T_EMERGENCY_HYST, + 0 +}; + +static const u32 nouveau_config_fan[] = { + HWMON_F_INPUT, + 0 +}; + +static const u32 nouveau_config_pwm[] = { + HWMON_PWM_INPUT | HWMON_PWM_ENABLE, + 0 +}; + +static const u32 nouveau_config_power[] = { + HWMON_P_INPUT | HWMON_P_CAP_MAX | HWMON_P_CRIT, + 0 +}; + +static const struct hwmon_channel_info nouveau_chip = { + .type = hwmon_chip, + .config = nouveau_config_chip, +}; + +static const struct hwmon_channel_info nouveau_temp = { + .type = hwmon_temp, + .config = nouveau_config_temp, +}; + +static const struct hwmon_channel_info nouveau_fan = { + .type = hwmon_fan, + .config = nouveau_config_fan, +}; + +static const struct hwmon_channel_info nouveau_in = { + .type = hwmon_in, + .config = nouveau_config_in, +}; + +static const struct hwmon_channel_info nouveau_pwm = { + .type = hwmon_pwm, + .config = nouveau_config_pwm, +}; + +static const struct hwmon_channel_info nouveau_power = { + .type = hwmon_power, + .config = nouveau_config_power, +}; + +static const struct hwmon_channel_info *nouveau_info[] = { + &nouveau_chip, + &nouveau_temp, + &nouveau_fan, + &nouveau_in, + &nouveau_pwm, + &nouveau_power, + NULL +}; #endif int From dbddaaf083e255958eee9debb441fb49f3dfc0e9 Mon Sep 17 00:00:00 2001 From: Oscar Salvador Date: Thu, 18 May 2017 23:24:35 +0200 Subject: [PATCH 65/73] drm/nouveau/hwmon: Add nouveau_hwmon_ops structure with .is_visible/.read_string This patch introduces the nouveau_hwmon_ops structure, sets up .is_visible and .read_string operations and adds all the functions for these operations. This is also a preparation for the next patches, where most of the work is being done. This code doesn't interacture with the old one. It's just to make easier the review of all patches. Signed-off-by: Oscar Salvador Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 163 ++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 24b40c5f0836..5ae3107d73df 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -764,6 +764,169 @@ static const struct hwmon_channel_info *nouveau_info[] = { &nouveau_power, NULL }; + +static umode_t +nouveau_chip_is_visible(const void *data, u32 attr, int channel) +{ + switch (attr) { + case hwmon_chip_update_interval: + return 0444; + default: + return 0; + } +} + +static umode_t +nouveau_power_is_visible(const void *data, u32 attr, int channel) +{ + struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data); + struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); + + if (!iccsense || !iccsense->data_valid || list_empty(&iccsense->rails)) + return 0; + + switch (attr) { + case hwmon_power_input: + return 0444; + case hwmon_power_max: + if (iccsense->power_w_max) + return 0444; + return 0; + case hwmon_power_crit: + if (iccsense->power_w_crit) + return 0444; + return 0; + default: + return 0; + } +} + +static umode_t +nouveau_temp_is_visible(const void *data, u32 attr, int channel) +{ + struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (therm && therm->attr_get && nvkm_therm_temp_get(therm) < 0) + return 0; + + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_max: + case hwmon_temp_max_hyst: + case hwmon_temp_crit: + case hwmon_temp_crit_hyst: + case hwmon_temp_emergency: + case hwmon_temp_emergency_hyst: + return 0444; + default: + return 0; + } +} + +static umode_t +nouveau_pwm_is_visible(const void *data, u32 attr, int channel) +{ + struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (therm && therm->attr_get && therm->fan_get && + therm->fan_get(therm) < 0) + return 0; + + switch (attr) { + case hwmon_pwm_enable: + case hwmon_pwm_input: + return 0644; + default: + return 0; + } +} + +static umode_t +nouveau_input_is_visible(const void *data, u32 attr, int channel) +{ + struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data); + struct nvkm_volt *volt = nvxx_volt(&drm->client.device); + + if (!volt || nvkm_volt_get(volt) < 0) + return 0; + + switch (attr) { + case hwmon_in_input: + case hwmon_in_label: + case hwmon_in_min: + case hwmon_in_max: + return 0444; + default: + return 0; + } +} + +static umode_t +nouveau_fan_is_visible(const void *data, u32 attr, int channel) +{ + struct nouveau_drm *drm = nouveau_drm((struct drm_device *)data); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (!therm || !therm->attr_get || nvkm_therm_fan_sense(therm) < 0) + return 0; + + switch (attr) { + case hwmon_fan_input: + return 0444; + default: + return 0; + } +} + +static umode_t +nouveau_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, + int channel) +{ + switch (type) { + case hwmon_chip: + return nouveau_chip_is_visible(data, attr, channel); + case hwmon_temp: + return nouveau_temp_is_visible(data, attr, channel); + case hwmon_fan: + return nouveau_fan_is_visible(data, attr, channel); + case hwmon_in: + return nouveau_input_is_visible(data, attr, channel); + case hwmon_pwm: + return nouveau_pwm_is_visible(data, attr, channel); + case hwmon_power: + return nouveau_power_is_visible(data, attr, channel); + default: + return 0; + } +} + +static const char input_label[] = "GPU core"; + +static int +nouveau_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, const char **buf) +{ + if (type == hwmon_in && attr == hwmon_in_label) { + *buf = input_label; + return 0; + } + + return -EOPNOTSUPP; +} + +static const struct hwmon_ops nouveau_hwmon_ops = { + .is_visible = nouveau_is_visible, + .read = NULL, + .read_string = nouveau_read_string, + .write = NULL, +}; + +static const struct hwmon_chip_info nouveau_chip_info = { + .ops = &nouveau_hwmon_ops, + .info = nouveau_info, +}; #endif int From bfb96e4c344e312858f53c9cad22150389a76cba Mon Sep 17 00:00:00 2001 From: Oscar Salvador Date: Thu, 18 May 2017 23:24:36 +0200 Subject: [PATCH 66/73] drm/nouveau/hwmon: Remove old code, add .write/.read operations This patch removes old code related to the old api and transforms the functions for the new api. It also adds the .write and .read operations. Signed-off-by: Oscar Salvador Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 844 ++++++++---------------- 1 file changed, 261 insertions(+), 583 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 5ae3107d73df..bb0718579c2c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -38,21 +38,6 @@ #include #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) -static ssize_t -nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - int temp = nvkm_therm_temp_get(therm); - - if (temp < 0) - return temp; - - return snprintf(buf, PAGE_SIZE, "%d\n", temp * 1000); -} -static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp, - NULL, 0); static ssize_t nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d, @@ -130,234 +115,7 @@ static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0); static ssize_t -nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000); -} -static ssize_t -nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a, - const char *buf, size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp, - nouveau_hwmon_set_max_temp, - 0); - -static ssize_t -nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000); -} -static ssize_t -nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a, - const char *buf, size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST, - value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - nouveau_hwmon_max_temp_hyst, - nouveau_hwmon_set_max_temp_hyst, 0); - -static ssize_t -nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000); -} -static ssize_t -nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a, - const char *buf, - size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, - nouveau_hwmon_critical_temp, - nouveau_hwmon_set_critical_temp, - 0); - -static ssize_t -nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) * 1000); -} -static ssize_t -nouveau_hwmon_set_critical_temp_hyst(struct device *d, - struct device_attribute *a, - const char *buf, - size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST, - value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO | S_IWUSR, - nouveau_hwmon_critical_temp_hyst, - nouveau_hwmon_set_critical_temp_hyst, 0); -static ssize_t -nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000); -} -static ssize_t -nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a, - const char *buf, - size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_emergency, S_IRUGO | S_IWUSR, - nouveau_hwmon_emergency_temp, - nouveau_hwmon_set_emergency_temp, - 0); - -static ssize_t -nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", - therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000); -} -static ssize_t -nouveau_hwmon_set_emergency_temp_hyst(struct device *d, - struct device_attribute *a, - const char *buf, - size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return count; - - therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST, - value / 1000); - - return count; -} -static SENSOR_DEVICE_ATTR(temp1_emergency_hyst, S_IRUGO | S_IWUSR, - nouveau_hwmon_emergency_temp_hyst, - nouveau_hwmon_set_emergency_temp_hyst, - 0); - -static ssize_t nouveau_hwmon_show_name(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "nouveau\n"); -} -static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0); - -static ssize_t nouveau_hwmon_show_update_rate(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "1000\n"); -} -static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO, - nouveau_hwmon_show_update_rate, - NULL, 0); - -static ssize_t -nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - - return snprintf(buf, PAGE_SIZE, "%d\n", nvkm_therm_fan_sense(therm)); -} -static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input, - NULL, 0); - - static ssize_t -nouveau_hwmon_get_pwm1_enable(struct device *d, +nouveau_hwmon_get_pwm1_max(struct device *d, struct device_attribute *a, char *buf) { struct drm_device *dev = dev_get_drvdata(d); @@ -365,76 +123,13 @@ nouveau_hwmon_get_pwm1_enable(struct device *d, struct nvkm_therm *therm = nvxx_therm(&drm->client.device); int ret; - ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE); + ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY); if (ret < 0) return ret; return sprintf(buf, "%i\n", ret); } -static ssize_t -nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, - const char *buf, size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - long value; - int ret; - - ret = kstrtol(buf, 10, &value); - if (ret) - return ret; - - ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value); - if (ret) - return ret; - else - return count; -} -static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, - nouveau_hwmon_get_pwm1_enable, - nouveau_hwmon_set_pwm1_enable, 0); - -static ssize_t -nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - int ret; - - ret = therm->fan_get(therm); - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret); -} - -static ssize_t -nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a, - const char *buf, size_t count) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - int ret = -ENODEV; - long value; - - if (kstrtol(buf, 10, &value) == -EINVAL) - return -EINVAL; - - ret = therm->fan_set(therm, value); - if (ret) - return ret; - - return count; -} - -static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, - nouveau_hwmon_get_pwm1, - nouveau_hwmon_set_pwm1, 0); - static ssize_t nouveau_hwmon_get_pwm1_min(struct device *d, struct device_attribute *a, char *buf) @@ -470,27 +165,10 @@ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, return count; } - static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, nouveau_hwmon_get_pwm1_min, nouveau_hwmon_set_pwm1_min, 0); -static ssize_t -nouveau_hwmon_get_pwm1_max(struct device *d, - struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - int ret; - - ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY); - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret); -} - static ssize_t nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, const char *buf, size_t count) @@ -510,189 +188,10 @@ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, return count; } - static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_get_pwm1_max, nouveau_hwmon_set_pwm1_max, 0); -static ssize_t -nouveau_hwmon_get_in0_input(struct device *d, - struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_volt *volt = nvxx_volt(&drm->client.device); - int ret; - - ret = nvkm_volt_get(volt); - if (ret < 0) - return ret; - - return sprintf(buf, "%i\n", ret / 1000); -} - -static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, - nouveau_hwmon_get_in0_input, NULL, 0); - -static ssize_t -nouveau_hwmon_get_in0_min(struct device *d, - struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_volt *volt = nvxx_volt(&drm->client.device); - - if (!volt || !volt->min_uv) - return -ENODEV; - - return sprintf(buf, "%i\n", volt->min_uv / 1000); -} - -static SENSOR_DEVICE_ATTR(in0_min, S_IRUGO, - nouveau_hwmon_get_in0_min, NULL, 0); - -static ssize_t -nouveau_hwmon_get_in0_max(struct device *d, - struct device_attribute *a, char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_volt *volt = nvxx_volt(&drm->client.device); - - if (!volt || !volt->max_uv) - return -ENODEV; - - return sprintf(buf, "%i\n", volt->max_uv / 1000); -} - -static SENSOR_DEVICE_ATTR(in0_max, S_IRUGO, - nouveau_hwmon_get_in0_max, NULL, 0); - -static ssize_t -nouveau_hwmon_get_in0_label(struct device *d, - struct device_attribute *a, char *buf) -{ - return sprintf(buf, "GPU core\n"); -} - -static SENSOR_DEVICE_ATTR(in0_label, S_IRUGO, - nouveau_hwmon_get_in0_label, NULL, 0); - -static ssize_t -nouveau_hwmon_get_power1_input(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); - int result = nvkm_iccsense_read_all(iccsense); - - if (result < 0) - return result; - - return sprintf(buf, "%i\n", result); -} - -static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, - nouveau_hwmon_get_power1_input, NULL, 0); - -static ssize_t -nouveau_hwmon_get_power1_max(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); - return sprintf(buf, "%i\n", iccsense->power_w_max); -} - -static SENSOR_DEVICE_ATTR(power1_max, S_IRUGO, - nouveau_hwmon_get_power1_max, NULL, 0); - -static ssize_t -nouveau_hwmon_get_power1_crit(struct device *d, struct device_attribute *a, - char *buf) -{ - struct drm_device *dev = dev_get_drvdata(d); - struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); - return sprintf(buf, "%i\n", iccsense->power_w_crit); -} - -static SENSOR_DEVICE_ATTR(power1_crit, S_IRUGO, - nouveau_hwmon_get_power1_crit, NULL, 0); - -static struct attribute *hwmon_default_attributes[] = { - &sensor_dev_attr_name.dev_attr.attr, - &sensor_dev_attr_update_rate.dev_attr.attr, - NULL -}; -static struct attribute *hwmon_temp_attributes[] = { - &sensor_dev_attr_temp1_input.dev_attr.attr, - &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, - &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, - &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_crit.dev_attr.attr, - &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, - &sensor_dev_attr_temp1_emergency.dev_attr.attr, - &sensor_dev_attr_temp1_emergency_hyst.dev_attr.attr, - NULL -}; -static struct attribute *hwmon_fan_rpm_attributes[] = { - &sensor_dev_attr_fan1_input.dev_attr.attr, - NULL -}; -static struct attribute *hwmon_pwm_fan_attributes[] = { - &sensor_dev_attr_pwm1_enable.dev_attr.attr, - &sensor_dev_attr_pwm1.dev_attr.attr, - &sensor_dev_attr_pwm1_min.dev_attr.attr, - &sensor_dev_attr_pwm1_max.dev_attr.attr, - NULL -}; - -static struct attribute *hwmon_in0_attributes[] = { - &sensor_dev_attr_in0_input.dev_attr.attr, - &sensor_dev_attr_in0_min.dev_attr.attr, - &sensor_dev_attr_in0_max.dev_attr.attr, - &sensor_dev_attr_in0_label.dev_attr.attr, - NULL -}; - -static struct attribute *hwmon_power_attributes[] = { - &sensor_dev_attr_power1_input.dev_attr.attr, - NULL -}; - -static struct attribute *hwmon_power_caps_attributes[] = { - &sensor_dev_attr_power1_max.dev_attr.attr, - &sensor_dev_attr_power1_crit.dev_attr.attr, - NULL -}; - -static const struct attribute_group hwmon_default_attrgroup = { - .attrs = hwmon_default_attributes, -}; -static const struct attribute_group hwmon_temp_attrgroup = { - .attrs = hwmon_temp_attributes, -}; -static const struct attribute_group hwmon_fan_rpm_attrgroup = { - .attrs = hwmon_fan_rpm_attributes, -}; -static const struct attribute_group hwmon_pwm_fan_attrgroup = { - .attrs = hwmon_pwm_fan_attributes, -}; -static const struct attribute_group hwmon_in0_attrgroup = { - .attrs = hwmon_in0_attributes, -}; -static const struct attribute_group hwmon_power_attrgroup = { - .attrs = hwmon_power_attributes, -}; -static const struct attribute_group hwmon_power_caps_attrgroup = { - .attrs = hwmon_power_caps_attributes, -}; - static const u32 nouveau_config_chip[] = { HWMON_C_UPDATE_INTERVAL, 0 @@ -812,13 +311,14 @@ nouveau_temp_is_visible(const void *data, u32 attr, int channel) switch (attr) { case hwmon_temp_input: + return 0444; case hwmon_temp_max: case hwmon_temp_max_hyst: case hwmon_temp_crit: case hwmon_temp_crit_hyst: case hwmon_temp_emergency: case hwmon_temp_emergency_hyst: - return 0444; + return 0644; default: return 0; } @@ -880,6 +380,222 @@ nouveau_fan_is_visible(const void *data, u32 attr, int channel) } } +static int +nouveau_chip_read(struct device *dev, u32 attr, int channel, long *val) +{ + switch (attr) { + case hwmon_chip_update_interval: + *val = 1000; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_temp_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + int ret; + + if (!therm || !therm->attr_get) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_temp_input: + ret = nvkm_therm_temp_get(therm); + *val = ret < 0 ? ret : (ret * 1000); + break; + case hwmon_temp_max: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) + * 1000; + break; + case hwmon_temp_max_hyst: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) + * 1000; + break; + case hwmon_temp_crit: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) + * 1000; + break; + case hwmon_temp_crit_hyst: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) + * 1000; + break; + case hwmon_temp_emergency: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) + * 1000; + break; + case hwmon_temp_emergency_hyst: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) + * 1000; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_fan_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (!therm) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_fan_input: + *val = nvkm_therm_fan_sense(therm); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_in_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_volt *volt = nvxx_volt(&drm->client.device); + int ret; + + if (!volt) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_in_input: + ret = nvkm_volt_get(volt); + *val = ret < 0 ? ret : (ret / 1000); + break; + case hwmon_in_min: + *val = volt->min_uv > 0 ? (volt->min_uv / 1000) : -ENODEV; + break; + case hwmon_in_max: + *val = volt->max_uv > 0 ? (volt->max_uv / 1000) : -ENODEV; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_pwm_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (!therm || !therm->attr_get || !therm->fan_get) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_pwm_enable: + *val = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE); + break; + case hwmon_pwm_input: + *val = therm->fan_get(therm); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_power_read(struct device *dev, u32 attr, int channel, long *val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); + + if (!iccsense) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_power_input: + *val = nvkm_iccsense_read_all(iccsense); + break; + case hwmon_power_max: + *val = iccsense->power_w_max; + break; + case hwmon_power_crit: + *val = iccsense->power_w_crit; + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} + +static int +nouveau_temp_write(struct device *dev, u32 attr, int channel, long val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (!therm || !therm->attr_set) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_temp_max: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, + val / 1000); + case hwmon_temp_max_hyst: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST, + val / 1000); + case hwmon_temp_crit: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, + val / 1000); + case hwmon_temp_crit_hyst: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST, + val / 1000); + case hwmon_temp_emergency: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, + val / 1000); + case hwmon_temp_emergency_hyst: + return therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST, + val / 1000); + default: + return -EOPNOTSUPP; + } +} + +static int +nouveau_pwm_write(struct device *dev, u32 attr, int channel, long val) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + struct nouveau_drm *drm = nouveau_drm(drm_dev); + struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + + if (!therm || !therm->attr_set) + return -EOPNOTSUPP; + + switch (attr) { + case hwmon_pwm_input: + return therm->fan_set(therm, val); + case hwmon_pwm_enable: + return therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, val); + default: + return -EOPNOTSUPP; + } +} + static umode_t nouveau_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -916,11 +632,47 @@ nouveau_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr, return -EOPNOTSUPP; } +static int +nouveau_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long *val) +{ + switch (type) { + case hwmon_chip: + return nouveau_chip_read(dev, attr, channel, val); + case hwmon_temp: + return nouveau_temp_read(dev, attr, channel, val); + case hwmon_fan: + return nouveau_fan_read(dev, attr, channel, val); + case hwmon_in: + return nouveau_in_read(dev, attr, channel, val); + case hwmon_pwm: + return nouveau_pwm_read(dev, attr, channel, val); + case hwmon_power: + return nouveau_power_read(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + +static int +nouveau_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, + int channel, long val) +{ + switch (type) { + case hwmon_temp: + return nouveau_temp_write(dev, attr, channel, val); + case hwmon_pwm: + return nouveau_pwm_write(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + static const struct hwmon_ops nouveau_hwmon_ops = { .is_visible = nouveau_is_visible, - .read = NULL, + .read = nouveau_read, .read_string = nouveau_read_string, - .write = NULL, + .write = nouveau_write, }; static const struct hwmon_chip_info nouveau_chip_info = { @@ -935,8 +687,6 @@ nouveau_hwmon_init(struct drm_device *dev) #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->client.device); - struct nvkm_volt *volt = nvxx_volt(&drm->client.device); - struct nvkm_iccsense *iccsense = nvxx_iccsense(&drm->client.device); struct nouveau_hwmon *hwmon; struct device *hwmon_dev; int ret = 0; @@ -946,79 +696,16 @@ nouveau_hwmon_init(struct drm_device *dev) return -ENOMEM; hwmon->dev = dev; - hwmon_dev = hwmon_device_register(dev->dev); + hwmon_dev = hwmon_device_register_with_info(dev->dev, "nouveau", dev, + &nouveau_chip_info, NULL); if (IS_ERR(hwmon_dev)) { ret = PTR_ERR(hwmon_dev); NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret); return ret; } - dev_set_drvdata(hwmon_dev, dev); - - /* set the default attributes */ - ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup); - if (ret) - goto error; - - if (therm && therm->attr_get && therm->attr_set) { - /* if the card has a working thermal sensor */ - if (nvkm_therm_temp_get(therm) >= 0) { - ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); - if (ret) - goto error; - } - - /* if the card has a pwm fan */ - /*XXX: incorrect, need better detection for this, some boards have - * the gpio entries for pwm fan control even when there's no - * actual fan connected to it... therm table? */ - if (therm->fan_get && therm->fan_get(therm) >= 0) { - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_pwm_fan_attrgroup); - if (ret) - goto error; - } - } - - /* if the card can read the fan rpm */ - if (therm && nvkm_therm_fan_sense(therm) >= 0) { - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_fan_rpm_attrgroup); - if (ret) - goto error; - } - - if (volt && nvkm_volt_get(volt) >= 0) { - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_in0_attrgroup); - - if (ret) - goto error; - } - - if (iccsense && iccsense->data_valid && !list_empty(&iccsense->rails)) { - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_power_attrgroup); - - if (ret) - goto error; - - if (iccsense->power_w_max && iccsense->power_w_crit) { - ret = sysfs_create_group(&hwmon_dev->kobj, - &hwmon_power_caps_attrgroup); - if (ret) - goto error; - } - } hwmon->hwmon = hwmon_dev; - return 0; - -error: - NV_ERROR(drm, "Unable to create some hwmon sysfs files: %d\n", ret); - hwmon_device_unregister(hwmon_dev); - hwmon->hwmon = NULL; - return ret; #else return 0; #endif @@ -1030,17 +717,8 @@ nouveau_hwmon_fini(struct drm_device *dev) #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct nouveau_hwmon *hwmon = nouveau_hwmon(dev); - if (hwmon->hwmon) { - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_default_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_temp_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_pwm_fan_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_fan_rpm_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_in0_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_power_attrgroup); - sysfs_remove_group(&hwmon->hwmon->kobj, &hwmon_power_caps_attrgroup); - + if (hwmon->hwmon) hwmon_device_unregister(hwmon->hwmon); - } nouveau_drm(dev)->hwmon = NULL; kfree(hwmon); From b28d78f1876f32692a122f5fb2f080363678ab2f Mon Sep 17 00:00:00 2001 From: Oscar Salvador Date: Thu, 18 May 2017 23:24:37 +0200 Subject: [PATCH 67/73] drm/nouveau/hwmon: expose the auto_point and pwm_min/max attrs This patch creates a special group attributes for attrs like "*auto_point*". We check if we have support for them, and if we do, we gather them all in an attribute_group's structure which is the parameter regarding special groups of hwmon_device_register_with_info We also do the same for pwm_min/max attrs. Signed-off-by: Oscar Salvador Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 34 ++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index bb0718579c2c..2304189addcb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -192,6 +192,27 @@ static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_get_pwm1_max, nouveau_hwmon_set_pwm1_max, 0); +static struct attribute *pwm_fan_sensor_attrs[] = { + &sensor_dev_attr_pwm1_min.dev_attr.attr, + &sensor_dev_attr_pwm1_max.dev_attr.attr, + NULL +}; +static const struct attribute_group pwm_fan_sensor_group = { + .attrs = pwm_fan_sensor_attrs, +}; + +static struct attribute *temp1_auto_point_sensor_attrs[] = { + &sensor_dev_attr_temp1_auto_point1_pwm.dev_attr.attr, + &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, + &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr, + NULL +}; +static const struct attribute_group temp1_auto_point_sensor_group = { + .attrs = temp1_auto_point_sensor_attrs, +}; + +#define N_ATTR_GROUPS 3 + static const u32 nouveau_config_chip[] = { HWMON_C_UPDATE_INTERVAL, 0 @@ -687,17 +708,28 @@ nouveau_hwmon_init(struct drm_device *dev) #if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->client.device); + const struct attribute_group *special_groups[N_ATTR_GROUPS]; struct nouveau_hwmon *hwmon; struct device *hwmon_dev; int ret = 0; + int i = 0; hwmon = drm->hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL); if (!hwmon) return -ENOMEM; hwmon->dev = dev; + if (therm && therm->attr_get && therm->attr_set) { + if (nvkm_therm_temp_get(therm) >= 0) + special_groups[i++] = &temp1_auto_point_sensor_group; + if (therm->fan_get && therm->fan_get(therm) >= 0) + special_groups[i++] = &pwm_fan_sensor_group; + } + + special_groups[i] = 0; hwmon_dev = hwmon_device_register_with_info(dev->dev, "nouveau", dev, - &nouveau_chip_info, NULL); + &nouveau_chip_info, + special_groups); if (IS_ERR(hwmon_dev)) { ret = PTR_ERR(hwmon_dev); NV_ERROR(drm, "Unable to register hwmon device: %d\n", ret); From 3a93dd2243c6af8a52edad675c11a6cdaef969c6 Mon Sep 17 00:00:00 2001 From: Oscar Salvador Date: Thu, 18 May 2017 23:24:38 +0200 Subject: [PATCH 68/73] drm/nouveau/hwmon: Change permissions to numeric This patch replaces the symbolic permissions with the numeric ones. Signed-off-by: Oscar Salvador Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 2304189addcb..7c965648df80 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -45,7 +45,7 @@ nouveau_hwmon_show_temp1_auto_point1_pwm(struct device *d, { return snprintf(buf, PAGE_SIZE, "%d\n", 100); } -static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO, +static SENSOR_DEVICE_ATTR(temp1_auto_point1_pwm, 0444, nouveau_hwmon_show_temp1_auto_point1_pwm, NULL, 0); static ssize_t @@ -77,7 +77,7 @@ nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d, return count; } -static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, S_IRUGO | S_IWUSR, +static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp, 0644, nouveau_hwmon_temp1_auto_point1_temp, nouveau_hwmon_set_temp1_auto_point1_temp, 0); @@ -110,7 +110,7 @@ nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d, return count; } -static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, S_IRUGO | S_IWUSR, +static SENSOR_DEVICE_ATTR(temp1_auto_point1_temp_hyst, 0644, nouveau_hwmon_temp1_auto_point1_temp_hyst, nouveau_hwmon_set_temp1_auto_point1_temp_hyst, 0); @@ -165,7 +165,7 @@ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a, return count; } -static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, +static SENSOR_DEVICE_ATTR(pwm1_min, 0644, nouveau_hwmon_get_pwm1_min, nouveau_hwmon_set_pwm1_min, 0); @@ -188,7 +188,7 @@ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a, return count; } -static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO | S_IWUSR, +static SENSOR_DEVICE_ATTR(pwm1_max, 0644, nouveau_hwmon_get_pwm1_max, nouveau_hwmon_set_pwm1_max, 0); From b1df242544b9477dd529b468c13066b66a3f9e97 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 9 Jun 2017 15:25:39 +0300 Subject: [PATCH 69/73] drm/nouveau/tegra: Skip manual unpowergating when not necessary On Tegra186, powergating is handled by the BPMP power domain provider and the "legacy" powergating API is not available. Therefore skip these calls if we are attached to a power domain. Signed-off-by: Mikko Perttunen Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 6474bd2a6d07..3d42cdbbe9c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -51,10 +51,12 @@ nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) reset_control_assert(tdev->rst); udelay(10); - ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); - if (ret) - goto err_clamp; - udelay(10); + if (!tdev->pdev->dev.pm_domain) { + ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); + if (ret) + goto err_clamp; + udelay(10); + } reset_control_deassert(tdev->rst); udelay(10); From fcd504e31292c9fdba07bcd44350c145bc214183 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 9 Jun 2017 15:25:40 +0300 Subject: [PATCH 70/73] drm/nouveau/tegra: Don't leave GPU in reset On Tegra186 systems with certain firmware revisions, leaving the GPU in reset can cause a hang. To prevent this, don't leave the GPU in reset. Signed-off-by: Mikko Perttunen Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 3d42cdbbe9c0..189ed80e21ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -82,9 +82,6 @@ nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev) { int ret; - reset_control_assert(tdev->rst); - udelay(10); - clk_disable_unprepare(tdev->clk_pwr); if (tdev->clk_ref) clk_disable_unprepare(tdev->clk_ref); From 876ea7be6a71614ef80c05037350a2ff986e3a80 Mon Sep 17 00:00:00 2001 From: Mikko Perttunen Date: Fri, 9 Jun 2017 15:25:41 +0300 Subject: [PATCH 71/73] drm/nouveau: Skip vga_fini on non-PCI device As with vga_init, this function doesn't make sense on non-PCI devices, and the Thunderbolt check in it dereferences a NULL pointer in that case. Add some code to skip this function when the device is not a PCI device. Signed-off-by: Mikko Perttunen Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_vga.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 02fe0efb9e16..48393a4f6331 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -111,6 +111,10 @@ nouveau_vga_fini(struct nouveau_drm *drm) struct drm_device *dev = drm->dev; bool runtime = nouveau_pmops_runtime(); + /* only relevant for PCI devices */ + if (!dev->pdev) + return; + vga_client_register(dev->pdev, NULL, NULL, NULL); if (pci_is_thunderbolt_attached(dev->pdev)) From 5499473c86503bb8e307ff7b554643a99a9478c2 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Jun 2017 12:38:33 +0200 Subject: [PATCH 72/73] drm/nouveau: use proper prototype in nouveau_pmops_runtime() definition There is a prototype for this function in the header, but the function itself lacks a 'void' in the argument list, causing a harmless warning when building with 'make W=1': drivers/gpu/drm/nouveau/nouveau_drm.c: In function 'nouveau_pmops_runtime': drivers/gpu/drm/nouveau/nouveau_drm.c:730:1: error: old-style function definition [-Werror=old-style-definition] Fixes: 321f5c5f2c49 ("drm/nouveau: replace multiple open-coded runpm support checks with function") Signed-off-by: Arnd Bergmann Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 7acd1cf8c5a6..90757af9bc73 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -727,7 +727,7 @@ nouveau_pmops_thaw(struct device *dev) } bool -nouveau_pmops_runtime() +nouveau_pmops_runtime(void) { if (nouveau_runtime_pm == -1) return nouveau_is_optimus() || nouveau_is_v1_dsm(); From 7df1bb87b8cb0b618e4b5964f89d81d8ce52c58e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sat, 17 Jun 2017 11:19:22 +1000 Subject: [PATCH 73/73] drm/nouveau/disp/nv50-: avoid creating ORs that aren't present on HW Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c | 11 ++++++++++- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c | 11 ++++++++++- 14 files changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c index 8392303b77ed..dbd032ef352a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacgf119.c @@ -58,5 +58,8 @@ gf119_dac = { int gf119_dac_new(struct nvkm_disp *disp, int id) { + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x612004) & (0x00000010 << id))) + return 0; return nvkm_ior_new_(&gf119_dac, disp, DAC, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 119cd02a2000..85e692b12260 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -109,5 +109,8 @@ nv50_dac = { int nv50_dac_new(struct nvkm_disp *disp, int id) { + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x610184) & (0x00100000 << id))) + return 0; return nvkm_ior_new_(&nv50_dac, disp, DAC, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h index 1e11e25a41f1..a24312fb0228 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h @@ -104,6 +104,7 @@ nv50_sor_link(struct nvkm_ior *ior) return nv50_ior_base(ior) + ((ior->asy.link == 2) * 0x80); } +int nv50_sor_new_(const struct nvkm_ior_func *, struct nvkm_disp *, int id); void nv50_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void nv50_sor_power(struct nvkm_ior *, bool, bool, bool, bool, bool); void nv50_sor_clock(struct nvkm_ior *); @@ -119,6 +120,7 @@ void g94_sor_dp_watermark(struct nvkm_ior *, int, u8); void gt215_sor_dp_audio(struct nvkm_ior *, int, bool); +int gf119_sor_new_(const struct nvkm_ior_func *, struct nvkm_disp *, int id); void gf119_sor_state(struct nvkm_ior *, struct nvkm_ior_state *); void gf119_sor_clock(struct nvkm_ior *); int gf119_sor_dp_links(struct nvkm_ior *, struct nvkm_i2c_aux *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index a1f24ef222c1..99b3b9050635 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -127,5 +127,8 @@ nv50_pior = { int nv50_pior_new(struct nvkm_disp *disp, int id) { + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x610184) & (0x10000000 << id))) + return 0; return nvkm_ior_new_(&nv50_pior, disp, PIOR, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c index ec3a7db08118..f40b909b4ca2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg84.c @@ -34,5 +34,5 @@ g84_sor = { int g84_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&g84_sor, disp, SOR, id); + return nv50_sor_new_(&g84_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 771a1abbdf15..49aeafde0031 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -279,5 +279,5 @@ g94_sor = { int g94_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&g94_sor, disp, SOR, id); + return nv50_sor_new_(&g94_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 5f8306b00f71..a2978a37b4f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -152,6 +152,15 @@ gf119_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) state->head = ctrl & 0x0000000f; } +int +gf119_sor_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, int id) +{ + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x612004) & (0x00000100 << id))) + return 0; + return nvkm_ior_new_(func, disp, SOR, id); +} + static const struct nvkm_ior_func gf119_sor = { .state = gf119_sor_state, @@ -179,5 +188,5 @@ gf119_sor = { int gf119_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&gf119_sor, disp, SOR, id); + return gf119_sor_new_(&gf119_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c index b94090edaebf..a1547bdf490b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgk104.c @@ -49,5 +49,5 @@ gk104_sor = { int gk104_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&gk104_sor, disp, SOR, id); + return gf119_sor_new_(&gk104_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c index e6965dec09c9..60230957d82b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm107.c @@ -63,5 +63,5 @@ gm107_sor = { int gm107_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&gm107_sor, disp, SOR, id); + return gf119_sor_new_(&gm107_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c index 8bc019b6ffab..f9b8107aa2a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm200.c @@ -120,5 +120,5 @@ gm200_sor = { int gm200_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&gm200_sor, disp, SOR, id); + return gf119_sor_new_(&gm200_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c index 54d134d4ca1d..da228b54b43e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgt215.c @@ -65,5 +65,5 @@ gt215_sor = { int gt215_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(>215_sor, disp, SOR, id); + return nv50_sor_new_(>215_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c index 8a70dd25b13a..c0179ccb956d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp77.c @@ -44,5 +44,5 @@ mcp77_sor = { int mcp77_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&mcp77_sor, disp, SOR, id); + return nv50_sor_new_(&mcp77_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c index eac9c5be9166..9bb01cd96697 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sormcp89.c @@ -49,5 +49,5 @@ mcp89_sor = { int mcp89_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&mcp89_sor, disp, SOR, id); + return nv50_sor_new_(&mcp89_sor, disp, id); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index dbb303db3178..f3ebd0c22e7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -84,6 +84,15 @@ nv50_sor_state(struct nvkm_ior *sor, struct nvkm_ior_state *state) state->head = ctrl & 0x00000003; } +int +nv50_sor_new_(const struct nvkm_ior_func *func, struct nvkm_disp *disp, int id) +{ + struct nvkm_device *device = disp->engine.subdev.device; + if (!(nvkm_rd32(device, 0x610184) & (0x01000000 << id))) + return 0; + return nvkm_ior_new_(func, disp, SOR, id); +} + static const struct nvkm_ior_func nv50_sor = { .state = nv50_sor_state, @@ -94,5 +103,5 @@ nv50_sor = { int nv50_sor_new(struct nvkm_disp *disp, int id) { - return nvkm_ior_new_(&nv50_sor, disp, SOR, id); + return nv50_sor_new_(&nv50_sor, disp, id); }