diff options
-rw-r--r-- | drivers/gpu/drm/drm_fb_helper.c | 121 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/intel_fbdev.c | 24 | ||||
-rw-r--r-- | include/drm/drm_fb_helper.h | 6 |
3 files changed, 128 insertions, 23 deletions
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index a467460f2aa6..52ce26d6b4fb 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c | |||
@@ -1000,19 +1000,21 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, | |||
1000 | crtc_count = 0; | 1000 | crtc_count = 0; |
1001 | for (i = 0; i < fb_helper->crtc_count; i++) { | 1001 | for (i = 0; i < fb_helper->crtc_count; i++) { |
1002 | struct drm_display_mode *desired_mode; | 1002 | struct drm_display_mode *desired_mode; |
1003 | int x, y; | ||
1003 | desired_mode = fb_helper->crtc_info[i].desired_mode; | 1004 | desired_mode = fb_helper->crtc_info[i].desired_mode; |
1004 | 1005 | x = fb_helper->crtc_info[i].x; | |
1006 | y = fb_helper->crtc_info[i].y; | ||
1005 | if (desired_mode) { | 1007 | if (desired_mode) { |
1006 | if (gamma_size == 0) | 1008 | if (gamma_size == 0) |
1007 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; | 1009 | gamma_size = fb_helper->crtc_info[i].mode_set.crtc->gamma_size; |
1008 | if (desired_mode->hdisplay < sizes.fb_width) | 1010 | if (desired_mode->hdisplay + x < sizes.fb_width) |
1009 | sizes.fb_width = desired_mode->hdisplay; | 1011 | sizes.fb_width = desired_mode->hdisplay + x; |
1010 | if (desired_mode->vdisplay < sizes.fb_height) | 1012 | if (desired_mode->vdisplay + y < sizes.fb_height) |
1011 | sizes.fb_height = desired_mode->vdisplay; | 1013 | sizes.fb_height = desired_mode->vdisplay + y; |
1012 | if (desired_mode->hdisplay > sizes.surface_width) | 1014 | if (desired_mode->hdisplay + x > sizes.surface_width) |
1013 | sizes.surface_width = desired_mode->hdisplay; | 1015 | sizes.surface_width = desired_mode->hdisplay + x; |
1014 | if (desired_mode->vdisplay > sizes.surface_height) | 1016 | if (desired_mode->vdisplay + y > sizes.surface_height) |
1015 | sizes.surface_height = desired_mode->vdisplay; | 1017 | sizes.surface_height = desired_mode->vdisplay + y; |
1016 | crtc_count++; | 1018 | crtc_count++; |
1017 | } | 1019 | } |
1018 | } | 1020 | } |
@@ -1312,6 +1314,7 @@ static void drm_enable_connectors(struct drm_fb_helper *fb_helper, | |||
1312 | 1314 | ||
1313 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | 1315 | static bool drm_target_cloned(struct drm_fb_helper *fb_helper, |
1314 | struct drm_display_mode **modes, | 1316 | struct drm_display_mode **modes, |
1317 | struct drm_fb_offset *offsets, | ||
1315 | bool *enabled, int width, int height) | 1318 | bool *enabled, int width, int height) |
1316 | { | 1319 | { |
1317 | int count, i, j; | 1320 | int count, i, j; |
@@ -1383,27 +1386,88 @@ static bool drm_target_cloned(struct drm_fb_helper *fb_helper, | |||
1383 | return false; | 1386 | return false; |
1384 | } | 1387 | } |
1385 | 1388 | ||
1389 | static int drm_get_tile_offsets(struct drm_fb_helper *fb_helper, | ||
1390 | struct drm_display_mode **modes, | ||
1391 | struct drm_fb_offset *offsets, | ||
1392 | int idx, | ||
1393 | int h_idx, int v_idx) | ||
1394 | { | ||
1395 | struct drm_fb_helper_connector *fb_helper_conn; | ||
1396 | int i; | ||
1397 | int hoffset = 0, voffset = 0; | ||
1398 | |||
1399 | for (i = 0; i < fb_helper->connector_count; i++) { | ||
1400 | fb_helper_conn = fb_helper->connector_info[i]; | ||
1401 | if (!fb_helper_conn->connector->has_tile) | ||
1402 | continue; | ||
1403 | |||
1404 | if (!modes[i] && (h_idx || v_idx)) { | ||
1405 | DRM_DEBUG_KMS("no modes for connector tiled %d %d\n", i, | ||
1406 | fb_helper_conn->connector->base.id); | ||
1407 | continue; | ||
1408 | } | ||
1409 | if (fb_helper_conn->connector->tile_h_loc < h_idx) | ||
1410 | hoffset += modes[i]->hdisplay; | ||
1411 | |||
1412 | if (fb_helper_conn->connector->tile_v_loc < v_idx) | ||
1413 | voffset += modes[i]->vdisplay; | ||
1414 | } | ||
1415 | offsets[idx].x = hoffset; | ||
1416 | offsets[idx].y = voffset; | ||
1417 | DRM_DEBUG_KMS("returned %d %d for %d %d\n", hoffset, voffset, h_idx, v_idx); | ||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1386 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | 1421 | static bool drm_target_preferred(struct drm_fb_helper *fb_helper, |
1387 | struct drm_display_mode **modes, | 1422 | struct drm_display_mode **modes, |
1423 | struct drm_fb_offset *offsets, | ||
1388 | bool *enabled, int width, int height) | 1424 | bool *enabled, int width, int height) |
1389 | { | 1425 | { |
1390 | struct drm_fb_helper_connector *fb_helper_conn; | 1426 | struct drm_fb_helper_connector *fb_helper_conn; |
1391 | int i; | 1427 | int i; |
1392 | 1428 | uint64_t conn_configured = 0, mask; | |
1429 | int tile_pass = 0; | ||
1430 | mask = (1 << fb_helper->connector_count) - 1; | ||
1431 | retry: | ||
1393 | for (i = 0; i < fb_helper->connector_count; i++) { | 1432 | for (i = 0; i < fb_helper->connector_count; i++) { |
1394 | fb_helper_conn = fb_helper->connector_info[i]; | 1433 | fb_helper_conn = fb_helper->connector_info[i]; |
1395 | 1434 | ||
1396 | if (enabled[i] == false) | 1435 | if (conn_configured & (1 << i)) |
1436 | continue; | ||
1437 | |||
1438 | if (enabled[i] == false) { | ||
1439 | conn_configured |= (1 << i); | ||
1440 | continue; | ||
1441 | } | ||
1442 | |||
1443 | /* first pass over all the untiled connectors */ | ||
1444 | if (tile_pass == 0 && fb_helper_conn->connector->has_tile) | ||
1397 | continue; | 1445 | continue; |
1398 | 1446 | ||
1447 | if (tile_pass == 1) { | ||
1448 | if (fb_helper_conn->connector->tile_h_loc != 0 || | ||
1449 | fb_helper_conn->connector->tile_v_loc != 0) | ||
1450 | continue; | ||
1451 | |||
1452 | } else { | ||
1453 | if (fb_helper_conn->connector->tile_h_loc != tile_pass -1 && | ||
1454 | fb_helper_conn->connector->tile_v_loc != tile_pass - 1) | ||
1455 | /* if this tile_pass doesn't cover any of the tiles - keep going */ | ||
1456 | continue; | ||
1457 | |||
1458 | /* find the tile offsets for this pass - need | ||
1459 | to find all tiles left and above */ | ||
1460 | drm_get_tile_offsets(fb_helper, modes, offsets, | ||
1461 | i, fb_helper_conn->connector->tile_h_loc, fb_helper_conn->connector->tile_v_loc); | ||
1462 | } | ||
1399 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", | 1463 | DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n", |
1400 | fb_helper_conn->connector->base.id); | 1464 | fb_helper_conn->connector->base.id); |
1401 | 1465 | ||
1402 | /* got for command line mode first */ | 1466 | /* got for command line mode first */ |
1403 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); | 1467 | modes[i] = drm_pick_cmdline_mode(fb_helper_conn, width, height); |
1404 | if (!modes[i]) { | 1468 | if (!modes[i]) { |
1405 | DRM_DEBUG_KMS("looking for preferred mode on connector %d\n", | 1469 | DRM_DEBUG_KMS("looking for preferred mode on connector %d %d\n", |
1406 | fb_helper_conn->connector->base.id); | 1470 | fb_helper_conn->connector->base.id, fb_helper_conn->connector->tile_group ? fb_helper_conn->connector->tile_group->id : 0); |
1407 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); | 1471 | modes[i] = drm_has_preferred_mode(fb_helper_conn, width, height); |
1408 | } | 1472 | } |
1409 | /* No preferred modes, pick one off the list */ | 1473 | /* No preferred modes, pick one off the list */ |
@@ -1413,6 +1477,12 @@ static bool drm_target_preferred(struct drm_fb_helper *fb_helper, | |||
1413 | } | 1477 | } |
1414 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : | 1478 | DRM_DEBUG_KMS("found mode %s\n", modes[i] ? modes[i]->name : |
1415 | "none"); | 1479 | "none"); |
1480 | conn_configured |= (1 << i); | ||
1481 | } | ||
1482 | |||
1483 | if ((conn_configured & mask) != mask) { | ||
1484 | tile_pass++; | ||
1485 | goto retry; | ||
1416 | } | 1486 | } |
1417 | return true; | 1487 | return true; |
1418 | } | 1488 | } |
@@ -1502,6 +1572,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1502 | struct drm_device *dev = fb_helper->dev; | 1572 | struct drm_device *dev = fb_helper->dev; |
1503 | struct drm_fb_helper_crtc **crtcs; | 1573 | struct drm_fb_helper_crtc **crtcs; |
1504 | struct drm_display_mode **modes; | 1574 | struct drm_display_mode **modes; |
1575 | struct drm_fb_offset *offsets; | ||
1505 | struct drm_mode_set *modeset; | 1576 | struct drm_mode_set *modeset; |
1506 | bool *enabled; | 1577 | bool *enabled; |
1507 | int width, height; | 1578 | int width, height; |
@@ -1516,9 +1587,11 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1516 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); | 1587 | sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); |
1517 | modes = kcalloc(dev->mode_config.num_connector, | 1588 | modes = kcalloc(dev->mode_config.num_connector, |
1518 | sizeof(struct drm_display_mode *), GFP_KERNEL); | 1589 | sizeof(struct drm_display_mode *), GFP_KERNEL); |
1590 | offsets = kcalloc(dev->mode_config.num_connector, | ||
1591 | sizeof(struct drm_fb_offset), GFP_KERNEL); | ||
1519 | enabled = kcalloc(dev->mode_config.num_connector, | 1592 | enabled = kcalloc(dev->mode_config.num_connector, |
1520 | sizeof(bool), GFP_KERNEL); | 1593 | sizeof(bool), GFP_KERNEL); |
1521 | if (!crtcs || !modes || !enabled) { | 1594 | if (!crtcs || !modes || !enabled || !offsets) { |
1522 | DRM_ERROR("Memory allocation failed\n"); | 1595 | DRM_ERROR("Memory allocation failed\n"); |
1523 | goto out; | 1596 | goto out; |
1524 | } | 1597 | } |
@@ -1528,14 +1601,16 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1528 | 1601 | ||
1529 | if (!(fb_helper->funcs->initial_config && | 1602 | if (!(fb_helper->funcs->initial_config && |
1530 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, | 1603 | fb_helper->funcs->initial_config(fb_helper, crtcs, modes, |
1604 | offsets, | ||
1531 | enabled, width, height))) { | 1605 | enabled, width, height))) { |
1532 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); | 1606 | memset(modes, 0, dev->mode_config.num_connector*sizeof(modes[0])); |
1533 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); | 1607 | memset(crtcs, 0, dev->mode_config.num_connector*sizeof(crtcs[0])); |
1608 | memset(offsets, 0, dev->mode_config.num_connector*sizeof(offsets[0])); | ||
1534 | 1609 | ||
1535 | if (!drm_target_cloned(fb_helper, | 1610 | if (!drm_target_cloned(fb_helper, modes, offsets, |
1536 | modes, enabled, width, height) && | 1611 | enabled, width, height) && |
1537 | !drm_target_preferred(fb_helper, | 1612 | !drm_target_preferred(fb_helper, modes, offsets, |
1538 | modes, enabled, width, height)) | 1613 | enabled, width, height)) |
1539 | DRM_ERROR("Unable to find initial modes\n"); | 1614 | DRM_ERROR("Unable to find initial modes\n"); |
1540 | 1615 | ||
1541 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", | 1616 | DRM_DEBUG_KMS("picking CRTCs for %dx%d config\n", |
@@ -1555,18 +1630,23 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1555 | for (i = 0; i < fb_helper->connector_count; i++) { | 1630 | for (i = 0; i < fb_helper->connector_count; i++) { |
1556 | struct drm_display_mode *mode = modes[i]; | 1631 | struct drm_display_mode *mode = modes[i]; |
1557 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; | 1632 | struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; |
1633 | struct drm_fb_offset *offset = &offsets[i]; | ||
1558 | modeset = &fb_crtc->mode_set; | 1634 | modeset = &fb_crtc->mode_set; |
1559 | 1635 | ||
1560 | if (mode && fb_crtc) { | 1636 | if (mode && fb_crtc) { |
1561 | DRM_DEBUG_KMS("desired mode %s set on crtc %d\n", | 1637 | DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", |
1562 | mode->name, fb_crtc->mode_set.crtc->base.id); | 1638 | mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); |
1563 | fb_crtc->desired_mode = mode; | 1639 | fb_crtc->desired_mode = mode; |
1640 | fb_crtc->x = offset->x; | ||
1641 | fb_crtc->y = offset->y; | ||
1564 | if (modeset->mode) | 1642 | if (modeset->mode) |
1565 | drm_mode_destroy(dev, modeset->mode); | 1643 | drm_mode_destroy(dev, modeset->mode); |
1566 | modeset->mode = drm_mode_duplicate(dev, | 1644 | modeset->mode = drm_mode_duplicate(dev, |
1567 | fb_crtc->desired_mode); | 1645 | fb_crtc->desired_mode); |
1568 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; | 1646 | modeset->connectors[modeset->num_connectors++] = fb_helper->connector_info[i]->connector; |
1569 | modeset->fb = fb_helper->fb; | 1647 | modeset->fb = fb_helper->fb; |
1648 | modeset->x = offset->x; | ||
1649 | modeset->y = offset->y; | ||
1570 | } | 1650 | } |
1571 | } | 1651 | } |
1572 | 1652 | ||
@@ -1583,6 +1663,7 @@ static void drm_setup_crtcs(struct drm_fb_helper *fb_helper) | |||
1583 | out: | 1663 | out: |
1584 | kfree(crtcs); | 1664 | kfree(crtcs); |
1585 | kfree(modes); | 1665 | kfree(modes); |
1666 | kfree(offsets); | ||
1586 | kfree(enabled); | 1667 | kfree(enabled); |
1587 | } | 1668 | } |
1588 | 1669 | ||
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index f2183b554cbc..850cf7d6578c 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c | |||
@@ -324,6 +324,7 @@ intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) | |||
324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | 324 | static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, |
325 | struct drm_fb_helper_crtc **crtcs, | 325 | struct drm_fb_helper_crtc **crtcs, |
326 | struct drm_display_mode **modes, | 326 | struct drm_display_mode **modes, |
327 | struct drm_fb_offset *offsets, | ||
327 | bool *enabled, int width, int height) | 328 | bool *enabled, int width, int height) |
328 | { | 329 | { |
329 | struct drm_device *dev = fb_helper->dev; | 330 | struct drm_device *dev = fb_helper->dev; |
@@ -332,6 +333,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
332 | bool fallback = true; | 333 | bool fallback = true; |
333 | int num_connectors_enabled = 0; | 334 | int num_connectors_enabled = 0; |
334 | int num_connectors_detected = 0; | 335 | int num_connectors_detected = 0; |
336 | uint64_t conn_configured = 0, mask; | ||
337 | int pass = 0; | ||
335 | 338 | ||
336 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), | 339 | save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool), |
337 | GFP_KERNEL); | 340 | GFP_KERNEL); |
@@ -339,7 +342,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
339 | return false; | 342 | return false; |
340 | 343 | ||
341 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); | 344 | memcpy(save_enabled, enabled, dev->mode_config.num_connector); |
342 | 345 | mask = (1 << fb_helper->connector_count) - 1; | |
346 | retry: | ||
343 | for (i = 0; i < fb_helper->connector_count; i++) { | 347 | for (i = 0; i < fb_helper->connector_count; i++) { |
344 | struct drm_fb_helper_connector *fb_conn; | 348 | struct drm_fb_helper_connector *fb_conn; |
345 | struct drm_connector *connector; | 349 | struct drm_connector *connector; |
@@ -349,12 +353,19 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
349 | fb_conn = fb_helper->connector_info[i]; | 353 | fb_conn = fb_helper->connector_info[i]; |
350 | connector = fb_conn->connector; | 354 | connector = fb_conn->connector; |
351 | 355 | ||
356 | if (conn_configured & (1 << i)) | ||
357 | continue; | ||
358 | |||
359 | if (pass == 0 && !connector->has_tile) | ||
360 | continue; | ||
361 | |||
352 | if (connector->status == connector_status_connected) | 362 | if (connector->status == connector_status_connected) |
353 | num_connectors_detected++; | 363 | num_connectors_detected++; |
354 | 364 | ||
355 | if (!enabled[i]) { | 365 | if (!enabled[i]) { |
356 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", | 366 | DRM_DEBUG_KMS("connector %s not enabled, skipping\n", |
357 | connector->name); | 367 | connector->name); |
368 | conn_configured |= (1 << i); | ||
358 | continue; | 369 | continue; |
359 | } | 370 | } |
360 | 371 | ||
@@ -373,6 +384,7 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
373 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", | 384 | DRM_DEBUG_KMS("connector %s has no encoder or crtc, skipping\n", |
374 | connector->name); | 385 | connector->name); |
375 | enabled[i] = false; | 386 | enabled[i] = false; |
387 | conn_configured |= (1 << i); | ||
376 | continue; | 388 | continue; |
377 | } | 389 | } |
378 | 390 | ||
@@ -400,8 +412,8 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
400 | 412 | ||
401 | /* try for preferred next */ | 413 | /* try for preferred next */ |
402 | if (!modes[i]) { | 414 | if (!modes[i]) { |
403 | DRM_DEBUG_KMS("looking for preferred mode on connector %s\n", | 415 | DRM_DEBUG_KMS("looking for preferred mode on connector %s %d\n", |
404 | connector->name); | 416 | connector->name, connector->has_tile); |
405 | modes[i] = drm_has_preferred_mode(fb_conn, width, | 417 | modes[i] = drm_has_preferred_mode(fb_conn, width, |
406 | height); | 418 | height); |
407 | } | 419 | } |
@@ -444,6 +456,12 @@ static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, | |||
444 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); | 456 | modes[i]->flags & DRM_MODE_FLAG_INTERLACE ? "i" :""); |
445 | 457 | ||
446 | fallback = false; | 458 | fallback = false; |
459 | conn_configured |= (1 << i); | ||
460 | } | ||
461 | |||
462 | if ((conn_configured & mask) != mask) { | ||
463 | pass++; | ||
464 | goto retry; | ||
447 | } | 465 | } |
448 | 466 | ||
449 | /* | 467 | /* |
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h index f4ad254e3488..b597068103aa 100644 --- a/include/drm/drm_fb_helper.h +++ b/include/drm/drm_fb_helper.h | |||
@@ -34,9 +34,14 @@ struct drm_fb_helper; | |||
34 | 34 | ||
35 | #include <linux/kgdb.h> | 35 | #include <linux/kgdb.h> |
36 | 36 | ||
37 | struct drm_fb_offset { | ||
38 | int x, y; | ||
39 | }; | ||
40 | |||
37 | struct drm_fb_helper_crtc { | 41 | struct drm_fb_helper_crtc { |
38 | struct drm_mode_set mode_set; | 42 | struct drm_mode_set mode_set; |
39 | struct drm_display_mode *desired_mode; | 43 | struct drm_display_mode *desired_mode; |
44 | int x, y; | ||
40 | }; | 45 | }; |
41 | 46 | ||
42 | struct drm_fb_helper_surface_size { | 47 | struct drm_fb_helper_surface_size { |
@@ -72,6 +77,7 @@ struct drm_fb_helper_funcs { | |||
72 | bool (*initial_config)(struct drm_fb_helper *fb_helper, | 77 | bool (*initial_config)(struct drm_fb_helper *fb_helper, |
73 | struct drm_fb_helper_crtc **crtcs, | 78 | struct drm_fb_helper_crtc **crtcs, |
74 | struct drm_display_mode **modes, | 79 | struct drm_display_mode **modes, |
80 | struct drm_fb_offset *offsets, | ||
75 | bool *enabled, int width, int height); | 81 | bool *enabled, int width, int height); |
76 | }; | 82 | }; |
77 | 83 | ||