v4 was: http://lists.freedesktop.org/archives/dri-devel/2013-September/045340.html
Changes from v4:
- The kernel is now in charge of adjusting the stereo mode timings. - There is a per-connector opt-in boolean to expose stereo modes, letting people enable stereo for each driver/connector. - The series now depends on the latest bits from the drm-intel tree - Removed the 2 buffers check that was judged unnecessary - I realized that for frame packing modes (where you have to adjust the vdisplay to be 2 * vdisplay + vblank) with a NTSC clock I was reconstructing the clock without adjusting it by 1000 / 1001. Now that the timing computation is in the kernel, fixed it there. - I also checked that we correctly match against the 2D CEA mode for the AVI infoframes. The last bit to make it work was the introduction of crtc_clock to separate the original clock from the one computed by drm_mode_set_crtcinfo() - And finally, I booted with i915.fastboot=1 and discovered that the pipe_src register was getting clobbered, so fixed that as well
This ioctl can be used to turn some knobs in a DRM driver. The client can ask the DRM core for an alternate view of the reality: it can be useful to be able to instruct the core that the DRM client can handle new functionnality that would otherwise break current ABI.
v2: Rename to ioctl from SET_CAP to SET_CLIENT_CAP (Chris Wilson)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_drv.c | 1 + drivers/gpu/drm/drm_ioctl.c | 9 +++++++++ include/drm/drmP.h | 2 ++ include/uapi/drm/drm.h | 7 +++++++ 4 files changed, 19 insertions(+)
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index e572dd2..e79d8d9 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -69,6 +69,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_GET_CLIENT, drm_getclient, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GET_STATS, drm_getstats, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_GET_CAP, drm_getcap, DRM_UNLOCKED|DRM_RENDER_ALLOW), + DRM_IOCTL_DEF(DRM_IOCTL_SET_CLIENT_CAP, drm_setclientcap, 0), DRM_IOCTL_DEF(DRM_IOCTL_SET_VERSION, drm_setversion, DRM_MASTER),
DRM_IOCTL_DEF(DRM_IOCTL_SET_UNIQUE, drm_setunique, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 07247e2..15da412 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -303,6 +303,15 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) }
/** + * Set device/driver capabilities + */ +int +drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) +{ + return -EINVAL; +} + +/** * Setversion ioctl. * * \param inode device inode. diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 2907341..782433b 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -1303,6 +1303,8 @@ extern int drm_getstats(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv); +extern int drm_setclientcap(struct drm_device *dev, void *data, + struct drm_file *file_priv); extern int drm_setversion(struct drm_device *dev, void *data, struct drm_file *file_priv); extern int drm_noop(struct drm_device *dev, void *data, diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 1e09e8f..526baed 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -627,6 +627,12 @@ struct drm_get_cap { __u64 value; };
+/** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ +struct drm_set_client_cap { + __u64 capability; + __u64 value; +}; + #define DRM_CLOEXEC O_CLOEXEC struct drm_prime_handle { __u32 handle; @@ -659,6 +665,7 @@ struct drm_prime_handle { #define DRM_IOCTL_GEM_FLINK DRM_IOWR(0x0a, struct drm_gem_flink) #define DRM_IOCTL_GEM_OPEN DRM_IOWR(0x0b, struct drm_gem_open) #define DRM_IOCTL_GET_CAP DRM_IOWR(0x0c, struct drm_get_cap) +#define DRM_IOCTL_SET_CLIENT_CAP DRM_IOW( 0x0d, struct drm_set_client_cap)
#define DRM_IOCTL_SET_UNIQUE DRM_IOW( 0x10, struct drm_unique) #define DRM_IOCTL_AUTH_MAGIC DRM_IOW( 0x11, struct drm_auth)
HDMI 1.4a defines a few layouts that we'd like to expose. This commits add new modeinfo flags that can be used to list the supported stereo layouts (when querying the list of modes) and to set a given stereo 3D mode (when setting a mode).
v2: Add a drm_mode_is_stereo() helper
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- include/drm/drm_crtc.h | 14 ++++++++++++++ include/uapi/drm/drm_mode.h | 36 ++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 14 deletions(-)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 24f4995..825d6fa 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -180,6 +180,20 @@ struct drm_display_mode { int hsync; /* in kHz */ };
+#define DRM_MODE_FLAG_3D_MASK (DRM_MODE_FLAG_3D_FRAME_PACKING | \ + DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE | \ + DRM_MODE_FLAG_3D_LINE_ALTERNATIVE | \ + DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL | \ + DRM_MODE_FLAG_3D_L_DEPTH | \ + DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH | \ + DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | \ + DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF) + +static inline bool drm_mode_is_stereo(const struct drm_display_mode *mode) +{ + return mode->flags & DRM_MODE_FLAG_3D_MASK; +} + enum drm_connector_status { connector_status_connected = 1, connector_status_disconnected = 2, diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h index 113d324..bafe612 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -44,20 +44,28 @@
/* Video mode flags */ /* bit compatible with the xorg definitions. */ -#define DRM_MODE_FLAG_PHSYNC (1<<0) -#define DRM_MODE_FLAG_NHSYNC (1<<1) -#define DRM_MODE_FLAG_PVSYNC (1<<2) -#define DRM_MODE_FLAG_NVSYNC (1<<3) -#define DRM_MODE_FLAG_INTERLACE (1<<4) -#define DRM_MODE_FLAG_DBLSCAN (1<<5) -#define DRM_MODE_FLAG_CSYNC (1<<6) -#define DRM_MODE_FLAG_PCSYNC (1<<7) -#define DRM_MODE_FLAG_NCSYNC (1<<8) -#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ -#define DRM_MODE_FLAG_BCAST (1<<10) -#define DRM_MODE_FLAG_PIXMUX (1<<11) -#define DRM_MODE_FLAG_DBLCLK (1<<12) -#define DRM_MODE_FLAG_CLKDIV2 (1<<13) +#define DRM_MODE_FLAG_PHSYNC (1<<0) +#define DRM_MODE_FLAG_NHSYNC (1<<1) +#define DRM_MODE_FLAG_PVSYNC (1<<2) +#define DRM_MODE_FLAG_NVSYNC (1<<3) +#define DRM_MODE_FLAG_INTERLACE (1<<4) +#define DRM_MODE_FLAG_DBLSCAN (1<<5) +#define DRM_MODE_FLAG_CSYNC (1<<6) +#define DRM_MODE_FLAG_PCSYNC (1<<7) +#define DRM_MODE_FLAG_NCSYNC (1<<8) +#define DRM_MODE_FLAG_HSKEW (1<<9) /* hskew provided */ +#define DRM_MODE_FLAG_BCAST (1<<10) +#define DRM_MODE_FLAG_PIXMUX (1<<11) +#define DRM_MODE_FLAG_DBLCLK (1<<12) +#define DRM_MODE_FLAG_CLKDIV2 (1<<13) +#define DRM_MODE_FLAG_3D_FRAME_PACKING (1<<14) +#define DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE (1<<15) +#define DRM_MODE_FLAG_3D_LINE_ALTERNATIVE (1<<16) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL (1<<17) +#define DRM_MODE_FLAG_3D_L_DEPTH (1<<18) +#define DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH (1<<19) +#define DRM_MODE_FLAG_3D_TOP_AND_BOTTOM (1<<20) +#define DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF (1<<21)
/* DPMS flags */ /* bit compatible with the xorg definitions. */
This capability allows user space to control the delivery of modes with the 3D flags set. This is to not play games with current user space users not knowing anything about stereo 3D flags and that could try to set a mode with one or several of those bits set.
So, the plan is to remove the stereo modes from the list of modes we give to DRM clients by default, and let them through if we are being told otherwise.
stereo_allowed is bound to the drm_file structure to make it a per-client setting, not a global one.
v2: Replace clearing 3D flags by discarding the stereo modes now that they are regular modes. v3: SET_CAP -> SET_CLIENT_CAP rename (Chris Wilson)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_crtc.c | 19 ++++++++++++++++++- drivers/gpu/drm/drm_ioctl.c | 14 +++++++++++++- include/drm/drmP.h | 3 +++ include/uapi/drm/drm.h | 9 +++++++++ 4 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index e79577c..454ac8a 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1581,6 +1581,19 @@ out: return ret; }
+static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, + const struct drm_file *file_priv) +{ + /* + * If user-space hasn't configured the driver to expose the stereo 3D + * modes, don't expose them. + */ + if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) + return false; + + return true; +} + /** * drm_mode_getconnector - get connector configuration * @dev: drm device for the ioctl @@ -1646,7 +1659,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
/* delayed so we get modes regardless of pre-fill_modes state */ list_for_each_entry(mode, &connector->modes, head) - mode_count++; + if (drm_mode_expose_to_userspace(mode, file_priv)) + mode_count++;
out_resp->connector_id = connector->base.id; out_resp->connector_type = connector->connector_type; @@ -1668,6 +1682,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, copied = 0; mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; list_for_each_entry(mode, &connector->modes, head) { + if (!drm_mode_expose_to_userspace(mode, file_priv)) + continue; + drm_crtc_convert_to_umode(&u_mode, mode); if (copy_to_user(mode_ptr + copied, &u_mode, sizeof(u_mode))) { diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 15da412..dffc836 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -308,7 +308,19 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) int drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) { - return -EINVAL; + struct drm_set_client_cap *req = data; + + switch (req->capability) { + case DRM_CLIENT_CAP_STEREO_3D: + if (req->value > 1) + return -EINVAL; + file_priv->stereo_allowed = req->value; + break; + default: + return -EINVAL; + } + + return 0; }
/** diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 782433b..da08697 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -433,6 +433,9 @@ struct drm_file { struct drm_master *master; /* master this node is currently associated with N.B. not always minor->master */
+ /* true when the client has asked us to expose stereo 3D mode flags */ + bool stereo_allowed; + /** * fbs - List of framebuffers associated with this file. * diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 526baed..9b24d65 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -627,6 +627,15 @@ struct drm_get_cap { __u64 value; };
+/** + * DRM_CLIENT_CAP_STEREO_3D + * + * if set to 1, the DRM core will expose the stereo 3D capabilities of the + * monitor by advertising the supported 3D layouts in the flags of struct + * drm_mode_modeinfo. + */ +#define DRM_CLIENT_CAP_STEREO_3D 1 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability;
For now, let's just look at the 3D_present flag of the CEA HDMI vendor block to detect if the sink supports a small list of then mandatory 3D formats.
See the HDMI 1.4a 3D extraction for detail: http://www.hdmi.org/manufacturer/specification.aspx
v2: Rename freq to vrefresh, make the mandatory structure a bit more compact, fix some white space issues and add a couple of const (Ville Syrjälä)
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 110 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 1688ff5..52e6087 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2553,13 +2553,95 @@ do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len) return modes; }
+struct stereo_mandatory_mode { + int width, height, vrefresh; + unsigned int flags; +}; + +static const struct stereo_mandatory_mode stereo_mandatory_modes[] = { + { 1920, 1080, 24, + DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }, + { 1920, 1080, 50, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1920, 1080, 60, + DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF }, + { 1280, 720, 50, + DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING }, + { 1280, 720, 60, + DRM_MODE_FLAG_3D_TOP_AND_BOTTOM | DRM_MODE_FLAG_3D_FRAME_PACKING } +}; + +static bool +stereo_match_mandatory(const struct drm_display_mode *mode, + const struct stereo_mandatory_mode *stereo_mode) +{ + unsigned int interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE; + + return mode->hdisplay == stereo_mode->width && + mode->vdisplay == stereo_mode->height && + interlaced == (stereo_mode->flags & DRM_MODE_FLAG_INTERLACE) && + drm_mode_vrefresh(mode) == stereo_mode->vrefresh; +} + +static const struct stereo_mandatory_mode * +hdmi_find_stereo_mandatory_mode(const struct drm_display_mode *mode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(stereo_mandatory_modes); i++) + if (stereo_match_mandatory(mode, &stereo_mandatory_modes[i])) + return &stereo_mandatory_modes[i]; + + return NULL; +} + +static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) +{ + struct drm_device *dev = connector->dev; + const struct drm_display_mode *mode; + struct list_head stereo_modes; + int modes = 0; + + INIT_LIST_HEAD(&stereo_modes); + + list_for_each_entry(mode, &connector->probed_modes, head) { + const struct stereo_mandatory_mode *mandatory; + u32 stereo_layouts, layout; + + mandatory = hdmi_find_stereo_mandatory_mode(mode); + if (!mandatory) + continue; + + stereo_layouts = mandatory->flags & DRM_MODE_FLAG_3D_MASK; + do { + struct drm_display_mode *new_mode; + + layout = 1 << (ffs(stereo_layouts) - 1); + stereo_layouts &= ~layout; + + new_mode = drm_mode_duplicate(dev, mode); + if (!new_mode) + continue; + + new_mode->flags |= layout; + list_add_tail(&new_mode->head, &stereo_modes); + modes++; + } while (stereo_layouts); + } + + list_splice_tail(&stereo_modes, &connector->probed_modes); + + return modes; +} + /* * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block * @connector: connector corresponding to the HDMI sink * @db: start of the CEA vendor specific block * @len: length of the CEA block payload, ie. one can access up to db[len] * - * Parses the HDMI VSDB looking for modes to add to @connector. + * Parses the HDMI VSDB looking for modes to add to @connector. This function + * also adds the stereo 3d modes when applicable. */ static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) @@ -2585,10 +2667,15 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len)
/* the declared length is not long enough for the 2 first bytes * of additional video format capabilities */ - offset += 2; - if (len < (8 + offset)) + if (len < (8 + offset + 2)) goto out;
+ /* 3D_Present */ + offset++; + if (db[8 + offset] & (1 << 7)) + modes += add_hdmi_mandatory_stereo_modes(connector); + + offset++; vic_len = db[8 + offset] >> 5;
for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { @@ -2668,8 +2755,8 @@ static int add_cea_modes(struct drm_connector *connector, struct edid *edid) { const u8 *cea = drm_find_cea_extension(edid); - const u8 *db; - u8 dbl; + const u8 *db, *hdmi = NULL; + u8 dbl, hdmi_len; int modes = 0;
if (cea && cea_revision(cea) >= 3) { @@ -2684,11 +2771,20 @@ add_cea_modes(struct drm_connector *connector, struct edid *edid)
if (cea_db_tag(db) == VIDEO_BLOCK) modes += do_cea_modes(connector, db + 1, dbl); - else if (cea_db_is_hdmi_vsdb(db)) - modes += do_hdmi_vsdb_modes(connector, db, dbl); + else if (cea_db_is_hdmi_vsdb(db)) { + hdmi = db; + hdmi_len = dbl; + } } }
+ /* + * We parse the HDMI VSDB after having added the cea modes as we will + * be patching their flags when the sink supports stereo 3D. + */ + if (hdmi) + modes += do_hdmi_vsdb_modes(connector, hdmi, hdmi_len); + return modes; }
So we respect a nice design of having similar functions at the same level, in this case:
do_hdmi_vsdb_modes() - add_hdmi_mandatory_stereo_modes() - add_hdmi_mode()
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 52e6087..7366007 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2634,6 +2634,26 @@ static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) return modes; }
+static int add_hdmi_mode(struct drm_connector *connector, u8 vic) +{ + struct drm_device *dev = connector->dev; + struct drm_display_mode *newmode; + + vic--; /* VICs start at 1 */ + if (vic >= ARRAY_SIZE(edid_4k_modes)) { + DRM_ERROR("Unknown HDMI VIC: %d\n", vic); + return 0; + } + + newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); + if (!newmode) + return 0; + + drm_mode_probed_add(connector, newmode); + + return 1; +} + /* * do_hdmi_vsdb_modes - Parse the HDMI Vendor Specific data block * @connector: connector corresponding to the HDMI sink @@ -2646,7 +2666,6 @@ static int add_hdmi_mandatory_stereo_modes(struct drm_connector *connector) static int do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) { - struct drm_device *dev = connector->dev; int modes = 0, offset = 0, i; u8 vic_len;
@@ -2679,23 +2698,10 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len) vic_len = db[8 + offset] >> 5;
for (i = 0; i < vic_len && len >= (9 + offset + i); i++) { - struct drm_display_mode *newmode; u8 vic;
vic = db[9 + offset + i]; - - vic--; /* VICs start at 1 */ - if (vic >= ARRAY_SIZE(edid_4k_modes)) { - DRM_ERROR("Unknown HDMI VIC: %d\n", vic); - continue; - } - - newmode = drm_mode_duplicate(dev, &edid_4k_modes[vic]); - if (!newmode) - continue; - - drm_mode_probed_add(connector, newmode); - modes++; + modes += add_hdmi_mode(connector, vic); }
out:
When setting a stereo 3D mode, there can be only one bit set describing the layout of the frambuffer(s). So reject invalid modes early.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_crtc.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 454ac8a..090415f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1319,6 +1319,10 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out, if (in->clock > INT_MAX || in->vrefresh > INT_MAX) return -ERANGE;
+ /* At most, 1 set bit describing the 3D layout of the mode */ + if (hweight32(in->flags & DRM_MODE_FLAG_3D_MASK) > 1) + return -EINVAL; + out->clock = in->clock; out->hdisplay = in->hdisplay; out->hsync_start = in->hsync_start;
When scanning out a 3D mode on HDMI, we need to send an HDMI infoframe with the corresponding layout to the sink.
v2: Make s3d_structure_from_display_mode() less subtle (Ville Syrjälä)
Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7366007..0bae76d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3421,6 +3421,33 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame, } EXPORT_SYMBOL(drm_hdmi_avi_infoframe_from_display_mode);
+static enum hdmi_3d_structure +s3d_structure_from_display_mode(const struct drm_display_mode *mode) +{ + u32 layout = mode->flags & DRM_MODE_FLAG_3D_MASK; + + switch (layout) { + case DRM_MODE_FLAG_3D_FRAME_PACKING: + return HDMI_3D_STRUCTURE_FRAME_PACKING; + case DRM_MODE_FLAG_3D_FIELD_ALTERNATIVE: + return HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE; + case DRM_MODE_FLAG_3D_LINE_ALTERNATIVE: + return HDMI_3D_STRUCTURE_LINE_ALTERNATIVE; + case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_FULL: + return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL; + case DRM_MODE_FLAG_3D_L_DEPTH: + return HDMI_3D_STRUCTURE_L_DEPTH; + case DRM_MODE_FLAG_3D_L_DEPTH_GFX_GFX_DEPTH: + return HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH; + case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM: + return HDMI_3D_STRUCTURE_TOP_AND_BOTTOM; + case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF: + return HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF; + default: + return HDMI_3D_STRUCTURE_INVALID; + } +} + /** * drm_hdmi_vendor_infoframe_from_display_mode() - fill an HDMI infoframe with * data from a DRM display mode @@ -3438,20 +3465,29 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, const struct drm_display_mode *mode) { int err; + u32 s3d_flags; u8 vic;
if (!frame || !mode) return -EINVAL;
vic = drm_match_hdmi_mode(mode); - if (!vic) + s3d_flags = mode->flags & DRM_MODE_FLAG_3D_MASK; + + if (!vic && !s3d_flags) + return -EINVAL; + + if (vic && s3d_flags) return -EINVAL;
err = hdmi_vendor_infoframe_init(frame); if (err < 0) return err;
- frame->vic = vic; + if (vic) + frame->vic = vic; + else + frame->s3d_struct = s3d_structure_from_display_mode(mode);
return 0; }
When scanning out a stereo mode, the AVI infoframe vic field has to be the underlyng 2D VIC. Before that commit, we weren't matching the CEA mode because of the extra stereo flag and then were setting the VIC field in the AVI infoframe to 0.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 4 ++-- drivers/gpu/drm/drm_modes.c | 18 ++++++++++++------ include/drm/drm_crtc.h | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 0bae76d..48f1746 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2404,7 +2404,7 @@ u8 drm_match_cea_mode(const struct drm_display_mode *to_match)
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && - drm_mode_equal_no_clocks(to_match, cea_mode)) + drm_mode_equal_no_clocks_no_stereo(to_match, cea_mode)) return mode + 1; } return 0; @@ -2453,7 +2453,7 @@ static u8 drm_match_hdmi_mode(const struct drm_display_mode *to_match)
if ((KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock1) || KHZ2PICOS(to_match->clock) == KHZ2PICOS(clock2)) && - drm_mode_equal_no_clocks(to_match, hdmi_mode)) + drm_mode_equal_no_clocks_no_stereo(to_match, hdmi_mode)) return mode + 1; } return 0; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index fc2adb6..c2cb2c8 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -830,12 +830,16 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ } else if (mode1->clock != mode2->clock) return false;
- return drm_mode_equal_no_clocks(mode1, mode2); + if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) != + (mode2->flags & DRM_MODE_FLAG_3D_MASK)) + return false; + + return drm_mode_equal_no_clocks_no_stereo(mode1, mode2); } EXPORT_SYMBOL(drm_mode_equal);
/** - * drm_mode_equal_no_clocks - test modes for equality + * drm_mode_equal_no_clocks_no_stereo - test modes for equality * @mode1: first mode * @mode2: second mode * @@ -843,12 +847,13 @@ EXPORT_SYMBOL(drm_mode_equal); * None. * * Check to see if @mode1 and @mode2 are equivalent, but - * don't check the pixel clocks. + * don't check the pixel clocks nor the stereo layout. * * RETURNS: * True if the modes are equal, false otherwise. */ -bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) +bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, + const struct drm_display_mode *mode2) { if (mode1->hdisplay == mode2->hdisplay && mode1->hsync_start == mode2->hsync_start && @@ -860,12 +865,13 @@ bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct mode1->vsync_end == mode2->vsync_end && mode1->vtotal == mode2->vtotal && mode1->vscan == mode2->vscan && - mode1->flags == mode2->flags) + (mode1->flags & ~DRM_MODE_FLAG_3D_MASK) == + (mode2->flags & ~DRM_MODE_FLAG_3D_MASK)) return true;
return false; } -EXPORT_SYMBOL(drm_mode_equal_no_clocks); +EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
/** * drm_mode_validate_size - make sure modes adhere to size constraints diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 825d6fa..6b7f9c7 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -989,7 +989,7 @@ extern void drm_mode_config_reset(struct drm_device *dev); extern void drm_mode_config_cleanup(struct drm_device *dev); extern void drm_mode_set_name(struct drm_display_mode *mode); extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); -extern bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); +extern bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); extern int drm_mode_width(const struct drm_display_mode *mode); extern int drm_mode_height(const struct drm_display_mode *mode);
This allows to expose the alternate clock versions of the stereo modes.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_edid.c | 3 +++ 1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 48f1746..c24af1d 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2507,6 +2507,9 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid) if (!newmode) continue;
+ /* Carry over the stereo flags */ + newmode->flags |= mode->flags & DRM_MODE_FLAG_3D_MASK; + /* * The current mode could be either variant. Make * sure to pick the "other" clock for the new mode.
Just like with interlaced or double scan modes, make stereo modes a per-connector opt-in to give a chance to driver authors to make it work before enabling it.
Suggested-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_crtc_helper.c | 8 +++++++- include/drm/drm_crtc.h | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index c722c3b..4280e37 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -76,7 +76,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector, { struct drm_display_mode *mode;
- if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE)) + if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | + DRM_MODE_FLAG_3D_MASK)) return;
list_for_each_entry(mode, &connector->modes, head) { @@ -86,6 +87,9 @@ static void drm_mode_validate_flag(struct drm_connector *connector, if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && !(flags & DRM_MODE_FLAG_DBLSCAN)) mode->status = MODE_NO_DBLESCAN; + if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && + !(flags & DRM_MODE_FLAG_3D_MASK)) + mode->status = MODE_NO_STEREO; }
return; @@ -175,6 +179,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector, mode_flags |= DRM_MODE_FLAG_INTERLACE; if (connector->doublescan_allowed) mode_flags |= DRM_MODE_FLAG_DBLSCAN; + if (connector->stereo_allowed) + mode_flags |= DRM_MODE_FLAG_3D_MASK; drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry(mode, &connector->modes, head) { diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 6b7f9c7..1b69407 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -108,6 +108,7 @@ enum drm_mode_status { MODE_ONE_HEIGHT, /* only one height is supported */ MODE_ONE_SIZE, /* only one resolution is supported */ MODE_NO_REDUCED, /* monitor doesn't accept reduced blanking */ + MODE_NO_STEREO, /* stereo modes not supported */ MODE_UNVERIFIED = -3, /* mode needs to reverified */ MODE_BAD = -2, /* unspecified reason */ MODE_ERROR = -1 /* error condition */ @@ -611,6 +612,7 @@ struct drm_connector { int connector_type_id; bool interlace_allowed; bool doublescan_allowed; + bool stereo_allowed; struct list_head modes; /* list of modes on this connector */
enum drm_connector_status status;
This field was only accessed by the nouveau driver, but never set. So concluded we can rid of this one.
Cc: Ben Skeggs bskeggs@redhat.com Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/nouveau/dispnv04/crtc.c | 2 -- include/drm/drm_crtc.h | 1 - 2 files changed, 3 deletions(-)
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index d4fbf11..0e3270c 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -326,8 +326,6 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) regp->MiscOutReg = 0x23; /* +hsync +vsync */ }
- regp->MiscOutReg |= (mode->clock_index & 0x03) << 2; - /* * Time Sequencer */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 1b69407..011baaa 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -156,7 +156,6 @@ struct drm_display_mode { int height_mm;
/* Actual mode we give to hw */ - int clock_index; int synth_clock; int crtc_hdisplay; int crtc_hblank_start;
On Fri, Sep 20, 2013 at 2:40 AM, Damien Lespiau damien.lespiau@intel.com wrote:
Acked-by: Ben Skeggs bskeggs@redhat.com
This field is unused. Garbage collect it.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- include/drm/drm_crtc.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 011baaa..8e9716e 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -156,7 +156,6 @@ struct drm_display_mode { int height_mm;
/* Actual mode we give to hw */ - int synth_clock; int crtc_hdisplay; int crtc_hblank_start; int crtc_hblank_end;
Just like the various timings, make it possible to have a clock field what we can tweak before giving it to hardware.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_modes.c | 1 + include/drm/drm_crtc.h | 1 + 2 files changed, 2 insertions(+)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index c2cb2c8..ef26eb2 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -719,6 +719,7 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) if ((p == NULL) || ((p->type & DRM_MODE_TYPE_CRTC_C) == DRM_MODE_TYPE_BUILTIN)) return;
+ p->crtc_clock = p->clock; p->crtc_hdisplay = p->hdisplay; p->crtc_hsync_start = p->hsync_start; p->crtc_hsync_end = p->hsync_end; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 8e9716e..73478bc 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -156,6 +156,7 @@ struct drm_display_mode { int height_mm;
/* Actual mode we give to hw */ + int crtc_clock; /* in KHz */ int crtc_hdisplay; int crtc_hblank_start; int crtc_hblank_end;
When using the frame packing and a single big framebuffer, some hardware requires that we do everything like if we were scanning out the big buffer itself. Let's instrument drm_mode_set_crtcinfo() to be able to do this adjustement if the driver is asking for it.
Suggested-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_modes.c | 51 ++++++++++++++++++++++++++++++++++++++++++++- include/drm/drm_crtc.h | 3 ++- 2 files changed, 52 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ef26eb2..d9c5a34 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -704,15 +704,47 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode) } EXPORT_SYMBOL(drm_mode_vrefresh);
+static bool drm_mode_is_ntsc(const struct drm_display_mode *mode) +{ + int ntsc_clock; + + ntsc_clock = DIV_ROUND_UP(mode->vtotal * mode->htotal * mode->vrefresh, + 1001); + + if (ntsc_clock == mode->clock) + return true; + + return false; +} + +static void drm_mode_reconstruct_crtc_clock(struct drm_display_mode *mode) +{ + int clock; + + clock = mode->crtc_vtotal * mode->crtc_htotal * + drm_mode_vrefresh(mode) / 1000; + + if (drm_mode_is_ntsc(mode)) + mode->crtc_clock = DIV_ROUND_UP(clock * 1000, 1001); + else + mode->crtc_clock = clock; +} + /** * drm_mode_set_crtcinfo - set CRTC modesetting parameters * @p: mode - * @adjust_flags: unused? (FIXME) + * @adjust_flags: a combination of adjustment flags * * LOCKING: * None. * * Setup the CRTC modesetting parameters for @p, adjusting if necessary. + * + * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of + * interlaced modes. + * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for + * buffers containing two eyes (only adjust the timings when needed, eg. for + * "frame packing" or "side by side full"). */ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) { @@ -753,6 +785,23 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vtotal *= p->vscan; }
+ if (adjust_flags & CRTC_STEREO_DOUBLE) { + unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK; + int vactive_space; + + switch (layout) { + case DRM_MODE_FLAG_3D_FRAME_PACKING: + vactive_space = p->vtotal - p->vdisplay; + + p->crtc_vdisplay += p->vdisplay + vactive_space; + p->crtc_vsync_start += p->vdisplay + vactive_space; + p->crtc_vsync_end += p->vdisplay + vactive_space; + p->crtc_vtotal += p->vdisplay + vactive_space; + drm_mode_reconstruct_crtc_clock(p); + break; + } + } + p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 73478bc..b2d08ca 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -125,7 +125,8 @@ enum drm_mode_status { .vscan = (vs), .flags = (f), \ .base.type = DRM_MODE_OBJECT_MODE
-#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ +#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ +#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */
struct drm_display_mode { /* Header */
On Thu, Sep 19, 2013 at 05:40:29PM +0100, Damien Lespiau wrote:
All of these are just '+= votal'. Maybe just write it that way and add a comment to help the uninformed.
In fact it should be crtc_vtotal to maintain the CRTC_INTERLACE_HALVE_V etc. adjustments already done. So even if you don't take my suggestion of using just += crtc_vtotal, you should at least switch to 'vactive_space = p->crtc_vtotal - p->crtc_vdisplay;'
This thing loses precision and shouldn't even be needed. Just double crtc_clock.
When using the frame packing and a single big framebuffer, some hardware requires that we do everything like if we were scanning out the big buffer itself. Let's instrument drm_mode_set_crtcinfo() to be able to do this adjustement if the driver is asking for it.
v2: Use crtc_vtotal and multiply the clock by 2 instead of reconstructing it (Ville Syrjälä)
Suggested-by: Daniel Vetter daniel.vetter@ffwll.ch Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/drm_modes.c | 22 +++++++++++++++++++++- include/drm/drm_crtc.h | 3 ++- 2 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ef26eb2..b073315 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -707,12 +707,18 @@ EXPORT_SYMBOL(drm_mode_vrefresh); /** * drm_mode_set_crtcinfo - set CRTC modesetting parameters * @p: mode - * @adjust_flags: unused? (FIXME) + * @adjust_flags: a combination of adjustment flags * * LOCKING: * None. * * Setup the CRTC modesetting parameters for @p, adjusting if necessary. + * + * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of + * interlaced modes. + * - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for + * buffers containing two eyes (only adjust the timings when needed, eg. for + * "frame packing" or "side by side full"). */ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) { @@ -753,6 +759,20 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags) p->crtc_vtotal *= p->vscan; }
+ if (adjust_flags & CRTC_STEREO_DOUBLE) { + unsigned int layout = p->flags & DRM_MODE_FLAG_3D_MASK; + + switch (layout) { + case DRM_MODE_FLAG_3D_FRAME_PACKING: + p->crtc_clock *= 2; + p->crtc_vdisplay += p->crtc_vtotal; + p->crtc_vsync_start += p->crtc_vtotal; + p->crtc_vsync_end += p->crtc_vtotal; + p->crtc_vtotal += p->crtc_vtotal; + break; + } + } + p->crtc_vblank_start = min(p->crtc_vsync_start, p->crtc_vdisplay); p->crtc_vblank_end = max(p->crtc_vsync_end, p->crtc_vtotal); p->crtc_hblank_start = min(p->crtc_hsync_start, p->crtc_hdisplay); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 73478bc..b2d08ca 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -125,7 +125,8 @@ enum drm_mode_status { .vscan = (vs), .flags = (f), \ .base.type = DRM_MODE_OBJECT_MODE
-#define CRTC_INTERLACE_HALVE_V 0x1 /* halve V values for interlacing */ +#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */ +#define CRTC_STEREO_DOUBLE (1 << 1) /* adjust timings for stereo modes */
struct drm_display_mode { /* Header */
We want to dump the parameters given to the hardware, so let's use crtc_clock here.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a1a8172..fb769fe 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8332,7 +8332,7 @@ static void intel_dump_crtc_timings(const struct drm_display_mode *mode) { DRM_DEBUG_KMS("crtc timings: %d %d %d %d %d %d %d %d %d, " "type: 0x%x flags: 0x%x\n", - mode->clock, + mode->crtc_clock, mode->crtc_hdisplay, mode->crtc_hsync_start, mode->crtc_hsync_end, mode->crtc_htotal, mode->crtc_vdisplay, mode->crtc_vsync_start,
struct drm_mode_display now has a separate crtc_ version of the clock to be used when we're talking about the timings given to the harwadre (was far as the mode is concerned).
This commit is really the result of a git grep adjusted_mode.*clock and replacing those by adjusted_mode.crtc_clock. No functional change.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_crt.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++------------------ drivers/gpu/drm/i915/intel_dp.c | 11 +++++++---- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 2 +- drivers/gpu/drm/i915/intel_hdmi.c | 6 +++--- drivers/gpu/drm/i915/intel_lvds.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 36 +++++++++++++++++++++++------------- drivers/gpu/drm/i915/intel_sdvo.c | 2 +- drivers/gpu/drm/i915/intel_tv.c | 2 +- 10 files changed, 57 insertions(+), 44 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6f101d5..6568d4b 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -110,7 +110,7 @@ static void intel_crt_get_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev_priv->dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.clock = dotclock; + pipe_config->adjusted_mode.crtc_clock = dotclock; }
/* Note: The caller is required to filter out dpms modes not supported by the diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index fb769fe..f868266 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -740,14 +740,14 @@ bool intel_crtc_active(struct drm_crtc *crtc) /* Be paranoid as we can arrive here with only partial * state retrieved from the hardware during setup. * - * We can ditch the adjusted_mode.clock check as soon + * We can ditch the adjusted_mode.crtc_clock check as soon * as Haswell has gained clock readout/fastboot support. * * We can ditch the crtc->fb check as soon as we can * properly reconstruct framebuffers. */ return intel_crtc->active && crtc->fb && - intel_crtc->config.adjusted_mode.clock; + intel_crtc->config.adjusted_mode.crtc_clock; }
enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, @@ -2914,7 +2914,7 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - int clock = to_intel_crtc(crtc)->config.adjusted_mode.clock; + int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; u32 divsel, phaseinc, auxdiv, phasedir = 0; u32 temp;
@@ -2938,8 +2938,8 @@ static void lpt_program_iclkip(struct drm_crtc *crtc) phaseinc = 0x20; } else { /* The iCLK virtual clock root frequency is in MHz, - * but the adjusted_mode->clock in in KHz. To get the divisors, - * it is necessary to divide one by another, so we + * but the adjusted_mode->crtc_clock in in KHz. To get the + * divisors, it is necessary to divide one by another, so we * convert the virtual clock precision to KHz here for higher * precision. */ @@ -4101,7 +4101,7 @@ retry: */ link_bw = intel_fdi_link_freq(dev) * MHz(100)/KHz(1)/10;
- fdi_dotclock = adjusted_mode->clock; + fdi_dotclock = adjusted_mode->crtc_clock;
lane = ironlake_get_lanes_required(fdi_dotclock, link_bw, pipe_config->pipe_bpp); @@ -4157,12 +4157,12 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, * otherwise pipe A only. */ if ((crtc->pipe == PIPE_A || IS_I915G(dev)) && - adjusted_mode->clock > clock_limit * 9 / 10) { + adjusted_mode->crtc_clock > clock_limit * 9 / 10) { clock_limit *= 2; pipe_config->double_wide = true; }
- if (adjusted_mode->clock > clock_limit * 9 / 10) + if (adjusted_mode->crtc_clock > clock_limit * 9 / 10) return -EINVAL; }
@@ -4822,7 +4822,7 @@ static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc,
crtc->mode.flags = pipe_config->adjusted_mode.flags;
- crtc->mode.clock = pipe_config->adjusted_mode.clock; + crtc->mode.clock = pipe_config->adjusted_mode.crtc_clock; crtc->mode.flags |= pipe_config->adjusted_mode.flags; }
@@ -7462,7 +7462,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
/* * This value includes pixel_multiplier. We will use - * port_clock to compute adjusted_mode.clock in the + * port_clock to compute adjusted_mode.crtc_clock in the * encoder's get_config() function. */ pipe_config->port_clock = clock.dot; @@ -7497,11 +7497,11 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
/* * This value does not include pixel_multiplier. - * We will check that port_clock and adjusted_mode.clock + * We will check that port_clock and adjusted_mode.crtc_clock * agree once we know their relationship in the encoder's * get_config() function. */ - pipe_config->adjusted_mode.clock = + pipe_config->adjusted_mode.crtc_clock = intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000, &pipe_config->fdi_m_n); } @@ -7539,7 +7539,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, pipe_config.dpll_hw_state.fp1 = I915_READ(FP1(pipe)); i9xx_crtc_clock_get(intel_crtc, &pipe_config);
- mode->clock = pipe_config.adjusted_mode.clock; + mode->clock = pipe_config.adjusted_mode.crtc_clock; mode->hdisplay = (htot & 0xffff) + 1; mode->htotal = ((htot & 0xffff0000) >> 16) + 1; mode->hsync_start = (hsync & 0xffff) + 1; @@ -8478,8 +8478,8 @@ encoder_retry: /* Set default port clock if not overwritten by the encoder. Needs to be * done afterwards in case the encoder adjusts the mode. */ if (!pipe_config->port_clock) - pipe_config->port_clock = pipe_config->adjusted_mode.clock * - pipe_config->pixel_multiplier; + pipe_config->port_clock = pipe_config->adjusted_mode.crtc_clock + * pipe_config->pixel_multiplier;
ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config); if (ret < 0) { @@ -8809,7 +8809,7 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pipe_bpp);
if (!IS_HASWELL(dev)) { - PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.clock); + PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock); PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock); }
@@ -9031,9 +9031,9 @@ void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config * FDI already provided one idea for the dotclock. * Yell if the encoder disagrees. */ - WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.clock, dotclock), + WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.crtc_clock, dotclock), "FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n", - pipe_config->adjusted_mode.clock, dotclock); + pipe_config->adjusted_mode.crtc_clock, dotclock); }
static int __intel_set_mode(struct drm_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 9770160..928050a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -800,7 +800,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
DRM_DEBUG_KMS("DP link computation with max lane count %i " "max bw %02x pixel clock %iKHz\n", - max_lane_count, bws[max_clock], adjusted_mode->clock); + max_lane_count, bws[max_clock], + adjusted_mode->crtc_clock);
/* Walk through all bpp values. Luckily they're all nicely spaced with 2 * bpc in between. */ @@ -812,7 +813,8 @@ intel_dp_compute_config(struct intel_encoder *encoder, }
for (; bpp >= 6*3; bpp -= 2*3) { - mode_rate = intel_dp_link_required(adjusted_mode->clock, bpp); + mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock, + bpp);
for (clock = 0; clock <= max_clock; clock++) { for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { @@ -857,7 +859,8 @@ found: mode_rate, link_avail);
intel_link_compute_m_n(bpp, lane_count, - adjusted_mode->clock, pipe_config->port_clock, + adjusted_mode->crtc_clock, + pipe_config->port_clock, &pipe_config->dp_m_n);
intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); @@ -1472,7 +1475,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A) ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.clock = dotclock; + pipe_config->adjusted_mode.crtc_clock = dotclock; }
static bool is_edp_psr(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6f5dd64..585cfea 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -218,7 +218,7 @@ struct intel_crtc_config { * preferred input timings. */ struct drm_display_mode requested_mode; /* Actual pipe timings ie. what we program into the pipe timing - * registers. adjusted_mode.clock is the pipe pixel clock. */ + * registers. adjusted_mode.crtc_clock is the pipe pixel clock. */ struct drm_display_mode adjusted_mode;
/* Pipe source size (ie. panel fitter input size) diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index ff86c36..270c0ae 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -154,7 +154,7 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
pipe_config->adjusted_mode.flags |= flags;
- pipe_config->adjusted_mode.clock = pipe_config->port_clock; + pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock; }
static void intel_disable_dvo(struct intel_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 79582f9..f21a57f 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -737,7 +737,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev_priv->dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.clock = dotclock; + pipe_config->adjusted_mode.crtc_clock = dotclock; }
static void intel_enable_hdmi(struct intel_encoder *encoder) @@ -873,7 +873,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode; - int clock_12bpc = pipe_config->adjusted_mode.clock * 3 / 2; + int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2; int portclock_limit = hdmi_portclock_limit(intel_hdmi); int desired_bpp;
@@ -915,7 +915,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, pipe_config->pipe_bpp = desired_bpp; }
- if (adjusted_mode->clock > portclock_limit) { + if (adjusted_mode->crtc_clock > portclock_limit) { DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); return false; } diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 05e5485..acfa8e2 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -123,7 +123,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev_priv->dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.clock = dotclock; + pipe_config->adjusted_mode.crtc_clock = dotclock; }
/* The LVDS pin pair needs to be on before the DPLLs are enabled. diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index db12c18..a0f20ac 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1100,8 +1100,12 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
crtc = single_enabled_crtc(dev); if (crtc) { - int clock = to_intel_crtc(crtc)->config.adjusted_mode.clock; + const struct drm_display_mode *adjusted_mode; int pixel_size = crtc->fb->bits_per_pixel / 8; + int clock; + + adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; + clock = adjusted_mode->crtc_clock;
/* Display SR */ wm = intel_calculate_wm(clock, &pineview_display_wm, @@ -1174,7 +1178,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, }
adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - clock = adjusted_mode->clock; + clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->htotal; hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; pixel_size = crtc->fb->bits_per_pixel / 8; @@ -1261,7 +1265,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
crtc = intel_get_crtc_for_plane(dev, plane); adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - clock = adjusted_mode->clock; + clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->htotal; hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; pixel_size = crtc->fb->bits_per_pixel / 8; @@ -1302,7 +1306,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, if (!intel_crtc_active(crtc)) return false;
- clock = to_intel_crtc(crtc)->config.adjusted_mode.clock; + clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */
entries = (clock / 1000) * pixel_size; @@ -1492,7 +1496,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) static const int sr_latency_ns = 12000; const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - int clock = adjusted_mode->clock; + int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->htotal; int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; int pixel_size = crtc->fb->bits_per_pixel / 8; @@ -1567,11 +1571,13 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) fifo_size = dev_priv->display.get_fifo_size(dev, 0); crtc = intel_get_crtc_for_plane(dev, 0); if (intel_crtc_active(crtc)) { + const struct drm_display_mode *adjusted_mode; int cpp = crtc->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4;
- planea_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock, + adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; + planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock, wm_info, fifo_size, cpp, latency_ns); enabled = crtc; @@ -1581,11 +1587,13 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) fifo_size = dev_priv->display.get_fifo_size(dev, 1); crtc = intel_get_crtc_for_plane(dev, 1); if (intel_crtc_active(crtc)) { + const struct drm_display_mode *adjusted_mode; int cpp = crtc->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4;
- planeb_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock, + adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; + planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock, wm_info, fifo_size, cpp, latency_ns); if (enabled == NULL) @@ -1614,7 +1622,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) static const int sr_latency_ns = 6000; const struct drm_display_mode *adjusted_mode = &to_intel_crtc(enabled)->config.adjusted_mode; - int clock = adjusted_mode->clock; + int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->htotal; int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; int pixel_size = enabled->fb->bits_per_pixel / 8; @@ -1670,6 +1678,7 @@ static void i830_update_wm(struct drm_crtc *unused_crtc) struct drm_device *dev = unused_crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + const struct drm_display_mode *adjusted_mode; uint32_t fwater_lo; int planea_wm;
@@ -1677,7 +1686,8 @@ static void i830_update_wm(struct drm_crtc *unused_crtc) if (crtc == NULL) return;
- planea_wm = intel_calculate_wm(to_intel_crtc(crtc)->config.adjusted_mode.clock, + adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; + planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock, &i830_wm_info, dev_priv->display.get_fifo_size(dev, 0), 4, latency_ns); @@ -1764,7 +1774,7 @@ static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
crtc = intel_get_crtc_for_plane(dev, plane); adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; - clock = adjusted_mode->clock; + clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->htotal; hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; pixel_size = crtc->fb->bits_per_pixel / 8; @@ -2112,7 +2122,7 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev, struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pixel_rate;
- pixel_rate = intel_crtc->config.adjusted_mode.clock; + pixel_rate = intel_crtc->config.adjusted_mode.crtc_clock;
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to * adjust the pixel_rate here. */ @@ -2913,7 +2923,7 @@ sandybridge_compute_sprite_wm(struct drm_device *dev, int plane, return false; }
- clock = to_intel_crtc(crtc)->config.adjusted_mode.clock; + clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
/* Use the small buffer method to calculate the sprite watermark */ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; @@ -2948,7 +2958,7 @@ sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane, }
crtc = intel_get_crtc_for_plane(dev, plane); - clock = to_intel_crtc(crtc)->config.adjusted_mode.clock; + clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; if (!clock) { *sprite_wm = 0; return false; diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 91aea9e..684cb60 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1369,7 +1369,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder, if (HAS_PCH_SPLIT(dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.clock = dotclock; + pipe_config->adjusted_mode.crtc_clock = dotclock;
/* Cross check the port pixel multiplier with the sdvo encoder state. */ if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index f2c6d79..11c759d 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -912,7 +912,7 @@ intel_tv_compute_config(struct intel_encoder *encoder, if (!tv_mode) return false;
- pipe_config->adjusted_mode.clock = tv_mode->clock; + pipe_config->adjusted_mode.crtc_clock = tv_mode->clock; DRM_DEBUG_KMS("forcing bpc to 8 for TV\n"); pipe_config->pipe_bpp = 8*3;
When booting with i915.fastboot=1, we always take tha code path and end up undoing what we're trying to do with adjusted_mode.
Hopefully, as the fastboot hardware readout code is using adjusted_mode as well, it should be equivalent.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_display.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f868266..2b9f80b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2288,9 +2288,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
/* Update pipe size and adjust fitter if needed */ if (i915_fastboot) { + const struct drm_display_mode *adjusted_mode = + &intel_crtc->config.adjusted_mode; + I915_WRITE(PIPESRC(intel_crtc->pipe), - ((crtc->mode.hdisplay - 1) << 16) | - (crtc->mode.vdisplay - 1)); + ((adjusted_mode->crtc_hdisplay - 1) << 16) | + (adjusted_mode->crtc_vdisplay - 1)); if (!intel_crtc->config.pch_pfit.enabled && (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
On Thu, Sep 19, 2013 at 05:40:32PM +0100, Damien Lespiau wrote:
OK, I'm offically confused by this thing. Maybe it got a bit broken by the pfit.enabled change?
I must assume that the original intention of this was to turn off the panel fitter in case the BIOS had left it enabled w/ 0x0 size, but I'm not sure how that would even work. Anyways, now it will turn it off if it's already off, which doesn't make much sense.
And I guess the PIPESRC write is there because we assume the BIOS left it wrong for the non-pfit case. We have explicit readout for it now, so we could actually check if that's the case.
Next I started to think we'd need to fix up DSPSIZE too, but that's only for gen2/3 plane B, and the pfit parts here clearly assume a PCH platform. But we never check for PCH anywhere actually, so i915_fastboot seems to be one of those shoot yourelf in the foot kind of things.
Also I have no idea what we'll be scanning out if the primary plane is enabled and ends up changing size when we hit this code.
On Fri, Sep 20, 2013 at 05:54:55PM +0300, Ville Syrjälä wrote:
Well, I didn't even read beyond the PIPESRC write, but yes, now that you mention it, it looks dodgy.
Jesse, do you remember what was the original intention? neither the commit introducing the change nor the comment are very verbose.
On Fri, 20 Sep 2013 16:33:47 +0100 Damien Lespiau damien.lespiau@intel.com wrote:
Just for the record, I'll capture what we discussed on IRC.
The reason for this is that in compute_mode_changes we check the native mode (not the pfit mode) to see if we can flip rather than do a full mode set. In the fastboot case, we'll flip, but if we don't update the pipesrc and pfit state, we'll end up with a big fb scanned out into the wrong sized surface.
To fix this properly, we need to hoist the checks up into compute_mode_changes (or above), check the actual pfit state and whether the platform allows pfit disable with pipe active, and only then update the pipesrc and pfit state, even on the flip path.
On top of that, other state like info frames and audio state needs to be tracked and preserved for fastboot as applicable. Then we can remove the parameter hacks.
When scanning out big stereo buffers that are actually bigger that their natural 2D counterpart, we need to blow up the crtc timings as well.
Not that this is only done for frame packing as this is the only stereo mode currently exposed needing this kind of ajdustements.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2b9f80b..0573036 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8460,7 +8460,7 @@ encoder_retry: pipe_config->pixel_multiplier = 1;
/* Fill in default crtc timings, allow encoders to overwrite them. */ - drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, 0); + drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, CRTC_STEREO_DOUBLE);
/* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also
Now that we ask to adjust the crtc timings for stereo modes, the correct pipe_src_w and pipe_src_h can be found in crtc_vdisplay and crtc_hdisplay.
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_display.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0573036..69d7167 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8425,9 +8425,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, drm_mode_copy(&pipe_config->adjusted_mode, mode); drm_mode_copy(&pipe_config->requested_mode, mode);
- pipe_config->pipe_src_w = mode->hdisplay; - pipe_config->pipe_src_h = mode->vdisplay; - pipe_config->cpu_transcoder = (enum transcoder) to_intel_crtc(crtc)->pipe; pipe_config->shared_dpll = DPLL_ID_PRIVATE; @@ -8462,6 +8459,9 @@ encoder_retry: /* Fill in default crtc timings, allow encoders to overwrite them. */ drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, CRTC_STEREO_DOUBLE);
+ pipe_config->pipe_src_w = pipe_config->adjusted_mode.crtc_hdisplay; + pipe_config->pipe_src_h = pipe_config->adjusted_mode.crtc_vdisplay; + /* Pass our mode to the connectors and the CRTC to give them a chance to * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely.
On Thu, Sep 19, 2013 at 05:40:34PM +0100, Damien Lespiau wrote:
I think a oneline comment here to explain the ordering would be nice. -Daniel
Signed-off-by: Damien Lespiau damien.lespiau@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f21a57f..0d4403e 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1228,6 +1228,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
connector->interlace_allowed = 1; connector->doublescan_allowed = 0; + connector->stereo_allowed = 1;
switch (port) { case PORT_B:
On Thu, Sep 19, 2013 at 05:40:15PM +0100, Damien Lespiau wrote:
Everything except patches 14 and 17: Reviewed-by: Ville Syrjälä ville.syrjala@linux.intel.com
One thing we're missing though is making sure the fb is big enough for the stereo adjusted primary plane size.
dri-devel@lists.freedesktop.org