Skip to content

Commit

Permalink
soc: ite: it8xxx2: support 96MHz PLL frequency and lcvco calibration
Browse files Browse the repository at this point in the history
To enhance USB clock's accuracy, this change supports 96MHz PLL frequency
and LCVCO calibration.

Signed-off-by: Ren Chen <[email protected]>
  • Loading branch information
Chenhongren authored and carlescufi committed Aug 29, 2024
1 parent cfaaf01 commit b90a507
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 16 deletions.
6 changes: 6 additions & 0 deletions soc/ite/ec/common/chip_chipregs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1279,6 +1279,12 @@ enum chip_pll_mode {
#define IT8XXX2_ECPM_SCDCR2 ECREG(IT8XXX2_ECPM_BASE + 0x0e)
#define IT8XXX2_ECPM_SCDCR3 ECREG(IT8XXX2_ECPM_BASE + 0x0f)
#define IT8XXX2_ECPM_SCDCR4 ECREG(IT8XXX2_ECPM_BASE + 0x10)
#define IT8XXX2_ECPM_PFACC0R ECREG(IT8XXX2_ECPM_BASE + 0x20)
#define IT8XXX2_ECPM_PFACC1R ECREG(IT8XXX2_ECPM_BASE + 0x21)
#define IT8XXX2_ECPM_PFACC2R ECREG(IT8XXX2_ECPM_BASE + 0x40)
#define IT8XXX2_ECPM_LCOTF2 ECREG(IT8XXX2_ECPM_BASE + 0x54)
#define IT8XXX2_ECPM_LCOCR ECREG(IT8XXX2_ECPM_BASE + 0x55)
#define IT8XXX2_ECPM_LCOCR1 ECREG(IT8XXX2_ECPM_BASE + 0x57)

/*
* The count number of the counter for 25 ms register.
Expand Down
9 changes: 9 additions & 0 deletions soc/ite/ec/it8xxx2/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ config SOC_IT8XXX2_JTAG_DEBUG_INTERFACE
- GPIOA6 -> TRST
Supported I/O voltage is 3.3V.

config SOC_IT8XXX2_LCVCO
bool "LCVCO calibration"
depends on SOC_IT8XXX2_INT_32K
help
The LCVCO is a highly precise clock controller used for
calibrating the frequency shift of the PLL. Enabling this
option allows for supported LCVCO calibration, improving
the accuracy of the USB clock.

choice
prompt "Clock source for PLL reference clock"

Expand Down
112 changes: 96 additions & 16 deletions soc/ite/ec/it8xxx2/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ COND_CODE_1(DT_NODE_EXISTS(DT_INST(1, ite_it8xxx2_usbpd)), (2), (1))
*/
#define SOC_USBPD_ITE_ACTIVE_PORT_COUNT DT_NUM_INST_STATUS_OKAY(ite_it8xxx2_usbpd)

/* PLL Frequency Auto-Calibration Control 0 Register */
#define PLL_FREQ_AUTO_CAL_EN BIT(7)
#define LOCK_TUNING_FACTORS_OF_LCO BIT(3)
/* LC Oscillator Control Register */
#define LCO_Power_CTRL BIT(1)
/* LC Oscillator Control Register 1 */
#define LDO_Power_CTRL BIT(1)
/* LC Oscillator Tuning Factor 2 */
#define LCO_SC_FACTOR_MASK GENMASK(6, 4)
#define LCO_SC_FACTOR(n) FIELD_PREP(LCO_SC_FACTOR_MASK, n)
/* PLL Frequency Auto-Calibration Control 2 Register */
#define AUTO_CAL_ENABLE BIT(1)
#define PLL_FREQ_AUTO_CAL_START BIT(0)
#define AUTO_CAL_ENABLE_AND_START (AUTO_CAL_ENABLE | PLL_FREQ_AUTO_CAL_START)

uint32_t chip_get_pll_freq(void)
{
uint32_t pllfreq;
Expand Down Expand Up @@ -83,7 +98,9 @@ void __soc_ram_code chip_pll_ctrl(enum chip_pll_mode mode)
#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M
struct pll_config_t {
uint8_t pll_freq;
uint8_t div_mcu;
uint8_t div_fnd;
uint8_t div_usb;
uint8_t div_uart;
uint8_t div_smb;
uint8_t div_sspi;
Expand All @@ -93,10 +110,18 @@ struct pll_config_t {
uint8_t div_usbpd;
};

static const struct pll_config_t pll_configuration[] = {
enum pll_frequency {
PLL_FREQ_48M = 0,
PLL_FREQ_96M,
PLL_FREQ_CNT
};

static const struct pll_config_t pll_configuration[PLL_FREQ_CNT] = {
/*
* PLL frequency setting = 4 (48MHz)
* MCU div = 0 (PLL / 1 = 48 mhz)
* FND div = 0 (PLL / 1 = 48 mhz)
* USB div = 0 (PLL / 1 = 48 mhz)
* UART div = 1 (PLL / 2 = 24 mhz)
* SMB div = 1 (PLL / 2 = 24 mhz)
* SSPI div = 1 (PLL / 2 = 24 mhz)
Expand All @@ -105,19 +130,49 @@ static const struct pll_config_t pll_configuration[] = {
* PWM div = 0 (PLL / 1 = 48 mhz)
* USBPD div = 5 (PLL / 6 = 8 mhz)
*/
{.pll_freq = 4,
.div_fnd = 0,
.div_uart = 1,
.div_smb = 1,
.div_sspi = 1,
[PLL_FREQ_48M] = {.pll_freq = 4,
.div_mcu = 0,
.div_fnd = 0,
.div_usb = 0,
.div_uart = 1,
.div_smb = 1,
.div_sspi = 1,
#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ
.div_ec = 1,
#else
.div_ec = 6,
#endif
.div_jtag = 1,
.div_pwm = 0,
.div_usbpd = 5},
/*
* PLL frequency setting = 7 (96MHz)
* MCU div = 1 (PLL / 2 = 48 mhz)
* FND div = 1 (PLL / 2 = 48 mhz)
* USB div = 1 (PLL / 2 = 48 mhz)
* UART div = 3 (PLL / 4 = 24 mhz)
* SMB div = 3 (PLL / 4 = 24 mhz)
* SSPI div = 3 (PLL / 4 = 24 mhz)
* EC div = 6 (FND / 6 = 8 mhz)
* JTAG div = 3 (PLL / 4 = 24 mhz)
* PWM div = 1 (PLL / 2 = 48 mhz)
* USBPD div = 11 (PLL / 12 = 8 mhz)
*/
[PLL_FREQ_96M] = {.pll_freq = 7,
.div_mcu = 1,
.div_fnd = 1,
.div_usb = 1,
.div_uart = 3,
.div_smb = 3,
.div_sspi = 3,
#ifdef CONFIG_SOC_IT8XXX2_EC_BUS_24MHZ
.div_ec = 1,
.div_ec = 1,
#else
.div_ec = 6,
.div_ec = 6,
#endif
.div_jtag = 1,
.div_pwm = 0,
.div_usbpd = 5}
.div_jtag = 3,
.div_pwm = 1,
.div_usbpd = 11},
};

void __soc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll)
Expand All @@ -142,12 +197,12 @@ void __soc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll)
chip_pll_ctrl(CHIP_PLL_SLEEP);
/* Chip sleep and wait timer wake it up */
__asm__ volatile ("wfi");
/* New FND clock frequency */
IT8XXX2_ECPM_SCDCR0 = pll->div_fnd << 4;
/* New FND and MCU clock frequency */
IT8XXX2_ECPM_SCDCR0 = (pll->div_fnd << 4) | pll->div_mcu;
/* Chip doze after wfi instruction */
chip_pll_ctrl(CHIP_PLL_DOZE);
/* UART */
IT8XXX2_ECPM_SCDCR1 = pll->div_uart;
/* USB and UART */
IT8XXX2_ECPM_SCDCR1 = (pll->div_usb << 4) | pll->div_uart;
/* SSPI and SMB */
IT8XXX2_ECPM_SCDCR2 = (pll->div_sspi << 4) | pll->div_smb;
/* USBPD and PWM */
Expand Down Expand Up @@ -182,8 +237,27 @@ static int chip_change_pll(void)
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
ite_intc_save_and_disable_interrupts();
}

/* Disable auto calibration before setting PLL frequency */
if (IT8XXX2_ECPM_PFACC0R & PLL_FREQ_AUTO_CAL_EN) {
IT8XXX2_ECPM_PFACC0R &= ~PLL_FREQ_AUTO_CAL_EN;
}

/* configure PLL/CPU/flash clock */
chip_configure_pll(&pll_configuration[0]);
if (IS_ENABLED(CONFIG_SOC_IT8XXX2_LCVCO)) {
chip_configure_pll(&pll_configuration[PLL_FREQ_96M]);

/* Enable LCVCO calibration */
IT8XXX2_ECPM_PFACC1R = 0x01;
IT8XXX2_ECPM_PFACC0R |= (PLL_FREQ_AUTO_CAL_EN | LOCK_TUNING_FACTORS_OF_LCO);
IT8XXX2_ECPM_LCOCR |= LCO_Power_CTRL;
IT8XXX2_ECPM_LCOCR1 |= LDO_Power_CTRL;
IT8XXX2_ECPM_LCOTF2 &= ~LCO_SC_FACTOR_MASK;
IT8XXX2_ECPM_LCOTF2 |= LCO_SC_FACTOR(2);
IT8XXX2_ECPM_PFACC2R = AUTO_CAL_ENABLE_AND_START;
} else {
chip_configure_pll(&pll_configuration[PLL_FREQ_48M]);
}
if (IS_ENABLED(CONFIG_HAS_ITE_INTC)) {
ite_intc_restore_interrupts();
}
Expand Down Expand Up @@ -253,6 +327,12 @@ void riscv_idle(enum chip_pll_mode mode, unsigned int key)
*/
} while (ite_intc_no_irq());

if (IS_ENABLED(CONFIG_SOC_IT8XXX2_LCVCO)) {
if (mode != CHIP_PLL_DOZE) {
IT8XXX2_ECPM_PFACC2R |= PLL_FREQ_AUTO_CAL_START;
}
}

#ifdef CONFIG_ESPI
/* CPU has been woken up, the interrupt is no longer needed */
espi_it8xxx2_enable_trans_irq(ESPI_IT8XXX2_SOC_DEV, false);
Expand Down

0 comments on commit b90a507

Please sign in to comment.