aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt36
-rw-r--r--arch/arm/Kconfig3
-rw-r--r--arch/arm/boot/dts/tegra114.dtsi23
-rw-r--r--arch/arm/boot/dts/tegra124.dtsi19
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi25
-rw-r--r--arch/arm/mach-tegra/Kconfig9
-rw-r--r--arch/arm64/Kconfig3
-rw-r--r--arch/powerpc/include/asm/iommu.h17
-rw-r--r--arch/powerpc/kernel/dma-iommu.c8
-rw-r--r--arch/powerpc/kernel/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/iommu.c9
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/amba/Kconfig14
-rw-r--r--drivers/clk/tegra/clk-divider.c13
-rw-r--r--drivers/clk/tegra/clk-tegra114.c7
-rw-r--r--drivers/clk/tegra/clk-tegra124.c7
-rw-r--r--drivers/clk/tegra/clk-tegra20.c8
-rw-r--r--drivers/clk/tegra/clk-tegra30.c7
-rw-r--r--drivers/clk/tegra/clk.h2
-rw-r--r--drivers/iommu/Kconfig12
-rw-r--r--drivers/iommu/amd_iommu.c1
-rw-r--r--drivers/iommu/arm-smmu.c1
-rw-r--r--drivers/iommu/exynos-iommu.c1
-rw-r--r--drivers/iommu/intel-iommu.c1
-rw-r--r--drivers/iommu/iommu.c50
-rw-r--r--drivers/iommu/ipmmu-vmsa.c1
-rw-r--r--drivers/iommu/msm_iommu.c1
-rw-r--r--drivers/iommu/omap-iommu.c1
-rw-r--r--drivers/iommu/shmobile-iommu.c1
-rw-r--r--drivers/iommu/tegra-smmu.c1609
-rw-r--r--drivers/memory/Kconfig12
-rw-r--r--drivers/memory/Makefile3
-rw-r--r--drivers/memory/tegra/Kconfig7
-rw-r--r--drivers/memory/tegra/Makefile7
-rw-r--r--drivers/memory/tegra/mc.c301
-rw-r--r--drivers/memory/tegra/mc.h40
-rw-r--r--drivers/memory/tegra/tegra114.c948
-rw-r--r--drivers/memory/tegra/tegra124.c995
-rw-r--r--drivers/memory/tegra/tegra30.c970
-rw-r--r--drivers/memory/tegra30-mc.c378
-rw-r--r--include/dt-bindings/clock/tegra114-car.h2
-rw-r--r--include/dt-bindings/clock/tegra124-car.h2
-rw-r--r--include/dt-bindings/clock/tegra20-car.h2
-rw-r--r--include/dt-bindings/memory/tegra114-mc.h25
-rw-r--r--include/dt-bindings/memory/tegra124-mc.h31
-rw-r--r--include/dt-bindings/memory/tegra30-mc.h24
-rw-r--r--include/linux/iommu.h22
-rw-r--r--include/soc/tegra/mc.h107
48 files changed, 4232 insertions, 1551 deletions
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
new file mode 100644
index 000000000000..f3db93c85eea
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
@@ -0,0 +1,36 @@
1NVIDIA Tegra Memory Controller device tree bindings
2===================================================
3
4Required properties:
5- compatible: Should be "nvidia,tegra<chip>-mc"
6- reg: Physical base address and length of the controller's registers.
7- clocks: Must contain an entry for each entry in clock-names.
8 See ../clocks/clock-bindings.txt for details.
9- clock-names: Must include the following entries:
10 - mc: the module's clock input
11- interrupts: The interrupt outputs from the controller.
12- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines
13 the SWGROUP of the master.
14
15This device implements an IOMMU that complies with the generic IOMMU binding.
16See ../iommu/iommu.txt for details.
17
18Example:
19--------
20
21 mc: memory-controller@0,70019000 {
22 compatible = "nvidia,tegra124-mc";
23 reg = <0x0 0x70019000 0x0 0x1000>;
24 clocks = <&tegra_car TEGRA124_CLK_MC>;
25 clock-names = "mc";
26
27 interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
28
29 #iommu-cells = <1>;
30 };
31
32 sdhci@0,700b0000 {
33 compatible = "nvidia,tegra124-sdhci";
34 ...
35 iommus = <&mc TEGRA_SWGROUP_SDMMC1A>;
36 };
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 89c4b5ccc68d..77f8ca5cc3e6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1259,9 +1259,6 @@ source "arch/arm/common/Kconfig"
1259 1259
1260menu "Bus support" 1260menu "Bus support"
1261 1261
1262config ARM_AMBA
1263 bool
1264
1265config ISA 1262config ISA
1266 bool 1263 bool
1267 help 1264 help
diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 2ca9c1807f72..c8c3b6438b4d 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -1,5 +1,6 @@
1#include <dt-bindings/clock/tegra114-car.h> 1#include <dt-bindings/clock/tegra114-car.h>
2#include <dt-bindings/gpio/tegra-gpio.h> 2#include <dt-bindings/gpio/tegra-gpio.h>
3#include <dt-bindings/memory/tegra114-mc.h>
3#include <dt-bindings/pinctrl/pinctrl-tegra.h> 4#include <dt-bindings/pinctrl/pinctrl-tegra.h>
4#include <dt-bindings/interrupt-controller/arm-gic.h> 5#include <dt-bindings/interrupt-controller/arm-gic.h>
5 6
@@ -57,6 +58,8 @@
57 resets = <&tegra_car 27>; 58 resets = <&tegra_car 27>;
58 reset-names = "dc"; 59 reset-names = "dc";
59 60
61 iommus = <&mc TEGRA_SWGROUP_DC>;
62
60 nvidia,head = <0>; 63 nvidia,head = <0>;
61 64
62 rgb { 65 rgb {
@@ -74,6 +77,8 @@
74 resets = <&tegra_car 26>; 77 resets = <&tegra_car 26>;
75 reset-names = "dc"; 78 reset-names = "dc";
76 79
80 iommus = <&mc TEGRA_SWGROUP_DCB>;
81
77 nvidia,head = <1>; 82 nvidia,head = <1>;
78 83
79 rgb { 84 rgb {
@@ -505,15 +510,15 @@
505 reset-names = "fuse"; 510 reset-names = "fuse";
506 }; 511 };
507 512
508 iommu@70019010 { 513 mc: memory-controller@70019000 {
509 compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu"; 514 compatible = "nvidia,tegra114-mc";
510 reg = <0x70019010 0x02c 515 reg = <0x70019000 0x1000>;
511 0x700191f0 0x010 516 clocks = <&tegra_car TEGRA114_CLK_MC>;
512 0x70019228 0x074>; 517 clock-names = "mc";
513 nvidia,#asids = <4>; 518
514 dma-window = <0 0x40000000>; 519 interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
515 nvidia,swgroups = <0x18659fe>; 520
516 nvidia,ahb = <&ahb>; 521 #iommu-cells = <1>;
517 }; 522 };
518 523
519 ahub@70080000 { 524 ahub@70080000 {
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 478c555ebd96..a9f3a3e1afc4 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -1,5 +1,6 @@
1#include <dt-bindings/clock/tegra124-car.h> 1#include <dt-bindings/clock/tegra124-car.h>
2#include <dt-bindings/gpio/tegra-gpio.h> 2#include <dt-bindings/gpio/tegra-gpio.h>
3#include <dt-bindings/memory/tegra124-mc.h>
3#include <dt-bindings/pinctrl/pinctrl-tegra.h> 4#include <dt-bindings/pinctrl/pinctrl-tegra.h>
4#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h> 5#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
5#include <dt-bindings/interrupt-controller/arm-gic.h> 6#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -102,6 +103,8 @@
102 resets = <&tegra_car 27>; 103 resets = <&tegra_car 27>;
103 reset-names = "dc"; 104 reset-names = "dc";
104 105
106 iommus = <&mc TEGRA_SWGROUP_DC>;
107
105 nvidia,head = <0>; 108 nvidia,head = <0>;
106 }; 109 };
107 110
@@ -115,6 +118,8 @@
115 resets = <&tegra_car 26>; 118 resets = <&tegra_car 26>;
116 reset-names = "dc"; 119 reset-names = "dc";
117 120
121 iommus = <&mc TEGRA_SWGROUP_DCB>;
122
118 nvidia,head = <1>; 123 nvidia,head = <1>;
119 }; 124 };
120 125
@@ -275,7 +280,8 @@
275 pinmux: pinmux@0,70000868 { 280 pinmux: pinmux@0,70000868 {
276 compatible = "nvidia,tegra124-pinmux"; 281 compatible = "nvidia,tegra124-pinmux";
277 reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */ 282 reg = <0x0 0x70000868 0x0 0x164>, /* Pad control registers */
278 <0x0 0x70003000 0x0 0x434>; /* Mux registers */ 283 <0x0 0x70003000 0x0 0x434>, /* Mux registers */
284 <0x0 0x70000820 0x0 0x008>; /* MIPI pad control */
279 }; 285 };
280 286
281 /* 287 /*
@@ -551,6 +557,17 @@
551 reset-names = "fuse"; 557 reset-names = "fuse";
552 }; 558 };
553 559
560 mc: memory-controller@0,70019000 {
561 compatible = "nvidia,tegra124-mc";
562 reg = <0x0 0x70019000 0x0 0x1000>;
563 clocks = <&tegra_car TEGRA124_CLK_MC>;
564 clock-names = "mc";
565
566 interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
567
568 #iommu-cells = <1>;
569 };
570
554 sata@0,70020000 { 571 sata@0,70020000 {
555 compatible = "nvidia,tegra124-ahci"; 572 compatible = "nvidia,tegra124-ahci";
556 573
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index aa6ccea13d30..976eb9ba8659 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -1,5 +1,6 @@
1#include <dt-bindings/clock/tegra30-car.h> 1#include <dt-bindings/clock/tegra30-car.h>
2#include <dt-bindings/gpio/tegra-gpio.h> 2#include <dt-bindings/gpio/tegra-gpio.h>
3#include <dt-bindings/memory/tegra30-mc.h>
3#include <dt-bindings/pinctrl/pinctrl-tegra.h> 4#include <dt-bindings/pinctrl/pinctrl-tegra.h>
4#include <dt-bindings/interrupt-controller/arm-gic.h> 5#include <dt-bindings/interrupt-controller/arm-gic.h>
5 6
@@ -174,6 +175,8 @@
174 resets = <&tegra_car 27>; 175 resets = <&tegra_car 27>;
175 reset-names = "dc"; 176 reset-names = "dc";
176 177
178 iommus = <&mc TEGRA_SWGROUP_DC>;
179
177 nvidia,head = <0>; 180 nvidia,head = <0>;
178 181
179 rgb { 182 rgb {
@@ -191,6 +194,8 @@
191 resets = <&tegra_car 26>; 194 resets = <&tegra_car 26>;
192 reset-names = "dc"; 195 reset-names = "dc";
193 196
197 iommus = <&mc TEGRA_SWGROUP_DCB>;
198
194 nvidia,head = <1>; 199 nvidia,head = <1>;
195 200
196 rgb { 201 rgb {
@@ -623,23 +628,15 @@
623 clock-names = "pclk", "clk32k_in"; 628 clock-names = "pclk", "clk32k_in";
624 }; 629 };
625 630
626 memory-controller@7000f000 { 631 mc: memory-controller@7000f000 {
627 compatible = "nvidia,tegra30-mc"; 632 compatible = "nvidia,tegra30-mc";
628 reg = <0x7000f000 0x010 633 reg = <0x7000f000 0x400>;
629 0x7000f03c 0x1b4 634 clocks = <&tegra_car TEGRA30_CLK_MC>;
630 0x7000f200 0x028 635 clock-names = "mc";
631 0x7000f284 0x17c>; 636
632 interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>; 637 interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
633 };
634 638
635 iommu@7000f010 { 639 #iommu-cells = <1>;
636 compatible = "nvidia,tegra30-smmu";
637 reg = <0x7000f010 0x02c
638 0x7000f1f0 0x010
639 0x7000f228 0x05c>;
640 nvidia,#asids = <4>; /* # of ASIDs */
641 dma-window = <0 0x40000000>; /* IOVA start & length */
642 nvidia,ahb = <&ahb>;
643 }; 640 };
644 641
645 fuse@7000f800 { 642 fuse@7000f800 {
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 095399618ca5..d0be9a1ef6b8 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -2,6 +2,7 @@ menuconfig ARCH_TEGRA
2 bool "NVIDIA Tegra" if ARCH_MULTI_V7 2 bool "NVIDIA Tegra" if ARCH_MULTI_V7
3 select ARCH_REQUIRE_GPIOLIB 3 select ARCH_REQUIRE_GPIOLIB
4 select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS 4 select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
5 select ARM_AMBA
5 select ARM_GIC 6 select ARM_GIC
6 select CLKSRC_MMIO 7 select CLKSRC_MMIO
7 select HAVE_ARM_SCU if SMP 8 select HAVE_ARM_SCU if SMP
@@ -59,12 +60,4 @@ config ARCH_TEGRA_124_SOC
59 Support for NVIDIA Tegra T124 processor family, based on the 60 Support for NVIDIA Tegra T124 processor family, based on the
60 ARM CortexA15MP CPU 61 ARM CortexA15MP CPU
61 62
62config TEGRA_AHB
63 bool "Enable AHB driver for NVIDIA Tegra SoCs"
64 default y
65 help
66 Adds AHB configuration functionality for NVIDIA Tegra SoCs,
67 which controls AHB bus master arbitration and some
68 performance parameters(priority, prefech size).
69
70endif 63endif
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9532f8d5857e..db1aa5446a57 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -166,9 +166,6 @@ endmenu
166 166
167menu "Bus support" 167menu "Bus support"
168 168
169config ARM_AMBA
170 bool
171
172config PCI 169config PCI
173 bool "PCI support" 170 bool "PCI support"
174 help 171 help
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 42632c7a2a4e..9cfa3706a1b8 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -137,13 +137,16 @@ static inline void set_iommu_table_base_and_group(struct device *dev,
137 iommu_add_device(dev); 137 iommu_add_device(dev);
138} 138}
139 139
140extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl, 140extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
141 struct scatterlist *sglist, int nelems, 141 struct scatterlist *sglist, int nelems,
142 unsigned long mask, enum dma_data_direction direction, 142 unsigned long mask,
143 struct dma_attrs *attrs); 143 enum dma_data_direction direction,
144extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, 144 struct dma_attrs *attrs);
145 int nelems, enum dma_data_direction direction, 145extern void ppc_iommu_unmap_sg(struct iommu_table *tbl,
146 struct dma_attrs *attrs); 146 struct scatterlist *sglist,
147 int nelems,
148 enum dma_data_direction direction,
149 struct dma_attrs *attrs);
147 150
148extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl, 151extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
149 size_t size, dma_addr_t *dma_handle, 152 size_t size, dma_addr_t *dma_handle,
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index 54d0116256f7..4c68bfe4108a 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -60,16 +60,16 @@ static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
60 int nelems, enum dma_data_direction direction, 60 int nelems, enum dma_data_direction direction,
61 struct dma_attrs *attrs) 61 struct dma_attrs *attrs)
62{ 62{
63 return iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems, 63 return ppc_iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems,
64 device_to_mask(dev), direction, attrs); 64 device_to_mask(dev), direction, attrs);
65} 65}
66 66
67static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, 67static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist,
68 int nelems, enum dma_data_direction direction, 68 int nelems, enum dma_data_direction direction,
69 struct dma_attrs *attrs) 69 struct dma_attrs *attrs)
70{ 70{
71 iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems, direction, 71 ppc_iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems,
72 attrs); 72 direction, attrs);
73} 73}
74 74
75/* We support DMA to/from any memory page via the iommu */ 75/* We support DMA to/from any memory page via the iommu */
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index a10642a0d861..a83cf5ef6488 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -428,10 +428,10 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
428 ppc_md.tce_flush(tbl); 428 ppc_md.tce_flush(tbl);
429} 429}
430 430
431int iommu_map_sg(struct device *dev, struct iommu_table *tbl, 431int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
432 struct scatterlist *sglist, int nelems, 432 struct scatterlist *sglist, int nelems,
433 unsigned long mask, enum dma_data_direction direction, 433 unsigned long mask, enum dma_data_direction direction,
434 struct dma_attrs *attrs) 434 struct dma_attrs *attrs)
435{ 435{
436 dma_addr_t dma_next = 0, dma_addr; 436 dma_addr_t dma_next = 0, dma_addr;
437 struct scatterlist *s, *outs, *segstart; 437 struct scatterlist *s, *outs, *segstart;
@@ -539,7 +539,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
539 539
540 DBG("mapped %d elements:\n", outcount); 540 DBG("mapped %d elements:\n", outcount);
541 541
542 /* For the sake of iommu_unmap_sg, we clear out the length in the 542 /* For the sake of ppc_iommu_unmap_sg, we clear out the length in the
543 * next entry of the sglist if we didn't fill the list completely 543 * next entry of the sglist if we didn't fill the list completely
544 */ 544 */
545 if (outcount < incount) { 545 if (outcount < incount) {
@@ -572,9 +572,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
572} 572}
573 573
574 574
575void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, 575void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
576 int nelems, enum dma_data_direction direction, 576 int nelems, enum dma_data_direction direction,
577 struct dma_attrs *attrs) 577 struct dma_attrs *attrs)
578{ 578{
579 struct scatterlist *sg; 579 struct scatterlist *sg;
580 580
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 2b90ff8a93be..c7c8720aa39f 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -621,8 +621,9 @@ static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
621 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) 621 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
622 return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs); 622 return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs);
623 else 623 else
624 return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents, 624 return ppc_iommu_map_sg(dev, cell_get_iommu_table(dev), sg,
625 device_to_mask(dev), direction, attrs); 625 nents, device_to_mask(dev),
626 direction, attrs);
626} 627}
627 628
628static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg, 629static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
@@ -632,8 +633,8 @@ static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
632 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs)) 633 if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
633 dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs); 634 dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs);
634 else 635 else
635 iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction, 636 ppc_iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents,
636 attrs); 637 direction, attrs);
637} 638}
638 639
639static int dma_fixed_dma_supported(struct device *dev, u64 mask) 640static int dma_fixed_dma_supported(struct device *dev, u64 mask)
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1a693d3f9d51..af02a8a8ec4a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
1menu "Device Drivers" 1menu "Device Drivers"
2 2
3source "drivers/amba/Kconfig"
4
3source "drivers/base/Kconfig" 5source "drivers/base/Kconfig"
4 6
5source "drivers/bus/Kconfig" 7source "drivers/bus/Kconfig"
diff --git a/drivers/amba/Kconfig b/drivers/amba/Kconfig
new file mode 100644
index 000000000000..4a5c9d279059
--- /dev/null
+++ b/drivers/amba/Kconfig
@@ -0,0 +1,14 @@
1config ARM_AMBA
2 bool
3
4if ARM_AMBA
5
6config TEGRA_AHB
7 bool "Enable AHB driver for NVIDIA Tegra SoCs"
8 default y if ARCH_TEGRA
9 help
10 Adds AHB configuration functionality for NVIDIA Tegra SoCs,
11 which controls AHB bus master arbitration and some performance
12 parameters (priority, prefetch size).
13
14endif
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 290f9c1a3749..59a5714dfe18 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -185,3 +185,16 @@ struct clk *tegra_clk_register_divider(const char *name,
185 185
186 return clk; 186 return clk;
187} 187}
188
189static const struct clk_div_table mc_div_table[] = {
190 { .val = 0, .div = 2 },
191 { .val = 1, .div = 1 },
192 { .val = 0, .div = 0 },
193};
194
195struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
196 void __iomem *reg, spinlock_t *lock)
197{
198 return clk_register_divider_table(NULL, name, parent_name, 0, reg,
199 16, 1, 0, mc_div_table, lock);
200}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index f760f31d05c4..0b03d2cf7264 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -173,6 +173,7 @@ static DEFINE_SPINLOCK(pll_d_lock);
173static DEFINE_SPINLOCK(pll_d2_lock); 173static DEFINE_SPINLOCK(pll_d2_lock);
174static DEFINE_SPINLOCK(pll_u_lock); 174static DEFINE_SPINLOCK(pll_u_lock);
175static DEFINE_SPINLOCK(pll_re_lock); 175static DEFINE_SPINLOCK(pll_re_lock);
176static DEFINE_SPINLOCK(emc_lock);
176 177
177static struct div_nmp pllxc_nmp = { 178static struct div_nmp pllxc_nmp = {
178 .divm_shift = 0, 179 .divm_shift = 0,
@@ -1228,7 +1229,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
1228 ARRAY_SIZE(mux_pllmcp_clkm), 1229 ARRAY_SIZE(mux_pllmcp_clkm),
1229 CLK_SET_RATE_NO_REPARENT, 1230 CLK_SET_RATE_NO_REPARENT,
1230 clk_base + CLK_SOURCE_EMC, 1231 clk_base + CLK_SOURCE_EMC,
1231 29, 3, 0, NULL); 1232 29, 3, 0, &emc_lock);
1233
1234 clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
1235 &emc_lock);
1236 clks[TEGRA114_CLK_MC] = clk;
1232 1237
1233 for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { 1238 for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
1234 data = &tegra_periph_clk_list[i]; 1239 data = &tegra_periph_clk_list[i];
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index e3a85842ce0c..f5f9baca7bb6 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -132,6 +132,7 @@ static DEFINE_SPINLOCK(pll_d2_lock);
132static DEFINE_SPINLOCK(pll_e_lock); 132static DEFINE_SPINLOCK(pll_e_lock);
133static DEFINE_SPINLOCK(pll_re_lock); 133static DEFINE_SPINLOCK(pll_re_lock);
134static DEFINE_SPINLOCK(pll_u_lock); 134static DEFINE_SPINLOCK(pll_u_lock);
135static DEFINE_SPINLOCK(emc_lock);
135 136
136/* possible OSC frequencies in Hz */ 137/* possible OSC frequencies in Hz */
137static unsigned long tegra124_input_freq[] = { 138static unsigned long tegra124_input_freq[] = {
@@ -1127,7 +1128,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
1127 clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, 1128 clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
1128 ARRAY_SIZE(mux_pllmcp_clkm), 0, 1129 ARRAY_SIZE(mux_pllmcp_clkm), 0,
1129 clk_base + CLK_SOURCE_EMC, 1130 clk_base + CLK_SOURCE_EMC,
1130 29, 3, 0, NULL); 1131 29, 3, 0, &emc_lock);
1132
1133 clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
1134 &emc_lock);
1135 clks[TEGRA124_CLK_MC] = clk;
1131 1136
1132 /* cml0 */ 1137 /* cml0 */
1133 clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, 1138 clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index dace2b1b5ae6..41272dcc9e22 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -140,6 +140,8 @@ static struct cpu_clk_suspend_context {
140static void __iomem *clk_base; 140static void __iomem *clk_base;
141static void __iomem *pmc_base; 141static void __iomem *pmc_base;
142 142
143static DEFINE_SPINLOCK(emc_lock);
144
143#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ 145#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
144 _clk_num, _gate_flags, _clk_id) \ 146 _clk_num, _gate_flags, _clk_id) \
145 TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ 147 TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \
@@ -819,11 +821,15 @@ static void __init tegra20_periph_clk_init(void)
819 ARRAY_SIZE(mux_pllmcp_clkm), 821 ARRAY_SIZE(mux_pllmcp_clkm),
820 CLK_SET_RATE_NO_REPARENT, 822 CLK_SET_RATE_NO_REPARENT,
821 clk_base + CLK_SOURCE_EMC, 823 clk_base + CLK_SOURCE_EMC,
822 30, 2, 0, NULL); 824 30, 2, 0, &emc_lock);
823 clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, 825 clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
824 57, periph_clk_enb_refcnt); 826 57, periph_clk_enb_refcnt);
825 clks[TEGRA20_CLK_EMC] = clk; 827 clks[TEGRA20_CLK_EMC] = clk;
826 828
829 clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
830 &emc_lock);
831 clks[TEGRA20_CLK_MC] = clk;
832
827 /* dsi */ 833 /* dsi */
828 clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, 834 clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0,
829 48, periph_clk_enb_refcnt); 835 48, periph_clk_enb_refcnt);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 5bbacd01094f..4b9d8bd3d0bf 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -177,6 +177,7 @@ static unsigned long input_freq;
177 177
178static DEFINE_SPINLOCK(cml_lock); 178static DEFINE_SPINLOCK(cml_lock);
179static DEFINE_SPINLOCK(pll_d_lock); 179static DEFINE_SPINLOCK(pll_d_lock);
180static DEFINE_SPINLOCK(emc_lock);
180 181
181#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ 182#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
182 _clk_num, _gate_flags, _clk_id) \ 183 _clk_num, _gate_flags, _clk_id) \
@@ -1157,11 +1158,15 @@ static void __init tegra30_periph_clk_init(void)
1157 ARRAY_SIZE(mux_pllmcp_clkm), 1158 ARRAY_SIZE(mux_pllmcp_clkm),
1158 CLK_SET_RATE_NO_REPARENT, 1159 CLK_SET_RATE_NO_REPARENT,
1159 clk_base + CLK_SOURCE_EMC, 1160 clk_base + CLK_SOURCE_EMC,
1160 30, 2, 0, NULL); 1161 30, 2, 0, &emc_lock);
1161 clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, 1162 clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
1162 57, periph_clk_enb_refcnt); 1163 57, periph_clk_enb_refcnt);
1163 clks[TEGRA30_CLK_EMC] = clk; 1164 clks[TEGRA30_CLK_EMC] = clk;
1164 1165
1166 clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
1167 &emc_lock);
1168 clks[TEGRA30_CLK_MC] = clk;
1169
1165 /* cml0 */ 1170 /* cml0 */
1166 clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, 1171 clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
1167 0, 0, &cml_lock); 1172 0, 0, &cml_lock);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 16ec8d6bb87f..4e458aa8d45c 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -86,6 +86,8 @@ struct clk *tegra_clk_register_divider(const char *name,
86 const char *parent_name, void __iomem *reg, 86 const char *parent_name, void __iomem *reg,
87 unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width, 87 unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
88 u8 frac_width, spinlock_t *lock); 88 u8 frac_width, spinlock_t *lock);
89struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
90 void __iomem *reg, spinlock_t *lock);
89 91
90/* 92/*
91 * Tegra PLL: 93 * Tegra PLL:
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dd5112265cc9..6dbfbc209491 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -163,14 +163,14 @@ config TEGRA_IOMMU_GART
163 hardware included on Tegra SoCs. 163 hardware included on Tegra SoCs.
164 164
165config TEGRA_IOMMU_SMMU 165config TEGRA_IOMMU_SMMU
166 bool "Tegra SMMU IOMMU Support" 166 bool "NVIDIA Tegra SMMU Support"
167 depends on ARCH_TEGRA && TEGRA_AHB 167 depends on ARCH_TEGRA
168 depends on TEGRA_AHB
169 depends on TEGRA_MC
168 select IOMMU_API 170 select IOMMU_API
169 help 171 help
170 Enables support for remapping discontiguous physical memory 172 This driver supports the IOMMU hardware (SMMU) found on NVIDIA Tegra
171 shared with the operating system into contiguous I/O virtual 173 SoCs (Tegra30 up to Tegra124).
172 space through the SMMU (System Memory Management Unit)
173 hardware included on Tegra SoCs.
174 174
175config EXYNOS_IOMMU 175config EXYNOS_IOMMU
176 bool "Exynos IOMMU Support" 176 bool "Exynos IOMMU Support"
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 505a9adac2d5..2d84c9edf3b8 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3424,6 +3424,7 @@ static const struct iommu_ops amd_iommu_ops = {
3424 .detach_dev = amd_iommu_detach_device, 3424 .detach_dev = amd_iommu_detach_device,
3425 .map = amd_iommu_map, 3425 .map = amd_iommu_map,
3426 .unmap = amd_iommu_unmap, 3426 .unmap = amd_iommu_unmap,
3427 .map_sg = default_iommu_map_sg,
3427 .iova_to_phys = amd_iommu_iova_to_phys, 3428 .iova_to_phys = amd_iommu_iova_to_phys,
3428 .pgsize_bitmap = AMD_IOMMU_PGSIZES, 3429 .pgsize_bitmap = AMD_IOMMU_PGSIZES,
3429}; 3430};
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 60558f794922..e393ae01b5d2 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1652,6 +1652,7 @@ static const struct iommu_ops arm_smmu_ops = {
1652 .detach_dev = arm_smmu_detach_dev, 1652 .detach_dev = arm_smmu_detach_dev,
1653 .map = arm_smmu_map, 1653 .map = arm_smmu_map,
1654 .unmap = arm_smmu_unmap, 1654 .unmap = arm_smmu_unmap,
1655 .map_sg = default_iommu_map_sg,
1655 .iova_to_phys = arm_smmu_iova_to_phys, 1656 .iova_to_phys = arm_smmu_iova_to_phys,
1656 .add_device = arm_smmu_add_device, 1657 .add_device = arm_smmu_add_device,
1657 .remove_device = arm_smmu_remove_device, 1658 .remove_device = arm_smmu_remove_device,
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 74233186f6f7..28372b85d8da 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1178,6 +1178,7 @@ static const struct iommu_ops exynos_iommu_ops = {
1178 .detach_dev = exynos_iommu_detach_device, 1178 .detach_dev = exynos_iommu_detach_device,
1179 .map = exynos_iommu_map, 1179 .map = exynos_iommu_map,
1180 .unmap = exynos_iommu_unmap, 1180 .unmap = exynos_iommu_unmap,
1181 .map_sg = default_iommu_map_sg,
1181 .iova_to_phys = exynos_iommu_iova_to_phys, 1182 .iova_to_phys = exynos_iommu_iova_to_phys,
1182 .add_device = exynos_iommu_add_device, 1183 .add_device = exynos_iommu_add_device,
1183 .remove_device = exynos_iommu_remove_device, 1184 .remove_device = exynos_iommu_remove_device,
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a27d6cb1a793..02cd26a17fe0 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4467,6 +4467,7 @@ static const struct iommu_ops intel_iommu_ops = {
4467 .detach_dev = intel_iommu_detach_device, 4467 .detach_dev = intel_iommu_detach_device,
4468 .map = intel_iommu_map, 4468 .map = intel_iommu_map,
4469 .unmap = intel_iommu_unmap, 4469 .unmap = intel_iommu_unmap,
4470 .map_sg = default_iommu_map_sg,
4470 .iova_to_phys = intel_iommu_iova_to_phys, 4471 .iova_to_phys = intel_iommu_iova_to_phys,
4471 .add_device = intel_iommu_add_device, 4472 .add_device = intel_iommu_add_device,
4472 .remove_device = intel_iommu_remove_device, 4473 .remove_device = intel_iommu_remove_device,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ed8b04867b1f..02e4313e937c 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -818,7 +818,15 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
818 kfree(nb); 818 kfree(nb);
819 return err; 819 return err;
820 } 820 }
821 return bus_for_each_dev(bus, NULL, &cb, add_iommu_group); 821
822 err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
823 if (err) {
824 bus_unregister_notifier(bus, nb);
825 kfree(nb);
826 return err;
827 }
828
829 return 0;
822} 830}
823 831
824/** 832/**
@@ -836,13 +844,19 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
836 */ 844 */
837int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops) 845int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
838{ 846{
847 int err;
848
839 if (bus->iommu_ops != NULL) 849 if (bus->iommu_ops != NULL)
840 return -EBUSY; 850 return -EBUSY;
841 851
842 bus->iommu_ops = ops; 852 bus->iommu_ops = ops;
843 853
844 /* Do IOMMU specific setup for this bus-type */ 854 /* Do IOMMU specific setup for this bus-type */
845 return iommu_bus_init(bus, ops); 855 err = iommu_bus_init(bus, ops);
856 if (err)
857 bus->iommu_ops = NULL;
858
859 return err;
846} 860}
847EXPORT_SYMBOL_GPL(bus_set_iommu); 861EXPORT_SYMBOL_GPL(bus_set_iommu);
848 862
@@ -1124,6 +1138,38 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
1124} 1138}
1125EXPORT_SYMBOL_GPL(iommu_unmap); 1139EXPORT_SYMBOL_GPL(iommu_unmap);
1126 1140
1141size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
1142 struct scatterlist *sg, unsigned int nents, int prot)
1143{
1144 struct scatterlist *s;
1145 size_t mapped = 0;
1146 unsigned int i;
1147 int ret;
1148
1149 for_each_sg(sg, s, nents, i) {
1150 phys_addr_t phys = page_to_phys(sg_page(s));
1151
1152 /* We are mapping on page boundarys, so offset must be 0 */
1153 if (s->offset)
1154 goto out_err;
1155
1156 ret = iommu_map(domain, iova + mapped, phys, s->length, prot);
1157 if (ret)
1158 goto out_err;
1159
1160 mapped += s->length;
1161 }
1162
1163 return mapped;
1164
1165out_err:
1166 /* undo mappings already done */
1167 iommu_unmap(domain, iova, mapped);
1168
1169 return 0;
1170
1171}
1172EXPORT_SYMBOL_GPL(default_iommu_map_sg);
1127 1173
1128int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, 1174int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
1129 phys_addr_t paddr, u64 size, int prot) 1175 phys_addr_t paddr, u64 size, int prot)
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 7dab5cbcc775..e509c58eee92 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -1127,6 +1127,7 @@ static const struct iommu_ops ipmmu_ops = {
1127 .detach_dev = ipmmu_detach_device, 1127 .detach_dev = ipmmu_detach_device,
1128 .map = ipmmu_map, 1128 .map = ipmmu_map,
1129 .unmap = ipmmu_unmap, 1129 .unmap = ipmmu_unmap,
1130 .map_sg = default_iommu_map_sg,
1130 .iova_to_phys = ipmmu_iova_to_phys, 1131 .iova_to_phys = ipmmu_iova_to_phys,
1131 .add_device = ipmmu_add_device, 1132 .add_device = ipmmu_add_device,
1132 .remove_device = ipmmu_remove_device, 1133 .remove_device = ipmmu_remove_device,
diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c
index 6e3dcc289d59..1c7b78ecf3e3 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -681,6 +681,7 @@ static const struct iommu_ops msm_iommu_ops = {
681 .detach_dev = msm_iommu_detach_dev, 681 .detach_dev = msm_iommu_detach_dev,
682 .map = msm_iommu_map, 682 .map = msm_iommu_map,
683 .unmap = msm_iommu_unmap, 683 .unmap = msm_iommu_unmap,
684 .map_sg = default_iommu_map_sg,
684 .iova_to_phys = msm_iommu_iova_to_phys, 685 .iova_to_phys = msm_iommu_iova_to_phys,
685 .pgsize_bitmap = MSM_IOMMU_PGSIZES, 686 .pgsize_bitmap = MSM_IOMMU_PGSIZES,
686}; 687};
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 36278870e84a..18003c044454 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1288,6 +1288,7 @@ static const struct iommu_ops omap_iommu_ops = {
1288 .detach_dev = omap_iommu_detach_dev, 1288 .detach_dev = omap_iommu_detach_dev,
1289 .map = omap_iommu_map, 1289 .map = omap_iommu_map,
1290 .unmap = omap_iommu_unmap, 1290 .unmap = omap_iommu_unmap,
1291 .map_sg = default_iommu_map_sg,
1291 .iova_to_phys = omap_iommu_iova_to_phys, 1292 .iova_to_phys = omap_iommu_iova_to_phys,
1292 .add_device = omap_iommu_add_device, 1293 .add_device = omap_iommu_add_device,
1293 .remove_device = omap_iommu_remove_device, 1294 .remove_device = omap_iommu_remove_device,
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c
index 1333e6fb3405..f1b00774e4de 100644
--- a/drivers/iommu/shmobile-iommu.c
+++ b/drivers/iommu/shmobile-iommu.c
@@ -361,6 +361,7 @@ static const struct iommu_ops shmobile_iommu_ops = {
361 .detach_dev = shmobile_iommu_detach_device, 361 .detach_dev = shmobile_iommu_detach_device,
362 .map = shmobile_iommu_map, 362 .map = shmobile_iommu_map,
363 .unmap = shmobile_iommu_unmap, 363 .unmap = shmobile_iommu_unmap,
364 .map_sg = default_iommu_map_sg,
364 .iova_to_phys = shmobile_iommu_iova_to_phys, 365 .iova_to_phys = shmobile_iommu_iova_to_phys,
365 .add_device = shmobile_iommu_add_device, 366 .add_device = shmobile_iommu_add_device,
366 .pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K, 367 .pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K,
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 3afdf43f732a..6e134c7c227f 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -1,1295 +1,732 @@
1/* 1/*
2 * IOMMU API for SMMU in Tegra30 2 * Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved.
3 * 3 *
4 * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved. 4 * This program is free software; you can redistribute it and/or modify
5 * 5 * it under the terms of the GNU General Public License version 2 as
6 * This program is free software; you can redistribute it and/or modify it 6 * published by the Free Software Foundation.
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 */ 7 */
19 8
20#define pr_fmt(fmt) "%s(): " fmt, __func__
21
22#include <linux/err.h> 9#include <linux/err.h>
23#include <linux/module.h>
24#include <linux/platform_device.h>
25#include <linux/spinlock.h>
26#include <linux/slab.h>
27#include <linux/vmalloc.h>
28#include <linux/mm.h>
29#include <linux/pagemap.h>
30#include <linux/device.h>
31#include <linux/sched.h>
32#include <linux/iommu.h> 10#include <linux/iommu.h>
33#include <linux/io.h> 11#include <linux/kernel.h>
34#include <linux/of.h> 12#include <linux/of.h>
35#include <linux/of_iommu.h> 13#include <linux/of_device.h>
36#include <linux/debugfs.h> 14#include <linux/platform_device.h>
37#include <linux/seq_file.h> 15#include <linux/slab.h>
38 16
39#include <soc/tegra/ahb.h> 17#include <soc/tegra/ahb.h>
18#include <soc/tegra/mc.h>
40 19
41#include <asm/page.h> 20struct tegra_smmu {
42#include <asm/cacheflush.h> 21 void __iomem *regs;
43 22 struct device *dev;
44enum smmu_hwgrp {
45 HWGRP_AFI,
46 HWGRP_AVPC,
47 HWGRP_DC,
48 HWGRP_DCB,
49 HWGRP_EPP,
50 HWGRP_G2,
51 HWGRP_HC,
52 HWGRP_HDA,
53 HWGRP_ISP,
54 HWGRP_MPE,
55 HWGRP_NV,
56 HWGRP_NV2,
57 HWGRP_PPCS,
58 HWGRP_SATA,
59 HWGRP_VDE,
60 HWGRP_VI,
61
62 HWGRP_COUNT,
63
64 HWGRP_END = ~0,
65};
66 23
67#define HWG_AFI (1 << HWGRP_AFI) 24 struct tegra_mc *mc;
68#define HWG_AVPC (1 << HWGRP_AVPC) 25 const struct tegra_smmu_soc *soc;
69#define HWG_DC (1 << HWGRP_DC)
70#define HWG_DCB (1 << HWGRP_DCB)
71#define HWG_EPP (1 << HWGRP_EPP)
72#define HWG_G2 (1 << HWGRP_G2)
73#define HWG_HC (1 << HWGRP_HC)
74#define HWG_HDA (1 << HWGRP_HDA)
75#define HWG_ISP (1 << HWGRP_ISP)
76#define HWG_MPE (1 << HWGRP_MPE)
77#define HWG_NV (1 << HWGRP_NV)
78#define HWG_NV2 (1 << HWGRP_NV2)
79#define HWG_PPCS (1 << HWGRP_PPCS)
80#define HWG_SATA (1 << HWGRP_SATA)
81#define HWG_VDE (1 << HWGRP_VDE)
82#define HWG_VI (1 << HWGRP_VI)
83
84/* bitmap of the page sizes currently supported */
85#define SMMU_IOMMU_PGSIZES (SZ_4K)
86
87#define SMMU_CONFIG 0x10
88#define SMMU_CONFIG_DISABLE 0
89#define SMMU_CONFIG_ENABLE 1
90
91/* REVISIT: To support multiple MCs */
92enum {
93 _MC = 0,
94};
95 26
96enum { 27 unsigned long *asids;
97 _TLB = 0, 28 struct mutex lock;
98 _PTC,
99};
100 29
101#define SMMU_CACHE_CONFIG_BASE 0x14 30 struct list_head list;
102#define __SMMU_CACHE_CONFIG(mc, cache) (SMMU_CACHE_CONFIG_BASE + 4 * cache)
103#define SMMU_CACHE_CONFIG(cache) __SMMU_CACHE_CONFIG(_MC, cache)
104
105#define SMMU_CACHE_CONFIG_STATS_SHIFT 31
106#define SMMU_CACHE_CONFIG_STATS_ENABLE (1 << SMMU_CACHE_CONFIG_STATS_SHIFT)
107#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT 30
108#define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
109
110#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
111#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10
112#define SMMU_TLB_CONFIG_RESET_VAL 0x20000010
113
114#define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29)
115#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f
116#define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f
117
118#define SMMU_PTB_ASID 0x1c
119#define SMMU_PTB_ASID_CURRENT_SHIFT 0
120
121#define SMMU_PTB_DATA 0x20
122#define SMMU_PTB_DATA_RESET_VAL 0
123#define SMMU_PTB_DATA_ASID_NONSECURE_SHIFT 29
124#define SMMU_PTB_DATA_ASID_WRITABLE_SHIFT 30
125#define SMMU_PTB_DATA_ASID_READABLE_SHIFT 31
126
127#define SMMU_TLB_FLUSH 0x30
128#define SMMU_TLB_FLUSH_VA_MATCH_ALL 0
129#define SMMU_TLB_FLUSH_VA_MATCH_SECTION 2
130#define SMMU_TLB_FLUSH_VA_MATCH_GROUP 3
131#define SMMU_TLB_FLUSH_ASID_SHIFT 29
132#define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE 0
133#define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE 1
134#define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT 31
135
136#define SMMU_PTC_FLUSH 0x34
137#define SMMU_PTC_FLUSH_TYPE_ALL 0
138#define SMMU_PTC_FLUSH_TYPE_ADR 1
139#define SMMU_PTC_FLUSH_ADR_SHIFT 4
140
141#define SMMU_ASID_SECURITY 0x38
142
143#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0
144
145#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss) \
146 (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
147
148#define SMMU_TRANSLATION_ENABLE_0 0x228
149#define SMMU_TRANSLATION_ENABLE_1 0x22c
150#define SMMU_TRANSLATION_ENABLE_2 0x230
151
152#define SMMU_AFI_ASID 0x238 /* PCIE */
153#define SMMU_AVPC_ASID 0x23c /* AVP */
154#define SMMU_DC_ASID 0x240 /* Display controller */
155#define SMMU_DCB_ASID 0x244 /* Display controller B */
156#define SMMU_EPP_ASID 0x248 /* Encoder pre-processor */
157#define SMMU_G2_ASID 0x24c /* 2D engine */
158#define SMMU_HC_ASID 0x250 /* Host1x */
159#define SMMU_HDA_ASID 0x254 /* High-def audio */
160#define SMMU_ISP_ASID 0x258 /* Image signal processor */
161#define SMMU_MPE_ASID 0x264 /* MPEG encoder */
162#define SMMU_NV_ASID 0x268 /* (3D) */
163#define SMMU_NV2_ASID 0x26c /* (3D) */
164#define SMMU_PPCS_ASID 0x270 /* AHB */
165#define SMMU_SATA_ASID 0x278 /* SATA */
166#define SMMU_VDE_ASID 0x27c /* Video decoder */
167#define SMMU_VI_ASID 0x280 /* Video input */
168
169#define SMMU_PDE_NEXT_SHIFT 28
170
171#define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000
172#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */
173#define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000
174#define SMMU_TLB_FLUSH_VA_GROUP__SHIFT 12 /* right shift */
175#define SMMU_TLB_FLUSH_VA(iova, which) \
176 ((((iova) & SMMU_TLB_FLUSH_VA_##which##__MASK) >> \
177 SMMU_TLB_FLUSH_VA_##which##__SHIFT) | \
178 SMMU_TLB_FLUSH_VA_MATCH_##which)
179#define SMMU_PTB_ASID_CUR(n) \
180 ((n) << SMMU_PTB_ASID_CURRENT_SHIFT)
181#define SMMU_TLB_FLUSH_ASID_MATCH_disable \
182 (SMMU_TLB_FLUSH_ASID_MATCH_DISABLE << \
183 SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
184#define SMMU_TLB_FLUSH_ASID_MATCH__ENABLE \
185 (SMMU_TLB_FLUSH_ASID_MATCH_ENABLE << \
186 SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
187
188#define SMMU_PAGE_SHIFT 12
189#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
190#define SMMU_PAGE_MASK ((1 << SMMU_PAGE_SHIFT) - 1)
191
192#define SMMU_PDIR_COUNT 1024
193#define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT)
194#define SMMU_PTBL_COUNT 1024
195#define SMMU_PTBL_SIZE (sizeof(unsigned long) * SMMU_PTBL_COUNT)
196#define SMMU_PDIR_SHIFT 12
197#define SMMU_PDE_SHIFT 12
198#define SMMU_PTE_SHIFT 12
199#define SMMU_PFN_MASK 0x000fffff
200
201#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
202#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
203#define SMMU_PDN_TO_ADDR(pdn) ((pdn) << 22)
204
205#define _READABLE (1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT)
206#define _WRITABLE (1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT)
207#define _NONSECURE (1 << SMMU_PTB_DATA_ASID_NONSECURE_SHIFT)
208#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
209#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
210
211#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
212
213#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
214#define _PDE_ATTR_N (_PDE_ATTR | _PDE_NEXT)
215#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
216
217#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
218#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
219
220#define SMMU_MK_PDIR(page, attr) \
221 ((page_to_phys(page) >> SMMU_PDIR_SHIFT) | (attr))
222#define SMMU_MK_PDE(page, attr) \
223 (unsigned long)((page_to_phys(page) >> SMMU_PDE_SHIFT) | (attr))
224#define SMMU_EX_PTBL_PAGE(pde) \
225 pfn_to_page((unsigned long)(pde) & SMMU_PFN_MASK)
226#define SMMU_PFN_TO_PTE(pfn, attr) (unsigned long)((pfn) | (attr))
227
228#define SMMU_ASID_ENABLE(asid) ((asid) | (1 << 31))
229#define SMMU_ASID_DISABLE 0
230#define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0))
231
232#define NUM_SMMU_REG_BANKS 3
233
234#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
235#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0)
236#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
237#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
238
239#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
240
241static const u32 smmu_hwgrp_asid_reg[] = {
242 HWGRP_INIT(AFI),
243 HWGRP_INIT(AVPC),
244 HWGRP_INIT(DC),
245 HWGRP_INIT(DCB),
246 HWGRP_INIT(EPP),
247 HWGRP_INIT(G2),
248 HWGRP_INIT(HC),
249 HWGRP_INIT(HDA),
250 HWGRP_INIT(ISP),
251 HWGRP_INIT(MPE),
252 HWGRP_INIT(NV),
253 HWGRP_INIT(NV2),
254 HWGRP_INIT(PPCS),
255 HWGRP_INIT(SATA),
256 HWGRP_INIT(VDE),
257 HWGRP_INIT(VI),
258}; 31};
259#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
260 32
261/* 33struct tegra_smmu_as {
262 * Per client for address space 34 struct iommu_domain *domain;
263 */ 35 struct tegra_smmu *smmu;
264struct smmu_client { 36 unsigned int use_count;
265 struct device *dev; 37 struct page *count;
266 struct list_head list; 38 struct page *pd;
267 struct smmu_as *as; 39 unsigned id;
268 u32 hwgrp; 40 u32 attr;
269}; 41};
270 42
271/* 43static inline void smmu_writel(struct tegra_smmu *smmu, u32 value,
272 * Per address space 44 unsigned long offset)
273 */ 45{
274struct smmu_as { 46 writel(value, smmu->regs + offset);
275 struct smmu_device *smmu; /* back pointer to container */ 47}
276 unsigned int asid;
277 spinlock_t lock; /* for pagetable */
278 struct page *pdir_page;
279 unsigned long pdir_attr;
280 unsigned long pde_attr;
281 unsigned long pte_attr;
282 unsigned int *pte_count;
283
284 struct list_head client;
285 spinlock_t client_lock; /* for client list */
286};
287 48
288struct smmu_debugfs_info { 49static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
289 struct smmu_device *smmu; 50{
290 int mc; 51 return readl(smmu->regs + offset);
291 int cache; 52}
292};
293 53
294/* 54#define SMMU_CONFIG 0x010
295 * Per SMMU device - IOMMU device 55#define SMMU_CONFIG_ENABLE (1 << 0)
296 */
297struct smmu_device {
298 void __iomem *regbase; /* register offset base */
299 void __iomem **regs; /* register block start address array */
300 void __iomem **rege; /* register block end address array */
301 int nregs; /* number of register blocks */
302
303 unsigned long iovmm_base; /* remappable base address */
304 unsigned long page_count; /* total remappable size */
305 spinlock_t lock;
306 char *name;
307 struct device *dev;
308 struct page *avp_vector_page; /* dummy page shared by all AS's */
309 56
310 /* 57#define SMMU_TLB_CONFIG 0x14
311 * Register image savers for suspend/resume 58#define SMMU_TLB_CONFIG_HIT_UNDER_MISS (1 << 29)
312 */ 59#define SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION (1 << 28)
313 unsigned long translation_enable_0; 60#define SMMU_TLB_CONFIG_ACTIVE_LINES(x) ((x) & 0x3f)
314 unsigned long translation_enable_1;
315 unsigned long translation_enable_2;
316 unsigned long asid_security;
317 61
318 struct dentry *debugfs_root; 62#define SMMU_PTC_CONFIG 0x18
319 struct smmu_debugfs_info *debugfs_info; 63#define SMMU_PTC_CONFIG_ENABLE (1 << 29)
64#define SMMU_PTC_CONFIG_REQ_LIMIT(x) (((x) & 0x0f) << 24)
65#define SMMU_PTC_CONFIG_INDEX_MAP(x) ((x) & 0x3f)
320 66
321 struct device_node *ahb; 67#define SMMU_PTB_ASID 0x01c
68#define SMMU_PTB_ASID_VALUE(x) ((x) & 0x7f)
322 69
323 int num_as; 70#define SMMU_PTB_DATA 0x020
324 struct smmu_as as[0]; /* Run-time allocated array */ 71#define SMMU_PTB_DATA_VALUE(page, attr) (page_to_phys(page) >> 12 | (attr))
325};
326 72
327static struct smmu_device *smmu_handle; /* unique for a system */ 73#define SMMU_MK_PDE(page, attr) (page_to_phys(page) >> SMMU_PTE_SHIFT | (attr))
328 74
329/* 75#define SMMU_TLB_FLUSH 0x030
330 * SMMU register accessors 76#define SMMU_TLB_FLUSH_VA_MATCH_ALL (0 << 0)
331 */ 77#define SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0)
332static bool inline smmu_valid_reg(struct smmu_device *smmu, 78#define SMMU_TLB_FLUSH_VA_MATCH_GROUP (3 << 0)
333 void __iomem *addr) 79#define SMMU_TLB_FLUSH_ASID(x) (((x) & 0x7f) << 24)
334{ 80#define SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \
335 int i; 81 SMMU_TLB_FLUSH_VA_MATCH_SECTION)
82#define SMMU_TLB_FLUSH_VA_GROUP(addr) ((((addr) & 0xffffc000) >> 12) | \
83 SMMU_TLB_FLUSH_VA_MATCH_GROUP)
84#define SMMU_TLB_FLUSH_ASID_MATCH (1 << 31)
336 85
337 for (i = 0; i < smmu->nregs; i++) { 86#define SMMU_PTC_FLUSH 0x034
338 if (addr < smmu->regs[i]) 87#define SMMU_PTC_FLUSH_TYPE_ALL (0 << 0)
339 break; 88#define SMMU_PTC_FLUSH_TYPE_ADR (1 << 0)
340 if (addr <= smmu->rege[i])
341 return true;
342 }
343 89
344 return false; 90#define SMMU_PTC_FLUSH_HI 0x9b8
345} 91#define SMMU_PTC_FLUSH_HI_MASK 0x3
346 92
347static inline u32 smmu_read(struct smmu_device *smmu, size_t offs) 93/* per-SWGROUP SMMU_*_ASID register */
348{ 94#define SMMU_ASID_ENABLE (1 << 31)
349 void __iomem *addr = smmu->regbase + offs; 95#define SMMU_ASID_MASK 0x7f
96#define SMMU_ASID_VALUE(x) ((x) & SMMU_ASID_MASK)
350 97
351 BUG_ON(!smmu_valid_reg(smmu, addr)); 98/* page table definitions */
99#define SMMU_NUM_PDE 1024
100#define SMMU_NUM_PTE 1024
352 101
353 return readl(addr); 102#define SMMU_SIZE_PD (SMMU_NUM_PDE * 4)
354} 103#define SMMU_SIZE_PT (SMMU_NUM_PTE * 4)
355 104
356static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) 105#define SMMU_PDE_SHIFT 22
357{ 106#define SMMU_PTE_SHIFT 12
358 void __iomem *addr = smmu->regbase + offs;
359 107
360 BUG_ON(!smmu_valid_reg(smmu, addr)); 108#define SMMU_PFN_MASK 0x000fffff
361 109
362 writel(val, addr); 110#define SMMU_PD_READABLE (1 << 31)
363} 111#define SMMU_PD_WRITABLE (1 << 30)
112#define SMMU_PD_NONSECURE (1 << 29)
364 113
365#define VA_PAGE_TO_PA(va, page) \ 114#define SMMU_PDE_READABLE (1 << 31)
366 (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK)) 115#define SMMU_PDE_WRITABLE (1 << 30)
116#define SMMU_PDE_NONSECURE (1 << 29)
117#define SMMU_PDE_NEXT (1 << 28)
367 118
368#define FLUSH_CPU_DCACHE(va, page, size) \ 119#define SMMU_PTE_READABLE (1 << 31)
369 do { \ 120#define SMMU_PTE_WRITABLE (1 << 30)
370 unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \ 121#define SMMU_PTE_NONSECURE (1 << 29)
371 __cpuc_flush_dcache_area((void *)(va), (size_t)(size)); \
372 outer_flush_range(_pa_, _pa_+(size_t)(size)); \
373 } while (0)
374 122
375/* 123#define SMMU_PDE_ATTR (SMMU_PDE_READABLE | SMMU_PDE_WRITABLE | \
376 * Any interaction between any block on PPSB and a block on APB or AHB 124 SMMU_PDE_NONSECURE)
377 * must have these read-back barriers to ensure the APB/AHB bus 125#define SMMU_PTE_ATTR (SMMU_PTE_READABLE | SMMU_PTE_WRITABLE | \
378 * transaction is complete before initiating activity on the PPSB 126 SMMU_PTE_NONSECURE)
379 * block.
380 */
381#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
382 127
383#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data) 128static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
384 129 unsigned long offset)
385static int __smmu_client_set_hwgrp(struct smmu_client *c,
386 unsigned long map, int on)
387{ 130{
388 int i; 131 phys_addr_t phys = page ? page_to_phys(page) : 0;
389 struct smmu_as *as = c->as; 132 u32 value;
390 u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid); 133
391 struct smmu_device *smmu = as->smmu; 134 if (page) {
392 135 offset &= ~(smmu->mc->soc->atom_size - 1);
393 WARN_ON(!on && map); 136
394 if (on && !map) 137 if (smmu->mc->soc->num_address_bits > 32) {
395 return -EINVAL; 138#ifdef CONFIG_PHYS_ADDR_T_64BIT
396 if (!on) 139 value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK;
397 map = smmu_client_hwgrp(c); 140#else
398 141 value = 0;
399 for_each_set_bit(i, &map, HWGRP_COUNT) { 142#endif
400 offs = HWGRP_ASID_REG(i); 143 smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI);
401 val = smmu_read(smmu, offs);
402 if (on) {
403 if (WARN_ON(val & mask))
404 goto err_hw_busy;
405 val |= mask;
406 } else {
407 WARN_ON((val & mask) == mask);
408 val &= ~mask;
409 } 144 }
410 smmu_write(smmu, val, offs);
411 }
412 FLUSH_SMMU_REGS(smmu);
413 c->hwgrp = map;
414 return 0;
415 145
416err_hw_busy: 146 value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
417 for_each_set_bit(i, &map, HWGRP_COUNT) { 147 } else {
418 offs = HWGRP_ASID_REG(i); 148 value = SMMU_PTC_FLUSH_TYPE_ALL;
419 val = smmu_read(smmu, offs);
420 val &= ~mask;
421 smmu_write(smmu, val, offs);
422 } 149 }
423 return -EBUSY; 150
151 smmu_writel(smmu, value, SMMU_PTC_FLUSH);
424} 152}
425 153
426static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on) 154static inline void smmu_flush_tlb(struct tegra_smmu *smmu)
427{ 155{
428 u32 val; 156 smmu_writel(smmu, SMMU_TLB_FLUSH_VA_MATCH_ALL, SMMU_TLB_FLUSH);
429 unsigned long flags;
430 struct smmu_as *as = c->as;
431 struct smmu_device *smmu = as->smmu;
432
433 spin_lock_irqsave(&smmu->lock, flags);
434 val = __smmu_client_set_hwgrp(c, map, on);
435 spin_unlock_irqrestore(&smmu->lock, flags);
436 return val;
437} 157}
438 158
439/* 159static inline void smmu_flush_tlb_asid(struct tegra_smmu *smmu,
440 * Flush all TLB entries and all PTC entries 160 unsigned long asid)
441 * Caller must lock smmu
442 */
443static void smmu_flush_regs(struct smmu_device *smmu, int enable)
444{ 161{
445 u32 val; 162 u32 value;
446
447 smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
448 FLUSH_SMMU_REGS(smmu);
449 val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
450 SMMU_TLB_FLUSH_ASID_MATCH_disable;
451 smmu_write(smmu, val, SMMU_TLB_FLUSH);
452 163
453 if (enable) 164 value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
454 smmu_write(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG); 165 SMMU_TLB_FLUSH_VA_MATCH_ALL;
455 FLUSH_SMMU_REGS(smmu); 166 smmu_writel(smmu, value, SMMU_TLB_FLUSH);
456} 167}
457 168
458static int smmu_setup_regs(struct smmu_device *smmu) 169static inline void smmu_flush_tlb_section(struct tegra_smmu *smmu,
170 unsigned long asid,
171 unsigned long iova)
459{ 172{
460 int i; 173 u32 value;
461 u32 val;
462 174
463 for (i = 0; i < smmu->num_as; i++) { 175 value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
464 struct smmu_as *as = &smmu->as[i]; 176 SMMU_TLB_FLUSH_VA_SECTION(iova);
465 struct smmu_client *c; 177 smmu_writel(smmu, value, SMMU_TLB_FLUSH);
466
467 smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
468 val = as->pdir_page ?
469 SMMU_MK_PDIR(as->pdir_page, as->pdir_attr) :
470 SMMU_PTB_DATA_RESET_VAL;
471 smmu_write(smmu, val, SMMU_PTB_DATA);
472
473 list_for_each_entry(c, &as->client, list)
474 __smmu_client_set_hwgrp(c, c->hwgrp, 1);
475 }
476
477 smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
478 smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
479 smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
480 smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
481 smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
482 smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
483
484 smmu_flush_regs(smmu, 1);
485
486 return tegra_ahb_enable_smmu(smmu->ahb);
487} 178}
488 179
489static void flush_ptc_and_tlb(struct smmu_device *smmu, 180static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu,
490 struct smmu_as *as, dma_addr_t iova, 181 unsigned long asid,
491 unsigned long *pte, struct page *page, int is_pde) 182 unsigned long iova)
492{ 183{
493 u32 val; 184 u32 value;
494 unsigned long tlb_flush_va = is_pde
495 ? SMMU_TLB_FLUSH_VA(iova, SECTION)
496 : SMMU_TLB_FLUSH_VA(iova, GROUP);
497
498 val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
499 smmu_write(smmu, val, SMMU_PTC_FLUSH);
500 FLUSH_SMMU_REGS(smmu);
501 val = tlb_flush_va |
502 SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
503 (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
504 smmu_write(smmu, val, SMMU_TLB_FLUSH);
505 FLUSH_SMMU_REGS(smmu);
506}
507 185
508static void free_ptbl(struct smmu_as *as, dma_addr_t iova) 186 value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
509{ 187 SMMU_TLB_FLUSH_VA_GROUP(iova);
510 unsigned long pdn = SMMU_ADDR_TO_PDN(iova); 188 smmu_writel(smmu, value, SMMU_TLB_FLUSH);
511 unsigned long *pdir = (unsigned long *)page_address(as->pdir_page);
512
513 if (pdir[pdn] != _PDE_VACANT(pdn)) {
514 dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn);
515
516 ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn]));
517 __free_page(SMMU_EX_PTBL_PAGE(pdir[pdn]));
518 pdir[pdn] = _PDE_VACANT(pdn);
519 FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
520 flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
521 as->pdir_page, 1);
522 }
523} 189}
524 190
525static void free_pdir(struct smmu_as *as) 191static inline void smmu_flush(struct tegra_smmu *smmu)
526{ 192{
527 unsigned addr; 193 smmu_readl(smmu, SMMU_CONFIG);
528 int count;
529 struct device *dev = as->smmu->dev;
530
531 if (!as->pdir_page)
532 return;
533
534 addr = as->smmu->iovmm_base;
535 count = as->smmu->page_count;
536 while (count-- > 0) {
537 free_ptbl(as, addr);
538 addr += SMMU_PAGE_SIZE * SMMU_PTBL_COUNT;
539 }
540 ClearPageReserved(as->pdir_page);
541 __free_page(as->pdir_page);
542 as->pdir_page = NULL;
543 devm_kfree(dev, as->pte_count);
544 as->pte_count = NULL;
545} 194}
546 195
547/* 196static int tegra_smmu_alloc_asid(struct tegra_smmu *smmu, unsigned int *idp)
548 * Maps PTBL for given iova and returns the PTE address
549 * Caller must unmap the mapped PTBL returned in *ptbl_page_p
550 */
551static unsigned long *locate_pte(struct smmu_as *as,
552 dma_addr_t iova, bool allocate,
553 struct page **ptbl_page_p,
554 unsigned int **count)
555{ 197{
556 unsigned long ptn = SMMU_ADDR_TO_PFN(iova); 198 unsigned long id;
557 unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
558 unsigned long *pdir = page_address(as->pdir_page);
559 unsigned long *ptbl;
560
561 if (pdir[pdn] != _PDE_VACANT(pdn)) {
562 /* Mapped entry table already exists */
563 *ptbl_page_p = SMMU_EX_PTBL_PAGE(pdir[pdn]);
564 ptbl = page_address(*ptbl_page_p);
565 } else if (!allocate) {
566 return NULL;
567 } else {
568 int pn;
569 unsigned long addr = SMMU_PDN_TO_ADDR(pdn);
570 199
571 /* Vacant - allocate a new page table */ 200 mutex_lock(&smmu->lock);
572 dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn);
573 201
574 *ptbl_page_p = alloc_page(GFP_ATOMIC); 202 id = find_first_zero_bit(smmu->asids, smmu->soc->num_asids);
575 if (!*ptbl_page_p) { 203 if (id >= smmu->soc->num_asids) {
576 dev_err(as->smmu->dev, 204 mutex_unlock(&smmu->lock);
577 "failed to allocate smmu_device page table\n"); 205 return -ENOSPC;
578 return NULL;
579 }
580 SetPageReserved(*ptbl_page_p);
581 ptbl = (unsigned long *)page_address(*ptbl_page_p);
582 for (pn = 0; pn < SMMU_PTBL_COUNT;
583 pn++, addr += SMMU_PAGE_SIZE) {
584 ptbl[pn] = _PTE_VACANT(addr);
585 }
586 FLUSH_CPU_DCACHE(ptbl, *ptbl_page_p, SMMU_PTBL_SIZE);
587 pdir[pdn] = SMMU_MK_PDE(*ptbl_page_p,
588 as->pde_attr | _PDE_NEXT);
589 FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
590 flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
591 as->pdir_page, 1);
592 } 206 }
593 *count = &as->pte_count[pdn];
594 207
595 return &ptbl[ptn % SMMU_PTBL_COUNT]; 208 set_bit(id, smmu->asids);
209 *idp = id;
210
211 mutex_unlock(&smmu->lock);
212 return 0;
596} 213}
597 214
598#ifdef CONFIG_SMMU_SIG_DEBUG 215static void tegra_smmu_free_asid(struct tegra_smmu *smmu, unsigned int id)
599static void put_signature(struct smmu_as *as,
600 dma_addr_t iova, unsigned long pfn)
601{ 216{
602 struct page *page; 217 mutex_lock(&smmu->lock);
603 unsigned long *vaddr; 218 clear_bit(id, smmu->asids);
604 219 mutex_unlock(&smmu->lock);
605 page = pfn_to_page(pfn);
606 vaddr = page_address(page);
607 if (!vaddr)
608 return;
609
610 vaddr[0] = iova;
611 vaddr[1] = pfn << PAGE_SHIFT;
612 FLUSH_CPU_DCACHE(vaddr, page, sizeof(vaddr[0]) * 2);
613} 220}
614#else 221
615static inline void put_signature(struct smmu_as *as, 222static bool tegra_smmu_capable(enum iommu_cap cap)
616 unsigned long addr, unsigned long pfn)
617{ 223{
224 return false;
618} 225}
619#endif
620 226
621/* 227static int tegra_smmu_domain_init(struct iommu_domain *domain)
622 * Caller must not hold as->lock
623 */
624static int alloc_pdir(struct smmu_as *as)
625{ 228{
626 unsigned long *pdir, flags; 229 struct tegra_smmu_as *as;
627 int pdn, err = 0; 230 unsigned int i;
628 u32 val; 231 uint32_t *pd;
629 struct smmu_device *smmu = as->smmu;
630 struct page *page;
631 unsigned int *cnt;
632 232
633 /* 233 as = kzalloc(sizeof(*as), GFP_KERNEL);
634 * do the allocation, then grab as->lock 234 if (!as)
635 */ 235 return -ENOMEM;
636 cnt = devm_kzalloc(smmu->dev,
637 sizeof(cnt[0]) * SMMU_PDIR_COUNT,
638 GFP_KERNEL);
639 page = alloc_page(GFP_KERNEL | __GFP_DMA);
640 236
641 spin_lock_irqsave(&as->lock, flags); 237 as->attr = SMMU_PD_READABLE | SMMU_PD_WRITABLE | SMMU_PD_NONSECURE;
238 as->domain = domain;
642 239
643 if (as->pdir_page) { 240 as->pd = alloc_page(GFP_KERNEL | __GFP_DMA);
644 /* We raced, free the redundant */ 241 if (!as->pd) {
645 err = -EAGAIN; 242 kfree(as);
646 goto err_out; 243 return -ENOMEM;
647 } 244 }
648 245
649 if (!page || !cnt) { 246 as->count = alloc_page(GFP_KERNEL);
650 dev_err(smmu->dev, "failed to allocate at %s\n", __func__); 247 if (!as->count) {
651 err = -ENOMEM; 248 __free_page(as->pd);
652 goto err_out; 249 kfree(as);
250 return -ENOMEM;
653 } 251 }
654 252
655 as->pdir_page = page; 253 /* clear PDEs */
656 as->pte_count = cnt; 254 pd = page_address(as->pd);
255 SetPageReserved(as->pd);
657 256
658 SetPageReserved(as->pdir_page); 257 for (i = 0; i < SMMU_NUM_PDE; i++)
659 pdir = page_address(as->pdir_page); 258 pd[i] = 0;
660 259
661 for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) 260 /* clear PDE usage counters */
662 pdir[pdn] = _PDE_VACANT(pdn); 261 pd = page_address(as->count);
663 FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE); 262 SetPageReserved(as->count);
664 val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page);
665 smmu_write(smmu, val, SMMU_PTC_FLUSH);
666 FLUSH_SMMU_REGS(as->smmu);
667 val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
668 SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
669 (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
670 smmu_write(smmu, val, SMMU_TLB_FLUSH);
671 FLUSH_SMMU_REGS(as->smmu);
672 263
673 spin_unlock_irqrestore(&as->lock, flags); 264 for (i = 0; i < SMMU_NUM_PDE; i++)
674 265 pd[i] = 0;
675 return 0;
676 266
677err_out: 267 domain->priv = as;
678 spin_unlock_irqrestore(&as->lock, flags);
679 268
680 devm_kfree(smmu->dev, cnt); 269 return 0;
681 if (page)
682 __free_page(page);
683 return err;
684} 270}
685 271
686static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova) 272static void tegra_smmu_domain_destroy(struct iommu_domain *domain)
687{ 273{
688 unsigned long *pte; 274 struct tegra_smmu_as *as = domain->priv;
689 struct page *page;
690 unsigned int *count;
691 275
692 pte = locate_pte(as, iova, false, &page, &count); 276 /* TODO: free page directory and page tables */
693 if (WARN_ON(!pte)) 277 ClearPageReserved(as->pd);
694 return;
695 278
696 if (WARN_ON(*pte == _PTE_VACANT(iova))) 279 kfree(as);
697 return;
698
699 *pte = _PTE_VACANT(iova);
700 FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
701 flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0);
702 if (!--(*count))
703 free_ptbl(as, iova);
704} 280}
705 281
706static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova, 282static const struct tegra_smmu_swgroup *
707 unsigned long pfn) 283tegra_smmu_find_swgroup(struct tegra_smmu *smmu, unsigned int swgroup)
708{ 284{
709 struct smmu_device *smmu = as->smmu; 285 const struct tegra_smmu_swgroup *group = NULL;
710 unsigned long *pte; 286 unsigned int i;
711 unsigned int *count;
712 struct page *page;
713 287
714 pte = locate_pte(as, iova, true, &page, &count); 288 for (i = 0; i < smmu->soc->num_swgroups; i++) {
715 if (WARN_ON(!pte)) 289 if (smmu->soc->swgroups[i].swgroup == swgroup) {
716 return; 290 group = &smmu->soc->swgroups[i];
291 break;
292 }
293 }
717 294
718 if (*pte == _PTE_VACANT(iova)) 295 return group;
719 (*count)++;
720 *pte = SMMU_PFN_TO_PTE(pfn, as->pte_attr);
721 if (unlikely((*pte == _PTE_VACANT(iova))))
722 (*count)--;
723 FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
724 flush_ptc_and_tlb(smmu, as, iova, pte, page, 0);
725 put_signature(as, iova, pfn);
726} 296}
727 297
728static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova, 298static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
729 phys_addr_t pa, size_t bytes, int prot) 299 unsigned int asid)
730{ 300{
731 struct smmu_as *as = domain->priv; 301 const struct tegra_smmu_swgroup *group;
732 unsigned long pfn = __phys_to_pfn(pa); 302 unsigned int i;
733 unsigned long flags; 303 u32 value;
734 304
735 dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa); 305 for (i = 0; i < smmu->soc->num_clients; i++) {
306 const struct tegra_mc_client *client = &smmu->soc->clients[i];
736 307
737 if (!pfn_valid(pfn)) 308 if (client->swgroup != swgroup)
738 return -ENOMEM; 309 continue;
739
740 spin_lock_irqsave(&as->lock, flags);
741 __smmu_iommu_map_pfn(as, iova, pfn);
742 spin_unlock_irqrestore(&as->lock, flags);
743 return 0;
744}
745
746static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
747 size_t bytes)
748{
749 struct smmu_as *as = domain->priv;
750 unsigned long flags;
751 310
752 dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova); 311 value = smmu_readl(smmu, client->smmu.reg);
312 value |= BIT(client->smmu.bit);
313 smmu_writel(smmu, value, client->smmu.reg);
314 }
753 315
754 spin_lock_irqsave(&as->lock, flags); 316 group = tegra_smmu_find_swgroup(smmu, swgroup);
755 __smmu_iommu_unmap(as, iova); 317 if (group) {
756 spin_unlock_irqrestore(&as->lock, flags); 318 value = smmu_readl(smmu, group->reg);
757 return SMMU_PAGE_SIZE; 319 value &= ~SMMU_ASID_MASK;
320 value |= SMMU_ASID_VALUE(asid);
321 value |= SMMU_ASID_ENABLE;
322 smmu_writel(smmu, value, group->reg);
323 }
758} 324}
759 325
760static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain, 326static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup,
761 dma_addr_t iova) 327 unsigned int asid)
762{ 328{
763 struct smmu_as *as = domain->priv; 329 const struct tegra_smmu_swgroup *group;
764 unsigned long *pte; 330 unsigned int i;
765 unsigned int *count; 331 u32 value;
766 struct page *page;
767 unsigned long pfn;
768 unsigned long flags;
769 332
770 spin_lock_irqsave(&as->lock, flags); 333 group = tegra_smmu_find_swgroup(smmu, swgroup);
334 if (group) {
335 value = smmu_readl(smmu, group->reg);
336 value &= ~SMMU_ASID_MASK;
337 value |= SMMU_ASID_VALUE(asid);
338 value &= ~SMMU_ASID_ENABLE;
339 smmu_writel(smmu, value, group->reg);
340 }
771 341
772 pte = locate_pte(as, iova, true, &page, &count); 342 for (i = 0; i < smmu->soc->num_clients; i++) {
773 pfn = *pte & SMMU_PFN_MASK; 343 const struct tegra_mc_client *client = &smmu->soc->clients[i];
774 WARN_ON(!pfn_valid(pfn));
775 dev_dbg(as->smmu->dev,
776 "iova:%08llx pfn:%08lx asid:%d\n", (unsigned long long)iova,
777 pfn, as->asid);
778 344
779 spin_unlock_irqrestore(&as->lock, flags); 345 if (client->swgroup != swgroup)
780 return PFN_PHYS(pfn); 346 continue;
781}
782 347
783static bool smmu_iommu_capable(enum iommu_cap cap) 348 value = smmu_readl(smmu, client->smmu.reg);
784{ 349 value &= ~BIT(client->smmu.bit);
785 return false; 350 smmu_writel(smmu, value, client->smmu.reg);
351 }
786} 352}
787 353
788static int smmu_iommu_attach_dev(struct iommu_domain *domain, 354static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
789 struct device *dev) 355 struct tegra_smmu_as *as)
790{ 356{
791 struct smmu_as *as = domain->priv; 357 u32 value;
792 struct smmu_device *smmu = as->smmu;
793 struct smmu_client *client, *c;
794 u32 map;
795 int err; 358 int err;
796 359
797 client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL); 360 if (as->use_count > 0) {
798 if (!client) 361 as->use_count++;
799 return -ENOMEM; 362 return 0;
800 client->dev = dev;
801 client->as = as;
802 map = (unsigned long)dev->platform_data;
803 if (!map)
804 return -EINVAL;
805
806 err = smmu_client_enable_hwgrp(client, map);
807 if (err)
808 goto err_hwgrp;
809
810 spin_lock(&as->client_lock);
811 list_for_each_entry(c, &as->client, list) {
812 if (c->dev == dev) {
813 dev_err(smmu->dev,
814 "%s is already attached\n", dev_name(c->dev));
815 err = -EINVAL;
816 goto err_client;
817 }
818 } 363 }
819 list_add(&client->list, &as->client);
820 spin_unlock(&as->client_lock);
821 364
822 /* 365 err = tegra_smmu_alloc_asid(smmu, &as->id);
823 * Reserve "page zero" for AVP vectors using a common dummy 366 if (err < 0)
824 * page. 367 return err;
825 */
826 if (map & HWG_AVPC) {
827 struct page *page;
828 368
829 page = as->smmu->avp_vector_page; 369 smmu->soc->ops->flush_dcache(as->pd, 0, SMMU_SIZE_PD);
830 __smmu_iommu_map_pfn(as, 0, page_to_pfn(page)); 370 smmu_flush_ptc(smmu, as->pd, 0);
371 smmu_flush_tlb_asid(smmu, as->id);
831 372
832 pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n"); 373 smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID);
833 } 374 value = SMMU_PTB_DATA_VALUE(as->pd, as->attr);
375 smmu_writel(smmu, value, SMMU_PTB_DATA);
376 smmu_flush(smmu);
834 377
835 dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev)); 378 as->smmu = smmu;
836 return 0; 379 as->use_count++;
837 380
838err_client: 381 return 0;
839 smmu_client_disable_hwgrp(client);
840 spin_unlock(&as->client_lock);
841err_hwgrp:
842 devm_kfree(smmu->dev, client);
843 return err;
844} 382}
845 383
846static void smmu_iommu_detach_dev(struct iommu_domain *domain, 384static void tegra_smmu_as_unprepare(struct tegra_smmu *smmu,
847 struct device *dev) 385 struct tegra_smmu_as *as)
848{ 386{
849 struct smmu_as *as = domain->priv; 387 if (--as->use_count > 0)
850 struct smmu_device *smmu = as->smmu; 388 return;
851 struct smmu_client *c; 389
852 390 tegra_smmu_free_asid(smmu, as->id);
853 spin_lock(&as->client_lock); 391 as->smmu = NULL;
854
855 list_for_each_entry(c, &as->client, list) {
856 if (c->dev == dev) {
857 smmu_client_disable_hwgrp(c);
858 list_del(&c->list);
859 devm_kfree(smmu->dev, c);
860 c->as = NULL;
861 dev_dbg(smmu->dev,
862 "%s is detached\n", dev_name(c->dev));
863 goto out;
864 }
865 }
866 dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev));
867out:
868 spin_unlock(&as->client_lock);
869} 392}
870 393
871static int smmu_iommu_domain_init(struct iommu_domain *domain) 394static int tegra_smmu_attach_dev(struct iommu_domain *domain,
395 struct device *dev)
872{ 396{
873 int i, err = -EAGAIN; 397 struct tegra_smmu *smmu = dev->archdata.iommu;
874 unsigned long flags; 398 struct tegra_smmu_as *as = domain->priv;
875 struct smmu_as *as; 399 struct device_node *np = dev->of_node;
876 struct smmu_device *smmu = smmu_handle; 400 struct of_phandle_args args;
401 unsigned int index = 0;
402 int err = 0;
877 403
878 /* Look for a free AS with lock held */ 404 while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
879 for (i = 0; i < smmu->num_as; i++) { 405 &args)) {
880 as = &smmu->as[i]; 406 unsigned int swgroup = args.args[0];
881 407
882 if (as->pdir_page) 408 if (args.np != smmu->dev->of_node) {
409 of_node_put(args.np);
883 continue; 410 continue;
411 }
884 412
885 err = alloc_pdir(as); 413 of_node_put(args.np);
886 if (!err)
887 goto found;
888 414
889 if (err != -EAGAIN) 415 err = tegra_smmu_as_prepare(smmu, as);
890 break; 416 if (err < 0)
417 return err;
418
419 tegra_smmu_enable(smmu, swgroup, as->id);
420 index++;
891 } 421 }
892 if (i == smmu->num_as)
893 dev_err(smmu->dev, "no free AS\n");
894 return err;
895 422
896found: 423 if (index == 0)
897 spin_lock_irqsave(&smmu->lock, flags); 424 return -ENODEV;
898 425
899 /* Update PDIR register */ 426 return 0;
900 smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID); 427}
901 smmu_write(smmu,
902 SMMU_MK_PDIR(as->pdir_page, as->pdir_attr), SMMU_PTB_DATA);
903 FLUSH_SMMU_REGS(smmu);
904 428
905 spin_unlock_irqrestore(&smmu->lock, flags); 429static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
430{
431 struct tegra_smmu_as *as = domain->priv;
432 struct device_node *np = dev->of_node;
433 struct tegra_smmu *smmu = as->smmu;
434 struct of_phandle_args args;
435 unsigned int index = 0;
906 436
907 domain->priv = as; 437 while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
438 &args)) {
439 unsigned int swgroup = args.args[0];
908 440
909 domain->geometry.aperture_start = smmu->iovmm_base; 441 if (args.np != smmu->dev->of_node) {
910 domain->geometry.aperture_end = smmu->iovmm_base + 442 of_node_put(args.np);
911 smmu->page_count * SMMU_PAGE_SIZE - 1; 443 continue;
912 domain->geometry.force_aperture = true; 444 }
913 445
914 dev_dbg(smmu->dev, "smmu_as@%p\n", as); 446 of_node_put(args.np);
915 447
916 return 0; 448 tegra_smmu_disable(smmu, swgroup, as->id);
449 tegra_smmu_as_unprepare(smmu, as);
450 index++;
451 }
917} 452}
918 453
919static void smmu_iommu_domain_destroy(struct iommu_domain *domain) 454static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
455 struct page **pagep)
920{ 456{
921 struct smmu_as *as = domain->priv; 457 u32 *pd = page_address(as->pd), *pt, *count;
922 struct smmu_device *smmu = as->smmu; 458 u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
923 unsigned long flags; 459 u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
460 struct tegra_smmu *smmu = as->smmu;
461 struct page *page;
462 unsigned int i;
463
464 if (pd[pde] == 0) {
465 page = alloc_page(GFP_KERNEL | __GFP_DMA);
466 if (!page)
467 return NULL;
924 468
925 spin_lock_irqsave(&as->lock, flags); 469 pt = page_address(page);
470 SetPageReserved(page);
926 471
927 if (as->pdir_page) { 472 for (i = 0; i < SMMU_NUM_PTE; i++)
928 spin_lock(&smmu->lock); 473 pt[i] = 0;
929 smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
930 smmu_write(smmu, SMMU_PTB_DATA_RESET_VAL, SMMU_PTB_DATA);
931 FLUSH_SMMU_REGS(smmu);
932 spin_unlock(&smmu->lock);
933 474
934 free_pdir(as); 475 smmu->soc->ops->flush_dcache(page, 0, SMMU_SIZE_PT);
935 }
936 476
937 if (!list_empty(&as->client)) { 477 pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
938 struct smmu_client *c;
939 478
940 list_for_each_entry(c, &as->client, list) 479 smmu->soc->ops->flush_dcache(as->pd, pde << 2, 4);
941 smmu_iommu_detach_dev(domain, c->dev); 480 smmu_flush_ptc(smmu, as->pd, pde << 2);
481 smmu_flush_tlb_section(smmu, as->id, iova);
482 smmu_flush(smmu);
483 } else {
484 page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
485 pt = page_address(page);
942 } 486 }
943 487
944 spin_unlock_irqrestore(&as->lock, flags); 488 *pagep = page;
945 489
946 domain->priv = NULL; 490 /* Keep track of entries in this page table. */
947 dev_dbg(smmu->dev, "smmu_as@%p\n", as); 491 count = page_address(as->count);
948} 492 if (pt[pte] == 0)
493 count[pde]++;
949 494
950static const struct iommu_ops smmu_iommu_ops = { 495 return &pt[pte];
951 .capable = smmu_iommu_capable, 496}
952 .domain_init = smmu_iommu_domain_init,
953 .domain_destroy = smmu_iommu_domain_destroy,
954 .attach_dev = smmu_iommu_attach_dev,
955 .detach_dev = smmu_iommu_detach_dev,
956 .map = smmu_iommu_map,
957 .unmap = smmu_iommu_unmap,
958 .iova_to_phys = smmu_iommu_iova_to_phys,
959 .pgsize_bitmap = SMMU_IOMMU_PGSIZES,
960};
961
962/* Should be in the order of enum */
963static const char * const smmu_debugfs_mc[] = { "mc", };
964static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", };
965 497
966static ssize_t smmu_debugfs_stats_write(struct file *file, 498static void as_put_pte(struct tegra_smmu_as *as, dma_addr_t iova)
967 const char __user *buffer,
968 size_t count, loff_t *pos)
969{ 499{
970 struct smmu_debugfs_info *info; 500 u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
971 struct smmu_device *smmu; 501 u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
972 int i; 502 u32 *count = page_address(as->count);
973 enum { 503 u32 *pd = page_address(as->pd), *pt;
974 _OFF = 0, 504 struct page *page;
975 _ON,
976 _RESET,
977 };
978 const char * const command[] = {
979 [_OFF] = "off",
980 [_ON] = "on",
981 [_RESET] = "reset",
982 };
983 char str[] = "reset";
984 u32 val;
985 size_t offs;
986 505
987 count = min_t(size_t, count, sizeof(str)); 506 page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
988 if (copy_from_user(str, buffer, count)) 507 pt = page_address(page);
989 return -EINVAL;
990 508
991 for (i = 0; i < ARRAY_SIZE(command); i++) 509 /*
992 if (strncmp(str, command[i], 510 * When no entries in this page table are used anymore, return the
993 strlen(command[i])) == 0) 511 * memory page to the system.
994 break; 512 */
513 if (pt[pte] != 0) {
514 if (--count[pde] == 0) {
515 ClearPageReserved(page);
516 __free_page(page);
517 pd[pde] = 0;
518 }
995 519
996 if (i == ARRAY_SIZE(command)) 520 pt[pte] = 0;
997 return -EINVAL;
998
999 info = file_inode(file)->i_private;
1000 smmu = info->smmu;
1001
1002 offs = SMMU_CACHE_CONFIG(info->cache);
1003 val = smmu_read(smmu, offs);
1004 switch (i) {
1005 case _OFF:
1006 val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
1007 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
1008 smmu_write(smmu, val, offs);
1009 break;
1010 case _ON:
1011 val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
1012 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
1013 smmu_write(smmu, val, offs);
1014 break;
1015 case _RESET:
1016 val |= SMMU_CACHE_CONFIG_STATS_TEST;
1017 smmu_write(smmu, val, offs);
1018 val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
1019 smmu_write(smmu, val, offs);
1020 break;
1021 default:
1022 BUG();
1023 break;
1024 } 521 }
1025
1026 dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
1027 val, smmu_read(smmu, offs), offs);
1028
1029 return count;
1030} 522}
1031 523
1032static int smmu_debugfs_stats_show(struct seq_file *s, void *v) 524static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
525 phys_addr_t paddr, size_t size, int prot)
1033{ 526{
1034 struct smmu_debugfs_info *info = s->private; 527 struct tegra_smmu_as *as = domain->priv;
1035 struct smmu_device *smmu = info->smmu; 528 struct tegra_smmu *smmu = as->smmu;
1036 int i; 529 unsigned long offset;
1037 const char * const stats[] = { "hit", "miss", }; 530 struct page *page;
531 u32 *pte;
1038 532
533 pte = as_get_pte(as, iova, &page);
534 if (!pte)
535 return -ENOMEM;
1039 536
1040 for (i = 0; i < ARRAY_SIZE(stats); i++) { 537 *pte = __phys_to_pfn(paddr) | SMMU_PTE_ATTR;
1041 u32 val; 538 offset = offset_in_page(pte);
1042 size_t offs;
1043 539
1044 offs = SMMU_STATS_CACHE_COUNT(info->mc, info->cache, i); 540 smmu->soc->ops->flush_dcache(page, offset, 4);
1045 val = smmu_read(smmu, offs); 541 smmu_flush_ptc(smmu, page, offset);
1046 seq_printf(s, "%s:%08x ", stats[i], val); 542 smmu_flush_tlb_group(smmu, as->id, iova);
543 smmu_flush(smmu);
1047 544
1048 dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
1049 stats[i], val, offs);
1050 }
1051 seq_printf(s, "\n");
1052 return 0; 545 return 0;
1053} 546}
1054 547
1055static int smmu_debugfs_stats_open(struct inode *inode, struct file *file) 548static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
549 size_t size)
1056{ 550{
1057 return single_open(file, smmu_debugfs_stats_show, inode->i_private); 551 struct tegra_smmu_as *as = domain->priv;
1058} 552 struct tegra_smmu *smmu = as->smmu;
553 unsigned long offset;
554 struct page *page;
555 u32 *pte;
1059 556
1060static const struct file_operations smmu_debugfs_stats_fops = { 557 pte = as_get_pte(as, iova, &page);
1061 .open = smmu_debugfs_stats_open, 558 if (!pte)
1062 .read = seq_read, 559 return 0;
1063 .llseek = seq_lseek,
1064 .release = single_release,
1065 .write = smmu_debugfs_stats_write,
1066};
1067 560
1068static void smmu_debugfs_delete(struct smmu_device *smmu) 561 offset = offset_in_page(pte);
1069{ 562 as_put_pte(as, iova);
1070 debugfs_remove_recursive(smmu->debugfs_root); 563
1071 kfree(smmu->debugfs_info); 564 smmu->soc->ops->flush_dcache(page, offset, 4);
565 smmu_flush_ptc(smmu, page, offset);
566 smmu_flush_tlb_group(smmu, as->id, iova);
567 smmu_flush(smmu);
568
569 return size;
1072} 570}
1073 571
1074static void smmu_debugfs_create(struct smmu_device *smmu) 572static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
573 dma_addr_t iova)
1075{ 574{
1076 int i; 575 struct tegra_smmu_as *as = domain->priv;
1077 size_t bytes; 576 struct page *page;
1078 struct dentry *root; 577 unsigned long pfn;
1079 578 u32 *pte;
1080 bytes = ARRAY_SIZE(smmu_debugfs_mc) * ARRAY_SIZE(smmu_debugfs_cache) *
1081 sizeof(*smmu->debugfs_info);
1082 smmu->debugfs_info = kmalloc(bytes, GFP_KERNEL);
1083 if (!smmu->debugfs_info)
1084 return;
1085
1086 root = debugfs_create_dir(dev_name(smmu->dev), NULL);
1087 if (!root)
1088 goto err_out;
1089 smmu->debugfs_root = root;
1090
1091 for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
1092 int j;
1093 struct dentry *mc;
1094
1095 mc = debugfs_create_dir(smmu_debugfs_mc[i], root);
1096 if (!mc)
1097 goto err_out;
1098
1099 for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
1100 struct dentry *cache;
1101 struct smmu_debugfs_info *info;
1102
1103 info = smmu->debugfs_info;
1104 info += i * ARRAY_SIZE(smmu_debugfs_mc) + j;
1105 info->smmu = smmu;
1106 info->mc = i;
1107 info->cache = j;
1108
1109 cache = debugfs_create_file(smmu_debugfs_cache[j],
1110 S_IWUGO | S_IRUGO, mc,
1111 (void *)info,
1112 &smmu_debugfs_stats_fops);
1113 if (!cache)
1114 goto err_out;
1115 }
1116 }
1117 579
1118 return; 580 pte = as_get_pte(as, iova, &page);
581 pfn = *pte & SMMU_PFN_MASK;
1119 582
1120err_out: 583 return PFN_PHYS(pfn);
1121 smmu_debugfs_delete(smmu);
1122} 584}
1123 585
1124static int tegra_smmu_suspend(struct device *dev) 586static struct tegra_smmu *tegra_smmu_find(struct device_node *np)
1125{ 587{
1126 struct smmu_device *smmu = dev_get_drvdata(dev); 588 struct platform_device *pdev;
589 struct tegra_mc *mc;
1127 590
1128 smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0); 591 pdev = of_find_device_by_node(np);
1129 smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1); 592 if (!pdev)
1130 smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2); 593 return NULL;
1131 smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY); 594
1132 return 0; 595 mc = platform_get_drvdata(pdev);
596 if (!mc)
597 return NULL;
598
599 return mc->smmu;
1133} 600}
1134 601
1135static int tegra_smmu_resume(struct device *dev) 602static int tegra_smmu_add_device(struct device *dev)
1136{ 603{
1137 struct smmu_device *smmu = dev_get_drvdata(dev); 604 struct device_node *np = dev->of_node;
1138 unsigned long flags; 605 struct of_phandle_args args;
1139 int err; 606 unsigned int index = 0;
1140 607
1141 spin_lock_irqsave(&smmu->lock, flags); 608 while (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
1142 err = smmu_setup_regs(smmu); 609 &args) == 0) {
1143 spin_unlock_irqrestore(&smmu->lock, flags); 610 struct tegra_smmu *smmu;
1144 return err; 611
612 smmu = tegra_smmu_find(args.np);
613 if (smmu) {
614 /*
615 * Only a single IOMMU master interface is currently
616 * supported by the Linux kernel, so abort after the
617 * first match.
618 */
619 dev->archdata.iommu = smmu;
620 break;
621 }
622
623 index++;
624 }
625
626 return 0;
1145} 627}
1146 628
1147static int tegra_smmu_probe(struct platform_device *pdev) 629static void tegra_smmu_remove_device(struct device *dev)
1148{ 630{
1149 struct smmu_device *smmu; 631 dev->archdata.iommu = NULL;
1150 struct device *dev = &pdev->dev; 632}
1151 int i, asids, err = 0;
1152 dma_addr_t uninitialized_var(base);
1153 size_t bytes, uninitialized_var(size);
1154 633
1155 if (smmu_handle) 634static const struct iommu_ops tegra_smmu_ops = {
1156 return -EIO; 635 .capable = tegra_smmu_capable,
636 .domain_init = tegra_smmu_domain_init,
637 .domain_destroy = tegra_smmu_domain_destroy,
638 .attach_dev = tegra_smmu_attach_dev,
639 .detach_dev = tegra_smmu_detach_dev,
640 .add_device = tegra_smmu_add_device,
641 .remove_device = tegra_smmu_remove_device,
642 .map = tegra_smmu_map,
643 .unmap = tegra_smmu_unmap,
644 .map_sg = default_iommu_map_sg,
645 .iova_to_phys = tegra_smmu_iova_to_phys,
1157 646
1158 BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT); 647 .pgsize_bitmap = SZ_4K,
648};
1159 649
1160 if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids)) 650static void tegra_smmu_ahb_enable(void)
1161 return -ENODEV; 651{
652 static const struct of_device_id ahb_match[] = {
653 { .compatible = "nvidia,tegra30-ahb", },
654 { }
655 };
656 struct device_node *ahb;
1162 657
1163 bytes = sizeof(*smmu) + asids * sizeof(*smmu->as); 658 ahb = of_find_matching_node(NULL, ahb_match);
1164 smmu = devm_kzalloc(dev, bytes, GFP_KERNEL); 659 if (ahb) {
1165 if (!smmu) { 660 tegra_ahb_enable_smmu(ahb);
1166 dev_err(dev, "failed to allocate smmu_device\n"); 661 of_node_put(ahb);
1167 return -ENOMEM;
1168 } 662 }
663}
1169 664
1170 smmu->nregs = pdev->num_resources; 665struct tegra_smmu *tegra_smmu_probe(struct device *dev,
1171 smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs), 666 const struct tegra_smmu_soc *soc,
1172 GFP_KERNEL); 667 struct tegra_mc *mc)
1173 smmu->rege = smmu->regs + smmu->nregs; 668{
1174 if (!smmu->regs) 669 struct tegra_smmu *smmu;
1175 return -ENOMEM; 670 size_t size;
1176 for (i = 0; i < smmu->nregs; i++) { 671 u32 value;
1177 struct resource *res; 672 int err;
1178
1179 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
1180 smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res);
1181 if (IS_ERR(smmu->regs[i]))
1182 return PTR_ERR(smmu->regs[i]);
1183 smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1;
1184 }
1185 /* Same as "mc" 1st regiter block start address */
1186 smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & PAGE_MASK);
1187 673
1188 err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size); 674 /* This can happen on Tegra20 which doesn't have an SMMU */
1189 if (err) 675 if (!soc)
1190 return -ENODEV; 676 return NULL;
1191 677
1192 if (size & SMMU_PAGE_MASK) 678 smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
1193 return -EINVAL; 679 if (!smmu)
680 return ERR_PTR(-ENOMEM);
1194 681
1195 size >>= SMMU_PAGE_SHIFT; 682 /*
1196 if (!size) 683 * This is a bit of a hack. Ideally we'd want to simply return this
1197 return -EINVAL; 684 * value. However the IOMMU registration process will attempt to add
685 * all devices to the IOMMU when bus_set_iommu() is called. In order
686 * not to rely on global variables to track the IOMMU instance, we
687 * set it here so that it can be looked up from the .add_device()
688 * callback via the IOMMU device's .drvdata field.
689 */
690 mc->smmu = smmu;
1198 691
1199 smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0); 692 size = BITS_TO_LONGS(soc->num_asids) * sizeof(long);
1200 if (!smmu->ahb)
1201 return -ENODEV;
1202 693
1203 smmu->dev = dev; 694 smmu->asids = devm_kzalloc(dev, size, GFP_KERNEL);
1204 smmu->num_as = asids; 695 if (!smmu->asids)
1205 smmu->iovmm_base = base; 696 return ERR_PTR(-ENOMEM);
1206 smmu->page_count = size;
1207
1208 smmu->translation_enable_0 = ~0;
1209 smmu->translation_enable_1 = ~0;
1210 smmu->translation_enable_2 = ~0;
1211 smmu->asid_security = 0;
1212
1213 for (i = 0; i < smmu->num_as; i++) {
1214 struct smmu_as *as = &smmu->as[i];
1215
1216 as->smmu = smmu;
1217 as->asid = i;
1218 as->pdir_attr = _PDIR_ATTR;
1219 as->pde_attr = _PDE_ATTR;
1220 as->pte_attr = _PTE_ATTR;
1221
1222 spin_lock_init(&as->lock);
1223 spin_lock_init(&as->client_lock);
1224 INIT_LIST_HEAD(&as->client);
1225 }
1226 spin_lock_init(&smmu->lock);
1227 err = smmu_setup_regs(smmu);
1228 if (err)
1229 return err;
1230 platform_set_drvdata(pdev, smmu);
1231 697
1232 smmu->avp_vector_page = alloc_page(GFP_KERNEL); 698 mutex_init(&smmu->lock);
1233 if (!smmu->avp_vector_page)
1234 return -ENOMEM;
1235 699
1236 smmu_debugfs_create(smmu); 700 smmu->regs = mc->regs;
1237 smmu_handle = smmu; 701 smmu->soc = soc;
1238 bus_set_iommu(&platform_bus_type, &smmu_iommu_ops); 702 smmu->dev = dev;
1239 return 0; 703 smmu->mc = mc;
1240}
1241 704
1242static int tegra_smmu_remove(struct platform_device *pdev) 705 value = SMMU_PTC_CONFIG_ENABLE | SMMU_PTC_CONFIG_INDEX_MAP(0x3f);
1243{
1244 struct smmu_device *smmu = platform_get_drvdata(pdev);
1245 int i;
1246 706
1247 smmu_debugfs_delete(smmu); 707 if (soc->supports_request_limit)
708 value |= SMMU_PTC_CONFIG_REQ_LIMIT(8);
1248 709
1249 smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG); 710 smmu_writel(smmu, value, SMMU_PTC_CONFIG);
1250 for (i = 0; i < smmu->num_as; i++)
1251 free_pdir(&smmu->as[i]);
1252 __free_page(smmu->avp_vector_page);
1253 smmu_handle = NULL;
1254 return 0;
1255}
1256 711
1257static const struct dev_pm_ops tegra_smmu_pm_ops = { 712 value = SMMU_TLB_CONFIG_HIT_UNDER_MISS |
1258 .suspend = tegra_smmu_suspend, 713 SMMU_TLB_CONFIG_ACTIVE_LINES(0x20);
1259 .resume = tegra_smmu_resume,
1260};
1261 714
1262static const struct of_device_id tegra_smmu_of_match[] = { 715 if (soc->supports_round_robin_arbitration)
1263 { .compatible = "nvidia,tegra30-smmu", }, 716 value |= SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION;
1264 { },
1265};
1266MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
1267
1268static struct platform_driver tegra_smmu_driver = {
1269 .probe = tegra_smmu_probe,
1270 .remove = tegra_smmu_remove,
1271 .driver = {
1272 .owner = THIS_MODULE,
1273 .name = "tegra-smmu",
1274 .pm = &tegra_smmu_pm_ops,
1275 .of_match_table = tegra_smmu_of_match,
1276 },
1277};
1278 717
1279static int tegra_smmu_init(void) 718 smmu_writel(smmu, value, SMMU_TLB_CONFIG);
1280{
1281 return platform_driver_register(&tegra_smmu_driver);
1282}
1283 719
1284static void __exit tegra_smmu_exit(void) 720 smmu_flush_ptc(smmu, NULL, 0);
1285{ 721 smmu_flush_tlb(smmu);
1286 platform_driver_unregister(&tegra_smmu_driver); 722 smmu_writel(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
1287} 723 smmu_flush(smmu);
724
725 tegra_smmu_ahb_enable();
1288 726
1289subsys_initcall(tegra_smmu_init); 727 err = bus_set_iommu(&platform_bus_type, &tegra_smmu_ops);
1290module_exit(tegra_smmu_exit); 728 if (err < 0)
729 return ERR_PTR(err);
1291 730
1292MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30"); 731 return smmu;
1293MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>"); 732}
1294MODULE_ALIAS("platform:tegra-smmu");
1295MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 6d91c27fd4c8..08bd4cfca2a4 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -61,16 +61,6 @@ config TEGRA20_MC
61 analysis, especially for IOMMU/GART(Graphics Address 61 analysis, especially for IOMMU/GART(Graphics Address
62 Relocation Table) module. 62 Relocation Table) module.
63 63
64config TEGRA30_MC
65 bool "Tegra30 Memory Controller(MC) driver"
66 default y
67 depends on ARCH_TEGRA_3x_SOC
68 help
69 This driver is for the Memory Controller(MC) module available
70 in Tegra30 SoCs, mainly for a address translation fault
71 analysis, especially for IOMMU/SMMU(System Memory Management
72 Unit) module.
73
74config FSL_CORENET_CF 64config FSL_CORENET_CF
75 tristate "Freescale CoreNet Error Reporting" 65 tristate "Freescale CoreNet Error Reporting"
76 depends on FSL_SOC_BOOKE 66 depends on FSL_SOC_BOOKE
@@ -85,4 +75,6 @@ config FSL_IFC
85 bool 75 bool
86 depends on FSL_SOC 76 depends on FSL_SOC
87 77
78source "drivers/memory/tegra/Kconfig"
79
88endif 80endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index c32d31981be3..ad98bb232623 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -12,4 +12,5 @@ obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
12obj-$(CONFIG_FSL_IFC) += fsl_ifc.o 12obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
13obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o 13obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
14obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o 14obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
15obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o 15
16obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
new file mode 100644
index 000000000000..571087621827
--- /dev/null
+++ b/drivers/memory/tegra/Kconfig
@@ -0,0 +1,7 @@
1config TEGRA_MC
2 bool "NVIDIA Tegra Memory Controller support"
3 default y
4 depends on ARCH_TEGRA
5 help
6 This driver supports the Memory Controller (MC) hardware found on
7 NVIDIA Tegra SoCs.
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
new file mode 100644
index 000000000000..0d9f497b786c
--- /dev/null
+++ b/drivers/memory/tegra/Makefile
@@ -0,0 +1,7 @@
1tegra-mc-y := mc.o
2
3tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o
4tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
5tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
6
7obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
new file mode 100644
index 000000000000..fe3c44e7e1d1
--- /dev/null
+++ b/drivers/memory/tegra/mc.c
@@ -0,0 +1,301 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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/interrupt.h>
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16
17#include "mc.h"
18
19#define MC_INTSTATUS 0x000
20#define MC_INT_DECERR_MTS (1 << 16)
21#define MC_INT_SECERR_SEC (1 << 13)
22#define MC_INT_DECERR_VPR (1 << 12)
23#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
24#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
25#define MC_INT_ARBITRATION_EMEM (1 << 9)
26#define MC_INT_SECURITY_VIOLATION (1 << 8)
27#define MC_INT_DECERR_EMEM (1 << 6)
28
29#define MC_INTMASK 0x004
30
31#define MC_ERR_STATUS 0x08
32#define MC_ERR_STATUS_TYPE_SHIFT 28
33#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT)
34#define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT)
35#define MC_ERR_STATUS_READABLE (1 << 27)
36#define MC_ERR_STATUS_WRITABLE (1 << 26)
37#define MC_ERR_STATUS_NONSECURE (1 << 25)
38#define MC_ERR_STATUS_ADR_HI_SHIFT 20
39#define MC_ERR_STATUS_ADR_HI_MASK 0x3
40#define MC_ERR_STATUS_SECURITY (1 << 17)
41#define MC_ERR_STATUS_RW (1 << 16)
42#define MC_ERR_STATUS_CLIENT_MASK 0x7f
43
44#define MC_ERR_ADR 0x0c
45
46#define MC_EMEM_ARB_CFG 0x90
47#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
48#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
49#define MC_EMEM_ARB_MISC0 0xd8
50
51static const struct of_device_id tegra_mc_of_match[] = {
52#ifdef CONFIG_ARCH_TEGRA_3x_SOC
53 { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc },
54#endif
55#ifdef CONFIG_ARCH_TEGRA_114_SOC
56 { .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc },
57#endif
58#ifdef CONFIG_ARCH_TEGRA_124_SOC
59 { .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc },
60#endif
61 { }
62};
63MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
64
65static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
66{
67 unsigned long long tick;
68 unsigned int i;
69 u32 value;
70
71 /* compute the number of MC clock cycles per tick */
72 tick = mc->tick * clk_get_rate(mc->clk);
73 do_div(tick, NSEC_PER_SEC);
74
75 value = readl(mc->regs + MC_EMEM_ARB_CFG);
76 value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
77 value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
78 writel(value, mc->regs + MC_EMEM_ARB_CFG);
79
80 /* write latency allowance defaults */
81 for (i = 0; i < mc->soc->num_clients; i++) {
82 const struct tegra_mc_la *la = &mc->soc->clients[i].la;
83 u32 value;
84
85 value = readl(mc->regs + la->reg);
86 value &= ~(la->mask << la->shift);
87 value |= (la->def & la->mask) << la->shift;
88 writel(value, mc->regs + la->reg);
89 }
90
91 return 0;
92}
93
94static const char *const status_names[32] = {
95 [ 1] = "External interrupt",
96 [ 6] = "EMEM address decode error",
97 [ 8] = "Security violation",
98 [ 9] = "EMEM arbitration error",
99 [10] = "Page fault",
100 [11] = "Invalid APB ASID update",
101 [12] = "VPR violation",
102 [13] = "Secure carveout violation",
103 [16] = "MTS carveout violation",
104};
105
106static const char *const error_names[8] = {
107 [2] = "EMEM decode error",
108 [3] = "TrustZone violation",
109 [4] = "Carveout violation",
110 [6] = "SMMU translation error",
111};
112
113static irqreturn_t tegra_mc_irq(int irq, void *data)
114{
115 struct tegra_mc *mc = data;
116 unsigned long status, mask;
117 unsigned int bit;
118
119 /* mask all interrupts to avoid flooding */
120 status = mc_readl(mc, MC_INTSTATUS);
121 mask = mc_readl(mc, MC_INTMASK);
122
123 for_each_set_bit(bit, &status, 32) {
124 const char *error = status_names[bit] ?: "unknown";
125 const char *client = "unknown", *desc;
126 const char *direction, *secure;
127 phys_addr_t addr = 0;
128 unsigned int i;
129 char perm[7];
130 u8 id, type;
131 u32 value;
132
133 value = mc_readl(mc, MC_ERR_STATUS);
134
135#ifdef CONFIG_PHYS_ADDR_T_64BIT
136 if (mc->soc->num_address_bits > 32) {
137 addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
138 MC_ERR_STATUS_ADR_HI_MASK);
139 addr <<= 32;
140 }
141#endif
142
143 if (value & MC_ERR_STATUS_RW)
144 direction = "write";
145 else
146 direction = "read";
147
148 if (value & MC_ERR_STATUS_SECURITY)
149 secure = "secure ";
150 else
151 secure = "";
152
153 id = value & MC_ERR_STATUS_CLIENT_MASK;
154
155 for (i = 0; i < mc->soc->num_clients; i++) {
156 if (mc->soc->clients[i].id == id) {
157 client = mc->soc->clients[i].name;
158 break;
159 }
160 }
161
162 type = (value & MC_ERR_STATUS_TYPE_MASK) >>
163 MC_ERR_STATUS_TYPE_SHIFT;
164 desc = error_names[type];
165
166 switch (value & MC_ERR_STATUS_TYPE_MASK) {
167 case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
168 perm[0] = ' ';
169 perm[1] = '[';
170
171 if (value & MC_ERR_STATUS_READABLE)
172 perm[2] = 'R';
173 else
174 perm[2] = '-';
175
176 if (value & MC_ERR_STATUS_WRITABLE)
177 perm[3] = 'W';
178 else
179 perm[3] = '-';
180
181 if (value & MC_ERR_STATUS_NONSECURE)
182 perm[4] = '-';
183 else
184 perm[4] = 'S';
185
186 perm[5] = ']';
187 perm[6] = '\0';
188 break;
189
190 default:
191 perm[0] = '\0';
192 break;
193 }
194
195 value = mc_readl(mc, MC_ERR_ADR);
196 addr |= value;
197
198 dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n",
199 client, secure, direction, &addr, error,
200 desc, perm);
201 }
202
203 /* clear interrupts */
204 mc_writel(mc, status, MC_INTSTATUS);
205
206 return IRQ_HANDLED;
207}
208
209static int tegra_mc_probe(struct platform_device *pdev)
210{
211 const struct of_device_id *match;
212 struct resource *res;
213 struct tegra_mc *mc;
214 u32 value;
215 int err;
216
217 match = of_match_node(tegra_mc_of_match, pdev->dev.of_node);
218 if (!match)
219 return -ENODEV;
220
221 mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
222 if (!mc)
223 return -ENOMEM;
224
225 platform_set_drvdata(pdev, mc);
226 mc->soc = match->data;
227 mc->dev = &pdev->dev;
228
229 /* length of MC tick in nanoseconds */
230 mc->tick = 30;
231
232 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
233 mc->regs = devm_ioremap_resource(&pdev->dev, res);
234 if (IS_ERR(mc->regs))
235 return PTR_ERR(mc->regs);
236
237 mc->clk = devm_clk_get(&pdev->dev, "mc");
238 if (IS_ERR(mc->clk)) {
239 dev_err(&pdev->dev, "failed to get MC clock: %ld\n",
240 PTR_ERR(mc->clk));
241 return PTR_ERR(mc->clk);
242 }
243
244 err = tegra_mc_setup_latency_allowance(mc);
245 if (err < 0) {
246 dev_err(&pdev->dev, "failed to setup latency allowance: %d\n",
247 err);
248 return err;
249 }
250
251 if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) {
252 mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
253 if (IS_ERR(mc->smmu)) {
254 dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
255 PTR_ERR(mc->smmu));
256 return PTR_ERR(mc->smmu);
257 }
258 }
259
260 mc->irq = platform_get_irq(pdev, 0);
261 if (mc->irq < 0) {
262 dev_err(&pdev->dev, "interrupt not specified\n");
263 return mc->irq;
264 }
265
266 err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED,
267 dev_name(&pdev->dev), mc);
268 if (err < 0) {
269 dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
270 err);
271 return err;
272 }
273
274 value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
275 MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
276 MC_INT_ARBITRATION_EMEM | MC_INT_SECURITY_VIOLATION |
277 MC_INT_DECERR_EMEM;
278 mc_writel(mc, value, MC_INTMASK);
279
280 return 0;
281}
282
283static struct platform_driver tegra_mc_driver = {
284 .driver = {
285 .name = "tegra-mc",
286 .of_match_table = tegra_mc_of_match,
287 .suppress_bind_attrs = true,
288 },
289 .prevent_deferred_probe = true,
290 .probe = tegra_mc_probe,
291};
292
293static int tegra_mc_init(void)
294{
295 return platform_driver_register(&tegra_mc_driver);
296}
297arch_initcall(tegra_mc_init);
298
299MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
300MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver");
301MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
new file mode 100644
index 000000000000..d5d21147fc77
--- /dev/null
+++ b/drivers/memory/tegra/mc.h
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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 MEMORY_TEGRA_MC_H
10#define MEMORY_TEGRA_MC_H
11
12#include <linux/io.h>
13#include <linux/types.h>
14
15#include <soc/tegra/mc.h>
16
17static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
18{
19 return readl(mc->regs + offset);
20}
21
22static inline void mc_writel(struct tegra_mc *mc, u32 value,
23 unsigned long offset)
24{
25 writel(value, mc->regs + offset);
26}
27
28#ifdef CONFIG_ARCH_TEGRA_3x_SOC
29extern const struct tegra_mc_soc tegra30_mc_soc;
30#endif
31
32#ifdef CONFIG_ARCH_TEGRA_114_SOC
33extern const struct tegra_mc_soc tegra114_mc_soc;
34#endif
35
36#ifdef CONFIG_ARCH_TEGRA_124_SOC
37extern const struct tegra_mc_soc tegra124_mc_soc;
38#endif
39
40#endif /* MEMORY_TEGRA_MC_H */
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
new file mode 100644
index 000000000000..511e9a25c151
--- /dev/null
+++ b/drivers/memory/tegra/tegra114.c
@@ -0,0 +1,948 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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/of.h>
10#include <linux/mm.h>
11
12#include <asm/cacheflush.h>
13
14#include <dt-bindings/memory/tegra114-mc.h>
15
16#include "mc.h"
17
18static const struct tegra_mc_client tegra114_mc_clients[] = {
19 {
20 .id = 0x00,
21 .name = "ptcr",
22 .swgroup = TEGRA_SWGROUP_PTC,
23 }, {
24 .id = 0x01,
25 .name = "display0a",
26 .swgroup = TEGRA_SWGROUP_DC,
27 .smmu = {
28 .reg = 0x228,
29 .bit = 1,
30 },
31 .la = {
32 .reg = 0x2e8,
33 .shift = 0,
34 .mask = 0xff,
35 .def = 0x4e,
36 },
37 }, {
38 .id = 0x02,
39 .name = "display0ab",
40 .swgroup = TEGRA_SWGROUP_DCB,
41 .smmu = {
42 .reg = 0x228,
43 .bit = 2,
44 },
45 .la = {
46 .reg = 0x2f4,
47 .shift = 0,
48 .mask = 0xff,
49 .def = 0x4e,
50 },
51 }, {
52 .id = 0x03,
53 .name = "display0b",
54 .swgroup = TEGRA_SWGROUP_DC,
55 .smmu = {
56 .reg = 0x228,
57 .bit = 3,
58 },
59 .la = {
60 .reg = 0x2e8,
61 .shift = 16,
62 .mask = 0xff,
63 .def = 0x4e,
64 },
65 }, {
66 .id = 0x04,
67 .name = "display0bb",
68 .swgroup = TEGRA_SWGROUP_DCB,
69 .smmu = {
70 .reg = 0x228,
71 .bit = 4,
72 },
73 .la = {
74 .reg = 0x2f4,
75 .shift = 16,
76 .mask = 0xff,
77 .def = 0x4e,
78 },
79 }, {
80 .id = 0x05,
81 .name = "display0c",
82 .swgroup = TEGRA_SWGROUP_DC,
83 .smmu = {
84 .reg = 0x228,
85 .bit = 5,
86 },
87 .la = {
88 .reg = 0x2ec,
89 .shift = 0,
90 .mask = 0xff,
91 .def = 0x4e,
92 },
93 }, {
94 .id = 0x06,
95 .name = "display0cb",
96 .swgroup = TEGRA_SWGROUP_DCB,
97 .smmu = {
98 .reg = 0x228,
99 .bit = 6,
100 },
101 .la = {
102 .reg = 0x2f8,
103 .shift = 0,
104 .mask = 0xff,
105 .def = 0x4e,
106 },
107 }, {
108 .id = 0x09,
109 .name = "eppup",
110 .swgroup = TEGRA_SWGROUP_EPP,
111 .smmu = {
112 .reg = 0x228,
113 .bit = 9,
114 },
115 .la = {
116 .reg = 0x300,
117 .shift = 0,
118 .mask = 0xff,
119 .def = 0x33,
120 },
121 }, {
122 .id = 0x0a,
123 .name = "g2pr",
124 .swgroup = TEGRA_SWGROUP_G2,
125 .smmu = {
126 .reg = 0x228,
127 .bit = 10,
128 },
129 .la = {
130 .reg = 0x308,
131 .shift = 0,
132 .mask = 0xff,
133 .def = 0x09,
134 },
135 }, {
136 .id = 0x0b,
137 .name = "g2sr",
138 .swgroup = TEGRA_SWGROUP_G2,
139 .smmu = {
140 .reg = 0x228,
141 .bit = 11,
142 },
143 .la = {
144 .reg = 0x308,
145 .shift = 16,
146 .mask = 0xff,
147 .def = 0x09,
148 },
149 }, {
150 .id = 0x0f,
151 .name = "avpcarm7r",
152 .swgroup = TEGRA_SWGROUP_AVPC,
153 .smmu = {
154 .reg = 0x228,
155 .bit = 15,
156 },
157 .la = {
158 .reg = 0x2e4,
159 .shift = 0,
160 .mask = 0xff,
161 .def = 0x04,
162 },
163 }, {
164 .id = 0x10,
165 .name = "displayhc",
166 .swgroup = TEGRA_SWGROUP_DC,
167 .smmu = {
168 .reg = 0x228,
169 .bit = 16,
170 },
171 .la = {
172 .reg = 0x2f0,
173 .shift = 0,
174 .mask = 0xff,
175 .def = 0x68,
176 },
177 }, {
178 .id = 0x11,
179 .name = "displayhcb",
180 .swgroup = TEGRA_SWGROUP_DCB,
181 .smmu = {
182 .reg = 0x228,
183 .bit = 17,
184 },
185 .la = {
186 .reg = 0x2fc,
187 .shift = 0,
188 .mask = 0xff,
189 .def = 0x68,
190 },
191 }, {
192 .id = 0x12,
193 .name = "fdcdrd",
194 .swgroup = TEGRA_SWGROUP_NV,
195 .smmu = {
196 .reg = 0x228,
197 .bit = 18,
198 },
199 .la = {
200 .reg = 0x334,
201 .shift = 0,
202 .mask = 0xff,
203 .def = 0x0c,
204 },
205 }, {
206 .id = 0x13,
207 .name = "fdcdrd2",
208 .swgroup = TEGRA_SWGROUP_NV,
209 .smmu = {
210 .reg = 0x228,
211 .bit = 19,
212 },
213 .la = {
214 .reg = 0x33c,
215 .shift = 0,
216 .mask = 0xff,
217 .def = 0x0c,
218 },
219 }, {
220 .id = 0x14,
221 .name = "g2dr",
222 .swgroup = TEGRA_SWGROUP_G2,
223 .smmu = {
224 .reg = 0x228,
225 .bit = 20,
226 },
227 .la = {
228 .reg = 0x30c,
229 .shift = 0,
230 .mask = 0xff,
231 .def = 0x0a,
232 },
233 }, {
234 .id = 0x15,
235 .name = "hdar",
236 .swgroup = TEGRA_SWGROUP_HDA,
237 .smmu = {
238 .reg = 0x228,
239 .bit = 21,
240 },
241 .la = {
242 .reg = 0x318,
243 .shift = 0,
244 .mask = 0xff,
245 .def = 0xff,
246 },
247 }, {
248 .id = 0x16,
249 .name = "host1xdmar",
250 .swgroup = TEGRA_SWGROUP_HC,
251 .smmu = {
252 .reg = 0x228,
253 .bit = 22,
254 },
255 .la = {
256 .reg = 0x310,
257 .shift = 0,
258 .mask = 0xff,
259 .def = 0x10,
260 },
261 }, {
262 .id = 0x17,
263 .name = "host1xr",
264 .swgroup = TEGRA_SWGROUP_HC,
265 .smmu = {
266 .reg = 0x228,
267 .bit = 23,
268 },
269 .la = {
270 .reg = 0x310,
271 .shift = 16,
272 .mask = 0xff,
273 .def = 0xa5,
274 },
275 }, {
276 .id = 0x18,
277 .name = "idxsrd",
278 .swgroup = TEGRA_SWGROUP_NV,
279 .smmu = {
280 .reg = 0x228,
281 .bit = 24,
282 },
283 .la = {
284 .reg = 0x334,
285 .shift = 16,
286 .mask = 0xff,
287 .def = 0x0b,
288 },
289 }, {
290 .id = 0x1c,
291 .name = "msencsrd",
292 .swgroup = TEGRA_SWGROUP_MSENC,
293 .smmu = {
294 .reg = 0x228,
295 .bit = 28,
296 },
297 .la = {
298 .reg = 0x328,
299 .shift = 0,
300 .mask = 0xff,
301 .def = 0x80,
302 },
303 }, {
304 .id = 0x1d,
305 .name = "ppcsahbdmar",
306 .swgroup = TEGRA_SWGROUP_PPCS,
307 .smmu = {
308 .reg = 0x228,
309 .bit = 29,
310 },
311 .la = {
312 .reg = 0x344,
313 .shift = 0,
314 .mask = 0xff,
315 .def = 0x50,
316 },
317 }, {
318 .id = 0x1e,
319 .name = "ppcsahbslvr",
320 .swgroup = TEGRA_SWGROUP_PPCS,
321 .smmu = {
322 .reg = 0x228,
323 .bit = 30,
324 },
325 .la = {
326 .reg = 0x344,
327 .shift = 16,
328 .mask = 0xff,
329 .def = 0xe8,
330 },
331 }, {
332 .id = 0x20,
333 .name = "texl2srd",
334 .swgroup = TEGRA_SWGROUP_NV,
335 .smmu = {
336 .reg = 0x22c,
337 .bit = 0,
338 },
339 .la = {
340 .reg = 0x338,
341 .shift = 0,
342 .mask = 0xff,
343 .def = 0x0c,
344 },
345 }, {
346 .id = 0x22,
347 .name = "vdebsevr",
348 .swgroup = TEGRA_SWGROUP_VDE,
349 .smmu = {
350 .reg = 0x22c,
351 .bit = 2,
352 },
353 .la = {
354 .reg = 0x354,
355 .shift = 0,
356 .mask = 0xff,
357 .def = 0xff,
358 },
359 }, {
360 .id = 0x23,
361 .name = "vdember",
362 .swgroup = TEGRA_SWGROUP_VDE,
363 .smmu = {
364 .reg = 0x22c,
365 .bit = 3,
366 },
367 .la = {
368 .reg = 0x354,
369 .shift = 16,
370 .mask = 0xff,
371 .def = 0xff,
372 },
373 }, {
374 .id = 0x24,
375 .name = "vdemcer",
376 .swgroup = TEGRA_SWGROUP_VDE,
377 .smmu = {
378 .reg = 0x22c,
379 .bit = 4,
380 },
381 .la = {
382 .reg = 0x358,
383 .shift = 0,
384 .mask = 0xff,
385 .def = 0xb8,
386 },
387 }, {
388 .id = 0x25,
389 .name = "vdetper",
390 .swgroup = TEGRA_SWGROUP_VDE,
391 .smmu = {
392 .reg = 0x22c,
393 .bit = 5,
394 },
395 .la = {
396 .reg = 0x358,
397 .shift = 16,
398 .mask = 0xff,
399 .def = 0xee,
400 },
401 }, {
402 .id = 0x26,
403 .name = "mpcorelpr",
404 .swgroup = TEGRA_SWGROUP_MPCORELP,
405 .la = {
406 .reg = 0x324,
407 .shift = 0,
408 .mask = 0xff,
409 .def = 0x04,
410 },
411 }, {
412 .id = 0x27,
413 .name = "mpcorer",
414 .swgroup = TEGRA_SWGROUP_MPCORE,
415 .la = {
416 .reg = 0x320,
417 .shift = 0,
418 .mask = 0xff,
419 .def = 0x04,
420 },
421 }, {
422 .id = 0x28,
423 .name = "eppu",
424 .swgroup = TEGRA_SWGROUP_EPP,
425 .smmu = {
426 .reg = 0x22c,
427 .bit = 8,
428 },
429 .la = {
430 .reg = 0x300,
431 .shift = 16,
432 .mask = 0xff,
433 .def = 0x33,
434 },
435 }, {
436 .id = 0x29,
437 .name = "eppv",
438 .swgroup = TEGRA_SWGROUP_EPP,
439 .smmu = {
440 .reg = 0x22c,
441 .bit = 9,
442 },
443 .la = {
444 .reg = 0x304,
445 .shift = 0,
446 .mask = 0xff,
447 .def = 0x6c,
448 },
449 }, {
450 .id = 0x2a,
451 .name = "eppy",
452 .swgroup = TEGRA_SWGROUP_EPP,
453 .smmu = {
454 .reg = 0x22c,
455 .bit = 10,
456 },
457 .la = {
458 .reg = 0x304,
459 .shift = 16,
460 .mask = 0xff,
461 .def = 0x6c,
462 },
463 }, {
464 .id = 0x2b,
465 .name = "msencswr",
466 .swgroup = TEGRA_SWGROUP_MSENC,
467 .smmu = {
468 .reg = 0x22c,
469 .bit = 11,
470 },
471 .la = {
472 .reg = 0x328,
473 .shift = 16,
474 .mask = 0xff,
475 .def = 0x80,
476 },
477 }, {
478 .id = 0x2c,
479 .name = "viwsb",
480 .swgroup = TEGRA_SWGROUP_VI,
481 .smmu = {
482 .reg = 0x22c,
483 .bit = 12,
484 },
485 .la = {
486 .reg = 0x364,
487 .shift = 0,
488 .mask = 0xff,
489 .def = 0x47,
490 },
491 }, {
492 .id = 0x2d,
493 .name = "viwu",
494 .swgroup = TEGRA_SWGROUP_VI,
495 .smmu = {
496 .reg = 0x22c,
497 .bit = 13,
498 },
499 .la = {
500 .reg = 0x368,
501 .shift = 0,
502 .mask = 0xff,
503 .def = 0xff,
504 },
505 }, {
506 .id = 0x2e,
507 .name = "viwv",
508 .swgroup = TEGRA_SWGROUP_VI,
509 .smmu = {
510 .reg = 0x22c,
511 .bit = 14,
512 },
513 .la = {
514 .reg = 0x368,
515 .shift = 16,
516 .mask = 0xff,
517 .def = 0xff,
518 },
519 }, {
520 .id = 0x2f,
521 .name = "viwy",
522 .swgroup = TEGRA_SWGROUP_VI,
523 .smmu = {
524 .reg = 0x22c,
525 .bit = 15,
526 },
527 .la = {
528 .reg = 0x36c,
529 .shift = 0,
530 .mask = 0xff,
531 .def = 0x47,
532 },
533 }, {
534 .id = 0x30,
535 .name = "g2dw",
536 .swgroup = TEGRA_SWGROUP_G2,
537 .smmu = {
538 .reg = 0x22c,
539 .bit = 16,
540 },
541 .la = {
542 .reg = 0x30c,
543 .shift = 16,
544 .mask = 0xff,
545 .def = 0x9,
546 },
547 }, {
548 .id = 0x32,
549 .name = "avpcarm7w",
550 .swgroup = TEGRA_SWGROUP_AVPC,
551 .smmu = {
552 .reg = 0x22c,
553 .bit = 18,
554 },
555 .la = {
556 .reg = 0x2e4,
557 .shift = 16,
558 .mask = 0xff,
559 .def = 0x0e,
560 },
561 }, {
562 .id = 0x33,
563 .name = "fdcdwr",
564 .swgroup = TEGRA_SWGROUP_NV,
565 .smmu = {
566 .reg = 0x22c,
567 .bit = 19,
568 },
569 .la = {
570 .reg = 0x338,
571 .shift = 16,
572 .mask = 0xff,
573 .def = 0x10,
574 },
575 }, {
576 .id = 0x34,
577 .name = "fdcwr2",
578 .swgroup = TEGRA_SWGROUP_NV,
579 .smmu = {
580 .reg = 0x22c,
581 .bit = 20,
582 },
583 .la = {
584 .reg = 0x340,
585 .shift = 0,
586 .mask = 0xff,
587 .def = 0x10,
588 },
589 }, {
590 .id = 0x35,
591 .name = "hdaw",
592 .swgroup = TEGRA_SWGROUP_HDA,
593 .smmu = {
594 .reg = 0x22c,
595 .bit = 21,
596 },
597 .la = {
598 .reg = 0x318,
599 .shift = 16,
600 .mask = 0xff,
601 .def = 0xff,
602 },
603 }, {
604 .id = 0x36,
605 .name = "host1xw",
606 .swgroup = TEGRA_SWGROUP_HC,
607 .smmu = {
608 .reg = 0x22c,
609 .bit = 22,
610 },
611 .la = {
612 .reg = 0x314,
613 .shift = 0,
614 .mask = 0xff,
615 .def = 0x25,
616 },
617 }, {
618 .id = 0x37,
619 .name = "ispw",
620 .swgroup = TEGRA_SWGROUP_ISP,
621 .smmu = {
622 .reg = 0x22c,
623 .bit = 23,
624 },
625 .la = {
626 .reg = 0x31c,
627 .shift = 0,
628 .mask = 0xff,
629 .def = 0xff,
630 },
631 }, {
632 .id = 0x38,
633 .name = "mpcorelpw",
634 .swgroup = TEGRA_SWGROUP_MPCORELP,
635 .la = {
636 .reg = 0x324,
637 .shift = 16,
638 .mask = 0xff,
639 .def = 0x80,
640 },
641 }, {
642 .id = 0x39,
643 .name = "mpcorew",
644 .swgroup = TEGRA_SWGROUP_MPCORE,
645 .la = {
646 .reg = 0x320,
647 .shift = 16,
648 .mask = 0xff,
649 .def = 0x0e,
650 },
651 }, {
652 .id = 0x3b,
653 .name = "ppcsahbdmaw",
654 .swgroup = TEGRA_SWGROUP_PPCS,
655 .smmu = {
656 .reg = 0x22c,
657 .bit = 27,
658 },
659 .la = {
660 .reg = 0x348,
661 .shift = 0,
662 .mask = 0xff,
663 .def = 0xa5,
664 },
665 }, {
666 .id = 0x3c,
667 .name = "ppcsahbslvw",
668 .swgroup = TEGRA_SWGROUP_PPCS,
669 .smmu = {
670 .reg = 0x22c,
671 .bit = 28,
672 },
673 .la = {
674 .reg = 0x348,
675 .shift = 16,
676 .mask = 0xff,
677 .def = 0xe8,
678 },
679 }, {
680 .id = 0x3e,
681 .name = "vdebsevw",
682 .swgroup = TEGRA_SWGROUP_VDE,
683 .smmu = {
684 .reg = 0x22c,
685 .bit = 30,
686 },
687 .la = {
688 .reg = 0x35c,
689 .shift = 0,
690 .mask = 0xff,
691 .def = 0xff,
692 },
693 }, {
694 .id = 0x3f,
695 .name = "vdedbgw",
696 .swgroup = TEGRA_SWGROUP_VDE,
697 .smmu = {
698 .reg = 0x22c,
699 .bit = 31,
700 },
701 .la = {
702 .reg = 0x35c,
703 .shift = 16,
704 .mask = 0xff,
705 .def = 0xff,
706 },
707 }, {
708 .id = 0x40,
709 .name = "vdembew",
710 .swgroup = TEGRA_SWGROUP_VDE,
711 .smmu = {
712 .reg = 0x230,
713 .bit = 0,
714 },
715 .la = {
716 .reg = 0x360,
717 .shift = 0,
718 .mask = 0xff,
719 .def = 0x89,
720 },
721 }, {
722 .id = 0x41,
723 .name = "vdetpmw",
724 .swgroup = TEGRA_SWGROUP_VDE,
725 .smmu = {
726 .reg = 0x230,
727 .bit = 1,
728 },
729 .la = {
730 .reg = 0x360,
731 .shift = 16,
732 .mask = 0xff,
733 .def = 0x59,
734 },
735 }, {
736 .id = 0x4a,
737 .name = "xusb_hostr",
738 .swgroup = TEGRA_SWGROUP_XUSB_HOST,
739 .smmu = {
740 .reg = 0x230,
741 .bit = 10,
742 },
743 .la = {
744 .reg = 0x37c,
745 .shift = 0,
746 .mask = 0xff,
747 .def = 0xa5,
748 },
749 }, {
750 .id = 0x4b,
751 .name = "xusb_hostw",
752 .swgroup = TEGRA_SWGROUP_XUSB_HOST,
753 .smmu = {
754 .reg = 0x230,
755 .bit = 11,
756 },
757 .la = {
758 .reg = 0x37c,
759 .shift = 16,
760 .mask = 0xff,
761 .def = 0xa5,
762 },
763 }, {
764 .id = 0x4c,
765 .name = "xusb_devr",
766 .swgroup = TEGRA_SWGROUP_XUSB_DEV,
767 .smmu = {
768 .reg = 0x230,
769 .bit = 12,
770 },
771 .la = {
772 .reg = 0x380,
773 .shift = 0,
774 .mask = 0xff,
775 .def = 0xa5,
776 },
777 }, {
778 .id = 0x4d,
779 .name = "xusb_devw",
780 .swgroup = TEGRA_SWGROUP_XUSB_DEV,
781 .smmu = {
782 .reg = 0x230,
783 .bit = 13,
784 },
785 .la = {
786 .reg = 0x380,
787 .shift = 16,
788 .mask = 0xff,
789 .def = 0xa5,
790 },
791 }, {
792 .id = 0x4e,
793 .name = "fdcdwr3",
794 .swgroup = TEGRA_SWGROUP_NV,
795 .smmu = {
796 .reg = 0x230,
797 .bit = 14,
798 },
799 .la = {
800 .reg = 0x388,
801 .shift = 0,
802 .mask = 0xff,
803 .def = 0x10,
804 },
805 }, {
806 .id = 0x4f,
807 .name = "fdcdrd3",
808 .swgroup = TEGRA_SWGROUP_NV,
809 .smmu = {
810 .reg = 0x230,
811 .bit = 15,
812 },
813 .la = {
814 .reg = 0x384,
815 .shift = 0,
816 .mask = 0xff,
817 .def = 0x0c,
818 },
819 }, {
820 .id = 0x50,
821 .name = "fdcwr4",
822 .swgroup = TEGRA_SWGROUP_NV,
823 .smmu = {
824 .reg = 0x230,
825 .bit = 16,
826 },
827 .la = {
828 .reg = 0x388,
829 .shift = 16,
830 .mask = 0xff,
831 .def = 0x10,
832 },
833 }, {
834 .id = 0x51,
835 .name = "fdcrd4",
836 .swgroup = TEGRA_SWGROUP_NV,
837 .smmu = {
838 .reg = 0x230,
839 .bit = 17,
840 },
841 .la = {
842 .reg = 0x384,
843 .shift = 16,
844 .mask = 0xff,
845 .def = 0x0c,
846 },
847 }, {
848 .id = 0x52,
849 .name = "emucifr",
850 .swgroup = TEGRA_SWGROUP_EMUCIF,
851 .la = {
852 .reg = 0x38c,
853 .shift = 0,
854 .mask = 0xff,
855 .def = 0x04,
856 },
857 }, {
858 .id = 0x53,
859 .name = "emucifw",
860 .swgroup = TEGRA_SWGROUP_EMUCIF,
861 .la = {
862 .reg = 0x38c,
863 .shift = 16,
864 .mask = 0xff,
865 .def = 0x0e,
866 },
867 }, {
868 .id = 0x54,
869 .name = "tsecsrd",
870 .swgroup = TEGRA_SWGROUP_TSEC,
871 .smmu = {
872 .reg = 0x230,
873 .bit = 20,
874 },
875 .la = {
876 .reg = 0x390,
877 .shift = 0,
878 .mask = 0xff,
879 .def = 0x50,
880 },
881 }, {
882 .id = 0x55,
883 .name = "tsecswr",
884 .swgroup = TEGRA_SWGROUP_TSEC,
885 .smmu = {
886 .reg = 0x230,
887 .bit = 21,
888 },
889 .la = {
890 .reg = 0x390,
891 .shift = 16,
892 .mask = 0xff,
893 .def = 0x50,
894 },
895 },
896};
897
898static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
899 { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
900 { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
901 { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 },
902 { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c },
903 { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
904 { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
905 { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
906 { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
907 { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 },
908 { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
909 { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
910 { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
911 { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
912 { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
913 { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c },
914 { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
915};
916
917static void tegra114_flush_dcache(struct page *page, unsigned long offset,
918 size_t size)
919{
920 phys_addr_t phys = page_to_phys(page) + offset;
921 void *virt = page_address(page) + offset;
922
923 __cpuc_flush_dcache_area(virt, size);
924 outer_flush_range(phys, phys + size);
925}
926
927static const struct tegra_smmu_ops tegra114_smmu_ops = {
928 .flush_dcache = tegra114_flush_dcache,
929};
930
931static const struct tegra_smmu_soc tegra114_smmu_soc = {
932 .clients = tegra114_mc_clients,
933 .num_clients = ARRAY_SIZE(tegra114_mc_clients),
934 .swgroups = tegra114_swgroups,
935 .num_swgroups = ARRAY_SIZE(tegra114_swgroups),
936 .supports_round_robin_arbitration = false,
937 .supports_request_limit = false,
938 .num_asids = 4,
939 .ops = &tegra114_smmu_ops,
940};
941
942const struct tegra_mc_soc tegra114_mc_soc = {
943 .clients = tegra114_mc_clients,
944 .num_clients = ARRAY_SIZE(tegra114_mc_clients),
945 .num_address_bits = 32,
946 .atom_size = 32,
947 .smmu = &tegra114_smmu_soc,
948};
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
new file mode 100644
index 000000000000..278d40b854c1
--- /dev/null
+++ b/drivers/memory/tegra/tegra124.c
@@ -0,0 +1,995 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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/of.h>
10#include <linux/mm.h>
11
12#include <asm/cacheflush.h>
13
14#include <dt-bindings/memory/tegra124-mc.h>
15
16#include "mc.h"
17
18static const struct tegra_mc_client tegra124_mc_clients[] = {
19 {
20 .id = 0x00,
21 .name = "ptcr",
22 .swgroup = TEGRA_SWGROUP_PTC,
23 }, {
24 .id = 0x01,
25 .name = "display0a",
26 .swgroup = TEGRA_SWGROUP_DC,
27 .smmu = {
28 .reg = 0x228,
29 .bit = 1,
30 },
31 .la = {
32 .reg = 0x2e8,
33 .shift = 0,
34 .mask = 0xff,
35 .def = 0xc2,
36 },
37 }, {
38 .id = 0x02,
39 .name = "display0ab",
40 .swgroup = TEGRA_SWGROUP_DCB,
41 .smmu = {
42 .reg = 0x228,
43 .bit = 2,
44 },
45 .la = {
46 .reg = 0x2f4,
47 .shift = 0,
48 .mask = 0xff,
49 .def = 0xc6,
50 },
51 }, {
52 .id = 0x03,
53 .name = "display0b",
54 .swgroup = TEGRA_SWGROUP_DC,
55 .smmu = {
56 .reg = 0x228,
57 .bit = 3,
58 },
59 .la = {
60 .reg = 0x2e8,
61 .shift = 16,
62 .mask = 0xff,
63 .def = 0x50,
64 },
65 }, {
66 .id = 0x04,
67 .name = "display0bb",
68 .swgroup = TEGRA_SWGROUP_DCB,
69 .smmu = {
70 .reg = 0x228,
71 .bit = 4,
72 },
73 .la = {
74 .reg = 0x2f4,
75 .shift = 16,
76 .mask = 0xff,
77 .def = 0x50,
78 },
79 }, {
80 .id = 0x05,
81 .name = "display0c",
82 .swgroup = TEGRA_SWGROUP_DC,
83 .smmu = {
84 .reg = 0x228,
85 .bit = 5,
86 },
87 .la = {
88 .reg = 0x2ec,
89 .shift = 0,
90 .mask = 0xff,
91 .def = 0x50,
92 },
93 }, {
94 .id = 0x06,
95 .name = "display0cb",
96 .swgroup = TEGRA_SWGROUP_DCB,
97 .smmu = {
98 .reg = 0x228,
99 .bit = 6,
100 },
101 .la = {
102 .reg = 0x2f8,
103 .shift = 0,
104 .mask = 0xff,
105 .def = 0x50,
106 },
107 }, {
108 .id = 0x0e,
109 .name = "afir",
110 .swgroup = TEGRA_SWGROUP_AFI,
111 .smmu = {
112 .reg = 0x228,
113 .bit = 14,
114 },
115 .la = {
116 .reg = 0x2e0,
117 .shift = 0,
118 .mask = 0xff,
119 .def = 0x13,
120 },
121 }, {
122 .id = 0x0f,
123 .name = "avpcarm7r",
124 .swgroup = TEGRA_SWGROUP_AVPC,
125 .smmu = {
126 .reg = 0x228,
127 .bit = 15,
128 },
129 .la = {
130 .reg = 0x2e4,
131 .shift = 0,
132 .mask = 0xff,
133 .def = 0x04,
134 },
135 }, {
136 .id = 0x10,
137 .name = "displayhc",
138 .swgroup = TEGRA_SWGROUP_DC,
139 .smmu = {
140 .reg = 0x228,
141 .bit = 16,
142 },
143 .la = {
144 .reg = 0x2f0,
145 .shift = 0,
146 .mask = 0xff,
147 .def = 0x50,
148 },
149 }, {
150 .id = 0x11,
151 .name = "displayhcb",
152 .swgroup = TEGRA_SWGROUP_DCB,
153 .smmu = {
154 .reg = 0x228,
155 .bit = 17,
156 },
157 .la = {
158 .reg = 0x2fc,
159 .shift = 0,
160 .mask = 0xff,
161 .def = 0x50,
162 },
163 }, {
164 .id = 0x15,
165 .name = "hdar",
166 .swgroup = TEGRA_SWGROUP_HDA,
167 .smmu = {
168 .reg = 0x228,
169 .bit = 21,
170 },
171 .la = {
172 .reg = 0x318,
173 .shift = 0,
174 .mask = 0xff,
175 .def = 0x24,
176 },
177 }, {
178 .id = 0x16,
179 .name = "host1xdmar",
180 .swgroup = TEGRA_SWGROUP_HC,
181 .smmu = {
182 .reg = 0x228,
183 .bit = 22,
184 },
185 .la = {
186 .reg = 0x310,
187 .shift = 0,
188 .mask = 0xff,
189 .def = 0x1e,
190 },
191 }, {
192 .id = 0x17,
193 .name = "host1xr",
194 .swgroup = TEGRA_SWGROUP_HC,
195 .smmu = {
196 .reg = 0x228,
197 .bit = 23,
198 },
199 .la = {
200 .reg = 0x310,
201 .shift = 16,
202 .mask = 0xff,
203 .def = 0x50,
204 },
205 }, {
206 .id = 0x1c,
207 .name = "msencsrd",
208 .swgroup = TEGRA_SWGROUP_MSENC,
209 .smmu = {
210 .reg = 0x228,
211 .bit = 28,
212 },
213 .la = {
214 .reg = 0x328,
215 .shift = 0,
216 .mask = 0xff,
217 .def = 0x23,
218 },
219 }, {
220 .id = 0x1d,
221 .name = "ppcsahbdmar",
222 .swgroup = TEGRA_SWGROUP_PPCS,
223 .smmu = {
224 .reg = 0x228,
225 .bit = 29,
226 },
227 .la = {
228 .reg = 0x344,
229 .shift = 0,
230 .mask = 0xff,
231 .def = 0x49,
232 },
233 }, {
234 .id = 0x1e,
235 .name = "ppcsahbslvr",
236 .swgroup = TEGRA_SWGROUP_PPCS,
237 .smmu = {
238 .reg = 0x228,
239 .bit = 30,
240 },
241 .la = {
242 .reg = 0x344,
243 .shift = 16,
244 .mask = 0xff,
245 .def = 0x1a,
246 },
247 }, {
248 .id = 0x1f,
249 .name = "satar",
250 .swgroup = TEGRA_SWGROUP_SATA,
251 .smmu = {
252 .reg = 0x228,
253 .bit = 31,
254 },
255 .la = {
256 .reg = 0x350,
257 .shift = 0,
258 .mask = 0xff,
259 .def = 0x65,
260 },
261 }, {
262 .id = 0x22,
263 .name = "vdebsevr",
264 .swgroup = TEGRA_SWGROUP_VDE,
265 .smmu = {
266 .reg = 0x22c,
267 .bit = 2,
268 },
269 .la = {
270 .reg = 0x354,
271 .shift = 0,
272 .mask = 0xff,
273 .def = 0x4f,
274 },
275 }, {
276 .id = 0x23,
277 .name = "vdember",
278 .swgroup = TEGRA_SWGROUP_VDE,
279 .smmu = {
280 .reg = 0x22c,
281 .bit = 3,
282 },
283 .la = {
284 .reg = 0x354,
285 .shift = 16,
286 .mask = 0xff,
287 .def = 0x3d,
288 },
289 }, {
290 .id = 0x24,
291 .name = "vdemcer",
292 .swgroup = TEGRA_SWGROUP_VDE,
293 .smmu = {
294 .reg = 0x22c,
295 .bit = 4,
296 },
297 .la = {
298 .reg = 0x358,
299 .shift = 0,
300 .mask = 0xff,
301 .def = 0x66,
302 },
303 }, {
304 .id = 0x25,
305 .name = "vdetper",
306 .swgroup = TEGRA_SWGROUP_VDE,
307 .smmu = {
308 .reg = 0x22c,
309 .bit = 5,
310 },
311 .la = {
312 .reg = 0x358,
313 .shift = 16,
314 .mask = 0xff,
315 .def = 0xa5,
316 },
317 }, {
318 .id = 0x26,
319 .name = "mpcorelpr",
320 .swgroup = TEGRA_SWGROUP_MPCORELP,
321 .la = {
322 .reg = 0x324,
323 .shift = 0,
324 .mask = 0xff,
325 .def = 0x04,
326 },
327 }, {
328 .id = 0x27,
329 .name = "mpcorer",
330 .swgroup = TEGRA_SWGROUP_MPCORE,
331 .la = {
332 .reg = 0x320,
333 .shift = 0,
334 .mask = 0xff,
335 .def = 0x04,
336 },
337 }, {
338 .id = 0x2b,
339 .name = "msencswr",
340 .swgroup = TEGRA_SWGROUP_MSENC,
341 .smmu = {
342 .reg = 0x22c,
343 .bit = 11,
344 },
345 .la = {
346 .reg = 0x328,
347 .shift = 16,
348 .mask = 0xff,
349 .def = 0x80,
350 },
351 }, {
352 .id = 0x31,
353 .name = "afiw",
354 .swgroup = TEGRA_SWGROUP_AFI,
355 .smmu = {
356 .reg = 0x22c,
357 .bit = 17,
358 },
359 .la = {
360 .reg = 0x2e0,
361 .shift = 16,
362 .mask = 0xff,
363 .def = 0x80,
364 },
365 }, {
366 .id = 0x32,
367 .name = "avpcarm7w",
368 .swgroup = TEGRA_SWGROUP_AVPC,
369 .smmu = {
370 .reg = 0x22c,
371 .bit = 18,
372 },
373 .la = {
374 .reg = 0x2e4,
375 .shift = 16,
376 .mask = 0xff,
377 .def = 0x80,
378 },
379 }, {
380 .id = 0x35,
381 .name = "hdaw",
382 .swgroup = TEGRA_SWGROUP_HDA,
383 .smmu = {
384 .reg = 0x22c,
385 .bit = 21,
386 },
387 .la = {
388 .reg = 0x318,
389 .shift = 16,
390 .mask = 0xff,
391 .def = 0x80,
392 },
393 }, {
394 .id = 0x36,
395 .name = "host1xw",
396 .swgroup = TEGRA_SWGROUP_HC,
397 .smmu = {
398 .reg = 0x22c,
399 .bit = 22,
400 },
401 .la = {
402 .reg = 0x314,
403 .shift = 0,
404 .mask = 0xff,
405 .def = 0x80,
406 },
407 }, {
408 .id = 0x38,
409 .name = "mpcorelpw",
410 .swgroup = TEGRA_SWGROUP_MPCORELP,
411 .la = {
412 .reg = 0x324,
413 .shift = 16,
414 .mask = 0xff,
415 .def = 0x80,
416 },
417 }, {
418 .id = 0x39,
419 .name = "mpcorew",
420 .swgroup = TEGRA_SWGROUP_MPCORE,
421 .la = {
422 .reg = 0x320,
423 .shift = 16,
424 .mask = 0xff,
425 .def = 0x80,
426 },
427 }, {
428 .id = 0x3b,
429 .name = "ppcsahbdmaw",
430 .swgroup = TEGRA_SWGROUP_PPCS,
431 .smmu = {
432 .reg = 0x22c,
433 .bit = 27,
434 },
435 .la = {
436 .reg = 0x348,
437 .shift = 0,
438 .mask = 0xff,
439 .def = 0x80,
440 },
441 }, {
442 .id = 0x3c,
443 .name = "ppcsahbslvw",
444 .swgroup = TEGRA_SWGROUP_PPCS,
445 .smmu = {
446 .reg = 0x22c,
447 .bit = 28,
448 },
449 .la = {
450 .reg = 0x348,
451 .shift = 16,
452 .mask = 0xff,
453 .def = 0x80,
454 },
455 }, {
456 .id = 0x3d,
457 .name = "sataw",
458 .swgroup = TEGRA_SWGROUP_SATA,
459 .smmu = {
460 .reg = 0x22c,
461 .bit = 29,
462 },
463 .la = {
464 .reg = 0x350,
465 .shift = 16,
466 .mask = 0xff,
467 .def = 0x65,
468 },
469 }, {
470 .id = 0x3e,
471 .name = "vdebsevw",
472 .swgroup = TEGRA_SWGROUP_VDE,
473 .smmu = {
474 .reg = 0x22c,
475 .bit = 30,
476 },
477 .la = {
478 .reg = 0x35c,
479 .shift = 0,
480 .mask = 0xff,
481 .def = 0x80,
482 },
483 }, {
484 .id = 0x3f,
485 .name = "vdedbgw",
486 .swgroup = TEGRA_SWGROUP_VDE,
487 .smmu = {
488 .reg = 0x22c,
489 .bit = 31,
490 },
491 .la = {
492 .reg = 0x35c,
493 .shift = 16,
494 .mask = 0xff,
495 .def = 0x80,
496 },
497 }, {
498 .id = 0x40,
499 .name = "vdembew",
500 .swgroup = TEGRA_SWGROUP_VDE,
501 .smmu = {
502 .reg = 0x230,
503 .bit = 0,
504 },
505 .la = {
506 .reg = 0x360,
507 .shift = 0,
508 .mask = 0xff,
509 .def = 0x80,
510 },
511 }, {
512 .id = 0x41,
513 .name = "vdetpmw",
514 .swgroup = TEGRA_SWGROUP_VDE,
515 .smmu = {
516 .reg = 0x230,
517 .bit = 1,
518 },
519 .la = {
520 .reg = 0x360,
521 .shift = 16,
522 .mask = 0xff,
523 .def = 0x80,
524 },
525 }, {
526 .id = 0x44,
527 .name = "ispra",
528 .swgroup = TEGRA_SWGROUP_ISP2,
529 .smmu = {
530 .reg = 0x230,
531 .bit = 4,
532 },
533 .la = {
534 .reg = 0x370,
535 .shift = 0,
536 .mask = 0xff,
537 .def = 0x18,
538 },
539 }, {
540 .id = 0x46,
541 .name = "ispwa",
542 .swgroup = TEGRA_SWGROUP_ISP2,
543 .smmu = {
544 .reg = 0x230,
545 .bit = 6,
546 },
547 .la = {
548 .reg = 0x374,
549 .shift = 0,
550 .mask = 0xff,
551 .def = 0x80,
552 },
553 }, {
554 .id = 0x47,
555 .name = "ispwb",
556 .swgroup = TEGRA_SWGROUP_ISP2,
557 .smmu = {
558 .reg = 0x230,
559 .bit = 7,
560 },
561 .la = {
562 .reg = 0x374,
563 .shift = 16,
564 .mask = 0xff,
565 .def = 0x80,
566 },
567 }, {
568 .id = 0x4a,
569 .name = "xusb_hostr",
570 .swgroup = TEGRA_SWGROUP_XUSB_HOST,
571 .smmu = {
572 .reg = 0x230,
573 .bit = 10,
574 },
575 .la = {
576 .reg = 0x37c,
577 .shift = 0,
578 .mask = 0xff,
579 .def = 0x39,
580 },
581 }, {
582 .id = 0x4b,
583 .name = "xusb_hostw",
584 .swgroup = TEGRA_SWGROUP_XUSB_HOST,
585 .smmu = {
586 .reg = 0x230,
587 .bit = 11,
588 },
589 .la = {
590 .reg = 0x37c,
591 .shift = 16,
592 .mask = 0xff,
593 .def = 0x80,
594 },
595 }, {
596 .id = 0x4c,
597 .name = "xusb_devr",
598 .swgroup = TEGRA_SWGROUP_XUSB_DEV,
599 .smmu = {
600 .reg = 0x230,
601 .bit = 12,
602 },
603 .la = {
604 .reg = 0x380,
605 .shift = 0,
606 .mask = 0xff,
607 .def = 0x39,
608 },
609 }, {
610 .id = 0x4d,
611 .name = "xusb_devw",
612 .swgroup = TEGRA_SWGROUP_XUSB_DEV,
613 .smmu = {
614 .reg = 0x230,
615 .bit = 13,
616 },
617 .la = {
618 .reg = 0x380,
619 .shift = 16,
620 .mask = 0xff,
621 .def = 0x80,
622 },
623 }, {
624 .id = 0x4e,
625 .name = "isprab",
626 .swgroup = TEGRA_SWGROUP_ISP2B,
627 .smmu = {
628 .reg = 0x230,
629 .bit = 14,
630 },
631 .la = {
632 .reg = 0x384,
633 .shift = 0,
634 .mask = 0xff,
635 .def = 0x18,
636 },
637 }, {
638 .id = 0x50,
639 .name = "ispwab",
640 .swgroup = TEGRA_SWGROUP_ISP2B,
641 .smmu = {
642 .reg = 0x230,
643 .bit = 16,
644 },
645 .la = {
646 .reg = 0x388,
647 .shift = 0,
648 .mask = 0xff,
649 .def = 0x80,
650 },
651 }, {
652 .id = 0x51,
653 .name = "ispwbb",
654 .swgroup = TEGRA_SWGROUP_ISP2B,
655 .smmu = {
656 .reg = 0x230,
657 .bit = 17,
658 },
659 .la = {
660 .reg = 0x388,
661 .shift = 16,
662 .mask = 0xff,
663 .def = 0x80,
664 },
665 }, {
666 .id = 0x54,
667 .name = "tsecsrd",
668 .swgroup = TEGRA_SWGROUP_TSEC,
669 .smmu = {
670 .reg = 0x230,
671 .bit = 20,
672 },
673 .la = {
674 .reg = 0x390,
675 .shift = 0,
676 .mask = 0xff,
677 .def = 0x9b,
678 },
679 }, {
680 .id = 0x55,
681 .name = "tsecswr",
682 .swgroup = TEGRA_SWGROUP_TSEC,
683 .smmu = {
684 .reg = 0x230,
685 .bit = 21,
686 },
687 .la = {
688 .reg = 0x390,
689 .shift = 16,
690 .mask = 0xff,
691 .def = 0x80,
692 },
693 }, {
694 .id = 0x56,
695 .name = "a9avpscr",
696 .swgroup = TEGRA_SWGROUP_A9AVP,
697 .smmu = {
698 .reg = 0x230,
699 .bit = 22,
700 },
701 .la = {
702 .reg = 0x3a4,
703 .shift = 0,
704 .mask = 0xff,
705 .def = 0x04,
706 },
707 }, {
708 .id = 0x57,
709 .name = "a9avpscw",
710 .swgroup = TEGRA_SWGROUP_A9AVP,
711 .smmu = {
712 .reg = 0x230,
713 .bit = 23,
714 },
715 .la = {
716 .reg = 0x3a4,
717 .shift = 16,
718 .mask = 0xff,
719 .def = 0x80,
720 },
721 }, {
722 .id = 0x58,
723 .name = "gpusrd",
724 .swgroup = TEGRA_SWGROUP_GPU,
725 .smmu = {
726 /* read-only */
727 .reg = 0x230,
728 .bit = 24,
729 },
730 .la = {
731 .reg = 0x3c8,
732 .shift = 0,
733 .mask = 0xff,
734 .def = 0x1a,
735 },
736 }, {
737 .id = 0x59,
738 .name = "gpuswr",
739 .swgroup = TEGRA_SWGROUP_GPU,
740 .smmu = {
741 /* read-only */
742 .reg = 0x230,
743 .bit = 25,
744 },
745 .la = {
746 .reg = 0x3c8,
747 .shift = 16,
748 .mask = 0xff,
749 .def = 0x80,
750 },
751 }, {
752 .id = 0x5a,
753 .name = "displayt",
754 .swgroup = TEGRA_SWGROUP_DC,
755 .smmu = {
756 .reg = 0x230,
757 .bit = 26,
758 },
759 .la = {
760 .reg = 0x2f0,
761 .shift = 16,
762 .mask = 0xff,
763 .def = 0x50,
764 },
765 }, {
766 .id = 0x60,
767 .name = "sdmmcra",
768 .swgroup = TEGRA_SWGROUP_SDMMC1A,
769 .smmu = {
770 .reg = 0x234,
771 .bit = 0,
772 },
773 .la = {
774 .reg = 0x3b8,
775 .shift = 0,
776 .mask = 0xff,
777 .def = 0x49,
778 },
779 }, {
780 .id = 0x61,
781 .name = "sdmmcraa",
782 .swgroup = TEGRA_SWGROUP_SDMMC2A,
783 .smmu = {
784 .reg = 0x234,
785 .bit = 1,
786 },
787 .la = {
788 .reg = 0x3bc,
789 .shift = 0,
790 .mask = 0xff,
791 .def = 0x49,
792 },
793 }, {
794 .id = 0x62,
795 .name = "sdmmcr",
796 .swgroup = TEGRA_SWGROUP_SDMMC3A,
797 .smmu = {
798 .reg = 0x234,
799 .bit = 2,
800 },
801 .la = {
802 .reg = 0x3c0,
803 .shift = 0,
804 .mask = 0xff,
805 .def = 0x49,
806 },
807 }, {
808 .id = 0x63,
809 .swgroup = TEGRA_SWGROUP_SDMMC4A,
810 .name = "sdmmcrab",
811 .smmu = {
812 .reg = 0x234,
813 .bit = 3,
814 },
815 .la = {
816 .reg = 0x3c4,
817 .shift = 0,
818 .mask = 0xff,
819 .def = 0x49,
820 },
821 }, {
822 .id = 0x64,
823 .name = "sdmmcwa",
824 .swgroup = TEGRA_SWGROUP_SDMMC1A,
825 .smmu = {
826 .reg = 0x234,
827 .bit = 4,
828 },
829 .la = {
830 .reg = 0x3b8,
831 .shift = 16,
832 .mask = 0xff,
833 .def = 0x80,
834 },
835 }, {
836 .id = 0x65,
837 .name = "sdmmcwaa",
838 .swgroup = TEGRA_SWGROUP_SDMMC2A,
839 .smmu = {
840 .reg = 0x234,
841 .bit = 5,
842 },
843 .la = {
844 .reg = 0x3bc,
845 .shift = 16,
846 .mask = 0xff,
847 .def = 0x80,
848 },
849 }, {
850 .id = 0x66,
851 .name = "sdmmcw",
852 .swgroup = TEGRA_SWGROUP_SDMMC3A,
853 .smmu = {
854 .reg = 0x234,
855 .bit = 6,
856 },
857 .la = {
858 .reg = 0x3c0,
859 .shift = 16,
860 .mask = 0xff,
861 .def = 0x80,
862 },
863 }, {
864 .id = 0x67,
865 .name = "sdmmcwab",
866 .swgroup = TEGRA_SWGROUP_SDMMC4A,
867 .smmu = {
868 .reg = 0x234,
869 .bit = 7,
870 },
871 .la = {
872 .reg = 0x3c4,
873 .shift = 16,
874 .mask = 0xff,
875 .def = 0x80,
876 },
877 }, {
878 .id = 0x6c,
879 .name = "vicsrd",
880 .swgroup = TEGRA_SWGROUP_VIC,
881 .smmu = {
882 .reg = 0x234,
883 .bit = 12,
884 },
885 .la = {
886 .reg = 0x394,
887 .shift = 0,
888 .mask = 0xff,
889 .def = 0x1a,
890 },
891 }, {
892 .id = 0x6d,
893 .name = "vicswr",
894 .swgroup = TEGRA_SWGROUP_VIC,
895 .smmu = {
896 .reg = 0x234,
897 .bit = 13,
898 },
899 .la = {
900 .reg = 0x394,
901 .shift = 16,
902 .mask = 0xff,
903 .def = 0x80,
904 },
905 }, {
906 .id = 0x72,
907 .name = "viw",
908 .swgroup = TEGRA_SWGROUP_VI,
909 .smmu = {
910 .reg = 0x234,
911 .bit = 18,
912 },
913 .la = {
914 .reg = 0x398,
915 .shift = 0,
916 .mask = 0xff,
917 .def = 0x80,
918 },
919 }, {
920 .id = 0x73,
921 .name = "displayd",
922 .swgroup = TEGRA_SWGROUP_DC,
923 .smmu = {
924 .reg = 0x234,
925 .bit = 19,
926 },
927 .la = {
928 .reg = 0x3c8,
929 .shift = 0,
930 .mask = 0xff,
931 .def = 0x50,
932 },
933 },
934};
935
936static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
937 { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
938 { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
939 { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
940 { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
941 { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
942 { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
943 { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 },
944 { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
945 { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x274 },
946 { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
947 { .swgroup = TEGRA_SWGROUP_ISP2, .reg = 0x258 },
948 { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
949 { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c },
950 { .swgroup = TEGRA_SWGROUP_ISP2B, .reg = 0xaa4 },
951 { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
952 { .swgroup = TEGRA_SWGROUP_A9AVP, .reg = 0x290 },
953 { .swgroup = TEGRA_SWGROUP_GPU, .reg = 0xaac },
954 { .swgroup = TEGRA_SWGROUP_SDMMC1A, .reg = 0xa94 },
955 { .swgroup = TEGRA_SWGROUP_SDMMC2A, .reg = 0xa98 },
956 { .swgroup = TEGRA_SWGROUP_SDMMC3A, .reg = 0xa9c },
957 { .swgroup = TEGRA_SWGROUP_SDMMC4A, .reg = 0xaa0 },
958 { .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284 },
959 { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
960};
961
962#ifdef CONFIG_ARCH_TEGRA_124_SOC
963static void tegra124_flush_dcache(struct page *page, unsigned long offset,
964 size_t size)
965{
966 phys_addr_t phys = page_to_phys(page) + offset;
967 void *virt = page_address(page) + offset;
968
969 __cpuc_flush_dcache_area(virt, size);
970 outer_flush_range(phys, phys + size);
971}
972
973static const struct tegra_smmu_ops tegra124_smmu_ops = {
974 .flush_dcache = tegra124_flush_dcache,
975};
976
977static const struct tegra_smmu_soc tegra124_smmu_soc = {
978 .clients = tegra124_mc_clients,
979 .num_clients = ARRAY_SIZE(tegra124_mc_clients),
980 .swgroups = tegra124_swgroups,
981 .num_swgroups = ARRAY_SIZE(tegra124_swgroups),
982 .supports_round_robin_arbitration = true,
983 .supports_request_limit = true,
984 .num_asids = 128,
985 .ops = &tegra124_smmu_ops,
986};
987
988const struct tegra_mc_soc tegra124_mc_soc = {
989 .clients = tegra124_mc_clients,
990 .num_clients = ARRAY_SIZE(tegra124_mc_clients),
991 .num_address_bits = 34,
992 .atom_size = 32,
993 .smmu = &tegra124_smmu_soc,
994};
995#endif /* CONFIG_ARCH_TEGRA_124_SOC */
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
new file mode 100644
index 000000000000..71fe9376fe53
--- /dev/null
+++ b/drivers/memory/tegra/tegra30.c
@@ -0,0 +1,970 @@
1/*
2 * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
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/of.h>
10#include <linux/mm.h>
11
12#include <asm/cacheflush.h>
13
14#include <dt-bindings/memory/tegra30-mc.h>
15
16#include "mc.h"
17
18static const struct tegra_mc_client tegra30_mc_clients[] = {
19 {
20 .id = 0x00,
21 .name = "ptcr",
22 .swgroup = TEGRA_SWGROUP_PTC,
23 }, {
24 .id = 0x01,
25 .name = "display0a",
26 .swgroup = TEGRA_SWGROUP_DC,
27 .smmu = {
28 .reg = 0x228,
29 .bit = 1,
30 },
31 .la = {
32 .reg = 0x2e8,
33 .shift = 0,
34 .mask = 0xff,
35 .def = 0x4e,
36 },
37 }, {
38 .id = 0x02,
39 .name = "display0ab",
40 .swgroup = TEGRA_SWGROUP_DCB,
41 .smmu = {
42 .reg = 0x228,
43 .bit = 2,
44 },
45 .la = {
46 .reg = 0x2f4,
47 .shift = 0,
48 .mask = 0xff,
49 .def = 0x4e,
50 },
51 }, {
52 .id = 0x03,
53 .name = "display0b",
54 .swgroup = TEGRA_SWGROUP_DC,
55 .smmu = {
56 .reg = 0x228,
57 .bit = 3,
58 },
59 .la = {
60 .reg = 0x2e8,
61 .shift = 16,
62 .mask = 0xff,
63 .def = 0x4e,
64 },
65 }, {
66 .id = 0x04,
67 .name = "display0bb",
68 .swgroup = TEGRA_SWGROUP_DCB,
69 .smmu = {
70 .reg = 0x228,
71 .bit = 4,
72 },
73 .la = {
74 .reg = 0x2f4,
75 .shift = 16,
76 .mask = 0xff,
77 .def = 0x4e,
78 },
79 }, {
80 .id = 0x05,
81 .name = "display0c",
82 .swgroup = TEGRA_SWGROUP_DC,
83 .smmu = {
84 .reg = 0x228,
85 .bit = 5,
86 },
87 .la = {
88 .reg = 0x2ec,
89 .shift = 0,
90 .mask = 0xff,
91 .def = 0x4e,
92 },
93 }, {
94 .id = 0x06,
95 .name = "display0cb",
96 .swgroup = TEGRA_SWGROUP_DCB,
97 .smmu = {
98 .reg = 0x228,
99 .bit = 6,
100 },
101 .la = {
102 .reg = 0x2f8,
103 .shift = 0,
104 .mask = 0xff,
105 .def = 0x4e,
106 },
107 }, {
108 .id = 0x07,
109 .name = "display1b",
110 .swgroup = TEGRA_SWGROUP_DC,
111 .smmu = {
112 .reg = 0x228,
113 .bit = 7,
114 },
115 .la = {
116 .reg = 0x2ec,
117 .shift = 16,
118 .mask = 0xff,
119 .def = 0x4e,
120 },
121 }, {
122 .id = 0x08,
123 .name = "display1bb",
124 .swgroup = TEGRA_SWGROUP_DCB,
125 .smmu = {
126 .reg = 0x228,
127 .bit = 8,
128 },
129 .la = {
130 .reg = 0x2f8,
131 .shift = 16,
132 .mask = 0xff,
133 .def = 0x4e,
134 },
135 }, {
136 .id = 0x09,
137 .name = "eppup",
138 .swgroup = TEGRA_SWGROUP_EPP,
139 .smmu = {
140 .reg = 0x228,
141 .bit = 9,
142 },
143 .la = {
144 .reg = 0x300,
145 .shift = 0,
146 .mask = 0xff,
147 .def = 0x17,
148 },
149 }, {
150 .id = 0x0a,
151 .name = "g2pr",
152 .swgroup = TEGRA_SWGROUP_G2,
153 .smmu = {
154 .reg = 0x228,
155 .bit = 10,
156 },
157 .la = {
158 .reg = 0x308,
159 .shift = 0,
160 .mask = 0xff,
161 .def = 0x09,
162 },
163 }, {
164 .id = 0x0b,
165 .name = "g2sr",
166 .swgroup = TEGRA_SWGROUP_G2,
167 .smmu = {
168 .reg = 0x228,
169 .bit = 11,
170 },
171 .la = {
172 .reg = 0x308,
173 .shift = 16,
174 .mask = 0xff,
175 .def = 0x09,
176 },
177 }, {
178 .id = 0x0c,
179 .name = "mpeunifbr",
180 .swgroup = TEGRA_SWGROUP_MPE,
181 .smmu = {
182 .reg = 0x228,
183 .bit = 12,
184 },
185 .la = {
186 .reg = 0x328,
187 .shift = 0,
188 .mask = 0xff,
189 .def = 0x50,
190 },
191 }, {
192 .id = 0x0d,
193 .name = "viruv",
194 .swgroup = TEGRA_SWGROUP_VI,
195 .smmu = {
196 .reg = 0x228,
197 .bit = 13,
198 },
199 .la = {
200 .reg = 0x364,
201 .shift = 0,
202 .mask = 0xff,
203 .def = 0x2c,
204 },
205 }, {
206 .id = 0x0e,
207 .name = "afir",
208 .swgroup = TEGRA_SWGROUP_AFI,
209 .smmu = {
210 .reg = 0x228,
211 .bit = 14,
212 },
213 .la = {
214 .reg = 0x2e0,
215 .shift = 0,
216 .mask = 0xff,
217 .def = 0x10,
218 },
219 }, {
220 .id = 0x0f,
221 .name = "avpcarm7r",
222 .swgroup = TEGRA_SWGROUP_AVPC,
223 .smmu = {
224 .reg = 0x228,
225 .bit = 15,
226 },
227 .la = {
228 .reg = 0x2e4,
229 .shift = 0,
230 .mask = 0xff,
231 .def = 0x04,
232 },
233 }, {
234 .id = 0x10,
235 .name = "displayhc",
236 .swgroup = TEGRA_SWGROUP_DC,
237 .smmu = {
238 .reg = 0x228,
239 .bit = 16,
240 },
241 .la = {
242 .reg = 0x2f0,
243 .shift = 0,
244 .mask = 0xff,
245 .def = 0xff,
246 },
247 }, {
248 .id = 0x11,
249 .name = "displayhcb",
250 .swgroup = TEGRA_SWGROUP_DCB,
251 .smmu = {
252 .reg = 0x228,
253 .bit = 17,
254 },
255 .la = {
256 .reg = 0x2fc,
257 .shift = 0,
258 .mask = 0xff,
259 .def = 0xff,
260 },
261 }, {
262 .id = 0x12,
263 .name = "fdcdrd",
264 .swgroup = TEGRA_SWGROUP_NV,
265 .smmu = {
266 .reg = 0x228,
267 .bit = 18,
268 },
269 .la = {
270 .reg = 0x334,
271 .shift = 0,
272 .mask = 0xff,
273 .def = 0x0a,
274 },
275 }, {
276 .id = 0x13,
277 .name = "fdcdrd2",
278 .swgroup = TEGRA_SWGROUP_NV2,
279 .smmu = {
280 .reg = 0x228,
281 .bit = 19,
282 },
283 .la = {
284 .reg = 0x33c,
285 .shift = 0,
286 .mask = 0xff,
287 .def = 0x0a,
288 },
289 }, {
290 .id = 0x14,
291 .name = "g2dr",
292 .swgroup = TEGRA_SWGROUP_G2,
293 .smmu = {
294 .reg = 0x228,
295 .bit = 20,
296 },
297 .la = {
298 .reg = 0x30c,
299 .shift = 0,
300 .mask = 0xff,
301 .def = 0x0a,
302 },
303 }, {
304 .id = 0x15,
305 .name = "hdar",
306 .swgroup = TEGRA_SWGROUP_HDA,
307 .smmu = {
308 .reg = 0x228,
309 .bit = 21,
310 },
311 .la = {
312 .reg = 0x318,
313 .shift = 0,
314 .mask = 0xff,
315 .def = 0xff,
316 },
317 }, {
318 .id = 0x16,
319 .name = "host1xdmar",
320 .swgroup = TEGRA_SWGROUP_HC,
321 .smmu = {
322 .reg = 0x228,
323 .bit = 22,
324 },
325 .la = {
326 .reg = 0x310,
327 .shift = 0,
328 .mask = 0xff,
329 .def = 0x05,
330 },
331 }, {
332 .id = 0x17,
333 .name = "host1xr",
334 .swgroup = TEGRA_SWGROUP_HC,
335 .smmu = {
336 .reg = 0x228,
337 .bit = 23,
338 },
339 .la = {
340 .reg = 0x310,
341 .shift = 16,
342 .mask = 0xff,
343 .def = 0x50,
344 },
345 }, {
346 .id = 0x18,
347 .name = "idxsrd",
348 .swgroup = TEGRA_SWGROUP_NV,
349 .smmu = {
350 .reg = 0x228,
351 .bit = 24,
352 },
353 .la = {
354 .reg = 0x334,
355 .shift = 16,
356 .mask = 0xff,
357 .def = 0x13,
358 },
359 }, {
360 .id = 0x19,
361 .name = "idxsrd2",
362 .swgroup = TEGRA_SWGROUP_NV2,
363 .smmu = {
364 .reg = 0x228,
365 .bit = 25,
366 },
367 .la = {
368 .reg = 0x33c,
369 .shift = 16,
370 .mask = 0xff,
371 .def = 0x13,
372 },
373 }, {
374 .id = 0x1a,
375 .name = "mpe_ipred",
376 .swgroup = TEGRA_SWGROUP_MPE,
377 .smmu = {
378 .reg = 0x228,
379 .bit = 26,
380 },
381 .la = {
382 .reg = 0x328,
383 .shift = 16,
384 .mask = 0xff,
385 .def = 0x80,
386 },
387 }, {
388 .id = 0x1b,
389 .name = "mpeamemrd",
390 .swgroup = TEGRA_SWGROUP_MPE,
391 .smmu = {
392 .reg = 0x228,
393 .bit = 27,
394 },
395 .la = {
396 .reg = 0x32c,
397 .shift = 0,
398 .mask = 0xff,
399 .def = 0x42,
400 },
401 }, {
402 .id = 0x1c,
403 .name = "mpecsrd",
404 .swgroup = TEGRA_SWGROUP_MPE,
405 .smmu = {
406 .reg = 0x228,
407 .bit = 28,
408 },
409 .la = {
410 .reg = 0x32c,
411 .shift = 16,
412 .mask = 0xff,
413 .def = 0xff,
414 },
415 }, {
416 .id = 0x1d,
417 .name = "ppcsahbdmar",
418 .swgroup = TEGRA_SWGROUP_PPCS,
419 .smmu = {
420 .reg = 0x228,
421 .bit = 29,
422 },
423 .la = {
424 .reg = 0x344,
425 .shift = 0,
426 .mask = 0xff,
427 .def = 0x10,
428 },
429 }, {
430 .id = 0x1e,
431 .name = "ppcsahbslvr",
432 .swgroup = TEGRA_SWGROUP_PPCS,
433 .smmu = {
434 .reg = 0x228,
435 .bit = 30,
436 },
437 .la = {
438 .reg = 0x344,
439 .shift = 16,
440 .mask = 0xff,
441 .def = 0x12,
442 },
443 }, {
444 .id = 0x1f,
445 .name = "satar",
446 .swgroup = TEGRA_SWGROUP_SATA,
447 .smmu = {
448 .reg = 0x228,
449 .bit = 31,
450 },
451 .la = {
452 .reg = 0x350,
453 .shift = 0,
454 .mask = 0xff,
455 .def = 0x33,
456 },
457 }, {
458 .id = 0x20,
459 .name = "texsrd",
460 .swgroup = TEGRA_SWGROUP_NV,
461 .smmu = {
462 .reg = 0x22c,
463 .bit = 0,
464 },
465 .la = {
466 .reg = 0x338,
467 .shift = 0,
468 .mask = 0xff,
469 .def = 0x13,
470 },
471 }, {
472 .id = 0x21,
473 .name = "texsrd2",
474 .swgroup = TEGRA_SWGROUP_NV2,
475 .smmu = {
476 .reg = 0x22c,
477 .bit = 1,
478 },
479 .la = {
480 .reg = 0x340,
481 .shift = 0,
482 .mask = 0xff,
483 .def = 0x13,
484 },
485 }, {
486 .id = 0x22,
487 .name = "vdebsevr",
488 .swgroup = TEGRA_SWGROUP_VDE,
489 .smmu = {
490 .reg = 0x22c,
491 .bit = 2,
492 },
493 .la = {
494 .reg = 0x354,
495 .shift = 0,
496 .mask = 0xff,
497 .def = 0xff,
498 },
499 }, {
500 .id = 0x23,
501 .name = "vdember",
502 .swgroup = TEGRA_SWGROUP_VDE,
503 .smmu = {
504 .reg = 0x22c,
505 .bit = 3,
506 },
507 .la = {
508 .reg = 0x354,
509 .shift = 16,
510 .mask = 0xff,
511 .def = 0xd0,
512 },
513 }, {
514 .id = 0x24,
515 .name = "vdemcer",
516 .swgroup = TEGRA_SWGROUP_VDE,
517 .smmu = {
518 .reg = 0x22c,
519 .bit = 4,
520 },
521 .la = {
522 .reg = 0x358,
523 .shift = 0,
524 .mask = 0xff,
525 .def = 0x2a,
526 },
527 }, {
528 .id = 0x25,
529 .name = "vdetper",
530 .swgroup = TEGRA_SWGROUP_VDE,
531 .smmu = {
532 .reg = 0x22c,
533 .bit = 5,
534 },
535 .la = {
536 .reg = 0x358,
537 .shift = 16,
538 .mask = 0xff,
539 .def = 0x74,
540 },
541 }, {
542 .id = 0x26,
543 .name = "mpcorelpr",
544 .swgroup = TEGRA_SWGROUP_MPCORELP,
545 .la = {
546 .reg = 0x324,
547 .shift = 0,
548 .mask = 0xff,
549 .def = 0x04,
550 },
551 }, {
552 .id = 0x27,
553 .name = "mpcorer",
554 .swgroup = TEGRA_SWGROUP_MPCORE,
555 .la = {
556 .reg = 0x320,
557 .shift = 0,
558 .mask = 0xff,
559 .def = 0x04,
560 },
561 }, {
562 .id = 0x28,
563 .name = "eppu",
564 .swgroup = TEGRA_SWGROUP_EPP,
565 .smmu = {
566 .reg = 0x22c,
567 .bit = 8,
568 },
569 .la = {
570 .reg = 0x300,
571 .shift = 16,
572 .mask = 0xff,
573 .def = 0x6c,
574 },
575 }, {
576 .id = 0x29,
577 .name = "eppv",
578 .swgroup = TEGRA_SWGROUP_EPP,
579 .smmu = {
580 .reg = 0x22c,
581 .bit = 9,
582 },
583 .la = {
584 .reg = 0x304,
585 .shift = 0,
586 .mask = 0xff,
587 .def = 0x6c,
588 },
589 }, {
590 .id = 0x2a,
591 .name = "eppy",
592 .swgroup = TEGRA_SWGROUP_EPP,
593 .smmu = {
594 .reg = 0x22c,
595 .bit = 10,
596 },
597 .la = {
598 .reg = 0x304,
599 .shift = 16,
600 .mask = 0xff,
601 .def = 0x6c,
602 },
603 }, {
604 .id = 0x2b,
605 .name = "mpeunifbw",
606 .swgroup = TEGRA_SWGROUP_MPE,
607 .smmu = {
608 .reg = 0x22c,
609 .bit = 11,
610 },
611 .la = {
612 .reg = 0x330,
613 .shift = 0,
614 .mask = 0xff,
615 .def = 0x13,
616 },
617 }, {
618 .id = 0x2c,
619 .name = "viwsb",
620 .swgroup = TEGRA_SWGROUP_VI,
621 .smmu = {
622 .reg = 0x22c,
623 .bit = 12,
624 },
625 .la = {
626 .reg = 0x364,
627 .shift = 16,
628 .mask = 0xff,
629 .def = 0x12,
630 },
631 }, {
632 .id = 0x2d,
633 .name = "viwu",
634 .swgroup = TEGRA_SWGROUP_VI,
635 .smmu = {
636 .reg = 0x22c,
637 .bit = 13,
638 },
639 .la = {
640 .reg = 0x368,
641 .shift = 0,
642 .mask = 0xff,
643 .def = 0xb2,
644 },
645 }, {
646 .id = 0x2e,
647 .name = "viwv",
648 .swgroup = TEGRA_SWGROUP_VI,
649 .smmu = {
650 .reg = 0x22c,
651 .bit = 14,
652 },
653 .la = {
654 .reg = 0x368,
655 .shift = 16,
656 .mask = 0xff,
657 .def = 0xb2,
658 },
659 }, {
660 .id = 0x2f,
661 .name = "viwy",
662 .swgroup = TEGRA_SWGROUP_VI,
663 .smmu = {
664 .reg = 0x22c,
665 .bit = 15,
666 },
667 .la = {
668 .reg = 0x36c,
669 .shift = 0,
670 .mask = 0xff,
671 .def = 0x12,
672 },
673 }, {
674 .id = 0x30,
675 .name = "g2dw",
676 .swgroup = TEGRA_SWGROUP_G2,
677 .smmu = {
678 .reg = 0x22c,
679 .bit = 16,
680 },
681 .la = {
682 .reg = 0x30c,
683 .shift = 16,
684 .mask = 0xff,
685 .def = 0x9,
686 },
687 }, {
688 .id = 0x31,
689 .name = "afiw",
690 .swgroup = TEGRA_SWGROUP_AFI,
691 .smmu = {
692 .reg = 0x22c,
693 .bit = 17,
694 },
695 .la = {
696 .reg = 0x2e0,
697 .shift = 16,
698 .mask = 0xff,
699 .def = 0x0c,
700 },
701 }, {
702 .id = 0x32,
703 .name = "avpcarm7w",
704 .swgroup = TEGRA_SWGROUP_AVPC,
705 .smmu = {
706 .reg = 0x22c,
707 .bit = 18,
708 },
709 .la = {
710 .reg = 0x2e4,
711 .shift = 16,
712 .mask = 0xff,
713 .def = 0x0e,
714 },
715 }, {
716 .id = 0x33,
717 .name = "fdcdwr",
718 .swgroup = TEGRA_SWGROUP_NV,
719 .smmu = {
720 .reg = 0x22c,
721 .bit = 19,
722 },
723 .la = {
724 .reg = 0x338,
725 .shift = 16,
726 .mask = 0xff,
727 .def = 0x0a,
728 },
729 }, {
730 .id = 0x34,
731 .name = "fdcwr2",
732 .swgroup = TEGRA_SWGROUP_NV2,
733 .smmu = {
734 .reg = 0x22c,
735 .bit = 20,
736 },
737 .la = {
738 .reg = 0x340,
739 .shift = 16,
740 .mask = 0xff,
741 .def = 0x0a,
742 },
743 }, {
744 .id = 0x35,
745 .name = "hdaw",
746 .swgroup = TEGRA_SWGROUP_HDA,
747 .smmu = {
748 .reg = 0x22c,
749 .bit = 21,
750 },
751 .la = {
752 .reg = 0x318,
753 .shift = 16,
754 .mask = 0xff,
755 .def = 0xff,
756 },
757 }, {
758 .id = 0x36,
759 .name = "host1xw",
760 .swgroup = TEGRA_SWGROUP_HC,
761 .smmu = {
762 .reg = 0x22c,
763 .bit = 22,
764 },
765 .la = {
766 .reg = 0x314,
767 .shift = 0,
768 .mask = 0xff,
769 .def = 0x10,
770 },
771 }, {
772 .id = 0x37,
773 .name = "ispw",
774 .swgroup = TEGRA_SWGROUP_ISP,
775 .smmu = {
776 .reg = 0x22c,
777 .bit = 23,
778 },
779 .la = {
780 .reg = 0x31c,
781 .shift = 0,
782 .mask = 0xff,
783 .def = 0xff,
784 },
785 }, {
786 .id = 0x38,
787 .name = "mpcorelpw",
788 .swgroup = TEGRA_SWGROUP_MPCORELP,
789 .la = {
790 .reg = 0x324,
791 .shift = 16,
792 .mask = 0xff,
793 .def = 0x0e,
794 },
795 }, {
796 .id = 0x39,
797 .name = "mpcorew",
798 .swgroup = TEGRA_SWGROUP_MPCORE,
799 .la = {
800 .reg = 0x320,
801 .shift = 16,
802 .mask = 0xff,
803 .def = 0x0e,
804 },
805 }, {
806 .id = 0x3a,
807 .name = "mpecswr",
808 .swgroup = TEGRA_SWGROUP_MPE,
809 .smmu = {
810 .reg = 0x22c,
811 .bit = 26,
812 },
813 .la = {
814 .reg = 0x330,
815 .shift = 16,
816 .mask = 0xff,
817 .def = 0xff,
818 },
819 }, {
820 .id = 0x3b,
821 .name = "ppcsahbdmaw",
822 .swgroup = TEGRA_SWGROUP_PPCS,
823 .smmu = {
824 .reg = 0x22c,
825 .bit = 27,
826 },
827 .la = {
828 .reg = 0x348,
829 .shift = 0,
830 .mask = 0xff,
831 .def = 0x10,
832 },
833 }, {
834 .id = 0x3c,
835 .name = "ppcsahbslvw",
836 .swgroup = TEGRA_SWGROUP_PPCS,
837 .smmu = {
838 .reg = 0x22c,
839 .bit = 28,
840 },
841 .la = {
842 .reg = 0x348,
843 .shift = 16,
844 .mask = 0xff,
845 .def = 0x06,
846 },
847 }, {
848 .id = 0x3d,
849 .name = "sataw",
850 .swgroup = TEGRA_SWGROUP_SATA,
851 .smmu = {
852 .reg = 0x22c,
853 .bit = 29,
854 },
855 .la = {
856 .reg = 0x350,
857 .shift = 16,
858 .mask = 0xff,
859 .def = 0x33,
860 },
861 }, {
862 .id = 0x3e,
863 .name = "vdebsevw",
864 .swgroup = TEGRA_SWGROUP_VDE,
865 .smmu = {
866 .reg = 0x22c,
867 .bit = 30,
868 },
869 .la = {
870 .reg = 0x35c,
871 .shift = 0,
872 .mask = 0xff,
873 .def = 0xff,
874 },
875 }, {
876 .id = 0x3f,
877 .name = "vdedbgw",
878 .swgroup = TEGRA_SWGROUP_VDE,
879 .smmu = {
880 .reg = 0x22c,
881 .bit = 31,
882 },
883 .la = {
884 .reg = 0x35c,
885 .shift = 16,
886 .mask = 0xff,
887 .def = 0xff,
888 },
889 }, {
890 .id = 0x40,
891 .name = "vdembew",
892 .swgroup = TEGRA_SWGROUP_VDE,
893 .smmu = {
894 .reg = 0x230,
895 .bit = 0,
896 },
897 .la = {
898 .reg = 0x360,
899 .shift = 0,
900 .mask = 0xff,
901 .def = 0x42,
902 },
903 }, {
904 .id = 0x41,
905 .name = "vdetpmw",
906 .swgroup = TEGRA_SWGROUP_VDE,
907 .smmu = {
908 .reg = 0x230,
909 .bit = 1,
910 },
911 .la = {
912 .reg = 0x360,
913 .shift = 16,
914 .mask = 0xff,
915 .def = 0x2a,
916 },
917 },
918};
919
920static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
921 { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
922 { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
923 { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 },
924 { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c },
925 { .swgroup = TEGRA_SWGROUP_MPE, .reg = 0x264 },
926 { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
927 { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
928 { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
929 { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
930 { .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c },
931 { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
932 { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
933 { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
934 { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 },
935 { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
936 { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
937};
938
939static void tegra30_flush_dcache(struct page *page, unsigned long offset,
940 size_t size)
941{
942 phys_addr_t phys = page_to_phys(page) + offset;
943 void *virt = page_address(page) + offset;
944
945 __cpuc_flush_dcache_area(virt, size);
946 outer_flush_range(phys, phys + size);
947}
948
949static const struct tegra_smmu_ops tegra30_smmu_ops = {
950 .flush_dcache = tegra30_flush_dcache,
951};
952
953static const struct tegra_smmu_soc tegra30_smmu_soc = {
954 .clients = tegra30_mc_clients,
955 .num_clients = ARRAY_SIZE(tegra30_mc_clients),
956 .swgroups = tegra30_swgroups,
957 .num_swgroups = ARRAY_SIZE(tegra30_swgroups),
958 .supports_round_robin_arbitration = false,
959 .supports_request_limit = false,
960 .num_asids = 4,
961 .ops = &tegra30_smmu_ops,
962};
963
964const struct tegra_mc_soc tegra30_mc_soc = {
965 .clients = tegra30_mc_clients,
966 .num_clients = ARRAY_SIZE(tegra30_mc_clients),
967 .num_address_bits = 32,
968 .atom_size = 16,
969 .smmu = &tegra30_smmu_soc,
970};
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
deleted file mode 100644
index ef7934535fd1..000000000000
--- a/drivers/memory/tegra30-mc.c
+++ /dev/null
@@ -1,378 +0,0 @@
1/*
2 * Tegra30 Memory Controller
3 *
4 * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20#include <linux/err.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/ratelimit.h>
24#include <linux/platform_device.h>
25#include <linux/interrupt.h>
26#include <linux/io.h>
27
28#define DRV_NAME "tegra30-mc"
29
30#define MC_INTSTATUS 0x0
31#define MC_INTMASK 0x4
32
33#define MC_INT_ERR_SHIFT 6
34#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
35#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
36#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
37#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
38#define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4)
39
40#define MC_ERR_STATUS 0x8
41#define MC_ERR_ADR 0xc
42
43#define MC_ERR_TYPE_SHIFT 28
44#define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT)
45#define MC_ERR_TYPE_DECERR_EMEM 2
46#define MC_ERR_TYPE_SECURITY_TRUSTZONE 3
47#define MC_ERR_TYPE_SECURITY_CARVEOUT 4
48#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6
49
50#define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25
51#define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
52#define MC_ERR_RW_SHIFT 16
53#define MC_ERR_RW BIT(MC_ERR_RW_SHIFT)
54#define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1)
55
56#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
57
58#define MC_EMEM_ARB_CFG 0x90
59#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
60#define MC_EMEM_ARB_TIMING_RCD 0x98
61#define MC_EMEM_ARB_TIMING_RP 0x9c
62#define MC_EMEM_ARB_TIMING_RC 0xa0
63#define MC_EMEM_ARB_TIMING_RAS 0xa4
64#define MC_EMEM_ARB_TIMING_FAW 0xa8
65#define MC_EMEM_ARB_TIMING_RRD 0xac
66#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
67#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
68#define MC_EMEM_ARB_TIMING_R2R 0xb8
69#define MC_EMEM_ARB_TIMING_W2W 0xbc
70#define MC_EMEM_ARB_TIMING_R2W 0xc0
71#define MC_EMEM_ARB_TIMING_W2R 0xc4
72
73#define MC_EMEM_ARB_DA_TURNS 0xd0
74#define MC_EMEM_ARB_DA_COVERS 0xd4
75#define MC_EMEM_ARB_MISC0 0xd8
76#define MC_EMEM_ARB_MISC1 0xdc
77
78#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
79#define MC_EMEM_ARB_OVERRIDE 0xe8
80
81#define MC_TIMING_CONTROL 0xfc
82
83#define MC_CLIENT_ID_MASK 0x7f
84
85#define NUM_MC_REG_BANKS 4
86
87struct tegra30_mc {
88 void __iomem *regs[NUM_MC_REG_BANKS];
89 struct device *dev;
90 u32 ctx[0];
91};
92
93static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
94{
95 u32 val = 0;
96
97 if (offs < 0x10)
98 val = readl(mc->regs[0] + offs);
99 else if (offs < 0x1f0)
100 val = readl(mc->regs[1] + offs - 0x3c);
101 else if (offs < 0x228)
102 val = readl(mc->regs[2] + offs - 0x200);
103 else if (offs < 0x400)
104 val = readl(mc->regs[3] + offs - 0x284);
105
106 return val;
107}
108
109static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
110{
111 if (offs < 0x10)
112 writel(val, mc->regs[0] + offs);
113 else if (offs < 0x1f0)
114 writel(val, mc->regs[1] + offs - 0x3c);
115 else if (offs < 0x228)
116 writel(val, mc->regs[2] + offs - 0x200);
117 else if (offs < 0x400)
118 writel(val, mc->regs[3] + offs - 0x284);
119}
120
121static const char * const tegra30_mc_client[] = {
122 "csr_ptcr",
123 "cbr_display0a",
124 "cbr_display0ab",
125 "cbr_display0b",
126 "cbr_display0bb",
127 "cbr_display0c",
128 "cbr_display0cb",
129 "cbr_display1b",
130 "cbr_display1bb",
131 "cbr_eppup",
132 "cbr_g2pr",
133 "cbr_g2sr",
134 "cbr_mpeunifbr",
135 "cbr_viruv",
136 "csr_afir",
137 "csr_avpcarm7r",
138 "csr_displayhc",
139 "csr_displayhcb",
140 "csr_fdcdrd",
141 "csr_fdcdrd2",
142 "csr_g2dr",
143 "csr_hdar",
144 "csr_host1xdmar",
145 "csr_host1xr",
146 "csr_idxsrd",
147 "csr_idxsrd2",
148 "csr_mpe_ipred",
149 "csr_mpeamemrd",
150 "csr_mpecsrd",
151 "csr_ppcsahbdmar",
152 "csr_ppcsahbslvr",
153 "csr_satar",
154 "csr_texsrd",
155 "csr_texsrd2",
156 "csr_vdebsevr",
157 "csr_vdember",
158 "csr_vdemcer",
159 "csr_vdetper",
160 "csr_mpcorelpr",
161 "csr_mpcorer",
162 "cbw_eppu",
163 "cbw_eppv",
164 "cbw_eppy",
165 "cbw_mpeunifbw",
166 "cbw_viwsb",
167 "cbw_viwu",
168 "cbw_viwv",
169 "cbw_viwy",
170 "ccw_g2dw",
171 "csw_afiw",
172 "csw_avpcarm7w",
173 "csw_fdcdwr",
174 "csw_fdcdwr2",
175 "csw_hdaw",
176 "csw_host1xw",
177 "csw_ispw",
178 "csw_mpcorelpw",
179 "csw_mpcorew",
180 "csw_mpecswr",
181 "csw_ppcsahbdmaw",
182 "csw_ppcsahbslvw",
183 "csw_sataw",
184 "csw_vdebsevw",
185 "csw_vdedbgw",
186 "csw_vdembew",
187 "csw_vdetpmw",
188};
189
190static void tegra30_mc_decode(struct tegra30_mc *mc, int n)
191{
192 u32 err, addr;
193 const char * const mc_int_err[] = {
194 "MC_DECERR",
195 "Unknown",
196 "MC_SECURITY_ERR",
197 "MC_ARBITRATION_EMEM",
198 "MC_SMMU_ERR",
199 };
200 const char * const err_type[] = {
201 "Unknown",
202 "Unknown",
203 "DECERR_EMEM",
204 "SECURITY_TRUSTZONE",
205 "SECURITY_CARVEOUT",
206 "Unknown",
207 "INVALID_SMMU_PAGE",
208 "Unknown",
209 };
210 char attr[6];
211 int cid, perm, type, idx;
212 const char *client = "Unknown";
213
214 idx = n - MC_INT_ERR_SHIFT;
215 if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
216 dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
217 BIT(n));
218 return;
219 }
220
221 err = mc_readl(mc, MC_ERR_STATUS);
222
223 type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
224 perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
225 MC_ERR_INVALID_SMMU_PAGE_SHIFT;
226 if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
227 sprintf(attr, "%c-%c-%c",
228 (perm & BIT(2)) ? 'R' : '-',
229 (perm & BIT(1)) ? 'W' : '-',
230 (perm & BIT(0)) ? 'S' : '-');
231 else
232 attr[0] = '\0';
233
234 cid = err & MC_CLIENT_ID_MASK;
235 if (cid < ARRAY_SIZE(tegra30_mc_client))
236 client = tegra30_mc_client[cid];
237
238 addr = mc_readl(mc, MC_ERR_ADR);
239
240 dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
241 mc_int_err[idx], err, addr, client,
242 (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
243 (err & MC_ERR_RW) ? "write" : "read",
244 err_type[type], attr);
245}
246
247static const u32 tegra30_mc_ctx[] = {
248 MC_EMEM_ARB_CFG,
249 MC_EMEM_ARB_OUTSTANDING_REQ,
250 MC_EMEM_ARB_TIMING_RCD,
251 MC_EMEM_ARB_TIMING_RP,
252 MC_EMEM_ARB_TIMING_RC,
253 MC_EMEM_ARB_TIMING_RAS,
254 MC_EMEM_ARB_TIMING_FAW,
255 MC_EMEM_ARB_TIMING_RRD,
256 MC_EMEM_ARB_TIMING_RAP2PRE,
257 MC_EMEM_ARB_TIMING_WAP2PRE,
258 MC_EMEM_ARB_TIMING_R2R,
259 MC_EMEM_ARB_TIMING_W2W,
260 MC_EMEM_ARB_TIMING_R2W,
261 MC_EMEM_ARB_TIMING_W2R,
262 MC_EMEM_ARB_DA_TURNS,
263 MC_EMEM_ARB_DA_COVERS,
264 MC_EMEM_ARB_MISC0,
265 MC_EMEM_ARB_MISC1,
266 MC_EMEM_ARB_RING3_THROTTLE,
267 MC_EMEM_ARB_OVERRIDE,
268 MC_INTMASK,
269};
270
271#ifdef CONFIG_PM
272static int tegra30_mc_suspend(struct device *dev)
273{
274 int i;
275 struct tegra30_mc *mc = dev_get_drvdata(dev);
276
277 for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
278 mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
279 return 0;
280}
281
282static int tegra30_mc_resume(struct device *dev)
283{
284 int i;
285 struct tegra30_mc *mc = dev_get_drvdata(dev);
286
287 for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
288 mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
289
290 mc_writel(mc, 1, MC_TIMING_CONTROL);
291 /* Read-back to ensure that write reached */
292 mc_readl(mc, MC_TIMING_CONTROL);
293 return 0;
294}
295#endif
296
297static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
298 tegra30_mc_suspend,
299 tegra30_mc_resume, NULL);
300
301static const struct of_device_id tegra30_mc_of_match[] = {
302 { .compatible = "nvidia,tegra30-mc", },
303 {},
304};
305
306static irqreturn_t tegra30_mc_isr(int irq, void *data)
307{
308 u32 stat, mask, bit;
309 struct tegra30_mc *mc = data;
310
311 stat = mc_readl(mc, MC_INTSTATUS);
312 mask = mc_readl(mc, MC_INTMASK);
313 mask &= stat;
314 if (!mask)
315 return IRQ_NONE;
316 while ((bit = ffs(mask)) != 0) {
317 tegra30_mc_decode(mc, bit - 1);
318 mask &= ~BIT(bit - 1);
319 }
320
321 mc_writel(mc, stat, MC_INTSTATUS);
322 return IRQ_HANDLED;
323}
324
325static int tegra30_mc_probe(struct platform_device *pdev)
326{
327 struct resource *irq;
328 struct tegra30_mc *mc;
329 size_t bytes;
330 int err, i;
331 u32 intmask;
332
333 bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
334 mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
335 if (!mc)
336 return -ENOMEM;
337 mc->dev = &pdev->dev;
338
339 for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
340 struct resource *res;
341
342 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
343 mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
344 if (IS_ERR(mc->regs[i]))
345 return PTR_ERR(mc->regs[i]);
346 }
347
348 irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
349 if (!irq)
350 return -ENODEV;
351 err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
352 IRQF_SHARED, dev_name(&pdev->dev), mc);
353 if (err)
354 return -ENODEV;
355
356 platform_set_drvdata(pdev, mc);
357
358 intmask = MC_INT_INVALID_SMMU_PAGE |
359 MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
360 mc_writel(mc, intmask, MC_INTMASK);
361 return 0;
362}
363
364static struct platform_driver tegra30_mc_driver = {
365 .probe = tegra30_mc_probe,
366 .driver = {
367 .name = DRV_NAME,
368 .owner = THIS_MODULE,
369 .of_match_table = tegra30_mc_of_match,
370 .pm = &tegra30_mc_pm,
371 },
372};
373module_platform_driver(tegra30_mc_driver);
374
375MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
376MODULE_DESCRIPTION("Tegra30 MC driver");
377MODULE_LICENSE("GPL v2");
378MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
index fc12621fb432..534c03f8ad72 100644
--- a/include/dt-bindings/clock/tegra114-car.h
+++ b/include/dt-bindings/clock/tegra114-car.h
@@ -49,7 +49,7 @@
49#define TEGRA114_CLK_I2S0 30 49#define TEGRA114_CLK_I2S0 30
50/* 31 */ 50/* 31 */
51 51
52/* 32 */ 52#define TEGRA114_CLK_MC 32
53/* 33 */ 53/* 33 */
54#define TEGRA114_CLK_APBDMA 34 54#define TEGRA114_CLK_APBDMA 34
55/* 35 */ 55/* 35 */
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h
index 6bac637fd635..af9bc9a3ddbc 100644
--- a/include/dt-bindings/clock/tegra124-car.h
+++ b/include/dt-bindings/clock/tegra124-car.h
@@ -48,7 +48,7 @@
48#define TEGRA124_CLK_I2S0 30 48#define TEGRA124_CLK_I2S0 30
49/* 31 */ 49/* 31 */
50 50
51/* 32 */ 51#define TEGRA124_CLK_MC 32
52/* 33 */ 52/* 33 */
53#define TEGRA124_CLK_APBDMA 34 53#define TEGRA124_CLK_APBDMA 34
54/* 35 */ 54/* 35 */
diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
index 9406207cfac8..04500b243a4d 100644
--- a/include/dt-bindings/clock/tegra20-car.h
+++ b/include/dt-bindings/clock/tegra20-car.h
@@ -49,7 +49,7 @@
49/* 30 */ 49/* 30 */
50#define TEGRA20_CLK_CACHE2 31 50#define TEGRA20_CLK_CACHE2 31
51 51
52#define TEGRA20_CLK_MEM 32 52#define TEGRA20_CLK_MC 32
53#define TEGRA20_CLK_AHBDMA 33 53#define TEGRA20_CLK_AHBDMA 33
54#define TEGRA20_CLK_APBDMA 34 54#define TEGRA20_CLK_APBDMA 34
55/* 35 */ 55/* 35 */
diff --git a/include/dt-bindings/memory/tegra114-mc.h b/include/dt-bindings/memory/tegra114-mc.h
new file mode 100644
index 000000000000..8f48985a3139
--- /dev/null
+++ b/include/dt-bindings/memory/tegra114-mc.h
@@ -0,0 +1,25 @@
1#ifndef DT_BINDINGS_MEMORY_TEGRA114_MC_H
2#define DT_BINDINGS_MEMORY_TEGRA114_MC_H
3
4#define TEGRA_SWGROUP_PTC 0
5#define TEGRA_SWGROUP_DC 1
6#define TEGRA_SWGROUP_DCB 2
7#define TEGRA_SWGROUP_EPP 3
8#define TEGRA_SWGROUP_G2 4
9#define TEGRA_SWGROUP_AVPC 5
10#define TEGRA_SWGROUP_NV 6
11#define TEGRA_SWGROUP_HDA 7
12#define TEGRA_SWGROUP_HC 8
13#define TEGRA_SWGROUP_MSENC 9
14#define TEGRA_SWGROUP_PPCS 10
15#define TEGRA_SWGROUP_VDE 11
16#define TEGRA_SWGROUP_MPCORELP 12
17#define TEGRA_SWGROUP_MPCORE 13
18#define TEGRA_SWGROUP_VI 14
19#define TEGRA_SWGROUP_ISP 15
20#define TEGRA_SWGROUP_XUSB_HOST 16
21#define TEGRA_SWGROUP_XUSB_DEV 17
22#define TEGRA_SWGROUP_EMUCIF 18
23#define TEGRA_SWGROUP_TSEC 19
24
25#endif
diff --git a/include/dt-bindings/memory/tegra124-mc.h b/include/dt-bindings/memory/tegra124-mc.h
new file mode 100644
index 000000000000..7d8ee798f34e
--- /dev/null
+++ b/include/dt-bindings/memory/tegra124-mc.h
@@ -0,0 +1,31 @@
1#ifndef DT_BINDINGS_MEMORY_TEGRA124_MC_H
2#define DT_BINDINGS_MEMORY_TEGRA124_MC_H
3
4#define TEGRA_SWGROUP_PTC 0
5#define TEGRA_SWGROUP_DC 1
6#define TEGRA_SWGROUP_DCB 2
7#define TEGRA_SWGROUP_AFI 3
8#define TEGRA_SWGROUP_AVPC 4
9#define TEGRA_SWGROUP_HDA 5
10#define TEGRA_SWGROUP_HC 6
11#define TEGRA_SWGROUP_MSENC 7
12#define TEGRA_SWGROUP_PPCS 8
13#define TEGRA_SWGROUP_SATA 9
14#define TEGRA_SWGROUP_VDE 10
15#define TEGRA_SWGROUP_MPCORELP 11
16#define TEGRA_SWGROUP_MPCORE 12
17#define TEGRA_SWGROUP_ISP2 13
18#define TEGRA_SWGROUP_XUSB_HOST 14
19#define TEGRA_SWGROUP_XUSB_DEV 15
20#define TEGRA_SWGROUP_ISP2B 16
21#define TEGRA_SWGROUP_TSEC 17
22#define TEGRA_SWGROUP_A9AVP 18
23#define TEGRA_SWGROUP_GPU 19
24#define TEGRA_SWGROUP_SDMMC1A 20
25#define TEGRA_SWGROUP_SDMMC2A 21
26#define TEGRA_SWGROUP_SDMMC3A 22
27#define TEGRA_SWGROUP_SDMMC4A 23
28#define TEGRA_SWGROUP_VIC 24
29#define TEGRA_SWGROUP_VI 25
30
31#endif
diff --git a/include/dt-bindings/memory/tegra30-mc.h b/include/dt-bindings/memory/tegra30-mc.h
new file mode 100644
index 000000000000..502beb03d777
--- /dev/null
+++ b/include/dt-bindings/memory/tegra30-mc.h
@@ -0,0 +1,24 @@
1#ifndef DT_BINDINGS_MEMORY_TEGRA30_MC_H
2#define DT_BINDINGS_MEMORY_TEGRA30_MC_H
3
4#define TEGRA_SWGROUP_PTC 0
5#define TEGRA_SWGROUP_DC 1
6#define TEGRA_SWGROUP_DCB 2
7#define TEGRA_SWGROUP_EPP 3
8#define TEGRA_SWGROUP_G2 4
9#define TEGRA_SWGROUP_MPE 5
10#define TEGRA_SWGROUP_VI 6
11#define TEGRA_SWGROUP_AFI 7
12#define TEGRA_SWGROUP_AVPC 8
13#define TEGRA_SWGROUP_NV 9
14#define TEGRA_SWGROUP_NV2 10
15#define TEGRA_SWGROUP_HDA 11
16#define TEGRA_SWGROUP_HC 12
17#define TEGRA_SWGROUP_PPCS 13
18#define TEGRA_SWGROUP_SATA 14
19#define TEGRA_SWGROUP_VDE 15
20#define TEGRA_SWGROUP_MPCORELP 16
21#define TEGRA_SWGROUP_MPCORE 17
22#define TEGRA_SWGROUP_ISP 18
23
24#endif
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e6a7c9ff72f2..b29a5982e1c3 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -22,6 +22,7 @@
22#include <linux/errno.h> 22#include <linux/errno.h>
23#include <linux/err.h> 23#include <linux/err.h>
24#include <linux/types.h> 24#include <linux/types.h>
25#include <linux/scatterlist.h>
25#include <trace/events/iommu.h> 26#include <trace/events/iommu.h>
26 27
27#define IOMMU_READ (1 << 0) 28#define IOMMU_READ (1 << 0)
@@ -97,6 +98,8 @@ enum iommu_attr {
97 * @detach_dev: detach device from an iommu domain 98 * @detach_dev: detach device from an iommu domain
98 * @map: map a physically contiguous memory region to an iommu domain 99 * @map: map a physically contiguous memory region to an iommu domain
99 * @unmap: unmap a physically contiguous memory region from an iommu domain 100 * @unmap: unmap a physically contiguous memory region from an iommu domain
101 * @map_sg: map a scatter-gather list of physically contiguous memory chunks
102 * to an iommu domain
100 * @iova_to_phys: translate iova to physical address 103 * @iova_to_phys: translate iova to physical address
101 * @add_device: add device to iommu grouping 104 * @add_device: add device to iommu grouping
102 * @remove_device: remove device from iommu grouping 105 * @remove_device: remove device from iommu grouping
@@ -114,6 +117,8 @@ struct iommu_ops {
114 phys_addr_t paddr, size_t size, int prot); 117 phys_addr_t paddr, size_t size, int prot);
115 size_t (*unmap)(struct iommu_domain *domain, unsigned long iova, 118 size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
116 size_t size); 119 size_t size);
120 size_t (*map_sg)(struct iommu_domain *domain, unsigned long iova,
121 struct scatterlist *sg, unsigned int nents, int prot);
117 phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova); 122 phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
118 int (*add_device)(struct device *dev); 123 int (*add_device)(struct device *dev);
119 void (*remove_device)(struct device *dev); 124 void (*remove_device)(struct device *dev);
@@ -156,6 +161,9 @@ extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
156 phys_addr_t paddr, size_t size, int prot); 161 phys_addr_t paddr, size_t size, int prot);
157extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, 162extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
158 size_t size); 163 size_t size);
164extern size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
165 struct scatterlist *sg,unsigned int nents,
166 int prot);
159extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova); 167extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova);
160extern void iommu_set_fault_handler(struct iommu_domain *domain, 168extern void iommu_set_fault_handler(struct iommu_domain *domain,
161 iommu_fault_handler_t handler, void *token); 169 iommu_fault_handler_t handler, void *token);
@@ -241,6 +249,13 @@ static inline int report_iommu_fault(struct iommu_domain *domain,
241 return ret; 249 return ret;
242} 250}
243 251
252static inline size_t iommu_map_sg(struct iommu_domain *domain,
253 unsigned long iova, struct scatterlist *sg,
254 unsigned int nents, int prot)
255{
256 return domain->ops->map_sg(domain, iova, sg, nents, prot);
257}
258
244#else /* CONFIG_IOMMU_API */ 259#else /* CONFIG_IOMMU_API */
245 260
246struct iommu_ops {}; 261struct iommu_ops {};
@@ -293,6 +308,13 @@ static inline int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
293 return -ENODEV; 308 return -ENODEV;
294} 309}
295 310
311static inline size_t iommu_map_sg(struct iommu_domain *domain,
312 unsigned long iova, struct scatterlist *sg,
313 unsigned int nents, int prot)
314{
315 return -ENODEV;
316}
317
296static inline int iommu_domain_window_enable(struct iommu_domain *domain, 318static inline int iommu_domain_window_enable(struct iommu_domain *domain,
297 u32 wnd_nr, phys_addr_t paddr, 319 u32 wnd_nr, phys_addr_t paddr,
298 u64 size, int prot) 320 u64 size, int prot)
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
new file mode 100644
index 000000000000..63deb8d9f82a
--- /dev/null
+++ b/include/soc/tegra/mc.h
@@ -0,0 +1,107 @@
1/*
2 * Copyright (C) 2014 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 __SOC_TEGRA_MC_H__
10#define __SOC_TEGRA_MC_H__
11
12#include <linux/types.h>
13
14struct clk;
15struct device;
16struct page;
17
18struct tegra_smmu_enable {
19 unsigned int reg;
20 unsigned int bit;
21};
22
23/* latency allowance */
24struct tegra_mc_la {
25 unsigned int reg;
26 unsigned int shift;
27 unsigned int mask;
28 unsigned int def;
29};
30
31struct tegra_mc_client {
32 unsigned int id;
33 const char *name;
34 unsigned int swgroup;
35
36 unsigned int fifo_size;
37
38 struct tegra_smmu_enable smmu;
39 struct tegra_mc_la la;
40};
41
42struct tegra_smmu_swgroup {
43 unsigned int swgroup;
44 unsigned int reg;
45};
46
47struct tegra_smmu_ops {
48 void (*flush_dcache)(struct page *page, unsigned long offset,
49 size_t size);
50};
51
52struct tegra_smmu_soc {
53 const struct tegra_mc_client *clients;
54 unsigned int num_clients;
55
56 const struct tegra_smmu_swgroup *swgroups;
57 unsigned int num_swgroups;
58
59 bool supports_round_robin_arbitration;
60 bool supports_request_limit;
61
62 unsigned int num_asids;
63
64 const struct tegra_smmu_ops *ops;
65};
66
67struct tegra_mc;
68struct tegra_smmu;
69
70#ifdef CONFIG_TEGRA_IOMMU_SMMU
71struct tegra_smmu *tegra_smmu_probe(struct device *dev,
72 const struct tegra_smmu_soc *soc,
73 struct tegra_mc *mc);
74#else
75static inline struct tegra_smmu *
76tegra_smmu_probe(struct device *dev, const struct tegra_smmu_soc *soc,
77 struct tegra_mc *mc)
78{
79 return NULL;
80}
81#endif
82
83struct tegra_mc_soc {
84 const struct tegra_mc_client *clients;
85 unsigned int num_clients;
86
87 const unsigned int *emem_regs;
88 unsigned int num_emem_regs;
89
90 unsigned int num_address_bits;
91 unsigned int atom_size;
92
93 const struct tegra_smmu_soc *smmu;
94};
95
96struct tegra_mc {
97 struct device *dev;
98 struct tegra_smmu *smmu;
99 void __iomem *regs;
100 struct clk *clk;
101 int irq;
102
103 const struct tegra_mc_soc *soc;
104 unsigned long tick;
105};
106
107#endif /* __SOC_TEGRA_MC_H__ */