1 /*
2 * Copyright (c) 2021-2022 Arm Limited. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "atu_rss_drv.h"
18
19 #include <stddef.h>
20
21 #define ATU_GET_ATUPS(atu_base) ( \
22 (uint8_t)(((atu_base)->atubc & ATU_ATUBC_PS_MASK) >> ATU_ATUBC_PS_OFF))
23
24 #define ATU_ATUBC_PS_OFF 4u
25 /*!< ATU Build Configuration Register Page Size bit field offset */
26 #define ATU_ATUBC_PS_MASK (0xFu << ATU_ATUBC_PS_OFF)
27 /*!< ATU Build Configuration Register Page Size bit field mask */
28 #define ATU_ATUBC_RC_OFF 0u
29 /*!< ATU Build Configuration Register Region Count bit field offset */
30 #define ATU_ATUBC_RC_MASK (0x7u << ATU_ATUBC_RC_OFF)
31 /*!< ATU Build Configuration Register Region Count bit field mask */
32 #define ATU_ATUIS_ME_OFF 0u
33 /*!< ATU Interrupt Status Register Mismatch Error bit field offset */
34 #define ATU_ATUIS_ME_MASK (0x1u << ATU_ATUIS_ME_OFF)
35 /*!< ATU Interrupt Status Register Mismatch Error bit field mask */
36 #define ATU_ATUIE_ME_OFF 0u
37 /*!< ATU Interrupt Enable Register Mismatch Error bit field offset */
38 #define ATU_ATUIE_ME_MASK (0x1u << ATU_ATUIE_ME_OFF)
39 /*!< ATU Interrupt Enable Register Mismatch Error bit field mask */
40 #define ATU_ATUIC_ME_OFF 0u
41 /*!< ATU Interrupt Clear Register Mismatch Error bit field offset */
42 #define ATU_ATUIC_ME_MASK (0x1u << ATU_ATUIC_ME_OFF)
43 /*!< ATU Interrupt Clear Register Mismatch Error bit field mask */
44 #define ATU_ATUROBA_AXNSE_OFF 14u
45 /*!< ATU ROBA Register AxNSE bit field offset */
46 #define ATU_ATUROBA_AXNSE_MASK (0x3u << ATU_ATUROBA_AXNSE_OFF)
47 /*!< ATU ROBA Register AxNSE bit field mask */
48 #define ATU_ATUROBA_AXCACHE3_OFF 12u
49 /*!< ATU ROBA Register AxCACHE3 bit field offset */
50 #define ATU_ATUROBA_AXCACHE3_MASK (0x3u << ATU_ATUROBA_AXCACHE3_OFF)
51 /*!< ATU ROBA Register AxCACHE3 bit field mask */
52 #define ATU_ATUROBA_AXCACHE2_OFF 10u
53 /*!< ATU ROBA Register AxCACHE2 bit field offset */
54 #define ATU_ATUROBA_AXCACHE2_MASK (0x3u << ATU_ATUROBA_AXCACHE2_OFF)
55 /*!< ATU ROBA Register AxCACHE2 bit field mask */
56 #define ATU_ATUROBA_AXCACHE1_OFF 8u
57 /*!< ATU ROBA Register AxCACHE1 bit field offset */
58 #define ATU_ATUROBA_AXCACHE1_MASK (0x3u << ATU_ATUROBA_AXCACHE1_OFF)
59 /*!< ATU ROBA Register AxCACHE1 bit field mask */
60 #define ATU_ATUROBA_AXCACHE0_OFF 6u
61 /*!< ATU ROBA Register AxCACHE0 bit field offset */
62 #define ATU_ATUROBA_AXCACHE0_MASK (0x3u << ATU_ATUROBA_AXCACHE0_OFF)
63 /*!< ATU ROBA Register AxCACHE0 bit field mask */
64 #define ATU_ATUROBA_AXPROT2_OFF 4u
65 /*!< ATU ROBA Register AxPROT2 bit field offset */
66 #define ATU_ATUROBA_AXPROT2_MASK (0x3u << ATU_ATUROBA_AXPROT2_OFF)
67 /*!< ATU ROBA Register AxPROT2 bit field mask */
68 #define ATU_ATUROBA_AXPROT1_OFF 2u
69 /*!< ATU ROBA Register AxPROT1 bit field offset */
70 #define ATU_ATUROBA_AXPROT1_MASK (0x3u << ATU_ATUROBA_AXPROT1_OFF)
71 /*!< ATU ROBA Register AxPROT1 bit field mask */
72 #define ATU_ATUROBA_AXPROT0_OFF 0u
73 /*!< ATU ROBA Register AxPROT0 bit field offset */
74 #define ATU_ATUROBA_AXPROT0_MASK (0x3u << ATU_ATUROBA_AXPROT0_OFF)
75 /*!< ATU ROBA Register AxPROT0 bit field mask */
76
77 /**
78 * \brief ATU register map structure
79 */
80 struct _atu_reg_map_t {
81 volatile uint32_t atubc;
82 /*!< Offset: 0x000 (R/ ) ATU Build Configuration Register */
83 volatile uint32_t atuc;
84 /*!< Offset: 0x004 (R/W) ATU Configuration Register */
85 volatile uint32_t atuis;
86 /*!< Offset: 0x008 (R/ ) ATU Interrupt Status Register */
87 volatile uint32_t atuie;
88 /*!< Offset: 0x00C (R/W) ATU Interrupt Enable Register */
89 volatile uint32_t atuic;
90 /*!< Offset: 0x010 (R/W) ATU Interrupt Clear Register */
91 volatile uint32_t atuma;
92 /*!< Offset: 0x014 (R/ ) ATU Mismatched Address Register */
93 volatile uint32_t reserved_0[2]; /*!< Offset: 0x018-0x01C Reserved */
94 volatile uint32_t atursla[32];
95 /*!< Offset: 0x020 (R/W) ATU Region Start Logical Address n
96 * Register */
97 volatile uint32_t aturela[32];
98 /*!< Offset: 0x0A0 (R/W) ATU Region End Logical Address n
99 * Register */
100 volatile uint32_t aturav_l[32];
101 /*!< Offset: 0x120 (R/W) ATU Region Add Value Low n Register */
102 volatile uint32_t aturav_m[32];
103 /*!< Offset: 0x1A0 (R/W) ATU Region Add Value High n Register */
104 volatile uint32_t aturoba[32];
105 /*!< Offset: 0x220 (R/W) ATU Region Output Bus Attributes n
106 * Register */
107 volatile uint32_t aturgp[32];
108 /*!< Offset: 0x2A0 (R/W) ATU Region General Purpose n
109 * Register */
110 volatile uint32_t reserved_1[811]; /*!< Offset: 0x320-0xFCC Reserved */
111 volatile uint32_t pidr4;
112 /*!< Offset: 0xFD0 (R/ ) Peripheral ID 4 */
113 volatile uint32_t reserved_2[2]; /*!< Offset: 0xFD4-0xFDC Reserved */
114 volatile uint32_t pidr0;
115 /*!< Offset: 0xFE0 (R/ ) Peripheral ID 0 */
116 volatile uint32_t pidr1;
117 /*!< Offset: 0xFE4 (R/ ) Peripheral ID 1 */
118 volatile uint32_t pidr2;
119 /*!< Offset: 0xFE8 (R/ ) Peripheral ID 2 */
120 volatile uint32_t pidr3;
121 /*!< Offset: 0xFEC (R/ ) Peripheral ID 3 */
122 volatile uint32_t cidr0;
123 /*!< Offset: 0xFF0 (R/ ) Component ID 0 */
124 volatile uint32_t cidr1;
125 /*!< Offset: 0xFF4 (R/ ) Component ID 1 */
126 volatile uint32_t cidr2;
127 /*!< Offset: 0xFF8 (R/ ) Component ID 2 */
128 volatile uint32_t cidr3;
129 /*!< Offset: 0xFFC (R/ ) Component ID 3 */
130 };
131
_set_bus_attribute(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region,uint8_t shift)132 static enum atu_error_t _set_bus_attribute(struct atu_dev_t* dev,
133 enum atu_roba_t val, uint8_t region, uint8_t shift)
134 {
135 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
136
137 if(region >= get_supported_region_count(dev))
138 return ATU_ERR_INVALID_REGION;
139
140 p_atu->aturoba[region] = ((p_atu->aturoba[region] & ~(0x3u << shift)) |
141 (val << shift));
142
143 return ATU_ERR_NONE;
144 }
145
get_page_size(struct atu_dev_t * dev)146 uint16_t get_page_size(struct atu_dev_t* dev)
147 {
148 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
149
150 return (uint16_t)(0x1u << ATU_GET_ATUPS(p_atu));
151 }
152
get_supported_region_count(struct atu_dev_t * dev)153 uint8_t get_supported_region_count(struct atu_dev_t* dev)
154 {
155 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
156
157 return (uint8_t)(0x1u << (p_atu->atubc & ATU_ATUBC_RC_MASK));
158 }
159
enable_atu_region(struct atu_dev_t * dev,uint8_t region)160 enum atu_error_t enable_atu_region(struct atu_dev_t* dev, uint8_t region)
161 {
162 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
163
164 if(region >= get_supported_region_count(dev))
165 return ATU_ERR_INVALID_REGION;
166
167 p_atu->atuc |= (1u << region);
168
169 return ATU_ERR_NONE;
170 }
171
disable_atu_region(struct atu_dev_t * dev,uint8_t region)172 enum atu_error_t disable_atu_region(struct atu_dev_t* dev, uint8_t region)
173 {
174 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
175
176 if(region >= get_supported_region_count(dev))
177 return ATU_ERR_INVALID_REGION;
178
179 p_atu->atuc &= ~(1u << region);
180
181 return ATU_ERR_NONE;
182 }
183
me_interrupt_is_waiting(struct atu_dev_t * dev)184 bool me_interrupt_is_waiting(struct atu_dev_t* dev)
185 {
186 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
187
188 return (bool)(p_atu->atuis & ATU_ATUIS_ME_MASK);
189 }
190
enable_me_interrupt(struct atu_dev_t * dev)191 void enable_me_interrupt(struct atu_dev_t* dev)
192 {
193 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
194
195 p_atu->atuie |= ATU_ATUIE_ME_MASK;
196 }
197
clear_me_interrupt(struct atu_dev_t * dev)198 void clear_me_interrupt(struct atu_dev_t* dev)
199 {
200 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
201
202 p_atu->atuic |= ATU_ATUIC_ME_MASK;
203 }
204
get_mismatch_address(struct atu_dev_t * dev)205 uint32_t get_mismatch_address(struct atu_dev_t* dev)
206 {
207 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
208
209 return p_atu->atuma;
210 }
211
set_start_logical_address(struct atu_dev_t * dev,uint32_t address,uint8_t region)212 enum atu_error_t set_start_logical_address(struct atu_dev_t* dev,
213 uint32_t address, uint8_t region)
214 {
215 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
216
217 uint8_t ps = ATU_GET_ATUPS(p_atu);
218
219 if(region >= get_supported_region_count(dev))
220 return ATU_ERR_INVALID_REGION;
221
222 /* The value stored in this field is the start logical address
223 * right shifted by the value of the PS */
224 p_atu->atursla[region] = (address >> ps);
225
226 return ATU_ERR_NONE;
227 }
228
set_end_logical_address(struct atu_dev_t * dev,uint32_t address,uint8_t region)229 enum atu_error_t set_end_logical_address(struct atu_dev_t* dev,
230 uint32_t address, uint8_t region)
231 {
232 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
233
234 uint8_t ps = ATU_GET_ATUPS(p_atu);
235
236 if(region >= get_supported_region_count(dev))
237 return ATU_ERR_INVALID_REGION;
238
239 /* The end page should be greater than or equal to the start page */
240 if((address >> ps) < p_atu->atursla[region])
241 return ATU_ERR_INVALID_ADDRESS;
242
243 /* The value stored in this field is the start logical address
244 * right shifted by the value of the PS */
245 p_atu->aturela[region] = (address >> ps);
246
247 return ATU_ERR_NONE;
248 }
249
set_add_value(struct atu_dev_t * dev,uint64_t offset_address,uint8_t region)250 enum atu_error_t set_add_value(struct atu_dev_t* dev,
251 uint64_t offset_address, uint8_t region)
252 {
253 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
254
255 if(region >= get_supported_region_count(dev))
256 return ATU_ERR_INVALID_REGION;
257
258 p_atu->aturav_l[region] = (uint32_t)(offset_address);
259
260 p_atu->aturav_m[region] = (uint32_t)(offset_address >> 32);
261
262 return ATU_ERR_NONE;
263 }
264
set_axnsc(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)265 enum atu_error_t set_axnsc(struct atu_dev_t* dev,
266 enum atu_roba_t val, uint8_t region)
267 {
268 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXNSE_OFF);
269 }
270
set_axcache3(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)271 enum atu_error_t set_axcache3(struct atu_dev_t* dev,
272 enum atu_roba_t val, uint8_t region)
273 {
274 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXCACHE3_OFF);
275 }
276
set_axcache2(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)277 enum atu_error_t set_axcache2(struct atu_dev_t* dev,
278 enum atu_roba_t val, uint8_t region)
279 {
280 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXCACHE2_OFF);
281 }
282
set_axcache1(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)283 enum atu_error_t set_axcache1(struct atu_dev_t* dev,
284 enum atu_roba_t val, uint8_t region)
285 {
286 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXCACHE1_OFF);
287 }
288
set_axcache0(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)289 enum atu_error_t set_axcache0(struct atu_dev_t* dev,
290 enum atu_roba_t val, uint8_t region)
291 {
292 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXCACHE0_OFF);
293 }
294
set_axprot2(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)295 enum atu_error_t set_axprot2(struct atu_dev_t* dev,
296 enum atu_roba_t val, uint8_t region)
297 {
298 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXPROT2_OFF);
299 }
300
set_axprot1(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)301 enum atu_error_t set_axprot1(struct atu_dev_t* dev,
302 enum atu_roba_t val, uint8_t region)
303 {
304 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXPROT1_OFF);
305 }
306
set_axprot0(struct atu_dev_t * dev,enum atu_roba_t val,uint8_t region)307 enum atu_error_t set_axprot0(struct atu_dev_t* dev,
308 enum atu_roba_t val, uint8_t region)
309 {
310 return _set_bus_attribute(dev, val, region, ATU_ATUROBA_AXPROT0_OFF);
311 }
312
set_gp_value(struct atu_dev_t * dev,uint8_t val,uint8_t region)313 enum atu_error_t set_gp_value(struct atu_dev_t* dev,
314 uint8_t val, uint8_t region)
315 {
316 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
317
318 if(region >= get_supported_region_count(dev))
319 return ATU_ERR_INVALID_REGION;
320
321 p_atu->aturgp[region] = (uint32_t)val;
322
323 return ATU_ERR_NONE;
324 }
325
get_gp_value(struct atu_dev_t * dev,uint8_t region)326 uint8_t get_gp_value(struct atu_dev_t* dev, uint8_t region)
327 {
328 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
329
330 return (uint8_t)(p_atu->aturgp[region] & 0xFF);
331 }
332
atu_initialize_region(struct atu_dev_t * dev,uint8_t region,uint32_t log_addr,uint64_t phys_addr,uint32_t size)333 enum atu_error_t atu_initialize_region(struct atu_dev_t *dev, uint8_t region,
334 uint32_t log_addr, uint64_t phys_addr,
335 uint32_t size)
336 {
337 enum atu_error_t err;
338 struct _atu_reg_map_t* p_atu = (struct _atu_reg_map_t*)dev->cfg->base;
339
340 uint32_t end_log_addr = log_addr + size - 1;
341 uint8_t ps = ATU_GET_ATUPS(p_atu);
342 uint64_t add_value = (phys_addr - log_addr) >> ps;
343
344 if (dev == NULL) {
345 /* Invalid parameters */
346 return ATU_ERR_INVALID_ARG;
347 }
348
349 err = set_start_logical_address(dev, log_addr, region);
350 if (err != ATU_ERR_NONE) {
351 return err;
352 }
353
354 err = set_end_logical_address(dev, end_log_addr, region);
355 if (err != ATU_ERR_NONE) {
356 return err;
357 }
358
359 err = set_add_value(dev, add_value, region);
360 if (err != ATU_ERR_NONE) {
361 return err;
362 }
363
364 err = enable_atu_region(dev, region);
365 if (err != ATU_ERR_NONE) {
366 return err;
367 }
368
369 return ATU_ERR_NONE;
370 }
371
atu_uninitialize_region(struct atu_dev_t * dev,uint8_t region)372 enum atu_error_t atu_uninitialize_region(struct atu_dev_t *dev, uint8_t region)
373 {
374 enum atu_error_t err;
375
376 if (dev == NULL) {
377 /* Invalid parameters */
378 return ATU_ERR_INVALID_ARG;
379 }
380
381 err = disable_atu_region(dev, region);
382 if (err != ATU_ERR_NONE) {
383 return err;
384 }
385
386 return ATU_ERR_NONE;
387 }
388