diff options
Diffstat (limited to 'chip/max32660/clock_chip.c')
-rw-r--r-- | chip/max32660/clock_chip.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/chip/max32660/clock_chip.c b/chip/max32660/clock_chip.c new file mode 100644 index 0000000000..901c5d559c --- /dev/null +++ b/chip/max32660/clock_chip.c @@ -0,0 +1,141 @@ +/* Copyright 2019 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* MAX32660 Clocks and Power Management Module for Chrome EC */ + +#include "clock.h" +#include "common.h" +#include "console.h" +#include "cpu.h" +#include "hooks.h" +#include "hwtimer.h" +#include "registers.h" +#include "system.h" +#include "timer.h" +#include "util.h" +#include "watchdog.h" +#include "tmr_regs.h" +#include "gcr_regs.h" +#include "pwrseq_regs.h" + +#define MAX32660_SYSTEMCLOCK SYS_CLOCK_HIRC + +/** Clock source */ +typedef enum { + SYS_CLOCK_NANORING = MXC_V_GCR_CLKCN_CLKSEL_NANORING, /**< 8KHz nanoring + on MAX32660 */ + SYS_CLOCK_HFXIN = + MXC_V_GCR_CLKCN_CLKSEL_HFXIN, /**< 32KHz on MAX32660 */ + SYS_CLOCK_HFXIN_DIGITAL = 0x9, /**< External Clock Input*/ + SYS_CLOCK_HIRC = MXC_V_GCR_CLKCN_CLKSEL_HIRC, /**< High Frequency + Internal Oscillator */ +} sys_system_clock_t; + +/***** Functions ******/ +static void clock_wait_ready(uint32_t ready) +{ + // Start timeout, wait for ready + do { + if (MXC_GCR->clkcn & ready) { + return; + } + } while (1); +} + +extern void (*const __isr_vector[])(void); +uint32_t SystemCoreClock = HIRC96_FREQ; + +static void clock_update(void) +{ + uint32_t base_freq, divide, ovr; + + // Get the clock source and frequency + ovr = (MXC_PWRSEQ->lp_ctrl & MXC_F_PWRSEQ_LP_CTRL_OVR); + if (ovr == MXC_S_PWRSEQ_LP_CTRL_OVR_0_9V) { + base_freq = HIRC96_FREQ / 4; + } else { + if (ovr == MXC_S_PWRSEQ_LP_CTRL_OVR_1_0V) { + base_freq = HIRC96_FREQ / 2; + } else { + base_freq = HIRC96_FREQ; + } + } + + // Get the clock divider + divide = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_PSC) >> + MXC_F_GCR_CLKCN_PSC_POS; + + SystemCoreClock = base_freq >> divide; +} + +void clock_init(void) +{ + /* Switch system clock to HIRC */ + uint32_t ovr, divide; + + // Set FWS higher than what the minimum for the fastest clock is + MXC_GCR->memckcn = (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x5UL << MXC_F_GCR_MEMCKCN_FWS_POS); + + // Enable 96MHz Clock + MXC_GCR->clkcn |= MXC_F_GCR_CLKCN_HIRC_EN; + + // Wait for the 96MHz clock + clock_wait_ready(MXC_F_GCR_CLKCN_HIRC_RDY); + + // Set 96MHz clock as System Clock + MXC_SETFIELD(MXC_GCR->clkcn, MXC_F_GCR_CLKCN_CLKSEL, + MXC_S_GCR_CLKCN_CLKSEL_HIRC); + + // Wait for system clock to be ready + clock_wait_ready(MXC_F_GCR_CLKCN_CKRDY); + + // Update the system core clock + clock_update(); + + // Get the clock divider + divide = (MXC_GCR->clkcn & MXC_F_GCR_CLKCN_PSC) >> + MXC_F_GCR_CLKCN_PSC_POS; + + // get ovr setting + ovr = (MXC_PWRSEQ->lp_ctrl & MXC_F_PWRSEQ_LP_CTRL_OVR); + + // Set flash wait settings + if (ovr == MXC_S_PWRSEQ_LP_CTRL_OVR_0_9V) { + if (divide == 0) { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x2UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } else { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x1UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } + } else if (ovr == MXC_S_PWRSEQ_LP_CTRL_OVR_1_0V) { + if (divide == 0) { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x2UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } else { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x1UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } + } else { + if (divide == 0) { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x4UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } else if (divide == 1) { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x2UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } else { + MXC_GCR->memckcn = + (MXC_GCR->memckcn & ~(MXC_F_GCR_MEMCKCN_FWS)) | + (0x1UL << MXC_F_GCR_MEMCKCN_FWS_POS); + } + } +} |