xref: /openbmc/linux/drivers/iommu/apple-dart.c (revision 8f1b4600373f9da2afc124f31788b16f47eb950c)
146d1fb07SSven Peter // SPDX-License-Identifier: GPL-2.0-only
246d1fb07SSven Peter /*
346d1fb07SSven Peter  * Apple DART (Device Address Resolution Table) IOMMU driver
446d1fb07SSven Peter  *
546d1fb07SSven Peter  * Copyright (C) 2021 The Asahi Linux Contributors
646d1fb07SSven Peter  *
746d1fb07SSven Peter  * Based on arm/arm-smmu/arm-ssmu.c and arm/arm-smmu-v3/arm-smmu-v3.c
846d1fb07SSven Peter  *  Copyright (C) 2013 ARM Limited
946d1fb07SSven Peter  *  Copyright (C) 2015 ARM Limited
1046d1fb07SSven Peter  * and on exynos-iommu.c
1146d1fb07SSven Peter  *  Copyright (c) 2011,2016 Samsung Electronics Co., Ltd.
1246d1fb07SSven Peter  */
1346d1fb07SSven Peter 
1446d1fb07SSven Peter #include <linux/atomic.h>
1546d1fb07SSven Peter #include <linux/bitfield.h>
1646d1fb07SSven Peter #include <linux/clk.h>
1746d1fb07SSven Peter #include <linux/dev_printk.h>
1846d1fb07SSven Peter #include <linux/dma-mapping.h>
1946d1fb07SSven Peter #include <linux/err.h>
2046d1fb07SSven Peter #include <linux/interrupt.h>
2146d1fb07SSven Peter #include <linux/io-pgtable.h>
2246d1fb07SSven Peter #include <linux/iommu.h>
2346d1fb07SSven Peter #include <linux/iopoll.h>
2446d1fb07SSven Peter #include <linux/module.h>
2546d1fb07SSven Peter #include <linux/of.h>
2646d1fb07SSven Peter #include <linux/of_address.h>
2746d1fb07SSven Peter #include <linux/of_iommu.h>
2846d1fb07SSven Peter #include <linux/of_platform.h>
2946d1fb07SSven Peter #include <linux/pci.h>
3046d1fb07SSven Peter #include <linux/platform_device.h>
3146d1fb07SSven Peter #include <linux/slab.h>
3246d1fb07SSven Peter #include <linux/swab.h>
3346d1fb07SSven Peter #include <linux/types.h>
3446d1fb07SSven Peter 
35f2042ed2SRobin Murphy #include "dma-iommu.h"
36f2042ed2SRobin Murphy 
37510d4072SHector Martin #define DART_MAX_STREAMS 256
3846d1fb07SSven Peter #define DART_MAX_TTBR 4
3946d1fb07SSven Peter #define MAX_DARTS_PER_DEVICE 2
4046d1fb07SSven Peter 
41b76c68fcSHector Martin /* Common registers */
4246d1fb07SSven Peter 
4346d1fb07SSven Peter #define DART_PARAMS1 0x00
44a772a02cSHector Martin #define DART_PARAMS1_PAGE_SHIFT GENMASK(27, 24)
4546d1fb07SSven Peter 
4646d1fb07SSven Peter #define DART_PARAMS2 0x04
47a772a02cSHector Martin #define DART_PARAMS2_BYPASS_SUPPORT BIT(0)
4846d1fb07SSven Peter 
49b76c68fcSHector Martin /* T8020/T6000 registers */
5046d1fb07SSven Peter 
51b76c68fcSHector Martin #define DART_T8020_STREAM_COMMAND 0x20
52b76c68fcSHector Martin #define DART_T8020_STREAM_COMMAND_BUSY BIT(2)
53b76c68fcSHector Martin #define DART_T8020_STREAM_COMMAND_INVALIDATE BIT(20)
5446d1fb07SSven Peter 
55b76c68fcSHector Martin #define DART_T8020_STREAM_SELECT 0x34
5646d1fb07SSven Peter 
57b76c68fcSHector Martin #define DART_T8020_ERROR 0x40
58b76c68fcSHector Martin #define DART_T8020_ERROR_STREAM GENMASK(27, 24)
59b76c68fcSHector Martin #define DART_T8020_ERROR_CODE GENMASK(11, 0)
60b76c68fcSHector Martin #define DART_T8020_ERROR_FLAG BIT(31)
6146d1fb07SSven Peter 
62b76c68fcSHector Martin #define DART_T8020_ERROR_READ_FAULT BIT(4)
63b76c68fcSHector Martin #define DART_T8020_ERROR_WRITE_FAULT BIT(3)
64b76c68fcSHector Martin #define DART_T8020_ERROR_NO_PTE BIT(2)
65b76c68fcSHector Martin #define DART_T8020_ERROR_NO_PMD BIT(1)
66b76c68fcSHector Martin #define DART_T8020_ERROR_NO_TTBR BIT(0)
67b76c68fcSHector Martin 
68b76c68fcSHector Martin #define DART_T8020_CONFIG 0x60
69b76c68fcSHector Martin #define DART_T8020_CONFIG_LOCK BIT(15)
7046d1fb07SSven Peter 
7146d1fb07SSven Peter #define DART_STREAM_COMMAND_BUSY_TIMEOUT 100
7246d1fb07SSven Peter 
73b76c68fcSHector Martin #define DART_T8020_ERROR_ADDR_HI 0x54
74b76c68fcSHector Martin #define DART_T8020_ERROR_ADDR_LO 0x50
7546d1fb07SSven Peter 
76b76c68fcSHector Martin #define DART_T8020_STREAMS_ENABLE 0xfc
775a009fc1SSven Peter 
78b76c68fcSHector Martin #define DART_T8020_TCR                  0x100
79b76c68fcSHector Martin #define DART_T8020_TCR_TRANSLATE_ENABLE BIT(7)
80b76c68fcSHector Martin #define DART_T8020_TCR_BYPASS_DART      BIT(8)
81b76c68fcSHector Martin #define DART_T8020_TCR_BYPASS_DAPF      BIT(12)
8246d1fb07SSven Peter 
83b76c68fcSHector Martin #define DART_T8020_TTBR       0x200
84b76c68fcSHector Martin #define DART_T8020_TTBR_VALID BIT(31)
85b76c68fcSHector Martin #define DART_T8020_TTBR_ADDR_FIELD_SHIFT 0
86b76c68fcSHector Martin #define DART_T8020_TTBR_SHIFT 12
8746d1fb07SSven Peter 
88d8bcc870SHector Martin /* T8110 registers */
89d8bcc870SHector Martin 
90d8bcc870SHector Martin #define DART_T8110_PARAMS3 0x08
91d8bcc870SHector Martin #define DART_T8110_PARAMS3_PA_WIDTH GENMASK(29, 24)
92d8bcc870SHector Martin #define DART_T8110_PARAMS3_VA_WIDTH GENMASK(21, 16)
93d8bcc870SHector Martin #define DART_T8110_PARAMS3_VER_MAJ GENMASK(15, 8)
94d8bcc870SHector Martin #define DART_T8110_PARAMS3_VER_MIN GENMASK(7, 0)
95d8bcc870SHector Martin 
96d8bcc870SHector Martin #define DART_T8110_PARAMS4 0x0c
97d8bcc870SHector Martin #define DART_T8110_PARAMS4_NUM_CLIENTS GENMASK(24, 16)
98d8bcc870SHector Martin #define DART_T8110_PARAMS4_NUM_SIDS GENMASK(8, 0)
99d8bcc870SHector Martin 
100d8bcc870SHector Martin #define DART_T8110_TLB_CMD              0x80
101d8bcc870SHector Martin #define DART_T8110_TLB_CMD_BUSY         BIT(31)
102d8bcc870SHector Martin #define DART_T8110_TLB_CMD_OP           GENMASK(10, 8)
103d8bcc870SHector Martin #define DART_T8110_TLB_CMD_OP_FLUSH_ALL 0
104d8bcc870SHector Martin #define DART_T8110_TLB_CMD_OP_FLUSH_SID 1
105d8bcc870SHector Martin #define DART_T8110_TLB_CMD_STREAM       GENMASK(7, 0)
106d8bcc870SHector Martin 
107d8bcc870SHector Martin #define DART_T8110_ERROR 0x100
108d8bcc870SHector Martin #define DART_T8110_ERROR_STREAM GENMASK(27, 20)
109d8bcc870SHector Martin #define DART_T8110_ERROR_CODE GENMASK(14, 0)
110d8bcc870SHector Martin #define DART_T8110_ERROR_FLAG BIT(31)
111d8bcc870SHector Martin 
112d8bcc870SHector Martin #define DART_T8110_ERROR_MASK 0x104
113d8bcc870SHector Martin 
1149e6a1825SEric Curtin #define DART_T8110_ERROR_READ_FAULT BIT(5)
1159e6a1825SEric Curtin #define DART_T8110_ERROR_WRITE_FAULT BIT(4)
116d8bcc870SHector Martin #define DART_T8110_ERROR_NO_PTE BIT(3)
117d8bcc870SHector Martin #define DART_T8110_ERROR_NO_PMD BIT(2)
118d8bcc870SHector Martin #define DART_T8110_ERROR_NO_PGD BIT(1)
119d8bcc870SHector Martin #define DART_T8110_ERROR_NO_TTBR BIT(0)
120d8bcc870SHector Martin 
121d8bcc870SHector Martin #define DART_T8110_ERROR_ADDR_LO 0x170
122d8bcc870SHector Martin #define DART_T8110_ERROR_ADDR_HI 0x174
123d8bcc870SHector Martin 
124d8bcc870SHector Martin #define DART_T8110_PROTECT 0x200
125d8bcc870SHector Martin #define DART_T8110_UNPROTECT 0x204
126d8bcc870SHector Martin #define DART_T8110_PROTECT_LOCK 0x208
127d8bcc870SHector Martin #define DART_T8110_PROTECT_TTBR_TCR BIT(0)
128d8bcc870SHector Martin 
129d8bcc870SHector Martin #define DART_T8110_ENABLE_STREAMS  0xc00
130d8bcc870SHector Martin #define DART_T8110_DISABLE_STREAMS 0xc20
131d8bcc870SHector Martin 
132d8bcc870SHector Martin #define DART_T8110_TCR                  0x1000
133d8bcc870SHector Martin #define DART_T8110_TCR_REMAP            GENMASK(11, 8)
134d8bcc870SHector Martin #define DART_T8110_TCR_REMAP_EN         BIT(7)
135d8bcc870SHector Martin #define DART_T8110_TCR_BYPASS_DAPF      BIT(2)
136d8bcc870SHector Martin #define DART_T8110_TCR_BYPASS_DART      BIT(1)
137d8bcc870SHector Martin #define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
138d8bcc870SHector Martin 
139d8bcc870SHector Martin #define DART_T8110_TTBR       0x1400
140d8bcc870SHector Martin #define DART_T8110_TTBR_VALID BIT(0)
141d8bcc870SHector Martin #define DART_T8110_TTBR_ADDR_FIELD_SHIFT 2
142d8bcc870SHector Martin #define DART_T8110_TTBR_SHIFT 14
143d8bcc870SHector Martin 
144b76c68fcSHector Martin #define DART_TCR(dart, sid) ((dart)->hw->tcr + ((sid) << 2))
145b76c68fcSHector Martin 
146b76c68fcSHector Martin #define DART_TTBR(dart, sid, idx) ((dart)->hw->ttbr + \
1470b459bcdSHector Martin 				   (((dart)->hw->ttbr_count * (sid)) << 2) + \
1480b459bcdSHector Martin 				   ((idx) << 2))
1490b459bcdSHector Martin 
150b76c68fcSHector Martin struct apple_dart_stream_map;
1510b459bcdSHector Martin 
152d8bcc870SHector Martin enum dart_type {
153d8bcc870SHector Martin 	DART_T8020,
154d8bcc870SHector Martin 	DART_T6000,
155d8bcc870SHector Martin 	DART_T8110,
156d8bcc870SHector Martin };
15746d1fb07SSven Peter 
158a380b8dcSSven Peter struct apple_dart_hw {
159d8bcc870SHector Martin 	enum dart_type type;
160b76c68fcSHector Martin 	irqreturn_t (*irq_handler)(int irq, void *dev);
161b76c68fcSHector Martin 	int (*invalidate_tlb)(struct apple_dart_stream_map *stream_map);
162b76c68fcSHector Martin 
163a380b8dcSSven Peter 	u32 oas;
164a380b8dcSSven Peter 	enum io_pgtable_fmt fmt;
165510d4072SHector Martin 
166510d4072SHector Martin 	int max_sid_count;
1670b459bcdSHector Martin 
168b76c68fcSHector Martin 	u64 lock;
169b76c68fcSHector Martin 	u64 lock_bit;
170b76c68fcSHector Martin 
171b76c68fcSHector Martin 	u64 error;
172b76c68fcSHector Martin 
173b76c68fcSHector Martin 	u64 enable_streams;
174b76c68fcSHector Martin 
175b76c68fcSHector Martin 	u64 tcr;
176b76c68fcSHector Martin 	u64 tcr_enabled;
177b76c68fcSHector Martin 	u64 tcr_disabled;
178b76c68fcSHector Martin 	u64 tcr_bypass;
179b76c68fcSHector Martin 
180b76c68fcSHector Martin 	u64 ttbr;
181b76c68fcSHector Martin 	u64 ttbr_valid;
182b76c68fcSHector Martin 	u64 ttbr_addr_field_shift;
183b76c68fcSHector Martin 	u64 ttbr_shift;
1840b459bcdSHector Martin 	int ttbr_count;
185a380b8dcSSven Peter };
186a380b8dcSSven Peter 
18746d1fb07SSven Peter /*
18846d1fb07SSven Peter  * Private structure associated with each DART device.
18946d1fb07SSven Peter  *
19046d1fb07SSven Peter  * @dev: device struct
191a380b8dcSSven Peter  * @hw: SoC-specific hardware data
19246d1fb07SSven Peter  * @regs: mapped MMIO region
19346d1fb07SSven Peter  * @irq: interrupt number, can be shared with other DARTs
19446d1fb07SSven Peter  * @clks: clocks associated with this DART
19546d1fb07SSven Peter  * @num_clks: number of @clks
19646d1fb07SSven Peter  * @lock: lock for hardware operations involving this dart
19746d1fb07SSven Peter  * @pgsize: pagesize supported by this DART
19846d1fb07SSven Peter  * @supports_bypass: indicates if this DART supports bypass mode
19946d1fb07SSven Peter  * @force_bypass: force bypass mode due to pagesize mismatch?
20046d1fb07SSven Peter  * @sid2group: maps stream ids to iommu_groups
20146d1fb07SSven Peter  * @iommu: iommu core device
20246d1fb07SSven Peter  */
20346d1fb07SSven Peter struct apple_dart {
20446d1fb07SSven Peter 	struct device *dev;
205a380b8dcSSven Peter 	const struct apple_dart_hw *hw;
20646d1fb07SSven Peter 
20746d1fb07SSven Peter 	void __iomem *regs;
20846d1fb07SSven Peter 
20946d1fb07SSven Peter 	int irq;
21046d1fb07SSven Peter 	struct clk_bulk_data *clks;
21146d1fb07SSven Peter 	int num_clks;
21246d1fb07SSven Peter 
21346d1fb07SSven Peter 	spinlock_t lock;
21446d1fb07SSven Peter 
215d8bcc870SHector Martin 	u32 ias;
216d8bcc870SHector Martin 	u32 oas;
21746d1fb07SSven Peter 	u32 pgsize;
218510d4072SHector Martin 	u32 num_streams;
21946d1fb07SSven Peter 	u32 supports_bypass : 1;
22046d1fb07SSven Peter 	u32 force_bypass : 1;
22146d1fb07SSven Peter 
22246d1fb07SSven Peter 	struct iommu_group *sid2group[DART_MAX_STREAMS];
22346d1fb07SSven Peter 	struct iommu_device iommu;
2243d68bbb8SHector Martin 
2253d68bbb8SHector Martin 	u32 save_tcr[DART_MAX_STREAMS];
2263d68bbb8SHector Martin 	u32 save_ttbr[DART_MAX_STREAMS][DART_MAX_TTBR];
22746d1fb07SSven Peter };
22846d1fb07SSven Peter 
22946d1fb07SSven Peter /*
23046d1fb07SSven Peter  * Convenience struct to identify streams.
23146d1fb07SSven Peter  *
23246d1fb07SSven Peter  * The normal variant is used inside apple_dart_master_cfg which isn't written
23346d1fb07SSven Peter  * to concurrently.
23446d1fb07SSven Peter  * The atomic variant is used inside apple_dart_domain where we have to guard
23546d1fb07SSven Peter  * against races from potential parallel calls to attach/detach_device.
23646d1fb07SSven Peter  * Note that even inside the atomic variant the apple_dart pointer is not
23746d1fb07SSven Peter  * protected: This pointer is initialized once under the domain init mutex
23846d1fb07SSven Peter  * and never changed again afterwards. Devices with different dart pointers
23946d1fb07SSven Peter  * cannot be attached to the same domain.
24046d1fb07SSven Peter  *
24146d1fb07SSven Peter  * @dart dart pointer
24246d1fb07SSven Peter  * @sid stream id bitmap
24346d1fb07SSven Peter  */
24446d1fb07SSven Peter struct apple_dart_stream_map {
24546d1fb07SSven Peter 	struct apple_dart *dart;
246510d4072SHector Martin 	DECLARE_BITMAP(sidmap, DART_MAX_STREAMS);
24746d1fb07SSven Peter };
24846d1fb07SSven Peter struct apple_dart_atomic_stream_map {
24946d1fb07SSven Peter 	struct apple_dart *dart;
250510d4072SHector Martin 	atomic_long_t sidmap[BITS_TO_LONGS(DART_MAX_STREAMS)];
25146d1fb07SSven Peter };
25246d1fb07SSven Peter 
25346d1fb07SSven Peter /*
25446d1fb07SSven Peter  * This structure is attached to each iommu domain handled by a DART.
25546d1fb07SSven Peter  *
25646d1fb07SSven Peter  * @pgtbl_ops: pagetable ops allocated by io-pgtable
25746d1fb07SSven Peter  * @finalized: true if the domain has been completely initialized
25846d1fb07SSven Peter  * @init_lock: protects domain initialization
25946d1fb07SSven Peter  * @stream_maps: streams attached to this domain (valid for DMA/UNMANAGED only)
26046d1fb07SSven Peter  * @domain: core iommu domain pointer
26146d1fb07SSven Peter  */
26246d1fb07SSven Peter struct apple_dart_domain {
26346d1fb07SSven Peter 	struct io_pgtable_ops *pgtbl_ops;
26446d1fb07SSven Peter 
26546d1fb07SSven Peter 	bool finalized;
26646d1fb07SSven Peter 	struct mutex init_lock;
26746d1fb07SSven Peter 	struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
26846d1fb07SSven Peter 
26946d1fb07SSven Peter 	struct iommu_domain domain;
27046d1fb07SSven Peter };
27146d1fb07SSven Peter 
27246d1fb07SSven Peter /*
27346d1fb07SSven Peter  * This structure is attached to devices with dev_iommu_priv_set() on of_xlate
27446d1fb07SSven Peter  * and contains a list of streams bound to this device.
27546d1fb07SSven Peter  * So far the worst case seen is a single device with two streams
27646d1fb07SSven Peter  * from different darts, such that this simple static array is enough.
27746d1fb07SSven Peter  *
27846d1fb07SSven Peter  * @streams: streams for this device
27946d1fb07SSven Peter  */
28046d1fb07SSven Peter struct apple_dart_master_cfg {
28146d1fb07SSven Peter 	struct apple_dart_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
28246d1fb07SSven Peter };
28346d1fb07SSven Peter 
28446d1fb07SSven Peter /*
28546d1fb07SSven Peter  * Helper macro to iterate over apple_dart_master_cfg.stream_maps and
28646d1fb07SSven Peter  * apple_dart_domain.stream_maps
28746d1fb07SSven Peter  *
28846d1fb07SSven Peter  * @i int used as loop variable
28946d1fb07SSven Peter  * @base pointer to base struct (apple_dart_master_cfg or apple_dart_domain)
29046d1fb07SSven Peter  * @stream pointer to the apple_dart_streams struct for each loop iteration
29146d1fb07SSven Peter  */
29246d1fb07SSven Peter #define for_each_stream_map(i, base, stream_map)                               \
29346d1fb07SSven Peter 	for (i = 0, stream_map = &(base)->stream_maps[0];                      \
29446d1fb07SSven Peter 	     i < MAX_DARTS_PER_DEVICE && stream_map->dart;                     \
29546d1fb07SSven Peter 	     stream_map = &(base)->stream_maps[++i])
29646d1fb07SSven Peter 
29746d1fb07SSven Peter static struct platform_driver apple_dart_driver;
29846d1fb07SSven Peter static const struct iommu_ops apple_dart_iommu_ops;
29946d1fb07SSven Peter 
to_dart_domain(struct iommu_domain * dom)30046d1fb07SSven Peter static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
30146d1fb07SSven Peter {
30246d1fb07SSven Peter 	return container_of(dom, struct apple_dart_domain, domain);
30346d1fb07SSven Peter }
30446d1fb07SSven Peter 
30546d1fb07SSven Peter static void
apple_dart_hw_enable_translation(struct apple_dart_stream_map * stream_map)30646d1fb07SSven Peter apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
30746d1fb07SSven Peter {
308510d4072SHector Martin 	struct apple_dart *dart = stream_map->dart;
30946d1fb07SSven Peter 	int sid;
31046d1fb07SSven Peter 
311510d4072SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
312b76c68fcSHector Martin 		writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
31346d1fb07SSven Peter }
31446d1fb07SSven Peter 
apple_dart_hw_disable_dma(struct apple_dart_stream_map * stream_map)31546d1fb07SSven Peter static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
31646d1fb07SSven Peter {
317510d4072SHector Martin 	struct apple_dart *dart = stream_map->dart;
31846d1fb07SSven Peter 	int sid;
31946d1fb07SSven Peter 
320510d4072SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
321b76c68fcSHector Martin 		writel(dart->hw->tcr_disabled, dart->regs + DART_TCR(dart, sid));
32246d1fb07SSven Peter }
32346d1fb07SSven Peter 
32446d1fb07SSven Peter static void
apple_dart_hw_enable_bypass(struct apple_dart_stream_map * stream_map)32546d1fb07SSven Peter apple_dart_hw_enable_bypass(struct apple_dart_stream_map *stream_map)
32646d1fb07SSven Peter {
327510d4072SHector Martin 	struct apple_dart *dart = stream_map->dart;
32846d1fb07SSven Peter 	int sid;
32946d1fb07SSven Peter 
33046d1fb07SSven Peter 	WARN_ON(!stream_map->dart->supports_bypass);
331510d4072SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
332b76c68fcSHector Martin 		writel(dart->hw->tcr_bypass,
333b76c68fcSHector Martin 		       dart->regs + DART_TCR(dart, sid));
33446d1fb07SSven Peter }
33546d1fb07SSven Peter 
apple_dart_hw_set_ttbr(struct apple_dart_stream_map * stream_map,u8 idx,phys_addr_t paddr)33646d1fb07SSven Peter static void apple_dart_hw_set_ttbr(struct apple_dart_stream_map *stream_map,
33746d1fb07SSven Peter 				   u8 idx, phys_addr_t paddr)
33846d1fb07SSven Peter {
339510d4072SHector Martin 	struct apple_dart *dart = stream_map->dart;
34046d1fb07SSven Peter 	int sid;
34146d1fb07SSven Peter 
342b76c68fcSHector Martin 	WARN_ON(paddr & ((1 << dart->hw->ttbr_shift) - 1));
343510d4072SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
344b76c68fcSHector Martin 		writel(dart->hw->ttbr_valid |
345b76c68fcSHector Martin 		       (paddr >> dart->hw->ttbr_shift) << dart->hw->ttbr_addr_field_shift,
3460b459bcdSHector Martin 		       dart->regs + DART_TTBR(dart, sid, idx));
34746d1fb07SSven Peter }
34846d1fb07SSven Peter 
apple_dart_hw_clear_ttbr(struct apple_dart_stream_map * stream_map,u8 idx)34946d1fb07SSven Peter static void apple_dart_hw_clear_ttbr(struct apple_dart_stream_map *stream_map,
35046d1fb07SSven Peter 				     u8 idx)
35146d1fb07SSven Peter {
352510d4072SHector Martin 	struct apple_dart *dart = stream_map->dart;
35346d1fb07SSven Peter 	int sid;
35446d1fb07SSven Peter 
355510d4072SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
3560b459bcdSHector Martin 		writel(0, dart->regs + DART_TTBR(dart, sid, idx));
35746d1fb07SSven Peter }
35846d1fb07SSven Peter 
35946d1fb07SSven Peter static void
apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map * stream_map)36046d1fb07SSven Peter apple_dart_hw_clear_all_ttbrs(struct apple_dart_stream_map *stream_map)
36146d1fb07SSven Peter {
36246d1fb07SSven Peter 	int i;
36346d1fb07SSven Peter 
3640b459bcdSHector Martin 	for (i = 0; i < stream_map->dart->hw->ttbr_count; ++i)
36546d1fb07SSven Peter 		apple_dart_hw_clear_ttbr(stream_map, i);
36646d1fb07SSven Peter }
36746d1fb07SSven Peter 
36846d1fb07SSven Peter static int
apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map * stream_map,u32 command)369b76c68fcSHector Martin apple_dart_t8020_hw_stream_command(struct apple_dart_stream_map *stream_map,
37046d1fb07SSven Peter 			     u32 command)
37146d1fb07SSven Peter {
37246d1fb07SSven Peter 	unsigned long flags;
37346d1fb07SSven Peter 	int ret;
37446d1fb07SSven Peter 	u32 command_reg;
37546d1fb07SSven Peter 
37646d1fb07SSven Peter 	spin_lock_irqsave(&stream_map->dart->lock, flags);
37746d1fb07SSven Peter 
378b76c68fcSHector Martin 	writel(stream_map->sidmap[0], stream_map->dart->regs + DART_T8020_STREAM_SELECT);
379b76c68fcSHector Martin 	writel(command, stream_map->dart->regs + DART_T8020_STREAM_COMMAND);
38046d1fb07SSven Peter 
38146d1fb07SSven Peter 	ret = readl_poll_timeout_atomic(
382b76c68fcSHector Martin 		stream_map->dart->regs + DART_T8020_STREAM_COMMAND, command_reg,
383b76c68fcSHector Martin 		!(command_reg & DART_T8020_STREAM_COMMAND_BUSY), 1,
38446d1fb07SSven Peter 		DART_STREAM_COMMAND_BUSY_TIMEOUT);
38546d1fb07SSven Peter 
38646d1fb07SSven Peter 	spin_unlock_irqrestore(&stream_map->dart->lock, flags);
38746d1fb07SSven Peter 
38846d1fb07SSven Peter 	if (ret) {
38946d1fb07SSven Peter 		dev_err(stream_map->dart->dev,
39046d1fb07SSven Peter 			"busy bit did not clear after command %x for streams %lx\n",
391510d4072SHector Martin 			command, stream_map->sidmap[0]);
39246d1fb07SSven Peter 		return ret;
39346d1fb07SSven Peter 	}
39446d1fb07SSven Peter 
39546d1fb07SSven Peter 	return 0;
39646d1fb07SSven Peter }
39746d1fb07SSven Peter 
39846d1fb07SSven Peter static int
apple_dart_t8110_hw_tlb_command(struct apple_dart_stream_map * stream_map,u32 command)399d8bcc870SHector Martin apple_dart_t8110_hw_tlb_command(struct apple_dart_stream_map *stream_map,
400d8bcc870SHector Martin 				u32 command)
40146d1fb07SSven Peter {
402d8bcc870SHector Martin 	struct apple_dart *dart = stream_map->dart;
403d8bcc870SHector Martin 	unsigned long flags;
404d8bcc870SHector Martin 	int ret = 0;
405d8bcc870SHector Martin 	int sid;
406d8bcc870SHector Martin 
407d8bcc870SHector Martin 	spin_lock_irqsave(&dart->lock, flags);
408d8bcc870SHector Martin 
409d8bcc870SHector Martin 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams) {
410d8bcc870SHector Martin 		u32 val = FIELD_PREP(DART_T8110_TLB_CMD_OP, command) |
411d8bcc870SHector Martin 			FIELD_PREP(DART_T8110_TLB_CMD_STREAM, sid);
412d8bcc870SHector Martin 		writel(val, dart->regs + DART_T8110_TLB_CMD);
413d8bcc870SHector Martin 
414d8bcc870SHector Martin 		ret = readl_poll_timeout_atomic(
415d8bcc870SHector Martin 			dart->regs + DART_T8110_TLB_CMD, val,
416d8bcc870SHector Martin 			!(val & DART_T8110_TLB_CMD_BUSY), 1,
417d8bcc870SHector Martin 			DART_STREAM_COMMAND_BUSY_TIMEOUT);
418d8bcc870SHector Martin 
419d8bcc870SHector Martin 		if (ret)
420d8bcc870SHector Martin 			break;
421d8bcc870SHector Martin 
422d8bcc870SHector Martin 	}
423d8bcc870SHector Martin 
424d8bcc870SHector Martin 	spin_unlock_irqrestore(&dart->lock, flags);
425d8bcc870SHector Martin 
426d8bcc870SHector Martin 	if (ret) {
427d8bcc870SHector Martin 		dev_err(stream_map->dart->dev,
428d8bcc870SHector Martin 			"busy bit did not clear after command %x for stream %d\n",
429d8bcc870SHector Martin 			command, sid);
430d8bcc870SHector Martin 		return ret;
431d8bcc870SHector Martin 	}
432d8bcc870SHector Martin 
433d8bcc870SHector Martin 	return 0;
434d8bcc870SHector Martin }
435d8bcc870SHector Martin 
436d8bcc870SHector Martin static int
apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map * stream_map)437b76c68fcSHector Martin apple_dart_t8020_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
43846d1fb07SSven Peter {
439b76c68fcSHector Martin 	return apple_dart_t8020_hw_stream_command(
440b76c68fcSHector Martin 		stream_map, DART_T8020_STREAM_COMMAND_INVALIDATE);
44146d1fb07SSven Peter }
44246d1fb07SSven Peter 
443d8bcc870SHector Martin static int
apple_dart_t8110_hw_invalidate_tlb(struct apple_dart_stream_map * stream_map)444d8bcc870SHector Martin apple_dart_t8110_hw_invalidate_tlb(struct apple_dart_stream_map *stream_map)
445d8bcc870SHector Martin {
446d8bcc870SHector Martin 	return apple_dart_t8110_hw_tlb_command(
447d8bcc870SHector Martin 		stream_map, DART_T8110_TLB_CMD_OP_FLUSH_SID);
44846d1fb07SSven Peter }
44946d1fb07SSven Peter 
apple_dart_hw_reset(struct apple_dart * dart)45046d1fb07SSven Peter static int apple_dart_hw_reset(struct apple_dart *dart)
45146d1fb07SSven Peter {
45246d1fb07SSven Peter 	u32 config;
45346d1fb07SSven Peter 	struct apple_dart_stream_map stream_map;
454510d4072SHector Martin 	int i;
45546d1fb07SSven Peter 
456b76c68fcSHector Martin 	config = readl(dart->regs + dart->hw->lock);
457b76c68fcSHector Martin 	if (config & dart->hw->lock_bit) {
45846d1fb07SSven Peter 		dev_err(dart->dev, "DART is locked down until reboot: %08x\n",
45946d1fb07SSven Peter 			config);
46046d1fb07SSven Peter 		return -EINVAL;
46146d1fb07SSven Peter 	}
46246d1fb07SSven Peter 
46346d1fb07SSven Peter 	stream_map.dart = dart;
464510d4072SHector Martin 	bitmap_zero(stream_map.sidmap, DART_MAX_STREAMS);
465510d4072SHector Martin 	bitmap_set(stream_map.sidmap, 0, dart->num_streams);
46646d1fb07SSven Peter 	apple_dart_hw_disable_dma(&stream_map);
46746d1fb07SSven Peter 	apple_dart_hw_clear_all_ttbrs(&stream_map);
46846d1fb07SSven Peter 
4695a009fc1SSven Peter 	/* enable all streams globally since TCR is used to control isolation */
470510d4072SHector Martin 	for (i = 0; i < BITS_TO_U32(dart->num_streams); i++)
471b76c68fcSHector Martin 		writel(U32_MAX, dart->regs + dart->hw->enable_streams + 4 * i);
4725a009fc1SSven Peter 
47346d1fb07SSven Peter 	/* clear any pending errors before the interrupt is unmasked */
474b76c68fcSHector Martin 	writel(readl(dart->regs + dart->hw->error), dart->regs + dart->hw->error);
47546d1fb07SSven Peter 
476d8bcc870SHector Martin 	if (dart->hw->type == DART_T8110)
477d8bcc870SHector Martin 		writel(0,  dart->regs + DART_T8110_ERROR_MASK);
478d8bcc870SHector Martin 
479b76c68fcSHector Martin 	return dart->hw->invalidate_tlb(&stream_map);
48046d1fb07SSven Peter }
48146d1fb07SSven Peter 
apple_dart_domain_flush_tlb(struct apple_dart_domain * domain)48246d1fb07SSven Peter static void apple_dart_domain_flush_tlb(struct apple_dart_domain *domain)
48346d1fb07SSven Peter {
484510d4072SHector Martin 	int i, j;
48546d1fb07SSven Peter 	struct apple_dart_atomic_stream_map *domain_stream_map;
48646d1fb07SSven Peter 	struct apple_dart_stream_map stream_map;
48746d1fb07SSven Peter 
48846d1fb07SSven Peter 	for_each_stream_map(i, domain, domain_stream_map) {
48946d1fb07SSven Peter 		stream_map.dart = domain_stream_map->dart;
490510d4072SHector Martin 
491510d4072SHector Martin 		for (j = 0; j < BITS_TO_LONGS(stream_map.dart->num_streams); j++)
492510d4072SHector Martin 			stream_map.sidmap[j] = atomic_long_read(&domain_stream_map->sidmap[j]);
493510d4072SHector Martin 
494b76c68fcSHector Martin 		stream_map.dart->hw->invalidate_tlb(&stream_map);
49546d1fb07SSven Peter 	}
49646d1fb07SSven Peter }
49746d1fb07SSven Peter 
apple_dart_flush_iotlb_all(struct iommu_domain * domain)49846d1fb07SSven Peter static void apple_dart_flush_iotlb_all(struct iommu_domain *domain)
49946d1fb07SSven Peter {
50046d1fb07SSven Peter 	apple_dart_domain_flush_tlb(to_dart_domain(domain));
50146d1fb07SSven Peter }
50246d1fb07SSven Peter 
apple_dart_iotlb_sync(struct iommu_domain * domain,struct iommu_iotlb_gather * gather)50346d1fb07SSven Peter static void apple_dart_iotlb_sync(struct iommu_domain *domain,
50446d1fb07SSven Peter 				  struct iommu_iotlb_gather *gather)
50546d1fb07SSven Peter {
50646d1fb07SSven Peter 	apple_dart_domain_flush_tlb(to_dart_domain(domain));
50746d1fb07SSven Peter }
50846d1fb07SSven Peter 
apple_dart_iotlb_sync_map(struct iommu_domain * domain,unsigned long iova,size_t size)50946d1fb07SSven Peter static void apple_dart_iotlb_sync_map(struct iommu_domain *domain,
51046d1fb07SSven Peter 				      unsigned long iova, size_t size)
51146d1fb07SSven Peter {
51246d1fb07SSven Peter 	apple_dart_domain_flush_tlb(to_dart_domain(domain));
51346d1fb07SSven Peter }
51446d1fb07SSven Peter 
apple_dart_iova_to_phys(struct iommu_domain * domain,dma_addr_t iova)51546d1fb07SSven Peter static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
51646d1fb07SSven Peter 					   dma_addr_t iova)
51746d1fb07SSven Peter {
51846d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
51946d1fb07SSven Peter 	struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
52046d1fb07SSven Peter 
52146d1fb07SSven Peter 	if (!ops)
52246d1fb07SSven Peter 		return 0;
52346d1fb07SSven Peter 
52446d1fb07SSven Peter 	return ops->iova_to_phys(ops, iova);
52546d1fb07SSven Peter }
52646d1fb07SSven Peter 
apple_dart_map_pages(struct iommu_domain * domain,unsigned long iova,phys_addr_t paddr,size_t pgsize,size_t pgcount,int prot,gfp_t gfp,size_t * mapped)52746d1fb07SSven Peter static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
52846d1fb07SSven Peter 				phys_addr_t paddr, size_t pgsize,
52946d1fb07SSven Peter 				size_t pgcount, int prot, gfp_t gfp,
53046d1fb07SSven Peter 				size_t *mapped)
53146d1fb07SSven Peter {
53246d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
53346d1fb07SSven Peter 	struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
53446d1fb07SSven Peter 
53546d1fb07SSven Peter 	if (!ops)
53646d1fb07SSven Peter 		return -ENODEV;
53746d1fb07SSven Peter 
53846d1fb07SSven Peter 	return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
53946d1fb07SSven Peter 			      mapped);
54046d1fb07SSven Peter }
54146d1fb07SSven Peter 
apple_dart_unmap_pages(struct iommu_domain * domain,unsigned long iova,size_t pgsize,size_t pgcount,struct iommu_iotlb_gather * gather)54246d1fb07SSven Peter static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
54346d1fb07SSven Peter 				     unsigned long iova, size_t pgsize,
54446d1fb07SSven Peter 				     size_t pgcount,
54546d1fb07SSven Peter 				     struct iommu_iotlb_gather *gather)
54646d1fb07SSven Peter {
54746d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
54846d1fb07SSven Peter 	struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
54946d1fb07SSven Peter 
55046d1fb07SSven Peter 	return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
55146d1fb07SSven Peter }
55246d1fb07SSven Peter 
55346d1fb07SSven Peter static void
apple_dart_setup_translation(struct apple_dart_domain * domain,struct apple_dart_stream_map * stream_map)55446d1fb07SSven Peter apple_dart_setup_translation(struct apple_dart_domain *domain,
55546d1fb07SSven Peter 			     struct apple_dart_stream_map *stream_map)
55646d1fb07SSven Peter {
55746d1fb07SSven Peter 	int i;
55846d1fb07SSven Peter 	struct io_pgtable_cfg *pgtbl_cfg =
55946d1fb07SSven Peter 		&io_pgtable_ops_to_pgtable(domain->pgtbl_ops)->cfg;
56046d1fb07SSven Peter 
56146d1fb07SSven Peter 	for (i = 0; i < pgtbl_cfg->apple_dart_cfg.n_ttbrs; ++i)
56246d1fb07SSven Peter 		apple_dart_hw_set_ttbr(stream_map, i,
56346d1fb07SSven Peter 				       pgtbl_cfg->apple_dart_cfg.ttbr[i]);
5640b459bcdSHector Martin 	for (; i < stream_map->dart->hw->ttbr_count; ++i)
56546d1fb07SSven Peter 		apple_dart_hw_clear_ttbr(stream_map, i);
56646d1fb07SSven Peter 
56746d1fb07SSven Peter 	apple_dart_hw_enable_translation(stream_map);
568b76c68fcSHector Martin 	stream_map->dart->hw->invalidate_tlb(stream_map);
56946d1fb07SSven Peter }
57046d1fb07SSven Peter 
apple_dart_finalize_domain(struct iommu_domain * domain,struct apple_dart_master_cfg * cfg)57146d1fb07SSven Peter static int apple_dart_finalize_domain(struct iommu_domain *domain,
57246d1fb07SSven Peter 				      struct apple_dart_master_cfg *cfg)
57346d1fb07SSven Peter {
57446d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
57546d1fb07SSven Peter 	struct apple_dart *dart = cfg->stream_maps[0].dart;
57646d1fb07SSven Peter 	struct io_pgtable_cfg pgtbl_cfg;
57746d1fb07SSven Peter 	int ret = 0;
578510d4072SHector Martin 	int i, j;
57946d1fb07SSven Peter 
58046d1fb07SSven Peter 	mutex_lock(&dart_domain->init_lock);
58146d1fb07SSven Peter 
58246d1fb07SSven Peter 	if (dart_domain->finalized)
58346d1fb07SSven Peter 		goto done;
58446d1fb07SSven Peter 
58546d1fb07SSven Peter 	for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
58646d1fb07SSven Peter 		dart_domain->stream_maps[i].dart = cfg->stream_maps[i].dart;
587510d4072SHector Martin 		for (j = 0; j < BITS_TO_LONGS(dart->num_streams); j++)
588510d4072SHector Martin 			atomic_long_set(&dart_domain->stream_maps[i].sidmap[j],
589510d4072SHector Martin 					cfg->stream_maps[i].sidmap[j]);
59046d1fb07SSven Peter 	}
59146d1fb07SSven Peter 
59246d1fb07SSven Peter 	pgtbl_cfg = (struct io_pgtable_cfg){
59346d1fb07SSven Peter 		.pgsize_bitmap = dart->pgsize,
594d8bcc870SHector Martin 		.ias = dart->ias,
595d8bcc870SHector Martin 		.oas = dart->oas,
59646d1fb07SSven Peter 		.coherent_walk = 1,
59746d1fb07SSven Peter 		.iommu_dev = dart->dev,
59846d1fb07SSven Peter 	};
59946d1fb07SSven Peter 
60046d1fb07SSven Peter 	dart_domain->pgtbl_ops =
601a380b8dcSSven Peter 		alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg, domain);
60246d1fb07SSven Peter 	if (!dart_domain->pgtbl_ops) {
60346d1fb07SSven Peter 		ret = -ENOMEM;
60446d1fb07SSven Peter 		goto done;
60546d1fb07SSven Peter 	}
60646d1fb07SSven Peter 
60746d1fb07SSven Peter 	domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
60846d1fb07SSven Peter 	domain->geometry.aperture_start = 0;
609d8bcc870SHector Martin 	domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(dart->ias);
61046d1fb07SSven Peter 	domain->geometry.force_aperture = true;
61146d1fb07SSven Peter 
61246d1fb07SSven Peter 	dart_domain->finalized = true;
61346d1fb07SSven Peter 
61446d1fb07SSven Peter done:
61546d1fb07SSven Peter 	mutex_unlock(&dart_domain->init_lock);
61646d1fb07SSven Peter 	return ret;
61746d1fb07SSven Peter }
61846d1fb07SSven Peter 
61946d1fb07SSven Peter static int
apple_dart_mod_streams(struct apple_dart_atomic_stream_map * domain_maps,struct apple_dart_stream_map * master_maps,bool add_streams)62046d1fb07SSven Peter apple_dart_mod_streams(struct apple_dart_atomic_stream_map *domain_maps,
62146d1fb07SSven Peter 		       struct apple_dart_stream_map *master_maps,
62246d1fb07SSven Peter 		       bool add_streams)
62346d1fb07SSven Peter {
624510d4072SHector Martin 	int i, j;
62546d1fb07SSven Peter 
62646d1fb07SSven Peter 	for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
62746d1fb07SSven Peter 		if (domain_maps[i].dart != master_maps[i].dart)
62846d1fb07SSven Peter 			return -EINVAL;
62946d1fb07SSven Peter 	}
63046d1fb07SSven Peter 
63146d1fb07SSven Peter 	for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
63246d1fb07SSven Peter 		if (!domain_maps[i].dart)
63346d1fb07SSven Peter 			break;
634510d4072SHector Martin 		for (j = 0; j < BITS_TO_LONGS(domain_maps[i].dart->num_streams); j++) {
63546d1fb07SSven Peter 			if (add_streams)
636510d4072SHector Martin 				atomic_long_or(master_maps[i].sidmap[j],
637510d4072SHector Martin 					       &domain_maps[i].sidmap[j]);
63846d1fb07SSven Peter 			else
639510d4072SHector Martin 				atomic_long_and(~master_maps[i].sidmap[j],
640510d4072SHector Martin 						&domain_maps[i].sidmap[j]);
641510d4072SHector Martin 		}
64246d1fb07SSven Peter 	}
64346d1fb07SSven Peter 
64446d1fb07SSven Peter 	return 0;
64546d1fb07SSven Peter }
64646d1fb07SSven Peter 
apple_dart_domain_add_streams(struct apple_dart_domain * domain,struct apple_dart_master_cfg * cfg)64746d1fb07SSven Peter static int apple_dart_domain_add_streams(struct apple_dart_domain *domain,
64846d1fb07SSven Peter 					 struct apple_dart_master_cfg *cfg)
64946d1fb07SSven Peter {
65046d1fb07SSven Peter 	return apple_dart_mod_streams(domain->stream_maps, cfg->stream_maps,
65146d1fb07SSven Peter 				      true);
65246d1fb07SSven Peter }
65346d1fb07SSven Peter 
apple_dart_attach_dev(struct iommu_domain * domain,struct device * dev)65446d1fb07SSven Peter static int apple_dart_attach_dev(struct iommu_domain *domain,
65546d1fb07SSven Peter 				 struct device *dev)
65646d1fb07SSven Peter {
65746d1fb07SSven Peter 	int ret, i;
65846d1fb07SSven Peter 	struct apple_dart_stream_map *stream_map;
65946d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
66046d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
66146d1fb07SSven Peter 
66246d1fb07SSven Peter 	if (cfg->stream_maps[0].dart->force_bypass &&
66346d1fb07SSven Peter 	    domain->type != IOMMU_DOMAIN_IDENTITY)
66446d1fb07SSven Peter 		return -EINVAL;
66546d1fb07SSven Peter 	if (!cfg->stream_maps[0].dart->supports_bypass &&
66646d1fb07SSven Peter 	    domain->type == IOMMU_DOMAIN_IDENTITY)
66746d1fb07SSven Peter 		return -EINVAL;
66846d1fb07SSven Peter 
66946d1fb07SSven Peter 	ret = apple_dart_finalize_domain(domain, cfg);
67046d1fb07SSven Peter 	if (ret)
67146d1fb07SSven Peter 		return ret;
67246d1fb07SSven Peter 
67346d1fb07SSven Peter 	switch (domain->type) {
674*c7bd8a1fSHector Martin 	default:
67546d1fb07SSven Peter 		ret = apple_dart_domain_add_streams(dart_domain, cfg);
67646d1fb07SSven Peter 		if (ret)
67746d1fb07SSven Peter 			return ret;
67846d1fb07SSven Peter 
67946d1fb07SSven Peter 		for_each_stream_map(i, cfg, stream_map)
68046d1fb07SSven Peter 			apple_dart_setup_translation(dart_domain, stream_map);
68146d1fb07SSven Peter 		break;
68246d1fb07SSven Peter 	case IOMMU_DOMAIN_BLOCKED:
68346d1fb07SSven Peter 		for_each_stream_map(i, cfg, stream_map)
68446d1fb07SSven Peter 			apple_dart_hw_disable_dma(stream_map);
68546d1fb07SSven Peter 		break;
68646d1fb07SSven Peter 	case IOMMU_DOMAIN_IDENTITY:
68746d1fb07SSven Peter 		for_each_stream_map(i, cfg, stream_map)
68846d1fb07SSven Peter 			apple_dart_hw_enable_bypass(stream_map);
68946d1fb07SSven Peter 		break;
69046d1fb07SSven Peter 	}
69146d1fb07SSven Peter 
69246d1fb07SSven Peter 	return ret;
69346d1fb07SSven Peter }
69446d1fb07SSven Peter 
apple_dart_probe_device(struct device * dev)69546d1fb07SSven Peter static struct iommu_device *apple_dart_probe_device(struct device *dev)
69646d1fb07SSven Peter {
69746d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
69846d1fb07SSven Peter 	struct apple_dart_stream_map *stream_map;
69946d1fb07SSven Peter 	int i;
70046d1fb07SSven Peter 
70146d1fb07SSven Peter 	if (!cfg)
70246d1fb07SSven Peter 		return ERR_PTR(-ENODEV);
70346d1fb07SSven Peter 
70446d1fb07SSven Peter 	for_each_stream_map(i, cfg, stream_map)
70546d1fb07SSven Peter 		device_link_add(
70646d1fb07SSven Peter 			dev, stream_map->dart->dev,
70746d1fb07SSven Peter 			DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_SUPPLIER);
70846d1fb07SSven Peter 
70946d1fb07SSven Peter 	return &cfg->stream_maps[0].dart->iommu;
71046d1fb07SSven Peter }
71146d1fb07SSven Peter 
apple_dart_release_device(struct device * dev)71246d1fb07SSven Peter static void apple_dart_release_device(struct device *dev)
71346d1fb07SSven Peter {
71446d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
71546d1fb07SSven Peter 
71646d1fb07SSven Peter 	dev_iommu_priv_set(dev, NULL);
71746d1fb07SSven Peter 	kfree(cfg);
71846d1fb07SSven Peter }
71946d1fb07SSven Peter 
apple_dart_domain_alloc(unsigned int type)72046d1fb07SSven Peter static struct iommu_domain *apple_dart_domain_alloc(unsigned int type)
72146d1fb07SSven Peter {
72246d1fb07SSven Peter 	struct apple_dart_domain *dart_domain;
72346d1fb07SSven Peter 
72446d1fb07SSven Peter 	if (type != IOMMU_DOMAIN_DMA && type != IOMMU_DOMAIN_UNMANAGED &&
72546d1fb07SSven Peter 	    type != IOMMU_DOMAIN_IDENTITY && type != IOMMU_DOMAIN_BLOCKED)
72646d1fb07SSven Peter 		return NULL;
72746d1fb07SSven Peter 
72846d1fb07SSven Peter 	dart_domain = kzalloc(sizeof(*dart_domain), GFP_KERNEL);
72946d1fb07SSven Peter 	if (!dart_domain)
73046d1fb07SSven Peter 		return NULL;
73146d1fb07SSven Peter 
73246d1fb07SSven Peter 	mutex_init(&dart_domain->init_lock);
73346d1fb07SSven Peter 
73446d1fb07SSven Peter 	/* no need to allocate pgtbl_ops or do any other finalization steps */
73546d1fb07SSven Peter 	if (type == IOMMU_DOMAIN_IDENTITY || type == IOMMU_DOMAIN_BLOCKED)
73646d1fb07SSven Peter 		dart_domain->finalized = true;
73746d1fb07SSven Peter 
73846d1fb07SSven Peter 	return &dart_domain->domain;
73946d1fb07SSven Peter }
74046d1fb07SSven Peter 
apple_dart_domain_free(struct iommu_domain * domain)74146d1fb07SSven Peter static void apple_dart_domain_free(struct iommu_domain *domain)
74246d1fb07SSven Peter {
74346d1fb07SSven Peter 	struct apple_dart_domain *dart_domain = to_dart_domain(domain);
74446d1fb07SSven Peter 
74546d1fb07SSven Peter 	if (dart_domain->pgtbl_ops)
74646d1fb07SSven Peter 		free_io_pgtable_ops(dart_domain->pgtbl_ops);
74746d1fb07SSven Peter 
74846d1fb07SSven Peter 	kfree(dart_domain);
74946d1fb07SSven Peter }
75046d1fb07SSven Peter 
apple_dart_of_xlate(struct device * dev,struct of_phandle_args * args)75146d1fb07SSven Peter static int apple_dart_of_xlate(struct device *dev, struct of_phandle_args *args)
75246d1fb07SSven Peter {
75346d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
75446d1fb07SSven Peter 	struct platform_device *iommu_pdev = of_find_device_by_node(args->np);
75546d1fb07SSven Peter 	struct apple_dart *dart = platform_get_drvdata(iommu_pdev);
75646d1fb07SSven Peter 	struct apple_dart *cfg_dart;
75746d1fb07SSven Peter 	int i, sid;
75846d1fb07SSven Peter 
75946d1fb07SSven Peter 	if (args->args_count != 1)
76046d1fb07SSven Peter 		return -EINVAL;
76146d1fb07SSven Peter 	sid = args->args[0];
76246d1fb07SSven Peter 
76346d1fb07SSven Peter 	if (!cfg)
76446d1fb07SSven Peter 		cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
76546d1fb07SSven Peter 	if (!cfg)
76646d1fb07SSven Peter 		return -ENOMEM;
76746d1fb07SSven Peter 	dev_iommu_priv_set(dev, cfg);
76846d1fb07SSven Peter 
76946d1fb07SSven Peter 	cfg_dart = cfg->stream_maps[0].dart;
77046d1fb07SSven Peter 	if (cfg_dart) {
77146d1fb07SSven Peter 		if (cfg_dart->supports_bypass != dart->supports_bypass)
77246d1fb07SSven Peter 			return -EINVAL;
77346d1fb07SSven Peter 		if (cfg_dart->force_bypass != dart->force_bypass)
77446d1fb07SSven Peter 			return -EINVAL;
77546d1fb07SSven Peter 		if (cfg_dart->pgsize != dart->pgsize)
77646d1fb07SSven Peter 			return -EINVAL;
77746d1fb07SSven Peter 	}
77846d1fb07SSven Peter 
77946d1fb07SSven Peter 	for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
78046d1fb07SSven Peter 		if (cfg->stream_maps[i].dart == dart) {
781510d4072SHector Martin 			set_bit(sid, cfg->stream_maps[i].sidmap);
78246d1fb07SSven Peter 			return 0;
78346d1fb07SSven Peter 		}
78446d1fb07SSven Peter 	}
78546d1fb07SSven Peter 	for (i = 0; i < MAX_DARTS_PER_DEVICE; ++i) {
78646d1fb07SSven Peter 		if (!cfg->stream_maps[i].dart) {
78746d1fb07SSven Peter 			cfg->stream_maps[i].dart = dart;
788510d4072SHector Martin 			set_bit(sid, cfg->stream_maps[i].sidmap);
78946d1fb07SSven Peter 			return 0;
79046d1fb07SSven Peter 		}
79146d1fb07SSven Peter 	}
79246d1fb07SSven Peter 
79346d1fb07SSven Peter 	return -EINVAL;
79446d1fb07SSven Peter }
79546d1fb07SSven Peter 
796f0b63680SSven Peter static DEFINE_MUTEX(apple_dart_groups_lock);
797f0b63680SSven Peter 
apple_dart_release_group(void * iommu_data)798f0b63680SSven Peter static void apple_dart_release_group(void *iommu_data)
799f0b63680SSven Peter {
800f0b63680SSven Peter 	int i, sid;
801f0b63680SSven Peter 	struct apple_dart_stream_map *stream_map;
802f0b63680SSven Peter 	struct apple_dart_master_cfg *group_master_cfg = iommu_data;
803f0b63680SSven Peter 
804f0b63680SSven Peter 	mutex_lock(&apple_dart_groups_lock);
805f0b63680SSven Peter 
806f0b63680SSven Peter 	for_each_stream_map(i, group_master_cfg, stream_map)
807510d4072SHector Martin 		for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams)
808f0b63680SSven Peter 			stream_map->dart->sid2group[sid] = NULL;
809f0b63680SSven Peter 
810f0b63680SSven Peter 	kfree(iommu_data);
811f0b63680SSven Peter 	mutex_unlock(&apple_dart_groups_lock);
812f0b63680SSven Peter }
813f0b63680SSven Peter 
apple_dart_merge_master_cfg(struct apple_dart_master_cfg * dst,struct apple_dart_master_cfg * src)814cf5c1c87SSven Peter static int apple_dart_merge_master_cfg(struct apple_dart_master_cfg *dst,
815cf5c1c87SSven Peter 				       struct apple_dart_master_cfg *src)
816cf5c1c87SSven Peter {
817cf5c1c87SSven Peter 	/*
818cf5c1c87SSven Peter 	 * We know that this function is only called for groups returned from
819cf5c1c87SSven Peter 	 * pci_device_group and that all Apple Silicon platforms never spread
820cf5c1c87SSven Peter 	 * PCIe devices from the same bus across multiple DARTs such that we can
821cf5c1c87SSven Peter 	 * just assume that both src and dst only have the same single DART.
822cf5c1c87SSven Peter 	 */
823cf5c1c87SSven Peter 	if (src->stream_maps[1].dart)
824cf5c1c87SSven Peter 		return -EINVAL;
825cf5c1c87SSven Peter 	if (dst->stream_maps[1].dart)
826cf5c1c87SSven Peter 		return -EINVAL;
827cf5c1c87SSven Peter 	if (src->stream_maps[0].dart != dst->stream_maps[0].dart)
828cf5c1c87SSven Peter 		return -EINVAL;
829cf5c1c87SSven Peter 
830cf5c1c87SSven Peter 	bitmap_or(dst->stream_maps[0].sidmap,
831cf5c1c87SSven Peter 		  dst->stream_maps[0].sidmap,
832cf5c1c87SSven Peter 		  src->stream_maps[0].sidmap,
833cf5c1c87SSven Peter 		  dst->stream_maps[0].dart->num_streams);
834cf5c1c87SSven Peter 	return 0;
835cf5c1c87SSven Peter }
836cf5c1c87SSven Peter 
apple_dart_device_group(struct device * dev)83746d1fb07SSven Peter static struct iommu_group *apple_dart_device_group(struct device *dev)
83846d1fb07SSven Peter {
83946d1fb07SSven Peter 	int i, sid;
84046d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
84146d1fb07SSven Peter 	struct apple_dart_stream_map *stream_map;
842f0b63680SSven Peter 	struct apple_dart_master_cfg *group_master_cfg;
84346d1fb07SSven Peter 	struct iommu_group *group = NULL;
84446d1fb07SSven Peter 	struct iommu_group *res = ERR_PTR(-EINVAL);
84546d1fb07SSven Peter 
846f0b63680SSven Peter 	mutex_lock(&apple_dart_groups_lock);
84746d1fb07SSven Peter 
84846d1fb07SSven Peter 	for_each_stream_map(i, cfg, stream_map) {
849510d4072SHector Martin 		for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams) {
85046d1fb07SSven Peter 			struct iommu_group *stream_group =
85146d1fb07SSven Peter 				stream_map->dart->sid2group[sid];
85246d1fb07SSven Peter 
85346d1fb07SSven Peter 			if (group && group != stream_group) {
85446d1fb07SSven Peter 				res = ERR_PTR(-EINVAL);
85546d1fb07SSven Peter 				goto out;
85646d1fb07SSven Peter 			}
85746d1fb07SSven Peter 
85846d1fb07SSven Peter 			group = stream_group;
85946d1fb07SSven Peter 		}
86046d1fb07SSven Peter 	}
86146d1fb07SSven Peter 
86246d1fb07SSven Peter 	if (group) {
86346d1fb07SSven Peter 		res = iommu_group_ref_get(group);
86446d1fb07SSven Peter 		goto out;
86546d1fb07SSven Peter 	}
86646d1fb07SSven Peter 
86746d1fb07SSven Peter #ifdef CONFIG_PCI
86846d1fb07SSven Peter 	if (dev_is_pci(dev))
86946d1fb07SSven Peter 		group = pci_device_group(dev);
87046d1fb07SSven Peter 	else
87146d1fb07SSven Peter #endif
87246d1fb07SSven Peter 		group = generic_device_group(dev);
87346d1fb07SSven Peter 
874f0b63680SSven Peter 	res = ERR_PTR(-ENOMEM);
875f0b63680SSven Peter 	if (!group)
876f0b63680SSven Peter 		goto out;
877f0b63680SSven Peter 
878cf5c1c87SSven Peter 	group_master_cfg = iommu_group_get_iommudata(group);
879cf5c1c87SSven Peter 	if (group_master_cfg) {
880cf5c1c87SSven Peter 		int ret;
881cf5c1c87SSven Peter 
882cf5c1c87SSven Peter 		ret = apple_dart_merge_master_cfg(group_master_cfg, cfg);
883cf5c1c87SSven Peter 		if (ret) {
884cf5c1c87SSven Peter 			dev_err(dev, "Failed to merge DART IOMMU grups.\n");
885cf5c1c87SSven Peter 			iommu_group_put(group);
886cf5c1c87SSven Peter 			res = ERR_PTR(ret);
887cf5c1c87SSven Peter 			goto out;
888cf5c1c87SSven Peter 		}
889cf5c1c87SSven Peter 	} else {
890cf5c1c87SSven Peter 		group_master_cfg = kmemdup(cfg, sizeof(*group_master_cfg),
891cf5c1c87SSven Peter 					   GFP_KERNEL);
892f0b63680SSven Peter 		if (!group_master_cfg) {
893f0b63680SSven Peter 			iommu_group_put(group);
894f0b63680SSven Peter 			goto out;
895f0b63680SSven Peter 		}
896f0b63680SSven Peter 
897f0b63680SSven Peter 		iommu_group_set_iommudata(group, group_master_cfg,
898f0b63680SSven Peter 			apple_dart_release_group);
899cf5c1c87SSven Peter 	}
900f0b63680SSven Peter 
90146d1fb07SSven Peter 	for_each_stream_map(i, cfg, stream_map)
902510d4072SHector Martin 		for_each_set_bit(sid, stream_map->sidmap, stream_map->dart->num_streams)
90346d1fb07SSven Peter 			stream_map->dart->sid2group[sid] = group;
90446d1fb07SSven Peter 
90546d1fb07SSven Peter 	res = group;
90646d1fb07SSven Peter 
90746d1fb07SSven Peter out:
908f0b63680SSven Peter 	mutex_unlock(&apple_dart_groups_lock);
90946d1fb07SSven Peter 	return res;
91046d1fb07SSven Peter }
91146d1fb07SSven Peter 
apple_dart_def_domain_type(struct device * dev)91246d1fb07SSven Peter static int apple_dart_def_domain_type(struct device *dev)
91346d1fb07SSven Peter {
91446d1fb07SSven Peter 	struct apple_dart_master_cfg *cfg = dev_iommu_priv_get(dev);
91546d1fb07SSven Peter 
91646d1fb07SSven Peter 	if (cfg->stream_maps[0].dart->force_bypass)
91746d1fb07SSven Peter 		return IOMMU_DOMAIN_IDENTITY;
91846d1fb07SSven Peter 	if (!cfg->stream_maps[0].dart->supports_bypass)
91946d1fb07SSven Peter 		return IOMMU_DOMAIN_DMA;
92046d1fb07SSven Peter 
92146d1fb07SSven Peter 	return 0;
92246d1fb07SSven Peter }
92346d1fb07SSven Peter 
924946d619fSMarc Zyngier #ifndef CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR
925946d619fSMarc Zyngier /* Keep things compiling when CONFIG_PCI_APPLE isn't selected */
926946d619fSMarc Zyngier #define CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR	0
927946d619fSMarc Zyngier #endif
928946d619fSMarc Zyngier #define DOORBELL_ADDR	(CONFIG_PCIE_APPLE_MSI_DOORBELL_ADDR & PAGE_MASK)
929946d619fSMarc Zyngier 
apple_dart_get_resv_regions(struct device * dev,struct list_head * head)930946d619fSMarc Zyngier static void apple_dart_get_resv_regions(struct device *dev,
931946d619fSMarc Zyngier 					struct list_head *head)
932946d619fSMarc Zyngier {
933946d619fSMarc Zyngier 	if (IS_ENABLED(CONFIG_PCIE_APPLE) && dev_is_pci(dev)) {
934946d619fSMarc Zyngier 		struct iommu_resv_region *region;
935946d619fSMarc Zyngier 		int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
936946d619fSMarc Zyngier 
937946d619fSMarc Zyngier 		region = iommu_alloc_resv_region(DOORBELL_ADDR,
938946d619fSMarc Zyngier 						 PAGE_SIZE, prot,
9390251d010SLu Baolu 						 IOMMU_RESV_MSI, GFP_KERNEL);
940946d619fSMarc Zyngier 		if (!region)
941946d619fSMarc Zyngier 			return;
942946d619fSMarc Zyngier 
943946d619fSMarc Zyngier 		list_add_tail(&region->list, head);
944946d619fSMarc Zyngier 	}
945946d619fSMarc Zyngier 
946946d619fSMarc Zyngier 	iommu_dma_get_resv_regions(dev, head);
947946d619fSMarc Zyngier }
948946d619fSMarc Zyngier 
94946d1fb07SSven Peter static const struct iommu_ops apple_dart_iommu_ops = {
95046d1fb07SSven Peter 	.domain_alloc = apple_dart_domain_alloc,
95146d1fb07SSven Peter 	.probe_device = apple_dart_probe_device,
95246d1fb07SSven Peter 	.release_device = apple_dart_release_device,
95346d1fb07SSven Peter 	.device_group = apple_dart_device_group,
95446d1fb07SSven Peter 	.of_xlate = apple_dart_of_xlate,
95546d1fb07SSven Peter 	.def_domain_type = apple_dart_def_domain_type,
956946d619fSMarc Zyngier 	.get_resv_regions = apple_dart_get_resv_regions,
95746d1fb07SSven Peter 	.pgsize_bitmap = -1UL, /* Restricted during dart probe */
9582ac2fab5SHector Martin 	.owner = THIS_MODULE,
9599a630a4bSLu Baolu 	.default_domain_ops = &(const struct iommu_domain_ops) {
9609a630a4bSLu Baolu 		.attach_dev	= apple_dart_attach_dev,
9619a630a4bSLu Baolu 		.map_pages	= apple_dart_map_pages,
9629a630a4bSLu Baolu 		.unmap_pages	= apple_dart_unmap_pages,
9639a630a4bSLu Baolu 		.flush_iotlb_all = apple_dart_flush_iotlb_all,
9649a630a4bSLu Baolu 		.iotlb_sync	= apple_dart_iotlb_sync,
9659a630a4bSLu Baolu 		.iotlb_sync_map	= apple_dart_iotlb_sync_map,
9669a630a4bSLu Baolu 		.iova_to_phys	= apple_dart_iova_to_phys,
9679a630a4bSLu Baolu 		.free		= apple_dart_domain_free,
9689a630a4bSLu Baolu 	}
96946d1fb07SSven Peter };
97046d1fb07SSven Peter 
apple_dart_t8020_irq(int irq,void * dev)971b76c68fcSHector Martin static irqreturn_t apple_dart_t8020_irq(int irq, void *dev)
97246d1fb07SSven Peter {
97346d1fb07SSven Peter 	struct apple_dart *dart = dev;
97446d1fb07SSven Peter 	const char *fault_name = NULL;
975b76c68fcSHector Martin 	u32 error = readl(dart->regs + DART_T8020_ERROR);
976b76c68fcSHector Martin 	u32 error_code = FIELD_GET(DART_T8020_ERROR_CODE, error);
977b76c68fcSHector Martin 	u32 addr_lo = readl(dart->regs + DART_T8020_ERROR_ADDR_LO);
978b76c68fcSHector Martin 	u32 addr_hi = readl(dart->regs + DART_T8020_ERROR_ADDR_HI);
97946d1fb07SSven Peter 	u64 addr = addr_lo | (((u64)addr_hi) << 32);
980b76c68fcSHector Martin 	u8 stream_idx = FIELD_GET(DART_T8020_ERROR_STREAM, error);
98146d1fb07SSven Peter 
982b76c68fcSHector Martin 	if (!(error & DART_T8020_ERROR_FLAG))
98346d1fb07SSven Peter 		return IRQ_NONE;
98446d1fb07SSven Peter 
98546d1fb07SSven Peter 	/* there should only be a single bit set but let's use == to be sure */
986b76c68fcSHector Martin 	if (error_code == DART_T8020_ERROR_READ_FAULT)
98746d1fb07SSven Peter 		fault_name = "READ FAULT";
988b76c68fcSHector Martin 	else if (error_code == DART_T8020_ERROR_WRITE_FAULT)
98946d1fb07SSven Peter 		fault_name = "WRITE FAULT";
990b76c68fcSHector Martin 	else if (error_code == DART_T8020_ERROR_NO_PTE)
99146d1fb07SSven Peter 		fault_name = "NO PTE FOR IOVA";
992b76c68fcSHector Martin 	else if (error_code == DART_T8020_ERROR_NO_PMD)
99346d1fb07SSven Peter 		fault_name = "NO PMD FOR IOVA";
994b76c68fcSHector Martin 	else if (error_code == DART_T8020_ERROR_NO_TTBR)
99546d1fb07SSven Peter 		fault_name = "NO TTBR FOR IOVA";
99646d1fb07SSven Peter 	else
99746d1fb07SSven Peter 		fault_name = "unknown";
99846d1fb07SSven Peter 
99946d1fb07SSven Peter 	dev_err_ratelimited(
100046d1fb07SSven Peter 		dart->dev,
100146d1fb07SSven Peter 		"translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx",
100246d1fb07SSven Peter 		error, stream_idx, error_code, fault_name, addr);
100346d1fb07SSven Peter 
1004b76c68fcSHector Martin 	writel(error, dart->regs + DART_T8020_ERROR);
100546d1fb07SSven Peter 	return IRQ_HANDLED;
100646d1fb07SSven Peter }
100746d1fb07SSven Peter 
apple_dart_t8110_irq(int irq,void * dev)1008d8bcc870SHector Martin static irqreturn_t apple_dart_t8110_irq(int irq, void *dev)
1009d8bcc870SHector Martin {
1010d8bcc870SHector Martin 	struct apple_dart *dart = dev;
1011d8bcc870SHector Martin 	const char *fault_name = NULL;
1012d8bcc870SHector Martin 	u32 error = readl(dart->regs + DART_T8110_ERROR);
1013d8bcc870SHector Martin 	u32 error_code = FIELD_GET(DART_T8110_ERROR_CODE, error);
1014d8bcc870SHector Martin 	u32 addr_lo = readl(dart->regs + DART_T8110_ERROR_ADDR_LO);
1015d8bcc870SHector Martin 	u32 addr_hi = readl(dart->regs + DART_T8110_ERROR_ADDR_HI);
1016d8bcc870SHector Martin 	u64 addr = addr_lo | (((u64)addr_hi) << 32);
1017d8bcc870SHector Martin 	u8 stream_idx = FIELD_GET(DART_T8110_ERROR_STREAM, error);
1018d8bcc870SHector Martin 
1019d8bcc870SHector Martin 	if (!(error & DART_T8110_ERROR_FLAG))
1020d8bcc870SHector Martin 		return IRQ_NONE;
1021d8bcc870SHector Martin 
1022d8bcc870SHector Martin 	/* there should only be a single bit set but let's use == to be sure */
1023d8bcc870SHector Martin 	if (error_code == DART_T8110_ERROR_READ_FAULT)
1024d8bcc870SHector Martin 		fault_name = "READ FAULT";
1025d8bcc870SHector Martin 	else if (error_code == DART_T8110_ERROR_WRITE_FAULT)
1026d8bcc870SHector Martin 		fault_name = "WRITE FAULT";
1027d8bcc870SHector Martin 	else if (error_code == DART_T8110_ERROR_NO_PTE)
1028d8bcc870SHector Martin 		fault_name = "NO PTE FOR IOVA";
1029d8bcc870SHector Martin 	else if (error_code == DART_T8110_ERROR_NO_PMD)
1030d8bcc870SHector Martin 		fault_name = "NO PMD FOR IOVA";
1031d8bcc870SHector Martin 	else if (error_code == DART_T8110_ERROR_NO_PGD)
1032d8bcc870SHector Martin 		fault_name = "NO PGD FOR IOVA";
1033d8bcc870SHector Martin 	else if (error_code == DART_T8110_ERROR_NO_TTBR)
1034d8bcc870SHector Martin 		fault_name = "NO TTBR FOR IOVA";
1035d8bcc870SHector Martin 	else
1036d8bcc870SHector Martin 		fault_name = "unknown";
1037d8bcc870SHector Martin 
1038d8bcc870SHector Martin 	dev_err_ratelimited(
1039d8bcc870SHector Martin 		dart->dev,
1040d8bcc870SHector Martin 		"translation fault: status:0x%x stream:%d code:0x%x (%s) at 0x%llx",
1041d8bcc870SHector Martin 		error, stream_idx, error_code, fault_name, addr);
1042d8bcc870SHector Martin 
1043d8bcc870SHector Martin 	writel(error, dart->regs + DART_T8110_ERROR);
104446d1fb07SSven Peter 	return IRQ_HANDLED;
104546d1fb07SSven Peter }
104646d1fb07SSven Peter 
apple_dart_probe(struct platform_device * pdev)104746d1fb07SSven Peter static int apple_dart_probe(struct platform_device *pdev)
104846d1fb07SSven Peter {
104946d1fb07SSven Peter 	int ret;
1050d8bcc870SHector Martin 	u32 dart_params[4];
105146d1fb07SSven Peter 	struct resource *res;
105246d1fb07SSven Peter 	struct apple_dart *dart;
105346d1fb07SSven Peter 	struct device *dev = &pdev->dev;
105446d1fb07SSven Peter 
105546d1fb07SSven Peter 	dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
105646d1fb07SSven Peter 	if (!dart)
105746d1fb07SSven Peter 		return -ENOMEM;
105846d1fb07SSven Peter 
105946d1fb07SSven Peter 	dart->dev = dev;
1060a380b8dcSSven Peter 	dart->hw = of_device_get_match_data(dev);
106146d1fb07SSven Peter 	spin_lock_init(&dart->lock);
106246d1fb07SSven Peter 
1063a15932f4SYang Yingliang 	dart->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1064a15932f4SYang Yingliang 	if (IS_ERR(dart->regs))
1065a15932f4SYang Yingliang 		return PTR_ERR(dart->regs);
1066a15932f4SYang Yingliang 
106746d1fb07SSven Peter 	if (resource_size(res) < 0x4000) {
106846d1fb07SSven Peter 		dev_err(dev, "MMIO region too small (%pr)\n", res);
106946d1fb07SSven Peter 		return -EINVAL;
107046d1fb07SSven Peter 	}
107146d1fb07SSven Peter 
107246d1fb07SSven Peter 	dart->irq = platform_get_irq(pdev, 0);
107346d1fb07SSven Peter 	if (dart->irq < 0)
107446d1fb07SSven Peter 		return -ENODEV;
107546d1fb07SSven Peter 
107646d1fb07SSven Peter 	ret = devm_clk_bulk_get_all(dev, &dart->clks);
107746d1fb07SSven Peter 	if (ret < 0)
107846d1fb07SSven Peter 		return ret;
107946d1fb07SSven Peter 	dart->num_clks = ret;
108046d1fb07SSven Peter 
108146d1fb07SSven Peter 	ret = clk_bulk_prepare_enable(dart->num_clks, dart->clks);
108246d1fb07SSven Peter 	if (ret)
108346d1fb07SSven Peter 		return ret;
108446d1fb07SSven Peter 
108546d1fb07SSven Peter 	dart_params[0] = readl(dart->regs + DART_PARAMS1);
108646d1fb07SSven Peter 	dart_params[1] = readl(dart->regs + DART_PARAMS2);
1087a772a02cSHector Martin 	dart->pgsize = 1 << FIELD_GET(DART_PARAMS1_PAGE_SHIFT, dart_params[0]);
1088a772a02cSHector Martin 	dart->supports_bypass = dart_params[1] & DART_PARAMS2_BYPASS_SUPPORT;
1089510d4072SHector Martin 
1090d8bcc870SHector Martin 	switch (dart->hw->type) {
1091d8bcc870SHector Martin 	case DART_T8020:
1092d8bcc870SHector Martin 	case DART_T6000:
1093d8bcc870SHector Martin 		dart->ias = 32;
1094d8bcc870SHector Martin 		dart->oas = dart->hw->oas;
1095510d4072SHector Martin 		dart->num_streams = dart->hw->max_sid_count;
1096d8bcc870SHector Martin 		break;
1097d8bcc870SHector Martin 
1098d8bcc870SHector Martin 	case DART_T8110:
1099d8bcc870SHector Martin 		dart_params[2] = readl(dart->regs + DART_T8110_PARAMS3);
1100d8bcc870SHector Martin 		dart_params[3] = readl(dart->regs + DART_T8110_PARAMS4);
1101d8bcc870SHector Martin 		dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
1102d8bcc870SHector Martin 		dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
1103d8bcc870SHector Martin 		dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
1104d8bcc870SHector Martin 		break;
1105d8bcc870SHector Martin 	}
1106510d4072SHector Martin 
1107510d4072SHector Martin 	if (dart->num_streams > DART_MAX_STREAMS) {
1108510d4072SHector Martin 		dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
1109510d4072SHector Martin 			dart->num_streams, DART_MAX_STREAMS);
1110510d4072SHector Martin 		ret = -EINVAL;
1111510d4072SHector Martin 		goto err_clk_disable;
1112510d4072SHector Martin 	}
1113510d4072SHector Martin 
111446d1fb07SSven Peter 	dart->force_bypass = dart->pgsize > PAGE_SIZE;
111546d1fb07SSven Peter 
111646d1fb07SSven Peter 	ret = apple_dart_hw_reset(dart);
111746d1fb07SSven Peter 	if (ret)
111846d1fb07SSven Peter 		goto err_clk_disable;
111946d1fb07SSven Peter 
1120b76c68fcSHector Martin 	ret = request_irq(dart->irq, dart->hw->irq_handler, IRQF_SHARED,
112146d1fb07SSven Peter 			  "apple-dart fault handler", dart);
112246d1fb07SSven Peter 	if (ret)
112346d1fb07SSven Peter 		goto err_clk_disable;
112446d1fb07SSven Peter 
112546d1fb07SSven Peter 	platform_set_drvdata(pdev, dart);
112646d1fb07SSven Peter 
112746d1fb07SSven Peter 	ret = iommu_device_sysfs_add(&dart->iommu, dev, NULL, "apple-dart.%s",
112846d1fb07SSven Peter 				     dev_name(&pdev->dev));
112946d1fb07SSven Peter 	if (ret)
1130006abbe3SRobin Murphy 		goto err_free_irq;
113146d1fb07SSven Peter 
113246d1fb07SSven Peter 	ret = iommu_device_register(&dart->iommu, &apple_dart_iommu_ops, dev);
113346d1fb07SSven Peter 	if (ret)
113446d1fb07SSven Peter 		goto err_sysfs_remove;
113546d1fb07SSven Peter 
113646d1fb07SSven Peter 	dev_info(
113746d1fb07SSven Peter 		&pdev->dev,
1138510d4072SHector Martin 		"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n",
1139510d4072SHector Martin 		dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass);
114046d1fb07SSven Peter 	return 0;
114146d1fb07SSven Peter 
114246d1fb07SSven Peter err_sysfs_remove:
114346d1fb07SSven Peter 	iommu_device_sysfs_remove(&dart->iommu);
114446d1fb07SSven Peter err_free_irq:
114546d1fb07SSven Peter 	free_irq(dart->irq, dart);
114646d1fb07SSven Peter err_clk_disable:
114746d1fb07SSven Peter 	clk_bulk_disable_unprepare(dart->num_clks, dart->clks);
114846d1fb07SSven Peter 
114946d1fb07SSven Peter 	return ret;
115046d1fb07SSven Peter }
115146d1fb07SSven Peter 
apple_dart_remove(struct platform_device * pdev)1152f8047318SUwe Kleine-König static void apple_dart_remove(struct platform_device *pdev)
115346d1fb07SSven Peter {
115446d1fb07SSven Peter 	struct apple_dart *dart = platform_get_drvdata(pdev);
115546d1fb07SSven Peter 
115646d1fb07SSven Peter 	apple_dart_hw_reset(dart);
115746d1fb07SSven Peter 	free_irq(dart->irq, dart);
115846d1fb07SSven Peter 
115946d1fb07SSven Peter 	iommu_device_unregister(&dart->iommu);
116046d1fb07SSven Peter 	iommu_device_sysfs_remove(&dart->iommu);
116146d1fb07SSven Peter 
116246d1fb07SSven Peter 	clk_bulk_disable_unprepare(dart->num_clks, dart->clks);
116346d1fb07SSven Peter }
116446d1fb07SSven Peter 
1165a380b8dcSSven Peter static const struct apple_dart_hw apple_dart_hw_t8103 = {
1166d8bcc870SHector Martin 	.type = DART_T8020,
1167b76c68fcSHector Martin 	.irq_handler = apple_dart_t8020_irq,
1168b76c68fcSHector Martin 	.invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
1169a380b8dcSSven Peter 	.oas = 36,
1170a380b8dcSSven Peter 	.fmt = APPLE_DART,
1171510d4072SHector Martin 	.max_sid_count = 16,
11720b459bcdSHector Martin 
1173b76c68fcSHector Martin 	.enable_streams = DART_T8020_STREAMS_ENABLE,
1174b76c68fcSHector Martin 	.lock = DART_T8020_CONFIG,
1175b76c68fcSHector Martin 	.lock_bit = DART_T8020_CONFIG_LOCK,
1176b76c68fcSHector Martin 
1177b76c68fcSHector Martin 	.error = DART_T8020_ERROR,
1178b76c68fcSHector Martin 
1179b76c68fcSHector Martin 	.tcr = DART_T8020_TCR,
1180b76c68fcSHector Martin 	.tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
1181b76c68fcSHector Martin 	.tcr_disabled = 0,
1182b76c68fcSHector Martin 	.tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
1183b76c68fcSHector Martin 
1184b76c68fcSHector Martin 	.ttbr = DART_T8020_TTBR,
1185b76c68fcSHector Martin 	.ttbr_valid = DART_T8020_TTBR_VALID,
1186b76c68fcSHector Martin 	.ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
1187b76c68fcSHector Martin 	.ttbr_shift = DART_T8020_TTBR_SHIFT,
11880b459bcdSHector Martin 	.ttbr_count = 4,
1189a380b8dcSSven Peter };
1190a380b8dcSSven Peter static const struct apple_dart_hw apple_dart_hw_t6000 = {
1191d8bcc870SHector Martin 	.type = DART_T6000,
1192b76c68fcSHector Martin 	.irq_handler = apple_dart_t8020_irq,
1193b76c68fcSHector Martin 	.invalidate_tlb = apple_dart_t8020_hw_invalidate_tlb,
1194a380b8dcSSven Peter 	.oas = 42,
1195a380b8dcSSven Peter 	.fmt = APPLE_DART2,
1196510d4072SHector Martin 	.max_sid_count = 16,
11970b459bcdSHector Martin 
1198b76c68fcSHector Martin 	.enable_streams = DART_T8020_STREAMS_ENABLE,
1199b76c68fcSHector Martin 	.lock = DART_T8020_CONFIG,
1200b76c68fcSHector Martin 	.lock_bit = DART_T8020_CONFIG_LOCK,
1201b76c68fcSHector Martin 
1202b76c68fcSHector Martin 	.error = DART_T8020_ERROR,
1203b76c68fcSHector Martin 
1204b76c68fcSHector Martin 	.tcr = DART_T8020_TCR,
1205b76c68fcSHector Martin 	.tcr_enabled = DART_T8020_TCR_TRANSLATE_ENABLE,
1206b76c68fcSHector Martin 	.tcr_disabled = 0,
1207b76c68fcSHector Martin 	.tcr_bypass = DART_T8020_TCR_BYPASS_DAPF | DART_T8020_TCR_BYPASS_DART,
1208b76c68fcSHector Martin 
1209b76c68fcSHector Martin 	.ttbr = DART_T8020_TTBR,
1210b76c68fcSHector Martin 	.ttbr_valid = DART_T8020_TTBR_VALID,
1211b76c68fcSHector Martin 	.ttbr_addr_field_shift = DART_T8020_TTBR_ADDR_FIELD_SHIFT,
1212b76c68fcSHector Martin 	.ttbr_shift = DART_T8020_TTBR_SHIFT,
12130b459bcdSHector Martin 	.ttbr_count = 4,
1214a380b8dcSSven Peter };
1215a380b8dcSSven Peter 
1216d8bcc870SHector Martin static const struct apple_dart_hw apple_dart_hw_t8110 = {
1217d8bcc870SHector Martin 	.type = DART_T8110,
1218d8bcc870SHector Martin 	.irq_handler = apple_dart_t8110_irq,
1219d8bcc870SHector Martin 	.invalidate_tlb = apple_dart_t8110_hw_invalidate_tlb,
1220d8bcc870SHector Martin 	.fmt = APPLE_DART2,
1221d8bcc870SHector Martin 	.max_sid_count = 256,
1222d8bcc870SHector Martin 
1223d8bcc870SHector Martin 	.enable_streams = DART_T8110_ENABLE_STREAMS,
1224d8bcc870SHector Martin 	.lock = DART_T8110_PROTECT,
1225d8bcc870SHector Martin 	.lock_bit = DART_T8110_PROTECT_TTBR_TCR,
1226d8bcc870SHector Martin 
1227d8bcc870SHector Martin 	.error = DART_T8110_ERROR,
1228d8bcc870SHector Martin 
1229d8bcc870SHector Martin 	.tcr = DART_T8110_TCR,
1230d8bcc870SHector Martin 	.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
1231d8bcc870SHector Martin 	.tcr_disabled = 0,
1232d8bcc870SHector Martin 	.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
1233d8bcc870SHector Martin 
1234d8bcc870SHector Martin 	.ttbr = DART_T8110_TTBR,
1235d8bcc870SHector Martin 	.ttbr_valid = DART_T8110_TTBR_VALID,
1236d8bcc870SHector Martin 	.ttbr_addr_field_shift = DART_T8110_TTBR_ADDR_FIELD_SHIFT,
1237d8bcc870SHector Martin 	.ttbr_shift = DART_T8110_TTBR_SHIFT,
1238d8bcc870SHector Martin 	.ttbr_count = 1,
1239d8bcc870SHector Martin };
1240d8bcc870SHector Martin 
apple_dart_suspend(struct device * dev)12413d68bbb8SHector Martin static __maybe_unused int apple_dart_suspend(struct device *dev)
12423d68bbb8SHector Martin {
12433d68bbb8SHector Martin 	struct apple_dart *dart = dev_get_drvdata(dev);
12443d68bbb8SHector Martin 	unsigned int sid, idx;
12453d68bbb8SHector Martin 
1246510d4072SHector Martin 	for (sid = 0; sid < dart->num_streams; sid++) {
1247b76c68fcSHector Martin 		dart->save_tcr[sid] = readl_relaxed(dart->regs + DART_TCR(dart, sid));
12480b459bcdSHector Martin 		for (idx = 0; idx < dart->hw->ttbr_count; idx++)
12493d68bbb8SHector Martin 			dart->save_ttbr[sid][idx] =
12500b459bcdSHector Martin 				readl(dart->regs + DART_TTBR(dart, sid, idx));
12513d68bbb8SHector Martin 	}
12523d68bbb8SHector Martin 
12533d68bbb8SHector Martin 	return 0;
12543d68bbb8SHector Martin }
12553d68bbb8SHector Martin 
apple_dart_resume(struct device * dev)12563d68bbb8SHector Martin static __maybe_unused int apple_dart_resume(struct device *dev)
12573d68bbb8SHector Martin {
12583d68bbb8SHector Martin 	struct apple_dart *dart = dev_get_drvdata(dev);
12593d68bbb8SHector Martin 	unsigned int sid, idx;
12603d68bbb8SHector Martin 	int ret;
12613d68bbb8SHector Martin 
12623d68bbb8SHector Martin 	ret = apple_dart_hw_reset(dart);
12633d68bbb8SHector Martin 	if (ret) {
12643d68bbb8SHector Martin 		dev_err(dev, "Failed to reset DART on resume\n");
12653d68bbb8SHector Martin 		return ret;
12663d68bbb8SHector Martin 	}
12673d68bbb8SHector Martin 
1268510d4072SHector Martin 	for (sid = 0; sid < dart->num_streams; sid++) {
12690b459bcdSHector Martin 		for (idx = 0; idx < dart->hw->ttbr_count; idx++)
12703d68bbb8SHector Martin 			writel(dart->save_ttbr[sid][idx],
12710b459bcdSHector Martin 			       dart->regs + DART_TTBR(dart, sid, idx));
1272b76c68fcSHector Martin 		writel(dart->save_tcr[sid], dart->regs + DART_TCR(dart, sid));
12733d68bbb8SHector Martin 	}
12743d68bbb8SHector Martin 
12753d68bbb8SHector Martin 	return 0;
12763d68bbb8SHector Martin }
12773d68bbb8SHector Martin 
1278ed8c975bSMin-Hua Chen static DEFINE_SIMPLE_DEV_PM_OPS(apple_dart_pm_ops, apple_dart_suspend, apple_dart_resume);
12793d68bbb8SHector Martin 
128046d1fb07SSven Peter static const struct of_device_id apple_dart_of_match[] = {
1281a380b8dcSSven Peter 	{ .compatible = "apple,t8103-dart", .data = &apple_dart_hw_t8103 },
1282d8bcc870SHector Martin 	{ .compatible = "apple,t8110-dart", .data = &apple_dart_hw_t8110 },
1283a380b8dcSSven Peter 	{ .compatible = "apple,t6000-dart", .data = &apple_dart_hw_t6000 },
128446d1fb07SSven Peter 	{},
128546d1fb07SSven Peter };
128646d1fb07SSven Peter MODULE_DEVICE_TABLE(of, apple_dart_of_match);
128746d1fb07SSven Peter 
128846d1fb07SSven Peter static struct platform_driver apple_dart_driver = {
128946d1fb07SSven Peter 	.driver	= {
129046d1fb07SSven Peter 		.name			= "apple-dart",
129146d1fb07SSven Peter 		.of_match_table		= apple_dart_of_match,
129246d1fb07SSven Peter 		.suppress_bind_attrs    = true,
12933d68bbb8SHector Martin 		.pm			= pm_sleep_ptr(&apple_dart_pm_ops),
129446d1fb07SSven Peter 	},
129546d1fb07SSven Peter 	.probe	= apple_dart_probe,
1296f8047318SUwe Kleine-König 	.remove_new = apple_dart_remove,
129746d1fb07SSven Peter };
129846d1fb07SSven Peter 
129946d1fb07SSven Peter module_platform_driver(apple_dart_driver);
130046d1fb07SSven Peter 
130146d1fb07SSven Peter MODULE_DESCRIPTION("IOMMU API for Apple's DART");
130246d1fb07SSven Peter MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>");
130346d1fb07SSven Peter MODULE_LICENSE("GPL v2");
1304