soc: it8xxx2: introduce SOC_IT8XXX2_PLL_FLASH_48M option

Enable SOC_IT8XXX2_PLL_FLASH_48M at default to reduce latency of
fetching code from flash.

Signed-off-by: Dino Li <Dino.Li@ite.com.tw>
This commit is contained in:
Dino Li 2021-07-05 14:08:50 +08:00 committed by Christopher Friedt
commit 7d5411d6e0
6 changed files with 211 additions and 0 deletions

View file

@ -69,6 +69,37 @@ inline void set_csr(unsigned long bit)
}
}
#define IT8XXX2_IER_COUNT ARRAY_SIZE(reg_enable)
static uint8_t ier_setting[IT8XXX2_IER_COUNT];
void ite_intc_save_and_disable_interrupts(void)
{
/* Disable global interrupt for critical section */
unsigned int key = irq_lock();
/* Save and disable interrupts */
for (int i = 0; i < IT8XXX2_IER_COUNT; i++) {
ier_setting[i] = *reg_enable[i];
*reg_enable[i] = 0;
}
irq_unlock(key);
}
void ite_intc_restore_interrupts(void)
{
/*
* Ensure the highest priority interrupt will be the first fired
* interrupt when soc is ready to go.
*/
unsigned int key = irq_lock();
/* Restore interrupt state */
for (int i = 0; i < IT8XXX2_IER_COUNT; i++) {
*reg_enable[i] = ier_setting[i];
}
irq_unlock(key);
}
void ite_intc_isr_clear(unsigned int irq)
{
uint32_t g, i;

View file

@ -204,6 +204,34 @@ static void timer_isr(const void *unused)
sys_clock_announce(dticks);
}
#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M
#define TIMER_CHANGE_PLL EXT_TIMER_8
static void timer_5ms_one_shot_isr(const void *unused)
{
ARG_UNUSED(unused);
/*
* We are here because we have completed changing PLL sequence.
* Disabled the timer.
*/
timer_init_ms(TIMER_CHANGE_PLL, ET_PSR_32K, 0, 0, 5);
}
/*
* This timer is used to wake up chip from sleep mode to complete
* changing PLL sequence.
*/
void timer_5ms_one_shot(void)
{
/* Initialize interrupt handler of external timer8. */
IRQ_CONNECT(DT_IRQ_BY_IDX(DT_NODELABEL(timer), 8, irq),
0, timer_5ms_one_shot_isr, NULL,
DT_IRQ_BY_IDX(DT_NODELABEL(timer), 8, flags));
/* enable 5ms timer with 32.768khz clock source */
timer_init_ms(TIMER_CHANGE_PLL, ET_PSR_32K, 1, 1, 5);
}
#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */
int sys_clock_driver_init(const struct device *dev)
{
timer_init_combine(CTIMER_HW_TIMER_INDEX, TRUE);

View file

@ -1774,6 +1774,15 @@ struct adc_it8xxx2_regs {
#define CGC_OFFSET_SMBB ((IT83XX_ECPM_CGCTRL4R_OFF << 8) | 0x08)
#define CGC_OFFSET_SMBA ((IT83XX_ECPM_CGCTRL4R_OFF << 8) | 0x04)
/* TODO: rename IT83XX_ECPM_BASE to IT8XXX2_ECPM_BASE */
#define IT8XXX2_ECPM_PLLCTRL ECREG(IT83XX_ECPM_BASE + 0x03)
#ifndef __ASSEMBLER__
enum chip_pll_mode {
CHIP_PLL_DOZE = 0,
CHIP_PLL_SLEEP = 1,
CHIP_PLL_DEEP_DOZE = 3,
};
#endif
#define IT8XXX2_ECPM_AUTOCG ECREG(IT83XX_ECPM_BASE + 0x04)
#define IT8XXX2_ECPM_CGCTRL3R ECREG(IT83XX_ECPM_BASE + 0x05)
#define IT8XXX2_ECPM_PLLFREQR ECREG(IT83XX_ECPM_BASE + 0x06)

View file

@ -71,6 +71,14 @@ int riscv_plic_get_irq(void);
#endif
#if CONFIG_ITE_IT8XXX2_INTC
/*
* Save current interrupt state of soc-level into ier_setting[] with
* disabling interrupt.
*/
void ite_intc_save_and_disable_interrupts(void);
/* Restore interrupt state of soc-level from ier_setting[], use with care. */
void ite_intc_restore_interrupts(void);
extern void ite_intc_irq_enable(unsigned int irq);
extern void ite_intc_irq_disable(unsigned int irq);
extern uint8_t ite_intc_get_irq_num(void);
@ -80,6 +88,10 @@ extern void ite_intc_irq_priority_set(unsigned int irq,
extern void ite_intc_isr_clear(unsigned int irq);
#endif /* CONFIG_ITE_IT8XXX2_INTC */
#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M
void timer_5ms_one_shot(void);
#endif
#endif /* !_ASMLANGUAGE */
#endif /* __SOC_COMMON_H_ */

View file

@ -12,6 +12,15 @@ config SOC_IT8XXX2
endchoice
config SOC_IT8XXX2_PLL_FLASH_48M
bool "Flash frequency is 48MHz"
default y
help
Change frequency of PLL, CPU, and flash to 48MHz during initialization.
Set n to use the default settings.
(PLL and CPU run at 48MHz, flash frequency is 16MHz)
choice
prompt "Clock source for PLL reference clock"

View file

@ -9,6 +9,128 @@
#include <device.h>
#include <init.h>
#include <soc.h>
#include <dt-bindings/interrupt-controller/ite-intc.h>
#ifdef CONFIG_SOC_IT8XXX2_PLL_FLASH_48M
#define __intc_ram_code __attribute__((section(".__ram_code")))
struct pll_config_t {
uint8_t pll_freq;
uint8_t div_fnd;
uint8_t div_uart;
uint8_t div_smb;
uint8_t div_sspi;
uint8_t div_ec;
uint8_t div_jtag;
uint8_t div_pwm;
uint8_t div_usbpd;
};
static const struct pll_config_t pll_configuration[] = {
/*
* PLL frequency setting = 4 (48MHz)
* FND 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)
* EC div = 6 (FND / 6 = 8 mhz)
* JTAG div = 1 (PLL / 2 = 24 mhz)
* 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,
.div_ec = 6,
.div_jtag = 1,
.div_pwm = 0,
.div_usbpd = 5}
};
void __intc_ram_code chip_pll_ctrl(enum chip_pll_mode mode)
{
IT8XXX2_ECPM_PLLCTRL = mode;
/* for deep doze / sleep mode */
IT8XXX2_ECPM_PLLCTRL = mode;
}
void __intc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll)
{
/* Enable HW timer to wakeup chip from the sleep mode */
timer_5ms_one_shot();
/*
* Configure PLL clock dividers.
* Writing data to these registers doesn't change the
* PLL frequency immediately until the status is changed
* into wakeup from the sleep mode.
* The following code is intended to make the system
* enter sleep mode, and wait HW timer to wakeup chip to
* complete PLL update.
*/
IT8XXX2_ECPM_PLLFREQR = pll->pll_freq;
/* Pre-set FND clock frequency = PLL / 3 */
IT8XXX2_ECPM_SCDCR0 = (2 << 4);
/* JTAG and EC */
IT8XXX2_ECPM_SCDCR3 = (pll->div_jtag << 4) | pll->div_ec;
/* Chip sleep after wait for interrupt (wfi) instruction */
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;
/* Chip doze after wfi instruction */
chip_pll_ctrl(CHIP_PLL_DOZE);
/* UART */
IT8XXX2_ECPM_SCDCR1 = pll->div_uart;
/* SSPI and SMB */
IT8XXX2_ECPM_SCDCR2 = (pll->div_sspi << 4) | pll->div_smb;
/* USBPD and PWM */
IT8XXX2_ECPM_SCDCR4 = (pll->div_usbpd << 4) | pll->div_pwm;
}
static void chip_configure_pll(const struct pll_config_t *pll)
{
/* Re-configure PLL clock or not. */
if (((IT8XXX2_ECPM_PLLFREQR & 0xf) != pll->pll_freq) ||
((IT8XXX2_ECPM_SCDCR0 & 0xf0) != (pll->div_fnd << 4)) ||
((IT8XXX2_ECPM_SCDCR3 & 0xf) != pll->div_ec)) {
#ifdef CONFIG_ESPI
/*
* TODO: implement me
* We have to disable eSPI pad before changing
* PLL sequence or sequence will fail if CS# pin is low.
*/
#endif
/* Run change PLL sequence */
chip_run_pll_sequence(pll);
#ifdef CONFIG_ESPI
/*
* TODO: implement me
* Enable eSPI pad after changing PLL sequence
*/
#endif
}
}
static int chip_change_pll(const struct device *dev)
{
ARG_UNUSED(dev);
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
ite_intc_save_and_disable_interrupts();
}
/* configure PLL/CPU/flash clock */
chip_configure_pll(&pll_configuration[0]);
if (IS_ENABLED(CONFIG_ITE_IT8XXX2_INTC)) {
ite_intc_restore_interrupts();
}
return 0;
}
SYS_INIT(chip_change_pll, POST_KERNEL, 0);
#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */
static int ite_it8xxx2_init(const struct device *arg)
{