aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-05-04 21:47:01 -0400
committerDave Airlie <airlied@redhat.com>2017-05-04 21:47:01 -0400
commit644b4930bf7e2adeffbe842e1097f7933c6a9158 (patch)
treedcb9e56d30af9b590c511f89b0b6815dd67321e6
parent8b03d1ed2c43a2ba5ef3381322ee4515b97381bf (diff)
parentb0d36daa0ab54714e05164f6e21d22f974a5eec1 (diff)
Merge tag 'drm/tegra/for-4.12-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.12-rc1 This contains various fixes to the host1x driver as well as a plug for a leak of kernel pointers to userspace. A fairly big addition this time around is the Video Image Composer (VIC) support that can be used to accelerate some 2D and image compositing operations. Furthermore the driver now supports FB modifiers, so we no longer rely on a custom IOCTL to set those. Finally this contains a few preparatory patches for Tegra186 support which unfortunately didn't quite make it this time, but will hopefully be ready for v4.13. * tag 'drm/tegra/for-4.12-rc1' of git://anongit.freedesktop.org/tegra/linux: gpu: host1x: Fix host1x driver shutdown gpu: host1x: Support module reset gpu: host1x: Sort includes alphabetically drm/tegra: Add VIC support dt-bindings: Add bindings for the Tegra VIC drm/tegra: Add falcon helper library drm/tegra: Add Tegra DRM allocation API drm/tegra: Add tiling FB modifiers drm/tegra: Don't leak kernel pointer to userspace drm/tegra: Protect IOMMU operations by mutex drm/tegra: Enable IOVA API when IOMMU support is enabled gpu: host1x: Add IOMMU support gpu: host1x: Fix potential out-of-bounds access iommu/iova: Fix compile error with CONFIG_IOMMU_IOVA=m iommu: Add dummy implementations for !IOMMU_IOVA MAINTAINERS: Add related headers to IOMMU section iommu/iova: Consolidate code for adding new node to iovad domain rbtree
-rw-r--r--Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt13
-rw-r--r--MAINTAINERS2
-rw-r--r--drivers/gpu/drm/tegra/Kconfig1
-rw-r--r--drivers/gpu/drm/tegra/Makefile4
-rw-r--r--drivers/gpu/drm/tegra/drm.c283
-rw-r--r--drivers/gpu/drm/tegra/drm.h15
-rw-r--r--drivers/gpu/drm/tegra/falcon.c259
-rw-r--r--drivers/gpu/drm/tegra/falcon.h127
-rw-r--r--drivers/gpu/drm/tegra/fb.c23
-rw-r--r--drivers/gpu/drm/tegra/gem.c12
-rw-r--r--drivers/gpu/drm/tegra/vic.c396
-rw-r--r--drivers/gpu/drm/tegra/vic.h31
-rw-r--r--drivers/gpu/host1x/bus.c68
-rw-r--r--drivers/gpu/host1x/cdma.c74
-rw-r--r--drivers/gpu/host1x/cdma.h6
-rw-r--r--drivers/gpu/host1x/dev.c76
-rw-r--r--drivers/gpu/host1x/dev.h14
-rw-r--r--drivers/gpu/host1x/hw/cdma_hw.c16
-rw-r--r--drivers/gpu/host1x/job.c72
-rw-r--r--drivers/gpu/host1x/job.h1
-rw-r--r--drivers/gpu/host1x/syncpt.c2
-rw-r--r--drivers/iommu/iova.c87
-rw-r--r--include/linux/host1x.h1
-rw-r--r--include/linux/iova.h91
-rw-r--r--include/uapi/drm/drm_fourcc.h45
25 files changed, 1517 insertions, 202 deletions
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
index 0fad7ed2ea19..74e1e8add5a1 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-host1x.txt
@@ -249,6 +249,19 @@ of the following host1x client modules:
249 See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information 249 See ../pinctrl/nvidia,tegra124-dpaux-padctl.txt for information
250 regarding the DPAUX pad controller bindings. 250 regarding the DPAUX pad controller bindings.
251 251
252- vic: Video Image Compositor
253 - compatible : "nvidia,tegra<chip>-vic"
254 - reg: Physical base address and length of the controller's registers.
255 - interrupts: The interrupt outputs from the controller.
256 - clocks: Must contain an entry for each entry in clock-names.
257 See ../clocks/clock-bindings.txt for details.
258 - clock-names: Must include the following entries:
259 - vic: clock input for the VIC hardware
260 - resets: Must contain an entry for each entry in reset-names.
261 See ../reset/reset.txt for details.
262 - reset-names: Must include the following entries:
263 - vic
264
252Example: 265Example:
253 266
254/ { 267/ {
diff --git a/MAINTAINERS b/MAINTAINERS
index 66f5b55d205a..ed22fc407635 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -6780,6 +6780,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git
6780S: Maintained 6780S: Maintained
6781F: Documentation/devicetree/bindings/iommu/ 6781F: Documentation/devicetree/bindings/iommu/
6782F: drivers/iommu/ 6782F: drivers/iommu/
6783F: include/linux/iommu.h
6784F: include/linux/iova.h
6783 6785
6784IP MASQUERADING 6786IP MASQUERADING
6785M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar> 6787M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index bbf5a4b7e0b6..2db29d67193d 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -7,6 +7,7 @@ config DRM_TEGRA
7 select DRM_MIPI_DSI 7 select DRM_MIPI_DSI
8 select DRM_PANEL 8 select DRM_PANEL
9 select TEGRA_HOST1X 9 select TEGRA_HOST1X
10 select IOMMU_IOVA if IOMMU_SUPPORT
10 help 11 help
11 Choose this option if you have an NVIDIA Tegra SoC. 12 Choose this option if you have an NVIDIA Tegra SoC.
12 13
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index 2c66a8db9da4..6af3a9ad6565 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -13,6 +13,8 @@ tegra-drm-y := \
13 sor.o \ 13 sor.o \
14 dpaux.o \ 14 dpaux.o \
15 gr2d.o \ 15 gr2d.o \
16 gr3d.o 16 gr3d.o \
17 falcon.o \
18 vic.o
17 19
18obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o 20obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index dba4e090d3df..9a1e34e48f64 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -1,13 +1,15 @@
1/* 1/*
2 * Copyright (C) 2012 Avionic Design GmbH 2 * Copyright (C) 2012 Avionic Design GmbH
3 * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. 3 * Copyright (C) 2012-2016 NVIDIA CORPORATION. All rights reserved.
4 * 4 *
5 * This program is free software; you can redistribute it and/or modify 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 6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 */ 8 */
9 9
10#include <linux/bitops.h>
10#include <linux/host1x.h> 11#include <linux/host1x.h>
12#include <linux/idr.h>
11#include <linux/iommu.h> 13#include <linux/iommu.h>
12 14
13#include <drm/drm_atomic.h> 15#include <drm/drm_atomic.h>
@@ -23,8 +25,11 @@
23#define DRIVER_MINOR 0 25#define DRIVER_MINOR 0
24#define DRIVER_PATCHLEVEL 0 26#define DRIVER_PATCHLEVEL 0
25 27
28#define CARVEOUT_SZ SZ_64M
29
26struct tegra_drm_file { 30struct tegra_drm_file {
27 struct list_head contexts; 31 struct idr contexts;
32 struct mutex lock;
28}; 33};
29 34
30static void tegra_atomic_schedule(struct tegra_drm *tegra, 35static void tegra_atomic_schedule(struct tegra_drm *tegra,
@@ -126,8 +131,9 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
126 return -ENOMEM; 131 return -ENOMEM;
127 132
128 if (iommu_present(&platform_bus_type)) { 133 if (iommu_present(&platform_bus_type)) {
134 u64 carveout_start, carveout_end, gem_start, gem_end;
129 struct iommu_domain_geometry *geometry; 135 struct iommu_domain_geometry *geometry;
130 u64 start, end; 136 unsigned long order;
131 137
132 tegra->domain = iommu_domain_alloc(&platform_bus_type); 138 tegra->domain = iommu_domain_alloc(&platform_bus_type);
133 if (!tegra->domain) { 139 if (!tegra->domain) {
@@ -136,12 +142,26 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
136 } 142 }
137 143
138 geometry = &tegra->domain->geometry; 144 geometry = &tegra->domain->geometry;
139 start = geometry->aperture_start; 145 gem_start = geometry->aperture_start;
140 end = geometry->aperture_end; 146 gem_end = geometry->aperture_end - CARVEOUT_SZ;
141 147 carveout_start = gem_end + 1;
142 DRM_DEBUG_DRIVER("IOMMU aperture initialized (%#llx-%#llx)\n", 148 carveout_end = geometry->aperture_end;
143 start, end); 149
144 drm_mm_init(&tegra->mm, start, end - start + 1); 150 order = __ffs(tegra->domain->pgsize_bitmap);
151 init_iova_domain(&tegra->carveout.domain, 1UL << order,
152 carveout_start >> order,
153 carveout_end >> order);
154
155 tegra->carveout.shift = iova_shift(&tegra->carveout.domain);
156 tegra->carveout.limit = carveout_end >> tegra->carveout.shift;
157
158 drm_mm_init(&tegra->mm, gem_start, gem_end - gem_start + 1);
159 mutex_init(&tegra->mm_lock);
160
161 DRM_DEBUG("IOMMU apertures:\n");
162 DRM_DEBUG(" GEM: %#llx-%#llx\n", gem_start, gem_end);
163 DRM_DEBUG(" Carveout: %#llx-%#llx\n", carveout_start,
164 carveout_end);
145 } 165 }
146 166
147 mutex_init(&tegra->clients_lock); 167 mutex_init(&tegra->clients_lock);
@@ -161,6 +181,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
161 drm->mode_config.max_width = 4096; 181 drm->mode_config.max_width = 4096;
162 drm->mode_config.max_height = 4096; 182 drm->mode_config.max_height = 4096;
163 183
184 drm->mode_config.allow_fb_modifiers = true;
185
164 drm->mode_config.funcs = &tegra_drm_mode_funcs; 186 drm->mode_config.funcs = &tegra_drm_mode_funcs;
165 187
166 err = tegra_drm_fb_prepare(drm); 188 err = tegra_drm_fb_prepare(drm);
@@ -208,6 +230,8 @@ config:
208 if (tegra->domain) { 230 if (tegra->domain) {
209 iommu_domain_free(tegra->domain); 231 iommu_domain_free(tegra->domain);
210 drm_mm_takedown(&tegra->mm); 232 drm_mm_takedown(&tegra->mm);
233 mutex_destroy(&tegra->mm_lock);
234 put_iova_domain(&tegra->carveout.domain);
211 } 235 }
212free: 236free:
213 kfree(tegra); 237 kfree(tegra);
@@ -232,6 +256,8 @@ static void tegra_drm_unload(struct drm_device *drm)
232 if (tegra->domain) { 256 if (tegra->domain) {
233 iommu_domain_free(tegra->domain); 257 iommu_domain_free(tegra->domain);
234 drm_mm_takedown(&tegra->mm); 258 drm_mm_takedown(&tegra->mm);
259 mutex_destroy(&tegra->mm_lock);
260 put_iova_domain(&tegra->carveout.domain);
235 } 261 }
236 262
237 kfree(tegra); 263 kfree(tegra);
@@ -245,7 +271,8 @@ static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp)
245 if (!fpriv) 271 if (!fpriv)
246 return -ENOMEM; 272 return -ENOMEM;
247 273
248 INIT_LIST_HEAD(&fpriv->contexts); 274 idr_init(&fpriv->contexts);
275 mutex_init(&fpriv->lock);
249 filp->driver_priv = fpriv; 276 filp->driver_priv = fpriv;
250 277
251 return 0; 278 return 0;
@@ -424,21 +451,16 @@ fail:
424 451
425 452
426#ifdef CONFIG_DRM_TEGRA_STAGING 453#ifdef CONFIG_DRM_TEGRA_STAGING
427static struct tegra_drm_context *tegra_drm_get_context(__u64 context) 454static struct tegra_drm_context *
428{ 455tegra_drm_file_get_context(struct tegra_drm_file *file, u32 id)
429 return (struct tegra_drm_context *)(uintptr_t)context;
430}
431
432static bool tegra_drm_file_owns_context(struct tegra_drm_file *file,
433 struct tegra_drm_context *context)
434{ 456{
435 struct tegra_drm_context *ctx; 457 struct tegra_drm_context *context;
436 458
437 list_for_each_entry(ctx, &file->contexts, list) 459 mutex_lock(&file->lock);
438 if (ctx == context) 460 context = idr_find(&file->contexts, id);
439 return true; 461 mutex_unlock(&file->lock);
440 462
441 return false; 463 return context;
442} 464}
443 465
444static int tegra_gem_create(struct drm_device *drm, void *data, 466static int tegra_gem_create(struct drm_device *drm, void *data,
@@ -519,6 +541,28 @@ static int tegra_syncpt_wait(struct drm_device *drm, void *data,
519 &args->value); 541 &args->value);
520} 542}
521 543
544static int tegra_client_open(struct tegra_drm_file *fpriv,
545 struct tegra_drm_client *client,
546 struct tegra_drm_context *context)
547{
548 int err;
549
550 err = client->ops->open_channel(client, context);
551 if (err < 0)
552 return err;
553
554 err = idr_alloc(&fpriv->contexts, context, 0, 0, GFP_KERNEL);
555 if (err < 0) {
556 client->ops->close_channel(context);
557 return err;
558 }
559
560 context->client = client;
561 context->id = err;
562
563 return 0;
564}
565
522static int tegra_open_channel(struct drm_device *drm, void *data, 566static int tegra_open_channel(struct drm_device *drm, void *data,
523 struct drm_file *file) 567 struct drm_file *file)
524{ 568{
@@ -533,19 +577,22 @@ static int tegra_open_channel(struct drm_device *drm, void *data,
533 if (!context) 577 if (!context)
534 return -ENOMEM; 578 return -ENOMEM;
535 579
580 mutex_lock(&fpriv->lock);
581
536 list_for_each_entry(client, &tegra->clients, list) 582 list_for_each_entry(client, &tegra->clients, list)
537 if (client->base.class == args->client) { 583 if (client->base.class == args->client) {
538 err = client->ops->open_channel(client, context); 584 err = tegra_client_open(fpriv, client, context);
539 if (err) 585 if (err < 0)
540 break; 586 break;
541 587
542 list_add(&context->list, &fpriv->contexts); 588 args->context = context->id;
543 args->context = (uintptr_t)context; 589 break;
544 context->client = client;
545 return 0;
546 } 590 }
547 591
548 kfree(context); 592 if (err < 0)
593 kfree(context);
594
595 mutex_unlock(&fpriv->lock);
549 return err; 596 return err;
550} 597}
551 598
@@ -555,16 +602,22 @@ static int tegra_close_channel(struct drm_device *drm, void *data,
555 struct tegra_drm_file *fpriv = file->driver_priv; 602 struct tegra_drm_file *fpriv = file->driver_priv;
556 struct drm_tegra_close_channel *args = data; 603 struct drm_tegra_close_channel *args = data;
557 struct tegra_drm_context *context; 604 struct tegra_drm_context *context;
605 int err = 0;
558 606
559 context = tegra_drm_get_context(args->context); 607 mutex_lock(&fpriv->lock);
560 608
561 if (!tegra_drm_file_owns_context(fpriv, context)) 609 context = tegra_drm_file_get_context(fpriv, args->context);
562 return -EINVAL; 610 if (!context) {
611 err = -EINVAL;
612 goto unlock;
613 }
563 614
564 list_del(&context->list); 615 idr_remove(&fpriv->contexts, context->id);
565 tegra_drm_context_free(context); 616 tegra_drm_context_free(context);
566 617
567 return 0; 618unlock:
619 mutex_unlock(&fpriv->lock);
620 return err;
568} 621}
569 622
570static int tegra_get_syncpt(struct drm_device *drm, void *data, 623static int tegra_get_syncpt(struct drm_device *drm, void *data,
@@ -574,19 +627,27 @@ static int tegra_get_syncpt(struct drm_device *drm, void *data,
574 struct drm_tegra_get_syncpt *args = data; 627 struct drm_tegra_get_syncpt *args = data;
575 struct tegra_drm_context *context; 628 struct tegra_drm_context *context;
576 struct host1x_syncpt *syncpt; 629 struct host1x_syncpt *syncpt;
630 int err = 0;
577 631
578 context = tegra_drm_get_context(args->context); 632 mutex_lock(&fpriv->lock);
579 633
580 if (!tegra_drm_file_owns_context(fpriv, context)) 634 context = tegra_drm_file_get_context(fpriv, args->context);
581 return -ENODEV; 635 if (!context) {
636 err = -ENODEV;
637 goto unlock;
638 }
582 639
583 if (args->index >= context->client->base.num_syncpts) 640 if (args->index >= context->client->base.num_syncpts) {
584 return -EINVAL; 641 err = -EINVAL;
642 goto unlock;
643 }
585 644
586 syncpt = context->client->base.syncpts[args->index]; 645 syncpt = context->client->base.syncpts[args->index];
587 args->id = host1x_syncpt_id(syncpt); 646 args->id = host1x_syncpt_id(syncpt);
588 647
589 return 0; 648unlock:
649 mutex_unlock(&fpriv->lock);
650 return err;
590} 651}
591 652
592static int tegra_submit(struct drm_device *drm, void *data, 653static int tegra_submit(struct drm_device *drm, void *data,
@@ -595,13 +656,21 @@ static int tegra_submit(struct drm_device *drm, void *data,
595 struct tegra_drm_file *fpriv = file->driver_priv; 656 struct tegra_drm_file *fpriv = file->driver_priv;
596 struct drm_tegra_submit *args = data; 657 struct drm_tegra_submit *args = data;
597 struct tegra_drm_context *context; 658 struct tegra_drm_context *context;
659 int err;
598 660
599 context = tegra_drm_get_context(args->context); 661 mutex_lock(&fpriv->lock);
662
663 context = tegra_drm_file_get_context(fpriv, args->context);
664 if (!context) {
665 err = -ENODEV;
666 goto unlock;
667 }
600 668
601 if (!tegra_drm_file_owns_context(fpriv, context)) 669 err = context->client->ops->submit(context, args, drm, file);
602 return -ENODEV;
603 670
604 return context->client->ops->submit(context, args, drm, file); 671unlock:
672 mutex_unlock(&fpriv->lock);
673 return err;
605} 674}
606 675
607static int tegra_get_syncpt_base(struct drm_device *drm, void *data, 676static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
@@ -612,24 +681,34 @@ static int tegra_get_syncpt_base(struct drm_device *drm, void *data,
612 struct tegra_drm_context *context; 681 struct tegra_drm_context *context;
613 struct host1x_syncpt_base *base; 682 struct host1x_syncpt_base *base;
614 struct host1x_syncpt *syncpt; 683 struct host1x_syncpt *syncpt;
684 int err = 0;
615 685
616 context = tegra_drm_get_context(args->context); 686 mutex_lock(&fpriv->lock);
617 687
618 if (!tegra_drm_file_owns_context(fpriv, context)) 688 context = tegra_drm_file_get_context(fpriv, args->context);
619 return -ENODEV; 689 if (!context) {
690 err = -ENODEV;
691 goto unlock;
692 }
620 693
621 if (args->syncpt >= context->client->base.num_syncpts) 694 if (args->syncpt >= context->client->base.num_syncpts) {
622 return -EINVAL; 695 err = -EINVAL;
696 goto unlock;
697 }
623 698
624 syncpt = context->client->base.syncpts[args->syncpt]; 699 syncpt = context->client->base.syncpts[args->syncpt];
625 700
626 base = host1x_syncpt_get_base(syncpt); 701 base = host1x_syncpt_get_base(syncpt);
627 if (!base) 702 if (!base) {
628 return -ENXIO; 703 err = -ENXIO;
704 goto unlock;
705 }
629 706
630 args->id = host1x_syncpt_base_id(base); 707 args->id = host1x_syncpt_base_id(base);
631 708
632 return 0; 709unlock:
710 mutex_unlock(&fpriv->lock);
711 return err;
633} 712}
634 713
635static int tegra_gem_set_tiling(struct drm_device *drm, void *data, 714static int tegra_gem_set_tiling(struct drm_device *drm, void *data,
@@ -804,14 +883,25 @@ static const struct file_operations tegra_drm_fops = {
804 .llseek = noop_llseek, 883 .llseek = noop_llseek,
805}; 884};
806 885
886static int tegra_drm_context_cleanup(int id, void *p, void *data)
887{
888 struct tegra_drm_context *context = p;
889
890 tegra_drm_context_free(context);
891
892 return 0;
893}
894
807static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) 895static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file)
808{ 896{
809 struct tegra_drm_file *fpriv = file->driver_priv; 897 struct tegra_drm_file *fpriv = file->driver_priv;
810 struct tegra_drm_context *context, *tmp;
811 898
812 list_for_each_entry_safe(context, tmp, &fpriv->contexts, list) 899 mutex_lock(&fpriv->lock);
813 tegra_drm_context_free(context); 900 idr_for_each(&fpriv->contexts, tegra_drm_context_cleanup, NULL);
901 mutex_unlock(&fpriv->lock);
814 902
903 idr_destroy(&fpriv->contexts);
904 mutex_destroy(&fpriv->lock);
815 kfree(fpriv); 905 kfree(fpriv);
816} 906}
817 907
@@ -844,7 +934,9 @@ static int tegra_debugfs_iova(struct seq_file *s, void *data)
844 struct tegra_drm *tegra = drm->dev_private; 934 struct tegra_drm *tegra = drm->dev_private;
845 struct drm_printer p = drm_seq_file_printer(s); 935 struct drm_printer p = drm_seq_file_printer(s);
846 936
937 mutex_lock(&tegra->mm_lock);
847 drm_mm_print(&tegra->mm, &p); 938 drm_mm_print(&tegra->mm, &p);
939 mutex_unlock(&tegra->mm_lock);
848 940
849 return 0; 941 return 0;
850} 942}
@@ -919,6 +1011,84 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
919 return 0; 1011 return 0;
920} 1012}
921 1013
1014void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size,
1015 dma_addr_t *dma)
1016{
1017 struct iova *alloc;
1018 void *virt;
1019 gfp_t gfp;
1020 int err;
1021
1022 if (tegra->domain)
1023 size = iova_align(&tegra->carveout.domain, size);
1024 else
1025 size = PAGE_ALIGN(size);
1026
1027 gfp = GFP_KERNEL | __GFP_ZERO;
1028 if (!tegra->domain) {
1029 /*
1030 * Many units only support 32-bit addresses, even on 64-bit
1031 * SoCs. If there is no IOMMU to translate into a 32-bit IO
1032 * virtual address space, force allocations to be in the
1033 * lower 32-bit range.
1034 */
1035 gfp |= GFP_DMA;
1036 }
1037
1038 virt = (void *)__get_free_pages(gfp, get_order(size));
1039 if (!virt)
1040 return ERR_PTR(-ENOMEM);
1041
1042 if (!tegra->domain) {
1043 /*
1044 * If IOMMU is disabled, devices address physical memory
1045 * directly.
1046 */
1047 *dma = virt_to_phys(virt);
1048 return virt;
1049 }
1050
1051 alloc = alloc_iova(&tegra->carveout.domain,
1052 size >> tegra->carveout.shift,
1053 tegra->carveout.limit, true);
1054 if (!alloc) {
1055 err = -EBUSY;
1056 goto free_pages;
1057 }
1058
1059 *dma = iova_dma_addr(&tegra->carveout.domain, alloc);
1060 err = iommu_map(tegra->domain, *dma, virt_to_phys(virt),
1061 size, IOMMU_READ | IOMMU_WRITE);
1062 if (err < 0)
1063 goto free_iova;
1064
1065 return virt;
1066
1067free_iova:
1068 __free_iova(&tegra->carveout.domain, alloc);
1069free_pages:
1070 free_pages((unsigned long)virt, get_order(size));
1071
1072 return ERR_PTR(err);
1073}
1074
1075void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt,
1076 dma_addr_t dma)
1077{
1078 if (tegra->domain)
1079 size = iova_align(&tegra->carveout.domain, size);
1080 else
1081 size = PAGE_ALIGN(size);
1082
1083 if (tegra->domain) {
1084 iommu_unmap(tegra->domain, dma, size);
1085 free_iova(&tegra->carveout.domain,
1086 iova_pfn(&tegra->carveout.domain, dma));
1087 }
1088
1089 free_pages((unsigned long)virt, get_order(size));
1090}
1091
922static int host1x_drm_probe(struct host1x_device *dev) 1092static int host1x_drm_probe(struct host1x_device *dev)
923{ 1093{
924 struct drm_driver *driver = &tegra_drm_driver; 1094 struct drm_driver *driver = &tegra_drm_driver;
@@ -1003,11 +1173,13 @@ static const struct of_device_id host1x_drm_subdevs[] = {
1003 { .compatible = "nvidia,tegra124-sor", }, 1173 { .compatible = "nvidia,tegra124-sor", },
1004 { .compatible = "nvidia,tegra124-hdmi", }, 1174 { .compatible = "nvidia,tegra124-hdmi", },
1005 { .compatible = "nvidia,tegra124-dsi", }, 1175 { .compatible = "nvidia,tegra124-dsi", },
1176 { .compatible = "nvidia,tegra124-vic", },
1006 { .compatible = "nvidia,tegra132-dsi", }, 1177 { .compatible = "nvidia,tegra132-dsi", },
1007 { .compatible = "nvidia,tegra210-dc", }, 1178 { .compatible = "nvidia,tegra210-dc", },
1008 { .compatible = "nvidia,tegra210-dsi", }, 1179 { .compatible = "nvidia,tegra210-dsi", },
1009 { .compatible = "nvidia,tegra210-sor", }, 1180 { .compatible = "nvidia,tegra210-sor", },
1010 { .compatible = "nvidia,tegra210-sor1", }, 1181 { .compatible = "nvidia,tegra210-sor1", },
1182 { .compatible = "nvidia,tegra210-vic", },
1011 { /* sentinel */ } 1183 { /* sentinel */ }
1012}; 1184};
1013 1185
@@ -1029,6 +1201,7 @@ static struct platform_driver * const drivers[] = {
1029 &tegra_sor_driver, 1201 &tegra_sor_driver,
1030 &tegra_gr2d_driver, 1202 &tegra_gr2d_driver,
1031 &tegra_gr3d_driver, 1203 &tegra_gr3d_driver,
1204 &tegra_vic_driver,
1032}; 1205};
1033 1206
1034static int __init host1x_drm_init(void) 1207static int __init host1x_drm_init(void)
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 5747accb2271..85aa2e3d9d4e 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -12,6 +12,7 @@
12 12
13#include <uapi/drm/tegra_drm.h> 13#include <uapi/drm/tegra_drm.h>
14#include <linux/host1x.h> 14#include <linux/host1x.h>
15#include <linux/iova.h>
15#include <linux/of_gpio.h> 16#include <linux/of_gpio.h>
16 17
17#include <drm/drmP.h> 18#include <drm/drmP.h>
@@ -42,8 +43,15 @@ struct tegra_drm {
42 struct drm_device *drm; 43 struct drm_device *drm;
43 44
44 struct iommu_domain *domain; 45 struct iommu_domain *domain;
46 struct mutex mm_lock;
45 struct drm_mm mm; 47 struct drm_mm mm;
46 48
49 struct {
50 struct iova_domain domain;
51 unsigned long shift;
52 unsigned long limit;
53 } carveout;
54
47 struct mutex clients_lock; 55 struct mutex clients_lock;
48 struct list_head clients; 56 struct list_head clients;
49 57
@@ -67,7 +75,7 @@ struct tegra_drm_client;
67struct tegra_drm_context { 75struct tegra_drm_context {
68 struct tegra_drm_client *client; 76 struct tegra_drm_client *client;
69 struct host1x_channel *channel; 77 struct host1x_channel *channel;
70 struct list_head list; 78 unsigned int id;
71}; 79};
72 80
73struct tegra_drm_client_ops { 81struct tegra_drm_client_ops {
@@ -105,6 +113,10 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
105int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); 113int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
106int tegra_drm_exit(struct tegra_drm *tegra); 114int tegra_drm_exit(struct tegra_drm *tegra);
107 115
116void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *iova);
117void tegra_drm_free(struct tegra_drm *tegra, size_t size, void *virt,
118 dma_addr_t iova);
119
108struct tegra_dc_soc_info; 120struct tegra_dc_soc_info;
109struct tegra_output; 121struct tegra_output;
110 122
@@ -283,5 +295,6 @@ extern struct platform_driver tegra_dpaux_driver;
283extern struct platform_driver tegra_sor_driver; 295extern struct platform_driver tegra_sor_driver;
284extern struct platform_driver tegra_gr2d_driver; 296extern struct platform_driver tegra_gr2d_driver;
285extern struct platform_driver tegra_gr3d_driver; 297extern struct platform_driver tegra_gr3d_driver;
298extern struct platform_driver tegra_vic_driver;
286 299
287#endif /* HOST1X_DRM_H */ 300#endif /* HOST1X_DRM_H */
diff --git a/drivers/gpu/drm/tegra/falcon.c b/drivers/gpu/drm/tegra/falcon.c
new file mode 100644
index 000000000000..f685e72949d1
--- /dev/null
+++ b/drivers/gpu/drm/tegra/falcon.c
@@ -0,0 +1,259 @@
1/*
2 * Copyright (c) 2015, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/platform_device.h>
10#include <linux/dma-mapping.h>
11#include <linux/firmware.h>
12#include <linux/pci_ids.h>
13#include <linux/iopoll.h>
14
15#include "falcon.h"
16#include "drm.h"
17
18enum falcon_memory {
19 FALCON_MEMORY_IMEM,
20 FALCON_MEMORY_DATA,
21};
22
23static void falcon_writel(struct falcon *falcon, u32 value, u32 offset)
24{
25 writel(value, falcon->regs + offset);
26}
27
28int falcon_wait_idle(struct falcon *falcon)
29{
30 u32 value;
31
32 return readl_poll_timeout(falcon->regs + FALCON_IDLESTATE, value,
33 (value == 0), 10, 100000);
34}
35
36static int falcon_dma_wait_idle(struct falcon *falcon)
37{
38 u32 value;
39
40 return readl_poll_timeout(falcon->regs + FALCON_DMATRFCMD, value,
41 (value & FALCON_DMATRFCMD_IDLE), 10, 100000);
42}
43
44static int falcon_copy_chunk(struct falcon *falcon,
45 phys_addr_t base,
46 unsigned long offset,
47 enum falcon_memory target)
48{
49 u32 cmd = FALCON_DMATRFCMD_SIZE_256B;
50
51 if (target == FALCON_MEMORY_IMEM)
52 cmd |= FALCON_DMATRFCMD_IMEM;
53
54 falcon_writel(falcon, offset, FALCON_DMATRFMOFFS);
55 falcon_writel(falcon, base, FALCON_DMATRFFBOFFS);
56 falcon_writel(falcon, cmd, FALCON_DMATRFCMD);
57
58 return falcon_dma_wait_idle(falcon);
59}
60
61static void falcon_copy_firmware_image(struct falcon *falcon,
62 const struct firmware *firmware)
63{
64 u32 *firmware_vaddr = falcon->firmware.vaddr;
65 dma_addr_t daddr;
66 size_t i;
67 int err;
68
69 /* copy the whole thing taking into account endianness */
70 for (i = 0; i < firmware->size / sizeof(u32); i++)
71 firmware_vaddr[i] = le32_to_cpu(((u32 *)firmware->data)[i]);
72
73 /* ensure that caches are flushed and falcon can see the firmware */
74 daddr = dma_map_single(falcon->dev, firmware_vaddr,
75 falcon->firmware.size, DMA_TO_DEVICE);
76 err = dma_mapping_error(falcon->dev, daddr);
77 if (err) {
78 dev_err(falcon->dev, "failed to map firmware: %d\n", err);
79 return;
80 }
81 dma_sync_single_for_device(falcon->dev, daddr,
82 falcon->firmware.size, DMA_TO_DEVICE);
83 dma_unmap_single(falcon->dev, daddr, falcon->firmware.size,
84 DMA_TO_DEVICE);
85}
86
87static int falcon_parse_firmware_image(struct falcon *falcon)
88{
89 struct falcon_fw_bin_header_v1 *bin = (void *)falcon->firmware.vaddr;
90 struct falcon_fw_os_header_v1 *os;
91
92 /* endian problems would show up right here */
93 if (bin->magic != PCI_VENDOR_ID_NVIDIA) {
94 dev_err(falcon->dev, "incorrect firmware magic\n");
95 return -EINVAL;
96 }
97
98 /* currently only version 1 is supported */
99 if (bin->version != 1) {
100 dev_err(falcon->dev, "unsupported firmware version\n");
101 return -EINVAL;
102 }
103
104 /* check that the firmware size is consistent */
105 if (bin->size > falcon->firmware.size) {
106 dev_err(falcon->dev, "firmware image size inconsistency\n");
107 return -EINVAL;
108 }
109
110 os = falcon->firmware.vaddr + bin->os_header_offset;
111
112 falcon->firmware.bin_data.size = bin->os_size;
113 falcon->firmware.bin_data.offset = bin->os_data_offset;
114 falcon->firmware.code.offset = os->code_offset;
115 falcon->firmware.code.size = os->code_size;
116 falcon->firmware.data.offset = os->data_offset;
117 falcon->firmware.data.size = os->data_size;
118
119 return 0;
120}
121
122int falcon_read_firmware(struct falcon *falcon, const char *name)
123{
124 int err;
125
126 /* request_firmware prints error if it fails */
127 err = request_firmware(&falcon->firmware.firmware, name, falcon->dev);
128 if (err < 0)
129 return err;
130
131 return 0;
132}
133
134int falcon_load_firmware(struct falcon *falcon)
135{
136 const struct firmware *firmware = falcon->firmware.firmware;
137 int err;
138
139 falcon->firmware.size = firmware->size;
140
141 /* allocate iova space for the firmware */
142 falcon->firmware.vaddr = falcon->ops->alloc(falcon, firmware->size,
143 &falcon->firmware.paddr);
144 if (!falcon->firmware.vaddr) {
145 dev_err(falcon->dev, "dma memory mapping failed\n");
146 return -ENOMEM;
147 }
148
149 /* copy firmware image into local area. this also ensures endianness */
150 falcon_copy_firmware_image(falcon, firmware);
151
152 /* parse the image data */
153 err = falcon_parse_firmware_image(falcon);
154 if (err < 0) {
155 dev_err(falcon->dev, "failed to parse firmware image\n");
156 goto err_setup_firmware_image;
157 }
158
159 release_firmware(firmware);
160 falcon->firmware.firmware = NULL;
161
162 return 0;
163
164err_setup_firmware_image:
165 falcon->ops->free(falcon, falcon->firmware.size,
166 falcon->firmware.paddr, falcon->firmware.vaddr);
167
168 return err;
169}
170
171int falcon_init(struct falcon *falcon)
172{
173 /* check mandatory ops */
174 if (!falcon->ops || !falcon->ops->alloc || !falcon->ops->free)
175 return -EINVAL;
176
177 falcon->firmware.vaddr = NULL;
178
179 return 0;
180}
181
182void falcon_exit(struct falcon *falcon)
183{
184 if (falcon->firmware.firmware) {
185 release_firmware(falcon->firmware.firmware);
186 falcon->firmware.firmware = NULL;
187 }
188
189 if (falcon->firmware.vaddr) {
190 falcon->ops->free(falcon, falcon->firmware.size,
191 falcon->firmware.paddr,
192 falcon->firmware.vaddr);
193 falcon->firmware.vaddr = NULL;
194 }
195}
196
197int falcon_boot(struct falcon *falcon)
198{
199 unsigned long offset;
200 int err;
201
202 if (!falcon->firmware.vaddr)
203 return -EINVAL;
204
205 falcon_writel(falcon, 0, FALCON_DMACTL);
206
207 /* setup the address of the binary data so Falcon can access it later */
208 falcon_writel(falcon, (falcon->firmware.paddr +
209 falcon->firmware.bin_data.offset) >> 8,
210 FALCON_DMATRFBASE);
211
212 /* copy the data segment into Falcon internal memory */
213 for (offset = 0; offset < falcon->firmware.data.size; offset += 256)
214 falcon_copy_chunk(falcon,
215 falcon->firmware.data.offset + offset,
216 offset, FALCON_MEMORY_DATA);
217
218 /* copy the first code segment into Falcon internal memory */
219 falcon_copy_chunk(falcon, falcon->firmware.code.offset,
220 0, FALCON_MEMORY_IMEM);
221
222 /* setup falcon interrupts */
223 falcon_writel(falcon, FALCON_IRQMSET_EXT(0xff) |
224 FALCON_IRQMSET_SWGEN1 |
225 FALCON_IRQMSET_SWGEN0 |
226 FALCON_IRQMSET_EXTERR |
227 FALCON_IRQMSET_HALT |
228 FALCON_IRQMSET_WDTMR,
229 FALCON_IRQMSET);
230 falcon_writel(falcon, FALCON_IRQDEST_EXT(0xff) |
231 FALCON_IRQDEST_SWGEN1 |
232 FALCON_IRQDEST_SWGEN0 |
233 FALCON_IRQDEST_EXTERR |
234 FALCON_IRQDEST_HALT,
235 FALCON_IRQDEST);
236
237 /* enable interface */
238 falcon_writel(falcon, FALCON_ITFEN_MTHDEN |
239 FALCON_ITFEN_CTXEN,
240 FALCON_ITFEN);
241
242 /* boot falcon */
243 falcon_writel(falcon, 0x00000000, FALCON_BOOTVEC);
244 falcon_writel(falcon, FALCON_CPUCTL_STARTCPU, FALCON_CPUCTL);
245
246 err = falcon_wait_idle(falcon);
247 if (err < 0) {
248 dev_err(falcon->dev, "Falcon boot failed due to timeout\n");
249 return err;
250 }
251
252 return 0;
253}
254
255void falcon_execute_method(struct falcon *falcon, u32 method, u32 data)
256{
257 falcon_writel(falcon, method >> 2, FALCON_UCLASS_METHOD_OFFSET);
258 falcon_writel(falcon, data, FALCON_UCLASS_METHOD_DATA);
259}
diff --git a/drivers/gpu/drm/tegra/falcon.h b/drivers/gpu/drm/tegra/falcon.h
new file mode 100644
index 000000000000..4504ed5a199e
--- /dev/null
+++ b/drivers/gpu/drm/tegra/falcon.h
@@ -0,0 +1,127 @@
1/*
2 * Copyright (c) 2015, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _FALCON_H_
10#define _FALCON_H_
11
12#include <linux/types.h>
13
14#define FALCON_UCLASS_METHOD_OFFSET 0x00000040
15
16#define FALCON_UCLASS_METHOD_DATA 0x00000044
17
18#define FALCON_IRQMSET 0x00001010
19#define FALCON_IRQMSET_WDTMR (1 << 1)
20#define FALCON_IRQMSET_HALT (1 << 4)
21#define FALCON_IRQMSET_EXTERR (1 << 5)
22#define FALCON_IRQMSET_SWGEN0 (1 << 6)
23#define FALCON_IRQMSET_SWGEN1 (1 << 7)
24#define FALCON_IRQMSET_EXT(v) (((v) & 0xff) << 8)
25
26#define FALCON_IRQDEST 0x0000101c
27#define FALCON_IRQDEST_HALT (1 << 4)
28#define FALCON_IRQDEST_EXTERR (1 << 5)
29#define FALCON_IRQDEST_SWGEN0 (1 << 6)
30#define FALCON_IRQDEST_SWGEN1 (1 << 7)
31#define FALCON_IRQDEST_EXT(v) (((v) & 0xff) << 8)
32
33#define FALCON_ITFEN 0x00001048
34#define FALCON_ITFEN_CTXEN (1 << 0)
35#define FALCON_ITFEN_MTHDEN (1 << 1)
36
37#define FALCON_IDLESTATE 0x0000104c
38
39#define FALCON_CPUCTL 0x00001100
40#define FALCON_CPUCTL_STARTCPU (1 << 1)
41
42#define FALCON_BOOTVEC 0x00001104
43
44#define FALCON_DMACTL 0x0000110c
45#define FALCON_DMACTL_DMEM_SCRUBBING (1 << 1)
46#define FALCON_DMACTL_IMEM_SCRUBBING (1 << 2)
47
48#define FALCON_DMATRFBASE 0x00001110
49
50#define FALCON_DMATRFMOFFS 0x00001114
51
52#define FALCON_DMATRFCMD 0x00001118
53#define FALCON_DMATRFCMD_IDLE (1 << 1)
54#define FALCON_DMATRFCMD_IMEM (1 << 4)
55#define FALCON_DMATRFCMD_SIZE_256B (6 << 8)
56
57#define FALCON_DMATRFFBOFFS 0x0000111c
58
59struct falcon_fw_bin_header_v1 {
60 u32 magic; /* 0x10de */
61 u32 version; /* version of bin format (1) */
62 u32 size; /* entire image size including this header */
63 u32 os_header_offset;
64 u32 os_data_offset;
65 u32 os_size;
66};
67
68struct falcon_fw_os_app_v1 {
69 u32 offset;
70 u32 size;
71};
72
73struct falcon_fw_os_header_v1 {
74 u32 code_offset;
75 u32 code_size;
76 u32 data_offset;
77 u32 data_size;
78};
79
80struct falcon;
81
82struct falcon_ops {
83 void *(*alloc)(struct falcon *falcon, size_t size,
84 dma_addr_t *paddr);
85 void (*free)(struct falcon *falcon, size_t size,
86 dma_addr_t paddr, void *vaddr);
87};
88
89struct falcon_firmware_section {
90 unsigned long offset;
91 size_t size;
92};
93
94struct falcon_firmware {
95 /* Firmware after it is read but not loaded */
96 const struct firmware *firmware;
97
98 /* Raw firmware data */
99 dma_addr_t paddr;
100 void *vaddr;
101 size_t size;
102
103 /* Parsed firmware information */
104 struct falcon_firmware_section bin_data;
105 struct falcon_firmware_section data;
106 struct falcon_firmware_section code;
107};
108
109struct falcon {
110 /* Set by falcon client */
111 struct device *dev;
112 void __iomem *regs;
113 const struct falcon_ops *ops;
114 void *data;
115
116 struct falcon_firmware firmware;
117};
118
119int falcon_init(struct falcon *falcon);
120void falcon_exit(struct falcon *falcon);
121int falcon_read_firmware(struct falcon *falcon, const char *firmware_name);
122int falcon_load_firmware(struct falcon *falcon);
123int falcon_boot(struct falcon *falcon);
124void falcon_execute_method(struct falcon *falcon, u32 method, u32 data);
125int falcon_wait_idle(struct falcon *falcon);
126
127#endif /* _FALCON_H_ */
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index c61d67d16ce3..25acb73ee728 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -52,9 +52,26 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
52 struct tegra_bo_tiling *tiling) 52 struct tegra_bo_tiling *tiling)
53{ 53{
54 struct tegra_fb *fb = to_tegra_fb(framebuffer); 54 struct tegra_fb *fb = to_tegra_fb(framebuffer);
55 55 uint64_t modifier = fb->base.modifier;
56 /* TODO: handle YUV formats? */ 56
57 *tiling = fb->planes[0]->tiling; 57 switch (fourcc_mod_tegra_mod(modifier)) {
58 case NV_FORMAT_MOD_TEGRA_TILED:
59 tiling->mode = TEGRA_BO_TILING_MODE_TILED;
60 tiling->value = 0;
61 break;
62
63 case NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(0):
64 tiling->mode = TEGRA_BO_TILING_MODE_BLOCK;
65 tiling->value = fourcc_mod_tegra_param(modifier);
66 if (tiling->value > 5)
67 return -EINVAL;
68 break;
69
70 default:
71 /* TODO: handle YUV formats? */
72 *tiling = fb->planes[0]->tiling;
73 break;
74 }
58 75
59 return 0; 76 return 0;
60} 77}
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 8672f5d2f237..424569b53e57 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -128,12 +128,14 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
128 if (!bo->mm) 128 if (!bo->mm)
129 return -ENOMEM; 129 return -ENOMEM;
130 130
131 mutex_lock(&tegra->mm_lock);
132
131 err = drm_mm_insert_node_generic(&tegra->mm, 133 err = drm_mm_insert_node_generic(&tegra->mm,
132 bo->mm, bo->gem.size, PAGE_SIZE, 0, 0); 134 bo->mm, bo->gem.size, PAGE_SIZE, 0, 0);
133 if (err < 0) { 135 if (err < 0) {
134 dev_err(tegra->drm->dev, "out of I/O virtual memory: %zd\n", 136 dev_err(tegra->drm->dev, "out of I/O virtual memory: %zd\n",
135 err); 137 err);
136 goto free; 138 goto unlock;
137 } 139 }
138 140
139 bo->paddr = bo->mm->start; 141 bo->paddr = bo->mm->start;
@@ -147,11 +149,14 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
147 149
148 bo->size = err; 150 bo->size = err;
149 151
152 mutex_unlock(&tegra->mm_lock);
153
150 return 0; 154 return 0;
151 155
152remove: 156remove:
153 drm_mm_remove_node(bo->mm); 157 drm_mm_remove_node(bo->mm);
154free: 158unlock:
159 mutex_unlock(&tegra->mm_lock);
155 kfree(bo->mm); 160 kfree(bo->mm);
156 return err; 161 return err;
157} 162}
@@ -161,8 +166,11 @@ static int tegra_bo_iommu_unmap(struct tegra_drm *tegra, struct tegra_bo *bo)
161 if (!bo->mm) 166 if (!bo->mm)
162 return 0; 167 return 0;
163 168
169 mutex_lock(&tegra->mm_lock);
164 iommu_unmap(tegra->domain, bo->paddr, bo->size); 170 iommu_unmap(tegra->domain, bo->paddr, bo->size);
165 drm_mm_remove_node(bo->mm); 171 drm_mm_remove_node(bo->mm);
172 mutex_unlock(&tegra->mm_lock);
173
166 kfree(bo->mm); 174 kfree(bo->mm);
167 175
168 return 0; 176 return 0;
diff --git a/drivers/gpu/drm/tegra/vic.c b/drivers/gpu/drm/tegra/vic.c
new file mode 100644
index 000000000000..cd804e404a11
--- /dev/null
+++ b/drivers/gpu/drm/tegra/vic.c
@@ -0,0 +1,396 @@
1/*
2 * Copyright (c) 2015, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/clk.h>
10#include <linux/host1x.h>
11#include <linux/iommu.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_device.h>
15#include <linux/of_platform.h>
16#include <linux/platform_device.h>
17#include <linux/pm_runtime.h>
18#include <linux/reset.h>
19
20#include <soc/tegra/pmc.h>
21
22#include "drm.h"
23#include "falcon.h"
24#include "vic.h"
25
26struct vic_config {
27 const char *firmware;
28};
29
30struct vic {
31 struct falcon falcon;
32 bool booted;
33
34 void __iomem *regs;
35 struct tegra_drm_client client;
36 struct host1x_channel *channel;
37 struct iommu_domain *domain;
38 struct device *dev;
39 struct clk *clk;
40
41 /* Platform configuration */
42 const struct vic_config *config;
43};
44
45static inline struct vic *to_vic(struct tegra_drm_client *client)
46{
47 return container_of(client, struct vic, client);
48}
49
50static void vic_writel(struct vic *vic, u32 value, unsigned int offset)
51{
52 writel(value, vic->regs + offset);
53}
54
55static int vic_runtime_resume(struct device *dev)
56{
57 struct vic *vic = dev_get_drvdata(dev);
58
59 return clk_prepare_enable(vic->clk);
60}
61
62static int vic_runtime_suspend(struct device *dev)
63{
64 struct vic *vic = dev_get_drvdata(dev);
65
66 clk_disable_unprepare(vic->clk);
67
68 vic->booted = false;
69
70 return 0;
71}
72
73static int vic_boot(struct vic *vic)
74{
75 u32 fce_ucode_size, fce_bin_data_offset;
76 void *hdr;
77 int err = 0;
78
79 if (vic->booted)
80 return 0;
81
82 /* setup clockgating registers */
83 vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) |
84 CG_IDLE_CG_EN |
85 CG_WAKEUP_DLY_CNT(4),
86 NV_PVIC_MISC_PRI_VIC_CG);
87
88 err = falcon_boot(&vic->falcon);
89 if (err < 0)
90 return err;
91
92 hdr = vic->falcon.firmware.vaddr;
93 fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET);
94 hdr = vic->falcon.firmware.vaddr +
95 *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET);
96 fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET);
97
98 falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1);
99 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE,
100 fce_ucode_size);
101 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET,
102 (vic->falcon.firmware.paddr + fce_bin_data_offset)
103 >> 8);
104
105 err = falcon_wait_idle(&vic->falcon);
106 if (err < 0) {
107 dev_err(vic->dev,
108 "failed to set application ID and FCE base\n");
109 return err;
110 }
111
112 vic->booted = true;
113
114 return 0;
115}
116
117static void *vic_falcon_alloc(struct falcon *falcon, size_t size,
118 dma_addr_t *iova)
119{
120 struct tegra_drm *tegra = falcon->data;
121
122 return tegra_drm_alloc(tegra, size, iova);
123}
124
125static void vic_falcon_free(struct falcon *falcon, size_t size,
126 dma_addr_t iova, void *va)
127{
128 struct tegra_drm *tegra = falcon->data;
129
130 return tegra_drm_free(tegra, size, va, iova);
131}
132
133static const struct falcon_ops vic_falcon_ops = {
134 .alloc = vic_falcon_alloc,
135 .free = vic_falcon_free
136};
137
138static int vic_init(struct host1x_client *client)
139{
140 struct tegra_drm_client *drm = host1x_to_drm_client(client);
141 struct drm_device *dev = dev_get_drvdata(client->parent);
142 struct tegra_drm *tegra = dev->dev_private;
143 struct vic *vic = to_vic(drm);
144 int err;
145
146 if (tegra->domain) {
147 err = iommu_attach_device(tegra->domain, vic->dev);
148 if (err < 0) {
149 dev_err(vic->dev, "failed to attach to domain: %d\n",
150 err);
151 return err;
152 }
153
154 vic->domain = tegra->domain;
155 }
156
157 if (!vic->falcon.data) {
158 vic->falcon.data = tegra;
159 err = falcon_load_firmware(&vic->falcon);
160 if (err < 0)
161 goto detach_device;
162 }
163
164 vic->channel = host1x_channel_request(client->dev);
165 if (!vic->channel) {
166 err = -ENOMEM;
167 goto detach_device;
168 }
169
170 client->syncpts[0] = host1x_syncpt_request(client->dev, 0);
171 if (!client->syncpts[0]) {
172 err = -ENOMEM;
173 goto free_channel;
174 }
175
176 err = tegra_drm_register_client(tegra, drm);
177 if (err < 0)
178 goto free_syncpt;
179
180 return 0;
181
182free_syncpt:
183 host1x_syncpt_free(client->syncpts[0]);
184free_channel:
185 host1x_channel_free(vic->channel);
186detach_device:
187 if (tegra->domain)
188 iommu_detach_device(tegra->domain, vic->dev);
189
190 return err;
191}
192
193static int vic_exit(struct host1x_client *client)
194{
195 struct tegra_drm_client *drm = host1x_to_drm_client(client);
196 struct drm_device *dev = dev_get_drvdata(client->parent);
197 struct tegra_drm *tegra = dev->dev_private;
198 struct vic *vic = to_vic(drm);
199 int err;
200
201 err = tegra_drm_unregister_client(tegra, drm);
202 if (err < 0)
203 return err;
204
205 host1x_syncpt_free(client->syncpts[0]);
206 host1x_channel_free(vic->channel);
207
208 if (vic->domain) {
209 iommu_detach_device(vic->domain, vic->dev);
210 vic->domain = NULL;
211 }
212
213 return 0;
214}
215
216static const struct host1x_client_ops vic_client_ops = {
217 .init = vic_init,
218 .exit = vic_exit,
219};
220
221static int vic_open_channel(struct tegra_drm_client *client,
222 struct tegra_drm_context *context)
223{
224 struct vic *vic = to_vic(client);
225 int err;
226
227 err = pm_runtime_get_sync(vic->dev);
228 if (err < 0)
229 return err;
230
231 err = vic_boot(vic);
232 if (err < 0) {
233 pm_runtime_put(vic->dev);
234 return err;
235 }
236
237 context->channel = host1x_channel_get(vic->channel);
238 if (!context->channel) {
239 pm_runtime_put(vic->dev);
240 return -ENOMEM;
241 }
242
243 return 0;
244}
245
246static void vic_close_channel(struct tegra_drm_context *context)
247{
248 struct vic *vic = to_vic(context->client);
249
250 host1x_channel_put(context->channel);
251
252 pm_runtime_put(vic->dev);
253}
254
255static const struct tegra_drm_client_ops vic_ops = {
256 .open_channel = vic_open_channel,
257 .close_channel = vic_close_channel,
258 .submit = tegra_drm_submit,
259};
260
261static const struct vic_config vic_t124_config = {
262 .firmware = "nvidia/tegra124/vic03_ucode.bin",
263};
264
265static const struct vic_config vic_t210_config = {
266 .firmware = "nvidia/tegra210/vic04_ucode.bin",
267};
268
269static const struct of_device_id vic_match[] = {
270 { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config },
271 { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config },
272 { },
273};
274
275static int vic_probe(struct platform_device *pdev)
276{
277 struct vic_config *vic_config = NULL;
278 struct device *dev = &pdev->dev;
279 struct host1x_syncpt **syncpts;
280 struct resource *regs;
281 const struct of_device_id *match;
282 struct vic *vic;
283 int err;
284
285 match = of_match_device(vic_match, dev);
286 vic_config = (struct vic_config *)match->data;
287
288 vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL);
289 if (!vic)
290 return -ENOMEM;
291
292 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL);
293 if (!syncpts)
294 return -ENOMEM;
295
296 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
297 if (!regs) {
298 dev_err(&pdev->dev, "failed to get registers\n");
299 return -ENXIO;
300 }
301
302 vic->regs = devm_ioremap_resource(dev, regs);
303 if (IS_ERR(vic->regs))
304 return PTR_ERR(vic->regs);
305
306 vic->clk = devm_clk_get(dev, NULL);
307 if (IS_ERR(vic->clk)) {
308 dev_err(&pdev->dev, "failed to get clock\n");
309 return PTR_ERR(vic->clk);
310 }
311
312 vic->falcon.dev = dev;
313 vic->falcon.regs = vic->regs;
314 vic->falcon.ops = &vic_falcon_ops;
315
316 err = falcon_init(&vic->falcon);
317 if (err < 0)
318 return err;
319
320 err = falcon_read_firmware(&vic->falcon, vic_config->firmware);
321 if (err < 0)
322 goto exit_falcon;
323
324 platform_set_drvdata(pdev, vic);
325
326 INIT_LIST_HEAD(&vic->client.base.list);
327 vic->client.base.ops = &vic_client_ops;
328 vic->client.base.dev = dev;
329 vic->client.base.class = HOST1X_CLASS_VIC;
330 vic->client.base.syncpts = syncpts;
331 vic->client.base.num_syncpts = 1;
332 vic->dev = dev;
333 vic->config = vic_config;
334
335 INIT_LIST_HEAD(&vic->client.list);
336 vic->client.ops = &vic_ops;
337
338 err = host1x_client_register(&vic->client.base);
339 if (err < 0) {
340 dev_err(dev, "failed to register host1x client: %d\n", err);
341 platform_set_drvdata(pdev, NULL);
342 goto exit_falcon;
343 }
344
345 pm_runtime_enable(&pdev->dev);
346 if (!pm_runtime_enabled(&pdev->dev)) {
347 err = vic_runtime_resume(&pdev->dev);
348 if (err < 0)
349 goto unregister_client;
350 }
351
352 return 0;
353
354unregister_client:
355 host1x_client_unregister(&vic->client.base);
356exit_falcon:
357 falcon_exit(&vic->falcon);
358
359 return err;
360}
361
362static int vic_remove(struct platform_device *pdev)
363{
364 struct vic *vic = platform_get_drvdata(pdev);
365 int err;
366
367 err = host1x_client_unregister(&vic->client.base);
368 if (err < 0) {
369 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
370 err);
371 return err;
372 }
373
374 if (pm_runtime_enabled(&pdev->dev))
375 pm_runtime_disable(&pdev->dev);
376 else
377 vic_runtime_suspend(&pdev->dev);
378
379 falcon_exit(&vic->falcon);
380
381 return 0;
382}
383
384static const struct dev_pm_ops vic_pm_ops = {
385 SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL)
386};
387
388struct platform_driver tegra_vic_driver = {
389 .driver = {
390 .name = "tegra-vic",
391 .of_match_table = vic_match,
392 .pm = &vic_pm_ops
393 },
394 .probe = vic_probe,
395 .remove = vic_remove,
396};
diff --git a/drivers/gpu/drm/tegra/vic.h b/drivers/gpu/drm/tegra/vic.h
new file mode 100644
index 000000000000..21844817a7e1
--- /dev/null
+++ b/drivers/gpu/drm/tegra/vic.h
@@ -0,0 +1,31 @@
1/*
2 * Copyright (c) 2015, NVIDIA Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef TEGRA_VIC_H
10#define TEGRA_VIC_H
11
12/* VIC methods */
13
14#define VIC_SET_APPLICATION_ID 0x00000200
15#define VIC_SET_FCE_UCODE_SIZE 0x0000071C
16#define VIC_SET_FCE_UCODE_OFFSET 0x0000072C
17
18/* VIC registers */
19
20#define NV_PVIC_MISC_PRI_VIC_CG 0x000016d0
21#define CG_IDLE_CG_DLY_CNT(val) ((val & 0x3f) << 0)
22#define CG_IDLE_CG_EN (1 << 6)
23#define CG_WAKEUP_DLY_CNT(val) ((val & 0xf) << 16)
24
25/* Firmware offsets */
26
27#define VIC_UCODE_FCE_HEADER_OFFSET (6*4)
28#define VIC_UCODE_FCE_DATA_OFFSET (7*4)
29#define FCE_UCODE_SIZE_OFFSET (2*4)
30
31#endif /* TEGRA_VIC_H */
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index eeb021fe6410..561831e1ae2c 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -267,37 +267,6 @@ static int host1x_device_match(struct device *dev, struct device_driver *drv)
267 return strcmp(dev_name(dev), drv->name) == 0; 267 return strcmp(dev_name(dev), drv->name) == 0;
268} 268}
269 269
270static int host1x_device_probe(struct device *dev)
271{
272 struct host1x_driver *driver = to_host1x_driver(dev->driver);
273 struct host1x_device *device = to_host1x_device(dev);
274
275 if (driver->probe)
276 return driver->probe(device);
277
278 return 0;
279}
280
281static int host1x_device_remove(struct device *dev)
282{
283 struct host1x_driver *driver = to_host1x_driver(dev->driver);
284 struct host1x_device *device = to_host1x_device(dev);
285
286 if (driver->remove)
287 return driver->remove(device);
288
289 return 0;
290}
291
292static void host1x_device_shutdown(struct device *dev)
293{
294 struct host1x_driver *driver = to_host1x_driver(dev->driver);
295 struct host1x_device *device = to_host1x_device(dev);
296
297 if (driver->shutdown)
298 driver->shutdown(device);
299}
300
301static const struct dev_pm_ops host1x_device_pm_ops = { 270static const struct dev_pm_ops host1x_device_pm_ops = {
302 .suspend = pm_generic_suspend, 271 .suspend = pm_generic_suspend,
303 .resume = pm_generic_resume, 272 .resume = pm_generic_resume,
@@ -310,9 +279,6 @@ static const struct dev_pm_ops host1x_device_pm_ops = {
310struct bus_type host1x_bus_type = { 279struct bus_type host1x_bus_type = {
311 .name = "host1x", 280 .name = "host1x",
312 .match = host1x_device_match, 281 .match = host1x_device_match,
313 .probe = host1x_device_probe,
314 .remove = host1x_device_remove,
315 .shutdown = host1x_device_shutdown,
316 .pm = &host1x_device_pm_ops, 282 .pm = &host1x_device_pm_ops,
317}; 283};
318 284
@@ -516,6 +482,37 @@ int host1x_unregister(struct host1x *host1x)
516 return 0; 482 return 0;
517} 483}
518 484
485static int host1x_device_probe(struct device *dev)
486{
487 struct host1x_driver *driver = to_host1x_driver(dev->driver);
488 struct host1x_device *device = to_host1x_device(dev);
489
490 if (driver->probe)
491 return driver->probe(device);
492
493 return 0;
494}
495
496static int host1x_device_remove(struct device *dev)
497{
498 struct host1x_driver *driver = to_host1x_driver(dev->driver);
499 struct host1x_device *device = to_host1x_device(dev);
500
501 if (driver->remove)
502 return driver->remove(device);
503
504 return 0;
505}
506
507static void host1x_device_shutdown(struct device *dev)
508{
509 struct host1x_driver *driver = to_host1x_driver(dev->driver);
510 struct host1x_device *device = to_host1x_device(dev);
511
512 if (driver->shutdown)
513 driver->shutdown(device);
514}
515
519int host1x_driver_register_full(struct host1x_driver *driver, 516int host1x_driver_register_full(struct host1x_driver *driver,
520 struct module *owner) 517 struct module *owner)
521{ 518{
@@ -536,6 +533,9 @@ int host1x_driver_register_full(struct host1x_driver *driver,
536 533
537 driver->driver.bus = &host1x_bus_type; 534 driver->driver.bus = &host1x_bus_type;
538 driver->driver.owner = owner; 535 driver->driver.owner = owner;
536 driver->driver.probe = host1x_device_probe;
537 driver->driver.remove = host1x_device_remove;
538 driver->driver.shutdown = host1x_device_shutdown;
539 539
540 return driver_register(&driver->driver); 540 return driver_register(&driver->driver);
541} 541}
diff --git a/drivers/gpu/host1x/cdma.c b/drivers/gpu/host1x/cdma.c
index c5d82a8a2ec9..28541b280739 100644
--- a/drivers/gpu/host1x/cdma.c
+++ b/drivers/gpu/host1x/cdma.c
@@ -51,9 +51,15 @@ static void host1x_pushbuffer_destroy(struct push_buffer *pb)
51 struct host1x_cdma *cdma = pb_to_cdma(pb); 51 struct host1x_cdma *cdma = pb_to_cdma(pb);
52 struct host1x *host1x = cdma_to_host1x(cdma); 52 struct host1x *host1x = cdma_to_host1x(cdma);
53 53
54 if (pb->phys != 0) 54 if (!pb->phys)
55 dma_free_wc(host1x->dev, pb->size_bytes + 4, pb->mapped, 55 return;
56 pb->phys); 56
57 if (host1x->domain) {
58 iommu_unmap(host1x->domain, pb->dma, pb->alloc_size);
59 free_iova(&host1x->iova, iova_pfn(&host1x->iova, pb->dma));
60 }
61
62 dma_free_wc(host1x->dev, pb->alloc_size, pb->mapped, pb->phys);
57 63
58 pb->mapped = NULL; 64 pb->mapped = NULL;
59 pb->phys = 0; 65 pb->phys = 0;
@@ -66,28 +72,64 @@ static int host1x_pushbuffer_init(struct push_buffer *pb)
66{ 72{
67 struct host1x_cdma *cdma = pb_to_cdma(pb); 73 struct host1x_cdma *cdma = pb_to_cdma(pb);
68 struct host1x *host1x = cdma_to_host1x(cdma); 74 struct host1x *host1x = cdma_to_host1x(cdma);
75 struct iova *alloc;
76 u32 size;
77 int err;
69 78
70 pb->mapped = NULL; 79 pb->mapped = NULL;
71 pb->phys = 0; 80 pb->phys = 0;
72 pb->size_bytes = HOST1X_PUSHBUFFER_SLOTS * 8; 81 pb->size = HOST1X_PUSHBUFFER_SLOTS * 8;
82
83 size = pb->size + 4;
73 84
74 /* initialize buffer pointers */ 85 /* initialize buffer pointers */
75 pb->fence = pb->size_bytes - 8; 86 pb->fence = pb->size - 8;
76 pb->pos = 0; 87 pb->pos = 0;
77 88
78 /* allocate and map pushbuffer memory */ 89 if (host1x->domain) {
79 pb->mapped = dma_alloc_wc(host1x->dev, pb->size_bytes + 4, &pb->phys, 90 unsigned long shift;
80 GFP_KERNEL); 91
81 if (!pb->mapped) 92 size = iova_align(&host1x->iova, size);
82 goto fail; 93
94 pb->mapped = dma_alloc_wc(host1x->dev, size, &pb->phys,
95 GFP_KERNEL);
96 if (!pb->mapped)
97 return -ENOMEM;
98
99 shift = iova_shift(&host1x->iova);
100 alloc = alloc_iova(&host1x->iova, size >> shift,
101 host1x->iova_end >> shift, true);
102 if (!alloc) {
103 err = -ENOMEM;
104 goto iommu_free_mem;
105 }
106
107 pb->dma = iova_dma_addr(&host1x->iova, alloc);
108 err = iommu_map(host1x->domain, pb->dma, pb->phys, size,
109 IOMMU_READ);
110 if (err)
111 goto iommu_free_iova;
112 } else {
113 pb->mapped = dma_alloc_wc(host1x->dev, size, &pb->phys,
114 GFP_KERNEL);
115 if (!pb->mapped)
116 return -ENOMEM;
117
118 pb->dma = pb->phys;
119 }
120
121 pb->alloc_size = size;
83 122
84 host1x_hw_pushbuffer_init(host1x, pb); 123 host1x_hw_pushbuffer_init(host1x, pb);
85 124
86 return 0; 125 return 0;
87 126
88fail: 127iommu_free_iova:
89 host1x_pushbuffer_destroy(pb); 128 __free_iova(&host1x->iova, alloc);
90 return -ENOMEM; 129iommu_free_mem:
130 dma_free_wc(host1x->dev, pb->alloc_size, pb->mapped, pb->phys);
131
132 return err;
91} 133}
92 134
93/* 135/*
@@ -101,7 +143,7 @@ static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2)
101 WARN_ON(pb->pos == pb->fence); 143 WARN_ON(pb->pos == pb->fence);
102 *(p++) = op1; 144 *(p++) = op1;
103 *(p++) = op2; 145 *(p++) = op2;
104 pb->pos = (pb->pos + 8) & (pb->size_bytes - 1); 146 pb->pos = (pb->pos + 8) & (pb->size - 1);
105} 147}
106 148
107/* 149/*
@@ -111,7 +153,7 @@ static void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2)
111static void host1x_pushbuffer_pop(struct push_buffer *pb, unsigned int slots) 153static void host1x_pushbuffer_pop(struct push_buffer *pb, unsigned int slots)
112{ 154{
113 /* Advance the next write position */ 155 /* Advance the next write position */
114 pb->fence = (pb->fence + slots * 8) & (pb->size_bytes - 1); 156 pb->fence = (pb->fence + slots * 8) & (pb->size - 1);
115} 157}
116 158
117/* 159/*
@@ -119,7 +161,7 @@ static void host1x_pushbuffer_pop(struct push_buffer *pb, unsigned int slots)
119 */ 161 */
120static u32 host1x_pushbuffer_space(struct push_buffer *pb) 162static u32 host1x_pushbuffer_space(struct push_buffer *pb)
121{ 163{
122 return ((pb->fence - pb->pos) & (pb->size_bytes - 1)) / 8; 164 return ((pb->fence - pb->pos) & (pb->size - 1)) / 8;
123} 165}
124 166
125/* 167/*
diff --git a/drivers/gpu/host1x/cdma.h b/drivers/gpu/host1x/cdma.h
index 470087af8fe5..ec170a78f4e1 100644
--- a/drivers/gpu/host1x/cdma.h
+++ b/drivers/gpu/host1x/cdma.h
@@ -43,10 +43,12 @@ struct host1x_job;
43 43
44struct push_buffer { 44struct push_buffer {
45 void *mapped; /* mapped pushbuffer memory */ 45 void *mapped; /* mapped pushbuffer memory */
46 dma_addr_t phys; /* physical address of pushbuffer */ 46 dma_addr_t dma; /* device address of pushbuffer */
47 phys_addr_t phys; /* physical address of pushbuffer */
47 u32 fence; /* index we've written */ 48 u32 fence; /* index we've written */
48 u32 pos; /* index to write to */ 49 u32 pos; /* index to write to */
49 u32 size_bytes; 50 u32 size;
51 u32 alloc_size;
50}; 52};
51 53
52struct buffer_timeout { 54struct buffer_timeout {
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index a62317af76ad..f05ebb14fa63 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -16,23 +16,25 @@
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */ 17 */
18 18
19#include <linux/module.h>
20#include <linux/list.h>
21#include <linux/slab.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/clk.h> 19#include <linux/clk.h>
25#include <linux/io.h>
26#include <linux/dma-mapping.h> 20#include <linux/dma-mapping.h>
21#include <linux/io.h>
22#include <linux/list.h>
23#include <linux/module.h>
24#include <linux/of_device.h>
25#include <linux/of.h>
26#include <linux/slab.h>
27 27
28#define CREATE_TRACE_POINTS 28#define CREATE_TRACE_POINTS
29#include <trace/events/host1x.h> 29#include <trace/events/host1x.h>
30#undef CREATE_TRACE_POINTS
30 31
31#include "bus.h" 32#include "bus.h"
32#include "dev.h"
33#include "intr.h"
34#include "channel.h" 33#include "channel.h"
35#include "debug.h" 34#include "debug.h"
35#include "dev.h"
36#include "intr.h"
37
36#include "hw/host1x01.h" 38#include "hw/host1x01.h"
37#include "hw/host1x02.h" 39#include "hw/host1x02.h"
38#include "hw/host1x04.h" 40#include "hw/host1x04.h"
@@ -168,22 +170,56 @@ static int host1x_probe(struct platform_device *pdev)
168 return err; 170 return err;
169 } 171 }
170 172
173 host->rst = devm_reset_control_get(&pdev->dev, "host1x");
174 if (IS_ERR(host->rst)) {
175 err = PTR_ERR(host->clk);
176 dev_err(&pdev->dev, "failed to get reset: %d\n", err);
177 return err;
178 }
179
180 if (iommu_present(&platform_bus_type)) {
181 struct iommu_domain_geometry *geometry;
182 unsigned long order;
183
184 host->domain = iommu_domain_alloc(&platform_bus_type);
185 if (!host->domain)
186 return -ENOMEM;
187
188 err = iommu_attach_device(host->domain, &pdev->dev);
189 if (err)
190 goto fail_free_domain;
191
192 geometry = &host->domain->geometry;
193
194 order = __ffs(host->domain->pgsize_bitmap);
195 init_iova_domain(&host->iova, 1UL << order,
196 geometry->aperture_start >> order,
197 geometry->aperture_end >> order);
198 host->iova_end = geometry->aperture_end;
199 }
200
171 err = host1x_channel_list_init(host); 201 err = host1x_channel_list_init(host);
172 if (err) { 202 if (err) {
173 dev_err(&pdev->dev, "failed to initialize channel list\n"); 203 dev_err(&pdev->dev, "failed to initialize channel list\n");
174 return err; 204 goto fail_detach_device;
175 } 205 }
176 206
177 err = clk_prepare_enable(host->clk); 207 err = clk_prepare_enable(host->clk);
178 if (err < 0) { 208 if (err < 0) {
179 dev_err(&pdev->dev, "failed to enable clock\n"); 209 dev_err(&pdev->dev, "failed to enable clock\n");
180 return err; 210 goto fail_detach_device;
211 }
212
213 err = reset_control_deassert(host->rst);
214 if (err < 0) {
215 dev_err(&pdev->dev, "failed to deassert reset: %d\n", err);
216 goto fail_unprepare_disable;
181 } 217 }
182 218
183 err = host1x_syncpt_init(host); 219 err = host1x_syncpt_init(host);
184 if (err) { 220 if (err) {
185 dev_err(&pdev->dev, "failed to initialize syncpts\n"); 221 dev_err(&pdev->dev, "failed to initialize syncpts\n");
186 goto fail_unprepare_disable; 222 goto fail_reset_assert;
187 } 223 }
188 224
189 err = host1x_intr_init(host, syncpt_irq); 225 err = host1x_intr_init(host, syncpt_irq);
@@ -204,8 +240,19 @@ fail_deinit_intr:
204 host1x_intr_deinit(host); 240 host1x_intr_deinit(host);
205fail_deinit_syncpt: 241fail_deinit_syncpt:
206 host1x_syncpt_deinit(host); 242 host1x_syncpt_deinit(host);
243fail_reset_assert:
244 reset_control_assert(host->rst);
207fail_unprepare_disable: 245fail_unprepare_disable:
208 clk_disable_unprepare(host->clk); 246 clk_disable_unprepare(host->clk);
247fail_detach_device:
248 if (host->domain) {
249 put_iova_domain(&host->iova);
250 iommu_detach_device(host->domain, &pdev->dev);
251 }
252fail_free_domain:
253 if (host->domain)
254 iommu_domain_free(host->domain);
255
209 return err; 256 return err;
210} 257}
211 258
@@ -216,8 +263,15 @@ static int host1x_remove(struct platform_device *pdev)
216 host1x_unregister(host); 263 host1x_unregister(host);
217 host1x_intr_deinit(host); 264 host1x_intr_deinit(host);
218 host1x_syncpt_deinit(host); 265 host1x_syncpt_deinit(host);
266 reset_control_assert(host->rst);
219 clk_disable_unprepare(host->clk); 267 clk_disable_unprepare(host->clk);
220 268
269 if (host->domain) {
270 put_iova_domain(&host->iova);
271 iommu_detach_device(host->domain, &pdev->dev);
272 iommu_domain_free(host->domain);
273 }
274
221 return 0; 275 return 0;
222} 276}
223 277
diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h
index 06dd4f85125f..229d08b6a45e 100644
--- a/drivers/gpu/host1x/dev.h
+++ b/drivers/gpu/host1x/dev.h
@@ -17,14 +17,17 @@
17#ifndef HOST1X_DEV_H 17#ifndef HOST1X_DEV_H
18#define HOST1X_DEV_H 18#define HOST1X_DEV_H
19 19
20#include <linux/platform_device.h>
21#include <linux/device.h> 20#include <linux/device.h>
21#include <linux/iommu.h>
22#include <linux/iova.h>
23#include <linux/platform_device.h>
24#include <linux/reset.h>
22 25
26#include "cdma.h"
23#include "channel.h" 27#include "channel.h"
24#include "syncpt.h"
25#include "intr.h" 28#include "intr.h"
26#include "cdma.h"
27#include "job.h" 29#include "job.h"
30#include "syncpt.h"
28 31
29struct host1x_syncpt; 32struct host1x_syncpt;
30struct host1x_syncpt_base; 33struct host1x_syncpt_base;
@@ -107,6 +110,11 @@ struct host1x {
107 struct host1x_syncpt_base *bases; 110 struct host1x_syncpt_base *bases;
108 struct device *dev; 111 struct device *dev;
109 struct clk *clk; 112 struct clk *clk;
113 struct reset_control *rst;
114
115 struct iommu_domain *domain;
116 struct iova_domain iova;
117 dma_addr_t iova_end;
110 118
111 struct mutex intr_mutex; 119 struct mutex intr_mutex;
112 int intr_syncpt_irq; 120 int intr_syncpt_irq;
diff --git a/drivers/gpu/host1x/hw/cdma_hw.c b/drivers/gpu/host1x/hw/cdma_hw.c
index 659c1bbfeeba..6b231119193e 100644
--- a/drivers/gpu/host1x/hw/cdma_hw.c
+++ b/drivers/gpu/host1x/hw/cdma_hw.c
@@ -30,7 +30,7 @@
30 */ 30 */
31static void push_buffer_init(struct push_buffer *pb) 31static void push_buffer_init(struct push_buffer *pb)
32{ 32{
33 *(u32 *)(pb->mapped + pb->size_bytes) = host1x_opcode_restart(0); 33 *(u32 *)(pb->mapped + pb->size) = host1x_opcode_restart(0);
34} 34}
35 35
36/* 36/*
@@ -55,8 +55,8 @@ static void cdma_timeout_cpu_incr(struct host1x_cdma *cdma, u32 getptr,
55 *(p++) = HOST1X_OPCODE_NOP; 55 *(p++) = HOST1X_OPCODE_NOP;
56 *(p++) = HOST1X_OPCODE_NOP; 56 *(p++) = HOST1X_OPCODE_NOP;
57 dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__, 57 dev_dbg(host1x->dev, "%s: NOP at %pad+%#x\n", __func__,
58 &pb->phys, getptr); 58 &pb->dma, getptr);
59 getptr = (getptr + 8) & (pb->size_bytes - 1); 59 getptr = (getptr + 8) & (pb->size - 1);
60 } 60 }
61 61
62 wmb(); 62 wmb();
@@ -78,10 +78,9 @@ static void cdma_start(struct host1x_cdma *cdma)
78 HOST1X_CHANNEL_DMACTRL); 78 HOST1X_CHANNEL_DMACTRL);
79 79
80 /* set base, put and end pointer */ 80 /* set base, put and end pointer */
81 host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); 81 host1x_ch_writel(ch, cdma->push_buffer.dma, HOST1X_CHANNEL_DMASTART);
82 host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT); 82 host1x_ch_writel(ch, cdma->push_buffer.pos, HOST1X_CHANNEL_DMAPUT);
83 host1x_ch_writel(ch, cdma->push_buffer.phys + 83 host1x_ch_writel(ch, cdma->push_buffer.dma + cdma->push_buffer.size + 4,
84 cdma->push_buffer.size_bytes + 4,
85 HOST1X_CHANNEL_DMAEND); 84 HOST1X_CHANNEL_DMAEND);
86 85
87 /* reset GET */ 86 /* reset GET */
@@ -115,9 +114,8 @@ static void cdma_timeout_restart(struct host1x_cdma *cdma, u32 getptr)
115 HOST1X_CHANNEL_DMACTRL); 114 HOST1X_CHANNEL_DMACTRL);
116 115
117 /* set base, end pointer (all of memory) */ 116 /* set base, end pointer (all of memory) */
118 host1x_ch_writel(ch, cdma->push_buffer.phys, HOST1X_CHANNEL_DMASTART); 117 host1x_ch_writel(ch, cdma->push_buffer.dma, HOST1X_CHANNEL_DMASTART);
119 host1x_ch_writel(ch, cdma->push_buffer.phys + 118 host1x_ch_writel(ch, cdma->push_buffer.dma + cdma->push_buffer.size,
120 cdma->push_buffer.size_bytes,
121 HOST1X_CHANNEL_DMAEND); 119 HOST1X_CHANNEL_DMAEND);
122 120
123 /* set GET, by loading the value in PUT (then reset GET) */ 121 /* set GET, by loading the value in PUT (then reset GET) */
diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c
index 92c3df933303..5f5f8ee6143d 100644
--- a/drivers/gpu/host1x/job.c
+++ b/drivers/gpu/host1x/job.c
@@ -174,9 +174,10 @@ static int do_waitchks(struct host1x_job *job, struct host1x *host,
174 return 0; 174 return 0;
175} 175}
176 176
177static unsigned int pin_job(struct host1x_job *job) 177static unsigned int pin_job(struct host1x *host, struct host1x_job *job)
178{ 178{
179 unsigned int i; 179 unsigned int i;
180 int err;
180 181
181 job->num_unpins = 0; 182 job->num_unpins = 0;
182 183
@@ -186,12 +187,16 @@ static unsigned int pin_job(struct host1x_job *job)
186 dma_addr_t phys_addr; 187 dma_addr_t phys_addr;
187 188
188 reloc->target.bo = host1x_bo_get(reloc->target.bo); 189 reloc->target.bo = host1x_bo_get(reloc->target.bo);
189 if (!reloc->target.bo) 190 if (!reloc->target.bo) {
191 err = -EINVAL;
190 goto unpin; 192 goto unpin;
193 }
191 194
192 phys_addr = host1x_bo_pin(reloc->target.bo, &sgt); 195 phys_addr = host1x_bo_pin(reloc->target.bo, &sgt);
193 if (!phys_addr) 196 if (!phys_addr) {
197 err = -EINVAL;
194 goto unpin; 198 goto unpin;
199 }
195 200
196 job->addr_phys[job->num_unpins] = phys_addr; 201 job->addr_phys[job->num_unpins] = phys_addr;
197 job->unpins[job->num_unpins].bo = reloc->target.bo; 202 job->unpins[job->num_unpins].bo = reloc->target.bo;
@@ -201,28 +206,67 @@ static unsigned int pin_job(struct host1x_job *job)
201 206
202 for (i = 0; i < job->num_gathers; i++) { 207 for (i = 0; i < job->num_gathers; i++) {
203 struct host1x_job_gather *g = &job->gathers[i]; 208 struct host1x_job_gather *g = &job->gathers[i];
209 size_t gather_size = 0;
210 struct scatterlist *sg;
204 struct sg_table *sgt; 211 struct sg_table *sgt;
205 dma_addr_t phys_addr; 212 dma_addr_t phys_addr;
213 unsigned long shift;
214 struct iova *alloc;
215 unsigned int j;
206 216
207 g->bo = host1x_bo_get(g->bo); 217 g->bo = host1x_bo_get(g->bo);
208 if (!g->bo) 218 if (!g->bo) {
219 err = -EINVAL;
209 goto unpin; 220 goto unpin;
221 }
210 222
211 phys_addr = host1x_bo_pin(g->bo, &sgt); 223 phys_addr = host1x_bo_pin(g->bo, &sgt);
212 if (!phys_addr) 224 if (!phys_addr) {
225 err = -EINVAL;
213 goto unpin; 226 goto unpin;
227 }
228
229 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
230 for_each_sg(sgt->sgl, sg, sgt->nents, j)
231 gather_size += sg->length;
232 gather_size = iova_align(&host->iova, gather_size);
233
234 shift = iova_shift(&host->iova);
235 alloc = alloc_iova(&host->iova, gather_size >> shift,
236 host->iova_end >> shift, true);
237 if (!alloc) {
238 err = -ENOMEM;
239 goto unpin;
240 }
241
242 err = iommu_map_sg(host->domain,
243 iova_dma_addr(&host->iova, alloc),
244 sgt->sgl, sgt->nents, IOMMU_READ);
245 if (err == 0) {
246 __free_iova(&host->iova, alloc);
247 err = -EINVAL;
248 goto unpin;
249 }
250
251 job->addr_phys[job->num_unpins] =
252 iova_dma_addr(&host->iova, alloc);
253 job->unpins[job->num_unpins].size = gather_size;
254 } else {
255 job->addr_phys[job->num_unpins] = phys_addr;
256 }
257
258 job->gather_addr_phys[i] = job->addr_phys[job->num_unpins];
214 259
215 job->addr_phys[job->num_unpins] = phys_addr;
216 job->unpins[job->num_unpins].bo = g->bo; 260 job->unpins[job->num_unpins].bo = g->bo;
217 job->unpins[job->num_unpins].sgt = sgt; 261 job->unpins[job->num_unpins].sgt = sgt;
218 job->num_unpins++; 262 job->num_unpins++;
219 } 263 }
220 264
221 return job->num_unpins; 265 return 0;
222 266
223unpin: 267unpin:
224 host1x_job_unpin(job); 268 host1x_job_unpin(job);
225 return 0; 269 return err;
226} 270}
227 271
228static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf) 272static int do_relocs(struct host1x_job *job, struct host1x_bo *cmdbuf)
@@ -525,8 +569,8 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev)
525 host1x_syncpt_load(host->syncpt + i); 569 host1x_syncpt_load(host->syncpt + i);
526 570
527 /* pin memory */ 571 /* pin memory */
528 err = pin_job(job); 572 err = pin_job(host, job);
529 if (!err) 573 if (err)
530 goto out; 574 goto out;
531 575
532 /* patch gathers */ 576 /* patch gathers */
@@ -572,11 +616,19 @@ EXPORT_SYMBOL(host1x_job_pin);
572 616
573void host1x_job_unpin(struct host1x_job *job) 617void host1x_job_unpin(struct host1x_job *job)
574{ 618{
619 struct host1x *host = dev_get_drvdata(job->channel->dev->parent);
575 unsigned int i; 620 unsigned int i;
576 621
577 for (i = 0; i < job->num_unpins; i++) { 622 for (i = 0; i < job->num_unpins; i++) {
578 struct host1x_job_unpin_data *unpin = &job->unpins[i]; 623 struct host1x_job_unpin_data *unpin = &job->unpins[i];
579 624
625 if (!IS_ENABLED(CONFIG_TEGRA_HOST1X_FIREWALL) && host->domain) {
626 iommu_unmap(host->domain, job->addr_phys[i],
627 unpin->size);
628 free_iova(&host->iova,
629 iova_pfn(&host->iova, job->addr_phys[i]));
630 }
631
580 host1x_bo_unpin(unpin->bo, unpin->sgt); 632 host1x_bo_unpin(unpin->bo, unpin->sgt);
581 host1x_bo_put(unpin->bo); 633 host1x_bo_put(unpin->bo);
582 } 634 }
diff --git a/drivers/gpu/host1x/job.h b/drivers/gpu/host1x/job.h
index 8b3c15df0660..878239c476d2 100644
--- a/drivers/gpu/host1x/job.h
+++ b/drivers/gpu/host1x/job.h
@@ -44,6 +44,7 @@ struct host1x_waitchk {
44struct host1x_job_unpin_data { 44struct host1x_job_unpin_data {
45 struct host1x_bo *bo; 45 struct host1x_bo *bo;
46 struct sg_table *sgt; 46 struct sg_table *sgt;
47 size_t size;
47}; 48};
48 49
49/* 50/*
diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
index 25c11a85050b..0ac026cdc30c 100644
--- a/drivers/gpu/host1x/syncpt.c
+++ b/drivers/gpu/host1x/syncpt.c
@@ -484,7 +484,7 @@ unsigned int host1x_syncpt_nb_mlocks(struct host1x *host)
484 484
485struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id) 485struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, unsigned int id)
486{ 486{
487 if (host->info->nb_pts < id) 487 if (id >= host->info->nb_pts)
488 return NULL; 488 return NULL;
489 489
490 return host->syncpt + id; 490 return host->syncpt + id;
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index b7268a14184f..e80a4105ac2a 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -100,6 +100,34 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
100 } 100 }
101} 101}
102 102
103/* Insert the iova into domain rbtree by holding writer lock */
104static void
105iova_insert_rbtree(struct rb_root *root, struct iova *iova,
106 struct rb_node *start)
107{
108 struct rb_node **new, *parent = NULL;
109
110 new = (start) ? &start : &(root->rb_node);
111 /* Figure out where to put new node */
112 while (*new) {
113 struct iova *this = rb_entry(*new, struct iova, node);
114
115 parent = *new;
116
117 if (iova->pfn_lo < this->pfn_lo)
118 new = &((*new)->rb_left);
119 else if (iova->pfn_lo > this->pfn_lo)
120 new = &((*new)->rb_right);
121 else {
122 WARN_ON(1); /* this should not happen */
123 return;
124 }
125 }
126 /* Add new node and rebalance tree. */
127 rb_link_node(&iova->node, parent, new);
128 rb_insert_color(&iova->node, root);
129}
130
103/* 131/*
104 * Computes the padding size required, to make the start address 132 * Computes the padding size required, to make the start address
105 * naturally aligned on the power-of-two order of its size 133 * naturally aligned on the power-of-two order of its size
@@ -157,35 +185,8 @@ move_left:
157 new->pfn_lo = limit_pfn - (size + pad_size) + 1; 185 new->pfn_lo = limit_pfn - (size + pad_size) + 1;
158 new->pfn_hi = new->pfn_lo + size - 1; 186 new->pfn_hi = new->pfn_lo + size - 1;
159 187
160 /* Insert the new_iova into domain rbtree by holding writer lock */ 188 /* If we have 'prev', it's a valid place to start the insertion. */
161 /* Add new node and rebalance tree. */ 189 iova_insert_rbtree(&iovad->rbroot, new, prev);
162 {
163 struct rb_node **entry, *parent = NULL;
164
165 /* If we have 'prev', it's a valid place to start the
166 insertion. Otherwise, start from the root. */
167 if (prev)
168 entry = &prev;
169 else
170 entry = &iovad->rbroot.rb_node;
171
172 /* Figure out where to put new node */
173 while (*entry) {
174 struct iova *this = rb_entry(*entry, struct iova, node);
175 parent = *entry;
176
177 if (new->pfn_lo < this->pfn_lo)
178 entry = &((*entry)->rb_left);
179 else if (new->pfn_lo > this->pfn_lo)
180 entry = &((*entry)->rb_right);
181 else
182 BUG(); /* this should not happen */
183 }
184
185 /* Add new node and rebalance tree. */
186 rb_link_node(&new->node, parent, entry);
187 rb_insert_color(&new->node, &iovad->rbroot);
188 }
189 __cached_rbnode_insert_update(iovad, saved_pfn, new); 190 __cached_rbnode_insert_update(iovad, saved_pfn, new);
190 191
191 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 192 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
@@ -194,28 +195,6 @@ move_left:
194 return 0; 195 return 0;
195} 196}
196 197
197static void
198iova_insert_rbtree(struct rb_root *root, struct iova *iova)
199{
200 struct rb_node **new = &(root->rb_node), *parent = NULL;
201 /* Figure out where to put new node */
202 while (*new) {
203 struct iova *this = rb_entry(*new, struct iova, node);
204
205 parent = *new;
206
207 if (iova->pfn_lo < this->pfn_lo)
208 new = &((*new)->rb_left);
209 else if (iova->pfn_lo > this->pfn_lo)
210 new = &((*new)->rb_right);
211 else
212 BUG(); /* this should not happen */
213 }
214 /* Add new node and rebalance tree. */
215 rb_link_node(&iova->node, parent, new);
216 rb_insert_color(&iova->node, root);
217}
218
219static struct kmem_cache *iova_cache; 198static struct kmem_cache *iova_cache;
220static unsigned int iova_cache_users; 199static unsigned int iova_cache_users;
221static DEFINE_MUTEX(iova_cache_mutex); 200static DEFINE_MUTEX(iova_cache_mutex);
@@ -505,7 +484,7 @@ __insert_new_range(struct iova_domain *iovad,
505 484
506 iova = alloc_and_init_iova(pfn_lo, pfn_hi); 485 iova = alloc_and_init_iova(pfn_lo, pfn_hi);
507 if (iova) 486 if (iova)
508 iova_insert_rbtree(&iovad->rbroot, iova); 487 iova_insert_rbtree(&iovad->rbroot, iova, NULL);
509 488
510 return iova; 489 return iova;
511} 490}
@@ -612,11 +591,11 @@ split_and_remove_iova(struct iova_domain *iovad, struct iova *iova,
612 rb_erase(&iova->node, &iovad->rbroot); 591 rb_erase(&iova->node, &iovad->rbroot);
613 592
614 if (prev) { 593 if (prev) {
615 iova_insert_rbtree(&iovad->rbroot, prev); 594 iova_insert_rbtree(&iovad->rbroot, prev, NULL);
616 iova->pfn_lo = pfn_lo; 595 iova->pfn_lo = pfn_lo;
617 } 596 }
618 if (next) { 597 if (next) {
619 iova_insert_rbtree(&iovad->rbroot, next); 598 iova_insert_rbtree(&iovad->rbroot, next, NULL);
620 iova->pfn_hi = pfn_hi; 599 iova->pfn_hi = pfn_hi;
621 } 600 }
622 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags); 601 spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 1ffbf2a8cb99..3d04aa1dc83e 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -26,6 +26,7 @@ enum host1x_class {
26 HOST1X_CLASS_HOST1X = 0x1, 26 HOST1X_CLASS_HOST1X = 0x1,
27 HOST1X_CLASS_GR2D = 0x51, 27 HOST1X_CLASS_GR2D = 0x51,
28 HOST1X_CLASS_GR2D_SB = 0x52, 28 HOST1X_CLASS_GR2D_SB = 0x52,
29 HOST1X_CLASS_VIC = 0x5D,
29 HOST1X_CLASS_GR3D = 0x60, 30 HOST1X_CLASS_GR3D = 0x60,
30}; 31};
31 32
diff --git a/include/linux/iova.h b/include/linux/iova.h
index f27bb2c62fca..e0a892ae45c0 100644
--- a/include/linux/iova.h
+++ b/include/linux/iova.h
@@ -82,6 +82,7 @@ static inline unsigned long iova_pfn(struct iova_domain *iovad, dma_addr_t iova)
82 return iova >> iova_shift(iovad); 82 return iova >> iova_shift(iovad);
83} 83}
84 84
85#if IS_ENABLED(CONFIG_IOMMU_IOVA)
85int iova_cache_get(void); 86int iova_cache_get(void);
86void iova_cache_put(void); 87void iova_cache_put(void);
87 88
@@ -106,5 +107,95 @@ void put_iova_domain(struct iova_domain *iovad);
106struct iova *split_and_remove_iova(struct iova_domain *iovad, 107struct iova *split_and_remove_iova(struct iova_domain *iovad,
107 struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi); 108 struct iova *iova, unsigned long pfn_lo, unsigned long pfn_hi);
108void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad); 109void free_cpu_cached_iovas(unsigned int cpu, struct iova_domain *iovad);
110#else
111static inline int iova_cache_get(void)
112{
113 return -ENOTSUPP;
114}
115
116static inline void iova_cache_put(void)
117{
118}
119
120static inline struct iova *alloc_iova_mem(void)
121{
122 return NULL;
123}
124
125static inline void free_iova_mem(struct iova *iova)
126{
127}
128
129static inline void free_iova(struct iova_domain *iovad, unsigned long pfn)
130{
131}
132
133static inline void __free_iova(struct iova_domain *iovad, struct iova *iova)
134{
135}
136
137static inline struct iova *alloc_iova(struct iova_domain *iovad,
138 unsigned long size,
139 unsigned long limit_pfn,
140 bool size_aligned)
141{
142 return NULL;
143}
144
145static inline void free_iova_fast(struct iova_domain *iovad,
146 unsigned long pfn,
147 unsigned long size)
148{
149}
150
151static inline unsigned long alloc_iova_fast(struct iova_domain *iovad,
152 unsigned long size,
153 unsigned long limit_pfn)
154{
155 return 0;
156}
157
158static inline struct iova *reserve_iova(struct iova_domain *iovad,
159 unsigned long pfn_lo,
160 unsigned long pfn_hi)
161{
162 return NULL;
163}
164
165static inline void copy_reserved_iova(struct iova_domain *from,
166 struct iova_domain *to)
167{
168}
169
170static inline void init_iova_domain(struct iova_domain *iovad,
171 unsigned long granule,
172 unsigned long start_pfn,
173 unsigned long pfn_32bit)
174{
175}
176
177static inline struct iova *find_iova(struct iova_domain *iovad,
178 unsigned long pfn)
179{
180 return NULL;
181}
182
183static inline void put_iova_domain(struct iova_domain *iovad)
184{
185}
186
187static inline struct iova *split_and_remove_iova(struct iova_domain *iovad,
188 struct iova *iova,
189 unsigned long pfn_lo,
190 unsigned long pfn_hi)
191{
192 return NULL;
193}
194
195static inline void free_cpu_cached_iovas(unsigned int cpu,
196 struct iova_domain *iovad)
197{
198}
199#endif
109 200
110#endif 201#endif
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 995c8f9c692f..55e301047b3e 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -306,6 +306,51 @@ extern "C" {
306 */ 306 */
307#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4) 307#define DRM_FORMAT_MOD_VIVANTE_SPLIT_SUPER_TILED fourcc_mod_code(VIVANTE, 4)
308 308
309
310/* NVIDIA Tegra frame buffer modifiers */
311
312/*
313 * Some modifiers take parameters, for example the number of vertical GOBs in
314 * a block. Reserve the lower 32 bits for parameters
315 */
316#define __fourcc_mod_tegra_mode_shift 32
317#define fourcc_mod_tegra_code(val, params) \
318 fourcc_mod_code(NV, ((((__u64)val) << __fourcc_mod_tegra_mode_shift) | params))
319#define fourcc_mod_tegra_mod(m) \
320 (m & ~((1ULL << __fourcc_mod_tegra_mode_shift) - 1))
321#define fourcc_mod_tegra_param(m) \
322 (m & ((1ULL << __fourcc_mod_tegra_mode_shift) - 1))
323
324/*
325 * Tegra Tiled Layout, used by Tegra 2, 3 and 4.
326 *
327 * Pixels are arranged in simple tiles of 16 x 16 bytes.
328 */
329#define NV_FORMAT_MOD_TEGRA_TILED fourcc_mod_tegra_code(1, 0)
330
331/*
332 * Tegra 16Bx2 Block Linear layout, used by TK1/TX1
333 *
334 * Pixels are arranged in 64x8 Groups Of Bytes (GOBs). GOBs are then stacked
335 * vertically by a power of 2 (1 to 32 GOBs) to form a block.
336 *
337 * Within a GOB, data is ordered as 16B x 2 lines sectors laid in Z-shape.
338 *
339 * Parameter 'v' is the log2 encoding of the number of GOBs stacked vertically.
340 * Valid values are:
341 *
342 * 0 == ONE_GOB
343 * 1 == TWO_GOBS
344 * 2 == FOUR_GOBS
345 * 3 == EIGHT_GOBS
346 * 4 == SIXTEEN_GOBS
347 * 5 == THIRTYTWO_GOBS
348 *
349 * Chapter 20 "Pixel Memory Formats" of the Tegra X1 TRM describes this format
350 * in full detail.
351 */
352#define NV_FORMAT_MOD_TEGRA_16BX2_BLOCK(v) fourcc_mod_tegra_code(2, v)
353
309#if defined(__cplusplus) 354#if defined(__cplusplus)
310} 355}
311#endif 356#endif