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