Commit c3ff0cdb authored by Ankit Nautiyal's avatar Ankit Nautiyal Committed by Maarten Lankhorst

drm: Expose modes with aspect ratio, only if requested

We parse the EDID and add all the modes in the connector's modelist.
This adds CEA modes with aspect ratio information too, regardless of
whether user space requested this information or not.

This patch:
-prunes the modes with aspect-ratio information, from the
 drm_mode_get_connector modelist supplied to the user, if the
 user-space has not set the aspect ratio DRM client cap. However if
 such a mode is unique in the list, it is kept in the list, with
 aspect-ratio flags reset.
-prepares a list of exposed modes, which is used to find unique modes
 if aspect-ratio is not allowed.
-adds a new list_head 'exposed_head' in drm_mode_display, to traverse
 the list of exposed modes.

Cc: Ville Syrjala <ville.syrjala@linux.intel.com>
Cc: Shashank Sharma <shashank.sharma@intel.com>
Cc: Jose Abreu <jose.abreu@synopsys.com>
Signed-off-by: default avatarAnkit Nautiyal <ankit.k.nautiyal@intel.com>

V3: As suggested by Ville, modified the mechanism of pruning of modes
    with aspect-ratio, if the aspect-ratio is not supported. Instead
    of straight away pruning such a mode, the mode is retained with
    aspect ratio bits set to zero, provided it is unique.
V4: rebase
V5: Addressed review comments from Ville:
    -used a pointer to store last valid mode.
    -avoided, modifying of picture_aspect_ratio in kernel mode,
     instead only flags bits of user mode are reset (if aspect-ratio
     is not supported).
V6: As suggested by Ville, corrected the mode pruning logic and
    elaborated the mode pruning logic and the assumptions taken.
V7: rebase
V8: rebase
V9: rebase
V10: rebase
V11: Fixed the issue caused in kms_3d test, and enhanced the pruning
     logic to correctly identify and prune modes with aspect-ratio,
     if aspect-ratio cap is not set.
V12: As suggested by Ville, added another list_head in
     drm_mode_display to traverse the list of exposed modes and
     avoided duplication of modes.
V13: Minor modifications, as suggested by Ville.
v14: As suggested by Daniel Vetter and Ville Syrjala, corrected the
     pruning logic to avoid any dependency in the order of mode with
     aspect-ratio.
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarMaarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1525777785-9740-9-git-send-email-ankit.k.nautiyal@intel.com
parent ace5bf0e
...@@ -1531,8 +1531,10 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne ...@@ -1531,8 +1531,10 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne
return connector->encoder; return connector->encoder;
} }
static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, static bool
const struct drm_file *file_priv) drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
const struct list_head *export_list,
const struct drm_file *file_priv)
{ {
/* /*
* If user-space hasn't configured the driver to expose the stereo 3D * If user-space hasn't configured the driver to expose the stereo 3D
...@@ -1540,6 +1542,23 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode, ...@@ -1540,6 +1542,23 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
*/ */
if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode)) if (!file_priv->stereo_allowed && drm_mode_is_stereo(mode))
return false; return false;
/*
* If user-space hasn't configured the driver to expose the modes
* with aspect-ratio, don't expose them. However if such a mode
* is unique, let it be exposed, but reset the aspect-ratio flags
* while preparing the list of user-modes.
*/
if (!file_priv->aspect_ratio_allowed) {
struct drm_display_mode *mode_itr;
list_for_each_entry(mode_itr, export_list, export_head)
if (drm_mode_match(mode_itr, mode,
DRM_MODE_MATCH_TIMINGS |
DRM_MODE_MATCH_CLOCK |
DRM_MODE_MATCH_FLAGS |
DRM_MODE_MATCH_3D_FLAGS))
return false;
}
return true; return true;
} }
...@@ -1559,6 +1578,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, ...@@ -1559,6 +1578,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
struct drm_mode_modeinfo u_mode; struct drm_mode_modeinfo u_mode;
struct drm_mode_modeinfo __user *mode_ptr; struct drm_mode_modeinfo __user *mode_ptr;
uint32_t __user *encoder_ptr; uint32_t __user *encoder_ptr;
LIST_HEAD(export_list);
if (!drm_core_check_feature(dev, DRIVER_MODESET)) if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL; return -EINVAL;
...@@ -1607,21 +1627,31 @@ int drm_mode_getconnector(struct drm_device *dev, void *data, ...@@ -1607,21 +1627,31 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
/* delayed so we get modes regardless of pre-fill_modes state */ /* delayed so we get modes regardless of pre-fill_modes state */
list_for_each_entry(mode, &connector->modes, head) list_for_each_entry(mode, &connector->modes, head)
if (drm_mode_expose_to_userspace(mode, file_priv)) if (drm_mode_expose_to_userspace(mode, &export_list,
file_priv)) {
list_add_tail(&mode->export_head, &export_list);
mode_count++; mode_count++;
}
/* /*
* This ioctl is called twice, once to determine how much space is * This ioctl is called twice, once to determine how much space is
* needed, and the 2nd time to fill it. * needed, and the 2nd time to fill it.
* The modes that need to be exposed to the user are maintained in the
* 'export_list'. When the ioctl is called first time to determine the,
* space, the export_list gets filled, to find the no.of modes. In the
* 2nd time, the user modes are filled, one by one from the export_list.
*/ */
if ((out_resp->count_modes >= mode_count) && mode_count) { if ((out_resp->count_modes >= mode_count) && mode_count) {
copied = 0; copied = 0;
mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr; mode_ptr = (struct drm_mode_modeinfo __user *)(unsigned long)out_resp->modes_ptr;
list_for_each_entry(mode, &connector->modes, head) { list_for_each_entry(mode, &export_list, export_head) {
if (!drm_mode_expose_to_userspace(mode, file_priv))
continue;
drm_mode_convert_to_umode(&u_mode, mode); drm_mode_convert_to_umode(&u_mode, mode);
/*
* Reset aspect ratio flags of user-mode, if modes with
* aspect-ratio are not supported.
*/
if (!file_priv->aspect_ratio_allowed)
u_mode.flags &= ~DRM_MODE_FLAG_PIC_AR_MASK;
if (copy_to_user(mode_ptr + copied, if (copy_to_user(mode_ptr + copied,
&u_mode, sizeof(u_mode))) { &u_mode, sizeof(u_mode))) {
ret = -EFAULT; ret = -EFAULT;
......
...@@ -411,6 +411,19 @@ struct drm_display_mode { ...@@ -411,6 +411,19 @@ struct drm_display_mode {
* Field for setting the HDMI picture aspect ratio of a mode. * Field for setting the HDMI picture aspect ratio of a mode.
*/ */
enum hdmi_picture_aspect picture_aspect_ratio; enum hdmi_picture_aspect picture_aspect_ratio;
/**
* @export_head:
*
* struct list_head for modes to be exposed to the userspace.
* This is to maintain a list of exposed modes while preparing
* user-mode's list in drm_mode_getconnector ioctl. The purpose of this
* list_head only lies in the ioctl function, and is not expected to be
* used outside the function.
* Once used, the stale pointers are not reset, but left as it is, to
* avoid overhead of protecting it by mode_config.mutex.
*/
struct list_head export_head;
}; };
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment