mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-09 00:51:29 +00:00
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:
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define __ram_code __attribute__((section(".ram_code")))
|
||||
|
||||
/* IRQ numbers */
|
||||
/* Group 0 */
|
||||
#define IT83XX_IRQ_WKO20 1
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user