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 | /* * Copyright (c) 2018 Foundries.io * * SPDX-License-Identifier: Apache-2.0 */ #include <kernel.h> #include <device.h> #include <init.h> #include <fsl_clock.h> #include <sys/util.h> #if defined(CONFIG_MULTI_LEVEL_INTERRUPTS) #include <errno.h> #include <irq_nextlevel.h> #endif #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL #include <logging/log.h> LOG_MODULE_REGISTER(soc); #define SCG_LPFLL_DISABLE 0U static struct device *dev_intmux; /* * Run-mode configuration for the fast internal reference clock (FIRC). */ static const scg_firc_config_t rv32m1_firc_config = { .enableMode = kSCG_FircEnable, .div1 = kSCG_AsyncClkDivBy1, .div2 = kSCG_AsyncClkDivBy1, .div3 = kSCG_AsyncClkDivBy1, .range = kSCG_FircRange48M, .trimConfig = NULL, }; /* * FIRC-based system clock configuration. */ static const scg_sys_clk_config_t rv32m1_sys_clk_config_firc = { .divSlow = kSCG_SysClkDivBy2, .divBus = kSCG_SysClkDivBy1, .divExt = kSCG_SysClkDivBy1, .divCore = kSCG_SysClkDivBy1, .src = kSCG_SysClkSrcFirc, }; /* * LPFLL configuration. */ static const scg_lpfll_config_t rv32m1_lpfll_cfg = { .enableMode = SCG_LPFLL_DISABLE, .div1 = kSCG_AsyncClkDivBy1, .div2 = kSCG_AsyncClkDisable, .div3 = kSCG_AsyncClkDisable, .range = kSCG_LpFllRange48M, .trimConfig = NULL, }; void sys_arch_reboot(int type) { ARG_UNUSED(type); EVENT_UNIT->SLPCTRL |= EVENT_SLPCTRL_SYSRSTREQST_MASK; } void z_arch_irq_enable(unsigned int irq) { if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) { unsigned int level = rv32m1_irq_level(irq); if (level == 1U) { EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq)); /* Ensures write has finished: */ (void)(EVENT_UNIT->INTPTEN); } else { irq_enable_next_level(dev_intmux, irq); } } else { EVENT_UNIT->INTPTEN |= BIT(rv32m1_level1_irq(irq)); (void)(EVENT_UNIT->INTPTEN); } } void z_arch_irq_disable(unsigned int irq) { if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) { unsigned int level = rv32m1_irq_level(irq); if (level == 1U) { EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq)); /* Ensures write has finished: */ (void)(EVENT_UNIT->INTPTEN); } else { irq_disable_next_level(dev_intmux, irq); } } else { EVENT_UNIT->INTPTEN &= ~BIT(rv32m1_level1_irq(irq)); (void)(EVENT_UNIT->INTPTEN); } } int z_arch_irq_is_enabled(unsigned int irq) { if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) { unsigned int level = rv32m1_irq_level(irq); if (level == 1U) { return (EVENT_UNIT->INTPTEN & BIT(rv32m1_level1_irq(irq))) != 0; } else { u32_t channel, line, ier; /* * Here we break the abstraction and look * directly at the INTMUX registers. We can't * use the irq_nextlevel.h API, as that only * tells us whether some IRQ at the next level * is enabled or not. */ channel = rv32m1_intmux_channel(irq); line = rv32m1_intmux_line(irq); ier = INTMUX->CHANNEL[channel].CHn_IER_31_0 & BIT(line); return ier != 0U; } } else { return (EVENT_UNIT->INTPTEN & BIT(rv32m1_level1_irq(irq))) != 0; } } /* * SoC-level interrupt initialization. Clear any pending interrupts or * events, and find the INTMUX device if necessary. * * This gets called as almost the first thing z_cstart() does, so it * will happen before any calls to the _arch_irq_xxx() routines above. */ void soc_interrupt_init(void) { EVENT_UNIT->INTPTPENDCLEAR = 0xFFFFFFFF; (void)(EVENT_UNIT->INTPTPENDCLEAR); /* Ensures write has finished. */ EVENT_UNIT->EVTPENDCLEAR = 0xFFFFFFFF; (void)(EVENT_UNIT->EVTPENDCLEAR); /* Ensures write has finished. */ if (IS_ENABLED(CONFIG_MULTI_LEVEL_INTERRUPTS)) { dev_intmux = device_get_binding(DT_OPENISA_RV32M1_INTMUX_INTMUX_LABEL); __ASSERT(dev_intmux, "no INTMUX device found"); } } /** * @brief Switch system clock configuration in run mode. * * Blocks until the updated configuration takes effect. * * @param cfg New system clock configuration */ static void rv32m1_switch_sys_clk(const scg_sys_clk_config_t *cfg) { scg_sys_clk_config_t cur_cfg; CLOCK_SetRunModeSysClkConfig(cfg); do { CLOCK_GetCurSysClkConfig(&cur_cfg); } while (cur_cfg.src != cfg->src); } /** * @brief Initializes SIRC and switches system clock source to SIRC. */ static void rv32m1_switch_to_sirc(void) { const scg_sirc_config_t sirc_config = { .enableMode = kSCG_SircEnable, .div1 = kSCG_AsyncClkDisable, .div2 = kSCG_AsyncClkDivBy2, .range = kSCG_SircRangeHigh, }; const scg_sys_clk_config_t sys_clk_config_sirc = { .divSlow = kSCG_SysClkDivBy4, .divCore = kSCG_SysClkDivBy1, .src = kSCG_SysClkSrcSirc, }; CLOCK_InitSirc(&sirc_config); rv32m1_switch_sys_clk(&sys_clk_config_sirc); } /** * @brief Perform basic hardware initialization * * Initializes the base clocks and LPFLL using helpers provided by the HAL. * * @return 0 */ static int soc_rv32m1_init(struct device *arg) { unsigned int key; ARG_UNUSED(arg); key = irq_lock(); /* Switch to SIRC so we can initialize the FIRC. */ rv32m1_switch_to_sirc(); /* Now that we're running off of SIRC, set up and switch to FIRC. */ CLOCK_InitFirc(&rv32m1_firc_config); rv32m1_switch_sys_clk(&rv32m1_sys_clk_config_firc); /* Initialize LPFLL */ CLOCK_InitLpFll(&rv32m1_lpfll_cfg); irq_unlock(key); return 0; } SYS_INIT(soc_rv32m1_init, PRE_KERNEL_1, 0); |