aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-10-20 02:31:53 -0400
committerDave Airlie <airlied@redhat.com>2014-12-08 18:56:49 -0500
commitb0ee9e7fa5b461a91f24d1d03b10c6bf162c86f9 (patch)
treedd12f04f8e18574f134a66bd8ceb93fbf5109606 /drivers/gpu
parent6f134d7bb4347ab4c66ef123efb838fedb54186f (diff)
drm/fb: add support for tiled monitor configurations. (v2)
This adds fbdev/con support for tiled monitors, so that we only set a mode on the correct half of the monitor, or span the two halves if needed. v2: remove unneeded ERROR, fix | vs || Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c121
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c24
2 files changed, 122 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
1313static bool drm_target_cloned(struct drm_fb_helper *fb_helper, 1315static 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
1389static 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
1386static bool drm_target_preferred(struct drm_fb_helper *fb_helper, 1421static 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;
1431retry:
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)
1583out: 1663out:
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)
324static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper, 324static 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;
346retry:
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 /*