Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/fb-helper: Remove drm_fb_helper_crtc

struct drm_fb_helper_crtc is now just a wrapper around drm_mode_set so
use that directly instead and attach it as a modeset array onto
drm_client_dev. drm_fb_helper will use this array to store its modesets
which means it will always initialize a drm_client, but it will not
register the client (callbacks) unless it's the generic fbdev emulation.

Code will later be moved to drm_client, so add code there in a new file
drm_client_modeset.c with MIT license to match drm_fb_helper.c.

The modeset connector array size is hardcoded for the cloned case to avoid
having to pass in a value from the driver. A value of 8 is chosen to err
on the safe side. This means that the max connector argument for
drm_fb_helper_init() and drm_fb_helper_fbdev_setup() isn't used anymore,
a todo entry for this is added.

In pan_display_atomic() restore_fbdev_mode_force() is used instead of
restore_fbdev_mode_atomic() because that one will later become internal
to drm_client_modeset.

Locking order:
1. drm_fb_helper->lock
2. drm_master_internal_acquire
3. drm_client_dev->modeset_mutex

v6: Improve commit message (Sam Ravnborg)

v3:
- Use full drm_client_init/release for the modesets (Daniel Vetter)
- drm_client_for_each_modeset: use lockdep_assert_held (Daniel Vetter)
- Hook up to Documentation/gpu/drm-client.rst (Daniel Vetter)

v2:
- Add modesets array to drm_client (Daniel Vetter)
- Use a new file for the modeset code (Daniel Vetter)
- File has to be MIT licensed (Emmanuel Vadot)
- Add copyrights from drm_fb_helper.c

Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
Reviewed-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190531140117.37751-3-noralf@tronnes.org

