Based upon discussions with HW designers the 32KHz
programming sequence can be simplified. When FW writes
a value to the VBAT 32KHz Clock Enable register HW checks
if the value is the same as the current value. If the same
the HW does nothing. If different HW begins a sequence to
switch off the current 32KHz source, revert to ring oscillator,
and switch to the new source. FW should program the new value
and then spin until the PCR OSC ID PLL Lock bit goes to 1.
Signed-off-by: Scott Worley <scott.worley@microchip.com>
162 lines
3.9 KiB
C
162 lines
3.9 KiB
C
/*
|
|
* Copyright (c) 2019 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <device.h>
|
|
#include <init.h>
|
|
#include <soc.h>
|
|
#include <kernel.h>
|
|
#include <arch/cpu.h>
|
|
#include <arch/arm/aarch32/cortex_m/cmsis.h>
|
|
|
|
|
|
/*
|
|
* Make sure PCR sleep enables are clear except for crypto
|
|
* which do not have internal clock gating.
|
|
*/
|
|
static int soc_pcr_init(void)
|
|
{
|
|
PCR_REGS->SLP_EN0 = 0;
|
|
PCR_REGS->SLP_EN1 = 0;
|
|
PCR_REGS->SLP_EN2 = 0;
|
|
PCR_REGS->SLP_EN4 = 0;
|
|
PCR_REGS->SLP_EN3 = MCHP_PCR3_CRYPTO_MASK;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Select 32KHz clock source used for PLL reference.
|
|
* Options are:
|
|
* Internal 32KHz silicon oscillator.
|
|
* External parallel resonant crystal between XTAL1 and XTAL2 pins.
|
|
* External single ended crystal connected to XTAL2 pin.
|
|
* External 32KHz square wave from Host chipset/board on 32KHZ_IN pin.
|
|
* NOTES:
|
|
* FW Program new value to VBAT CLK32 Enable register.
|
|
* HW if new value != current value
|
|
* HW endif
|
|
* FW spin until PCR PLL lock is set.
|
|
* 32K stable and PLL locked.
|
|
* PLL POR or clock source change can take up to 3ms to lock.
|
|
* 32KHZ_IN pin must be configured for 32KHZ_IN function.
|
|
* Crystals vary and may take longer time to stabilize this will
|
|
* affect PLL lock time.
|
|
* Crystal do not like to be power cycled. If using a crystal
|
|
* the board should supply a battery backed (VBAT) power rail.
|
|
* The VBAT clock control register selecting 32KHz source is
|
|
* connected to the VBAT power rail. If using a battery one can
|
|
* check the VBAT Power Fail and Reset Status register for a VBAT POR.
|
|
*/
|
|
static void clk32_change(uint8_t new_clk32)
|
|
{
|
|
/* Program new value. */
|
|
VBATR_REGS->CLK32_EN = new_clk32 & MCHP_VBATR_CLKEN_MASK;
|
|
|
|
/* Wait for PLL lock. HW state machine is configuring PLL. */
|
|
while ((PCR_REGS->OSC_ID & MCHP_PCR_OSC_ID_PLL_LOCK) == 0)
|
|
;
|
|
}
|
|
|
|
static int soc_clk32_init(void)
|
|
{
|
|
uint8_t new_clk32;
|
|
|
|
#ifdef CONFIG_SOC_MEC1501_EXT_32K
|
|
#ifdef CONFIG_SOC_MEC1501_EXT_32K_CRYSTAL
|
|
#ifdef CONFIG_SOC_MEC1501_EXT_32K_PARALLEL_CRYSTAL
|
|
new_clk32 = MCHP_VBATR_USE_PAR_CRYSTAL;
|
|
#else
|
|
new_clk32 = MCHP_VBATR_USE_SE_CRYSTAL;
|
|
#endif
|
|
#else
|
|
/* Use 32KHZ_PIN as 32KHz source */
|
|
new_clk32 = MCHP_VBATR_USE_32KIN_PIN;
|
|
#endif
|
|
#else
|
|
/* Use internal 32KHz +/-2% silicon oscillator
|
|
* if required performed OTP value override
|
|
*/
|
|
if (MCHP_DEVICE_ID() == 0x0020U) { /* MEC150x ? */
|
|
if (MCHP_REVISION_ID() == MCHP_GCFG_REV_B0) {
|
|
VBATR_REGS->CKK32_TRIM = 0x06U;
|
|
}
|
|
}
|
|
|
|
new_clk32 = MCHP_VBATR_USE_SIL_OSC;
|
|
#endif
|
|
clk32_change(new_clk32);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Initialize MEC1501 EC Interrupt Aggregator (ECIA) and external NVIC
|
|
* inputs.
|
|
*/
|
|
static int soc_ecia_init(void)
|
|
{
|
|
GIRQ_Type *pg;
|
|
uint32_t n;
|
|
|
|
mchp_pcr_periph_slp_ctrl(PCR_ECIA, MCHP_PCR_SLEEP_DIS);
|
|
|
|
ECS_REGS->INTR_CTRL |= MCHP_ECS_ICTRL_DIRECT_EN;
|
|
|
|
/* gate off all aggregated outputs */
|
|
ECIA_REGS->BLK_EN_CLR = 0xFFFFFFFFul;
|
|
/* gate on GIRQ's that are aggregated only */
|
|
ECIA_REGS->BLK_EN_SET = MCHP_ECIA_AGGR_BITMAP;
|
|
|
|
/* Clear all GIRQn source enables and source status */
|
|
pg = &ECIA_REGS->GIRQ08;
|
|
for (n = MCHP_FIRST_GIRQ; n <= MCHP_LAST_GIRQ; n++) {
|
|
pg->EN_CLR = 0xFFFFFFFFul;
|
|
pg->SRC = 0xFFFFFFFFul;
|
|
pg++;
|
|
}
|
|
|
|
/* Clear all external NVIC enables and pending status */
|
|
for (n = 0u; n < MCHP_NUM_NVIC_REGS; n++) {
|
|
NVIC->ICER[n] = 0xFFFFFFFFul;
|
|
NVIC->ICPR[n] = 0xFFFFFFFFul;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int soc_init(const struct device *dev)
|
|
{
|
|
uint32_t isave;
|
|
|
|
ARG_UNUSED(dev);
|
|
|
|
isave = __get_PRIMASK();
|
|
__disable_irq();
|
|
|
|
soc_pcr_init();
|
|
|
|
soc_clk32_init();
|
|
|
|
/*
|
|
* On HW reset PCR Processor Clock Divider = 4 for 48/4 = 12 MHz.
|
|
* Set clock divider = 1 for maximum speed.
|
|
* NOTE1: This clock divider affects all Cortex-M4 core clocks.
|
|
* If you change it you must repogram SYSTICK to maintain the
|
|
* same absolute time interval.
|
|
*/
|
|
PCR_REGS->PROC_CLK_CTRL = CONFIG_SOC_MEC1501_PROC_CLK_DIV;
|
|
|
|
soc_ecia_init();
|
|
|
|
if (!isave) {
|
|
__enable_irq();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(soc_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|