1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "low_level_access.h"
9 #include "synquacer_mmap.h"
10
11 #include <internal/reset.h>
12 #include <internal/sysoc.h>
13
14 #include <mod_synquacer_system.h>
15
16 #include <fwk_assert.h>
17 #include <fwk_log.h>
18 #include <fwk_macros.h>
19 #include <fwk_status.h>
20
21 #include <inttypes.h>
22 #include <stdbool.h>
23 #include <stddef.h>
24 #include <stdint.h>
25
26 #define MAIN_BUS_RESET_BIT (0x1)
27
28 #define REG_ADDR_RSTSTA (0)
29 #define REG_ADDR_RSTSET (0x4U)
30 #define REG_ADDR_RSTCLR (0x8U)
31
32 #define SYSOC_WAIT_TIME_MS 1U
33 #define SYSOC_WAIT_NUM 500
34
35 #define SYSOC_OFFSET_RESET_STATUS (0)
36 #define SYSOC_OFFSET_RESET (4)
37 #define SYSOC_OFFSET_RESET_CLEAR (8)
38
39 #define LPCM_OFFSET_CONTROL (0)
40 #define LPCM_OFFSET_MON (4)
41
42 #define LPCM_OFFSET_NUM (8)
43
44 static const struct {
45 uint32_t block_sysoc;
46 uint32_t block_lpcm;
47 uint32_t bus_sysoc;
48 uint32_t bus_lpcm;
49 uint32_t addr_sysoc_blk;
50 uint32_t addr_sysoc_bus;
51 uint32_t addr_lpcm;
52 } reset_info[] = RESET_INFO;
53
sysoc_set_reset(uint32_t sysoc_addr,uint32_t value)54 void sysoc_set_reset(uint32_t sysoc_addr, uint32_t value)
55 {
56 if ((void *)sysoc_addr == NULL)
57 return;
58
59 writel((sysoc_addr + REG_ADDR_RSTSET), value);
60 }
61
sysoc_clr_reset(uint32_t sysoc_addr,uint32_t value)62 void sysoc_clr_reset(uint32_t sysoc_addr, uint32_t value)
63 {
64 if ((void *)sysoc_addr == NULL)
65 return;
66
67 writel((sysoc_addr + REG_ADDR_RSTCLR), value);
68 }
69
sysoc_read_reset_status(uint32_t sysoc_addr)70 uint32_t sysoc_read_reset_status(uint32_t sysoc_addr)
71 {
72 if ((void *)sysoc_addr == NULL)
73 return 0;
74
75 return readl(sysoc_addr + REG_ADDR_RSTSTA);
76 }
77
sysoc_wait_status_change(uint32_t sysoc_addr,bool reset_set_flag,uint32_t set_bit)78 int sysoc_wait_status_change(
79 uint32_t sysoc_addr,
80 bool reset_set_flag,
81 uint32_t set_bit)
82 {
83 uint32_t i;
84 uint32_t wait_bit;
85 int ret;
86
87 if ((void *)sysoc_addr == NULL)
88 return FWK_E_PARAM;
89
90 if (reset_set_flag)
91 wait_bit = set_bit;
92 else
93 wait_bit = 0;
94
95 /* wait ppu power status change */
96 for (i = 0, ret = FWK_E_TIMEOUT; i < SYSOC_WAIT_NUM; i++) {
97 int status;
98
99 if ((readl(sysoc_addr + REG_ADDR_RSTSTA) & set_bit) == wait_bit) {
100 ret = FWK_SUCCESS;
101 break;
102 }
103 /* sleep for wait status change */
104 status = synquacer_system_ctx.timer_api->delay(
105 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
106 MSEC_TO_USEC(SYSOC_WAIT_TIME_MS));
107 if (status != FWK_SUCCESS) {
108 /* sleep error */
109 return status;
110 }
111 }
112 return ret;
113 }
114
sysoc_reset(uint32_t addr_head,uint32_t bitmap)115 static void sysoc_reset(uint32_t addr_head, uint32_t bitmap)
116 {
117 writel(addr_head + SYSOC_OFFSET_RESET, bitmap);
118 }
119
sysoc_reset_clear(uint32_t addr_head,uint32_t bitmap)120 static void sysoc_reset_clear(uint32_t addr_head, uint32_t bitmap)
121 {
122 writel(addr_head + SYSOC_OFFSET_RESET_CLEAR, bitmap);
123 }
124
lpcm_reset(uint32_t addr_head,uint32_t bitmap)125 static void lpcm_reset(uint32_t addr_head, uint32_t bitmap)
126 {
127 int i;
128
129 for (i = 0; i < LPCM_OFFSET_NUM; i++) {
130 if ((bitmap & 1) == 1)
131 writel(addr_head + (i * 8), 0);
132
133 bitmap >>= 1;
134 }
135 }
136
lpcm_reset_clear(uint32_t addr_head,uint32_t bitmap)137 static void lpcm_reset_clear(uint32_t addr_head, uint32_t bitmap)
138 {
139 int i;
140
141 for (i = 0; i < LPCM_OFFSET_NUM; i++) {
142 if ((bitmap & 1) == 1)
143 writel(addr_head + (i * 8), 1);
144
145 bitmap >>= 1;
146 }
147 }
148
sysoc_reset_status(uint32_t addr_head,uint32_t bitmap)149 static uint32_t sysoc_reset_status(uint32_t addr_head, uint32_t bitmap)
150 {
151 return readl(addr_head + SYSOC_OFFSET_RESET_STATUS) & bitmap;
152 }
153
lpcm_reset_status(uint32_t addr_head,uint32_t bitmap)154 static uint32_t lpcm_reset_status(uint32_t addr_head, uint32_t bitmap)
155 {
156 int i, status_bitmap, b;
157 status_bitmap = 0;
158
159 for (i = 0; i < LPCM_OFFSET_NUM; i++) {
160 if ((bitmap & 1) == 1) {
161 b = readl(addr_head + (i * 8) + LPCM_OFFSET_MON) & 1;
162 status_bitmap |= b << i;
163 }
164 bitmap >>= 1;
165 }
166 return status_bitmap;
167 }
168
169 #define RESET_TIMEOUT_MS 100
170 #define RESET_CHECK_CYCLE_MS 1
171
lpcm_sysoc_reset(RST_TYPE_t type,RST_BLOCK block)172 void lpcm_sysoc_reset(RST_TYPE_t type, RST_BLOCK block)
173 {
174 uint32_t lpcm_bitmap, sysoc_bitmap_blk, sysoc_bitmap_bus;
175 uint32_t status_check_num, i, r;
176
177 lpcm_bitmap = 0;
178 sysoc_bitmap_blk = 0;
179 sysoc_bitmap_bus = 0;
180
181 status_check_num = (RESET_TIMEOUT_MS / RESET_CHECK_CYCLE_MS);
182
183 if (type != RST_TYPE_BUS) {
184 sysoc_bitmap_blk |= reset_info[block].block_sysoc;
185 lpcm_bitmap |= reset_info[block].block_lpcm;
186 }
187 if (type != RST_TYPE_WO_BUS) {
188 sysoc_bitmap_bus |= reset_info[block].bus_sysoc;
189 lpcm_bitmap |= reset_info[block].bus_lpcm;
190 }
191
192 if (lpcm_bitmap != 0)
193 lpcm_reset(reset_info[block].addr_lpcm, lpcm_bitmap);
194
195 if (sysoc_bitmap_bus != 0)
196 sysoc_reset(reset_info[block].addr_sysoc_bus, sysoc_bitmap_bus);
197
198 if (sysoc_bitmap_blk != 0)
199 sysoc_reset(reset_info[block].addr_sysoc_blk, sysoc_bitmap_blk);
200
201 if (lpcm_bitmap != 0) {
202 for (i = 0; i < status_check_num; i++) {
203 r = lpcm_reset_status(reset_info[block].addr_lpcm, lpcm_bitmap);
204 if (r == 0)
205 break;
206
207 synquacer_system_ctx.timer_api->delay(
208 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
209 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
210 }
211 if (i == status_check_num) {
212 FWK_LOG_ERR(
213 "[LPCM] Reset timeout.(%dms, %08" PRIx32 ")",
214 RESET_TIMEOUT_MS,
215 reset_info[block].addr_lpcm);
216 }
217 }
218
219 if (sysoc_bitmap_bus != 0) {
220 for (i = 0; i < status_check_num; i++) {
221 r = sysoc_reset_status(
222 reset_info[block].addr_sysoc_bus, sysoc_bitmap_bus);
223 if (r == sysoc_bitmap_bus)
224 break;
225
226 synquacer_system_ctx.timer_api->delay(
227 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
228 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
229 }
230 if (i == status_check_num) {
231 FWK_LOG_ERR(
232 "[SYSOC] Reset timeout.(%dms, %08" PRIx32 ")",
233 RESET_TIMEOUT_MS,
234 reset_info[block].addr_sysoc_bus);
235 }
236 }
237
238 if (sysoc_bitmap_blk != 0) {
239 for (i = 0; i < status_check_num; i++) {
240 r = sysoc_reset_status(
241 reset_info[block].addr_sysoc_blk, sysoc_bitmap_blk);
242 if (r == sysoc_bitmap_blk)
243 break;
244
245 synquacer_system_ctx.timer_api->delay(
246 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
247 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
248 }
249 if (i == status_check_num) {
250 FWK_LOG_ERR(
251 "[SYSOC] Reset timeout.(%dms, %08" PRIx32 ")",
252 RESET_TIMEOUT_MS,
253 reset_info[block].addr_sysoc_blk);
254 }
255 }
256 }
257
lpcm_sysoc_reset_clear(RST_TYPE_t type,RST_BLOCK block)258 void lpcm_sysoc_reset_clear(RST_TYPE_t type, RST_BLOCK block)
259 {
260 uint32_t lpcm_bitmap, sysoc_bitmap_blk, sysoc_bitmap_bus;
261 uint32_t status_check_num, i, r;
262
263 lpcm_bitmap = 0;
264 sysoc_bitmap_blk = 0;
265 sysoc_bitmap_bus = 0;
266
267 status_check_num = (RESET_TIMEOUT_MS / RESET_CHECK_CYCLE_MS);
268
269 if (type != RST_TYPE_BUS) {
270 sysoc_bitmap_blk |= reset_info[block].block_sysoc;
271 lpcm_bitmap |= reset_info[block].block_lpcm;
272 }
273 if (type != RST_TYPE_WO_BUS) {
274 sysoc_bitmap_bus |= reset_info[block].bus_sysoc;
275 lpcm_bitmap |= reset_info[block].bus_lpcm;
276 }
277
278 if (sysoc_bitmap_blk != 0)
279 sysoc_reset_clear(reset_info[block].addr_sysoc_blk, sysoc_bitmap_blk);
280
281 if (sysoc_bitmap_bus != 0)
282 sysoc_reset_clear(reset_info[block].addr_sysoc_bus, sysoc_bitmap_bus);
283
284 if (lpcm_bitmap != 0)
285 lpcm_reset_clear(reset_info[block].addr_lpcm, lpcm_bitmap);
286
287 if (sysoc_bitmap_blk != 0) {
288 for (i = 0; i < status_check_num; i++) {
289 r = sysoc_reset_status(
290 reset_info[block].addr_sysoc_blk, sysoc_bitmap_blk);
291 if (r == 0)
292 break;
293
294 synquacer_system_ctx.timer_api->delay(
295 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
296 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
297 }
298 if (i == status_check_num) {
299 FWK_LOG_ERR(
300 "[SYSOC] Reset clear timeout.(%dms, %08" PRIx32 ")",
301 RESET_TIMEOUT_MS,
302 reset_info[block].addr_sysoc_blk);
303 }
304 }
305
306 if (sysoc_bitmap_bus != 0) {
307 for (i = 0; i < status_check_num; i++) {
308 r = sysoc_reset_status(
309 reset_info[block].addr_sysoc_bus, sysoc_bitmap_bus);
310 if (r == 0)
311 break;
312
313 synquacer_system_ctx.timer_api->delay(
314 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
315 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
316 }
317 if (i == status_check_num) {
318 FWK_LOG_ERR(
319 "[SYSOC] Reset clear timeout.(%dms, %08" PRIx32 ")",
320 RESET_TIMEOUT_MS,
321 reset_info[block].addr_sysoc_bus);
322 }
323 }
324
325 if (lpcm_bitmap != 0) {
326 for (i = 0; i < status_check_num; i++) {
327 r = lpcm_reset_status(reset_info[block].addr_lpcm, lpcm_bitmap);
328 if (r == lpcm_bitmap)
329 break;
330
331 synquacer_system_ctx.timer_api->delay(
332 FWK_ID_ELEMENT(FWK_MODULE_IDX_TIMER, 0),
333 MSEC_TO_USEC(RESET_CHECK_CYCLE_MS));
334 }
335 if (i == status_check_num) {
336 FWK_LOG_ERR(
337 "[LPCM] Reset clear timeout.(%dms, %08" PRIx32 ")",
338 RESET_TIMEOUT_MS,
339 reset_info[block].addr_lpcm);
340 }
341 }
342 }
343
bus_sysoc_init(void)344 void bus_sysoc_init(void)
345 {
346 int result;
347 uint32_t value;
348
349 (void)result;
350
351 value = sysoc_read_reset_status(CONFIG_SOC_REG_ADDR_SYSOC_BUS_TOP);
352 if (value == 0)
353 return; /* reset bit not active */
354
355 /* reset set only active bit */
356 sysoc_clr_reset(
357 CONFIG_SOC_REG_ADDR_SYSOC_BUS_TOP, (MAIN_BUS_RESET_BIT & value));
358 result = sysoc_wait_status_change(
359 CONFIG_SOC_REG_ADDR_SYSOC_BUS_TOP, false, MAIN_BUS_RESET_BIT);
360
361 fwk_assert(result == FWK_SUCCESS);
362 }
363
364 #define CONFIG_SOC_PCIEB_SYSOC_REG_BASE UINT32_C(0x78240000)
365
366 /* configure PCIEB SYSOC as secure */
pcie_wrapper_configure_pcieb_sysoc(void)367 void pcie_wrapper_configure_pcieb_sysoc(void)
368 {
369 const struct {
370 uint32_t offset;
371 uint32_t value;
372 } pcieb_sysoc_config[] = {
373 { 0x00, 0 }, /* CFG_CTTW */
374 { 0x04, 0 }, /* CFG_NORMALIZE */
375 { 0x08, 0 }, /* INTEG_SEC_OVERRIDE */
376 { 0x0C, 0 }, /* SYSBARDISABLE_TBU */
377 { 0x10, 0 }, /* WSB_NS */
378 { 0x14, 0 }, /* RSB_NS */
379 { 0x18, 0 }, /* AWDOMAIN */
380 { 0x1C, 0 } /* ARDOMAIN */
381 };
382
383 size_t i;
384
385 for (i = 0; i < FWK_ARRAY_SIZE(pcieb_sysoc_config); i++) {
386 writel(
387 CONFIG_SOC_PCIEB_SYSOC_REG_BASE + pcieb_sysoc_config[i].offset,
388 pcieb_sysoc_config[i].value);
389 }
390 }
391
pcie_wrapper_tweak_slv_axmisc_info_tph(uint32_t tweak)392 void pcie_wrapper_tweak_slv_axmisc_info_tph(uint32_t tweak)
393 {
394 writel(0x7FFF0080, tweak);
395 }
396
pcie_wrapper_configure(void)397 void pcie_wrapper_configure(void)
398 {
399 pcie_wrapper_configure_pcieb_sysoc();
400 pcie_wrapper_tweak_slv_axmisc_info_tph(
401 CONFIG_SCB_TWEAK_PCIE_TLP_BE_OVERRIDE);
402 }
403