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>
This commit is contained in:
Dino Li
2016-06-07 10:02:02 +08:00
committed by chrome-bot
parent 4bb0efcc28
commit 43552fb3f5
8 changed files with 162 additions and 37 deletions

View File

@@ -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;
#else
#error "Support only for PLL clock speed of 48MHz."
#endif
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 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 */

View File

@@ -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);

View File

@@ -10,6 +10,8 @@
#include "common.h"
#define __ram_code __attribute__((section(".ram_code")))
/* IRQ numbers */
/* Group 0 */
#define IT83XX_IRQ_WKO20 1

View File

@@ -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)

View File

@@ -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;

View File

@@ -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");
}

View File

@@ -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);

View File

@@ -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);