1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/cache.h>
8 #include <zephyr/devicetree.h>
9 #include <zephyr/init.h>
10 #include <zephyr/kernel.h>
11 #include <zephyr/logging/log.h>
12
13 #ifdef CONFIG_LOG_FRONTEND_STMESP
14 #include <zephyr/logging/log_frontend_stmesp.h>
15 #endif
16
17 #include <hal/nrf_hsfll.h>
18 #include <hal/nrf_lrcconf.h>
19 #include <hal/nrf_spu.h>
20 #include <hal/nrf_memconf.h>
21 #include <soc/nrfx_coredep.h>
22 #include <soc_lrcconf.h>
23 #include <dmm.h>
24
25 LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
26
27 #if defined(NRF_APPLICATION)
28 #define HSFLL_NODE DT_NODELABEL(cpuapp_hsfll)
29 #elif defined(NRF_RADIOCORE)
30 #define HSFLL_NODE DT_NODELABEL(cpurad_hsfll)
31 #endif
32
33 sys_snode_t soc_node;
34
35 #define FICR_ADDR_GET(node_id, name) \
36 DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) + \
37 DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset)
38
39 #define SPU_INSTANCE_GET(p_addr) \
40 ((NRF_SPU_Type *)((p_addr) & (ADDRESS_REGION_Msk | \
41 ADDRESS_SECURITY_Msk | \
42 ADDRESS_DOMAIN_Msk | \
43 ADDRESS_BUS_Msk)))
44
power_domain_init(void)45 static void power_domain_init(void)
46 {
47 /*
48 * Set:
49 * - LRCCONF010.POWERON.MAIN: 1
50 * - LRCCONF010.POWERON.ACT: 1
51 * - LRCCONF010.RETAIN.MAIN: 1
52 * - LRCCONF010.RETAIN.ACT: 1
53 *
54 * This is done here at boot so that when the idle routine will hit
55 * WFI the power domain will be correctly retained.
56 */
57
58 soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0);
59 nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false);
60
61 nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_ICACHE, false);
62 nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_BIT_DCACHE, false);
63 nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_BIT_ICACHE, false);
64 nrf_memconf_ramblock_ret_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_BIT_DCACHE, false);
65 #if defined(RAMBLOCK_RET2_BIT_ICACHE)
66 nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET2_BIT_ICACHE, false);
67 nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET2_BIT_ICACHE, false);
68 #endif
69 #if defined(RAMBLOCK_RET2_BIT_DCACHE)
70 nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET2_BIT_DCACHE, false);
71 nrf_memconf_ramblock_ret2_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET2_BIT_DCACHE, false);
72 #endif
73 nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 0, RAMBLOCK_RET_MASK, true);
74 nrf_memconf_ramblock_ret_mask_enable_set(NRF_MEMCONF, 1, RAMBLOCK_RET_MASK, true);
75 #if defined(RAMBLOCK_RET2_MASK)
76 /*
77 * TODO: Use nrf_memconf_ramblock_ret2_mask_enable_set() function
78 * when will be provided by HAL.
79 */
80 NRF_MEMCONF->POWER[0].RET2 = RAMBLOCK_RET2_MASK;
81 NRF_MEMCONF->POWER[1].RET2 = RAMBLOCK_RET2_MASK;
82 #endif
83 }
84
trim_hsfll(void)85 static int trim_hsfll(void)
86 {
87 #if defined(HSFLL_NODE)
88
89 NRF_HSFLL_Type *hsfll = (NRF_HSFLL_Type *)DT_REG_ADDR(HSFLL_NODE);
90 nrf_hsfll_trim_t trim = {
91 .vsup = sys_read32(FICR_ADDR_GET(HSFLL_NODE, vsup)),
92 .coarse = sys_read32(FICR_ADDR_GET(HSFLL_NODE, coarse)),
93 .fine = sys_read32(FICR_ADDR_GET(HSFLL_NODE, fine))
94 };
95
96 LOG_DBG("Trim: HSFLL VSUP: 0x%.8x", trim.vsup);
97 LOG_DBG("Trim: HSFLL COARSE: 0x%.8x", trim.coarse);
98 LOG_DBG("Trim: HSFLL FINE: 0x%.8x", trim.fine);
99
100 nrf_hsfll_clkctrl_mult_set(hsfll,
101 DT_PROP(HSFLL_NODE, clock_frequency) /
102 DT_PROP(DT_CLOCKS_CTLR(HSFLL_NODE), clock_frequency));
103 nrf_hsfll_trim_set(hsfll, &trim);
104
105 nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE);
106 /* HSFLL task frequency change needs to be triggered twice to take effect.*/
107 nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE);
108
109 LOG_DBG("NRF_HSFLL->TRIM.VSUP = %d", hsfll->TRIM.VSUP);
110 LOG_DBG("NRF_HSFLL->TRIM.COARSE = %d", hsfll->TRIM.COARSE);
111 LOG_DBG("NRF_HSFLL->TRIM.FINE = %d", hsfll->TRIM.FINE);
112
113 #endif /* defined(HSFLL_NODE) */
114
115 return 0;
116 }
117
118 #if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK)
z_arm_on_enter_cpu_idle(void)119 bool z_arm_on_enter_cpu_idle(void)
120 {
121 #ifdef CONFIG_LOG_FRONTEND_STMESP
122 log_frontend_stmesp_pre_sleep();
123 #endif
124 return true;
125 }
126 #endif
127
nordicsemi_nrf54h_init(void)128 static int nordicsemi_nrf54h_init(void)
129 {
130 int err;
131
132 sys_cache_instr_enable();
133 sys_cache_data_enable();
134
135 power_domain_init();
136
137 trim_hsfll();
138
139 err = dmm_init();
140 if (err < 0) {
141 return err;
142 }
143
144 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ccm030))
145 /* DMASEC is set to non-secure by default, which prevents CCM from
146 * accessing secure memory. Change DMASEC to secure.
147 */
148 uint32_t ccm030_addr = DT_REG_ADDR(DT_NODELABEL(ccm030));
149 NRF_SPU_Type *spu = SPU_INSTANCE_GET(ccm030_addr);
150
151 nrf_spu_periph_perm_dmasec_set(spu, nrf_address_slave_get(ccm030_addr), true);
152 #endif
153
154 return 0;
155 }
156
arch_busy_wait(uint32_t time_us)157 void arch_busy_wait(uint32_t time_us)
158 {
159 nrfx_coredep_delay_us(time_us);
160 }
161
162 SYS_INIT(nordicsemi_nrf54h_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
163