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 #include <hal/nrf_hsfll.h>
14 #include <hal/nrf_lrcconf.h>
15 #include <hal/nrf_spu.h>
16 #include <soc/nrfx_coredep.h>
17 
18 LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL);
19 
20 #if defined(NRF_APPLICATION)
21 #define HSFLL_NODE DT_NODELABEL(cpuapp_hsfll)
22 #elif defined(NRF_RADIOCORE)
23 #define HSFLL_NODE DT_NODELABEL(cpurad_hsfll)
24 #endif
25 
26 #define FICR_ADDR_GET(node_id, name)                                           \
27 	DT_REG_ADDR(DT_PHANDLE_BY_NAME(node_id, nordic_ficrs, name)) +         \
28 		DT_PHA_BY_NAME(node_id, nordic_ficrs, name, offset)
29 
30 #define SPU_INSTANCE_GET(p_addr)                                               \
31 	((NRF_SPU_Type *)((p_addr) & (ADDRESS_REGION_Msk |                     \
32 				      ADDRESS_SECURITY_Msk |                   \
33 				      ADDRESS_DOMAIN_Msk |                     \
34 				      ADDRESS_BUS_Msk)))
35 
power_domain_init(void)36 static void power_domain_init(void)
37 {
38 	/*
39 	 * Set:
40 	 *  - LRCCONF010.POWERON.MAIN: 1
41 	 *  - LRCCONF010.POWERON.ACT: 1
42 	 *  - LRCCONF010.RETAIN.MAIN: 1
43 	 *  - LRCCONF010.RETAIN.ACT: 1
44 	 *
45 	 *  This is done here at boot so that when the idle routine will hit
46 	 *  WFI the power domain will be correctly retained.
47 	 */
48 
49 	nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true);
50 	nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true);
51 
52 	nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, true);
53 	nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true);
54 }
55 
trim_hsfll(void)56 static int trim_hsfll(void)
57 {
58 #if defined(HSFLL_NODE)
59 
60 	NRF_HSFLL_Type *hsfll = (NRF_HSFLL_Type *)DT_REG_ADDR(HSFLL_NODE);
61 	nrf_hsfll_trim_t trim = {
62 		.vsup = sys_read32(FICR_ADDR_GET(HSFLL_NODE, vsup)),
63 		.coarse = sys_read32(FICR_ADDR_GET(HSFLL_NODE, coarse)),
64 		.fine = sys_read32(FICR_ADDR_GET(HSFLL_NODE, fine))
65 	};
66 
67 	LOG_DBG("Trim: HSFLL VSUP: 0x%.8x", trim.vsup);
68 	LOG_DBG("Trim: HSFLL COARSE: 0x%.8x", trim.coarse);
69 	LOG_DBG("Trim: HSFLL FINE: 0x%.8x", trim.fine);
70 
71 	nrf_hsfll_clkctrl_mult_set(hsfll,
72 				   DT_PROP(HSFLL_NODE, clock_frequency) /
73 					   DT_PROP(DT_CLOCKS_CTLR(HSFLL_NODE), clock_frequency));
74 	nrf_hsfll_trim_set(hsfll, &trim);
75 
76 	nrf_hsfll_task_trigger(hsfll, NRF_HSFLL_TASK_FREQ_CHANGE);
77 
78 	LOG_DBG("NRF_HSFLL->TRIM.VSUP = %d", hsfll->TRIM.VSUP);
79 	LOG_DBG("NRF_HSFLL->TRIM.COARSE = %d", hsfll->TRIM.COARSE);
80 	LOG_DBG("NRF_HSFLL->TRIM.FINE = %d", hsfll->TRIM.FINE);
81 
82 #endif /* defined(HSFLL_NODE) */
83 
84 	return 0;
85 }
86 
nordicsemi_nrf92_init(void)87 static int nordicsemi_nrf92_init(void)
88 {
89 	sys_cache_instr_enable();
90 	sys_cache_data_enable();
91 
92 	power_domain_init();
93 
94 	trim_hsfll();
95 
96 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(ccm030))
97 	/* DMASEC is set to non-secure by default, which prevents CCM from
98 	 * accessing secure memory. Change DMASEC to secure.
99 	 */
100 	uint32_t ccm030_addr = DT_REG_ADDR(DT_NODELABEL(ccm030));
101 	NRF_SPU_Type *spu = SPU_INSTANCE_GET(ccm030_addr);
102 
103 	nrf_spu_periph_perm_dmasec_set(spu, nrf_address_slave_get(ccm030_addr), true);
104 #endif
105 
106 	return 0;
107 }
108 
arch_busy_wait(uint32_t time_us)109 void arch_busy_wait(uint32_t time_us)
110 {
111 	nrfx_coredep_delay_us(time_us);
112 }
113 
114 SYS_INIT(nordicsemi_nrf92_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
115