From 35dd9874bf6138ab290c7f58020fcdc88f508805 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:16 -0400 Subject: 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; } -- cgit v1.2.3 From 31fe2c200262a512255340d6f9493d51e06a8207 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:17 -0400 Subject: 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); -- cgit v1.2.3 From 34fd3e5d8c5f6bdcc2245084036680a4bfc23370 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:18 -0400 Subject: 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); } -- cgit v1.2.3 From f60213c0ee93ffb89a64bad9a5db52e854530b1d Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:19 -0400 Subject: 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 --- drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 1 + .../drm/nouveau/nvkm/engine/disp/hdmi_infoframe.c | 66 ++++++++++++++++++++++ drivers/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); -- cgit v1.2.3 From a45f7908b3ac4691d9abba5fc480ba0f718db3ea Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:20 -0400 Subject: 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 --- drivers/gpu/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 */ -- cgit v1.2.3 From ba32836879c32b027adacf0bad4a5c62f22d2173 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:21 -0400 Subject: 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 --- .../gpu/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 */ -- cgit v1.2.3 From 2709b275c5d7ad01ae08cad004587f479aa3ea95 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:22 -0400 Subject: 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 --- .../gpu/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); -- cgit v1.2.3 From a8970743502f6e52297fca4181ae524041119106 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:23 -0400 Subject: 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 --- .../gpu/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); -- cgit v1.2.3 From 37aa2243ff4985c0bdf309bf951f2cdd680fbe5c Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:24 -0400 Subject: 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 -- cgit v1.2.3 From 0f18d2765ab1ab9530e1b80dc1bc247c8b13cef7 Mon Sep 17 00:00:00 2001 From: Alastair Bridgewater Date: Tue, 11 Apr 2017 13:11:25 -0400 Subject: 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; -- cgit v1.2.3 From c0cd04700f5c88145602b35c24e9128767a4ad69 Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 23 Apr 2017 10:36:31 +0200 Subject: 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); -- cgit v1.2.3 From 4dc33b12229fc540dc69b0d4aced60672bab142d Mon Sep 17 00:00:00 2001 From: Karol Herbst Date: Sun, 23 Apr 2017 20:06:37 +0200 Subject: 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; -- cgit v1.2.3 From 7eaf1198a9aaa9c31c9270e370088d8a79c149ab Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 11 May 2017 17:29:58 +1000 Subject: 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) { -- cgit v1.2.3 From 4bb4a7466af6d96d4fc8471336eb738d13c2471c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: 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 -- cgit v1.2.3 From 5b0e787ad599a8e6803daf743dfc4642018ba469 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 19 May 2017 23:59:34 +1000 Subject: 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 --- drivers/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 +136