]>
Commit | Line | Data |
---|---|---|
9952f691 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
75471687 TB |
2 | /* |
3 | * Tegra host1x driver | |
4 | * | |
5 | * Copyright (c) 2010-2013, NVIDIA Corporation. | |
75471687 TB |
6 | */ |
7 | ||
75471687 | 8 | #include <linux/clk.h> |
097452e6 | 9 | #include <linux/dma-mapping.h> |
7e7d432c TR |
10 | #include <linux/io.h> |
11 | #include <linux/list.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/of_device.h> | |
14 | #include <linux/of.h> | |
15 | #include <linux/slab.h> | |
75471687 TB |
16 | |
17 | #define CREATE_TRACE_POINTS | |
18 | #include <trace/events/host1x.h> | |
404bfb78 | 19 | #undef CREATE_TRACE_POINTS |
75471687 | 20 | |
776dc384 | 21 | #include "bus.h" |
6579324a | 22 | #include "channel.h" |
6236451d | 23 | #include "debug.h" |
7e7d432c TR |
24 | #include "dev.h" |
25 | #include "intr.h" | |
26 | ||
75471687 | 27 | #include "hw/host1x01.h" |
5407f31b | 28 | #include "hw/host1x02.h" |
e6fff4aa | 29 | #include "hw/host1x04.h" |
a134789a | 30 | #include "hw/host1x05.h" |
f1b53c4e | 31 | #include "hw/host1x06.h" |
ac1bdbf2 | 32 | #include "hw/host1x07.h" |
f1b53c4e MP |
33 | |
34 | void host1x_hypervisor_writel(struct host1x *host1x, u32 v, u32 r) | |
35 | { | |
36 | writel(v, host1x->hv_regs + r); | |
37 | } | |
38 | ||
39 | u32 host1x_hypervisor_readl(struct host1x *host1x, u32 r) | |
40 | { | |
41 | return readl(host1x->hv_regs + r); | |
42 | } | |
75471687 TB |
43 | |
44 | void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) | |
45 | { | |
46 | void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; | |
47 | ||
48 | writel(v, sync_regs + r); | |
49 | } | |
50 | ||
51 | u32 host1x_sync_readl(struct host1x *host1x, u32 r) | |
52 | { | |
53 | void __iomem *sync_regs = host1x->regs + host1x->info->sync_offset; | |
54 | ||
55 | return readl(sync_regs + r); | |
56 | } | |
57 | ||
6579324a TB |
58 | void host1x_ch_writel(struct host1x_channel *ch, u32 v, u32 r) |
59 | { | |
60 | writel(v, ch->regs + r); | |
61 | } | |
62 | ||
63 | u32 host1x_ch_readl(struct host1x_channel *ch, u32 r) | |
64 | { | |
65 | return readl(ch->regs + r); | |
66 | } | |
67 | ||
75471687 | 68 | static const struct host1x_info host1x01_info = { |
0b8070d1 TR |
69 | .nb_channels = 8, |
70 | .nb_pts = 32, | |
71 | .nb_mlocks = 16, | |
72 | .nb_bases = 8, | |
73 | .init = host1x01_init, | |
74 | .sync_offset = 0x3000, | |
75 | .dma_mask = DMA_BIT_MASK(32), | |
06867a36 | 76 | .has_wide_gather = false, |
8f45f507 TR |
77 | .has_hypervisor = false, |
78 | .num_sid_entries = 0, | |
79 | .sid_table = NULL, | |
75471687 TB |
80 | }; |
81 | ||
5407f31b TR |
82 | static const struct host1x_info host1x02_info = { |
83 | .nb_channels = 9, | |
84 | .nb_pts = 32, | |
85 | .nb_mlocks = 16, | |
86 | .nb_bases = 12, | |
87 | .init = host1x02_init, | |
88 | .sync_offset = 0x3000, | |
097452e6 | 89 | .dma_mask = DMA_BIT_MASK(32), |
06867a36 | 90 | .has_wide_gather = false, |
8f45f507 TR |
91 | .has_hypervisor = false, |
92 | .num_sid_entries = 0, | |
93 | .sid_table = NULL, | |
5407f31b TR |
94 | }; |
95 | ||
e6fff4aa TR |
96 | static const struct host1x_info host1x04_info = { |
97 | .nb_channels = 12, | |
98 | .nb_pts = 192, | |
99 | .nb_mlocks = 16, | |
100 | .nb_bases = 64, | |
101 | .init = host1x04_init, | |
102 | .sync_offset = 0x2100, | |
097452e6 | 103 | .dma_mask = DMA_BIT_MASK(34), |
06867a36 | 104 | .has_wide_gather = false, |
8f45f507 TR |
105 | .has_hypervisor = false, |
106 | .num_sid_entries = 0, | |
107 | .sid_table = NULL, | |
e6fff4aa TR |
108 | }; |
109 | ||
a134789a TR |
110 | static const struct host1x_info host1x05_info = { |
111 | .nb_channels = 14, | |
112 | .nb_pts = 192, | |
113 | .nb_mlocks = 16, | |
114 | .nb_bases = 64, | |
115 | .init = host1x05_init, | |
116 | .sync_offset = 0x2100, | |
097452e6 | 117 | .dma_mask = DMA_BIT_MASK(34), |
06867a36 | 118 | .has_wide_gather = false, |
8f45f507 TR |
119 | .has_hypervisor = false, |
120 | .num_sid_entries = 0, | |
121 | .sid_table = NULL, | |
a134789a TR |
122 | }; |
123 | ||
6841482b TR |
124 | static const struct host1x_sid_entry tegra186_sid_table[] = { |
125 | { | |
126 | /* VIC */ | |
127 | .base = 0x1af0, | |
128 | .offset = 0x30, | |
129 | .limit = 0x34 | |
130 | }, | |
131 | }; | |
132 | ||
f1b53c4e MP |
133 | static const struct host1x_info host1x06_info = { |
134 | .nb_channels = 63, | |
135 | .nb_pts = 576, | |
136 | .nb_mlocks = 24, | |
137 | .nb_bases = 16, | |
138 | .init = host1x06_init, | |
139 | .sync_offset = 0x0, | |
8de896eb | 140 | .dma_mask = DMA_BIT_MASK(40), |
06867a36 | 141 | .has_wide_gather = true, |
f1b53c4e | 142 | .has_hypervisor = true, |
6841482b TR |
143 | .num_sid_entries = ARRAY_SIZE(tegra186_sid_table), |
144 | .sid_table = tegra186_sid_table, | |
145 | }; | |
146 | ||
147 | static const struct host1x_sid_entry tegra194_sid_table[] = { | |
148 | { | |
149 | /* VIC */ | |
150 | .base = 0x1af0, | |
151 | .offset = 0x30, | |
152 | .limit = 0x34 | |
153 | }, | |
f1b53c4e MP |
154 | }; |
155 | ||
ac1bdbf2 TR |
156 | static const struct host1x_info host1x07_info = { |
157 | .nb_channels = 63, | |
158 | .nb_pts = 704, | |
159 | .nb_mlocks = 32, | |
160 | .nb_bases = 0, | |
161 | .init = host1x07_init, | |
162 | .sync_offset = 0x0, | |
163 | .dma_mask = DMA_BIT_MASK(40), | |
06867a36 | 164 | .has_wide_gather = true, |
ac1bdbf2 | 165 | .has_hypervisor = true, |
6841482b TR |
166 | .num_sid_entries = ARRAY_SIZE(tegra194_sid_table), |
167 | .sid_table = tegra194_sid_table, | |
ac1bdbf2 TR |
168 | }; |
169 | ||
6df633d0 | 170 | static const struct of_device_id host1x_of_match[] = { |
ac1bdbf2 | 171 | { .compatible = "nvidia,tegra194-host1x", .data = &host1x07_info, }, |
f1b53c4e | 172 | { .compatible = "nvidia,tegra186-host1x", .data = &host1x06_info, }, |
a134789a | 173 | { .compatible = "nvidia,tegra210-host1x", .data = &host1x05_info, }, |
e6fff4aa | 174 | { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, |
5407f31b | 175 | { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, |
75471687 TB |
176 | { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, |
177 | { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, | |
178 | { }, | |
179 | }; | |
180 | MODULE_DEVICE_TABLE(of, host1x_of_match); | |
181 | ||
6841482b TR |
182 | static void host1x_setup_sid_table(struct host1x *host) |
183 | { | |
184 | const struct host1x_info *info = host->info; | |
185 | unsigned int i; | |
186 | ||
187 | for (i = 0; i < info->num_sid_entries; i++) { | |
188 | const struct host1x_sid_entry *entry = &info->sid_table[i]; | |
189 | ||
190 | host1x_hypervisor_writel(host, entry->offset, entry->base); | |
191 | host1x_hypervisor_writel(host, entry->limit, entry->base + 4); | |
192 | } | |
193 | } | |
194 | ||
4010e729 TR |
195 | static bool host1x_wants_iommu(struct host1x *host1x) |
196 | { | |
197 | /* | |
198 | * If we support addressing a maximum of 32 bits of physical memory | |
199 | * and if the host1x firewall is enabled, there's no need to enable | |
200 | * IOMMU support. This can happen for example on Tegra20, Tegra30 | |
201 | * and Tegra114. | |
202 | * | |
203 | * Tegra124 and later can address up to 34 bits of physical memory and | |
204 | * many platforms come equipped with more than 2 GiB of system memory, | |
205 | * which requires crossing the 4 GiB boundary. But there's a catch: on | |
206 | * SoCs before Tegra186 (i.e. Tegra124 and Tegra210), the host1x can | |
207 | * only address up to 32 bits of memory in GATHER opcodes, which means | |
208 | * that command buffers need to either be in the first 2 GiB of system | |
209 | * memory (which could quickly lead to memory exhaustion), or command | |
210 | * buffers need to be treated differently from other buffers (which is | |
211 | * not possible with the current ABI). | |
212 | * | |
213 | * A third option is to use the IOMMU in these cases to make sure all | |
214 | * buffers will be mapped into a 32-bit IOVA space that host1x can | |
215 | * address. This allows all of the system memory to be used and works | |
216 | * within the limitations of the host1x on these SoCs. | |
217 | * | |
218 | * In summary, default to enable IOMMU on Tegra124 and later. For any | |
219 | * of the earlier SoCs, only use the IOMMU for additional safety when | |
220 | * the host1x firewall is disabled. | |
221 | */ | |
222 | if (host1x->info->dma_mask <= DMA_BIT_MASK(32)) { | |
223 | if (IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL)) | |
224 | return false; | |
225 | } | |
226 | ||
227 | return true; | |
228 | } | |
229 | ||
06867a36 TR |
230 | static struct iommu_domain *host1x_iommu_attach(struct host1x *host) |
231 | { | |
232 | struct iommu_domain *domain = iommu_get_domain_for_dev(host->dev); | |
233 | int err; | |
234 | ||
235 | /* | |
4010e729 TR |
236 | * We may not always want to enable IOMMU support (for example if the |
237 | * host1x firewall is already enabled and we don't support addressing | |
238 | * more than 32 bits of physical memory), so check for that first. | |
239 | * | |
240 | * Similarly, if host1x is already attached to an IOMMU (via the DMA | |
241 | * API), don't try to attach again. | |
06867a36 | 242 | */ |
4010e729 | 243 | if (!host1x_wants_iommu(host) || domain) |
06867a36 TR |
244 | return domain; |
245 | ||
246 | host->group = iommu_group_get(host->dev); | |
247 | if (host->group) { | |
248 | struct iommu_domain_geometry *geometry; | |
249 | dma_addr_t start, end; | |
250 | unsigned long order; | |
251 | ||
252 | err = iova_cache_get(); | |
253 | if (err < 0) | |
254 | goto put_group; | |
255 | ||
256 | host->domain = iommu_domain_alloc(&platform_bus_type); | |
257 | if (!host->domain) { | |
258 | err = -ENOMEM; | |
259 | goto put_cache; | |
260 | } | |
261 | ||
262 | err = iommu_attach_group(host->domain, host->group); | |
263 | if (err) { | |
264 | if (err == -ENODEV) | |
265 | err = 0; | |
266 | ||
267 | goto free_domain; | |
268 | } | |
269 | ||
270 | geometry = &host->domain->geometry; | |
271 | start = geometry->aperture_start & host->info->dma_mask; | |
272 | end = geometry->aperture_end & host->info->dma_mask; | |
273 | ||
274 | order = __ffs(host->domain->pgsize_bitmap); | |
275 | init_iova_domain(&host->iova, 1UL << order, start >> order); | |
276 | host->iova_end = end; | |
277 | ||
278 | domain = host->domain; | |
279 | } | |
280 | ||
281 | return domain; | |
282 | ||
283 | free_domain: | |
284 | iommu_domain_free(host->domain); | |
285 | host->domain = NULL; | |
286 | put_cache: | |
287 | iova_cache_put(); | |
288 | put_group: | |
289 | iommu_group_put(host->group); | |
290 | host->group = NULL; | |
291 | ||
292 | return ERR_PTR(err); | |
293 | } | |
294 | ||
295 | static int host1x_iommu_init(struct host1x *host) | |
296 | { | |
297 | u64 mask = host->info->dma_mask; | |
298 | struct iommu_domain *domain; | |
299 | int err; | |
300 | ||
301 | domain = host1x_iommu_attach(host); | |
302 | if (IS_ERR(domain)) { | |
303 | err = PTR_ERR(domain); | |
304 | dev_err(host->dev, "failed to attach to IOMMU: %d\n", err); | |
305 | return err; | |
306 | } | |
307 | ||
308 | /* | |
309 | * If we're not behind an IOMMU make sure we don't get push buffers | |
310 | * that are allocated outside of the range addressable by the GATHER | |
311 | * opcode. | |
312 | * | |
313 | * Newer generations of Tegra (Tegra186 and later) support a wide | |
314 | * variant of the GATHER opcode that allows addressing more bits. | |
315 | */ | |
316 | if (!domain && !host->info->has_wide_gather) | |
317 | mask = DMA_BIT_MASK(32); | |
318 | ||
319 | err = dma_coerce_mask_and_coherent(host->dev, mask); | |
320 | if (err < 0) { | |
321 | dev_err(host->dev, "failed to set DMA mask: %d\n", err); | |
322 | return err; | |
323 | } | |
324 | ||
325 | return 0; | |
326 | } | |
327 | ||
328 | static void host1x_iommu_exit(struct host1x *host) | |
329 | { | |
330 | if (host->domain) { | |
331 | put_iova_domain(&host->iova); | |
332 | iommu_detach_group(host->domain, host->group); | |
333 | ||
334 | iommu_domain_free(host->domain); | |
335 | host->domain = NULL; | |
336 | ||
337 | iova_cache_put(); | |
338 | ||
339 | iommu_group_put(host->group); | |
340 | host->group = NULL; | |
341 | } | |
342 | } | |
343 | ||
75471687 TB |
344 | static int host1x_probe(struct platform_device *pdev) |
345 | { | |
75471687 | 346 | struct host1x *host; |
f1b53c4e | 347 | struct resource *regs, *hv_regs = NULL; |
75471687 TB |
348 | int syncpt_irq; |
349 | int err; | |
350 | ||
6a341fdf TR |
351 | host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); |
352 | if (!host) | |
353 | return -ENOMEM; | |
75471687 | 354 | |
6a341fdf | 355 | host->info = of_device_get_match_data(&pdev->dev); |
75471687 | 356 | |
f1b53c4e MP |
357 | if (host->info->has_hypervisor) { |
358 | regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vm"); | |
359 | if (!regs) { | |
360 | dev_err(&pdev->dev, "failed to get vm registers\n"); | |
361 | return -ENXIO; | |
362 | } | |
363 | ||
364 | hv_regs = platform_get_resource_byname(pdev, IORESOURCE_MEM, | |
365 | "hypervisor"); | |
366 | if (!hv_regs) { | |
367 | dev_err(&pdev->dev, | |
368 | "failed to get hypervisor registers\n"); | |
369 | return -ENXIO; | |
370 | } | |
371 | } else { | |
372 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
373 | if (!regs) { | |
374 | dev_err(&pdev->dev, "failed to get registers\n"); | |
375 | return -ENXIO; | |
376 | } | |
75471687 TB |
377 | } |
378 | ||
379 | syncpt_irq = platform_get_irq(pdev, 0); | |
033ccdb7 | 380 | if (syncpt_irq < 0) |
7b2c63de | 381 | return syncpt_irq; |
75471687 | 382 | |
776dc384 TR |
383 | mutex_init(&host->devices_lock); |
384 | INIT_LIST_HEAD(&host->devices); | |
385 | INIT_LIST_HEAD(&host->list); | |
75471687 | 386 | host->dev = &pdev->dev; |
75471687 TB |
387 | |
388 | /* set common host1x device data */ | |
389 | platform_set_drvdata(pdev, host); | |
390 | ||
391 | host->regs = devm_ioremap_resource(&pdev->dev, regs); | |
392 | if (IS_ERR(host->regs)) | |
393 | return PTR_ERR(host->regs); | |
394 | ||
f1b53c4e MP |
395 | if (host->info->has_hypervisor) { |
396 | host->hv_regs = devm_ioremap_resource(&pdev->dev, hv_regs); | |
397 | if (IS_ERR(host->hv_regs)) | |
398 | return PTR_ERR(host->hv_regs); | |
399 | } | |
400 | ||
d98914eb TR |
401 | host->dev->dma_parms = &host->dma_parms; |
402 | dma_set_max_seg_size(host->dev, UINT_MAX); | |
403 | ||
75471687 TB |
404 | if (host->info->init) { |
405 | err = host->info->init(host); | |
406 | if (err) | |
407 | return err; | |
408 | } | |
409 | ||
410 | host->clk = devm_clk_get(&pdev->dev, NULL); | |
411 | if (IS_ERR(host->clk)) { | |
75471687 | 412 | err = PTR_ERR(host->clk); |
4bb923e8 TR |
413 | |
414 | if (err != -EPROBE_DEFER) | |
415 | dev_err(&pdev->dev, "failed to get clock: %d\n", err); | |
416 | ||
75471687 TB |
417 | return err; |
418 | } | |
419 | ||
b386c6b7 TR |
420 | host->rst = devm_reset_control_get(&pdev->dev, "host1x"); |
421 | if (IS_ERR(host->rst)) { | |
59e04bc2 | 422 | err = PTR_ERR(host->rst); |
b386c6b7 TR |
423 | dev_err(&pdev->dev, "failed to get reset: %d\n", err); |
424 | return err; | |
425 | } | |
af1cbfb9 | 426 | |
06867a36 TR |
427 | err = host1x_iommu_init(host); |
428 | if (err < 0) { | |
429 | dev_err(&pdev->dev, "failed to setup IOMMU: %d\n", err); | |
430 | return err; | |
404bfb78 MP |
431 | } |
432 | ||
8474b025 MP |
433 | err = host1x_channel_list_init(&host->channel_list, |
434 | host->info->nb_channels); | |
6579324a TB |
435 | if (err) { |
436 | dev_err(&pdev->dev, "failed to initialize channel list\n"); | |
06867a36 | 437 | goto iommu_exit; |
6579324a TB |
438 | } |
439 | ||
75471687 TB |
440 | err = clk_prepare_enable(host->clk); |
441 | if (err < 0) { | |
442 | dev_err(&pdev->dev, "failed to enable clock\n"); | |
06867a36 | 443 | goto free_channels; |
75471687 TB |
444 | } |
445 | ||
b386c6b7 TR |
446 | err = reset_control_deassert(host->rst); |
447 | if (err < 0) { | |
448 | dev_err(&pdev->dev, "failed to deassert reset: %d\n", err); | |
06867a36 | 449 | goto unprepare_disable; |
b386c6b7 TR |
450 | } |
451 | ||
75471687 TB |
452 | err = host1x_syncpt_init(host); |
453 | if (err) { | |
454 | dev_err(&pdev->dev, "failed to initialize syncpts\n"); | |
06867a36 | 455 | goto reset_assert; |
75471687 TB |
456 | } |
457 | ||
7ede0b0b TB |
458 | err = host1x_intr_init(host, syncpt_irq); |
459 | if (err) { | |
460 | dev_err(&pdev->dev, "failed to initialize interrupts\n"); | |
06867a36 | 461 | goto deinit_syncpt; |
7ede0b0b TB |
462 | } |
463 | ||
6236451d TB |
464 | host1x_debug_init(host); |
465 | ||
6841482b TR |
466 | if (host->info->has_hypervisor) |
467 | host1x_setup_sid_table(host); | |
468 | ||
776dc384 TR |
469 | err = host1x_register(host); |
470 | if (err < 0) | |
06867a36 | 471 | goto deinit_intr; |
692e6d7b | 472 | |
75471687 | 473 | return 0; |
7ede0b0b | 474 | |
06867a36 | 475 | deinit_intr: |
776dc384 | 476 | host1x_intr_deinit(host); |
06867a36 | 477 | deinit_syncpt: |
7ede0b0b | 478 | host1x_syncpt_deinit(host); |
06867a36 | 479 | reset_assert: |
b386c6b7 | 480 | reset_control_assert(host->rst); |
06867a36 | 481 | unprepare_disable: |
9c78c4c3 | 482 | clk_disable_unprepare(host->clk); |
06867a36 | 483 | free_channels: |
8474b025 | 484 | host1x_channel_list_free(&host->channel_list); |
06867a36 TR |
485 | iommu_exit: |
486 | host1x_iommu_exit(host); | |
404bfb78 | 487 | |
7ede0b0b | 488 | return err; |
75471687 TB |
489 | } |
490 | ||
452e7f0c | 491 | static int host1x_remove(struct platform_device *pdev) |
75471687 TB |
492 | { |
493 | struct host1x *host = platform_get_drvdata(pdev); | |
494 | ||
776dc384 | 495 | host1x_unregister(host); |
44156eee | 496 | host1x_debug_deinit(host); |
7ede0b0b | 497 | host1x_intr_deinit(host); |
75471687 | 498 | host1x_syncpt_deinit(host); |
b386c6b7 | 499 | reset_control_assert(host->rst); |
75471687 | 500 | clk_disable_unprepare(host->clk); |
06867a36 | 501 | host1x_iommu_exit(host); |
404bfb78 | 502 | |
75471687 TB |
503 | return 0; |
504 | } | |
505 | ||
692e6d7b | 506 | static struct platform_driver tegra_host1x_driver = { |
75471687 | 507 | .driver = { |
75471687 TB |
508 | .name = "tegra-host1x", |
509 | .of_match_table = host1x_of_match, | |
510 | }, | |
452e7f0c TR |
511 | .probe = host1x_probe, |
512 | .remove = host1x_remove, | |
75471687 TB |
513 | }; |
514 | ||
28fae81f TR |
515 | static struct platform_driver * const drivers[] = { |
516 | &tegra_host1x_driver, | |
517 | &tegra_mipi_driver, | |
518 | }; | |
519 | ||
692e6d7b TB |
520 | static int __init tegra_host1x_init(void) |
521 | { | |
522 | int err; | |
523 | ||
f4c5cf88 | 524 | err = bus_register(&host1x_bus_type); |
692e6d7b TB |
525 | if (err < 0) |
526 | return err; | |
527 | ||
28fae81f | 528 | err = platform_register_drivers(drivers, ARRAY_SIZE(drivers)); |
4de6a2d6 | 529 | if (err < 0) |
28fae81f | 530 | bus_unregister(&host1x_bus_type); |
692e6d7b | 531 | |
4de6a2d6 | 532 | return err; |
692e6d7b TB |
533 | } |
534 | module_init(tegra_host1x_init); | |
535 | ||
536 | static void __exit tegra_host1x_exit(void) | |
537 | { | |
28fae81f | 538 | platform_unregister_drivers(drivers, ARRAY_SIZE(drivers)); |
f4c5cf88 | 539 | bus_unregister(&host1x_bus_type); |
692e6d7b TB |
540 | } |
541 | module_exit(tegra_host1x_exit); | |
75471687 | 542 | |
501be6c1 TR |
543 | /** |
544 | * host1x_get_dma_mask() - query the supported DMA mask for host1x | |
545 | * @host1x: host1x instance | |
546 | * | |
547 | * Note that this returns the supported DMA mask for host1x, which can be | |
548 | * different from the applicable DMA mask under certain circumstances. | |
549 | */ | |
550 | u64 host1x_get_dma_mask(struct host1x *host1x) | |
551 | { | |
552 | return host1x->info->dma_mask; | |
553 | } | |
554 | EXPORT_SYMBOL(host1x_get_dma_mask); | |
555 | ||
692e6d7b | 556 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); |
75471687 TB |
557 | MODULE_AUTHOR("Terje Bergstrom <tbergstrom@nvidia.com>"); |
558 | MODULE_DESCRIPTION("Host1x driver for Tegra products"); | |
559 | MODULE_LICENSE("GPL"); |