|
18 | 18 | #include <soc/nrfx_coredep.h>
|
19 | 19 | #include <zephyr/logging/log.h>
|
20 | 20 | #include <nrf_erratas.h>
|
| 21 | +#include <hal/nrf_power.h> |
21 | 22 | #if defined(CONFIG_SOC_NRF5340_CPUAPP)
|
22 | 23 | #include <zephyr/drivers/gpio.h>
|
23 | 24 | #include <zephyr/devicetree.h>
|
@@ -98,6 +99,83 @@ static void enable_ram_retention(void)
|
98 | 99 | }
|
99 | 100 | #endif /* CONFIG_PM_S2RAM */
|
100 | 101 |
|
| 102 | +#if defined(CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND) |
| 103 | +static void nrf53_anomaly_160_workaround(void) |
| 104 | +{ |
| 105 | + /* This part is supposed to be removed once the writes are available |
| 106 | + * in hal_nordic/nrfx/MDK. |
| 107 | + */ |
| 108 | +#if defined(CONFIG_SOC_NRF5340_CPUAPP) && !defined(CONFIG_TRUSTED_EXECUTION_NONSECURE) |
| 109 | + *((volatile uint32_t *)0x5000470C) = 0x7Eul; |
| 110 | + *((volatile uint32_t *)0x5000493C) = 0x7Eul; |
| 111 | + *((volatile uint32_t *)0x50002118) = 0x7Ful; |
| 112 | + *((volatile uint32_t *)0x50039E04) = 0x0ul; |
| 113 | + *((volatile uint32_t *)0x50039E08) = 0x0ul; |
| 114 | + *((volatile uint32_t *)0x50101110) = 0x0ul; |
| 115 | + *((volatile uint32_t *)0x50002124) = 0x0ul; |
| 116 | + *((volatile uint32_t *)0x5000212C) = 0x0ul; |
| 117 | + *((volatile uint32_t *)0x502012A0) = 0x0ul; |
| 118 | +#elif defined(CONFIG_SOC_NRF5340_CPUNET) |
| 119 | + *((volatile uint32_t *)0x41002118) = 0x7Ful; |
| 120 | + *((volatile uint32_t *)0x41080E04) = 0x0ul; |
| 121 | + *((volatile uint32_t *)0x41080E08) = 0x0ul; |
| 122 | + *((volatile uint32_t *)0x41002124) = 0x0ul; |
| 123 | + *((volatile uint32_t *)0x4100212C) = 0x0ul; |
| 124 | + *((volatile uint32_t *)0x41101110) = 0x0ul; |
| 125 | +#endif |
| 126 | +} |
| 127 | + |
| 128 | +bool z_arm_on_enter_cpu_idle(void) |
| 129 | +{ |
| 130 | + /* This code prevents the CPU from entering sleep again if it already |
| 131 | + * entered sleep 5 times within last 200 us. |
| 132 | + */ |
| 133 | + |
| 134 | + /* System clock cycles needed to cover 200 us window. */ |
| 135 | + const uint32_t window_cycles = |
| 136 | + ceiling_fraction(200 * CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC, |
| 137 | + 1000000); |
| 138 | + static uint32_t timestamps[5]; |
| 139 | + static bool timestamps_filled; |
| 140 | + static bool suppress_warning; |
| 141 | + static uint8_t current; |
| 142 | + uint8_t oldest = (current + 1) % ARRAY_SIZE(timestamps); |
| 143 | + uint32_t now = k_cycle_get_32(); |
| 144 | + |
| 145 | + if (timestamps_filled && |
| 146 | + /* + 1 because only fully elapsed cycles need to be counted. */ |
| 147 | + (now - timestamps[oldest]) < (window_cycles + 1)) { |
| 148 | + if (!suppress_warning) { |
| 149 | + LOG_WRN("Anomaly 160 trigger conditions detected."); |
| 150 | + suppress_warning = true; |
| 151 | + } |
| 152 | + return false; |
| 153 | + } |
| 154 | + suppress_warning = false; |
| 155 | + |
| 156 | + /* Check if the CPU actually entered sleep since the last visit here |
| 157 | + * (WFE/WFI could return immediately if the wake-up event was already |
| 158 | + * registered). |
| 159 | + */ |
| 160 | + if (nrf_power_event_check(NRF_POWER, NRF_POWER_EVENT_SLEEPENTER)) { |
| 161 | + nrf_power_event_clear(NRF_POWER, NRF_POWER_EVENT_SLEEPENTER); |
| 162 | + /* If so, update the index at which the current timestamp is |
| 163 | + * to be stored so that it replaces the oldest one, otherwise |
| 164 | + * (when the CPU did not sleep), the recently stored timestamp |
| 165 | + * is updated. |
| 166 | + */ |
| 167 | + current = oldest; |
| 168 | + if (current == 0) { |
| 169 | + timestamps_filled = true; |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + timestamps[current] = k_cycle_get_32(); |
| 174 | + |
| 175 | + return true; |
| 176 | +} |
| 177 | +#endif /* CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND */ |
| 178 | + |
101 | 179 | static int nordicsemi_nrf53_init(const struct device *arg)
|
102 | 180 | {
|
103 | 181 | uint32_t key;
|
@@ -159,6 +237,11 @@ static int nordicsemi_nrf53_init(const struct device *arg)
|
159 | 237 | nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS, false, 0);
|
160 | 238 | #endif
|
161 | 239 |
|
| 240 | +#if defined(CONFIG_SOC_NRF53_ANOMALY_160_WORKAROUND) |
| 241 | + /* This needs to be done before DC/DC operation is enabled. */ |
| 242 | + nrf53_anomaly_160_workaround(); |
| 243 | +#endif |
| 244 | + |
162 | 245 | #if defined(CONFIG_SOC_DCDC_NRF53X_APP)
|
163 | 246 | nrf_regulators_dcdcen_set(NRF_REGULATORS, true);
|
164 | 247 | #endif
|
|
0 commit comments