.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright (C) 2012 Avionic Design GmbH |
---|
3 | 4 | * Copyright (C) 2012-2016 NVIDIA CORPORATION. All rights reserved. |
---|
4 | | - * |
---|
5 | | - * This program is free software; you can redistribute it and/or modify |
---|
6 | | - * it under the terms of the GNU General Public License version 2 as |
---|
7 | | - * published by the Free Software Foundation. |
---|
8 | 5 | */ |
---|
9 | 6 | |
---|
10 | 7 | #include <linux/bitops.h> |
---|
11 | 8 | #include <linux/host1x.h> |
---|
12 | 9 | #include <linux/idr.h> |
---|
13 | 10 | #include <linux/iommu.h> |
---|
| 11 | +#include <linux/module.h> |
---|
| 12 | +#include <linux/platform_device.h> |
---|
14 | 13 | |
---|
15 | 14 | #include <drm/drm_atomic.h> |
---|
16 | 15 | #include <drm/drm_atomic_helper.h> |
---|
| 16 | +#include <drm/drm_debugfs.h> |
---|
| 17 | +#include <drm/drm_drv.h> |
---|
| 18 | +#include <drm/drm_fourcc.h> |
---|
| 19 | +#include <drm/drm_ioctl.h> |
---|
| 20 | +#include <drm/drm_prime.h> |
---|
| 21 | +#include <drm/drm_vblank.h> |
---|
17 | 22 | |
---|
18 | 23 | #include "drm.h" |
---|
19 | 24 | #include "gem.h" |
---|
.. | .. |
---|
77 | 82 | .atomic_commit_tail = tegra_atomic_commit_tail, |
---|
78 | 83 | }; |
---|
79 | 84 | |
---|
80 | | -static int tegra_drm_load(struct drm_device *drm, unsigned long flags) |
---|
81 | | -{ |
---|
82 | | - struct host1x_device *device = to_host1x_device(drm->dev); |
---|
83 | | - struct tegra_drm *tegra; |
---|
84 | | - int err; |
---|
85 | | - |
---|
86 | | - tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); |
---|
87 | | - if (!tegra) |
---|
88 | | - return -ENOMEM; |
---|
89 | | - |
---|
90 | | - if (iommu_present(&platform_bus_type)) { |
---|
91 | | - u64 carveout_start, carveout_end, gem_start, gem_end; |
---|
92 | | - struct iommu_domain_geometry *geometry; |
---|
93 | | - unsigned long order; |
---|
94 | | - |
---|
95 | | - tegra->domain = iommu_domain_alloc(&platform_bus_type); |
---|
96 | | - if (!tegra->domain) { |
---|
97 | | - err = -ENOMEM; |
---|
98 | | - goto free; |
---|
99 | | - } |
---|
100 | | - |
---|
101 | | - err = iova_cache_get(); |
---|
102 | | - if (err < 0) |
---|
103 | | - goto domain; |
---|
104 | | - |
---|
105 | | - geometry = &tegra->domain->geometry; |
---|
106 | | - gem_start = geometry->aperture_start; |
---|
107 | | - gem_end = geometry->aperture_end - CARVEOUT_SZ; |
---|
108 | | - carveout_start = gem_end + 1; |
---|
109 | | - carveout_end = geometry->aperture_end; |
---|
110 | | - |
---|
111 | | - order = __ffs(tegra->domain->pgsize_bitmap); |
---|
112 | | - init_iova_domain(&tegra->carveout.domain, 1UL << order, |
---|
113 | | - carveout_start >> order); |
---|
114 | | - |
---|
115 | | - tegra->carveout.shift = iova_shift(&tegra->carveout.domain); |
---|
116 | | - tegra->carveout.limit = carveout_end >> tegra->carveout.shift; |
---|
117 | | - |
---|
118 | | - drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1); |
---|
119 | | - mutex_init(&tegra->mm_lock); |
---|
120 | | - |
---|
121 | | - DRM_DEBUG("IOMMU apertures:\n"); |
---|
122 | | - DRM_DEBUG(" GEM: %#llx-%#llx\n", gem_start, gem_end); |
---|
123 | | - DRM_DEBUG(" Carveout: %#llx-%#llx\n", carveout_start, |
---|
124 | | - carveout_end); |
---|
125 | | - } |
---|
126 | | - |
---|
127 | | - mutex_init(&tegra->clients_lock); |
---|
128 | | - INIT_LIST_HEAD(&tegra->clients); |
---|
129 | | - |
---|
130 | | - drm->dev_private = tegra; |
---|
131 | | - tegra->drm = drm; |
---|
132 | | - |
---|
133 | | - drm_mode_config_init(drm); |
---|
134 | | - |
---|
135 | | - drm->mode_config.min_width = 0; |
---|
136 | | - drm->mode_config.min_height = 0; |
---|
137 | | - |
---|
138 | | - drm->mode_config.max_width = 4096; |
---|
139 | | - drm->mode_config.max_height = 4096; |
---|
140 | | - |
---|
141 | | - drm->mode_config.allow_fb_modifiers = true; |
---|
142 | | - |
---|
143 | | - drm->mode_config.normalize_zpos = true; |
---|
144 | | - |
---|
145 | | - drm->mode_config.funcs = &tegra_drm_mode_config_funcs; |
---|
146 | | - drm->mode_config.helper_private = &tegra_drm_mode_config_helpers; |
---|
147 | | - |
---|
148 | | - err = tegra_drm_fb_prepare(drm); |
---|
149 | | - if (err < 0) |
---|
150 | | - goto config; |
---|
151 | | - |
---|
152 | | - drm_kms_helper_poll_init(drm); |
---|
153 | | - |
---|
154 | | - err = host1x_device_init(device); |
---|
155 | | - if (err < 0) |
---|
156 | | - goto fbdev; |
---|
157 | | - |
---|
158 | | - if (tegra->hub) { |
---|
159 | | - err = tegra_display_hub_prepare(tegra->hub); |
---|
160 | | - if (err < 0) |
---|
161 | | - goto device; |
---|
162 | | - } |
---|
163 | | - |
---|
164 | | - /* |
---|
165 | | - * We don't use the drm_irq_install() helpers provided by the DRM |
---|
166 | | - * core, so we need to set this manually in order to allow the |
---|
167 | | - * DRM_IOCTL_WAIT_VBLANK to operate correctly. |
---|
168 | | - */ |
---|
169 | | - drm->irq_enabled = true; |
---|
170 | | - |
---|
171 | | - /* syncpoints are used for full 32-bit hardware VBLANK counters */ |
---|
172 | | - drm->max_vblank_count = 0xffffffff; |
---|
173 | | - |
---|
174 | | - err = drm_vblank_init(drm, drm->mode_config.num_crtc); |
---|
175 | | - if (err < 0) |
---|
176 | | - goto hub; |
---|
177 | | - |
---|
178 | | - drm_mode_config_reset(drm); |
---|
179 | | - |
---|
180 | | - err = tegra_drm_fb_init(drm); |
---|
181 | | - if (err < 0) |
---|
182 | | - goto hub; |
---|
183 | | - |
---|
184 | | - return 0; |
---|
185 | | - |
---|
186 | | -hub: |
---|
187 | | - if (tegra->hub) |
---|
188 | | - tegra_display_hub_cleanup(tegra->hub); |
---|
189 | | -device: |
---|
190 | | - host1x_device_exit(device); |
---|
191 | | -fbdev: |
---|
192 | | - drm_kms_helper_poll_fini(drm); |
---|
193 | | - tegra_drm_fb_free(drm); |
---|
194 | | -config: |
---|
195 | | - drm_mode_config_cleanup(drm); |
---|
196 | | - |
---|
197 | | - if (tegra->domain) { |
---|
198 | | - mutex_destroy(&tegra->mm_lock); |
---|
199 | | - drm_mm_takedown(&tegra->mm); |
---|
200 | | - put_iova_domain(&tegra->carveout.domain); |
---|
201 | | - iova_cache_put(); |
---|
202 | | - } |
---|
203 | | -domain: |
---|
204 | | - if (tegra->domain) |
---|
205 | | - iommu_domain_free(tegra->domain); |
---|
206 | | -free: |
---|
207 | | - kfree(tegra); |
---|
208 | | - return err; |
---|
209 | | -} |
---|
210 | | - |
---|
211 | | -static void tegra_drm_unload(struct drm_device *drm) |
---|
212 | | -{ |
---|
213 | | - struct host1x_device *device = to_host1x_device(drm->dev); |
---|
214 | | - struct tegra_drm *tegra = drm->dev_private; |
---|
215 | | - int err; |
---|
216 | | - |
---|
217 | | - drm_kms_helper_poll_fini(drm); |
---|
218 | | - tegra_drm_fb_exit(drm); |
---|
219 | | - drm_atomic_helper_shutdown(drm); |
---|
220 | | - drm_mode_config_cleanup(drm); |
---|
221 | | - |
---|
222 | | - err = host1x_device_exit(device); |
---|
223 | | - if (err < 0) |
---|
224 | | - return; |
---|
225 | | - |
---|
226 | | - if (tegra->domain) { |
---|
227 | | - mutex_destroy(&tegra->mm_lock); |
---|
228 | | - drm_mm_takedown(&tegra->mm); |
---|
229 | | - put_iova_domain(&tegra->carveout.domain); |
---|
230 | | - iova_cache_put(); |
---|
231 | | - iommu_domain_free(tegra->domain); |
---|
232 | | - } |
---|
233 | | - |
---|
234 | | - kfree(tegra); |
---|
235 | | -} |
---|
236 | | - |
---|
237 | 85 | static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) |
---|
238 | 86 | { |
---|
239 | 87 | struct tegra_drm_file *fpriv; |
---|
.. | .. |
---|
296 | 144 | err = get_user(dest->shift, &src->shift); |
---|
297 | 145 | if (err < 0) |
---|
298 | 146 | return err; |
---|
| 147 | + |
---|
| 148 | + dest->flags = HOST1X_RELOC_READ | HOST1X_RELOC_WRITE; |
---|
299 | 149 | |
---|
300 | 150 | dest->cmdbuf.bo = host1x_bo_lookup(file, cmdbuf); |
---|
301 | 151 | if (!dest->cmdbuf.bo) |
---|
.. | .. |
---|
478 | 328 | |
---|
479 | 329 | fail: |
---|
480 | 330 | while (num_refs--) |
---|
481 | | - drm_gem_object_put_unlocked(refs[num_refs]); |
---|
| 331 | + drm_gem_object_put(refs[num_refs]); |
---|
482 | 332 | |
---|
483 | 333 | kfree(refs); |
---|
484 | 334 | |
---|
.. | .. |
---|
518 | 368 | |
---|
519 | 369 | args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node); |
---|
520 | 370 | |
---|
521 | | - drm_gem_object_put_unlocked(gem); |
---|
| 371 | + drm_gem_object_put(gem); |
---|
522 | 372 | |
---|
523 | 373 | return 0; |
---|
524 | 374 | } |
---|
.. | .. |
---|
786 | 636 | bo->tiling.mode = mode; |
---|
787 | 637 | bo->tiling.value = value; |
---|
788 | 638 | |
---|
789 | | - drm_gem_object_put_unlocked(gem); |
---|
| 639 | + drm_gem_object_put(gem); |
---|
790 | 640 | |
---|
791 | 641 | return 0; |
---|
792 | 642 | } |
---|
.. | .. |
---|
826 | 676 | break; |
---|
827 | 677 | } |
---|
828 | 678 | |
---|
829 | | - drm_gem_object_put_unlocked(gem); |
---|
| 679 | + drm_gem_object_put(gem); |
---|
830 | 680 | |
---|
831 | 681 | return err; |
---|
832 | 682 | } |
---|
.. | .. |
---|
851 | 701 | if (args->flags & DRM_TEGRA_GEM_BOTTOM_UP) |
---|
852 | 702 | bo->flags |= TEGRA_BO_BOTTOM_UP; |
---|
853 | 703 | |
---|
854 | | - drm_gem_object_put_unlocked(gem); |
---|
| 704 | + drm_gem_object_put(gem); |
---|
855 | 705 | |
---|
856 | 706 | return 0; |
---|
857 | 707 | } |
---|
.. | .. |
---|
873 | 723 | if (bo->flags & TEGRA_BO_BOTTOM_UP) |
---|
874 | 724 | args->flags |= DRM_TEGRA_GEM_BOTTOM_UP; |
---|
875 | 725 | |
---|
876 | | - drm_gem_object_put_unlocked(gem); |
---|
| 726 | + drm_gem_object_put(gem); |
---|
877 | 727 | |
---|
878 | 728 | return 0; |
---|
879 | 729 | } |
---|
.. | .. |
---|
882 | 732 | static const struct drm_ioctl_desc tegra_drm_ioctls[] = { |
---|
883 | 733 | #ifdef CONFIG_DRM_TEGRA_STAGING |
---|
884 | 734 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, |
---|
885 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 735 | + DRM_RENDER_ALLOW), |
---|
886 | 736 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, |
---|
887 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 737 | + DRM_RENDER_ALLOW), |
---|
888 | 738 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, |
---|
889 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 739 | + DRM_RENDER_ALLOW), |
---|
890 | 740 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, |
---|
891 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 741 | + DRM_RENDER_ALLOW), |
---|
892 | 742 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, |
---|
893 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 743 | + DRM_RENDER_ALLOW), |
---|
894 | 744 | DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, |
---|
895 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 745 | + DRM_RENDER_ALLOW), |
---|
896 | 746 | DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, |
---|
897 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 747 | + DRM_RENDER_ALLOW), |
---|
898 | 748 | DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, |
---|
899 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 749 | + DRM_RENDER_ALLOW), |
---|
900 | 750 | DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, |
---|
901 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 751 | + DRM_RENDER_ALLOW), |
---|
902 | 752 | DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT_BASE, tegra_get_syncpt_base, |
---|
903 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 753 | + DRM_RENDER_ALLOW), |
---|
904 | 754 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_TILING, tegra_gem_set_tiling, |
---|
905 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 755 | + DRM_RENDER_ALLOW), |
---|
906 | 756 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_TILING, tegra_gem_get_tiling, |
---|
907 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 757 | + DRM_RENDER_ALLOW), |
---|
908 | 758 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_SET_FLAGS, tegra_gem_set_flags, |
---|
909 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 759 | + DRM_RENDER_ALLOW), |
---|
910 | 760 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_GET_FLAGS, tegra_gem_get_flags, |
---|
911 | | - DRM_UNLOCKED | DRM_RENDER_ALLOW), |
---|
| 761 | + DRM_RENDER_ALLOW), |
---|
912 | 762 | #endif |
---|
913 | 763 | }; |
---|
914 | 764 | |
---|
.. | .. |
---|
989 | 839 | { "iova", tegra_debugfs_iova, 0 }, |
---|
990 | 840 | }; |
---|
991 | 841 | |
---|
992 | | -static int tegra_debugfs_init(struct drm_minor *minor) |
---|
| 842 | +static void tegra_debugfs_init(struct drm_minor *minor) |
---|
993 | 843 | { |
---|
994 | | - return drm_debugfs_create_files(tegra_debugfs_list, |
---|
995 | | - ARRAY_SIZE(tegra_debugfs_list), |
---|
996 | | - minor->debugfs_root, minor); |
---|
| 844 | + drm_debugfs_create_files(tegra_debugfs_list, |
---|
| 845 | + ARRAY_SIZE(tegra_debugfs_list), |
---|
| 846 | + minor->debugfs_root, minor); |
---|
997 | 847 | } |
---|
998 | 848 | #endif |
---|
999 | 849 | |
---|
1000 | 850 | static struct drm_driver tegra_drm_driver = { |
---|
1001 | | - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | |
---|
| 851 | + .driver_features = DRIVER_MODESET | DRIVER_GEM | |
---|
1002 | 852 | DRIVER_ATOMIC | DRIVER_RENDER, |
---|
1003 | | - .load = tegra_drm_load, |
---|
1004 | | - .unload = tegra_drm_unload, |
---|
1005 | 853 | .open = tegra_drm_open, |
---|
1006 | 854 | .postclose = tegra_drm_postclose, |
---|
1007 | 855 | .lastclose = drm_fb_helper_lastclose, |
---|
.. | .. |
---|
1037 | 885 | { |
---|
1038 | 886 | mutex_lock(&tegra->clients_lock); |
---|
1039 | 887 | list_add_tail(&client->list, &tegra->clients); |
---|
| 888 | + client->drm = tegra; |
---|
1040 | 889 | mutex_unlock(&tegra->clients_lock); |
---|
1041 | 890 | |
---|
1042 | 891 | return 0; |
---|
.. | .. |
---|
1047 | 896 | { |
---|
1048 | 897 | mutex_lock(&tegra->clients_lock); |
---|
1049 | 898 | list_del_init(&client->list); |
---|
| 899 | + client->drm = NULL; |
---|
1050 | 900 | mutex_unlock(&tegra->clients_lock); |
---|
1051 | 901 | |
---|
1052 | 902 | return 0; |
---|
1053 | 903 | } |
---|
1054 | 904 | |
---|
1055 | | -struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client, |
---|
1056 | | - bool shared) |
---|
| 905 | +int host1x_client_iommu_attach(struct host1x_client *client) |
---|
1057 | 906 | { |
---|
1058 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
---|
| 907 | + struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev); |
---|
| 908 | + struct drm_device *drm = dev_get_drvdata(client->host); |
---|
1059 | 909 | struct tegra_drm *tegra = drm->dev_private; |
---|
1060 | 910 | struct iommu_group *group = NULL; |
---|
1061 | 911 | int err; |
---|
1062 | 912 | |
---|
| 913 | + /* |
---|
| 914 | + * If the host1x client is already attached to an IOMMU domain that is |
---|
| 915 | + * not the shared IOMMU domain, don't try to attach it to a different |
---|
| 916 | + * domain. This allows using the IOMMU-backed DMA API. |
---|
| 917 | + */ |
---|
| 918 | + if (domain && domain != tegra->domain) |
---|
| 919 | + return 0; |
---|
| 920 | + |
---|
1063 | 921 | if (tegra->domain) { |
---|
1064 | 922 | group = iommu_group_get(client->dev); |
---|
1065 | | - if (!group) { |
---|
1066 | | - dev_err(client->dev, "failed to get IOMMU group\n"); |
---|
1067 | | - return ERR_PTR(-ENODEV); |
---|
1068 | | - } |
---|
| 923 | + if (!group) |
---|
| 924 | + return -ENODEV; |
---|
1069 | 925 | |
---|
1070 | | - if (!shared || (shared && (group != tegra->group))) { |
---|
| 926 | + if (domain != tegra->domain) { |
---|
1071 | 927 | err = iommu_attach_group(tegra->domain, group); |
---|
1072 | 928 | if (err < 0) { |
---|
1073 | 929 | iommu_group_put(group); |
---|
1074 | | - return ERR_PTR(err); |
---|
| 930 | + return err; |
---|
1075 | 931 | } |
---|
1076 | | - |
---|
1077 | | - if (shared && !tegra->group) |
---|
1078 | | - tegra->group = group; |
---|
1079 | 932 | } |
---|
| 933 | + |
---|
| 934 | + tegra->use_explicit_iommu = true; |
---|
1080 | 935 | } |
---|
1081 | 936 | |
---|
1082 | | - return group; |
---|
| 937 | + client->group = group; |
---|
| 938 | + |
---|
| 939 | + return 0; |
---|
1083 | 940 | } |
---|
1084 | 941 | |
---|
1085 | | -void host1x_client_iommu_detach(struct host1x_client *client, |
---|
1086 | | - struct iommu_group *group) |
---|
| 942 | +void host1x_client_iommu_detach(struct host1x_client *client) |
---|
1087 | 943 | { |
---|
1088 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
---|
| 944 | + struct drm_device *drm = dev_get_drvdata(client->host); |
---|
1089 | 945 | struct tegra_drm *tegra = drm->dev_private; |
---|
| 946 | + struct iommu_domain *domain; |
---|
1090 | 947 | |
---|
1091 | | - if (group) { |
---|
1092 | | - if (group == tegra->group) { |
---|
1093 | | - iommu_detach_group(tegra->domain, group); |
---|
1094 | | - tegra->group = NULL; |
---|
1095 | | - } |
---|
| 948 | + if (client->group) { |
---|
| 949 | + /* |
---|
| 950 | + * Devices that are part of the same group may no longer be |
---|
| 951 | + * attached to a domain at this point because their group may |
---|
| 952 | + * have been detached by an earlier client. |
---|
| 953 | + */ |
---|
| 954 | + domain = iommu_get_domain_for_dev(client->dev); |
---|
| 955 | + if (domain) |
---|
| 956 | + iommu_detach_group(tegra->domain, client->group); |
---|
1096 | 957 | |
---|
1097 | | - iommu_group_put(group); |
---|
| 958 | + iommu_group_put(client->group); |
---|
| 959 | + client->group = NULL; |
---|
1098 | 960 | } |
---|
1099 | 961 | } |
---|
1100 | 962 | |
---|
.. | .. |
---|
1175 | 1037 | free_pages((unsigned long)virt, get_order(size)); |
---|
1176 | 1038 | } |
---|
1177 | 1039 | |
---|
| 1040 | +static bool host1x_drm_wants_iommu(struct host1x_device *dev) |
---|
| 1041 | +{ |
---|
| 1042 | + struct host1x *host1x = dev_get_drvdata(dev->dev.parent); |
---|
| 1043 | + struct iommu_domain *domain; |
---|
| 1044 | + |
---|
| 1045 | + /* Our IOMMU usage policy doesn't currently play well with GART */ |
---|
| 1046 | + if (of_machine_is_compatible("nvidia,tegra20")) |
---|
| 1047 | + return false; |
---|
| 1048 | + |
---|
| 1049 | + /* |
---|
| 1050 | + * If the Tegra DRM clients are backed by an IOMMU, push buffers are |
---|
| 1051 | + * likely to be allocated beyond the 32-bit boundary if sufficient |
---|
| 1052 | + * system memory is available. This is problematic on earlier Tegra |
---|
| 1053 | + * generations where host1x supports a maximum of 32 address bits in |
---|
| 1054 | + * the GATHER opcode. In this case, unless host1x is behind an IOMMU |
---|
| 1055 | + * as well it won't be able to process buffers allocated beyond the |
---|
| 1056 | + * 32-bit boundary. |
---|
| 1057 | + * |
---|
| 1058 | + * The DMA API will use bounce buffers in this case, so that could |
---|
| 1059 | + * perhaps still be made to work, even if less efficient, but there |
---|
| 1060 | + * is another catch: in order to perform cache maintenance on pages |
---|
| 1061 | + * allocated for discontiguous buffers we need to map and unmap the |
---|
| 1062 | + * SG table representing these buffers. This is fine for something |
---|
| 1063 | + * small like a push buffer, but it exhausts the bounce buffer pool |
---|
| 1064 | + * (typically on the order of a few MiB) for framebuffers (many MiB |
---|
| 1065 | + * for any modern resolution). |
---|
| 1066 | + * |
---|
| 1067 | + * Work around this by making sure that Tegra DRM clients only use |
---|
| 1068 | + * an IOMMU if the parent host1x also uses an IOMMU. |
---|
| 1069 | + * |
---|
| 1070 | + * Note that there's still a small gap here that we don't cover: if |
---|
| 1071 | + * the DMA API is backed by an IOMMU there's no way to control which |
---|
| 1072 | + * device is attached to an IOMMU and which isn't, except via wiring |
---|
| 1073 | + * up the device tree appropriately. This is considered an problem |
---|
| 1074 | + * of integration, so care must be taken for the DT to be consistent. |
---|
| 1075 | + */ |
---|
| 1076 | + domain = iommu_get_domain_for_dev(dev->dev.parent); |
---|
| 1077 | + |
---|
| 1078 | + /* |
---|
| 1079 | + * Tegra20 and Tegra30 don't support addressing memory beyond the |
---|
| 1080 | + * 32-bit boundary, so the regular GATHER opcodes will always be |
---|
| 1081 | + * sufficient and whether or not the host1x is attached to an IOMMU |
---|
| 1082 | + * doesn't matter. |
---|
| 1083 | + */ |
---|
| 1084 | + if (!domain && host1x_get_dma_mask(host1x) <= DMA_BIT_MASK(32)) |
---|
| 1085 | + return true; |
---|
| 1086 | + |
---|
| 1087 | + return domain != NULL; |
---|
| 1088 | +} |
---|
| 1089 | + |
---|
1178 | 1090 | static int host1x_drm_probe(struct host1x_device *dev) |
---|
1179 | 1091 | { |
---|
1180 | 1092 | struct drm_driver *driver = &tegra_drm_driver; |
---|
| 1093 | + struct tegra_drm *tegra; |
---|
1181 | 1094 | struct drm_device *drm; |
---|
1182 | 1095 | int err; |
---|
1183 | 1096 | |
---|
.. | .. |
---|
1185 | 1098 | if (IS_ERR(drm)) |
---|
1186 | 1099 | return PTR_ERR(drm); |
---|
1187 | 1100 | |
---|
| 1101 | + tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); |
---|
| 1102 | + if (!tegra) { |
---|
| 1103 | + err = -ENOMEM; |
---|
| 1104 | + goto put; |
---|
| 1105 | + } |
---|
| 1106 | + |
---|
| 1107 | + if (host1x_drm_wants_iommu(dev) && iommu_present(&platform_bus_type)) { |
---|
| 1108 | + tegra->domain = iommu_domain_alloc(&platform_bus_type); |
---|
| 1109 | + if (!tegra->domain) { |
---|
| 1110 | + err = -ENOMEM; |
---|
| 1111 | + goto free; |
---|
| 1112 | + } |
---|
| 1113 | + |
---|
| 1114 | + err = iova_cache_get(); |
---|
| 1115 | + if (err < 0) |
---|
| 1116 | + goto domain; |
---|
| 1117 | + } |
---|
| 1118 | + |
---|
| 1119 | + mutex_init(&tegra->clients_lock); |
---|
| 1120 | + INIT_LIST_HEAD(&tegra->clients); |
---|
| 1121 | + |
---|
1188 | 1122 | dev_set_drvdata(&dev->dev, drm); |
---|
| 1123 | + drm->dev_private = tegra; |
---|
| 1124 | + tegra->drm = drm; |
---|
| 1125 | + |
---|
| 1126 | + drm_mode_config_init(drm); |
---|
| 1127 | + |
---|
| 1128 | + drm->mode_config.min_width = 0; |
---|
| 1129 | + drm->mode_config.min_height = 0; |
---|
| 1130 | + |
---|
| 1131 | + drm->mode_config.max_width = 4096; |
---|
| 1132 | + drm->mode_config.max_height = 4096; |
---|
| 1133 | + |
---|
| 1134 | + drm->mode_config.normalize_zpos = true; |
---|
| 1135 | + |
---|
| 1136 | + drm->mode_config.funcs = &tegra_drm_mode_config_funcs; |
---|
| 1137 | + drm->mode_config.helper_private = &tegra_drm_mode_config_helpers; |
---|
| 1138 | + |
---|
| 1139 | + err = tegra_drm_fb_prepare(drm); |
---|
| 1140 | + if (err < 0) |
---|
| 1141 | + goto config; |
---|
| 1142 | + |
---|
| 1143 | + drm_kms_helper_poll_init(drm); |
---|
| 1144 | + |
---|
| 1145 | + err = host1x_device_init(dev); |
---|
| 1146 | + if (err < 0) |
---|
| 1147 | + goto fbdev; |
---|
| 1148 | + |
---|
| 1149 | + if (tegra->use_explicit_iommu) { |
---|
| 1150 | + u64 carveout_start, carveout_end, gem_start, gem_end; |
---|
| 1151 | + u64 dma_mask = dma_get_mask(&dev->dev); |
---|
| 1152 | + dma_addr_t start, end; |
---|
| 1153 | + unsigned long order; |
---|
| 1154 | + |
---|
| 1155 | + start = tegra->domain->geometry.aperture_start & dma_mask; |
---|
| 1156 | + end = tegra->domain->geometry.aperture_end & dma_mask; |
---|
| 1157 | + |
---|
| 1158 | + gem_start = start; |
---|
| 1159 | + gem_end = end - CARVEOUT_SZ; |
---|
| 1160 | + carveout_start = gem_end + 1; |
---|
| 1161 | + carveout_end = end; |
---|
| 1162 | + |
---|
| 1163 | + order = __ffs(tegra->domain->pgsize_bitmap); |
---|
| 1164 | + init_iova_domain(&tegra->carveout.domain, 1UL << order, |
---|
| 1165 | + carveout_start >> order); |
---|
| 1166 | + |
---|
| 1167 | + tegra->carveout.shift = iova_shift(&tegra->carveout.domain); |
---|
| 1168 | + tegra->carveout.limit = carveout_end >> tegra->carveout.shift; |
---|
| 1169 | + |
---|
| 1170 | + drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1); |
---|
| 1171 | + mutex_init(&tegra->mm_lock); |
---|
| 1172 | + |
---|
| 1173 | + DRM_DEBUG_DRIVER("IOMMU apertures:\n"); |
---|
| 1174 | + DRM_DEBUG_DRIVER(" GEM: %#llx-%#llx\n", gem_start, gem_end); |
---|
| 1175 | + DRM_DEBUG_DRIVER(" Carveout: %#llx-%#llx\n", carveout_start, |
---|
| 1176 | + carveout_end); |
---|
| 1177 | + } else if (tegra->domain) { |
---|
| 1178 | + iommu_domain_free(tegra->domain); |
---|
| 1179 | + tegra->domain = NULL; |
---|
| 1180 | + iova_cache_put(); |
---|
| 1181 | + } |
---|
| 1182 | + |
---|
| 1183 | + if (tegra->hub) { |
---|
| 1184 | + err = tegra_display_hub_prepare(tegra->hub); |
---|
| 1185 | + if (err < 0) |
---|
| 1186 | + goto device; |
---|
| 1187 | + } |
---|
| 1188 | + |
---|
| 1189 | + /* |
---|
| 1190 | + * We don't use the drm_irq_install() helpers provided by the DRM |
---|
| 1191 | + * core, so we need to set this manually in order to allow the |
---|
| 1192 | + * DRM_IOCTL_WAIT_VBLANK to operate correctly. |
---|
| 1193 | + */ |
---|
| 1194 | + drm->irq_enabled = true; |
---|
| 1195 | + |
---|
| 1196 | + /* syncpoints are used for full 32-bit hardware VBLANK counters */ |
---|
| 1197 | + drm->max_vblank_count = 0xffffffff; |
---|
| 1198 | + |
---|
| 1199 | + err = drm_vblank_init(drm, drm->mode_config.num_crtc); |
---|
| 1200 | + if (err < 0) |
---|
| 1201 | + goto hub; |
---|
| 1202 | + |
---|
| 1203 | + drm_mode_config_reset(drm); |
---|
| 1204 | + |
---|
| 1205 | + err = drm_fb_helper_remove_conflicting_framebuffers(NULL, "tegradrmfb", |
---|
| 1206 | + false); |
---|
| 1207 | + if (err < 0) |
---|
| 1208 | + goto hub; |
---|
| 1209 | + |
---|
| 1210 | + err = tegra_drm_fb_init(drm); |
---|
| 1211 | + if (err < 0) |
---|
| 1212 | + goto hub; |
---|
1189 | 1213 | |
---|
1190 | 1214 | err = drm_dev_register(drm, 0); |
---|
1191 | 1215 | if (err < 0) |
---|
1192 | | - goto unref; |
---|
| 1216 | + goto fb; |
---|
1193 | 1217 | |
---|
1194 | 1218 | return 0; |
---|
1195 | 1219 | |
---|
1196 | | -unref: |
---|
1197 | | - drm_dev_unref(drm); |
---|
| 1220 | +fb: |
---|
| 1221 | + tegra_drm_fb_exit(drm); |
---|
| 1222 | +hub: |
---|
| 1223 | + if (tegra->hub) |
---|
| 1224 | + tegra_display_hub_cleanup(tegra->hub); |
---|
| 1225 | +device: |
---|
| 1226 | + if (tegra->domain) { |
---|
| 1227 | + mutex_destroy(&tegra->mm_lock); |
---|
| 1228 | + drm_mm_takedown(&tegra->mm); |
---|
| 1229 | + put_iova_domain(&tegra->carveout.domain); |
---|
| 1230 | + iova_cache_put(); |
---|
| 1231 | + } |
---|
| 1232 | + |
---|
| 1233 | + host1x_device_exit(dev); |
---|
| 1234 | +fbdev: |
---|
| 1235 | + drm_kms_helper_poll_fini(drm); |
---|
| 1236 | + tegra_drm_fb_free(drm); |
---|
| 1237 | +config: |
---|
| 1238 | + drm_mode_config_cleanup(drm); |
---|
| 1239 | +domain: |
---|
| 1240 | + if (tegra->domain) |
---|
| 1241 | + iommu_domain_free(tegra->domain); |
---|
| 1242 | +free: |
---|
| 1243 | + kfree(tegra); |
---|
| 1244 | +put: |
---|
| 1245 | + drm_dev_put(drm); |
---|
1198 | 1246 | return err; |
---|
1199 | 1247 | } |
---|
1200 | 1248 | |
---|
1201 | 1249 | static int host1x_drm_remove(struct host1x_device *dev) |
---|
1202 | 1250 | { |
---|
1203 | 1251 | struct drm_device *drm = dev_get_drvdata(&dev->dev); |
---|
| 1252 | + struct tegra_drm *tegra = drm->dev_private; |
---|
| 1253 | + int err; |
---|
1204 | 1254 | |
---|
1205 | 1255 | drm_dev_unregister(drm); |
---|
1206 | | - drm_dev_unref(drm); |
---|
| 1256 | + |
---|
| 1257 | + drm_kms_helper_poll_fini(drm); |
---|
| 1258 | + tegra_drm_fb_exit(drm); |
---|
| 1259 | + drm_atomic_helper_shutdown(drm); |
---|
| 1260 | + drm_mode_config_cleanup(drm); |
---|
| 1261 | + |
---|
| 1262 | + if (tegra->hub) |
---|
| 1263 | + tegra_display_hub_cleanup(tegra->hub); |
---|
| 1264 | + |
---|
| 1265 | + err = host1x_device_exit(dev); |
---|
| 1266 | + if (err < 0) |
---|
| 1267 | + dev_err(&dev->dev, "host1x device cleanup failed: %d\n", err); |
---|
| 1268 | + |
---|
| 1269 | + if (tegra->domain) { |
---|
| 1270 | + mutex_destroy(&tegra->mm_lock); |
---|
| 1271 | + drm_mm_takedown(&tegra->mm); |
---|
| 1272 | + put_iova_domain(&tegra->carveout.domain); |
---|
| 1273 | + iova_cache_put(); |
---|
| 1274 | + iommu_domain_free(tegra->domain); |
---|
| 1275 | + } |
---|
| 1276 | + |
---|
| 1277 | + kfree(tegra); |
---|
| 1278 | + drm_dev_put(drm); |
---|
1207 | 1279 | |
---|
1208 | 1280 | return 0; |
---|
1209 | 1281 | } |
---|
.. | .. |
---|
1212 | 1284 | static int host1x_drm_suspend(struct device *dev) |
---|
1213 | 1285 | { |
---|
1214 | 1286 | struct drm_device *drm = dev_get_drvdata(dev); |
---|
1215 | | - struct tegra_drm *tegra = drm->dev_private; |
---|
1216 | 1287 | |
---|
1217 | | - drm_kms_helper_poll_disable(drm); |
---|
1218 | | - tegra_drm_fb_suspend(drm); |
---|
1219 | | - |
---|
1220 | | - tegra->state = drm_atomic_helper_suspend(drm); |
---|
1221 | | - if (IS_ERR(tegra->state)) { |
---|
1222 | | - tegra_drm_fb_resume(drm); |
---|
1223 | | - drm_kms_helper_poll_enable(drm); |
---|
1224 | | - return PTR_ERR(tegra->state); |
---|
1225 | | - } |
---|
1226 | | - |
---|
1227 | | - return 0; |
---|
| 1288 | + return drm_mode_config_helper_suspend(drm); |
---|
1228 | 1289 | } |
---|
1229 | 1290 | |
---|
1230 | 1291 | static int host1x_drm_resume(struct device *dev) |
---|
1231 | 1292 | { |
---|
1232 | 1293 | struct drm_device *drm = dev_get_drvdata(dev); |
---|
1233 | | - struct tegra_drm *tegra = drm->dev_private; |
---|
1234 | 1294 | |
---|
1235 | | - drm_atomic_helper_resume(drm, tegra->state); |
---|
1236 | | - tegra_drm_fb_resume(drm); |
---|
1237 | | - drm_kms_helper_poll_enable(drm); |
---|
1238 | | - |
---|
1239 | | - return 0; |
---|
| 1295 | + return drm_mode_config_helper_resume(drm); |
---|
1240 | 1296 | } |
---|
1241 | 1297 | #endif |
---|
1242 | 1298 | |
---|
.. | .. |
---|
1271 | 1327 | { .compatible = "nvidia,tegra186-sor", }, |
---|
1272 | 1328 | { .compatible = "nvidia,tegra186-sor1", }, |
---|
1273 | 1329 | { .compatible = "nvidia,tegra186-vic", }, |
---|
| 1330 | + { .compatible = "nvidia,tegra194-display", }, |
---|
| 1331 | + { .compatible = "nvidia,tegra194-dc", }, |
---|
| 1332 | + { .compatible = "nvidia,tegra194-sor", }, |
---|
| 1333 | + { .compatible = "nvidia,tegra194-vic", }, |
---|
1274 | 1334 | { /* sentinel */ } |
---|
1275 | 1335 | }; |
---|
1276 | 1336 | |
---|