drm/nouveau/dp: probe dpcd to determine connectedness
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
efa366fdf5
commit
8777c5c117
|
@ -111,15 +111,15 @@ nouveau_connector_destroy(struct drm_connector *connector)
|
||||||
kfree(connector);
|
kfree(connector);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nouveau_i2c_port *
|
static struct nouveau_encoder *
|
||||||
nouveau_connector_ddc_detect(struct drm_connector *connector,
|
nouveau_connector_ddc_detect(struct drm_connector *connector)
|
||||||
struct nouveau_encoder **pnv_encoder)
|
|
||||||
{
|
{
|
||||||
struct drm_device *dev = connector->dev;
|
struct drm_device *dev = connector->dev;
|
||||||
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
struct nouveau_connector *nv_connector = nouveau_connector(connector);
|
||||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||||
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
|
struct nouveau_gpio *gpio = nouveau_gpio(drm->device);
|
||||||
struct nouveau_i2c_port *port = NULL;
|
struct nouveau_encoder *nv_encoder;
|
||||||
|
struct drm_mode_object *obj;
|
||||||
int i, panel = -ENODEV;
|
int i, panel = -ENODEV;
|
||||||
|
|
||||||
/* eDP panels need powering on by us (if the VBIOS doesn't default it
|
/* eDP panels need powering on by us (if the VBIOS doesn't default it
|
||||||
|
@ -134,13 +134,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
|
for (i = 0; nv_encoder = NULL, i < DRM_CONNECTOR_MAX_ENCODER; i++) {
|
||||||
struct nouveau_encoder *nv_encoder;
|
int id = connector->encoder_ids[i];
|
||||||
struct drm_mode_object *obj;
|
if (id == 0)
|
||||||
int id;
|
|
||||||
|
|
||||||
id = connector->encoder_ids[i];
|
|
||||||
if (!id)
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
|
obj = drm_mode_object_find(dev, id, DRM_MODE_OBJECT_ENCODER);
|
||||||
|
@ -148,22 +144,24 @@ nouveau_connector_ddc_detect(struct drm_connector *connector,
|
||||||
continue;
|
continue;
|
||||||
nv_encoder = nouveau_encoder(obj_to_encoder(obj));
|
nv_encoder = nouveau_encoder(obj_to_encoder(obj));
|
||||||
|
|
||||||
port = nv_encoder->i2c;
|
if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
|
||||||
if (port && nv_probe_i2c(port, 0x50)) {
|
int ret = nouveau_dp_detect(nv_encoder);
|
||||||
*pnv_encoder = nv_encoder;
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
|
} else
|
||||||
|
if (nv_encoder->i2c) {
|
||||||
|
if (nv_probe_i2c(nv_encoder->i2c, 0x50))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
port = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eDP panel not detected, restore panel power GPIO to previous
|
/* eDP panel not detected, restore panel power GPIO to previous
|
||||||
* state to avoid confusing the SOR for other output types.
|
* state to avoid confusing the SOR for other output types.
|
||||||
*/
|
*/
|
||||||
if (!port && panel == 0)
|
if (!nv_encoder && panel == 0)
|
||||||
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
|
gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel);
|
||||||
|
|
||||||
return port;
|
return nv_encoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nouveau_encoder *
|
static struct nouveau_encoder *
|
||||||
|
@ -262,8 +260,8 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||||
if (ret < 0 && ret != -EACCES)
|
if (ret < 0 && ret != -EACCES)
|
||||||
return conn_status;
|
return conn_status;
|
||||||
|
|
||||||
i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
|
nv_encoder = nouveau_connector_ddc_detect(connector);
|
||||||
if (i2c) {
|
if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) {
|
||||||
nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
|
nv_connector->edid = drm_get_edid(connector, &i2c->adapter);
|
||||||
drm_mode_connector_update_edid_property(connector,
|
drm_mode_connector_update_edid_property(connector,
|
||||||
nv_connector->edid);
|
nv_connector->edid);
|
||||||
|
@ -273,14 +271,6 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
|
||||||
goto detect_analog;
|
goto detect_analog;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nv_encoder->dcb->type == DCB_OUTPUT_DP &&
|
|
||||||
!nouveau_dp_detect(to_drm_encoder(nv_encoder))) {
|
|
||||||
NV_ERROR(drm, "Detected %s, but failed init\n",
|
|
||||||
connector->name);
|
|
||||||
conn_status = connector_status_disconnected;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Override encoder type for DVI-I based on whether EDID
|
/* Override encoder type for DVI-I based on whether EDID
|
||||||
* says the display is digital or analog, both use the
|
* says the display is digital or analog, both use the
|
||||||
* same i2c channel so the value returned from ddc_detect
|
* same i2c channel so the value returned from ddc_detect
|
||||||
|
|
|
@ -55,11 +55,10 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
int
|
||||||
nouveau_dp_detect(struct drm_encoder *encoder)
|
nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
|
||||||
{
|
{
|
||||||
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
|
struct drm_device *dev = nv_encoder->base.base.dev;
|
||||||
struct drm_device *dev = encoder->dev;
|
|
||||||
struct nouveau_drm *drm = nouveau_drm(dev);
|
struct nouveau_drm *drm = nouveau_drm(dev);
|
||||||
struct nouveau_i2c_port *auxch;
|
struct nouveau_i2c_port *auxch;
|
||||||
u8 *dpcd = nv_encoder->dp.dpcd;
|
u8 *dpcd = nv_encoder->dp.dpcd;
|
||||||
|
@ -67,11 +66,11 @@ nouveau_dp_detect(struct drm_encoder *encoder)
|
||||||
|
|
||||||
auxch = nv_encoder->i2c;
|
auxch = nv_encoder->i2c;
|
||||||
if (!auxch)
|
if (!auxch)
|
||||||
return false;
|
return -ENODEV;
|
||||||
|
|
||||||
ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8);
|
ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8);
|
||||||
if (ret)
|
if (ret)
|
||||||
return false;
|
return ret;
|
||||||
|
|
||||||
nv_encoder->dp.link_bw = 27000 * dpcd[1];
|
nv_encoder->dp.link_bw = 27000 * dpcd[1];
|
||||||
nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
|
nv_encoder->dp.link_nr = dpcd[2] & DP_MAX_LANE_COUNT_MASK;
|
||||||
|
@ -91,6 +90,5 @@ nouveau_dp_detect(struct drm_encoder *encoder)
|
||||||
nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
|
nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
|
||||||
|
|
||||||
nouveau_dp_probe_oui(dev, auxch, dpcd);
|
nouveau_dp_probe_oui(dev, auxch, dpcd);
|
||||||
|
return 0;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,9 +85,7 @@ get_slave_funcs(struct drm_encoder *enc)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nouveau_dp.c */
|
/* nouveau_dp.c */
|
||||||
bool nouveau_dp_detect(struct drm_encoder *);
|
int nouveau_dp_detect(struct nouveau_encoder *);
|
||||||
void nouveau_dp_dpms(struct drm_encoder *, int mode, u32 datarate,
|
|
||||||
struct nouveau_object *);
|
|
||||||
|
|
||||||
struct nouveau_connector *
|
struct nouveau_connector *
|
||||||
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
|
nouveau_encoder_connector_get(struct nouveau_encoder *encoder);
|
||||||
|
|
Loading…
Reference in New Issue