summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMulin Chao <mlchao@nuvoton.com>2017-04-25 17:34:42 +0800
committerchrome-bot <chrome-bot@chromium.org>2017-04-25 21:19:57 -0700
commit4123b5861e359318b1caf48b03f4751608a4122a (patch)
treece3fa7769ef94d7b5a4fb7b7583a1e1f29eda1ce
parentaa5578e64cc117ced4ad6107210aac3e11360a93 (diff)
downloadchrome-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.c136
-rw-r--r--chip/npcx/clock_chip.h147
-rw-r--r--chip/npcx/registers.h11
-rw-r--r--chip/npcx/uart.c45
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