1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2019-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "juno_ppu_idx.h"
9 #include "juno_utils.h"
10 #include "juno_wdog_rom.h"
11 #include "scp_config.h"
12 
13 #include <mod_juno_ppu.h>
14 #include <mod_power_domain.h>
15 
16 #include <fwk_assert.h>
17 #include <fwk_id.h>
18 #include <fwk_interrupt.h>
19 #include <fwk_module_idx.h>
20 #include <fwk_status.h>
21 
22 #include <fmw_cmsis.h>
23 
24 #include <stdbool.h>
25 #include <stdint.h>
26 
27 /* Platform default dividers for debug clocks */
28 #define JUNO_DEBUG_ROM_DIVIDER_ATCLK        16
29 #define JUNO_DEBUG_ROM_DIVIDER_TRACECLK     16
30 #define JUNO_DEBUG_ROM_DIVIDER_PCLK         16
31 
32 const struct mod_juno_ppu_rom_api *ppu_api;
33 
34 static const fwk_id_t dbgsys_ppu_id =
35     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_JUNO_PPU, JUNO_PPU_DEV_IDX_DBGSYS);
36 
37 static const fwk_id_t big_sstop_ppu_id =
38     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_JUNO_PPU, JUNO_PPU_DEV_IDX_BIG_SSTOP);
39 
40 static const fwk_id_t little_sstop_ppu_id =
41     FWK_ID_ELEMENT_INIT(FWK_MODULE_IDX_JUNO_PPU, JUNO_PPU_DEV_IDX_LITTLE_SSTOP);
42 
43 static const uint32_t debug_clk_mask = (SCP_CONFIG_CLOCK_ENABLE_PCLKDBGEN |
44                                         SCP_CONFIG_CLOCK_ENABLE_TRACECLKINEN |
45                                         SCP_CONFIG_CLOCK_ENABLE_ATCLKEN);
46 
47 /*
48  * Static helpers
49  */
50 
juno_debug_rom_set_clocks(void)51 static void juno_debug_rom_set_clocks(void)
52 {
53     /*
54      * Setup ATCLK
55      */
56     juno_utils_atclk_clock_div_set(JUNO_DEBUG_ROM_DIVIDER_ATCLK);
57     while (
58         !juno_utils_atclk_clock_div_set_check(JUNO_DEBUG_ROM_DIVIDER_ATCLK)) {
59         continue;
60     }
61 
62     juno_utils_atclk_clock_sel_set(SCP_CONFIG_STDCLK_CONTROL_CLKSEL_SYSINCLK);
63     while (!juno_utils_atclk_clock_sel_set_check(
64         SCP_CONFIG_STDCLK_CONTROL_CLKSEL_SYSINCLK)) {
65         continue;
66     }
67 
68     /*
69      * Setup TRACECLKIN
70      */
71     juno_utils_traceclk_clock_div_set(JUNO_DEBUG_ROM_DIVIDER_TRACECLK);
72     while (!juno_utils_traceclk_clock_div_set_check(
73         JUNO_DEBUG_ROM_DIVIDER_TRACECLK)) {
74         continue;
75     }
76 
77     juno_utils_traceclk_clock_sel_set(
78         SCP_CONFIG_STDCLK_CONTROL_CLKSEL_SYSINCLK);
79     while (!juno_utils_traceclk_clock_sel_set_check(
80         SCP_CONFIG_STDCLK_CONTROL_CLKSEL_SYSINCLK)) {
81         continue;
82     }
83 
84     /*
85      * Setup PCLKDBG
86      */
87     juno_utils_pclkdbg_clock_div_set(JUNO_DEBUG_ROM_DIVIDER_PCLK);
88     while (
89         !juno_utils_pclkdbg_clock_div_set_check(JUNO_DEBUG_ROM_DIVIDER_PCLK)) {
90         continue;
91     }
92 }
93 
94 /*
95  * Interrupt service routines
96  */
97 
juno_debug_cdbg_pwr_up_req_isr(void)98 static void juno_debug_cdbg_pwr_up_req_isr(void)
99 {
100     int status;
101 
102     #ifndef BUILD_MODE_DEBUG
103     juno_wdog_rom_reload();
104     #endif
105 
106     if (SCP_CONFIG->DEBUG_STATUS & SCP_CONFIG_DEBUG_STATUS_CDBGPWRUPREQ) {
107         #ifndef BUILD_MODE_DEBUG
108         juno_wdog_rom_halt_on_debug_enable(true);
109         #endif
110 
111         juno_utils_system_clock_enable(debug_clk_mask);
112 
113         /* Turn on DBGSYS */
114         status = ppu_api->set_state_and_wait(dbgsys_ppu_id, MOD_PD_STATE_ON);
115         fwk_assert(status == FWK_SUCCESS);
116 
117         status = ppu_api->set_state_and_wait(big_sstop_ppu_id, MOD_PD_STATE_ON);
118         fwk_assert(status == FWK_SUCCESS);
119 
120         status =
121             ppu_api->set_state_and_wait(little_sstop_ppu_id, MOD_PD_STATE_ON);
122         fwk_assert(status == FWK_SUCCESS);
123 
124         juno_debug_rom_set_clocks();
125 
126         SCP_CONFIG->SYS_MANUAL_RESET.SET =
127             SCP_CONFIG_SYS_MANUAL_RESET_DBGSYSRESET;
128         SCP_CONFIG->SYS_MANUAL_RESET.CLEAR =
129             SCP_CONFIG_SYS_MANUAL_RESET_DBGSYSRESET;
130 
131         /* Acknowledge end of debug power up */
132         SCP_CONFIG->DEBUG_CONTROL |= SCP_CONFIG_DEBUG_CONTROL_CDBGPWRUPACK;
133 
134     } else {
135         status = ppu_api->set_state_and_wait(dbgsys_ppu_id, MOD_PD_STATE_OFF);
136         fwk_assert(status == FWK_SUCCESS);
137 
138         SCP_CONFIG->DEBUG_CONTROL &= ~SCP_CONFIG_DEBUG_CONTROL_CDBGPWRUPACK;
139 
140         #ifndef BUILD_MODE_DEBUG
141         juno_wdog_rom_halt_on_debug_enable(false);
142         #endif
143     }
144 }
145 
juno_debug_csys_pwr_up_req_isr(void)146 static void juno_debug_csys_pwr_up_req_isr(void)
147 {
148     int status;
149 
150     #ifndef BUILD_MODE_DEBUG
151     juno_wdog_rom_reload();
152     #endif
153 
154     if (SCP_CONFIG->DEBUG_STATUS & SCP_CONFIG_DEBUG_STATUS_CSYSPWRUPREQ) {
155         juno_utils_system_clock_enable(debug_clk_mask);
156 
157         status = ppu_api->set_state_and_wait(dbgsys_ppu_id, MOD_PD_STATE_ON);
158         fwk_assert(status == FWK_SUCCESS);
159 
160         juno_debug_rom_set_clocks();
161 
162         SCP_CONFIG->DEBUG_CONTROL |= SCP_CONFIG_DEBUG_CONTROL_CSYSPWRUPACK;
163     } else {
164         status = ppu_api->set_state_and_wait(dbgsys_ppu_id, MOD_PD_STATE_OFF);
165         fwk_assert(status == FWK_SUCCESS);
166 
167         SCP_CONFIG->DEBUG_CONTROL &= ~SCP_CONFIG_DEBUG_CONTROL_CSYSPWRUPACK;
168     }
169 }
170 
juno_debug_cdbg_rst_req_isr(void)171 static void juno_debug_cdbg_rst_req_isr(void)
172 {
173     #ifndef BUILD_MODE_DEBUG
174     juno_wdog_rom_reload();
175     #endif
176 
177     /* Reset debug system */
178     SCP_CONFIG->SYS_MANUAL_RESET.SET = SCP_CONFIG_SYS_MANUAL_RESET_DBGSYSRESET;
179 
180     /* Acknowledge request */
181     SCP_CONFIG->DEBUG_CONTROL |= SCP_CONFIG_DEBUG_CONTROL_CDBGRSTACK;
182 
183     /* Wait for CoreSight to de-assert request */
184     while ((SCP_CONFIG->DEBUG_STATUS & SCP_CONFIG_DEBUG_STATUS_CDBGRSTREQ) ==
185            SCP_CONFIG_DEBUG_STATUS_CDBGRSTREQ) {
186         continue;
187     }
188 
189     /* De-assert reset */
190     SCP_CONFIG->SYS_MANUAL_RESET.SET = SCP_CONFIG_SYS_MANUAL_RESET_DBGSYSRESET;
191 
192     /* De-assert ACK */
193     SCP_CONFIG->DEBUG_CONTROL &= ~SCP_CONFIG_DEBUG_CONTROL_CDBGRSTACK;
194 }
195 
196 /*
197  * Public interface
198  */
199 
juno_debug_rom_init(const struct mod_juno_ppu_rom_api * rom_ppu_api)200 int juno_debug_rom_init(const struct mod_juno_ppu_rom_api *rom_ppu_api)
201 {
202     int status;
203     ppu_api = rom_ppu_api;
204 
205     /*
206      * IRQs are not yet enabled but there may be a pending debug power-up
207      * request that was raised before SCP was released from reset
208      */
209     if (SCP_CONFIG->DEBUG_STATUS & SCP_CONFIG_DEBUG_STATUS_CDBGPWRUPREQ) {
210         juno_debug_cdbg_pwr_up_req_isr();
211 
212         fwk_assert((SCP_CONFIG->DEBUG_CONTROL &
213             SCP_CONFIG_DEBUG_CONTROL_CDBGPWRUPACK) != 0);
214     }
215 
216     status = fwk_interrupt_clear_pending((unsigned int)CDBG_PWR_UP_REQ_IRQ);
217     if (status != FWK_SUCCESS) {
218         return status;
219     }
220 
221     status = fwk_interrupt_clear_pending((unsigned int)CDBG_RST_REQ_IRQ);
222     if (status != FWK_SUCCESS) {
223         return status;
224     }
225 
226     status = fwk_interrupt_clear_pending((unsigned int)CSYS_PWR_UP_REQ_IRQ);
227     if (status != FWK_SUCCESS) {
228         return status;
229     }
230 
231     status = fwk_interrupt_set_isr(
232         (unsigned int)CDBG_PWR_UP_REQ_IRQ, juno_debug_cdbg_pwr_up_req_isr);
233     if (status != FWK_SUCCESS) {
234         return status;
235     }
236 
237     status = fwk_interrupt_set_isr(
238         (unsigned int)CSYS_PWR_UP_REQ_IRQ, juno_debug_csys_pwr_up_req_isr);
239     if (status != FWK_SUCCESS) {
240         return status;
241     }
242 
243     status = fwk_interrupt_set_isr(
244         (unsigned int)CDBG_RST_REQ_IRQ, juno_debug_cdbg_rst_req_isr);
245     if (status != FWK_SUCCESS) {
246         return status;
247     }
248 
249     status = fwk_interrupt_enable((unsigned int)CDBG_PWR_UP_REQ_IRQ);
250     if (status != FWK_SUCCESS) {
251         return status;
252     }
253 
254     status = fwk_interrupt_enable((unsigned int)CDBG_RST_REQ_IRQ);
255     if (status != FWK_SUCCESS) {
256         return status;
257     }
258 
259     status = fwk_interrupt_enable((unsigned int)CSYS_PWR_UP_REQ_IRQ);
260     if (status != FWK_SUCCESS) {
261         return status;
262     }
263 
264     return FWK_SUCCESS;
265 }
266