Path: blob/master/drivers/gpu/drm/drm_crtc_helper.c
15111 views
/*1* Copyright (c) 2006-2008 Intel Corporation2* Copyright (c) 2007 Dave Airlie <[email protected]>3*4* DRM core CRTC related functions5*6* Permission to use, copy, modify, distribute, and sell this software and its7* documentation for any purpose is hereby granted without fee, provided that8* the above copyright notice appear in all copies and that both that copyright9* notice and this permission notice appear in supporting documentation, and10* that the name of the copyright holders not be used in advertising or11* publicity pertaining to distribution of the software without specific,12* written prior permission. The copyright holders make no representations13* about the suitability of this software for any purpose. It is provided "as14* is" without express or implied warranty.15*16* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,17* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO18* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR19* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,20* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER21* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE22* OF THIS SOFTWARE.23*24* Authors:25* Keith Packard26* Eric Anholt <[email protected]>27* Dave Airlie <[email protected]>28* Jesse Barnes <[email protected]>29*/3031#include "drmP.h"32#include "drm_crtc.h"33#include "drm_crtc_helper.h"34#include "drm_fb_helper.h"3536static bool drm_kms_helper_poll = true;37module_param_named(poll, drm_kms_helper_poll, bool, 0600);3839static void drm_mode_validate_flag(struct drm_connector *connector,40int flags)41{42struct drm_display_mode *mode, *t;4344if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE))45return;4647list_for_each_entry_safe(mode, t, &connector->modes, head) {48if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&49!(flags & DRM_MODE_FLAG_INTERLACE))50mode->status = MODE_NO_INTERLACE;51if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&52!(flags & DRM_MODE_FLAG_DBLSCAN))53mode->status = MODE_NO_DBLESCAN;54}5556return;57}5859/**60* drm_helper_probe_single_connector_modes - get complete set of display modes61* @dev: DRM device62* @maxX: max width for modes63* @maxY: max height for modes64*65* LOCKING:66* Caller must hold mode config lock.67*68* Based on @dev's mode_config layout, scan all the connectors and try to detect69* modes on them. Modes will first be added to the connector's probed_modes70* list, then culled (based on validity and the @maxX, @maxY parameters) and71* put into the normal modes list.72*73* Intended to be used either at bootup time or when major configuration74* changes have occurred.75*76* FIXME: take into account monitor limits77*78* RETURNS:79* Number of modes found on @connector.80*/81int drm_helper_probe_single_connector_modes(struct drm_connector *connector,82uint32_t maxX, uint32_t maxY)83{84struct drm_device *dev = connector->dev;85struct drm_display_mode *mode, *t;86struct drm_connector_helper_funcs *connector_funcs =87connector->helper_private;88int count = 0;89int mode_flags = 0;9091DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,92drm_get_connector_name(connector));93/* set all modes to the unverified state */94list_for_each_entry_safe(mode, t, &connector->modes, head)95mode->status = MODE_UNVERIFIED;9697if (connector->force) {98if (connector->force == DRM_FORCE_ON)99connector->status = connector_status_connected;100else101connector->status = connector_status_disconnected;102if (connector->funcs->force)103connector->funcs->force(connector);104} else {105connector->status = connector->funcs->detect(connector, true);106drm_kms_helper_poll_enable(dev);107}108109if (connector->status == connector_status_disconnected) {110DRM_DEBUG_KMS("[CONNECTOR:%d:%s] disconnected\n",111connector->base.id, drm_get_connector_name(connector));112drm_mode_connector_update_edid_property(connector, NULL);113goto prune;114}115116count = (*connector_funcs->get_modes)(connector);117if (count == 0 && connector->status == connector_status_connected)118count = drm_add_modes_noedid(connector, 1024, 768);119if (count == 0)120goto prune;121122drm_mode_connector_list_update(connector);123124if (maxX && maxY)125drm_mode_validate_size(dev, &connector->modes, maxX,126maxY, 0);127128if (connector->interlace_allowed)129mode_flags |= DRM_MODE_FLAG_INTERLACE;130if (connector->doublescan_allowed)131mode_flags |= DRM_MODE_FLAG_DBLSCAN;132drm_mode_validate_flag(connector, mode_flags);133134list_for_each_entry_safe(mode, t, &connector->modes, head) {135if (mode->status == MODE_OK)136mode->status = connector_funcs->mode_valid(connector,137mode);138}139140prune:141drm_mode_prune_invalid(dev, &connector->modes, true);142143if (list_empty(&connector->modes))144return 0;145146drm_mode_sort(&connector->modes);147148DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed modes :\n", connector->base.id,149drm_get_connector_name(connector));150list_for_each_entry_safe(mode, t, &connector->modes, head) {151mode->vrefresh = drm_mode_vrefresh(mode);152153drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);154drm_mode_debug_printmodeline(mode);155}156157return count;158}159EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);160161/**162* drm_helper_encoder_in_use - check if a given encoder is in use163* @encoder: encoder to check164*165* LOCKING:166* Caller must hold mode config lock.167*168* Walk @encoders's DRM device's mode_config and see if it's in use.169*170* RETURNS:171* True if @encoder is part of the mode_config, false otherwise.172*/173bool drm_helper_encoder_in_use(struct drm_encoder *encoder)174{175struct drm_connector *connector;176struct drm_device *dev = encoder->dev;177list_for_each_entry(connector, &dev->mode_config.connector_list, head)178if (connector->encoder == encoder)179return true;180return false;181}182EXPORT_SYMBOL(drm_helper_encoder_in_use);183184/**185* drm_helper_crtc_in_use - check if a given CRTC is in a mode_config186* @crtc: CRTC to check187*188* LOCKING:189* Caller must hold mode config lock.190*191* Walk @crtc's DRM device's mode_config and see if it's in use.192*193* RETURNS:194* True if @crtc is part of the mode_config, false otherwise.195*/196bool drm_helper_crtc_in_use(struct drm_crtc *crtc)197{198struct drm_encoder *encoder;199struct drm_device *dev = crtc->dev;200/* FIXME: Locking around list access? */201list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)202if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))203return true;204return false;205}206EXPORT_SYMBOL(drm_helper_crtc_in_use);207208static void209drm_encoder_disable(struct drm_encoder *encoder)210{211struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;212213if (encoder_funcs->disable)214(*encoder_funcs->disable)(encoder);215else216(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);217}218219/**220* drm_helper_disable_unused_functions - disable unused objects221* @dev: DRM device222*223* LOCKING:224* Caller must hold mode config lock.225*226* If an connector or CRTC isn't part of @dev's mode_config, it can be disabled227* by calling its dpms function, which should power it off.228*/229void drm_helper_disable_unused_functions(struct drm_device *dev)230{231struct drm_encoder *encoder;232struct drm_connector *connector;233struct drm_crtc *crtc;234235list_for_each_entry(connector, &dev->mode_config.connector_list, head) {236if (!connector->encoder)237continue;238if (connector->status == connector_status_disconnected)239connector->encoder = NULL;240}241242list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {243if (!drm_helper_encoder_in_use(encoder)) {244drm_encoder_disable(encoder);245/* disconnector encoder from any connector */246encoder->crtc = NULL;247}248}249250list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {251struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;252crtc->enabled = drm_helper_crtc_in_use(crtc);253if (!crtc->enabled) {254if (crtc_funcs->disable)255(*crtc_funcs->disable)(crtc);256else257(*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);258crtc->fb = NULL;259}260}261}262EXPORT_SYMBOL(drm_helper_disable_unused_functions);263264/**265* drm_encoder_crtc_ok - can a given crtc drive a given encoder?266* @encoder: encoder to test267* @crtc: crtc to test268*269* Return false if @encoder can't be driven by @crtc, true otherwise.270*/271static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,272struct drm_crtc *crtc)273{274struct drm_device *dev;275struct drm_crtc *tmp;276int crtc_mask = 1;277278WARN(!crtc, "checking null crtc?\n");279280dev = crtc->dev;281282list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {283if (tmp == crtc)284break;285crtc_mask <<= 1;286}287288if (encoder->possible_crtcs & crtc_mask)289return true;290return false;291}292293/*294* Check the CRTC we're going to map each output to vs. its current295* CRTC. If they don't match, we have to disable the output and the CRTC296* since the driver will have to re-route things.297*/298static void299drm_crtc_prepare_encoders(struct drm_device *dev)300{301struct drm_encoder_helper_funcs *encoder_funcs;302struct drm_encoder *encoder;303304list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {305encoder_funcs = encoder->helper_private;306/* Disable unused encoders */307if (encoder->crtc == NULL)308drm_encoder_disable(encoder);309/* Disable encoders whose CRTC is about to change */310if (encoder_funcs->get_crtc &&311encoder->crtc != (*encoder_funcs->get_crtc)(encoder))312drm_encoder_disable(encoder);313}314}315316/**317* drm_crtc_set_mode - set a mode318* @crtc: CRTC to program319* @mode: mode to use320* @x: width of mode321* @y: height of mode322*323* LOCKING:324* Caller must hold mode config lock.325*326* Try to set @mode on @crtc. Give @crtc and its associated connectors a chance327* to fixup or reject the mode prior to trying to set it.328*329* RETURNS:330* True if the mode was set successfully, or false otherwise.331*/332bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,333struct drm_display_mode *mode,334int x, int y,335struct drm_framebuffer *old_fb)336{337struct drm_device *dev = crtc->dev;338struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;339struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;340struct drm_encoder_helper_funcs *encoder_funcs;341int saved_x, saved_y;342struct drm_encoder *encoder;343bool ret = true;344345crtc->enabled = drm_helper_crtc_in_use(crtc);346if (!crtc->enabled)347return true;348349adjusted_mode = drm_mode_duplicate(dev, mode);350351saved_hwmode = crtc->hwmode;352saved_mode = crtc->mode;353saved_x = crtc->x;354saved_y = crtc->y;355356/* Update crtc values up front so the driver can rely on them for mode357* setting.358*/359crtc->mode = *mode;360crtc->x = x;361crtc->y = y;362363/* Pass our mode to the connectors and the CRTC to give them a chance to364* adjust it according to limitations or connector properties, and also365* a chance to reject the mode entirely.366*/367list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {368369if (encoder->crtc != crtc)370continue;371encoder_funcs = encoder->helper_private;372if (!(ret = encoder_funcs->mode_fixup(encoder, mode,373adjusted_mode))) {374goto done;375}376}377378if (!(ret = crtc_funcs->mode_fixup(crtc, mode, adjusted_mode))) {379goto done;380}381DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);382383/* Prepare the encoders and CRTCs before setting the mode. */384list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {385386if (encoder->crtc != crtc)387continue;388encoder_funcs = encoder->helper_private;389/* Disable the encoders as the first thing we do. */390encoder_funcs->prepare(encoder);391}392393drm_crtc_prepare_encoders(dev);394395crtc_funcs->prepare(crtc);396397/* Set up the DPLL and any encoders state that needs to adjust or depend398* on the DPLL.399*/400ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);401if (!ret)402goto done;403404list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {405406if (encoder->crtc != crtc)407continue;408409DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",410encoder->base.id, drm_get_encoder_name(encoder),411mode->base.id, mode->name);412encoder_funcs = encoder->helper_private;413encoder_funcs->mode_set(encoder, mode, adjusted_mode);414}415416/* Now enable the clocks, plane, pipe, and connectors that we set up. */417crtc_funcs->commit(crtc);418419list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {420421if (encoder->crtc != crtc)422continue;423424encoder_funcs = encoder->helper_private;425encoder_funcs->commit(encoder);426427}428429/* Store real post-adjustment hardware mode. */430crtc->hwmode = *adjusted_mode;431432/* Calculate and store various constants which433* are later needed by vblank and swap-completion434* timestamping. They are derived from true hwmode.435*/436drm_calc_timestamping_constants(crtc);437438/* FIXME: add subpixel order */439done:440drm_mode_destroy(dev, adjusted_mode);441if (!ret) {442crtc->hwmode = saved_hwmode;443crtc->mode = saved_mode;444crtc->x = saved_x;445crtc->y = saved_y;446}447448return ret;449}450EXPORT_SYMBOL(drm_crtc_helper_set_mode);451452453/**454* drm_crtc_helper_set_config - set a new config from userspace455* @crtc: CRTC to setup456* @crtc_info: user provided configuration457* @new_mode: new mode to set458* @connector_set: set of connectors for the new config459* @fb: new framebuffer460*461* LOCKING:462* Caller must hold mode config lock.463*464* Setup a new configuration, provided by the user in @crtc_info, and enable465* it.466*467* RETURNS:468* Zero. (FIXME)469*/470int drm_crtc_helper_set_config(struct drm_mode_set *set)471{472struct drm_device *dev;473struct drm_crtc *save_crtcs, *new_crtc, *crtc;474struct drm_encoder *save_encoders, *new_encoder, *encoder;475struct drm_framebuffer *old_fb = NULL;476bool mode_changed = false; /* if true do a full mode set */477bool fb_changed = false; /* if true and !mode_changed just do a flip */478struct drm_connector *save_connectors, *connector;479int count = 0, ro, fail = 0;480struct drm_crtc_helper_funcs *crtc_funcs;481int ret = 0;482int i;483484DRM_DEBUG_KMS("\n");485486if (!set)487return -EINVAL;488489if (!set->crtc)490return -EINVAL;491492if (!set->crtc->helper_private)493return -EINVAL;494495crtc_funcs = set->crtc->helper_private;496497if (!set->mode)498set->fb = NULL;499500if (set->fb) {501DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n",502set->crtc->base.id, set->fb->base.id,503(int)set->num_connectors, set->x, set->y);504} else {505DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id);506set->mode = NULL;507set->num_connectors = 0;508}509510dev = set->crtc->dev;511512/* Allocate space for the backup of all (non-pointer) crtc, encoder and513* connector data. */514save_crtcs = kzalloc(dev->mode_config.num_crtc *515sizeof(struct drm_crtc), GFP_KERNEL);516if (!save_crtcs)517return -ENOMEM;518519save_encoders = kzalloc(dev->mode_config.num_encoder *520sizeof(struct drm_encoder), GFP_KERNEL);521if (!save_encoders) {522kfree(save_crtcs);523return -ENOMEM;524}525526save_connectors = kzalloc(dev->mode_config.num_connector *527sizeof(struct drm_connector), GFP_KERNEL);528if (!save_connectors) {529kfree(save_crtcs);530kfree(save_encoders);531return -ENOMEM;532}533534/* Copy data. Note that driver private data is not affected.535* Should anything bad happen only the expected state is536* restored, not the drivers personal bookkeeping.537*/538count = 0;539list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {540save_crtcs[count++] = *crtc;541}542543count = 0;544list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {545save_encoders[count++] = *encoder;546}547548count = 0;549list_for_each_entry(connector, &dev->mode_config.connector_list, head) {550save_connectors[count++] = *connector;551}552553/* We should be able to check here if the fb has the same properties554* and then just flip_or_move it */555if (set->crtc->fb != set->fb) {556/* If we have no fb then treat it as a full mode set */557if (set->crtc->fb == NULL) {558DRM_DEBUG_KMS("crtc has no fb, full mode set\n");559mode_changed = true;560} else if (set->fb == NULL) {561mode_changed = true;562} else563fb_changed = true;564}565566if (set->x != set->crtc->x || set->y != set->crtc->y)567fb_changed = true;568569if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {570DRM_DEBUG_KMS("modes are different, full mode set\n");571drm_mode_debug_printmodeline(&set->crtc->mode);572drm_mode_debug_printmodeline(set->mode);573mode_changed = true;574}575576/* a) traverse passed in connector list and get encoders for them */577count = 0;578list_for_each_entry(connector, &dev->mode_config.connector_list, head) {579struct drm_connector_helper_funcs *connector_funcs =580connector->helper_private;581new_encoder = connector->encoder;582for (ro = 0; ro < set->num_connectors; ro++) {583if (set->connectors[ro] == connector) {584new_encoder = connector_funcs->best_encoder(connector);585/* if we can't get an encoder for a connector586we are setting now - then fail */587if (new_encoder == NULL)588/* don't break so fail path works correct */589fail = 1;590break;591}592}593594if (new_encoder != connector->encoder) {595DRM_DEBUG_KMS("encoder changed, full mode switch\n");596mode_changed = true;597/* If the encoder is reused for another connector, then598* the appropriate crtc will be set later.599*/600if (connector->encoder)601connector->encoder->crtc = NULL;602connector->encoder = new_encoder;603}604}605606if (fail) {607ret = -EINVAL;608goto fail;609}610611count = 0;612list_for_each_entry(connector, &dev->mode_config.connector_list, head) {613if (!connector->encoder)614continue;615616if (connector->encoder->crtc == set->crtc)617new_crtc = NULL;618else619new_crtc = connector->encoder->crtc;620621for (ro = 0; ro < set->num_connectors; ro++) {622if (set->connectors[ro] == connector)623new_crtc = set->crtc;624}625626/* Make sure the new CRTC will work with the encoder */627if (new_crtc &&628!drm_encoder_crtc_ok(connector->encoder, new_crtc)) {629ret = -EINVAL;630goto fail;631}632if (new_crtc != connector->encoder->crtc) {633DRM_DEBUG_KMS("crtc changed, full mode switch\n");634mode_changed = true;635connector->encoder->crtc = new_crtc;636}637if (new_crtc) {638DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n",639connector->base.id, drm_get_connector_name(connector),640new_crtc->base.id);641} else {642DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n",643connector->base.id, drm_get_connector_name(connector));644}645}646647/* mode_set_base is not a required function */648if (fb_changed && !crtc_funcs->mode_set_base)649mode_changed = true;650651if (mode_changed) {652set->crtc->enabled = drm_helper_crtc_in_use(set->crtc);653if (set->crtc->enabled) {654DRM_DEBUG_KMS("attempting to set mode from"655" userspace\n");656drm_mode_debug_printmodeline(set->mode);657old_fb = set->crtc->fb;658set->crtc->fb = set->fb;659if (!drm_crtc_helper_set_mode(set->crtc, set->mode,660set->x, set->y,661old_fb)) {662DRM_ERROR("failed to set mode on [CRTC:%d]\n",663set->crtc->base.id);664set->crtc->fb = old_fb;665ret = -EINVAL;666goto fail;667}668DRM_DEBUG_KMS("Setting connector DPMS state to on\n");669for (i = 0; i < set->num_connectors; i++) {670DRM_DEBUG_KMS("\t[CONNECTOR:%d:%s] set DPMS on\n", set->connectors[i]->base.id,671drm_get_connector_name(set->connectors[i]));672set->connectors[i]->dpms = DRM_MODE_DPMS_ON;673}674}675drm_helper_disable_unused_functions(dev);676} else if (fb_changed) {677set->crtc->x = set->x;678set->crtc->y = set->y;679680old_fb = set->crtc->fb;681if (set->crtc->fb != set->fb)682set->crtc->fb = set->fb;683ret = crtc_funcs->mode_set_base(set->crtc,684set->x, set->y, old_fb);685if (ret != 0) {686set->crtc->fb = old_fb;687goto fail;688}689}690691kfree(save_connectors);692kfree(save_encoders);693kfree(save_crtcs);694return 0;695696fail:697/* Restore all previous data. */698count = 0;699list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {700*crtc = save_crtcs[count++];701}702703count = 0;704list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {705*encoder = save_encoders[count++];706}707708count = 0;709list_for_each_entry(connector, &dev->mode_config.connector_list, head) {710*connector = save_connectors[count++];711}712713kfree(save_connectors);714kfree(save_encoders);715kfree(save_crtcs);716return ret;717}718EXPORT_SYMBOL(drm_crtc_helper_set_config);719720static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder)721{722int dpms = DRM_MODE_DPMS_OFF;723struct drm_connector *connector;724struct drm_device *dev = encoder->dev;725726list_for_each_entry(connector, &dev->mode_config.connector_list, head)727if (connector->encoder == encoder)728if (connector->dpms < dpms)729dpms = connector->dpms;730return dpms;731}732733static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc)734{735int dpms = DRM_MODE_DPMS_OFF;736struct drm_connector *connector;737struct drm_device *dev = crtc->dev;738739list_for_each_entry(connector, &dev->mode_config.connector_list, head)740if (connector->encoder && connector->encoder->crtc == crtc)741if (connector->dpms < dpms)742dpms = connector->dpms;743return dpms;744}745746/**747* drm_helper_connector_dpms748* @connector affected connector749* @mode DPMS mode750*751* Calls the low-level connector DPMS function, then752* calls appropriate encoder and crtc DPMS functions as well753*/754void drm_helper_connector_dpms(struct drm_connector *connector, int mode)755{756struct drm_encoder *encoder = connector->encoder;757struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;758int old_dpms;759760if (mode == connector->dpms)761return;762763old_dpms = connector->dpms;764connector->dpms = mode;765766/* from off to on, do crtc then encoder */767if (mode < old_dpms) {768if (crtc) {769struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;770if (crtc_funcs->dpms)771(*crtc_funcs->dpms) (crtc,772drm_helper_choose_crtc_dpms(crtc));773}774if (encoder) {775struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;776if (encoder_funcs->dpms)777(*encoder_funcs->dpms) (encoder,778drm_helper_choose_encoder_dpms(encoder));779}780}781782/* from on to off, do encoder then crtc */783if (mode > old_dpms) {784if (encoder) {785struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;786if (encoder_funcs->dpms)787(*encoder_funcs->dpms) (encoder,788drm_helper_choose_encoder_dpms(encoder));789}790if (crtc) {791struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;792if (crtc_funcs->dpms)793(*crtc_funcs->dpms) (crtc,794drm_helper_choose_crtc_dpms(crtc));795}796}797798return;799}800EXPORT_SYMBOL(drm_helper_connector_dpms);801802int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,803struct drm_mode_fb_cmd *mode_cmd)804{805fb->width = mode_cmd->width;806fb->height = mode_cmd->height;807fb->pitch = mode_cmd->pitch;808fb->bits_per_pixel = mode_cmd->bpp;809fb->depth = mode_cmd->depth;810811return 0;812}813EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);814815int drm_helper_resume_force_mode(struct drm_device *dev)816{817struct drm_crtc *crtc;818struct drm_encoder *encoder;819struct drm_encoder_helper_funcs *encoder_funcs;820struct drm_crtc_helper_funcs *crtc_funcs;821int ret;822823list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {824825if (!crtc->enabled)826continue;827828ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,829crtc->x, crtc->y, crtc->fb);830831if (ret == false)832DRM_ERROR("failed to set mode on crtc %p\n", crtc);833834/* Turn off outputs that were already powered off */835if (drm_helper_choose_crtc_dpms(crtc)) {836list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {837838if(encoder->crtc != crtc)839continue;840841encoder_funcs = encoder->helper_private;842if (encoder_funcs->dpms)843(*encoder_funcs->dpms) (encoder,844drm_helper_choose_encoder_dpms(encoder));845}846847crtc_funcs = crtc->helper_private;848if (crtc_funcs->dpms)849(*crtc_funcs->dpms) (crtc,850drm_helper_choose_crtc_dpms(crtc));851}852}853/* disable the unused connectors while restoring the modesetting */854drm_helper_disable_unused_functions(dev);855return 0;856}857EXPORT_SYMBOL(drm_helper_resume_force_mode);858859#define DRM_OUTPUT_POLL_PERIOD (10*HZ)860static void output_poll_execute(struct work_struct *work)861{862struct delayed_work *delayed_work = to_delayed_work(work);863struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);864struct drm_connector *connector;865enum drm_connector_status old_status;866bool repoll = false, changed = false;867868if (!drm_kms_helper_poll)869return;870871mutex_lock(&dev->mode_config.mutex);872list_for_each_entry(connector, &dev->mode_config.connector_list, head) {873874/* if this is HPD or polled don't check it -875TV out for instance */876if (!connector->polled)877continue;878879else if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT))880repoll = true;881882old_status = connector->status;883/* if we are connected and don't want to poll for disconnect884skip it */885if (old_status == connector_status_connected &&886!(connector->polled & DRM_CONNECTOR_POLL_DISCONNECT) &&887!(connector->polled & DRM_CONNECTOR_POLL_HPD))888continue;889890connector->status = connector->funcs->detect(connector, false);891DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",892connector->base.id,893drm_get_connector_name(connector),894old_status, connector->status);895if (old_status != connector->status)896changed = true;897}898899mutex_unlock(&dev->mode_config.mutex);900901if (changed) {902/* send a uevent + call fbdev */903drm_sysfs_hotplug_event(dev);904if (dev->mode_config.funcs->output_poll_changed)905dev->mode_config.funcs->output_poll_changed(dev);906}907908if (repoll)909queue_delayed_work(system_nrt_wq, delayed_work, DRM_OUTPUT_POLL_PERIOD);910}911912void drm_kms_helper_poll_disable(struct drm_device *dev)913{914if (!dev->mode_config.poll_enabled)915return;916cancel_delayed_work_sync(&dev->mode_config.output_poll_work);917}918EXPORT_SYMBOL(drm_kms_helper_poll_disable);919920void drm_kms_helper_poll_enable(struct drm_device *dev)921{922bool poll = false;923struct drm_connector *connector;924925if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll)926return;927928list_for_each_entry(connector, &dev->mode_config.connector_list, head) {929if (connector->polled)930poll = true;931}932933if (poll)934queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD);935}936EXPORT_SYMBOL(drm_kms_helper_poll_enable);937938void drm_kms_helper_poll_init(struct drm_device *dev)939{940INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);941dev->mode_config.poll_enabled = true;942943drm_kms_helper_poll_enable(dev);944}945EXPORT_SYMBOL(drm_kms_helper_poll_init);946947void drm_kms_helper_poll_fini(struct drm_device *dev)948{949drm_kms_helper_poll_disable(dev);950}951EXPORT_SYMBOL(drm_kms_helper_poll_fini);952953void drm_helper_hpd_irq_event(struct drm_device *dev)954{955if (!dev->mode_config.poll_enabled)956return;957958/* kill timer and schedule immediate execution, this doesn't block */959cancel_delayed_work(&dev->mode_config.output_poll_work);960if (drm_kms_helper_poll)961queue_delayed_work(system_nrt_wq, &dev->mode_config.output_poll_work, 0);962}963EXPORT_SYMBOL(drm_helper_hpd_irq_event);964965966