39,6 → 39,35 |
#include <drm/drm_fb_helper.h> |
#include <drm/drm_edid.h> |
|
/** |
* drm_helper_move_panel_connectors_to_head() - move panels to the front in the |
* connector list |
* @dev: drm device to operate on |
* |
* Some userspace presumes that the first connected connector is the main |
* display, where it's supposed to display e.g. the login screen. For |
* laptops, this should be the main panel. Use this function to sort all |
* (eDP/LVDS) panels to the front of the connector list, instead of |
* painstakingly trying to initialize them in the right order. |
*/ |
void drm_helper_move_panel_connectors_to_head(struct drm_device *dev) |
{ |
struct drm_connector *connector, *tmp; |
struct list_head panel_list; |
|
INIT_LIST_HEAD(&panel_list); |
|
list_for_each_entry_safe(connector, tmp, |
&dev->mode_config.connector_list, head) { |
if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS || |
connector->connector_type == DRM_MODE_CONNECTOR_eDP) |
list_move_tail(&connector->head, &panel_list); |
} |
|
list_splice(&panel_list, &dev->mode_config.connector_list); |
} |
EXPORT_SYMBOL(drm_helper_move_panel_connectors_to_head); |
|
static bool drm_kms_helper_poll = true; |
|
static void drm_mode_validate_flag(struct drm_connector *connector, |
63,7 → 92,7 |
|
/** |
* drm_helper_probe_single_connector_modes - get complete set of display modes |
* @dev: DRM device |
* @connector: connector to probe |
* @maxX: max width for modes |
* @maxY: max height for modes |
* |
70,16 → 99,15 |
* LOCKING: |
* Caller must hold mode config lock. |
* |
* Based on @dev's mode_config layout, scan all the connectors and try to detect |
* modes on them. Modes will first be added to the connector's probed_modes |
* list, then culled (based on validity and the @maxX, @maxY parameters) and |
* put into the normal modes list. |
* Based on the helper callbacks implemented by @connector try to detect all |
* valid modes. Modes will first be added to the connector's probed_modes list, |
* then culled (based on validity and the @maxX, @maxY parameters) and put into |
* the normal modes list. |
* |
* Intended to be used either at bootup time or when major configuration |
* changes have occurred. |
* Intended to be use as a generic implementation of the ->probe() @connector |
* callback for drivers that use the crtc helpers for output mode filtering and |
* detection. |
* |
* FIXME: take into account monitor limits |
* |
* RETURNS: |
* Number of modes found on @connector. |
*/ |
325,17 → 353,24 |
} |
|
/** |
* drm_crtc_set_mode - set a mode |
* drm_crtc_helper_set_mode - internal helper to set a mode |
* @crtc: CRTC to program |
* @mode: mode to use |
* @x: width of mode |
* @y: height of mode |
* @x: horizontal offset into the surface |
* @y: vertical offset into the surface |
* @old_fb: old framebuffer, for cleanup |
* |
* LOCKING: |
* Caller must hold mode config lock. |
* |
* Try to set @mode on @crtc. Give @crtc and its associated connectors a chance |
* to fixup or reject the mode prior to trying to set it. |
* to fixup or reject the mode prior to trying to set it. This is an internal |
* helper that drivers could e.g. use to update properties that require the |
* entire output pipe to be disabled and re-enabled in a new configuration. For |
* example for changing whether audio is enabled on a hdmi link or for changing |
* panel fitter or dither attributes. It is also called by the |
* drm_crtc_helper_set_config() helper function to drive the mode setting |
* sequence. |
* |
* RETURNS: |
* True if the mode was set successfully, or false otherwise. |
357,14 → 392,10 |
if (!crtc->enabled) |
return true; |
|
printf("crtc->enabled\n"); |
|
adjusted_mode = drm_mode_duplicate(dev, mode); |
if (!adjusted_mode) |
return false; |
|
printf("adjusted_mode\n"); |
|
saved_hwmode = crtc->hwmode; |
saved_mode = crtc->mode; |
saved_x = crtc->x; |
393,9 → 424,6 |
} |
} |
|
printf("list_for_each_entry\n"); |
printf("mode_fixup %x\n", crtc_funcs->mode_fixup); |
|
if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) { |
DRM_DEBUG_KMS("CRTC fixup failed\n"); |
goto done; |
498,20 → 526,19 |
|
/** |
* drm_crtc_helper_set_config - set a new config from userspace |
* @crtc: CRTC to setup |
* @crtc_info: user provided configuration |
* @new_mode: new mode to set |
* @connector_set: set of connectors for the new config |
* @fb: new framebuffer |
* @set: mode set configuration |
* |
* LOCKING: |
* Caller must hold mode config lock. |
* |
* Setup a new configuration, provided by the user in @crtc_info, and enable |
* it. |
* Setup a new configuration, provided by the upper layers (either an ioctl call |
* from userspace or internally e.g. from the fbdev suppport code) in @set, and |
* enable it. This is the main helper functions for drivers that implement |
* kernel mode setting with the crtc helper functions and the assorted |
* ->prepare(), ->modeset() and ->commit() helper callbacks. |
* |
* RETURNS: |
* Zero. (FIXME) |
* Returns 0 on success, -ERRNO on failure. |
*/ |
int drm_crtc_helper_set_config(struct drm_mode_set *set) |
{ |
807,12 → 834,14 |
} |
|
/** |
* drm_helper_connector_dpms |
* @connector affected connector |
* @mode DPMS mode |
* drm_helper_connector_dpms() - connector dpms helper implementation |
* @connector: affected connector |
* @mode: DPMS mode |
* |
* Calls the low-level connector DPMS function, then |
* calls appropriate encoder and crtc DPMS functions as well |
* This is the main helper function provided by the crtc helper framework for |
* implementing the DPMS connector attribute. It computes the new desired DPMS |
* state for all encoders and crtcs in the output mesh and calls the ->dpms() |
* callback provided by the driver appropriately. |
*/ |
void drm_helper_connector_dpms(struct drm_connector *connector, int mode) |
{ |
942,12 → 971,15 |
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
/* if this is HPD or polled don't check it - |
TV out for instance */ |
if (!connector->polled) |
/* Ignore forced connectors. */ |
if (connector->force) |
continue; |
|
else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) |
/* Ignore HPD capable connectors and connectors where we don't |
* want any hotplug detection at all for polling. */ |
if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) |
continue; |
|
repoll = true; |
|
old_status = connector->status; |
954,8 → 986,7 |
/* if we are connected and don't want to poll for disconnect |
skip it */ |
if (old_status == connector_status_connected && |
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) && |
!(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) |
continue; |
|
connector->status = connector->funcs->detect(connector, false); |
969,12 → 1000,8 |
|
mutex_unlock(&dev->mode_config.mutex); |
|
if (changed) { |
/* send a uevent + call fbdev */ |
drm_sysfs_hotplug_event(dev); |
if (dev->mode_config.funcs->output_poll_changed) |
dev->mode_config.funcs->output_poll_changed(dev); |
} |
if (changed) |
drm_kms_helper_hotplug_event(dev); |
|
if (repoll) |
schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); |
997,7 → 1024,8 |
return; |
|
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
if (connector->polled) |
if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | |
DRM_CONNECTOR_POLL_DISCONNECT)) |
poll = true; |
} |
|
1023,14 → 1051,36 |
|
void drm_helper_hpd_irq_event(struct drm_device *dev) |
{ |
struct drm_connector *connector; |
enum drm_connector_status old_status; |
bool changed = false; |
|
if (!dev->mode_config.poll_enabled) |
return; |
|
/* kill timer and schedule immediate execution, this doesn't block */ |
cancel_delayed_work(&dev->mode_config.output_poll_work); |
if (drm_kms_helper_poll) |
schedule_delayed_work(&dev->mode_config.output_poll_work, 0); |
mutex_lock(&dev->mode_config.mutex); |
list_for_each_entry(connector, &dev->mode_config.connector_list, head) { |
|
/* Only handle HPD capable connectors. */ |
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) |
continue; |
|
old_status = connector->status; |
|
connector->status = connector->funcs->detect(connector, false); |
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", |
connector->base.id, |
drm_get_connector_name(connector), |
old_status, connector->status); |
if (old_status != connector->status) |
changed = true; |
} |
|
mutex_unlock(&dev->mode_config.mutex); |
|
if (changed) |
drm_kms_helper_hotplug_event(dev); |
} |
EXPORT_SYMBOL(drm_helper_hpd_irq_event); |
|
#endif |