Path: blob/master/drivers/gpu/drm/nouveau/nouveau_connector.c
15112 views
/*1* Copyright (C) 2008 Maarten Maathuis.2* All Rights Reserved.3*4* Permission is hereby granted, free of charge, to any person obtaining5* a copy of this software and associated documentation files (the6* "Software"), to deal in the Software without restriction, including7* without limitation the rights to use, copy, modify, merge, publish,8* distribute, sublicense, and/or sell copies of the Software, and to9* permit persons to whom the Software is furnished to do so, subject to10* the following conditions:11*12* The above copyright notice and this permission notice (including the13* next paragraph) shall be included in all copies or substantial14* portions of the Software.15*16* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,17* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF18* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.19* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE20* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION21* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION22* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.23*24*/2526#include <acpi/button.h>2728#include "drmP.h"29#include "drm_edid.h"30#include "drm_crtc_helper.h"3132#include "nouveau_reg.h"33#include "nouveau_drv.h"34#include "nouveau_encoder.h"35#include "nouveau_crtc.h"36#include "nouveau_connector.h"37#include "nouveau_hw.h"3839static void nouveau_connector_hotplug(void *, int);4041static struct nouveau_encoder *42find_encoder_by_type(struct drm_connector *connector, int type)43{44struct drm_device *dev = connector->dev;45struct nouveau_encoder *nv_encoder;46struct drm_mode_object *obj;47int i, id;4849for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {50id = connector->encoder_ids[i];51if (!id)52break;5354obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);55if (!obj)56continue;57nv_encoder = nouveau_encoder(obj_to_encoder(obj));5859if (type == OUTPUT_ANY || nv_encoder->dcb->type == type)60return nv_encoder;61}6263return NULL;64}6566struct nouveau_connector *67nouveau_encoder_connector_get(struct nouveau_encoder *encoder)68{69struct drm_device *dev = to_drm_encoder(encoder)->dev;70struct drm_connector *drm_connector;7172list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) {73if (drm_connector->encoder == to_drm_encoder(encoder))74return nouveau_connector(drm_connector);75}7677return NULL;78}7980/*TODO: This could use improvement, and learn to handle the fixed81* BIOS tables etc. It's fine currently, for its only user.82*/83int84nouveau_connector_bpp(struct drm_connector *connector)85{86struct nouveau_connector *nv_connector = nouveau_connector(connector);8788if (nv_connector->edid && nv_connector->edid->revision >= 4) {89u8 bpc = ((nv_connector->edid->input & 0x70) >> 3) + 4;90if (bpc > 4)91return bpc;92}9394return 18;95}9697static void98nouveau_connector_destroy(struct drm_connector *connector)99{100struct nouveau_connector *nv_connector = nouveau_connector(connector);101struct drm_nouveau_private *dev_priv;102struct nouveau_gpio_engine *pgpio;103struct drm_device *dev;104105if (!nv_connector)106return;107108dev = nv_connector->base.dev;109dev_priv = dev->dev_private;110NV_DEBUG_KMS(dev, "\n");111112pgpio = &dev_priv->engine.gpio;113if (pgpio->irq_unregister) {114pgpio->irq_unregister(dev, nv_connector->dcb->gpio_tag,115nouveau_connector_hotplug, connector);116}117118if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||119connector->connector_type == DRM_MODE_CONNECTOR_eDP)120nouveau_backlight_exit(connector);121122kfree(nv_connector->edid);123drm_sysfs_connector_remove(connector);124drm_connector_cleanup(connector);125kfree(connector);126}127128static struct nouveau_i2c_chan *129nouveau_connector_ddc_detect(struct drm_connector *connector,130struct nouveau_encoder **pnv_encoder)131{132struct drm_device *dev = connector->dev;133int i;134135for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {136struct nouveau_i2c_chan *i2c = NULL;137struct nouveau_encoder *nv_encoder;138struct drm_mode_object *obj;139int id;140141id = connector->encoder_ids[i];142if (!id)143break;144145obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);146if (!obj)147continue;148nv_encoder = nouveau_encoder(obj_to_encoder(obj));149150if (nv_encoder->dcb->i2c_index < 0xf)151i2c = nouveau_i2c_find(dev, nv_encoder->dcb->i2c_index);152153if (i2c && nouveau_probe_i2c_addr(i2c, 0x50)) {154*pnv_encoder = nv_encoder;155return i2c;156}157}158159return NULL;160}161162static struct nouveau_encoder *163nouveau_connector_of_detect(struct drm_connector *connector)164{165#ifdef __powerpc__166struct drm_device *dev = connector->dev;167struct nouveau_connector *nv_connector = nouveau_connector(connector);168struct nouveau_encoder *nv_encoder;169struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev);170171if (!dn ||172!((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) ||173(nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG))))174return NULL;175176for_each_child_of_node(dn, cn) {177const char *name = of_get_property(cn, "name", NULL);178const void *edid = of_get_property(cn, "EDID", NULL);179int idx = name ? name[strlen(name) - 1] - 'A' : 0;180181if (nv_encoder->dcb->i2c_index == idx && edid) {182nv_connector->edid =183kmemdup(edid, EDID_LENGTH, GFP_KERNEL);184of_node_put(cn);185return nv_encoder;186}187}188#endif189return NULL;190}191192static void193nouveau_connector_set_encoder(struct drm_connector *connector,194struct nouveau_encoder *nv_encoder)195{196struct nouveau_connector *nv_connector = nouveau_connector(connector);197struct drm_nouveau_private *dev_priv = connector->dev->dev_private;198struct drm_device *dev = connector->dev;199200if (nv_connector->detected_encoder == nv_encoder)201return;202nv_connector->detected_encoder = nv_encoder;203204if (nv_encoder->dcb->type == OUTPUT_LVDS ||205nv_encoder->dcb->type == OUTPUT_TMDS) {206connector->doublescan_allowed = false;207connector->interlace_allowed = false;208} else {209connector->doublescan_allowed = true;210if (dev_priv->card_type == NV_20 ||211(dev_priv->card_type == NV_10 &&212(dev->pci_device & 0x0ff0) != 0x0100 &&213(dev->pci_device & 0x0ff0) != 0x0150))214/* HW is broken */215connector->interlace_allowed = false;216else217connector->interlace_allowed = true;218}219220if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {221drm_connector_property_set_value(connector,222dev->mode_config.dvi_i_subconnector_property,223nv_encoder->dcb->type == OUTPUT_TMDS ?224DRM_MODE_SUBCONNECTOR_DVID :225DRM_MODE_SUBCONNECTOR_DVIA);226}227}228229static enum drm_connector_status230nouveau_connector_detect(struct drm_connector *connector, bool force)231{232struct drm_device *dev = connector->dev;233struct nouveau_connector *nv_connector = nouveau_connector(connector);234struct nouveau_encoder *nv_encoder = NULL;235struct nouveau_i2c_chan *i2c;236int type;237238/* Cleanup the previous EDID block. */239if (nv_connector->edid) {240drm_mode_connector_update_edid_property(connector, NULL);241kfree(nv_connector->edid);242nv_connector->edid = NULL;243}244245i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);246if (i2c) {247nv_connector->edid = drm_get_edid(connector, &i2c->adapter);248drm_mode_connector_update_edid_property(connector,249nv_connector->edid);250if (!nv_connector->edid) {251NV_ERROR(dev, "DDC responded, but no EDID for %s\n",252drm_get_connector_name(connector));253goto detect_analog;254}255256if (nv_encoder->dcb->type == OUTPUT_DP &&257!nouveau_dp_detect(to_drm_encoder(nv_encoder))) {258NV_ERROR(dev, "Detected %s, but failed init\n",259drm_get_connector_name(connector));260return connector_status_disconnected;261}262263/* Override encoder type for DVI-I based on whether EDID264* says the display is digital or analog, both use the265* same i2c channel so the value returned from ddc_detect266* isn't necessarily correct.267*/268if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {269if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL)270type = OUTPUT_TMDS;271else272type = OUTPUT_ANALOG;273274nv_encoder = find_encoder_by_type(connector, type);275if (!nv_encoder) {276NV_ERROR(dev, "Detected %d encoder on %s, "277"but no object!\n", type,278drm_get_connector_name(connector));279return connector_status_disconnected;280}281}282283nouveau_connector_set_encoder(connector, nv_encoder);284return connector_status_connected;285}286287nv_encoder = nouveau_connector_of_detect(connector);288if (nv_encoder) {289nouveau_connector_set_encoder(connector, nv_encoder);290return connector_status_connected;291}292293detect_analog:294nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG);295if (!nv_encoder && !nouveau_tv_disable)296nv_encoder = find_encoder_by_type(connector, OUTPUT_TV);297if (nv_encoder && force) {298struct drm_encoder *encoder = to_drm_encoder(nv_encoder);299struct drm_encoder_helper_funcs *helper =300encoder->helper_private;301302if (helper->detect(encoder, connector) ==303connector_status_connected) {304nouveau_connector_set_encoder(connector, nv_encoder);305return connector_status_connected;306}307308}309310return connector_status_disconnected;311}312313static enum drm_connector_status314nouveau_connector_detect_lvds(struct drm_connector *connector, bool force)315{316struct drm_device *dev = connector->dev;317struct drm_nouveau_private *dev_priv = dev->dev_private;318struct nouveau_connector *nv_connector = nouveau_connector(connector);319struct nouveau_encoder *nv_encoder = NULL;320enum drm_connector_status status = connector_status_disconnected;321322/* Cleanup the previous EDID block. */323if (nv_connector->edid) {324drm_mode_connector_update_edid_property(connector, NULL);325kfree(nv_connector->edid);326nv_connector->edid = NULL;327}328329nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS);330if (!nv_encoder)331return connector_status_disconnected;332333/* Try retrieving EDID via DDC */334if (!dev_priv->vbios.fp_no_ddc) {335status = nouveau_connector_detect(connector, force);336if (status == connector_status_connected)337goto out;338}339340/* On some laptops (Sony, i'm looking at you) there appears to341* be no direct way of accessing the panel's EDID. The only342* option available to us appears to be to ask ACPI for help..343*344* It's important this check's before trying straps, one of the345* said manufacturer's laptops are configured in such a way346* the nouveau decides an entry in the VBIOS FP mode table is347* valid - it's not (rh#613284)348*/349if (nv_encoder->dcb->lvdsconf.use_acpi_for_edid) {350if (!nouveau_acpi_edid(dev, connector)) {351status = connector_status_connected;352goto out;353}354}355356/* If no EDID found above, and the VBIOS indicates a hardcoded357* modeline is avalilable for the panel, set it as the panel's358* native mode and exit.359*/360if (nouveau_bios_fp_mode(dev, NULL) && (dev_priv->vbios.fp_no_ddc ||361nv_encoder->dcb->lvdsconf.use_straps_for_mode)) {362status = connector_status_connected;363goto out;364}365366/* Still nothing, some VBIOS images have a hardcoded EDID block367* stored for the panel stored in them.368*/369if (!dev_priv->vbios.fp_no_ddc) {370struct edid *edid =371(struct edid *)nouveau_bios_embedded_edid(dev);372if (edid) {373nv_connector->edid = kmalloc(EDID_LENGTH, GFP_KERNEL);374*(nv_connector->edid) = *edid;375status = connector_status_connected;376}377}378379out:380#if defined(CONFIG_ACPI_BUTTON) || \381(defined(CONFIG_ACPI_BUTTON_MODULE) && defined(MODULE))382if (status == connector_status_connected &&383!nouveau_ignorelid && !acpi_lid_open())384status = connector_status_unknown;385#endif386387drm_mode_connector_update_edid_property(connector, nv_connector->edid);388nouveau_connector_set_encoder(connector, nv_encoder);389return status;390}391392static void393nouveau_connector_force(struct drm_connector *connector)394{395struct nouveau_connector *nv_connector = nouveau_connector(connector);396struct nouveau_encoder *nv_encoder;397int type;398399if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) {400if (connector->force == DRM_FORCE_ON_DIGITAL)401type = OUTPUT_TMDS;402else403type = OUTPUT_ANALOG;404} else405type = OUTPUT_ANY;406407nv_encoder = find_encoder_by_type(connector, type);408if (!nv_encoder) {409NV_ERROR(connector->dev, "can't find encoder to force %s on!\n",410drm_get_connector_name(connector));411connector->status = connector_status_disconnected;412return;413}414415nouveau_connector_set_encoder(connector, nv_encoder);416}417418static int419nouveau_connector_set_property(struct drm_connector *connector,420struct drm_property *property, uint64_t value)421{422struct nouveau_connector *nv_connector = nouveau_connector(connector);423struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;424struct drm_encoder *encoder = to_drm_encoder(nv_encoder);425struct drm_device *dev = connector->dev;426int ret;427428/* Scaling mode */429if (property == dev->mode_config.scaling_mode_property) {430struct nouveau_crtc *nv_crtc = NULL;431bool modeset = false;432433switch (value) {434case DRM_MODE_SCALE_NONE:435case DRM_MODE_SCALE_FULLSCREEN:436case DRM_MODE_SCALE_CENTER:437case DRM_MODE_SCALE_ASPECT:438break;439default:440return -EINVAL;441}442443/* LVDS always needs gpu scaling */444if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&445value == DRM_MODE_SCALE_NONE)446return -EINVAL;447448/* Changing between GPU and panel scaling requires a full449* modeset450*/451if ((nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) ||452(value == DRM_MODE_SCALE_NONE))453modeset = true;454nv_connector->scaling_mode = value;455456if (connector->encoder && connector->encoder->crtc)457nv_crtc = nouveau_crtc(connector->encoder->crtc);458if (!nv_crtc)459return 0;460461if (modeset || !nv_crtc->set_scale) {462ret = drm_crtc_helper_set_mode(&nv_crtc->base,463&nv_crtc->base.mode,464nv_crtc->base.x,465nv_crtc->base.y, NULL);466if (!ret)467return -EINVAL;468} else {469ret = nv_crtc->set_scale(nv_crtc, value, true);470if (ret)471return ret;472}473474return 0;475}476477/* Dithering */478if (property == dev->mode_config.dithering_mode_property) {479struct nouveau_crtc *nv_crtc = NULL;480481if (value == DRM_MODE_DITHERING_ON)482nv_connector->use_dithering = true;483else484nv_connector->use_dithering = false;485486if (connector->encoder && connector->encoder->crtc)487nv_crtc = nouveau_crtc(connector->encoder->crtc);488489if (!nv_crtc || !nv_crtc->set_dither)490return 0;491492return nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering,493true);494}495496if (nv_encoder && nv_encoder->dcb->type == OUTPUT_TV)497return get_slave_funcs(encoder)->set_property(498encoder, connector, property, value);499500return -EINVAL;501}502503static struct drm_display_mode *504nouveau_connector_native_mode(struct drm_connector *connector)505{506struct drm_connector_helper_funcs *helper = connector->helper_private;507struct nouveau_connector *nv_connector = nouveau_connector(connector);508struct drm_device *dev = connector->dev;509struct drm_display_mode *mode, *largest = NULL;510int high_w = 0, high_h = 0, high_v = 0;511512list_for_each_entry(mode, &nv_connector->base.probed_modes, head) {513mode->vrefresh = drm_mode_vrefresh(mode);514if (helper->mode_valid(connector, mode) != MODE_OK ||515(mode->flags & DRM_MODE_FLAG_INTERLACE))516continue;517518/* Use preferred mode if there is one.. */519if (mode->type & DRM_MODE_TYPE_PREFERRED) {520NV_DEBUG_KMS(dev, "native mode from preferred\n");521return drm_mode_duplicate(dev, mode);522}523524/* Otherwise, take the resolution with the largest width, then525* height, then vertical refresh526*/527if (mode->hdisplay < high_w)528continue;529530if (mode->hdisplay == high_w && mode->vdisplay < high_h)531continue;532533if (mode->hdisplay == high_w && mode->vdisplay == high_h &&534mode->vrefresh < high_v)535continue;536537high_w = mode->hdisplay;538high_h = mode->vdisplay;539high_v = mode->vrefresh;540largest = mode;541}542543NV_DEBUG_KMS(dev, "native mode from largest: %dx%d@%d\n",544high_w, high_h, high_v);545return largest ? drm_mode_duplicate(dev, largest) : NULL;546}547548struct moderec {549int hdisplay;550int vdisplay;551};552553static struct moderec scaler_modes[] = {554{ 1920, 1200 },555{ 1920, 1080 },556{ 1680, 1050 },557{ 1600, 1200 },558{ 1400, 1050 },559{ 1280, 1024 },560{ 1280, 960 },561{ 1152, 864 },562{ 1024, 768 },563{ 800, 600 },564{ 720, 400 },565{ 640, 480 },566{ 640, 400 },567{ 640, 350 },568{}569};570571static int572nouveau_connector_scaler_modes_add(struct drm_connector *connector)573{574struct nouveau_connector *nv_connector = nouveau_connector(connector);575struct drm_display_mode *native = nv_connector->native_mode, *m;576struct drm_device *dev = connector->dev;577struct moderec *mode = &scaler_modes[0];578int modes = 0;579580if (!native)581return 0;582583while (mode->hdisplay) {584if (mode->hdisplay <= native->hdisplay &&585mode->vdisplay <= native->vdisplay) {586m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,587drm_mode_vrefresh(native), false,588false, false);589if (!m)590continue;591592m->type |= DRM_MODE_TYPE_DRIVER;593594drm_mode_probed_add(connector, m);595modes++;596}597598mode++;599}600601return modes;602}603604static int605nouveau_connector_get_modes(struct drm_connector *connector)606{607struct drm_device *dev = connector->dev;608struct drm_nouveau_private *dev_priv = dev->dev_private;609struct nouveau_connector *nv_connector = nouveau_connector(connector);610struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;611struct drm_encoder *encoder = to_drm_encoder(nv_encoder);612int ret = 0;613614/* destroy the native mode, the attached monitor could have changed.615*/616if (nv_connector->native_mode) {617drm_mode_destroy(dev, nv_connector->native_mode);618nv_connector->native_mode = NULL;619}620621if (nv_connector->edid)622ret = drm_add_edid_modes(connector, nv_connector->edid);623else624if (nv_encoder->dcb->type == OUTPUT_LVDS &&625(nv_encoder->dcb->lvdsconf.use_straps_for_mode ||626dev_priv->vbios.fp_no_ddc) && nouveau_bios_fp_mode(dev, NULL)) {627struct drm_display_mode mode;628629nouveau_bios_fp_mode(dev, &mode);630nv_connector->native_mode = drm_mode_duplicate(dev, &mode);631}632633/* Find the native mode if this is a digital panel, if we didn't634* find any modes through DDC previously add the native mode to635* the list of modes.636*/637if (!nv_connector->native_mode)638nv_connector->native_mode =639nouveau_connector_native_mode(connector);640if (ret == 0 && nv_connector->native_mode) {641struct drm_display_mode *mode;642643mode = drm_mode_duplicate(dev, nv_connector->native_mode);644drm_mode_probed_add(connector, mode);645ret = 1;646}647648if (nv_encoder->dcb->type == OUTPUT_TV)649ret = get_slave_funcs(encoder)->get_modes(encoder, connector);650651if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||652nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||653nv_connector->dcb->type == DCB_CONNECTOR_eDP)654ret += nouveau_connector_scaler_modes_add(connector);655656return ret;657}658659static unsigned660get_tmds_link_bandwidth(struct drm_connector *connector)661{662struct nouveau_connector *nv_connector = nouveau_connector(connector);663struct drm_nouveau_private *dev_priv = connector->dev->dev_private;664struct dcb_entry *dcb = nv_connector->detected_encoder->dcb;665666if (dcb->location != DCB_LOC_ON_CHIP ||667dev_priv->chipset >= 0x46)668return 165000;669else if (dev_priv->chipset >= 0x40)670return 155000;671else if (dev_priv->chipset >= 0x18)672return 135000;673else674return 112000;675}676677static int678nouveau_connector_mode_valid(struct drm_connector *connector,679struct drm_display_mode *mode)680{681struct nouveau_connector *nv_connector = nouveau_connector(connector);682struct nouveau_encoder *nv_encoder = nv_connector->detected_encoder;683struct drm_encoder *encoder = to_drm_encoder(nv_encoder);684unsigned min_clock = 25000, max_clock = min_clock;685unsigned clock = mode->clock;686687switch (nv_encoder->dcb->type) {688case OUTPUT_LVDS:689if (nv_connector->native_mode &&690(mode->hdisplay > nv_connector->native_mode->hdisplay ||691mode->vdisplay > nv_connector->native_mode->vdisplay))692return MODE_PANEL;693694min_clock = 0;695max_clock = 400000;696break;697case OUTPUT_TMDS:698max_clock = get_tmds_link_bandwidth(connector);699if (nouveau_duallink && nv_encoder->dcb->duallink_possible)700max_clock *= 2;701break;702case OUTPUT_ANALOG:703max_clock = nv_encoder->dcb->crtconf.maxfreq;704if (!max_clock)705max_clock = 350000;706break;707case OUTPUT_TV:708return get_slave_funcs(encoder)->mode_valid(encoder, mode);709case OUTPUT_DP:710if (nv_encoder->dp.link_bw == DP_LINK_BW_2_7)711max_clock = nv_encoder->dp.link_nr * 270000;712else713max_clock = nv_encoder->dp.link_nr * 162000;714715clock = clock * nouveau_connector_bpp(connector) / 8;716break;717default:718BUG_ON(1);719return MODE_BAD;720}721722if (clock < min_clock)723return MODE_CLOCK_LOW;724725if (clock > max_clock)726return MODE_CLOCK_HIGH;727728return MODE_OK;729}730731static struct drm_encoder *732nouveau_connector_best_encoder(struct drm_connector *connector)733{734struct nouveau_connector *nv_connector = nouveau_connector(connector);735736if (nv_connector->detected_encoder)737return to_drm_encoder(nv_connector->detected_encoder);738739return NULL;740}741742static const struct drm_connector_helper_funcs743nouveau_connector_helper_funcs = {744.get_modes = nouveau_connector_get_modes,745.mode_valid = nouveau_connector_mode_valid,746.best_encoder = nouveau_connector_best_encoder,747};748749static const struct drm_connector_funcs750nouveau_connector_funcs = {751.dpms = drm_helper_connector_dpms,752.save = NULL,753.restore = NULL,754.detect = nouveau_connector_detect,755.destroy = nouveau_connector_destroy,756.fill_modes = drm_helper_probe_single_connector_modes,757.set_property = nouveau_connector_set_property,758.force = nouveau_connector_force759};760761static const struct drm_connector_funcs762nouveau_connector_funcs_lvds = {763.dpms = drm_helper_connector_dpms,764.save = NULL,765.restore = NULL,766.detect = nouveau_connector_detect_lvds,767.destroy = nouveau_connector_destroy,768.fill_modes = drm_helper_probe_single_connector_modes,769.set_property = nouveau_connector_set_property,770.force = nouveau_connector_force771};772773struct drm_connector *774nouveau_connector_create(struct drm_device *dev, int index)775{776const struct drm_connector_funcs *funcs = &nouveau_connector_funcs;777struct drm_nouveau_private *dev_priv = dev->dev_private;778struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio;779struct nouveau_connector *nv_connector = NULL;780struct dcb_connector_table_entry *dcb = NULL;781struct drm_connector *connector;782int type, ret = 0;783784NV_DEBUG_KMS(dev, "\n");785786if (index >= dev_priv->vbios.dcb.connector.entries)787return ERR_PTR(-EINVAL);788789dcb = &dev_priv->vbios.dcb.connector.entry[index];790if (dcb->drm)791return dcb->drm;792793switch (dcb->type) {794case DCB_CONNECTOR_VGA:795type = DRM_MODE_CONNECTOR_VGA;796break;797case DCB_CONNECTOR_TV_0:798case DCB_CONNECTOR_TV_1:799case DCB_CONNECTOR_TV_3:800type = DRM_MODE_CONNECTOR_TV;801break;802case DCB_CONNECTOR_DVI_I:803type = DRM_MODE_CONNECTOR_DVII;804break;805case DCB_CONNECTOR_DVI_D:806type = DRM_MODE_CONNECTOR_DVID;807break;808case DCB_CONNECTOR_HDMI_0:809case DCB_CONNECTOR_HDMI_1:810type = DRM_MODE_CONNECTOR_HDMIA;811break;812case DCB_CONNECTOR_LVDS:813case DCB_CONNECTOR_LVDS_SPWG:814type = DRM_MODE_CONNECTOR_LVDS;815funcs = &nouveau_connector_funcs_lvds;816break;817case DCB_CONNECTOR_DP:818type = DRM_MODE_CONNECTOR_DisplayPort;819break;820case DCB_CONNECTOR_eDP:821type = DRM_MODE_CONNECTOR_eDP;822break;823default:824NV_ERROR(dev, "unknown connector type: 0x%02x!!\n", dcb->type);825return ERR_PTR(-EINVAL);826}827828nv_connector = kzalloc(sizeof(*nv_connector), GFP_KERNEL);829if (!nv_connector)830return ERR_PTR(-ENOMEM);831nv_connector->dcb = dcb;832connector = &nv_connector->base;833834/* defaults, will get overridden in detect() */835connector->interlace_allowed = false;836connector->doublescan_allowed = false;837838drm_connector_init(dev, connector, funcs, type);839drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);840841/* Check if we need dithering enabled */842if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {843bool dummy, is_24bit = false;844845ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);846if (ret) {847NV_ERROR(dev, "Error parsing LVDS table, disabling "848"LVDS\n");849goto fail;850}851852nv_connector->use_dithering = !is_24bit;853}854855/* Init DVI-I specific properties */856if (dcb->type == DCB_CONNECTOR_DVI_I) {857drm_mode_create_dvi_i_properties(dev);858drm_connector_attach_property(connector, dev->mode_config.dvi_i_subconnector_property, 0);859drm_connector_attach_property(connector, dev->mode_config.dvi_i_select_subconnector_property, 0);860}861862switch (dcb->type) {863case DCB_CONNECTOR_VGA:864if (dev_priv->card_type >= NV_50) {865drm_connector_attach_property(connector,866dev->mode_config.scaling_mode_property,867nv_connector->scaling_mode);868}869connector->polled = DRM_CONNECTOR_POLL_CONNECT;870/* fall-through */871case DCB_CONNECTOR_TV_0:872case DCB_CONNECTOR_TV_1:873case DCB_CONNECTOR_TV_3:874nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;875break;876default:877nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;878879drm_connector_attach_property(connector,880dev->mode_config.scaling_mode_property,881nv_connector->scaling_mode);882drm_connector_attach_property(connector,883dev->mode_config.dithering_mode_property,884nv_connector->use_dithering ?885DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);886887if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {888if (dev_priv->card_type >= NV_50)889connector->polled = DRM_CONNECTOR_POLL_HPD;890else891connector->polled = DRM_CONNECTOR_POLL_CONNECT;892}893break;894}895896if (pgpio->irq_register) {897pgpio->irq_register(dev, nv_connector->dcb->gpio_tag,898nouveau_connector_hotplug, connector);899}900901drm_sysfs_connector_add(connector);902903if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||904connector->connector_type == DRM_MODE_CONNECTOR_eDP)905nouveau_backlight_init(connector);906907dcb->drm = connector;908return dcb->drm;909910fail:911drm_connector_cleanup(connector);912kfree(connector);913return ERR_PTR(ret);914915}916917static void918nouveau_connector_hotplug(void *data, int plugged)919{920struct drm_connector *connector = data;921struct drm_device *dev = connector->dev;922923NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un",924drm_get_connector_name(connector));925926if (connector->encoder && connector->encoder->crtc &&927connector->encoder->crtc->enabled) {928struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder);929struct drm_encoder_helper_funcs *helper =930connector->encoder->helper_private;931932if (nv_encoder->dcb->type == OUTPUT_DP) {933if (plugged)934helper->dpms(connector->encoder, DRM_MODE_DPMS_ON);935else936helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF);937}938}939940drm_helper_hpd_irq_event(dev);941}942943944