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