Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 | /* * Copyright (c) 2019 Microchip Technology Inc. * Copyright (c) 2016 Intel Corporation. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr.h> #include <sys/sys_io.h> #include <sys/__assert.h> #include <power/power.h> #include <soc.h> /* * CPU will spin up to DEEP_SLEEP_WAIT_SPIN_CLK_REQ times * waiting for PCR CLK_REQ bits to clear except for the * CPU bit itself. This is not necessary as the sleep hardware * will wait for all CLK_REQ to clear once WFI has executed. * Once all CLK_REQ signals are clear the hardware will transition * to the low power state. */ /* #define DEEP_SLEEP_WAIT_ON_CLK_REQ_ENABLE */ #define DEEP_SLEEP_WAIT_SPIN_CLK_REQ 1000 /* * Some peripherals if enabled always assert their CLK_REQ bits. * For example, any peripheral with a clock generator such as * timers, counters, UART, etc. We save the enables for these * peripherals, disable them, and restore the enabled state upon * wake. */ #define DEEP_SLEEP_PERIPH_SAVE_RESTORE /* * Light sleep: PLL remains on. Fastest wake latency. */ void soc_lite_sleep_enable(void) { SCB->SCR &= ~(1ul << 2); PCR_REGS->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_LIGHT; } /* * Deep sleep: PLL is turned off. Wake is fast. PLL requires * a minimum of 3ms to lock. During this time the main clock * will be ramping up from ~16 to 24 MHz. */ #if defined(CONFIG_SYS_POWER_DEEP_SLEEP_STATES) void soc_deep_sleep_enable(void) { SCB->SCR = (1ul << 2); /* Cortex-M4 SLEEPDEEP */ PCR_REGS->SYS_SLP_CTRL = MCHP_PCR_SYS_SLP_HEAVY; } void soc_deep_sleep_disable(void) { SCB->SCR &= ~(1ul << 2); /* disable Cortex-M4 SLEEPDEEP */ } void soc_deep_sleep_wait_clk_idle(void) { #ifdef DEEP_SLEEP_WAIT_ON_CLK_REQ_ENABLE u32_t clkreq, cnt; cnt = DEEP_SLEEP_WAIT_CLK_REQ; do { clkreq = PCR_REGS->CLK_REQ0 | PCR_REGS->CLK_REQ1 | PCR_REGS->CLK_REQ2 | PCR_REGS->CLK_REQ3 | PCR_REGS->CLK_REQ4; } while ((clkreq != (1ul << MCHP_PCR1_CPU_POS)) && (cnt-- != 0)); #endif } /* * Allow peripherals connected to external masters to wake the PLL but not * the EC. Once the peripheral has serviced the external master the PLL * will be turned back off. For example, if the eSPI master requests eSPI * configuration information or state of virtual wires the EC doesn't need * to be involved. The hardware can power on the PLL long enough to service * the request and then turn the PLL back off. The SMBus and I2C peripherals * in slave mode can also make use of this feature. */ void soc_deep_sleep_non_wake_en(void) { #ifdef CONFIG_ESPI_XEC GIRQ22_REGS->SRC = 0xfffffffful; GIRQ22_REGS->EN_SET = (1ul << 9); #endif } void soc_deep_sleep_non_wake_dis(void) { #ifdef CONFIG_ESPI_XEC GIRQ22_REGS->EN_CLR = 0xfffffffful; GIRQ22_REGS->SRC = 0xfffffffful; #endif } /* Variables used to save various HW state */ #ifdef DEEP_SLEEP_PERIPH_SAVE_RESTORE static u32_t ecs[1]; static void deep_sleep_save_ecs(void) { ecs[0] = ECS_REGS->ETM_CTRL; ECS_REGS->ETM_CTRL = 0; } struct ds_timer_info { uintptr_t addr; u32_t restore_mask; }; const struct ds_timer_info ds_timer_tbl[] = { { (uintptr_t)&B16TMR0_REGS->CTRL, 0 }, { (uintptr_t)&B16TMR1_REGS->CTRL, 0 }, { (uintptr_t)&B32TMR0_REGS->CTRL, 0 }, { (uintptr_t)&B32TMR1_REGS->CTRL, 0 }, { (uintptr_t)&CCT_REGS->CTRL, (MCHP_CCT_CTRL_COMP1_SET | MCHP_CCT_CTRL_COMP0_SET), }, }; #define NUM_DS_TIMER_ENTRIES \ (sizeof(ds_timer_tbl) / sizeof(struct ds_timer_info)) static u32_t timers[NUM_DS_TIMER_ENTRIES]; static u8_t uart_activate[3]; static void deep_sleep_save_uarts(void) { uart_activate[0] = UART0_REGS->ACTV; if (uart_activate[0]) { while ((UART0_REGS->LSR & MCHP_UART_LSR_TEMT) == 0) { }; } UART0_REGS->ACTV = 0; uart_activate[1] = UART1_REGS->ACTV; if (uart_activate[1]) { while ((UART1_REGS->LSR & MCHP_UART_LSR_TEMT) == 0) { }; } UART1_REGS->ACTV = 0; uart_activate[2] = UART2_REGS->ACTV; if (uart_activate[2]) { while ((UART2_REGS->LSR & MCHP_UART_LSR_TEMT) == 0) { }; } UART2_REGS->ACTV = 0; } static void deep_sleep_save_timers(void) { const struct ds_timer_info *p; u32_t i; p = &ds_timer_tbl[0]; for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) { timers[i] = REG32(p->addr); REG32(p->addr) = 0; p++; } } static void deep_sleep_restore_ecs(void) { ECS_REGS->ETM_CTRL = ecs[0]; } static void deep_sleep_restore_uarts(void) { UART0_REGS->ACTV = uart_activate[0]; UART1_REGS->ACTV = uart_activate[1]; UART2_REGS->ACTV = uart_activate[2]; } static void deep_sleep_restore_timers(void) { const struct ds_timer_info *p; u32_t i; p = &ds_timer_tbl[0]; for (i = 0; i < NUM_DS_TIMER_ENTRIES; i++) { REG32(p->addr) = timers[i] & ~p->restore_mask; p++; } } void soc_deep_sleep_periph_save(void) { deep_sleep_save_uarts(); deep_sleep_save_ecs(); deep_sleep_save_timers(); } void soc_deep_sleep_periph_restore(void) { deep_sleep_restore_ecs(); deep_sleep_restore_uarts(); deep_sleep_restore_timers(); } #else void soc_deep_sleep_periph_save(void) { } void soc_deep_sleep_periph_restore(void) { } #endif /* DEEP_SLEEP_PERIPH_SAVE_RESTORE */ #endif /* CONFIG_SYS_POWER_DEEP_SLEEP_STATES */ |