Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2009 Red Hat Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  * Authors: Ben Skeggs
0023  */
0024 
0025 #include <drm/display/drm_dp_helper.h>
0026 
0027 #include "nouveau_drv.h"
0028 #include "nouveau_connector.h"
0029 #include "nouveau_encoder.h"
0030 #include "nouveau_crtc.h"
0031 
0032 #include <nvif/class.h>
0033 #include <nvif/cl5070.h>
0034 
0035 MODULE_PARM_DESC(mst, "Enable DisplayPort multi-stream (default: enabled)");
0036 static int nouveau_mst = 1;
0037 module_param_named(mst, nouveau_mst, int, 0400);
0038 
0039 static bool
0040 nouveau_dp_has_sink_count(struct drm_connector *connector,
0041               struct nouveau_encoder *outp)
0042 {
0043     return drm_dp_read_sink_count_cap(connector, outp->dp.dpcd, &outp->dp.desc);
0044 }
0045 
0046 static enum drm_connector_status
0047 nouveau_dp_probe_dpcd(struct nouveau_connector *nv_connector,
0048               struct nouveau_encoder *outp)
0049 {
0050     struct drm_connector *connector = &nv_connector->base;
0051     struct drm_dp_aux *aux = &nv_connector->aux;
0052     struct nv50_mstm *mstm = NULL;
0053     enum drm_connector_status status = connector_status_disconnected;
0054     int ret;
0055     u8 *dpcd = outp->dp.dpcd;
0056 
0057     ret = drm_dp_read_dpcd_caps(aux, dpcd);
0058     if (ret < 0)
0059         goto out;
0060 
0061     ret = drm_dp_read_desc(aux, &outp->dp.desc, drm_dp_is_branch(dpcd));
0062     if (ret < 0)
0063         goto out;
0064 
0065     if (nouveau_mst) {
0066         mstm = outp->dp.mstm;
0067         if (mstm)
0068             mstm->can_mst = drm_dp_read_mst_cap(aux, dpcd);
0069     }
0070 
0071     if (nouveau_dp_has_sink_count(connector, outp)) {
0072         ret = drm_dp_read_sink_count(aux);
0073         if (ret < 0)
0074             goto out;
0075 
0076         outp->dp.sink_count = ret;
0077 
0078         /*
0079          * Dongle connected, but no display. Don't bother reading
0080          * downstream port info
0081          */
0082         if (!outp->dp.sink_count)
0083             return connector_status_disconnected;
0084     }
0085 
0086     ret = drm_dp_read_downstream_info(aux, dpcd,
0087                       outp->dp.downstream_ports);
0088     if (ret < 0)
0089         goto out;
0090 
0091     status = connector_status_connected;
0092 out:
0093     if (status != connector_status_connected) {
0094         /* Clear any cached info */
0095         outp->dp.sink_count = 0;
0096     }
0097     return status;
0098 }
0099 
0100 int
0101 nouveau_dp_detect(struct nouveau_connector *nv_connector,
0102           struct nouveau_encoder *nv_encoder)
0103 {
0104     struct drm_device *dev = nv_encoder->base.base.dev;
0105     struct nouveau_drm *drm = nouveau_drm(dev);
0106     struct drm_connector *connector = &nv_connector->base;
0107     struct nv50_mstm *mstm = nv_encoder->dp.mstm;
0108     enum drm_connector_status status;
0109     u8 *dpcd = nv_encoder->dp.dpcd;
0110     int ret = NOUVEAU_DP_NONE, hpd;
0111 
0112     /* If we've already read the DPCD on an eDP device, we don't need to
0113      * reread it as it won't change
0114      */
0115     if (connector->connector_type == DRM_MODE_CONNECTOR_eDP &&
0116         dpcd[DP_DPCD_REV] != 0)
0117         return NOUVEAU_DP_SST;
0118 
0119     mutex_lock(&nv_encoder->dp.hpd_irq_lock);
0120     if (mstm) {
0121         /* If we're not ready to handle MST state changes yet, just
0122          * report the last status of the connector. We'll reprobe it
0123          * once we've resumed.
0124          */
0125         if (mstm->suspended) {
0126             if (mstm->is_mst)
0127                 ret = NOUVEAU_DP_MST;
0128             else if (connector->status ==
0129                  connector_status_connected)
0130                 ret = NOUVEAU_DP_SST;
0131 
0132             goto out;
0133         }
0134     }
0135 
0136     /* Check status of HPD pin before attempting an AUX transaction that
0137      * would result in a number of (futile) retries on a connector which
0138      * has no display plugged.
0139      *
0140      * TODO: look into checking this before probing I2C to detect DVI/HDMI
0141      */
0142     hpd = nvif_conn_hpd_status(&nv_connector->conn);
0143     if (hpd == NVIF_CONN_HPD_STATUS_NOT_PRESENT)
0144         goto out;
0145 
0146     status = nouveau_dp_probe_dpcd(nv_connector, nv_encoder);
0147     if (status == connector_status_disconnected)
0148         goto out;
0149 
0150     /* If we're in MST mode, we're done here */
0151     if (mstm && mstm->can_mst && mstm->is_mst) {
0152         ret = NOUVEAU_DP_MST;
0153         goto out;
0154     }
0155 
0156     nv_encoder->dp.link_bw = 27000 * dpcd[DP_MAX_LINK_RATE];
0157     nv_encoder->dp.link_nr =
0158         dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK;
0159 
0160     if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) {
0161         struct drm_dp_aux *aux = &nv_connector->aux;
0162         int ret, i;
0163         u8 sink_rates[16];
0164 
0165         ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates));
0166         if (ret == sizeof(sink_rates)) {
0167             for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) {
0168                 int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10;
0169                 if (val && (i == 0 || val > nv_encoder->dp.link_bw))
0170                     nv_encoder->dp.link_bw = val;
0171             }
0172         }
0173     }
0174 
0175     NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n",
0176          nv_encoder->dp.link_nr, nv_encoder->dp.link_bw,
0177          dpcd[DP_DPCD_REV]);
0178     NV_DEBUG(drm, "encoder: %dx%d\n",
0179          nv_encoder->dcb->dpconf.link_nr,
0180          nv_encoder->dcb->dpconf.link_bw);
0181 
0182     if (nv_encoder->dcb->dpconf.link_nr < nv_encoder->dp.link_nr)
0183         nv_encoder->dp.link_nr = nv_encoder->dcb->dpconf.link_nr;
0184     if (nv_encoder->dcb->dpconf.link_bw < nv_encoder->dp.link_bw)
0185         nv_encoder->dp.link_bw = nv_encoder->dcb->dpconf.link_bw;
0186 
0187     NV_DEBUG(drm, "maximum: %dx%d\n",
0188          nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
0189 
0190     if (mstm && mstm->can_mst) {
0191         ret = nv50_mstm_detect(nv_encoder);
0192         if (ret == 1) {
0193             ret = NOUVEAU_DP_MST;
0194             goto out;
0195         } else if (ret != 0) {
0196             goto out;
0197         }
0198     }
0199     ret = NOUVEAU_DP_SST;
0200 
0201 out:
0202     if (mstm && !mstm->suspended && ret != NOUVEAU_DP_MST)
0203         nv50_mstm_remove(mstm);
0204 
0205     mutex_unlock(&nv_encoder->dp.hpd_irq_lock);
0206     return ret;
0207 }
0208 
0209 void nouveau_dp_irq(struct nouveau_drm *drm,
0210             struct nouveau_connector *nv_connector)
0211 {
0212     struct drm_connector *connector = &nv_connector->base;
0213     struct nouveau_encoder *outp = find_encoder(connector, DCB_OUTPUT_DP);
0214     struct nv50_mstm *mstm;
0215     int ret;
0216     bool send_hpd = false;
0217 
0218     if (!outp)
0219         return;
0220 
0221     mstm = outp->dp.mstm;
0222     NV_DEBUG(drm, "service %s\n", connector->name);
0223 
0224     mutex_lock(&outp->dp.hpd_irq_lock);
0225 
0226     if (mstm && mstm->is_mst) {
0227         if (!nv50_mstm_service(drm, nv_connector, mstm))
0228             send_hpd = true;
0229     } else {
0230         drm_dp_cec_irq(&nv_connector->aux);
0231 
0232         if (nouveau_dp_has_sink_count(connector, outp)) {
0233             ret = drm_dp_read_sink_count(&nv_connector->aux);
0234             if (ret != outp->dp.sink_count)
0235                 send_hpd = true;
0236             if (ret >= 0)
0237                 outp->dp.sink_count = ret;
0238         }
0239     }
0240 
0241     mutex_unlock(&outp->dp.hpd_irq_lock);
0242 
0243     if (send_hpd)
0244         nouveau_connector_hpd(connector);
0245 }
0246 
0247 /* TODO:
0248  * - Use the minimum possible BPC here, once we add support for the max bpc
0249  *   property.
0250  * - Validate against the DP caps advertised by the GPU (we don't check these
0251  *   yet)
0252  */
0253 enum drm_mode_status
0254 nv50_dp_mode_valid(struct drm_connector *connector,
0255            struct nouveau_encoder *outp,
0256            const struct drm_display_mode *mode,
0257            unsigned *out_clock)
0258 {
0259     const unsigned int min_clock = 25000;
0260     unsigned int max_rate, mode_rate, ds_max_dotclock, clock = mode->clock;
0261     const u8 bpp = connector->display_info.bpc * 3;
0262 
0263     if (mode->flags & DRM_MODE_FLAG_INTERLACE && !outp->caps.dp_interlace)
0264         return MODE_NO_INTERLACE;
0265 
0266     if ((mode->flags & DRM_MODE_FLAG_3D_MASK) == DRM_MODE_FLAG_3D_FRAME_PACKING)
0267         clock *= 2;
0268 
0269     max_rate = outp->dp.link_nr * outp->dp.link_bw;
0270     mode_rate = DIV_ROUND_UP(clock * bpp, 8);
0271     if (mode_rate > max_rate)
0272         return MODE_CLOCK_HIGH;
0273 
0274     ds_max_dotclock = drm_dp_downstream_max_dotclock(outp->dp.dpcd, outp->dp.downstream_ports);
0275     if (ds_max_dotclock && clock > ds_max_dotclock)
0276         return MODE_CLOCK_HIGH;
0277 
0278     if (clock < min_clock)
0279         return MODE_CLOCK_LOW;
0280 
0281     if (out_clock)
0282         *out_clock = clock;
0283 
0284     return MODE_OK;
0285 }