+274 -187
+3
Documentation/gpu/drm-client.rst
··· 10 10 11 11 .. kernel-doc:: drivers/gpu/drm/drm_client.c 12 12 :export: 13 + 14 + .. kernel-doc:: drivers/gpu/drm/drm_client_modeset.c 15 + :export:
+3
Documentation/gpu/todo.rst
··· 289 289 these igt tests need to be fixed: kms_fbcon_fbt@psr and 290 290 kms_fbcon_fbt@psr-suspend. 291 291 292 + - The max connector argument for drm_fb_helper_init() and 293 + drm_fb_helper_fbdev_setup() isn't used anymore and can be removed. 294 + 292 295 Core refactorings 293 296 ================= 294 297
+1 -1
drivers/gpu/drm/Makefile
··· 17 17 drm_plane.o drm_color_mgmt.o drm_print.o \ 18 18 drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ 19 19 drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ 20 - drm_atomic_uapi.o drm_hdcp.o 20 + drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o 21 21 22 22 drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o 23 23 drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o
+8 -2
drivers/gpu/drm/drm_client.c
··· 27 27 * DOC: overview 28 28 * 29 29 * This library provides support for clients running in the kernel like fbdev and bootsplash. 30 - * Currently it's only partially implemented, just enough to support fbdev. 31 30 * 32 31 * GEM drivers which provide a GEM based dumb buffer with a virtual address are supported. 33 32 */ ··· 91 92 client->name = name; 92 93 client->funcs = funcs; 93 94 94 - ret = drm_client_open(client); 95 + ret = drm_client_modeset_create(client); 95 96 if (ret) 96 97 goto err_put_module; 98 + 99 + ret = drm_client_open(client); 100 + if (ret) 101 + goto err_free; 97 102 98 103 drm_dev_get(dev); 99 104 100 105 return 0; 101 106 107 + err_free: 108 + drm_client_modeset_free(client); 102 109 err_put_module: 103 110 if (funcs) 104 111 module_put(funcs->owner); ··· 153 148 154 149 DRM_DEV_DEBUG_KMS(dev->dev, "%s\n", client->name); 155 150 151 + drm_client_modeset_free(client); 156 152 drm_client_close(client); 157 153 drm_dev_put(dev); 158 154 if (client->funcs)
+104
drivers/gpu/drm/drm_client_modeset.c
··· 1 + // SPDX-License-Identifier: MIT 2 + /* 3 + * Copyright 2018 Noralf Trønnes 4 + * Copyright (c) 2006-2009 Red Hat Inc. 5 + * Copyright (c) 2006-2008 Intel Corporation 6 + * Jesse Barnes <jesse.barnes@intel.com> 7 + * Copyright (c) 2007 Dave Airlie <airlied@linux.ie> 8 + */ 9 + 10 + #include <linux/module.h> 11 + #include <linux/mutex.h> 12 + #include <linux/slab.h> 13 + 14 + #include <drm/drm_client.h> 15 + #include <drm/drm_crtc.h> 16 + #include <drm/drm_device.h> 17 + 18 + int drm_client_modeset_create(struct drm_client_dev *client) 19 + { 20 + struct drm_device *dev = client->dev; 21 + unsigned int num_crtc = dev->mode_config.num_crtc; 22 + unsigned int max_connector_count = 1; 23 + struct drm_mode_set *modeset; 24 + struct drm_crtc *crtc; 25 + unsigned int i = 0; 26 + 27 + /* Add terminating zero entry to enable index less iteration */ 28 + client->modesets = kcalloc(num_crtc + 1, sizeof(*client->modesets), GFP_KERNEL); 29 + if (!client->modesets) 30 + return -ENOMEM; 31 + 32 + mutex_init(&client->modeset_mutex); 33 + 34 + drm_for_each_crtc(crtc, dev) 35 + client->modesets[i++].crtc = crtc; 36 + 37 + /* Cloning is only supported in the single crtc case. */ 38 + if (num_crtc == 1) 39 + max_connector_count = DRM_CLIENT_MAX_CLONED_CONNECTORS; 40 + 41 + for (modeset = client->modesets; modeset->crtc; modeset++) { 42 + modeset->connectors = kcalloc(max_connector_count, 43 + sizeof(*modeset->connectors), GFP_KERNEL); 44 + if (!modeset->connectors) 45 + goto err_free; 46 + } 47 + 48 + return 0; 49 + 50 + err_free: 51 + drm_client_modeset_free(client); 52 + 53 + return -ENOMEM; 54 + } 55 + 56 + void drm_client_modeset_release(struct drm_client_dev *client) 57 + { 58 + struct drm_mode_set *modeset; 59 + unsigned int i; 60 + 61 + drm_client_for_each_modeset(modeset, client) { 62 + drm_mode_destroy(client->dev, modeset->mode); 63 + modeset->mode = NULL; 64 + modeset->fb = NULL; 65 + 66 + for (i = 0; i < modeset->num_connectors; i++) { 67 + drm_connector_put(modeset->connectors[i]); 68 + modeset->connectors[i] = NULL; 69 + } 70 + modeset->num_connectors = 0; 71 + } 72 + } 73 + /* TODO: Remove export when modeset code has been moved over */ 74 + EXPORT_SYMBOL(drm_client_modeset_release); 75 + 76 + void drm_client_modeset_free(struct drm_client_dev *client) 77 + { 78 + struct drm_mode_set *modeset; 79 + 80 + mutex_lock(&client->modeset_mutex); 81 + 82 + drm_client_modeset_release(client); 83 + 84 + drm_client_for_each_modeset(modeset, client) 85 + kfree(modeset->connectors); 86 + 87 + mutex_unlock(&client->modeset_mutex); 88 + 89 + mutex_destroy(&client->modeset_mutex); 90 + kfree(client->modesets); 91 + } 92 + 93 + struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc) 94 + { 95 + struct drm_mode_set *modeset; 96 + 97 + drm_client_for_each_modeset(modeset, client) 98 + if (modeset->crtc == crtc) 99 + return modeset; 100 + 101 + return NULL; 102 + } 103 + /* TODO: Remove export when modeset code has been moved over */ 104 + EXPORT_SYMBOL(drm_client_find_modeset);
+125 -176
drivers/gpu/drm/drm_fb_helper.c
··· 322 322 { 323 323 struct drm_fb_helper *helper = info->par; 324 324 const struct drm_crtc_helper_funcs *funcs; 325 - int i; 325 + struct drm_mode_set *mode_set; 326 326 327 327 list_for_each_entry(helper, &kernel_fb_helper_list, kernel_fb_list) { 328 - for (i = 0; i < helper->crtc_count; i++) { 329 - struct drm_mode_set *mode_set = 330 - &helper->crtc_info[i].mode_set; 331 - 328 + mutex_lock(&helper->client.modeset_mutex); 329 + drm_client_for_each_modeset(mode_set, &helper->client) { 332 330 if (!mode_set->crtc->enabled) 333 331 continue; 334 332 ··· 343 345 mode_set->y, 344 346 ENTER_ATOMIC_MODE_SET); 345 347 } 348 + mutex_unlock(&helper->client.modeset_mutex); 346 349 } 347 350 348 351 return 0; ··· 357 358 int drm_fb_helper_debug_leave(struct fb_info *info) 358 359 { 359 360 struct drm_fb_helper *helper = info->par; 361 + struct drm_client_dev *client = &helper->client; 360 362 struct drm_crtc *crtc; 361 363 const struct drm_crtc_helper_funcs *funcs; 364 + struct drm_mode_set *mode_set; 362 365 struct drm_framebuffer *fb; 363 - int i; 364 366 365 - for (i = 0; i < helper->crtc_count; i++) { 366 - struct drm_mode_set *mode_set = &helper->crtc_info[i].mode_set; 367 - 367 + mutex_lock(&client->modeset_mutex); 368 + drm_client_for_each_modeset(mode_set, client) { 368 369 crtc = mode_set->crtc; 369 370 if (drm_drv_uses_atomic_modeset(crtc->dev)) 370 371 continue; ··· 387 388 funcs->mode_set_base_atomic(mode_set->crtc, fb, crtc->x, 388 389 crtc->y, LEAVE_ATOMIC_MODE_SET); 389 390 } 391 + mutex_unlock(&client->modeset_mutex); 390 392 391 393 return 0; 392 394 } ··· 438 438 439 439 static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper, bool active) 440 440 { 441 + struct drm_client_dev *client = &fb_helper->client; 441 442 struct drm_device *dev = fb_helper->dev; 442 443 struct drm_plane_state *plane_state; 443 444 struct drm_plane *plane; 444 445 struct drm_atomic_state *state; 445 - int i, ret; 446 446 struct drm_modeset_acquire_ctx ctx; 447 + struct drm_mode_set *mode_set; 448 + int ret; 447 449 448 450 drm_modeset_acquire_init(&ctx, 0); 449 451 ··· 475 473 goto out_state; 476 474 } 477 475 478 - for (i = 0; i < fb_helper->crtc_count; i++) { 479 - struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 476 + drm_client_for_each_modeset(mode_set, client) { 480 477 struct drm_plane *primary = mode_set->crtc->primary; 481 478 unsigned int rotation; 482 479 ··· 523 522 524 523 static int restore_fbdev_mode_legacy(struct drm_fb_helper *fb_helper) 525 524 { 525 + struct drm_client_dev *client = &fb_helper->client; 526 526 struct drm_device *dev = fb_helper->dev; 527 + struct drm_mode_set *mode_set; 527 528 struct drm_plane *plane; 528 - int i, ret = 0; 529 + int ret = 0; 529 530 530 531 drm_modeset_lock_all(fb_helper->dev); 531 532 drm_for_each_plane(plane, dev) { ··· 540 537 DRM_MODE_ROTATE_0); 541 538 } 542 539 543 - for (i = 0; i < fb_helper->crtc_count; i++) { 544 - struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 540 + drm_client_for_each_modeset(mode_set, client) { 545 541 struct drm_crtc *crtc = mode_set->crtc; 546 542 547 543 if (crtc->funcs->cursor_set2) { ··· 566 564 static int restore_fbdev_mode_force(struct drm_fb_helper *fb_helper) 567 565 { 568 566 struct drm_device *dev = fb_helper->dev; 567 + int ret; 569 568 569 + mutex_lock(&fb_helper->client.modeset_mutex); 570 570 if (drm_drv_uses_atomic_modeset(dev)) 571 - return restore_fbdev_mode_atomic(fb_helper, true); 571 + ret = restore_fbdev_mode_atomic(fb_helper, true); 572 572 else 573 - return restore_fbdev_mode_legacy(fb_helper); 573 + ret = restore_fbdev_mode_legacy(fb_helper); 574 + mutex_unlock(&fb_helper->client.modeset_mutex); 575 + 576 + return ret; 574 577 } 575 578 576 579 static int restore_fbdev_mode(struct drm_fb_helper *fb_helper) ··· 694 687 695 688 static void dpms_legacy(struct drm_fb_helper *fb_helper, int dpms_mode) 696 689 { 690 + struct drm_client_dev *client = &fb_helper->client; 697 691 struct drm_device *dev = fb_helper->dev; 698 692 struct drm_connector *connector; 699 693 struct drm_mode_set *modeset; 700 - int i, j; 694 + int j; 701 695 702 696 drm_modeset_lock_all(dev); 703 - for (i = 0; i < fb_helper->crtc_count; i++) { 704 - modeset = &fb_helper->crtc_info[i].mode_set; 705 - 697 + drm_client_for_each_modeset(modeset, client) { 706 698 if (!modeset->crtc->enabled) 707 699 continue; 708 700 ··· 718 712 static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode) 719 713 { 720 714 struct drm_fb_helper *fb_helper = info->par; 715 + struct drm_client_dev *client = &fb_helper->client; 721 716 struct drm_device *dev = fb_helper->dev; 722 717 723 718 /* ··· 728 721 if (!drm_master_internal_acquire(dev)) 729 722 goto unlock; 730 723 724 + mutex_lock(&client->modeset_mutex); 731 725 if (drm_drv_uses_atomic_modeset(dev)) 732 726 restore_fbdev_mode_atomic(fb_helper, dpms_mode == DRM_MODE_DPMS_ON); 733 727 else 734 728 dpms_legacy(fb_helper, dpms_mode); 729 + mutex_unlock(&client->modeset_mutex); 735 730 736 731 drm_master_internal_release(dev); 737 732 unlock: ··· 775 766 return 0; 776 767 } 777 768 EXPORT_SYMBOL(drm_fb_helper_blank); 778 - 779 - static void drm_fb_helper_modeset_release(struct drm_fb_helper *helper, 780 - struct drm_mode_set *modeset) 781 - { 782 - int i; 783 - 784 - for (i = 0; i < modeset->num_connectors; i++) { 785 - drm_connector_put(modeset->connectors[i]); 786 - modeset->connectors[i] = NULL; 787 - } 788 - modeset->num_connectors = 0; 789 - 790 - drm_mode_destroy(helper->dev, modeset->mode); 791 - modeset->mode = NULL; 792 - 793 - /* FIXME should hold a ref? */ 794 - modeset->fb = NULL; 795 - } 796 - 797 - static void drm_fb_helper_crtc_free(struct drm_fb_helper *helper) 798 - { 799 - int i; 800 - 801 - for (i = 0; i < helper->connector_count; i++) { 802 - drm_connector_put(helper->connector_info[i]->connector); 803 - kfree(helper->connector_info[i]); 804 - } 805 - kfree(helper->connector_info); 806 - 807 - for (i = 0; i < helper->crtc_count; i++) { 808 - struct drm_mode_set *modeset = &helper->crtc_info[i].mode_set; 809 - 810 - drm_fb_helper_modeset_release(helper, modeset); 811 - kfree(modeset->connectors); 812 - } 813 - kfree(helper->crtc_info); 814 - } 815 769 816 770 static void drm_fb_helper_resume_worker(struct work_struct *work) 817 771 { ··· 854 882 * drm_fb_helper_init - initialize a &struct drm_fb_helper 855 883 * @dev: drm device 856 884 * @fb_helper: driver-allocated fbdev helper structure to initialize 857 - * @max_conn_count: max connector count 885 + * @max_conn_count: max connector count (not used) 858 886 * 859 887 * This allocates the structures for the fbdev helper with the given limits. 860 888 * Note that this won't yet touch the hardware (through the driver interfaces) ··· 870 898 struct drm_fb_helper *fb_helper, 871 899 int max_conn_count) 872 900 { 873 - struct drm_crtc *crtc; 874 - struct drm_mode_config *config = &dev->mode_config; 875 - int i; 901 + int ret; 876 902 877 903 if (!drm_fbdev_emulation) { 878 904 dev->fb_helper = fb_helper; 879 905 return 0; 880 906 } 881 907 882 - if (!max_conn_count) 883 - return -EINVAL; 884 - 885 - fb_helper->crtc_info = kcalloc(config->num_crtc, sizeof(struct drm_fb_helper_crtc), GFP_KERNEL); 886 - if (!fb_helper->crtc_info) 887 - return -ENOMEM; 888 - 889 - fb_helper->crtc_count = config->num_crtc; 890 - fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); 891 - if (!fb_helper->connector_info) { 892 - kfree(fb_helper->crtc_info); 893 - return -ENOMEM; 908 + /* 909 + * If this is not the generic fbdev client, initialize a drm_client 910 + * without callbacks so we can use the modesets. 911 + */ 912 + if (!fb_helper->client.funcs) { 913 + ret = drm_client_init(dev, &fb_helper->client, "drm_fb_helper", NULL); 914 + if (ret) 915 + return ret; 894 916 } 917 + 918 + fb_helper->connector_info = kcalloc(dev->mode_config.num_connector, sizeof(struct drm_fb_helper_connector *), GFP_KERNEL); 919 + if (!fb_helper->connector_info) 920 + goto out_free; 921 + 895 922 fb_helper->connector_info_alloc_count = dev->mode_config.num_connector; 896 923 fb_helper->connector_count = 0; 897 - 898 - for (i = 0; i < fb_helper->crtc_count; i++) { 899 - fb_helper->crtc_info[i].mode_set.connectors = 900 - kcalloc(max_conn_count, 901 - sizeof(struct drm_connector *), 902 - GFP_KERNEL); 903 - 904 - if (!fb_helper->crtc_info[i].mode_set.connectors) 905 - goto out_free; 906 - fb_helper->crtc_info[i].mode_set.num_connectors = 0; 907 - } 908 - 909 - i = 0; 910 - drm_for_each_crtc(crtc, dev) { 911 - fb_helper->crtc_info[i].mode_set.crtc = crtc; 912 - i++; 913 - } 914 924 915 925 dev->fb_helper = fb_helper; 916 926 917 927 return 0; 918 928 out_free: 919 - drm_fb_helper_crtc_free(fb_helper); 929 + drm_client_release(&fb_helper->client); 930 + 920 931 return -ENOMEM; 921 932 } 922 933 EXPORT_SYMBOL(drm_fb_helper_init); ··· 975 1020 void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) 976 1021 { 977 1022 struct fb_info *info; 1023 + int i; 978 1024 979 1025 if (!fb_helper) 980 1026 return; ··· 1005 1049 mutex_unlock(&kernel_fb_helper_lock); 1006 1050 1007 1051 mutex_destroy(&fb_helper->lock); 1008 - drm_fb_helper_crtc_free(fb_helper); 1009 1052 1053 + if (!fb_helper->client.funcs) 1054 + drm_client_release(&fb_helper->client); 1055 + 1056 + for (i = 0; i < fb_helper->connector_count; i++) { 1057 + drm_connector_put(fb_helper->connector_info[i]->connector); 1058 + kfree(fb_helper->connector_info[i]); 1059 + } 1060 + kfree(fb_helper->connector_info); 1010 1061 } 1011 1062 EXPORT_SYMBOL(drm_fb_helper_fini); 1012 1063 ··· 1358 1395 static int setcmap_legacy(struct fb_cmap *cmap, struct fb_info *info) 1359 1396 { 1360 1397 struct drm_fb_helper *fb_helper = info->par; 1398 + struct drm_mode_set *modeset; 1361 1399 struct drm_crtc *crtc; 1362 1400 u16 *r, *g, *b; 1363 - int i, ret = 0; 1401 + int ret = 0; 1364 1402 1365 1403 drm_modeset_lock_all(fb_helper->dev); 1366 - for (i = 0; i < fb_helper->crtc_count; i++) { 1367 - crtc = fb_helper->crtc_info[i].mode_set.crtc; 1404 + drm_client_for_each_modeset(modeset, &fb_helper->client) { 1405 + crtc = modeset->crtc; 1368 1406 if (!crtc->funcs->gamma_set || !crtc->gamma_size) 1369 1407 return -EINVAL; 1370 1408 ··· 1441 1477 struct drm_modeset_acquire_ctx ctx; 1442 1478 struct drm_crtc_state *crtc_state; 1443 1479 struct drm_atomic_state *state; 1480 + struct drm_mode_set *modeset; 1444 1481 struct drm_crtc *crtc; 1445 1482 u16 *r, *g, *b; 1446 - int i, ret = 0; 1447 1483 bool replaced; 1484 + int ret = 0; 1448 1485 1449 1486 drm_modeset_acquire_init(&ctx, 0); 1450 1487 ··· 1457 1492 1458 1493 state->acquire_ctx = &ctx; 1459 1494 retry: 1460 - for (i = 0; i < fb_helper->crtc_count; i++) { 1461 - crtc = fb_helper->crtc_info[i].mode_set.crtc; 1495 + drm_client_for_each_modeset(modeset, &fb_helper->client) { 1496 + crtc = modeset->crtc; 1462 1497 1463 1498 if (!gamma_lut) 1464 1499 gamma_lut = setcmap_new_gamma_lut(crtc, cmap); ··· 1486 1521 if (ret) 1487 1522 goto out_state; 1488 1523 1489 - for (i = 0; i < fb_helper->crtc_count; i++) { 1490 - crtc = fb_helper->crtc_info[i].mode_set.crtc; 1524 + drm_client_for_each_modeset(modeset, &fb_helper->client) { 1525 + crtc = modeset->crtc; 1491 1526 1492 1527 r = crtc->gamma_store; 1493 1528 g = r + crtc->gamma_size; ··· 1537 1572 goto unlock; 1538 1573 } 1539 1574 1575 + mutex_lock(&fb_helper->client.modeset_mutex); 1540 1576 if (info->fix.visual == FB_VISUAL_TRUECOLOR) 1541 1577 ret = setcmap_pseudo_palette(cmap, info); 1542 1578 else if (drm_drv_uses_atomic_modeset(fb_helper->dev)) 1543 1579 ret = setcmap_atomic(cmap, info); 1544 1580 else 1545 1581 ret = setcmap_legacy(cmap, info); 1582 + mutex_unlock(&fb_helper->client.modeset_mutex); 1546 1583 1547 1584 drm_master_internal_release(dev); 1548 1585 unlock: ··· 1568 1601 { 1569 1602 struct drm_fb_helper *fb_helper = info->par; 1570 1603 struct drm_device *dev = fb_helper->dev; 1571 - struct drm_mode_set *mode_set; 1572 1604 struct drm_crtc *crtc; 1573 1605 int ret = 0; 1574 1606 ··· 1595 1629 * make. If we're not smart enough here, one should 1596 1630 * just consider switch the userspace to KMS. 1597 1631 */ 1598 - mode_set = &fb_helper->crtc_info[0].mode_set; 1599 - crtc = mode_set->crtc; 1632 + crtc = fb_helper->client.modesets[0].crtc; 1600 1633 1601 1634 /* 1602 1635 * Only wait for a vblank event if the CRTC is ··· 1792 1827 1793 1828 static void pan_set(struct drm_fb_helper *fb_helper, int x, int y) 1794 1829 { 1795 - int i; 1830 + struct drm_mode_set *mode_set; 1796 1831 1797 - for (i = 0; i < fb_helper->crtc_count; i++) { 1798 - struct drm_mode_set *mode_set; 1799 - 1800 - mode_set = &fb_helper->crtc_info[i].mode_set; 1801 - 1832 + mutex_lock(&fb_helper->client.modeset_mutex); 1833 + drm_client_for_each_modeset(mode_set, &fb_helper->client) { 1802 1834 mode_set->x = x; 1803 1835 mode_set->y = y; 1804 1836 } 1837 + mutex_unlock(&fb_helper->client.modeset_mutex); 1805 1838 } 1806 1839 1807 1840 static int pan_display_atomic(struct fb_var_screeninfo *var, ··· 1810 1847 1811 1848 pan_set(fb_helper, var->xoffset, var->yoffset); 1812 1849 1813 - ret = restore_fbdev_mode_atomic(fb_helper, true); 1850 + ret = restore_fbdev_mode_force(fb_helper); 1814 1851 if (!ret) { 1815 1852 info->var.xoffset = var->xoffset; 1816 1853 info->var.yoffset = var->yoffset; ··· 1824 1861 struct fb_info *info) 1825 1862 { 1826 1863 struct drm_fb_helper *fb_helper = info->par; 1864 + struct drm_client_dev *client = &fb_helper->client; 1827 1865 struct drm_mode_set *modeset; 1828 1866 int ret = 0; 1829 - int i; 1830 1867 1831 1868 drm_modeset_lock_all(fb_helper->dev); 1832 - for (i = 0; i < fb_helper->crtc_count; i++) { 1833 - modeset = &fb_helper->crtc_info[i].mode_set; 1834 - 1869 + mutex_lock(&client->modeset_mutex); 1870 + drm_client_for_each_modeset(modeset, client) { 1835 1871 modeset->x = var->xoffset; 1836 1872 modeset->y = var->yoffset; 1837 1873 ··· 1842 1880 } 1843 1881 } 1844 1882 } 1883 + mutex_unlock(&client->modeset_mutex); 1845 1884 drm_modeset_unlock_all(fb_helper->dev); 1846 1885 1847 1886 return ret; ··· 1889 1926 static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, 1890 1927 int preferred_bpp) 1891 1928 { 1929 + struct drm_client_dev *client = &fb_helper->client; 1892 1930 int ret = 0; 1893 1931 int crtc_count = 0; 1894 1932 int i; 1895 1933 struct drm_fb_helper_surface_size sizes; 1934 + struct drm_mode_set *mode_set; 1896 1935 int best_depth = 0; 1897 1936 1898 1937 memset(&sizes, 0, sizeof(struct drm_fb_helper_surface_size)); ··· 1945 1980 * supports RGBA5551 (16 bpp, depth 15) but not RGB565 (16 bpp, depth 1946 1981 * 16) we need to scale down the depth of the sizes we request. 1947 1982 */ 1948 - for (i = 0; i < fb_helper->crtc_count; i++) { 1949 - struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; 1983 + mutex_lock(&client->modeset_mutex); 1984 + drm_client_for_each_modeset(mode_set, client) { 1950 1985 struct drm_crtc *crtc = mode_set->crtc; 1951 1986 struct drm_plane *plane = crtc->primary; 1952 1987 int j; 1953 1988 1954 - DRM_DEBUG("test CRTC %d primary plane\n", i); 1989 + DRM_DEBUG("test CRTC %u primary plane\n", drm_crtc_index(crtc)); 1955 1990 1956 1991 for (j = 0; j < plane->format_count; j++) { 1957 1992 const struct drm_format_info *fmt; ··· 1991 2026 1992 2027 /* first up get a count of crtcs now in use and new min/maxes width/heights */ 1993 2028 crtc_count = 0; 1994 - for (i = 0; i < fb_helper->crtc_count; i++) { 2029 + drm_client_for_each_modeset(mode_set, client) { 1995 2030 struct drm_display_mode *desired_mode; 1996 - struct drm_mode_set *mode_set; 1997 2031 int x, y, j; 1998 2032 /* in case of tile group, are we the last tile vert or horiz? 1999 2033 * If no tile group you are always the last one both vertically ··· 2000 2036 */ 2001 2037 bool lastv = true, lasth = true; 2002 2038 2003 - mode_set = &fb_helper->crtc_info[i].mode_set; 2004 2039 desired_mode = mode_set->mode; 2005 2040 2006 2041 if (!desired_mode) ··· 2029 2066 if (lastv) 2030 2067 sizes.fb_height = min_t(u32, desired_mode->vdisplay + y, sizes.fb_height); 2031 2068 } 2069 + mutex_unlock(&client->modeset_mutex); 2032 2070 2033 2071 if (crtc_count == 0 || sizes.fb_width == -1 || sizes.fb_height == -1) { 2034 2072 DRM_INFO("Cannot find any crtc or sizes\n"); ··· 2261 2297 struct drm_display_mode *dmt_mode, *mode; 2262 2298 2263 2299 /* only contemplate cloning in the single crtc case */ 2264 - if (fb_helper->crtc_count > 1) 2300 + if (fb_helper->dev->mode_config.num_crtc > 1) 2265 2301 return false; 2266 2302 2267 2303 count = 0; ··· 2450 2486 } 2451 2487 2452 2488 static int drm_pick_crtcs(struct drm_fb_helper *fb_helper, 2453 - struct drm_fb_helper_crtc **best_crtcs, 2489 + struct drm_crtc **best_crtcs, 2454 2490 struct drm_display_mode **modes, 2455 2491 int n, int width, int height) 2456 2492 { 2457 - int c, o; 2493 + struct drm_client_dev *client = &fb_helper->client; 2458 2494 struct drm_connector *connector; 2459 2495 int my_score, best_score, score; 2460 - struct drm_fb_helper_crtc **crtcs, *crtc; 2496 + struct drm_crtc **crtcs, *crtc; 2497 + struct drm_mode_set *modeset; 2461 2498 struct drm_fb_helper_connector *fb_helper_conn; 2499 + int o; 2462 2500 2463 2501 if (n == fb_helper->connector_count) 2464 2502 return 0; ··· 2473 2507 if (modes[n] == NULL) 2474 2508 return best_score; 2475 2509 2476 - crtcs = kcalloc(fb_helper->connector_count, 2477 - sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 2510 + crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL); 2478 2511 if (!crtcs) 2479 2512 return best_score; 2480 2513 ··· 2489 2524 * select a crtc for this connector and then attempt to configure 2490 2525 * remaining connectors 2491 2526 */ 2492 - for (c = 0; c < fb_helper->crtc_count; c++) { 2493 - crtc = &fb_helper->crtc_info[c]; 2527 + drm_client_for_each_modeset(modeset, client) { 2528 + crtc = modeset->crtc; 2494 2529 2495 - if (!connector_has_possible_crtc(connector, 2496 - crtc->mode_set.crtc)) 2530 + if (!connector_has_possible_crtc(connector, crtc)) 2497 2531 continue; 2498 2532 2499 2533 for (o = 0; o < n; o++) ··· 2501 2537 2502 2538 if (o < n) { 2503 2539 /* ignore cloning unless only a single crtc */ 2504 - if (fb_helper->crtc_count > 1) 2540 + if (fb_helper->dev->mode_config.num_crtc > 1) 2505 2541 continue; 2506 2542 2507 2543 if (!drm_mode_equal(modes[o], modes[n])) ··· 2509 2545 } 2510 2546 2511 2547 crtcs[n] = crtc; 2512 - memcpy(crtcs, best_crtcs, n * sizeof(struct drm_fb_helper_crtc *)); 2548 + memcpy(crtcs, best_crtcs, n * sizeof(*crtcs)); 2513 2549 score = my_score + drm_pick_crtcs(fb_helper, crtcs, modes, n + 1, 2514 2550 width, height); 2515 2551 if (score > best_score) { 2516 2552 best_score = score; 2517 2553 memcpy(best_crtcs, crtcs, 2518 - fb_helper->connector_count * 2519 - sizeof(struct drm_fb_helper_crtc *)); 2554 + fb_helper->connector_count * sizeof(*crtcs)); 2520 2555 } 2521 2556 } 2522 2557 ··· 2523 2560 return best_score; 2524 2561 } 2525 2562 2526 - static struct drm_fb_helper_crtc * 2527 - drm_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc) 2528 - { 2529 - int i; 2530 - 2531 - for (i = 0; i < fb_helper->crtc_count; i++) 2532 - if (fb_helper->crtc_info[i].mode_set.crtc == crtc) 2533 - return &fb_helper->crtc_info[i]; 2534 - 2535 - return NULL; 2536 - } 2537 - 2538 2563 /* Try to read the BIOS display configuration and use it for the initial config */ 2539 2564 static bool drm_fb_helper_firmware_config(struct drm_fb_helper *fb_helper, 2540 - struct drm_fb_helper_crtc **crtcs, 2565 + struct drm_crtc **crtcs, 2541 2566 struct drm_display_mode **modes, 2542 2567 struct drm_fb_offset *offsets, 2543 2568 bool *enabled, int width, int height) ··· 2561 2610 struct drm_fb_helper_connector *fb_conn; 2562 2611 struct drm_connector *connector; 2563 2612 struct drm_encoder *encoder; 2564 - struct drm_fb_helper_crtc *new_crtc; 2613 + struct drm_crtc *new_crtc; 2565 2614 2566 2615 fb_conn = fb_helper->connector_info[i]; 2567 2616 connector = fb_conn->connector; ··· 2603 2652 2604 2653 num_connectors_enabled++; 2605 2654 2606 - new_crtc = drm_fb_helper_crtc(fb_helper, connector->state->crtc); 2655 + new_crtc = connector->state->crtc; 2607 2656 2608 2657 /* 2609 2658 * Make sure we're not trying to drive multiple connectors ··· 2703 2752 static void drm_setup_crtcs(struct drm_fb_helper *fb_helper, 2704 2753 u32 width, u32 height) 2705 2754 { 2755 + struct drm_client_dev *client = &fb_helper->client; 2706 2756 struct drm_device *dev = fb_helper->dev; 2707 - struct drm_fb_helper_crtc **crtcs; 2708 2757 struct drm_display_mode **modes; 2709 2758 struct drm_fb_offset *offsets; 2759 + struct drm_crtc **crtcs; 2710 2760 bool *enabled; 2711 2761 int i; 2712 2762 ··· 2715 2763 /* prevent concurrent modification of connector_count by hotplug */ 2716 2764 lockdep_assert_held(&fb_helper->lock); 2717 2765 2718 - crtcs = kcalloc(fb_helper->connector_count, 2719 - sizeof(struct drm_fb_helper_crtc *), GFP_KERNEL); 2766 + crtcs = kcalloc(fb_helper->connector_count, sizeof(*crtcs), GFP_KERNEL); 2720 2767 modes = kcalloc(fb_helper->connector_count, 2721 2768 sizeof(struct drm_display_mode *), GFP_KERNEL); 2722 2769 offsets = kcalloc(fb_helper->connector_count, ··· 2726 2775 DRM_ERROR("Memory allocation failed\n"); 2727 2776 goto out; 2728 2777 } 2778 + 2779 + mutex_lock(&client->modeset_mutex); 2729 2780 2730 2781 mutex_lock(&fb_helper->dev->mode_config.mutex); 2731 2782 if (drm_fb_helper_probe_connector_modes(fb_helper, width, height) == 0) ··· 2753 2800 } 2754 2801 mutex_unlock(&fb_helper->dev->mode_config.mutex); 2755 2802 2756 - /* need to set the modesets up here for use later */ 2757 - /* fill out the connector<->crtc mappings into the modesets */ 2758 - for (i = 0; i < fb_helper->crtc_count; i++) 2759 - drm_fb_helper_modeset_release(fb_helper, 2760 - &fb_helper->crtc_info[i].mode_set); 2803 + drm_client_modeset_release(client); 2761 2804 2762 2805 drm_fb_helper_for_each_connector(fb_helper, i) { 2763 2806 struct drm_display_mode *mode = modes[i]; 2764 - struct drm_fb_helper_crtc *fb_crtc = crtcs[i]; 2807 + struct drm_crtc *crtc = crtcs[i]; 2765 2808 struct drm_fb_offset *offset = &offsets[i]; 2766 2809 2767 - if (mode && fb_crtc) { 2768 - struct drm_mode_set *modeset = &fb_crtc->mode_set; 2810 + if (mode && crtc) { 2811 + struct drm_mode_set *modeset = drm_client_find_modeset(client, crtc); 2769 2812 struct drm_connector *connector = 2770 2813 fb_helper->connector_info[i]->connector; 2771 2814 2772 2815 DRM_DEBUG_KMS("desired mode %s set on crtc %d (%d,%d)\n", 2773 - mode->name, fb_crtc->mode_set.crtc->base.id, offset->x, offset->y); 2816 + mode->name, crtc->base.id, offset->x, offset->y); 2817 + 2818 + if (WARN_ON_ONCE(modeset->num_connectors == DRM_CLIENT_MAX_CLONED_CONNECTORS || 2819 + (dev->mode_config.num_crtc > 1 && modeset->num_connectors == 1))) 2820 + break; 2774 2821 2775 2822 modeset->mode = drm_mode_duplicate(dev, mode); 2776 2823 drm_connector_get(connector); ··· 2779 2826 modeset->y = offset->y; 2780 2827 } 2781 2828 } 2829 + 2830 + mutex_unlock(&client->modeset_mutex); 2782 2831 out: 2783 2832 kfree(crtcs); 2784 2833 kfree(modes); ··· 2797 2842 */ 2798 2843 static void drm_setup_crtcs_fb(struct drm_fb_helper *fb_helper) 2799 2844 { 2845 + struct drm_client_dev *client = &fb_helper->client; 2800 2846 struct fb_info *info = fb_helper->fbdev; 2801 2847 unsigned int rotation, sw_rotations = 0; 2848 + struct drm_mode_set *modeset; 2802 2849 int i; 2803 2850 2804 - for (i = 0; i < fb_helper->crtc_count; i++) { 2805 - struct drm_mode_set *modeset = &fb_helper->crtc_info[i].mode_set; 2806 - 2851 + mutex_lock(&client->modeset_mutex); 2852 + drm_client_for_each_modeset(modeset, client) { 2807 2853 if (!modeset->num_connectors) 2808 2854 continue; 2809 2855 ··· 2816 2860 else 2817 2861 sw_rotations |= rotation; 2818 2862 } 2863 + mutex_unlock(&client->modeset_mutex); 2819 2864 2820 2865 mutex_lock(&fb_helper->dev->mode_config.mutex); 2821 2866 drm_fb_helper_for_each_connector(fb_helper, i) { ··· 3032 3075 * @funcs: fbdev helper functions 3033 3076 * @preferred_bpp: Preferred bits per pixel for the device. 3034 3077 * @dev->mode_config.preferred_depth is used if this is zero. 3035 - * @max_conn_count: Maximum number of connectors. 3036 - * @dev->mode_config.num_connector is used if this is zero. 3078 + * @max_conn_count: Maximum number of connectors (not used) 3037 3079 * 3038 3080 * This function sets up fbdev emulation and registers fbdev for access by 3039 3081 * userspace. If all connectors are disconnected, setup is deferred to the next ··· 3060 3104 if (!preferred_bpp) 3061 3105 preferred_bpp = 32; 3062 3106 3063 - if (!max_conn_count) 3064 - max_conn_count = dev->mode_config.num_connector; 3065 - if (!max_conn_count) { 3066 - DRM_DEV_ERROR(dev->dev, "fbdev: No connectors\n"); 3067 - return -EINVAL; 3068 - } 3069 - 3070 3107 drm_fb_helper_prepare(dev, fb_helper, funcs); 3071 3108 3072 - ret = drm_fb_helper_init(dev, fb_helper, max_conn_count); 3109 + ret = drm_fb_helper_init(dev, fb_helper, 0); 3073 3110 if (ret < 0) { 3074 3111 DRM_DEV_ERROR(dev->dev, "fbdev: Failed to initialize (ret=%d)\n", ret); 3075 3112 return ret; ··· 3375 3426 3376 3427 drm_fb_helper_prepare(dev, fb_helper, &drm_fb_helper_generic_funcs); 3377 3428 3378 - ret = drm_fb_helper_init(dev, fb_helper, dev->mode_config.num_connector); 3429 + ret = drm_fb_helper_init(dev, fb_helper, 0); 3379 3430 if (ret) 3380 3431 goto err; 3381 3432
+30
include/drm/drm_client.h
··· 3 3 #ifndef _DRM_CLIENT_H_ 4 4 #define _DRM_CLIENT_H_ 5 5 6 + #include <linux/lockdep.h> 7 + #include <linux/mutex.h> 6 8 #include <linux/types.h> 9 + 10 + #include <drm/drm_crtc.h> 7 11 8 12 struct drm_client_dev; 9 13 struct drm_device; ··· 16 12 struct drm_gem_object; 17 13 struct drm_minor; 18 14 struct module; 15 + 16 + #define DRM_CLIENT_MAX_CLONED_CONNECTORS 8 19 17 20 18 /** 21 19 * struct drm_client_funcs - DRM client callbacks ··· 91 85 * @file: DRM file 92 86 */ 93 87 struct drm_file *file; 88 + 89 + /** 90 + * @modeset_mutex: Protects @modesets. 91 + */ 92 + struct mutex modeset_mutex; 93 + 94 + /** 95 + * @modesets: CRTC configurations 96 + */ 97 + struct drm_mode_set *modesets; 94 98 }; 95 99 96 100 int drm_client_init(struct drm_device *dev, struct drm_client_dev *client, ··· 150 134 struct drm_client_buffer * 151 135 drm_client_framebuffer_create(struct drm_client_dev *client, u32 width, u32 height, u32 format); 152 136 void drm_client_framebuffer_delete(struct drm_client_buffer *buffer); 137 + 138 + int drm_client_modeset_create(struct drm_client_dev *client); 139 + void drm_client_modeset_free(struct drm_client_dev *client); 140 + void drm_client_modeset_release(struct drm_client_dev *client); 141 + struct drm_mode_set *drm_client_find_modeset(struct drm_client_dev *client, struct drm_crtc *crtc); 142 + 143 + /** 144 + * drm_client_for_each_modeset() - Iterate over client modesets 145 + * @modeset: &drm_mode_set loop cursor 146 + * @client: DRM client 147 + */ 148 + #define drm_client_for_each_modeset(modeset, client) \ 149 + for (({ lockdep_assert_held(&(client)->modeset_mutex); }), \ 150 + modeset = (client)->modesets; modeset->crtc; modeset++) 153 151 154 152 int drm_client_debugfs_init(struct drm_minor *minor); 155 153
-8
include/drm/drm_fb_helper.h
··· 47 47 int x, y; 48 48 }; 49 49 50 - struct drm_fb_helper_crtc { 51 - struct drm_mode_set mode_set; 52 - }; 53 - 54 50 /** 55 51 * struct drm_fb_helper_surface_size - describes fbdev size and scanout surface size 56 52 * @fb_width: fbdev width ··· 105 109 * struct drm_fb_helper - main structure to emulate fbdev on top of KMS 106 110 * @fb: Scanout framebuffer object 107 111 * @dev: DRM device 108 - * @crtc_count: number of possible CRTCs 109 - * @crtc_info: per-CRTC helper state (mode, x/y offset, etc) 110 112 * @connector_count: number of connected connectors 111 113 * @connector_info_alloc_count: size of connector_info 112 114 * @funcs: driver callbacks for fb helper ··· 138 144 139 145 struct drm_framebuffer *fb; 140 146 struct drm_device *dev; 141 - int crtc_count; 142 - struct drm_fb_helper_crtc *crtc_info; 143 147 int connector_count; 144 148 int connector_info_alloc_count; 145 149 /**