global: Migrate CONFIG_SYS_FSL* symbols to the CFG_SYS namespace
[platform/kernel/u-boot.git] / arch / arm / mach-apple / sart.c
1 // SPDX-License-Identifier: MIT
2 /*
3  * The sart code is copied from m1n1 (https://github.com/AsahiLinux/m1n1) and
4  * licensed as MIT.
5  *
6  * (C) Copyright 2022 The Asahi Linux Contributors
7  */
8
9 #include <asm/io.h>
10 #include <asm/arch/sart.h>
11
12 #include <linux/bitfield.h>
13 #include <linux/types.h>
14
15 #include <malloc.h>
16
17 #define APPLE_SART_MAX_ENTRIES 16
18
19 /* This is probably a bitfield but the exact meaning of each bit is unknown. */
20 #define APPLE_SART_FLAGS_ALLOW 0xff
21
22 /* SARTv2 registers */
23 #define APPLE_SART2_CONFIG(idx)       (0x00 + 4 * (idx))
24 #define APPLE_SART2_CONFIG_FLAGS      GENMASK(31, 24)
25 #define APPLE_SART2_CONFIG_SIZE       GENMASK(23, 0)
26 #define APPLE_SART2_CONFIG_SIZE_SHIFT 12
27 #define APPLE_SART2_CONFIG_SIZE_MAX   GENMASK(23, 0)
28
29 #define APPLE_SART2_PADDR(idx)  (0x40 + 4 * (idx))
30 #define APPLE_SART2_PADDR_SHIFT 12
31
32 /* SARTv3 registers */
33 #define APPLE_SART3_CONFIG(idx) (0x00 + 4 * (idx))
34
35 #define APPLE_SART3_PADDR(idx)  (0x40 + 4 * (idx))
36 #define APPLE_SART3_PADDR_SHIFT 12
37
38 #define APPLE_SART3_SIZE(idx)  (0x80 + 4 * (idx))
39 #define APPLE_SART3_SIZE_SHIFT 12
40 #define APPLE_SART3_SIZE_MAX   GENMASK(29, 0)
41
42 struct apple_sart {
43         uintptr_t base;
44         u32 protected_entries;
45
46         void (*get_entry)(struct apple_sart *sart, int index, u8 *flags, void **paddr,
47                           size_t *size);
48         bool (*set_entry)(struct apple_sart *sart, int index, u8 flags, void *paddr,
49                           size_t size);
50 };
51
52 static void sart2_get_entry(struct apple_sart *sart, int index, u8 *flags, void **paddr,
53                             size_t *size)
54 {
55         u32 cfg = readl(sart->base + APPLE_SART2_CONFIG(index));
56         *flags = FIELD_GET(APPLE_SART2_CONFIG_FLAGS, cfg);
57         *size = (size_t)FIELD_GET(APPLE_SART2_CONFIG_SIZE, cfg) << APPLE_SART2_CONFIG_SIZE_SHIFT;
58         *paddr = (void *)
59                 ((u64)readl(sart->base + APPLE_SART2_PADDR(index)) << APPLE_SART2_PADDR_SHIFT);
60 }
61
62 static bool sart2_set_entry(struct apple_sart *sart, int index, u8 flags, void *paddr_,
63                             size_t size)
64 {
65         u32 cfg;
66         u64 paddr = (u64)paddr_;
67
68         if (size & ((1 << APPLE_SART2_CONFIG_SIZE_SHIFT) - 1))
69                 return false;
70         if (paddr & ((1 << APPLE_SART2_PADDR_SHIFT) - 1))
71                 return false;
72
73         size >>= APPLE_SART2_CONFIG_SIZE_SHIFT;
74         paddr >>= APPLE_SART2_PADDR_SHIFT;
75
76         if (size > APPLE_SART2_CONFIG_SIZE_MAX)
77                 return false;
78
79         cfg = FIELD_PREP(APPLE_SART2_CONFIG_FLAGS, flags);
80         cfg |= FIELD_PREP(APPLE_SART2_CONFIG_SIZE, size);
81
82         writel(paddr, sart->base + APPLE_SART2_PADDR(index));
83         writel(cfg, sart->base + APPLE_SART2_CONFIG(index));
84
85         return true;
86 }
87
88 static void sart3_get_entry(struct apple_sart *sart, int index, u8 *flags, void **paddr,
89                             size_t *size)
90 {
91         *flags = readl(sart->base + APPLE_SART3_CONFIG(index));
92         *size = (size_t)readl(sart->base + APPLE_SART3_SIZE(index)) << APPLE_SART3_SIZE_SHIFT;
93         *paddr = (void *)
94                 ((u64)readl(sart->base + APPLE_SART3_PADDR(index)) << APPLE_SART3_PADDR_SHIFT);
95 }
96
97 static bool sart3_set_entry(struct apple_sart *sart, int index, u8 flags, void *paddr_,
98                             size_t size)
99 {
100         u64 paddr = (u64)paddr_;
101
102         if (size & ((1 << APPLE_SART3_SIZE_SHIFT) - 1))
103                 return false;
104         if (paddr & ((1 << APPLE_SART3_PADDR_SHIFT) - 1))
105                 return false;
106
107         paddr >>= APPLE_SART3_PADDR_SHIFT;
108         size >>= APPLE_SART3_SIZE_SHIFT;
109
110         if (size > APPLE_SART3_SIZE_MAX)
111                 return false;
112
113         writel(paddr, sart->base + APPLE_SART3_PADDR(index));
114         writel(size, sart->base + APPLE_SART3_SIZE(index));
115         writel(flags, sart->base + APPLE_SART3_CONFIG(index));
116
117         return true;
118 }
119
120 struct apple_sart *sart_init(ofnode node)
121 {
122         phys_addr_t base;
123         u32 sart_version;
124         struct apple_sart *sart;
125
126         base = ofnode_get_addr(node);
127         if (base == FDT_ADDR_T_NONE)
128                 return NULL;
129
130         if (ofnode_device_is_compatible(node, "apple,t8103-sart")) {
131                 sart_version = 2;
132         } else if (ofnode_device_is_compatible(node, "apple,t6000-sart")) {
133                 sart_version = 3;
134         } else {
135                 printf("sart: unknown SART compatible: %sd\n",
136                        ofnode_read_string(node, "compatible"));
137                 return NULL;
138         }
139
140         sart = calloc(sizeof(*sart), 1);
141         if (!sart)
142                 return NULL;
143
144         sart->base = base;
145
146         switch (sart_version) {
147         case 2:
148                 sart->get_entry = sart2_get_entry;
149                 sart->set_entry = sart2_set_entry;
150                 break;
151         case 3:
152                 sart->get_entry = sart3_get_entry;
153                 sart->set_entry = sart3_set_entry;
154                 break;
155         default:
156                 printf("sart: SART has unknown version %d\n", sart_version);
157                 free(sart);
158                 return NULL;
159         }
160
161         sart->protected_entries = 0;
162         for (unsigned int i = 0; i < APPLE_SART_MAX_ENTRIES; ++i) {
163                 void *paddr;
164                 u8 flags;
165                 size_t sz;
166
167                 sart->get_entry(sart, i, &flags, &paddr, &sz);
168                 if (flags)
169                         sart->protected_entries |= 1 << i;
170         }
171
172         return sart;
173 }
174
175 void sart_free(struct apple_sart *sart)
176 {
177         for (unsigned int i = 0; i < APPLE_SART_MAX_ENTRIES; ++i) {
178                 if (sart->protected_entries & (1 << i))
179                         continue;
180                 sart->set_entry(sart, i, 0, NULL, 0);
181         }
182
183         free(sart);
184 }
185
186 bool sart_add_allowed_region(struct apple_sart *sart, void *paddr, size_t sz)
187 {
188         for (unsigned int i = 0; i < APPLE_SART_MAX_ENTRIES; ++i) {
189                 void *e_paddr;
190                 u8 e_flags;
191                 size_t e_sz;
192
193                 if (sart->protected_entries & (1 << i))
194                         continue;
195
196                 sart->get_entry(sart, i, &e_flags, &e_paddr, &e_sz);
197                 if (e_flags)
198                         continue;
199
200                 return sart->set_entry(sart, i, APPLE_SART_FLAGS_ALLOW, paddr, sz);
201         }
202
203         printf("sart: no more free entries\n");
204         return false;
205 }
206
207 bool sart_remove_allowed_region(struct apple_sart *sart, void *paddr, size_t sz)
208 {
209         for (unsigned int i = 0; i < APPLE_SART_MAX_ENTRIES; ++i) {
210                 void *e_paddr;
211                 u8 e_flags;
212                 size_t e_sz;
213
214                 if (sart->protected_entries & (1 << i))
215                         continue;
216
217                 sart->get_entry(sart, i, &e_flags, &e_paddr, &e_sz);
218                 if (!e_flags)
219                         continue;
220                 if (e_paddr != paddr)
221                         continue;
222                 if (e_sz != sz)
223                         continue;
224
225                 return sart->set_entry(sart, i, 0, NULL, 0);
226         }
227
228         printf("sart: could not find entry to be removed\n");
229         return false;
230 }