drivers: clock: Microchip XEC clock driver add MEC15xx support

Add support for Microchip MEC15xx to the XEC clock control driver.
MEC15xx 32KHz clock support uses the same 32KHz source for both the
PLL and peripherals. MEC152x does not include the PCR clock monitor
present in MEC172x.  MEC15xx and MEC172x support internal silicon
oscillator, parallel and single ended crystal inputs, and the
32KHZ_PIN input. MEC152x supports fall back to internal silicon
OSC when VTR and 32KHZ_PIN are turned off. Therefore in MEC152x the
internal silicon oscillator can only be disabled if using an external
32KHz which is always on. For MEC152x the driver will only use the
PLL source clock device tree value.

Signed-off-by: Jay Vasanth <jay.vasanth@microchip.com>
This commit is contained in:
Jay Vasanth 2022-11-16 12:07:42 -05:00 committed by Carles Cufí
commit c7e0d727d7
9 changed files with 138 additions and 143 deletions

View file

@ -49,6 +49,10 @@
cpu-power-states = <&idle &suspend_to_ram>;
};
&pcr {
status = "okay";
};
&uart1 {
status = "okay";
current-speed = <115200>;

View file

@ -12,6 +12,8 @@ CONFIG_SOC_MEC1501_VCI_PINS_AS_GPIOS=n
CONFIG_BOARD_MEC1501MODULAR_ASSY6885=y
CONFIG_RTOS_TIMER=y
CONFIG_CLOCK_CONTROL=y
CONFIG_PINCTRL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y

View file

@ -77,6 +77,10 @@
cpu-power-states = <&idle &suspend_to_ram>;
};
&pcr {
status = "okay";
};
&uart2 {
status = "okay";
current-speed = <115200>;

View file

@ -10,7 +10,9 @@ CONFIG_SOC_MEC1501_VTR3_1_8V=y
CONFIG_BOARD_MEC15XXEVB_ASSY6853=y
CONFIG_RTOS_TIMER=y
CONFIG_CLOCK_CONTROL=y
CONFIG_CONSOLE=y
CONFIG_PINCTRL=y
CONFIG_UART_CONSOLE=y
CONFIG_SERIAL=y
CONFIG_GPIO=y

View file

@ -118,7 +118,11 @@ struct pcr_hw_regs {
#define XEC_CC_PCR_CLK32K_SRC_PIN 2
#define XEC_CC_PCR_CLK32K_SRC_OFF 3
#ifdef CONFIG_SOC_SERIES_MEC1501X
#define XEC_CC_PCR3_CRYPTO_MASK (BIT(26) | BIT(27) | BIT(28))
#else
#define XEC_CC_PCR3_CRYPTO_MASK BIT(26)
#endif
/* VBAT powered hardware registers related to clock configuration */
struct vbatr_hw_regs {
@ -129,6 +133,17 @@ struct vbatr_hw_regs {
volatile uint32_t CLK32_TRIM;
};
/* MEC152x VBAT CLK32_SRC register defines */
#define XEC_CC15_VBATR_USE_SIL_OSC 0u
#define XEC_CC15_VBATR_USE_32KIN_PIN BIT(1)
#define XEC_CC15_VBATR_USE_PAR_CRYSTAL BIT(2)
#define XEC_CC15_VBATR_USE_SE_CRYSTAL (BIT(2) | BIT(3))
/* MEC150x special requirements */
#define XEC_CC15_GCFG_DID_DEV_ID_MEC150x 0x0020U
#define XEC_CC15_TRIM_ENABLE_INT_OSCILLATOR 0x06U
/* MEC172x VBAT CLK32_SRC register defines */
#define XEC_CC_VBATR_CS_SO_EN BIT(0) /* enable and start silicon OSC */
#define XEC_CC_VBATR_CS_XTAL_EN BIT(8) /* enable & start external crystal */
@ -204,6 +219,10 @@ static void pcr_slp_init(struct pcr_hw_regs *pcr)
* We use the hibernation timer GIRQ interrupt status bit instead of reading
* the timer's count register due to race condition of HW taking at least
* one 32KHz cycle to move pre-load into count register.
* MEC15xx:
* Hibernation timer is using the chosen 32KHz source. If the external 32KHz source
* has a ramp up time, we make not get an accurate delay. This may only occur for
* the parallel crystal.
*/
static int pll_wait_lock_periph(struct pcr_hw_regs *const pcr, uint16_t ms)
{
@ -227,6 +246,71 @@ static int pll_wait_lock_periph(struct pcr_hw_regs *const pcr, uint16_t ms)
return rc;
}
static int periph_clk_src_using_pin(enum periph_clk32k_src src)
{
switch (src) {
case PERIPH_CLK32K_SRC_PIN_SO:
case PERIPH_CLK32K_SRC_PIN_XTAL:
return 1;
default:
return 0;
}
}
#ifdef CONFIG_SOC_SERIES_MEC1501X
/* MEC15xx uses the same 32KHz source for both PLL and Peripheral 32K clock domains.
* We ignore the peripheral clock source.
* If XTAL is selected (parallel) or single-ended the external 32KHz MUST stay on
* even when when VTR goes off.
* If PIN(32KHZ_IN pin) as the external source, hardware can auto-switch to internal
* silicon OSC if the signal on the 32KHZ_PIN goes away.
* We ignore th
*/
static int soc_clk32_init(const struct device *dev,
enum pll_clk32k_src pll_clk_src,
enum periph_clk32k_src periph_clk_src,
uint32_t flags)
{
const struct xec_pcr_config * const devcfg = dev->config;
struct pcr_hw_regs *const pcr = (struct pcr_hw_regs *)devcfg->pcr_base;
struct vbatr_hw_regs *const vbr = (struct vbatr_hw_regs *)devcfg->vbr_base;
uint32_t cken = 0U;
int rc = 0;
if (MCHP_DEVICE_ID() == XEC_CC15_GCFG_DID_DEV_ID_MEC150x) {
if (MCHP_REVISION_ID() == MCHP_GCFG_REV_B0) {
vbr->CLK32_TRIM = XEC_CC15_TRIM_ENABLE_INT_OSCILLATOR;
}
}
switch (pll_clk_src) {
case PLL_CLK32K_SRC_SO:
cken = XEC_CC15_VBATR_USE_SIL_OSC;
break;
case PLL_CLK32K_SRC_XTAL:
if (flags & CLK32K_FLAG_CRYSTAL_SE) {
cken = XEC_CC15_VBATR_USE_SE_CRYSTAL;
} else {
cken = XEC_CC15_VBATR_USE_PAR_CRYSTAL;
}
break;
case PLL_CLK32K_SRC_PIN: /* 32KHZ_IN pin falls back to Silicon OSC */
cken = XEC_CC15_VBATR_USE_32KIN_PIN;
break;
default: /* do not touch HW */
return -EINVAL;
}
if ((vbr->CLK32_SRC & 0xffU) != cken) {
vbr->CLK32_SRC = cken;
}
rc = pll_wait_lock_periph(pcr, devcfg->xtal_enable_delay_ms);
return rc;
}
#else
static int periph_clk_src_using_si(enum periph_clk32k_src src)
{
switch (src) {
@ -249,17 +333,6 @@ static int periph_clk_src_using_xtal(enum periph_clk32k_src src)
}
}
static int periph_clk_src_using_pin(enum periph_clk32k_src src)
{
switch (src) {
case PERIPH_CLK32K_SRC_PIN_SO:
case PERIPH_CLK32K_SRC_PIN_XTAL:
return 1;
default:
return 0;
}
}
static bool is_sil_osc_enabled(struct vbatr_hw_regs *vbr)
{
if (vbr->CLK32_SRC & XEC_CC_VBATR_CS_SO_EN) {
@ -661,6 +734,7 @@ static int soc_clk32_init(const struct device *dev,
return rc;
}
#endif
/*
* MEC172x Errata document DS80000913C
@ -812,6 +886,11 @@ static inline int xec_clock_control_off(const struct device *dev,
*/
static uint32_t get_turbo_clock(const struct device *dev)
{
#ifdef CONFIG_SOC_SERIES_MEC1501X
ARG_UNUSED(dev);
return MHZ(48);
#else
const struct xec_pcr_config * const devcfg = dev->config;
struct pcr_hw_regs *const pcr = (struct pcr_hw_regs *)devcfg->pcr_base;
@ -820,6 +899,7 @@ static uint32_t get_turbo_clock(const struct device *dev)
}
return MHZ(48);
#endif
}
/*

View file

@ -5,6 +5,7 @@
*/
#include <arm/armv7-m.dtsi>
#include <zephyr/dt-bindings/clock/mchp_xec_pcr.h>
#include <zephyr/dt-bindings/i2c/i2c.h>
#include <zephyr/dt-bindings/gpio/gpio.h>
@ -72,13 +73,36 @@
reg = <0x4000fc00 0x200>;
};
pcr: pcr@40080100 {
compatible = "microchip,xec-pcr";
reg = <0x40080100 0x100 0x4000a400 0x100>;
reg-names = "pcrr", "vbatr";
core-clock-div = <1>;
/* MEC15xx requires both sources to be the same */
pll-32k-src = <MCHP_XEC_PLL_CLK32K_SRC_SIL_OSC>;
periph-32k-src = <MCHP_XEC_PERIPH_CLK32K_SRC_SO_SO>;
clk32kmon-period-min = <1435>;
clk32kmon-period-max = <1495>;
clk32kmon-duty-cycle-var-max = <132>;
clk32kmon-valid-min = <4>;
xtal-enable-delay-ms = <300>;
pll-lock-timeout-ms = <30>;
/* pin configured only if the sources is set to PIN */
pinctrl-0 = <&clk_32khz_in_gpio165>;
pinctrl-names = "default";
#clock-cells = <2>;
};
ecia: ecia@4000e000 {
reg = <0x4000e000 0x400>;
#address-cells = <1>;
#size-cells = <1>;
girq23: girq23@12c {
reg = <0x12c 0x14>;
interrupts = <14 0>;
girq-id = <15>;
sources = <0 1 2 4 5 10 16 17>;
status = "disabled";
};
};
pinctrl: pin-controller@40081000 {
compatible = "microchip,xec-pinctrl";
@ -326,6 +350,16 @@
girqs = <23 5>;
pcrs = <3 24>;
};
hibtimer0: timer@40009800 {
reg = <0x40009800 0x20>;
interrupts = <112 0>;
girqs = <23 16>;
};
hibtimer1: timer@40009820 {
reg = <0x40009820 0x20>;
interrupts = <113 0>;
girqs = <23 17>;
};
ps2_0: ps2@40009000 {
compatible = "microchip,xec-ps2";
reg = <0x40009000 0x40>;

View file

@ -26,41 +26,6 @@ config SOC_MEC1501_PROC_CLK_DIV
HCLK = MCK / PROC_CLK_DIV
Allowed divider values: 1, 3, 4, 16, and 48.
config SOC_MEC1501_EXT_32K
bool "Use external 32KHz clock source"
help
Use an external 32768 Hz clock source for PLL reference
clock.
Say y if you want to use an external source for the PLL
32KHz reference clock.
Say n to use the +/-2% internal silicon oscillator.
config SOC_MEC1501_EXT_32K_CRYSTAL
bool "External 32KHz is a crystal"
depends on SOC_MEC1501_EXT_32K
help
Choose a crystal as the external 32KHz source.
Say y if you wish to use a crystal as the external
32KHz clock source.
Saying n will select the 32KHZ_IN pin as the external
32KHz clock source.
config SOC_MEC1501_EXT_32K_PARALLEL_CRYSTAL
bool "Use parallel connected 32KHz crystal"
depends on SOC_MEC1501_EXT_32K_CRYSTAL
help
Choose external 32KHz crystal connection.
Say y if the crystal is connected parallel between
the XTAL1 and XTAL pins.
Say n if the crystal is connected single ended to
the XTAL2 pin or a 32KHz square wave is on XTAL2.
config SOC_MEC1501_VTR3_1_8V
bool "VTR3 power rail is tied to 1.8V"
help

View file

@ -12,92 +12,8 @@
#include <zephyr/arch/cpu.h>
#include <zephyr/arch/arm/aarch32/cortex_m/cmsis.h>
/* MEC devices IDs with special PLL handling */
#define MCHP_GCFG_DID_DEV_ID_MEC150x 0x0020U
#define MCHP_TRIM_ENABLE_INT_OSCILLATOR 0x06U
#define TEST_CLK_OUT_PIN_COUNT 1
/*
* 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() == MCHP_GCFG_DID_DEV_ID_MEC150x) {
if (MCHP_REVISION_ID() == MCHP_GCFG_REV_B0) {
VBATR_REGS->CKK32_TRIM = MCHP_TRIM_ENABLE_INT_OSCILLATOR;
}
}
new_clk32 = MCHP_VBATR_USE_SIL_OSC;
#endif
clk32_change(new_clk32);
return 0;
}
/*
* Initialize MEC1501 EC Interrupt Aggregator (ECIA) and external NVIC
* inputs.
@ -169,19 +85,6 @@ static int soc_init(const struct device *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 reprogram SYSTICK to maintain the
* same absolute time interval.
*/
PCR_REGS->PROC_CLK_CTRL = CONFIG_SOC_MEC1501_PROC_CLK_DIV;
soc_ecia_init();
/* Configure GPIO bank before usage

View file

@ -17,6 +17,7 @@
/* common SoC API */
#include "../common/soc_dt.h"
#include "../common/soc_gpio.h"
#include "../common/soc_pcr.h"
#include "../common/soc_pins.h"
#include "../common/soc_espi_channels.h"
#include "soc_espi_saf_v1.h"