diff options
author | Dino Li <Dino.Li@ite.com.tw> | 2016-06-07 10:02:02 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-06-14 22:00:58 -0700 |
commit | 43552fb3f596573e0c633ad20fb313c21ddb281f (patch) | |
tree | 51e58abbf6a2b62f589b972b6c34e7fce1a6d564 | |
parent | 4bb0efcc28d5c13721867f0bca1bfd3db68268b4 (diff) | |
download | chrome-ec-43552fb3f596573e0c633ad20fb313c21ddb281f.tar.gz |
it83xx: Support different PLL frequencies setting (24/48/96 MHz)
Default setting is at 48MHz.
For PLL frequency at 24MHz:
1. USB module can't work, it requires 48MHz to work.
2. SSPI clock frequency is divide by two.
Signed-off-by: Dino Li <dino.li@ite.com.tw>
BRANCH=none
BUG=none
TEST=1. uart, i2c, timer, and pd modules are function normally
at different PLL frequency settings.
2. use 'flashrom' utility to flash EC binary with different
PLL settings.
Change-Id: Iabce4726baff493a6136136af18732b58df45d7f
Reviewed-on: https://chromium-review.googlesource.com/347551
Commit-Ready: Dino Li <Dino.Li@ite.com.tw>
Tested-by: Dino Li <Dino.Li@ite.com.tw>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | chip/it83xx/clock.c | 161 | ||||
-rw-r--r-- | chip/it83xx/hwtimer.c | 9 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 2 | ||||
-rw-r--r-- | chip/it83xx/spi.c | 3 | ||||
-rw-r--r-- | chip/it83xx/uart.c | 7 | ||||
-rw-r--r-- | core/nds32/cpu.c | 8 | ||||
-rw-r--r-- | core/nds32/ec.lds.S | 5 | ||||
-rw-r--r-- | driver/tcpm/it83xx.c | 2 |
8 files changed, 161 insertions, 36 deletions
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c index 2e5bdca1d2..a63a86ec0a 100644 --- a/chip/it83xx/clock.c +++ b/chip/it83xx/clock.c @@ -65,16 +65,153 @@ static void clock_module_disable(void) CGC_OFFSET_USB), 0, 0); } +enum pll_freq_idx { + PLL_24_MHZ = 1, + PLL_48_MHZ = 2, + PLL_96_MHZ = 4, +}; + +static const uint8_t pll_to_idx[8] = { + 0, + 0, + PLL_24_MHZ, + 0, + PLL_48_MHZ, + 0, + 0, + PLL_96_MHZ +}; + +struct clock_pll_t { + int pll_freq; + uint8_t pll_setting; + uint8_t div_fnd; + uint8_t div_uart; + uint8_t div_usb; + uint8_t div_smb; + uint8_t div_sspi; + uint8_t div_ec; + uint8_t div_jtag; + uint8_t div_pwm; + uint8_t div_usbpd; +}; + +const struct clock_pll_t clock_pll_ctrl[] = { + /* + * UART: 24MHz + * SMB: 24MHz + * EC: 8MHz + * JTAG: 24MHz + * USBPD: 8MHz + * USB: 48MHz(no support if PLL=24MHz) + * SSPI: 48MHz(24MHz if PLL=24MHz) + */ + /* PLL:24MHz, MCU:24MHz, Fnd(e-flash):24MHz */ + [PLL_24_MHZ] = {24000000, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0x2}, + /* PLL:48MHz, MCU:48MHz, Fnd:24MHz */ + [PLL_48_MHZ] = {48000000, 4, 1, 1, 0, 1, 0, 2, 1, 0, 0x5}, + /* PLL:96MHz, MCU:96MHz, Fnd:32MHz */ + [PLL_96_MHZ] = {96000000, 7, 2, 3, 1, 3, 1, 4, 3, 1, 0xb}, +}; + +static uint8_t pll_div_fnd; +static uint8_t pll_div_ec; +static uint8_t pll_div_jtag; +static uint8_t pll_setting; + +void __ram_code clock_ec_pll_ctrl(enum ec_pll_ctrl mode) +{ + IT83XX_ECPM_PLLCTRL = mode; + /* for deep doze / sleep mode */ + IT83XX_ECPM_PLLCTRL = mode; + asm volatile ("dsb"); +} + +void __ram_code clock_pll_changed(void) +{ + IT83XX_GCTRL_SSCR &= ~(1 << 0); + /* + * Update PLL settings. + * Writing data to this register 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 set up a HW timer to wakeup EC to + * complete PLL update. + */ + IT83XX_ECPM_PLLFREQR = pll_setting; + /* Pre-set FND clock frequency = PLL / 3 */ + IT83XX_ECPM_SCDCR0 = (2 << 4); + /* JTAG and EC */ + IT83XX_ECPM_SCDCR3 = (pll_div_jtag << 4) | pll_div_ec; + /* EC sleep after stanbdy instructioin */ + clock_ec_pll_ctrl(EC_PLL_SLEEP); + /* Global interrupt enable */ + asm volatile ("setgie.e"); + /* EC sleep */ + asm("standby wake_grant"); + /* Global interrupt disable */ + asm volatile ("setgie.d"); + /* New FND clock frequency */ + IT83XX_ECPM_SCDCR0 = (pll_div_fnd << 4); + /* EC doze after stanbdy instructioin */ + clock_ec_pll_ctrl(EC_PLL_DOZE); +} + +/* NOTE: Don't use this function in other place. */ +static void clock_set_pll(enum pll_freq_idx idx) +{ + int pll; + + pll_div_fnd = clock_pll_ctrl[idx].div_fnd; + pll_div_ec = clock_pll_ctrl[idx].div_ec; + pll_div_jtag = clock_pll_ctrl[idx].div_jtag; + pll_setting = clock_pll_ctrl[idx].pll_setting; + + /* Update PLL settings or not */ + if (((IT83XX_ECPM_PLLFREQR & 0xf) != pll_setting) || + ((IT83XX_ECPM_SCDCR0 & 0xf0) != (pll_div_fnd << 4)) || + ((IT83XX_ECPM_SCDCR3 & 0xf) != pll_div_ec)) { + /* Enable hw timer to wakeup EC from the sleep mode */ + ext_timer_ms(LOW_POWER_EXT_TIMER, EXT_PSR_32P768K_HZ, + 1, 1, 5, 1, 0); + task_clear_pending_irq(et_ctrl_regs[LOW_POWER_EXT_TIMER].irq); + /* Update PLL settings. */ + clock_pll_changed(); + } + + /* Get new/current setting of PLL frequency */ + pll = pll_to_idx[IT83XX_ECPM_PLLFREQR & 0xf]; + /* USB and UART */ + IT83XX_ECPM_SCDCR1 = (clock_pll_ctrl[pll].div_usb << 4) | + clock_pll_ctrl[pll].div_uart; + /* SSPI and SMB */ + IT83XX_ECPM_SCDCR2 = (clock_pll_ctrl[pll].div_sspi << 4) | + clock_pll_ctrl[pll].div_smb; + /* USBPD and PWM */ + IT83XX_ECPM_SCDCR4 = (clock_pll_ctrl[pll].div_usbpd << 4) | + clock_pll_ctrl[pll].div_pwm; + /* Current PLL frequency */ + freq = clock_pll_ctrl[pll].pll_freq; +} + void clock_init(void) { -#if PLL_CLOCK == 48000000 - /* Set PLL frequency to 48MHz. */ - IT83XX_ECPM_PLLFREQR = 0x04; - freq = PLL_CLOCK; + uint32_t image_type = (uint32_t)clock_init; + + /* To change interrupt vector base if at RW image */ + if (image_type > CONFIG_RW_MEM_OFF) + /* Interrupt Vector Table Base Address, in 64k Byte unit */ + IT83XX_GCTRL_IVTBAR = (CONFIG_RW_MEM_OFF >> 16) & 0xFF; + +#if (PLL_CLOCK == 24000000) || \ + (PLL_CLOCK == 48000000) || \ + (PLL_CLOCK == 96000000) + /* Set PLL frequency */ + clock_set_pll(PLL_CLOCK / 24000000); #else -#error "Support only for PLL clock speed of 48MHz." +#error "Support only for PLL clock speed of 24/48/96MHz." #endif - /* * The VCC power status is treated as power-on. * The VCC supply of LPC and related functions (EC2I, @@ -89,7 +226,7 @@ void clock_init(void) IT83XX_ECPM_AUTOCG = 0x00; /* Default doze mode */ - IT83XX_ECPM_PLLCTRL = EC_PLL_DOZE; + clock_ec_pll_ctrl(EC_PLL_DOZE); clock_module_disable(); @@ -201,19 +338,11 @@ static int clock_allow_low_power_idle(void) return 1; } -static void clock_ec_pll_ctrl(enum ec_pll_ctrl mode) -{ - IT83XX_ECPM_PLLCTRL = mode; - /* for deep doze / sleep mode */ - IT83XX_ECPM_PLLCTRL = mode; - asm volatile ("dsb"); -} - void clock_sleep_mode_wakeup_isr(void) { uint32_t st_us, c; - if (IT83XX_ECPM_PLLCTRL != EC_PLL_DOZE) { + if (IT83XX_ECPM_PLLCTRL == EC_PLL_DEEP_DOZE) { clock_ec_pll_ctrl(EC_PLL_DOZE); /* update free running timer */ diff --git a/chip/it83xx/hwtimer.c b/chip/it83xx/hwtimer.c index 72e9fc7e81..aa21092e40 100644 --- a/chip/it83xx/hwtimer.c +++ b/chip/it83xx/hwtimer.c @@ -203,6 +203,15 @@ static void __hw_clock_source_irq(void) free_run_timer_overflow(); return; } + + /* + * This interrupt is used to wakeup EC from sleep mode + * to complete PLL frequency change. + */ + if (irq == et_ctrl_regs[LOW_POWER_EXT_TIMER].irq) { + ext_timer_stop(LOW_POWER_EXT_TIMER, 1); + return; + } } DECLARE_IRQ(CPU_INT_GROUP_3, __hw_clock_source_irq, 1); diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index 615674a5d7..b46151cbdb 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -10,6 +10,8 @@ #include "common.h" +#define __ram_code __attribute__((section(".ram_code"))) + /* IRQ numbers */ /* Group 0 */ #define IT83XX_IRQ_WKO20 1 diff --git a/chip/it83xx/spi.c b/chip/it83xx/spi.c index 6e876b3aee..8e8ebf47d6 100644 --- a/chip/it83xx/spi.c +++ b/chip/it83xx/spi.c @@ -37,9 +37,6 @@ enum sspi_ch_sel { static void sspi_frequency(enum sspi_clk_sel freq) { - /* SSPI clock frequency select 48MHz (clk_sspi) */ - IT83XX_ECPM_SCDCR2 &= ~0xF0; - /* * bit[6:5] * Bit 6:Clock Polarity (CLPOL) diff --git a/chip/it83xx/uart.c b/chip/it83xx/uart.c index d6bb08fbc1..91624d4930 100644 --- a/chip/it83xx/uart.c +++ b/chip/it83xx/uart.c @@ -125,18 +125,11 @@ DECLARE_IRQ(CPU_INT_GROUP_9, intc_cpu_int_group_9, 1); static void uart_config(void) { -#if PLL_CLOCK == 48000000 - /* Set CLK_UART_DIV_SEL to /2. Assumes PLL is 48 MHz. */ - IT83XX_ECPM_SCDCR1 |= 0x01; - /* * Specify clock source of the UART is 24MHz, * must match CLK_UART_DIV_SEL. */ IT83XX_UART_CSSR(UART_PORT) = 0x01; -#else -#error "Support only for PLL clock speed of 48MHz." -#endif /* 8-N-1 and DLAB set to allow access to DLL and DLM registers. */ IT83XX_UART_LCR(UART_PORT) = 0x83; diff --git a/core/nds32/cpu.c b/core/nds32/cpu.c index 7a8a043656..3db4be3f19 100644 --- a/core/nds32/cpu.c +++ b/core/nds32/cpu.c @@ -11,14 +11,6 @@ void cpu_init(void) { /* DLM initialization is done in init.S */ - - uint32_t image_type = (uint32_t)cpu_init; - - /* To change interrupt vector base if at RW image */ - if (image_type > CONFIG_RW_MEM_OFF) - /* Interrupt Vector Table Base Address, in 64k Byte unit */ - IT83XX_GCTRL_IVTBAR = (CONFIG_RW_MEM_OFF >> 16) & 0xFF; - /* Global interrupt enable */ asm volatile ("setgie.e"); } diff --git a/core/nds32/ec.lds.S b/core/nds32/ec.lds.S index 0d91c6d6e4..adff240325 100644 --- a/core/nds32/ec.lds.S +++ b/core/nds32/ec.lds.S @@ -40,6 +40,11 @@ SECTIONS . = ALIGN(CONFIG_IT83XX_ILM_BLOCK_SIZE); __flash_dma_start = .; KEEP(*(.flash_direct_map)) + . = ALIGN(16); + KEEP(*(.ram_code)) + __flash_dma_size = . - __flash_dma_start; + ASSERT((__flash_dma_size < CONFIG_IT83XX_ILM_BLOCK_SIZE), + "__flash_dma_size < CONFIG_IT83XX_ILM_BLOCK_SIZE"); . = ALIGN(CONFIG_IT83XX_ILM_BLOCK_SIZE); } > FLASH . = ALIGN(4); diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c index 3bc0c0db32..ed871edd02 100644 --- a/driver/tcpm/it83xx.c +++ b/driver/tcpm/it83xx.c @@ -262,8 +262,6 @@ static void it83xx_set_data_role(enum usbpd_port port, int pd_role) static void it83xx_init(enum usbpd_port port, int role) { - /* defalut PD Clock = PLL 48 / 6 = 8M. */ - IT83XX_ECPM_SCDCR4 = (IT83XX_ECPM_SCDCR4 & 0xf0) | 5; /* reset */ IT83XX_USBPD_GCR(port) = 0; USBPD_SW_RESET(port); |