diff options
author | Paulo Zanoni <paulo.r.zanoni@intel.com> | 2012-10-26 17:05:52 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-11-11 17:51:08 -0500 |
commit | 00c09d70df6b30c980f20facc1db3def3f5a637e (patch) | |
tree | 740478e3bb71cdc18ae91ba03e9f3ef9513c3d46 /drivers/gpu/drm/i915/intel_ddi.c | |
parent | bcbc889bc44a781577479939490f6b7452d5b808 (diff) |
drm/i915: create the DDI encoder
Now intel_ddi_init is just like intel_hdmi_init and intel_dp_init: it
inits the encoder and then calls the proper init_connector functions.
Notice that for non-eDP ports we call both HDMI and DP connector init,
so we have 2 connectors attached to each DDI encoder.
After this change, intel_hdmi_init and intel_dp_init are only called
by Ivy Bridge and earlier, while hardware containing DDI outputs
should call intel_ddi_init.
Also added/removed quite a few "static" keywords due to the fact that
some function pointers were moved from intel_dp.c and intel_hdmi.c to
intel_ddi.c.
DP finally works on Haswell now! \o/
Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
Reviewed-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ddi.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_ddi.c | 143 |
1 files changed, 106 insertions, 37 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 58a529d9f1e3..67bd6ba64a35 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c | |||
@@ -64,7 +64,7 @@ static enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) | |||
64 | int type = intel_encoder->type; | 64 | int type = intel_encoder->type; |
65 | 65 | ||
66 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || | 66 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || |
67 | type == INTEL_OUTPUT_HDMI) { | 67 | type == INTEL_OUTPUT_HDMI || type == INTEL_OUTPUT_UNKNOWN) { |
68 | struct intel_digital_port *intel_dig_port = | 68 | struct intel_digital_port *intel_dig_port = |
69 | enc_to_dig_port(encoder); | 69 | enc_to_dig_port(encoder); |
70 | return intel_dig_port->port; | 70 | return intel_dig_port->port; |
@@ -227,35 +227,6 @@ void hsw_fdi_link_train(struct drm_crtc *crtc) | |||
227 | DRM_DEBUG_KMS("FDI train done.\n"); | 227 | DRM_DEBUG_KMS("FDI train done.\n"); |
228 | } | 228 | } |
229 | 229 | ||
230 | /* For DDI connections, it is possible to support different outputs over the | ||
231 | * same DDI port, such as HDMI or DP or even VGA via FDI. So we don't know by | ||
232 | * the time the output is detected what exactly is on the other end of it. This | ||
233 | * function aims at providing support for this detection and proper output | ||
234 | * configuration. | ||
235 | */ | ||
236 | void intel_ddi_init(struct drm_device *dev, enum port port) | ||
237 | { | ||
238 | /* For now, we don't do any proper output detection and assume that we | ||
239 | * handle HDMI only */ | ||
240 | |||
241 | switch(port){ | ||
242 | case PORT_A: | ||
243 | DRM_DEBUG_DRIVER("Found digital output on DDI port A\n"); | ||
244 | intel_dp_init(dev, DDI_BUF_CTL_A, PORT_A); | ||
245 | break; | ||
246 | /* Assume that the ports B, C and D are working in HDMI mode for now */ | ||
247 | case PORT_B: | ||
248 | case PORT_C: | ||
249 | case PORT_D: | ||
250 | intel_hdmi_init(dev, DDI_BUF_CTL(port), port); | ||
251 | break; | ||
252 | default: | ||
253 | DRM_DEBUG_DRIVER("No handlers defined for port %d, skipping DDI initialization\n", | ||
254 | port); | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | /* WRPLL clock dividers */ | 230 | /* WRPLL clock dividers */ |
260 | struct wrpll_tmds_clock { | 231 | struct wrpll_tmds_clock { |
261 | u32 clock; | 232 | u32 clock; |
@@ -642,9 +613,9 @@ static const struct wrpll_tmds_clock wrpll_tmds_clock_table[] = { | |||
642 | {298000, 2, 21, 19}, | 613 | {298000, 2, 21, 19}, |
643 | }; | 614 | }; |
644 | 615 | ||
645 | void intel_ddi_mode_set(struct drm_encoder *encoder, | 616 | static void intel_ddi_mode_set(struct drm_encoder *encoder, |
646 | struct drm_display_mode *mode, | 617 | struct drm_display_mode *mode, |
647 | struct drm_display_mode *adjusted_mode) | 618 | struct drm_display_mode *adjusted_mode) |
648 | { | 619 | { |
649 | struct drm_crtc *crtc = encoder->crtc; | 620 | struct drm_crtc *crtc = encoder->crtc; |
650 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | 621 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); |
@@ -1192,7 +1163,7 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) | |||
1192 | TRANS_CLK_SEL_DISABLED); | 1163 | TRANS_CLK_SEL_DISABLED); |
1193 | } | 1164 | } |
1194 | 1165 | ||
1195 | void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) | 1166 | static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) |
1196 | { | 1167 | { |
1197 | struct drm_encoder *encoder = &intel_encoder->base; | 1168 | struct drm_encoder *encoder = &intel_encoder->base; |
1198 | struct drm_crtc *crtc = encoder->crtc; | 1169 | struct drm_crtc *crtc = encoder->crtc; |
@@ -1234,7 +1205,7 @@ static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, | |||
1234 | DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); | 1205 | DRM_ERROR("Timeout waiting for DDI BUF %c idle bit\n", port_name(port)); |
1235 | } | 1206 | } |
1236 | 1207 | ||
1237 | void intel_ddi_post_disable(struct intel_encoder *intel_encoder) | 1208 | static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) |
1238 | { | 1209 | { |
1239 | struct drm_encoder *encoder = &intel_encoder->base; | 1210 | struct drm_encoder *encoder = &intel_encoder->base; |
1240 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; | 1211 | struct drm_i915_private *dev_priv = encoder->dev->dev_private; |
@@ -1267,7 +1238,7 @@ void intel_ddi_post_disable(struct intel_encoder *intel_encoder) | |||
1267 | I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); | 1238 | I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE); |
1268 | } | 1239 | } |
1269 | 1240 | ||
1270 | void intel_enable_ddi(struct intel_encoder *intel_encoder) | 1241 | static void intel_enable_ddi(struct intel_encoder *intel_encoder) |
1271 | { | 1242 | { |
1272 | struct drm_encoder *encoder = &intel_encoder->base; | 1243 | struct drm_encoder *encoder = &intel_encoder->base; |
1273 | struct drm_device *dev = encoder->dev; | 1244 | struct drm_device *dev = encoder->dev; |
@@ -1288,7 +1259,7 @@ void intel_enable_ddi(struct intel_encoder *intel_encoder) | |||
1288 | } | 1259 | } |
1289 | } | 1260 | } |
1290 | 1261 | ||
1291 | void intel_disable_ddi(struct intel_encoder *intel_encoder) | 1262 | static void intel_disable_ddi(struct intel_encoder *intel_encoder) |
1292 | { | 1263 | { |
1293 | struct drm_encoder *encoder = &intel_encoder->base; | 1264 | struct drm_encoder *encoder = &intel_encoder->base; |
1294 | int type = intel_encoder->type; | 1265 | int type = intel_encoder->type; |
@@ -1371,3 +1342,101 @@ void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) | |||
1371 | 1342 | ||
1372 | udelay(600); | 1343 | udelay(600); |
1373 | } | 1344 | } |
1345 | |||
1346 | static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) | ||
1347 | { | ||
1348 | struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base); | ||
1349 | int type = intel_encoder->type; | ||
1350 | |||
1351 | if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) | ||
1352 | intel_dp_check_link_status(intel_dp); | ||
1353 | } | ||
1354 | |||
1355 | static void intel_ddi_destroy(struct drm_encoder *encoder) | ||
1356 | { | ||
1357 | /* HDMI has nothing special to destroy, so we can go with this. */ | ||
1358 | intel_dp_encoder_destroy(encoder); | ||
1359 | } | ||
1360 | |||
1361 | static bool intel_ddi_mode_fixup(struct drm_encoder *encoder, | ||
1362 | const struct drm_display_mode *mode, | ||
1363 | struct drm_display_mode *adjusted_mode) | ||
1364 | { | ||
1365 | struct intel_encoder *intel_encoder = to_intel_encoder(encoder); | ||
1366 | int type = intel_encoder->type; | ||
1367 | |||
1368 | WARN(type == INTEL_OUTPUT_UNKNOWN, "mode_fixup() on unknown output!\n"); | ||
1369 | |||
1370 | if (type == INTEL_OUTPUT_HDMI) | ||
1371 | return intel_hdmi_mode_fixup(encoder, mode, adjusted_mode); | ||
1372 | else | ||
1373 | return intel_dp_mode_fixup(encoder, mode, adjusted_mode); | ||
1374 | } | ||
1375 | |||
1376 | static const struct drm_encoder_funcs intel_ddi_funcs = { | ||
1377 | .destroy = intel_ddi_destroy, | ||
1378 | }; | ||
1379 | |||
1380 | static const struct drm_encoder_helper_funcs intel_ddi_helper_funcs = { | ||
1381 | .mode_fixup = intel_ddi_mode_fixup, | ||
1382 | .mode_set = intel_ddi_mode_set, | ||
1383 | .disable = intel_encoder_noop, | ||
1384 | }; | ||
1385 | |||
1386 | void intel_ddi_init(struct drm_device *dev, enum port port) | ||
1387 | { | ||
1388 | struct intel_digital_port *intel_dig_port; | ||
1389 | struct intel_encoder *intel_encoder; | ||
1390 | struct drm_encoder *encoder; | ||
1391 | struct intel_connector *hdmi_connector = NULL; | ||
1392 | struct intel_connector *dp_connector = NULL; | ||
1393 | |||
1394 | intel_dig_port = kzalloc(sizeof(struct intel_digital_port), GFP_KERNEL); | ||
1395 | if (!intel_dig_port) | ||
1396 | return; | ||
1397 | |||
1398 | dp_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); | ||
1399 | if (!dp_connector) { | ||
1400 | kfree(intel_dig_port); | ||
1401 | return; | ||
1402 | } | ||
1403 | |||
1404 | if (port != PORT_A) { | ||
1405 | hdmi_connector = kzalloc(sizeof(struct intel_connector), | ||
1406 | GFP_KERNEL); | ||
1407 | if (!hdmi_connector) { | ||
1408 | kfree(dp_connector); | ||
1409 | kfree(intel_dig_port); | ||
1410 | return; | ||
1411 | } | ||
1412 | } | ||
1413 | |||
1414 | intel_encoder = &intel_dig_port->base; | ||
1415 | encoder = &intel_encoder->base; | ||
1416 | |||
1417 | drm_encoder_init(dev, encoder, &intel_ddi_funcs, | ||
1418 | DRM_MODE_ENCODER_TMDS); | ||
1419 | drm_encoder_helper_add(encoder, &intel_ddi_helper_funcs); | ||
1420 | |||
1421 | intel_encoder->enable = intel_enable_ddi; | ||
1422 | intel_encoder->pre_enable = intel_ddi_pre_enable; | ||
1423 | intel_encoder->disable = intel_disable_ddi; | ||
1424 | intel_encoder->post_disable = intel_ddi_post_disable; | ||
1425 | intel_encoder->get_hw_state = intel_ddi_get_hw_state; | ||
1426 | |||
1427 | intel_dig_port->port = port; | ||
1428 | if (hdmi_connector) | ||
1429 | intel_dig_port->hdmi.sdvox_reg = DDI_BUF_CTL(port); | ||
1430 | else | ||
1431 | intel_dig_port->hdmi.sdvox_reg = 0; | ||
1432 | intel_dig_port->dp.output_reg = DDI_BUF_CTL(port); | ||
1433 | |||
1434 | intel_encoder->type = INTEL_OUTPUT_UNKNOWN; | ||
1435 | intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); | ||
1436 | intel_encoder->cloneable = false; | ||
1437 | intel_encoder->hot_plug = intel_ddi_hot_plug; | ||
1438 | |||
1439 | if (hdmi_connector) | ||
1440 | intel_hdmi_init_connector(intel_dig_port, hdmi_connector); | ||
1441 | intel_dp_init_connector(intel_dig_port, dp_connector); | ||
1442 | } | ||