diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2017-04-25 17:34:42 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-04-25 21:19:57 -0700 |
commit | 4123b5861e359318b1caf48b03f4751608a4122a (patch) | |
tree | ce3fa7769ef94d7b5a4fb7b7583a1e1f29eda1ce | |
parent | aa5578e64cc117ced4ad6107210aac3e11360a93 (diff) | |
download | chrome-ec-4123b5861e359318b1caf48b03f4751608a4122a.tar.gz |
npcx: clock: uart: Add support for npcx7 series ec.
In old clock driver, the relationships between each clock sources are
ambiguous. For example, we treat OSC_CLK and FM_CLK as the same but
sometimes they're not on npcx5. (Only one OSC_CLK definition cannot
present the npcx ec's clock tree very well.) This CL added FM_CLK,
CORE_CLK, and APBx_CLK definitions and used macro functions to confine
the limitation of each clock sources in clock_chip.h to make it more
clearly.
We also modified the uart driver and fixed its source clock to 15MHz so
far in this CL. Since npcx7 already supports uart wake-up mechanism, we
removed the functions of switching pins from UART to GPIO by CHIP_FAMILY
definitions for saving code space.
It also includes:
1. Remove useless CHIP_VERSION definition.
2. Move frequency multiplier values M/N for OSC_CLK to clock_chip.h
3. Add clock_get_fm_freq() for the modules rely on it. Ex, peci.
4. Add clock turbo utilities for npcx7 series.
5. Support uart wake-up mechanism for npcx7 series.
BRANCH=none
BUG=none
TEST=No build errors for all boards using npcx5 series.
Build poppy board and upload FW to platform. No issues found.
Passed clock turbo, sysjump and wake-up from UART signals stress
tests on npcx796f evb.
Change-Id: Id01a8a5d0263f0d2438e6346dfa33bcdef2be56e
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/486821
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r-- | chip/npcx/clock.c | 136 | ||||
-rw-r--r-- | chip/npcx/clock_chip.h | 147 | ||||
-rw-r--r-- | chip/npcx/registers.h | 11 | ||||
-rw-r--r-- | chip/npcx/uart.c | 45 |
4 files changed, 236 insertions, 103 deletions
diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c index 34a9b6a726..17885b40e4 100644 --- a/chip/npcx/clock.c +++ b/chip/npcx/clock.c @@ -29,36 +29,6 @@ #define WAKE_INTERVAL 61 /* Unit: 61 usec */ #define IDLE_PARAMS 0x7 /* Support deep idle, instant wake-up */ -/* - * Frequency multiplier values definition according to the requested - * PLL_CLOCK Clock Frequency - */ -#define HFCGN 0x02 -#if (OSC_CLK == 50000000) -#define HFCGMH 0x0B -#define HFCGML 0xEC -#elif (OSC_CLK == 48000000) -#define HFCGMH 0x0B -#define HFCGML 0x72 -#elif (OSC_CLK == 40000000) -#define HFCGMH 0x09 -#define HFCGML 0x89 -#elif (OSC_CLK == 33000000) -#define HFCGMH 0x07 -#define HFCGML 0xDE -#elif (OSC_CLK == 24000000) -#define HFCGMH 0x0B -#define HFCGML 0x71 -#elif (OSC_CLK == 15000000) -#define HFCGMH 0x07 -#define HFCGML 0x27 -#elif (OSC_CLK == 13000000) -#define HFCGMH 0x06 -#define HFCGML 0x33 -#else -#error "Unsupported FMCLK Clock Frequency" -#endif - /* Low power idle statistics */ #ifdef CONFIG_LOW_POWER_IDLE static int idle_sleep_cnt; @@ -73,11 +43,6 @@ static int console_in_use_timeout_sec = 15; static timestamp_t console_expire_time; #endif - -static int freq; - -/* Low power idle statistics */ - /** * Enable clock to peripheral by setting the CGC register pertaining * to run, sleep, and/or deep sleep modes. @@ -124,8 +89,8 @@ void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode) void clock_init(void) { /* - * Configure Frequency multiplier values according to the requested - * FMCLK Clock Frequency + * Configure frequency multiplier M/N values according to + * the requested OSC_CLK (Unit:Hz). */ NPCX_HFCGN = HFCGN; NPCX_HFCGML = HFCGML; @@ -138,25 +103,17 @@ void clock_init(void) while (IS_BIT_SET(NPCX_HFCGCTRL, NPCX_HFCGCTRL_CLK_CHNG)) ; - /* Keep FMCLK in 33-50 MHz which is tested strictly. */ -#if (OSC_CLK >= 33000000) - /* Keep Core CLK & FMCLK are the same */ - NPCX_HFCGP = 0x00; -#else - /* Keep Core CLK = 0.5 * FMCLK */ - NPCX_HFCGP = 0x10; -#endif - - /* - * Let APB2 and Core CLK are equal if default APB2 clock isn't - * divisible by 1MHz - */ -#if (OSC_CLK % 2000000) - NPCX_HFCBCD = NPCX_HFCBCD & 0xF3; + /* Set all clock prescalers of core and peripherals. */ +#if defined(CHIP_FAMILY_NPCX5) + NPCX_HFCGP = (FPRED << 4); + NPCX_HFCBCD = (NPCX_HFCBCD & 0xF0) | (APB1DIV | (APB2DIV << 2)); +#elif defined(CHIP_FAMILY_NPCX7) + NPCX_HFCGP = ((FPRED << 4) | AHB6DIV); + NPCX_HFCBCD = (FIUDIV << 4); + NPCX_HFCBCD1 = (APB1DIV | (APB2DIV << 4)); + NPCX_HFCBCD2 = APB3DIV; #endif - freq = OSC_CLK; - /* Notify modules of frequency change */ hook_notify(HOOK_FREQ_CHANGE); @@ -164,10 +121,7 @@ void clock_init(void) gpio_config_module(MODULE_CLOCK, 1); } - -/** - * Set the CPU clock to maximum freq for better performance. - */ +#if defined(CHIP_FAMILY_NPCX5) void clock_turbo(void) { /* Configure Frequency multiplier values to 50MHz */ @@ -191,13 +145,39 @@ void clock_turbo(void) */ NPCX_HFCBCD = NPCX_HFCBCD & 0xF3; } +#elif defined(CHIP_FAMILY_NPCX7) +void clock_turbo(void) +{ + /* + * Increase CORE_CLK (CPU) as the same as OSC_CLK. Since + * CORE_CLK > 66MHz, we also need to set AHB6DIV and FIUDIV as 1. + */ + NPCX_HFCGP = 0x01; + NPCX_HFCBCD = (1 << 4); +} + +void clock_turbo_disable(void) +{ + /* Set CORE_CLK (CPU), AHB6_CLK and FIU_CLK back to original values. */ + NPCX_HFCGP = ((FPRED << 4) | AHB6DIV); + NPCX_HFCBCD = (FIUDIV << 4); +} +#endif /** * Return the current clock frequency in Hz. */ int clock_get_freq(void) { - return freq; + return CORE_CLK; +} + +/** + * Return the current FMUL clock frequency in Hz. + */ +int clock_get_fm_freq(void) +{ + return FMCLK; } /** @@ -205,8 +185,7 @@ int clock_get_freq(void) */ int clock_get_apb1_freq(void) { - int apb1_div = (NPCX_HFCBCD & 0x03) + 1; - return freq/apb1_div; + return NPCX_APB_CLOCK(1); } /** @@ -214,11 +193,20 @@ int clock_get_apb1_freq(void) */ int clock_get_apb2_freq(void) { - int apb2_div = ((NPCX_HFCBCD>>2) & 0x03) + 1; - return freq/apb2_div; + return NPCX_APB_CLOCK(2); } /** + * Return the current APB3 clock frequency in Hz. + */ +#if defined(CHIP_FAMILY_NPCX7) +int clock_get_apb3_freq(void) +{ + return NPCX_APB_CLOCK(3); +} +#endif + +/** * Wait for a number of clock cycles. * * Simple busy waiting for use before clocks/timers are initialized. @@ -240,6 +228,7 @@ void clock_refresh_console_in_use(void) return; } +#if defined(CHIP_FAMILY_NPCX5) void clock_uart2gpio(void) { /* Is pimux to UART? */ @@ -271,20 +260,11 @@ void clock_gpio2uart(void) task_enable_irq(NPCX_IRQ_UART); } } +#endif /* Idle task. Executed when no tasks are ready to be scheduled. */ void __idle(void) { -#if (CHIP_VERSION < 3) - while (1) { - /* - * TODO:(ML) JTAG bug: if debugger is connected, - * CPU can't enter wfi. Rev A3 will fix it. - */ - ; - }; -#else - timestamp_t t0, t1; uint32_t next_evt; uint32_t next_evt_us; @@ -334,8 +314,15 @@ void __idle(void) /* Enable Host access wakeup */ SET_BIT(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_5), 6); +#if defined(CHIP_FAMILY_NPCX5) /* UART-rx(console) become to GPIO (NONE INT mode) */ clock_uart2gpio(); +#elif defined(CHIP_FAMILY_NPCX7) + /* Clear pending bit before enable uart wake-up */ + SET_BIT(NPCX_WKPCL(MIWU_TABLE_1, MIWU_GROUP_8), 7); + /* Enable UART wake-up and interrupt request */ + SET_BIT(NPCX_WKEN(MIWU_TABLE_1, MIWU_GROUP_8), 7); +#endif /* Set deep idle - instant wake-up mode */ NPCX_PMCSR = IDLE_PARAMS; @@ -364,8 +351,10 @@ void __idle(void) * setting it and wfi. */ NPCX_PMCSR = 0; +#if defined(CHIP_FAMILY_NPCX5) /* GPIO back to UART-rx (console) */ clock_gpio2uart(); +#endif /* Record time spent in deep sleep. */ idle_dsleep_time_us += next_evt_us; @@ -401,7 +390,6 @@ void __idle(void) */ interrupt_enable(); } -#endif } #endif /* CONFIG_LOW_POWER_IDLE */ diff --git a/chip/npcx/clock_chip.h b/chip/npcx/clock_chip.h index d1ad63bdcc..30c4965516 100644 --- a/chip/npcx/clock_chip.h +++ b/chip/npcx/clock_chip.h @@ -8,8 +8,141 @@ #ifndef __CROS_EC_CLOCK_CHIP_H #define __CROS_EC_CLOCK_CHIP_H -/* Default is 40MHz (target is 15MHz) */ -#define OSC_CLK 15000000 +/* + * EC clock tree plan: (Default OSC_CLK is 40MHz.) + * + * Target OSC_CLK for NPCX7 is 90MHz, FMCLK is 45MHz, CPU and APBs is 15MHz. + * Target OSC_CLK for NPCX5 is 30MHz, FMCLK is 30MHz, CPU and APBs is 15MHz. + */ +#if defined(CHIP_FAMILY_NPCX5) +/* + * NPCX5 clock tree: (Please refer Figure 55. for more information.) + * + * Suggestion: + * - OSC_CLK >= 30MHz, FPRED should be 1, else 0. + * (Keep FMCLK in 30-50 MHz possibly which is tested strictly.) + */ +/* Target OSC_CLK freq */ +#define OSC_CLK 30000000 +/* Core clock prescaler */ +#if (OSC_CLK >= 30000000) +#define FPRED 1 /* CORE_CLK = OSC_CLK(FMCLK)/2 */ +#else +#define FPRED 0 /* CORE_CLK = OSC_CLK(FMCLK) */ +#endif +/* Core domain clock */ +#define CORE_CLK (OSC_CLK / (FPRED + 1)) +/* FMUL clock */ +#define FMCLK OSC_CLK +/* APBs source clock */ +#define APBSRC_CLK CORE_CLK +/* APB1 clock divider */ +#define APB1DIV 3 /* Default APB1 clock = CORE_CLK/4 */ +/* APB2 clock divider */ +#define APB2DIV 0 /* Let APB2 = CORE_CLK since UART baudrate tolerance */ +#elif defined(CHIP_FAMILY_NPCX7) +/* + * NPCX7 clock tree: (Please refer Figure 58. for more information.) + * + * Suggestion: + * - OSC_CLK >= 80MHz, XF_RANGE should be 1, else 0. + * - CORE_CLK > 66MHz, AHB6DIV should be 1, else 0. + * - CORE_CLK > 50MHz, FIUDIV should be 1, else 0. + */ +/* Target OSC_CLK freq */ +#define OSC_CLK 90000000 +/* Core clock prescaler */ +#define FPRED 5 /* CORE_CLK = OSC_CLK/6 */ +/* Core domain clock */ +#define CORE_CLK (OSC_CLK / (FPRED + 1)) +/* FMUL clock */ +#if (OSC_CLK >= 80000000) +#define FMCLK (OSC_CLK / 2) /* FMUL clock = OSC_CLK/2 if OSC_CLK >= 80MHz */ +#else +#define FMCLK OSC_CLK /* FMUL clock = OSC_CLK */ +#endif +/* AHB6 clock */ +#if (CORE_CLK > 66000000) +#define AHB6DIV 1 /* AHB6_CLK = CORE_CLK/2 if CORE_CLK > 66MHz */ +#else +#define AHB6DIV 0 /* AHB6_CLK = CORE_CLK */ +#endif +/* FIU clock divider */ +#if (CORE_CLK > 50000000) +#define FIUDIV 1 /* FIU_CLK = CORE_CLK/2 */ +#else +#define FIUDIV 0 /* FIU_CLK = CORE_CLK */ +#endif +/* APBs source clock */ +#define APBSRC_CLK OSC_CLK +/* APB1 clock divider */ +#define APB1DIV 5 /* APB1 clock = OSC_CLK/6 */ +/* APB2 clock divider */ +#define APB2DIV 5 /* APB2 clock = OSC_CLK/6 */ +/* APB3 clock divider */ +#define APB3DIV 5 /* APB3 clock = OSC_CLK/6 */ +#endif + +/* Get APB clock freq */ +#define NPCX_APB_CLOCK(no) (APBSRC_CLK / (APB##no##DIV + 1)) + +/* + * Frequency multiplier M/N value definitions according to the requested + * OSC_CLK (Unit:Hz). + */ +#if (OSC_CLK > 80000000) +#define HFCGN 0x82 /* Set XF_RANGE as 1 if OSC_CLK >= 80MHz */ +#else +#define HFCGN 0x02 +#endif +#if (OSC_CLK == 100000000) +#define HFCGMH 0x0B +#define HFCGML 0xEC +#elif (OSC_CLK == 90000000) +#define HFCGMH 0x0A +#define HFCGML 0xBA +#elif (OSC_CLK == 80000000) +#define HFCGMH 0x09 +#define HFCGML 0x89 +#elif (OSC_CLK == 66000000) +#define HFCGMH 0x0F +#define HFCGML 0xBC +#elif (OSC_CLK == 50000000) +#define HFCGMH 0x0B +#define HFCGML 0xEC +#elif (OSC_CLK == 48000000) +#define HFCGMH 0x0B +#define HFCGML 0x72 +#elif (OSC_CLK == 40000000) +#define HFCGMH 0x09 +#define HFCGML 0x89 +#elif (OSC_CLK == 33000000) +#define HFCGMH 0x07 +#define HFCGML 0xDE +#elif (OSC_CLK == 30000000) +#define HFCGMH 0x07 +#define HFCGML 0x27 +#elif (OSC_CLK == 26000000) +#define HFCGMH 0x06 +#define HFCGML 0x33 +#else +#error "Unsupported OSC_CLK Frequency" +#endif + +#if defined(CHIP_FAMILY_NPCX5) +#if (OSC_CLK > 50000000) +#error "Unsupported OSC_CLK on NPCX5 series!" +#endif +#elif defined(CHIP_FAMILY_NPCX7) +#if (OSC_CLK > 100000000) +#error "Unsupported OSC_CLK on NPCX7 series!" +#endif +#endif + +/** + * Return the current FMUL clock frequency in Hz. + */ +int clock_get_fm_freq(void); /** * Return the current APB1 clock frequency in Hz. @@ -22,8 +155,18 @@ int clock_get_apb1_freq(void); int clock_get_apb2_freq(void); /** + * Return the current APB3 clock frequency in Hz. + */ +int clock_get_apb3_freq(void); + +/** * Set the CPU clock to maximum freq for better performance. */ void clock_turbo(void); +/** + * Set the CPU clock back to normal freq. + */ +void clock_turbo_disable(void); + #endif /* __CROS_EC_CLOCK_CHIP_H */ diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index c08bd5d614..dc57852de4 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -43,7 +43,6 @@ */ /* Global Definition */ -#define CHIP_VERSION 3 /* A3 version */ #define I2C_7BITS_ADDR 0 /* Switcher of features */ #define SUPPORT_LCT 1 @@ -251,6 +250,10 @@ #define NPCX_HFCGN REG8(NPCX_HFCG_BASE_ADDR + 0x006) #define NPCX_HFCGP REG8(NPCX_HFCG_BASE_ADDR + 0x008) #define NPCX_HFCBCD REG8(NPCX_HFCG_BASE_ADDR + 0x010) +#if defined(CHIP_FAMILY_NPCX7) +#define NPCX_HFCBCD1 REG8(NPCX_HFCG_BASE_ADDR + 0x012) +#define NPCX_HFCBCD2 REG8(NPCX_HFCG_BASE_ADDR + 0x014) +#endif /* HFCG register fields */ #define NPCX_HFCGCTRL_LOAD 0 @@ -1645,6 +1648,7 @@ enum { /******************************************************************************/ /* Inline functions */ /* This routine checks pending bit of GPIO wake-up functionality */ +#if defined(CHIP_FAMILY_NPCX5) static inline int uart_is_wakeup_from_gpio(void) { #if NPCX_UART_MODULE2 @@ -1705,6 +1709,7 @@ static inline void npcx_uart2gpio(void) CLEAR_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1); #endif } +#endif /* This routine switches the functionality from GPIO to UART rx */ static inline void npcx_gpio2uart(void) @@ -1713,6 +1718,10 @@ static inline void npcx_gpio2uart(void) CLEAR_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1); SET_BIT(NPCX_DEVALT(0x0C), NPCX_DEVALTC_UART_SL2); #else +#if defined(CHIP_FAMILY_NPCX7) + /* UART module 1 belongs to KSO since wake-up functionality in npcx7. */ + CLEAR_BIT(NPCX_DEVALT(0x09), NPCX_DEVALT9_NO_KSO09_SL); +#endif SET_BIT(NPCX_DEVALT(0x0A), NPCX_DEVALTA_UART_SL1); #endif } diff --git a/chip/npcx/uart.c b/chip/npcx/uart.c index 7aa0dacb6d..eb6f6a4920 100644 --- a/chip/npcx/uart.c +++ b/chip/npcx/uart.c @@ -26,6 +26,8 @@ int uart_init_done(void) void uart_tx_start(void) { + /* We needn't to switch uart from gpio again in npcx7. */ +#if defined(CHIP_FAMILY_NPCX5) if (uart_is_enable_wakeup()) { /* disable MIWU */ uart_enable_wakeup(0); @@ -34,6 +36,7 @@ void uart_tx_start(void) /* enable uart again from MIWU mode */ task_enable_irq(NPCX_IRQ_UART); } +#endif /* If interrupt is already enabled, nothing to do */ if (NPCX_UICTRL & 0x20) @@ -132,45 +135,35 @@ void uart_ec_interrupt(void) } DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 0); - static void uart_config(void) { /* Configure pins from GPIOs to CR_UART */ gpio_config_module(MODULE_UART, 1); - /* Enable MIWU IRQ of UART*/ + + /* Enable MIWU IRQ of UART */ #if NPCX_UART_MODULE2 task_enable_irq(NPCX_IRQ_WKINTG_1); #else task_enable_irq(NPCX_IRQ_WKINTB_1); - +#endif + /* + * Configure the UART wake-up event triggered from a falling edge + * on CR_SIN pin. + */ +#if defined(CHIP_FAMILY_NPCX7) && defined(CONFIG_LOW_POWER_IDLE) + SET_BIT(NPCX_WKEDG(MIWU_TABLE_1, MIWU_GROUP_8), 7); +#endif + /* + * If apb2's clock is not 15MHz, we need to find the other optimized + * values of UPSR and UBAUD for baud rate 115200. + */ +#if (NPCX_APB_CLOCK(2) != 15000000) +#error "Unsupported apb2 clock for UART!" #endif /* Fix baud rate to 115200 */ -#if (OSC_CLK == 50000000) - NPCX_UPSR = 0x10; - NPCX_UBAUD = 0x08; -#elif (OSC_CLK == 48000000) - NPCX_UPSR = 0x08; - NPCX_UBAUD = 0x0C; -#elif (OSC_CLK == 40000000) - NPCX_UPSR = 0x30; - NPCX_UBAUD = 0x02; -#elif (OSC_CLK == 33000000) /* APB2 is the same as core clock */ - NPCX_UPSR = 0x08; - NPCX_UBAUD = 0x11; -#elif (OSC_CLK == 24000000) - NPCX_UPSR = 0x60; - NPCX_UBAUD = 0x00; -#elif (OSC_CLK == 15000000) /* APB2 is the same as core clock */ NPCX_UPSR = 0x38; NPCX_UBAUD = 0x01; -#elif (OSC_CLK == 13000000) /* APB2 is the same as core clock */ - NPCX_UPSR = 0x30; - NPCX_UBAUD = 0x01; -#else -#error "Unsupported Core Clock Frequency" -#endif - /* * 8-N-1, FIFO enabled. Must be done after setting |