1*8d754544SDaniel Vetter /* 2*8d754544SDaniel Vetter * Copyright (c) 2006-2008 Intel Corporation 3*8d754544SDaniel Vetter * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 4*8d754544SDaniel Vetter * 5*8d754544SDaniel Vetter * DRM core CRTC related functions 6*8d754544SDaniel Vetter * 7*8d754544SDaniel Vetter * Permission to use, copy, modify, distribute, and sell this software and its 8*8d754544SDaniel Vetter * documentation for any purpose is hereby granted without fee, provided that 9*8d754544SDaniel Vetter * the above copyright notice appear in all copies and that both that copyright 10*8d754544SDaniel Vetter * notice and this permission notice appear in supporting documentation, and 11*8d754544SDaniel Vetter * that the name of the copyright holders not be used in advertising or 12*8d754544SDaniel Vetter * publicity pertaining to distribution of the software without specific, 13*8d754544SDaniel Vetter * written prior permission. The copyright holders make no representations 14*8d754544SDaniel Vetter * about the suitability of this software for any purpose. It is provided "as 15*8d754544SDaniel Vetter * is" without express or implied warranty. 16*8d754544SDaniel Vetter * 17*8d754544SDaniel Vetter * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 18*8d754544SDaniel Vetter * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 19*8d754544SDaniel Vetter * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 20*8d754544SDaniel Vetter * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 21*8d754544SDaniel Vetter * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 22*8d754544SDaniel Vetter * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 23*8d754544SDaniel Vetter * OF THIS SOFTWARE. 24*8d754544SDaniel Vetter * 25*8d754544SDaniel Vetter * Authors: 26*8d754544SDaniel Vetter * Keith Packard 27*8d754544SDaniel Vetter * Eric Anholt <eric@anholt.net> 28*8d754544SDaniel Vetter * Dave Airlie <airlied@linux.ie> 29*8d754544SDaniel Vetter * Jesse Barnes <jesse.barnes@intel.com> 30*8d754544SDaniel Vetter */ 31*8d754544SDaniel Vetter 32*8d754544SDaniel Vetter #include <linux/export.h> 33*8d754544SDaniel Vetter #include <linux/moduleparam.h> 34*8d754544SDaniel Vetter 35*8d754544SDaniel Vetter #include <drm/drmP.h> 36*8d754544SDaniel Vetter #include <drm/drm_crtc.h> 37*8d754544SDaniel Vetter #include <drm/drm_fourcc.h> 38*8d754544SDaniel Vetter #include <drm/drm_crtc_helper.h> 39*8d754544SDaniel Vetter #include <drm/drm_fb_helper.h> 40*8d754544SDaniel Vetter #include <drm/drm_edid.h> 41*8d754544SDaniel Vetter 42*8d754544SDaniel Vetter /** 43*8d754544SDaniel Vetter * DOC: output probing helper overview 44*8d754544SDaniel Vetter * 45*8d754544SDaniel Vetter * This library provides some helper code for output probing. It provides an 46*8d754544SDaniel Vetter * implementation of the core connector->fill_modes interface with 47*8d754544SDaniel Vetter * drm_helper_probe_single_connector_modes. 48*8d754544SDaniel Vetter * 49*8d754544SDaniel Vetter * It also provides support for polling connectors with a work item and for 50*8d754544SDaniel Vetter * generic hotplug interrupt handling where the driver doesn't or cannot keep 51*8d754544SDaniel Vetter * track of a per-connector hpd interrupt. 52*8d754544SDaniel Vetter * 53*8d754544SDaniel Vetter * This helper library can be used independently of the modeset helper library. 54*8d754544SDaniel Vetter * Drivers can also overwrite different parts e.g. use their own hotplug 55*8d754544SDaniel Vetter * handling code to avoid probing unrelated outputs. 56*8d754544SDaniel Vetter */ 57*8d754544SDaniel Vetter 58*8d754544SDaniel Vetter static bool drm_kms_helper_poll = true; 59*8d754544SDaniel Vetter module_param_named(poll, drm_kms_helper_poll, bool, 0600); 60*8d754544SDaniel Vetter 61*8d754544SDaniel Vetter static void drm_mode_validate_flag(struct drm_connector *connector, 62*8d754544SDaniel Vetter int flags) 63*8d754544SDaniel Vetter { 64*8d754544SDaniel Vetter struct drm_display_mode *mode; 65*8d754544SDaniel Vetter 66*8d754544SDaniel Vetter if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE | 67*8d754544SDaniel Vetter DRM_MODE_FLAG_3D_MASK)) 68*8d754544SDaniel Vetter return; 69*8d754544SDaniel Vetter 70*8d754544SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) { 71*8d754544SDaniel Vetter if ((mode->flags & DRM_MODE_FLAG_INTERLACE) && 72*8d754544SDaniel Vetter !(flags & DRM_MODE_FLAG_INTERLACE)) 73*8d754544SDaniel Vetter mode->status = MODE_NO_INTERLACE; 74*8d754544SDaniel Vetter if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) && 75*8d754544SDaniel Vetter !(flags & DRM_MODE_FLAG_DBLSCAN)) 76*8d754544SDaniel Vetter mode->status = MODE_NO_DBLESCAN; 77*8d754544SDaniel Vetter if ((mode->flags & DRM_MODE_FLAG_3D_MASK) && 78*8d754544SDaniel Vetter !(flags & DRM_MODE_FLAG_3D_MASK)) 79*8d754544SDaniel Vetter mode->status = MODE_NO_STEREO; 80*8d754544SDaniel Vetter } 81*8d754544SDaniel Vetter 82*8d754544SDaniel Vetter return; 83*8d754544SDaniel Vetter } 84*8d754544SDaniel Vetter 85*8d754544SDaniel Vetter /** 86*8d754544SDaniel Vetter * drm_helper_probe_single_connector_modes - get complete set of display modes 87*8d754544SDaniel Vetter * @connector: connector to probe 88*8d754544SDaniel Vetter * @maxX: max width for modes 89*8d754544SDaniel Vetter * @maxY: max height for modes 90*8d754544SDaniel Vetter * 91*8d754544SDaniel Vetter * Based on the helper callbacks implemented by @connector try to detect all 92*8d754544SDaniel Vetter * valid modes. Modes will first be added to the connector's probed_modes list, 93*8d754544SDaniel Vetter * then culled (based on validity and the @maxX, @maxY parameters) and put into 94*8d754544SDaniel Vetter * the normal modes list. 95*8d754544SDaniel Vetter * 96*8d754544SDaniel Vetter * Intended to be use as a generic implementation of the ->fill_modes() 97*8d754544SDaniel Vetter * @connector vfunc for drivers that use the crtc helpers for output mode 98*8d754544SDaniel Vetter * filtering and detection. 99*8d754544SDaniel Vetter * 100*8d754544SDaniel Vetter * Returns: 101*8d754544SDaniel Vetter * The number of modes found on @connector. 102*8d754544SDaniel Vetter */ 103*8d754544SDaniel Vetter int drm_helper_probe_single_connector_modes(struct drm_connector *connector, 104*8d754544SDaniel Vetter uint32_t maxX, uint32_t maxY) 105*8d754544SDaniel Vetter { 106*8d754544SDaniel Vetter struct drm_device *dev = connector->dev; 107*8d754544SDaniel Vetter struct drm_display_mode *mode; 108*8d754544SDaniel Vetter struct drm_connector_helper_funcs *connector_funcs = 109*8d754544SDaniel Vetter connector->helper_private; 110*8d754544SDaniel Vetter int count = 0; 111*8d754544SDaniel Vetter int mode_flags = 0; 112*8d754544SDaniel Vetter bool verbose_prune = true; 113*8d754544SDaniel Vetter 114*8d754544SDaniel Vetter WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); 115*8d754544SDaniel Vetter 116*8d754544SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, 117*8d754544SDaniel Vetter drm_get_connector_name(connector)); 118*8d754544SDaniel Vetter /* set all modes to the unverified state */ 119*8d754544SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) 120*8d754544SDaniel Vetter mode->status = MODE_UNVERIFIED; 121*8d754544SDaniel Vetter 122*8d754544SDaniel Vetter if (connector->force) { 123*8d754544SDaniel Vetter if (connector->force == DRM_FORCE_ON) 124*8d754544SDaniel Vetter connector->status = connector_status_connected; 125*8d754544SDaniel Vetter else 126*8d754544SDaniel Vetter connector->status = connector_status_disconnected; 127*8d754544SDaniel Vetter if (connector->funcs->force) 128*8d754544SDaniel Vetter connector->funcs->force(connector); 129*8d754544SDaniel Vetter } else { 130*8d754544SDaniel Vetter connector->status = connector->funcs->detect(connector, true); 131*8d754544SDaniel Vetter } 132*8d754544SDaniel Vetter 133*8d754544SDaniel Vetter /* Re-enable polling in case the global poll config changed. */ 134*8d754544SDaniel Vetter if (drm_kms_helper_poll != dev->mode_config.poll_running) 135*8d754544SDaniel Vetter drm_kms_helper_poll_enable(dev); 136*8d754544SDaniel Vetter 137*8d754544SDaniel Vetter dev->mode_config.poll_running = drm_kms_helper_poll; 138*8d754544SDaniel Vetter 139*8d754544SDaniel Vetter if (connector->status == connector_status_disconnected) { 140*8d754544SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n", 141*8d754544SDaniel Vetter connector->base.id, drm_get_connector_name(connector)); 142*8d754544SDaniel Vetter drm_mode_connector_update_edid_property(connector, NULL); 143*8d754544SDaniel Vetter verbose_prune = false; 144*8d754544SDaniel Vetter goto prune; 145*8d754544SDaniel Vetter } 146*8d754544SDaniel Vetter 147*8d754544SDaniel Vetter #ifdef CONFIG_DRM_LOAD_EDID_FIRMWARE 148*8d754544SDaniel Vetter count = drm_load_edid_firmware(connector); 149*8d754544SDaniel Vetter if (count == 0) 150*8d754544SDaniel Vetter #endif 151*8d754544SDaniel Vetter count = (*connector_funcs->get_modes)(connector); 152*8d754544SDaniel Vetter 153*8d754544SDaniel Vetter if (count == 0 && connector->status == connector_status_connected) 154*8d754544SDaniel Vetter count = drm_add_modes_noedid(connector, 1024, 768); 155*8d754544SDaniel Vetter if (count == 0) 156*8d754544SDaniel Vetter goto prune; 157*8d754544SDaniel Vetter 158*8d754544SDaniel Vetter drm_mode_connector_list_update(connector); 159*8d754544SDaniel Vetter 160*8d754544SDaniel Vetter if (maxX && maxY) 161*8d754544SDaniel Vetter drm_mode_validate_size(dev, &connector->modes, maxX, maxY); 162*8d754544SDaniel Vetter 163*8d754544SDaniel Vetter if (connector->interlace_allowed) 164*8d754544SDaniel Vetter mode_flags |= DRM_MODE_FLAG_INTERLACE; 165*8d754544SDaniel Vetter if (connector->doublescan_allowed) 166*8d754544SDaniel Vetter mode_flags |= DRM_MODE_FLAG_DBLSCAN; 167*8d754544SDaniel Vetter if (connector->stereo_allowed) 168*8d754544SDaniel Vetter mode_flags |= DRM_MODE_FLAG_3D_MASK; 169*8d754544SDaniel Vetter drm_mode_validate_flag(connector, mode_flags); 170*8d754544SDaniel Vetter 171*8d754544SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) { 172*8d754544SDaniel Vetter if (mode->status == MODE_OK) 173*8d754544SDaniel Vetter mode->status = connector_funcs->mode_valid(connector, 174*8d754544SDaniel Vetter mode); 175*8d754544SDaniel Vetter } 176*8d754544SDaniel Vetter 177*8d754544SDaniel Vetter prune: 178*8d754544SDaniel Vetter drm_mode_prune_invalid(dev, &connector->modes, verbose_prune); 179*8d754544SDaniel Vetter 180*8d754544SDaniel Vetter if (list_empty(&connector->modes)) 181*8d754544SDaniel Vetter return 0; 182*8d754544SDaniel Vetter 183*8d754544SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) 184*8d754544SDaniel Vetter mode->vrefresh = drm_mode_vrefresh(mode); 185*8d754544SDaniel Vetter 186*8d754544SDaniel Vetter drm_mode_sort(&connector->modes); 187*8d754544SDaniel Vetter 188*8d754544SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id, 189*8d754544SDaniel Vetter drm_get_connector_name(connector)); 190*8d754544SDaniel Vetter list_for_each_entry(mode, &connector->modes, head) { 191*8d754544SDaniel Vetter drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); 192*8d754544SDaniel Vetter drm_mode_debug_printmodeline(mode); 193*8d754544SDaniel Vetter } 194*8d754544SDaniel Vetter 195*8d754544SDaniel Vetter return count; 196*8d754544SDaniel Vetter } 197*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_helper_probe_single_connector_modes); 198*8d754544SDaniel Vetter 199*8d754544SDaniel Vetter /** 200*8d754544SDaniel Vetter * drm_kms_helper_hotplug_event - fire off KMS hotplug events 201*8d754544SDaniel Vetter * @dev: drm_device whose connector state changed 202*8d754544SDaniel Vetter * 203*8d754544SDaniel Vetter * This function fires off the uevent for userspace and also calls the 204*8d754544SDaniel Vetter * output_poll_changed function, which is most commonly used to inform the fbdev 205*8d754544SDaniel Vetter * emulation code and allow it to update the fbcon output configuration. 206*8d754544SDaniel Vetter * 207*8d754544SDaniel Vetter * Drivers should call this from their hotplug handling code when a change is 208*8d754544SDaniel Vetter * detected. Note that this function does not do any output detection of its 209*8d754544SDaniel Vetter * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the 210*8d754544SDaniel Vetter * driver already. 211*8d754544SDaniel Vetter * 212*8d754544SDaniel Vetter * This function must be called from process context with no mode 213*8d754544SDaniel Vetter * setting locks held. 214*8d754544SDaniel Vetter */ 215*8d754544SDaniel Vetter void drm_kms_helper_hotplug_event(struct drm_device *dev) 216*8d754544SDaniel Vetter { 217*8d754544SDaniel Vetter /* send a uevent + call fbdev */ 218*8d754544SDaniel Vetter drm_sysfs_hotplug_event(dev); 219*8d754544SDaniel Vetter if (dev->mode_config.funcs->output_poll_changed) 220*8d754544SDaniel Vetter dev->mode_config.funcs->output_poll_changed(dev); 221*8d754544SDaniel Vetter } 222*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_kms_helper_hotplug_event); 223*8d754544SDaniel Vetter 224*8d754544SDaniel Vetter #define DRM_OUTPUT_POLL_PERIOD (10*HZ) 225*8d754544SDaniel Vetter static void output_poll_execute(struct work_struct *work) 226*8d754544SDaniel Vetter { 227*8d754544SDaniel Vetter struct delayed_work *delayed_work = to_delayed_work(work); 228*8d754544SDaniel Vetter struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work); 229*8d754544SDaniel Vetter struct drm_connector *connector; 230*8d754544SDaniel Vetter enum drm_connector_status old_status; 231*8d754544SDaniel Vetter bool repoll = false, changed = false; 232*8d754544SDaniel Vetter 233*8d754544SDaniel Vetter if (!drm_kms_helper_poll) 234*8d754544SDaniel Vetter return; 235*8d754544SDaniel Vetter 236*8d754544SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 237*8d754544SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 238*8d754544SDaniel Vetter 239*8d754544SDaniel Vetter /* Ignore forced connectors. */ 240*8d754544SDaniel Vetter if (connector->force) 241*8d754544SDaniel Vetter continue; 242*8d754544SDaniel Vetter 243*8d754544SDaniel Vetter /* Ignore HPD capable connectors and connectors where we don't 244*8d754544SDaniel Vetter * want any hotplug detection at all for polling. */ 245*8d754544SDaniel Vetter if (!connector->polled || connector->polled == DRM_CONNECTOR_POLL_HPD) 246*8d754544SDaniel Vetter continue; 247*8d754544SDaniel Vetter 248*8d754544SDaniel Vetter repoll = true; 249*8d754544SDaniel Vetter 250*8d754544SDaniel Vetter old_status = connector->status; 251*8d754544SDaniel Vetter /* if we are connected and don't want to poll for disconnect 252*8d754544SDaniel Vetter skip it */ 253*8d754544SDaniel Vetter if (old_status == connector_status_connected && 254*8d754544SDaniel Vetter !(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT)) 255*8d754544SDaniel Vetter continue; 256*8d754544SDaniel Vetter 257*8d754544SDaniel Vetter connector->status = connector->funcs->detect(connector, false); 258*8d754544SDaniel Vetter if (old_status != connector->status) { 259*8d754544SDaniel Vetter const char *old, *new; 260*8d754544SDaniel Vetter 261*8d754544SDaniel Vetter old = drm_get_connector_status_name(old_status); 262*8d754544SDaniel Vetter new = drm_get_connector_status_name(connector->status); 263*8d754544SDaniel Vetter 264*8d754544SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s] " 265*8d754544SDaniel Vetter "status updated from %s to %s\n", 266*8d754544SDaniel Vetter connector->base.id, 267*8d754544SDaniel Vetter drm_get_connector_name(connector), 268*8d754544SDaniel Vetter old, new); 269*8d754544SDaniel Vetter 270*8d754544SDaniel Vetter changed = true; 271*8d754544SDaniel Vetter } 272*8d754544SDaniel Vetter } 273*8d754544SDaniel Vetter 274*8d754544SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 275*8d754544SDaniel Vetter 276*8d754544SDaniel Vetter if (changed) 277*8d754544SDaniel Vetter drm_kms_helper_hotplug_event(dev); 278*8d754544SDaniel Vetter 279*8d754544SDaniel Vetter if (repoll) 280*8d754544SDaniel Vetter schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD); 281*8d754544SDaniel Vetter } 282*8d754544SDaniel Vetter 283*8d754544SDaniel Vetter /** 284*8d754544SDaniel Vetter * drm_kms_helper_poll_disable - disable output polling 285*8d754544SDaniel Vetter * @dev: drm_device 286*8d754544SDaniel Vetter * 287*8d754544SDaniel Vetter * This function disables the output polling work. 288*8d754544SDaniel Vetter * 289*8d754544SDaniel Vetter * Drivers can call this helper from their device suspend implementation. It is 290*8d754544SDaniel Vetter * not an error to call this even when output polling isn't enabled or arlready 291*8d754544SDaniel Vetter * disabled. 292*8d754544SDaniel Vetter */ 293*8d754544SDaniel Vetter void drm_kms_helper_poll_disable(struct drm_device *dev) 294*8d754544SDaniel Vetter { 295*8d754544SDaniel Vetter if (!dev->mode_config.poll_enabled) 296*8d754544SDaniel Vetter return; 297*8d754544SDaniel Vetter cancel_delayed_work_sync(&dev->mode_config.output_poll_work); 298*8d754544SDaniel Vetter } 299*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_kms_helper_poll_disable); 300*8d754544SDaniel Vetter 301*8d754544SDaniel Vetter /** 302*8d754544SDaniel Vetter * drm_kms_helper_poll_enable - re-enable output polling. 303*8d754544SDaniel Vetter * @dev: drm_device 304*8d754544SDaniel Vetter * 305*8d754544SDaniel Vetter * This function re-enables the output polling work. 306*8d754544SDaniel Vetter * 307*8d754544SDaniel Vetter * Drivers can call this helper from their device resume implementation. It is 308*8d754544SDaniel Vetter * an error to call this when the output polling support has not yet been set 309*8d754544SDaniel Vetter * up. 310*8d754544SDaniel Vetter */ 311*8d754544SDaniel Vetter void drm_kms_helper_poll_enable(struct drm_device *dev) 312*8d754544SDaniel Vetter { 313*8d754544SDaniel Vetter bool poll = false; 314*8d754544SDaniel Vetter struct drm_connector *connector; 315*8d754544SDaniel Vetter 316*8d754544SDaniel Vetter if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) 317*8d754544SDaniel Vetter return; 318*8d754544SDaniel Vetter 319*8d754544SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 320*8d754544SDaniel Vetter if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | 321*8d754544SDaniel Vetter DRM_CONNECTOR_POLL_DISCONNECT)) 322*8d754544SDaniel Vetter poll = true; 323*8d754544SDaniel Vetter } 324*8d754544SDaniel Vetter 325*8d754544SDaniel Vetter if (poll) 326*8d754544SDaniel Vetter schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); 327*8d754544SDaniel Vetter } 328*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_kms_helper_poll_enable); 329*8d754544SDaniel Vetter 330*8d754544SDaniel Vetter /** 331*8d754544SDaniel Vetter * drm_kms_helper_poll_init - initialize and enable output polling 332*8d754544SDaniel Vetter * @dev: drm_device 333*8d754544SDaniel Vetter * 334*8d754544SDaniel Vetter * This function intializes and then also enables output polling support for 335*8d754544SDaniel Vetter * @dev. Drivers which do not have reliable hotplug support in hardware can use 336*8d754544SDaniel Vetter * this helper infrastructure to regularly poll such connectors for changes in 337*8d754544SDaniel Vetter * their connection state. 338*8d754544SDaniel Vetter * 339*8d754544SDaniel Vetter * Drivers can control which connectors are polled by setting the 340*8d754544SDaniel Vetter * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On 341*8d754544SDaniel Vetter * connectors where probing live outputs can result in visual distortion drivers 342*8d754544SDaniel Vetter * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this. 343*8d754544SDaniel Vetter * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are 344*8d754544SDaniel Vetter * completely ignored by the polling logic. 345*8d754544SDaniel Vetter * 346*8d754544SDaniel Vetter * Note that a connector can be both polled and probed from the hotplug handler, 347*8d754544SDaniel Vetter * in case the hotplug interrupt is known to be unreliable. 348*8d754544SDaniel Vetter */ 349*8d754544SDaniel Vetter void drm_kms_helper_poll_init(struct drm_device *dev) 350*8d754544SDaniel Vetter { 351*8d754544SDaniel Vetter INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute); 352*8d754544SDaniel Vetter dev->mode_config.poll_enabled = true; 353*8d754544SDaniel Vetter 354*8d754544SDaniel Vetter drm_kms_helper_poll_enable(dev); 355*8d754544SDaniel Vetter } 356*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_kms_helper_poll_init); 357*8d754544SDaniel Vetter 358*8d754544SDaniel Vetter /** 359*8d754544SDaniel Vetter * drm_kms_helper_poll_fini - disable output polling and clean it up 360*8d754544SDaniel Vetter * @dev: drm_device 361*8d754544SDaniel Vetter */ 362*8d754544SDaniel Vetter void drm_kms_helper_poll_fini(struct drm_device *dev) 363*8d754544SDaniel Vetter { 364*8d754544SDaniel Vetter drm_kms_helper_poll_disable(dev); 365*8d754544SDaniel Vetter } 366*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_kms_helper_poll_fini); 367*8d754544SDaniel Vetter 368*8d754544SDaniel Vetter /** 369*8d754544SDaniel Vetter * drm_helper_hpd_irq_event - hotplug processing 370*8d754544SDaniel Vetter * @dev: drm_device 371*8d754544SDaniel Vetter * 372*8d754544SDaniel Vetter * Drivers can use this helper function to run a detect cycle on all connectors 373*8d754544SDaniel Vetter * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All 374*8d754544SDaniel Vetter * other connectors are ignored, which is useful to avoid reprobing fixed 375*8d754544SDaniel Vetter * panels. 376*8d754544SDaniel Vetter * 377*8d754544SDaniel Vetter * This helper function is useful for drivers which can't or don't track hotplug 378*8d754544SDaniel Vetter * interrupts for each connector. 379*8d754544SDaniel Vetter * 380*8d754544SDaniel Vetter * Drivers which support hotplug interrupts for each connector individually and 381*8d754544SDaniel Vetter * which have a more fine-grained detect logic should bypass this code and 382*8d754544SDaniel Vetter * directly call drm_kms_helper_hotplug_event() in case the connector state 383*8d754544SDaniel Vetter * changed. 384*8d754544SDaniel Vetter * 385*8d754544SDaniel Vetter * This function must be called from process context with no mode 386*8d754544SDaniel Vetter * setting locks held. 387*8d754544SDaniel Vetter * 388*8d754544SDaniel Vetter * Note that a connector can be both polled and probed from the hotplug handler, 389*8d754544SDaniel Vetter * in case the hotplug interrupt is known to be unreliable. 390*8d754544SDaniel Vetter */ 391*8d754544SDaniel Vetter bool drm_helper_hpd_irq_event(struct drm_device *dev) 392*8d754544SDaniel Vetter { 393*8d754544SDaniel Vetter struct drm_connector *connector; 394*8d754544SDaniel Vetter enum drm_connector_status old_status; 395*8d754544SDaniel Vetter bool changed = false; 396*8d754544SDaniel Vetter 397*8d754544SDaniel Vetter if (!dev->mode_config.poll_enabled) 398*8d754544SDaniel Vetter return false; 399*8d754544SDaniel Vetter 400*8d754544SDaniel Vetter mutex_lock(&dev->mode_config.mutex); 401*8d754544SDaniel Vetter list_for_each_entry(connector, &dev->mode_config.connector_list, head) { 402*8d754544SDaniel Vetter 403*8d754544SDaniel Vetter /* Only handle HPD capable connectors. */ 404*8d754544SDaniel Vetter if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) 405*8d754544SDaniel Vetter continue; 406*8d754544SDaniel Vetter 407*8d754544SDaniel Vetter old_status = connector->status; 408*8d754544SDaniel Vetter 409*8d754544SDaniel Vetter connector->status = connector->funcs->detect(connector, false); 410*8d754544SDaniel Vetter DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", 411*8d754544SDaniel Vetter connector->base.id, 412*8d754544SDaniel Vetter drm_get_connector_name(connector), 413*8d754544SDaniel Vetter drm_get_connector_status_name(old_status), 414*8d754544SDaniel Vetter drm_get_connector_status_name(connector->status)); 415*8d754544SDaniel Vetter if (old_status != connector->status) 416*8d754544SDaniel Vetter changed = true; 417*8d754544SDaniel Vetter } 418*8d754544SDaniel Vetter 419*8d754544SDaniel Vetter mutex_unlock(&dev->mode_config.mutex); 420*8d754544SDaniel Vetter 421*8d754544SDaniel Vetter if (changed) 422*8d754544SDaniel Vetter drm_kms_helper_hotplug_event(dev); 423*8d754544SDaniel Vetter 424*8d754544SDaniel Vetter return changed; 425*8d754544SDaniel Vetter } 426*8d754544SDaniel Vetter EXPORT_SYMBOL(drm_helper_hpd_irq_event); 427