diff options
-rw-r--r-- | board/npcx7_evb/board.h | 9 | ||||
-rw-r--r-- | board/npcx7_evb/gpio.inc | 8 | ||||
-rw-r--r-- | chip/npcx/build.mk | 2 | ||||
-rw-r--r-- | chip/npcx/clock.c | 6 | ||||
-rw-r--r-- | chip/npcx/config_chip-npcx5.h | 4 | ||||
-rw-r--r-- | chip/npcx/config_chip-npcx7.h | 5 | ||||
-rw-r--r-- | chip/npcx/config_chip.h | 2 | ||||
-rw-r--r-- | chip/npcx/gpio.c | 34 | ||||
-rw-r--r-- | chip/npcx/gpio_chip-npcx7.h | 22 | ||||
-rw-r--r-- | chip/npcx/gpio_chip.h | 6 | ||||
-rw-r--r-- | chip/npcx/registers.h | 71 | ||||
-rw-r--r-- | chip/npcx/uart.c | 218 | ||||
-rw-r--r-- | chip/npcx/uartn.c | 261 | ||||
-rw-r--r-- | chip/npcx/uartn.h | 63 |
14 files changed, 484 insertions, 227 deletions
diff --git a/board/npcx7_evb/board.h b/board/npcx7_evb/board.h index bcc9437270..9080615006 100644 --- a/board/npcx7_evb/board.h +++ b/board/npcx7_evb/board.h @@ -74,6 +74,15 @@ #endif /* Optional feature to configure npcx7 chip */ + +/* Select which UART Controller is the Console UART */ +#undef CONFIG_CONSOLE_UART +#define CONFIG_CONSOLE_UART 0 /* 0:UART1 1:UART2 */ +/* + * This definition below actually doesn't define which UART controller to be + * used. Instead, it defines which pinouts (GPIO10/11 or GPIO64/65) are + * connected to "UART1" controller. + */ #if (BOARD_VERSION == 2) #define NPCX_UART_MODULE2 1 /* 1:GPIO64/65 as UART1 */ #else diff --git a/board/npcx7_evb/gpio.inc b/board/npcx7_evb/gpio.inc index 2acec02f09..e0bb9c1df8 100644 --- a/board/npcx7_evb/gpio.inc +++ b/board/npcx7_evb/gpio.inc @@ -52,12 +52,18 @@ GPIO(BOARD_VERSION2, PIN(6, 5), GPIO_INPUT) GPIO(BOARD_VERSION3, PIN(6, 6), GPIO_INPUT) /*********************** Alternate pins for npcx7 series **********************/ -/* UART Tx/Rx */ +#if (CONFIG_CONSOLE_UART == 0) +/* UART1 Tx/Rx */ #if NPCX_UART_MODULE2 ALTERNATE(PIN_MASK(6, 0x30), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO64/65 */ #else ALTERNATE(PIN_MASK(1, 0x03), 1, MODULE_UART, 0) /* CR_SIN/SOUT GPIO10/11 */ #endif +#else +/* UART2 Tx/Rx */ +ALTERNATE(PIN_MASK(7, 0x20), 1, MODULE_UART, 0) /* CR_SIN2 GPIO75 */ +ALTERNATE(PIN_MASK(8, 0x40), 1, MODULE_UART, 0) /* CR_SOUT2 GPIO86 */ +#endif /* ADC */ ALTERNATE(PIN_MASK(4, 0x3E), 1, MODULE_ADC, 0) /* ADC0/1/2/3/4 GPIO45/44/43/42/41 */ diff --git a/chip/npcx/build.mk b/chip/npcx/build.mk index e4783439a3..166519db62 100644 --- a/chip/npcx/build.mk +++ b/chip/npcx/build.mk @@ -17,7 +17,7 @@ CHIP_FAMILY:=npcx5 endif # Required chip modules -chip-y=header.o clock.o gpio.o hwtimer.o system.o uart.o +chip-y=header.o clock.o gpio.o hwtimer.o system.o uart.o uartn.o chip-y+=system-$(CHIP_FAMILY).o # Optional chip modules diff --git a/chip/npcx/clock.c b/chip/npcx/clock.c index 9411959515..ca3ebf88d8 100644 --- a/chip/npcx/clock.c +++ b/chip/npcx/clock.c @@ -20,6 +20,7 @@ #include "task.h" #include "timer.h" #include "uart.h" +#include "uartn.h" #include "util.h" #include "watchdog.h" @@ -324,10 +325,7 @@ void __idle(void) /* 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); + uartn_wui_en(CONFIG_CONSOLE_UART); #endif /* diff --git a/chip/npcx/config_chip-npcx5.h b/chip/npcx/config_chip-npcx5.h index 9abe21d1c9..e1ad4923b8 100644 --- a/chip/npcx/config_chip-npcx5.h +++ b/chip/npcx/config_chip-npcx5.h @@ -15,6 +15,10 @@ /*****************************************************************************/ /* Hardware features */ + +/* Number of UART modules. */ +#define UART_MODULE_COUNT 1 + /* * Number of I2C controllers. Controller 0 has 2 ports, so the chip has one * additional port. diff --git a/chip/npcx/config_chip-npcx7.h b/chip/npcx/config_chip-npcx7.h index 93525fadc7..65668b7b38 100644 --- a/chip/npcx/config_chip-npcx7.h +++ b/chip/npcx/config_chip-npcx7.h @@ -28,6 +28,11 @@ #if defined(CHIP_VARIANT_NPCX7M6FB) || defined(CHIP_VARIANT_NPCX7M7WB) #define NPCX_UART_FIFO_SUPPORT +/* Number of UART modules. */ +#define NPCX_SECOND_UART +#define UART_MODULE_COUNT 2 +#else +#define UART_MODULE_COUNT 1 #endif #ifdef CHIP_VARIANT_NPCX7M7WB diff --git a/chip/npcx/config_chip.h b/chip/npcx/config_chip.h index 9dac257850..e956e4cf6a 100644 --- a/chip/npcx/config_chip.h +++ b/chip/npcx/config_chip.h @@ -69,6 +69,8 @@ /* Chip needs to do custom pre-init */ #define CONFIG_CHIP_PRE_INIT +/* Default use UART1 as console */ +#define CONFIG_CONSOLE_UART 0 #define GPIO_PIN(port, index) GPIO_##port, (1 << index) #define GPIO_PIN_MASK(p, m) .port = GPIO_##p, .mask = (m) diff --git a/chip/npcx/gpio.c b/chip/npcx/gpio.c index 01a0a6897f..cabda69b15 100644 --- a/chip/npcx/gpio.c +++ b/chip/npcx/gpio.c @@ -31,12 +31,6 @@ #define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) #endif -struct npcx_wui { - uint8_t table : 2; - uint8_t group : 3; - uint8_t bit : 3; -}; - /* Constants for GPIO interrupt mapping */ #define GPIO_INT(name, pin, flags, signal) NPCX_WUI_GPIO_##pin, #ifdef CONFIG_LOW_POWER_IDLE @@ -605,17 +599,35 @@ void __gpio_rtc_interrupt(void) /* Clear pending bit for WUI */ SET_BIT(NPCX_WKPCL(MIWU_TABLE_0, MIWU_GROUP_4), 7); host_set_single_event(EC_HOST_EVENT_RTC); - } else + return; + } #endif - { - gpio_interrupt(WUI_INT(MIWU_TABLE_0, MIWU_GROUP_1)); - gpio_interrupt(WUI_INT(MIWU_TABLE_0, MIWU_GROUP_4)); +#if defined(CHIP_FAMILY_NPCX7) && defined(CONFIG_LOW_POWER_IDLE) && \ + (CONFIG_CONSOLE_UART == 1) + /* Handle the interrupt from UART wakeup event */ + if (IS_BIT_SET(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_1), 6) && + IS_BIT_SET(NPCX_WKPND(MIWU_TABLE_0, MIWU_GROUP_1), 6)) { + /* + * Disable WKEN bit to avoid the other unnecessary interrupts + * from the coming data bits after the start bit. (Pending bit + * of CR_SIN is set when a high-to-low transaction occurs.) + */ + CLEAR_BIT(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_1), 6); + /* Clear pending bit for WUI */ + SET_BIT(NPCX_WKPCL(MIWU_TABLE_0, MIWU_GROUP_1), 6); + /* Notify the clock module that the console is in use. */ + clock_refresh_console_in_use(); + return; } +#endif + gpio_interrupt(WUI_INT(MIWU_TABLE_0, MIWU_GROUP_1)); + gpio_interrupt(WUI_INT(MIWU_TABLE_0, MIWU_GROUP_4)); } void __gpio_wk1h_interrupt(void) { -#if defined(CHIP_FAMILY_NPCX7) && defined(CONFIG_LOW_POWER_IDLE) +#if defined(CHIP_FAMILY_NPCX7) && defined(CONFIG_LOW_POWER_IDLE) && \ + (CONFIG_CONSOLE_UART == 0) /* Handle the interrupt from UART wakeup event */ if (IS_BIT_SET(NPCX_WKEN(MIWU_TABLE_1, MIWU_GROUP_8), 7) && IS_BIT_SET(NPCX_WKPND(MIWU_TABLE_1, MIWU_GROUP_8), 7)) { diff --git a/chip/npcx/gpio_chip-npcx7.h b/chip/npcx/gpio_chip-npcx7.h index e0081b761a..3511ad8ac2 100644 --- a/chip/npcx/gpio_chip-npcx7.h +++ b/chip/npcx/gpio_chip-npcx7.h @@ -229,11 +229,23 @@ /* UART Module 1/2 */ #if NPCX_UART_MODULE2 -#define NPCX_ALT_CR_SIN ALT(6, 4, NPCX_ALT(C, UART_SL2)) /* CR_SIN2 */ -#define NPCX_ALT_CR_SOUT ALT(6, 5, NPCX_ALT(C, UART_SL2)) /* CR_SOUT2 */ +/* CR_SIN Select 2 */ +#define NPCX_ALT_CR_SIN ALT(6, 4, NPCX_ALT(C, UART_SL2)) +/* CR_SOUT Select 2 */ +#define NPCX_ALT_CR_SOUT ALT(6, 5, NPCX_ALT(C, UART_SL2)) #else -#define NPCX_ALT_CR_SIN ALT(1, 0, NPCX_ALT_INV(9, NO_KSO08_SL)) /* CR_SIN */ -#define NPCX_ALT_CR_SOUT ALT(1, 1, NPCX_ALT_INV(9, NO_KSO09_SL)) /* CR_SOUT */ +/* CR_SIN Select 1 */ +#define NPCX_ALT_CR_SIN ALT(1, 0, NPCX_ALT_INV(9, NO_KSO08_SL)) +/* CR_SOUT Select 1 */ +#define NPCX_ALT_CR_SOUT ALT(1, 1, NPCX_ALT_INV(9, NO_KSO09_SL)) +#endif + +#ifdef NPCX_SECOND_UART +#define NPCX_ALT_CR_SIN2 ALT(7, 5, NPCX_ALT(A, UART2_SL)) /* CR_SIN2 */ +#define NPCX_ALT_CR_SOUT2 ALT(8, 6, NPCX_ALT(A, UART2_SL)) /* CR_SOUT2 */ +#else +#define NPCX_ALT_CR_SIN2 +#define NPCX_ALT_CR_SOUT2 #endif /* SPI Module */ @@ -370,6 +382,8 @@ NPCX_ALT_ADC9 \ NPCX_ALT_CR_SIN \ NPCX_ALT_CR_SOUT \ + NPCX_ALT_CR_SIN2 \ + NPCX_ALT_CR_SOUT2 \ NPCX_ALT_SPIP_MISO \ NPCX_ALT_SPIP_CS1 \ NPCX_ALT_SPIP_MOSI \ diff --git a/chip/npcx/gpio_chip.h b/chip/npcx/gpio_chip.h index 6d704a5e6a..6282794e44 100644 --- a/chip/npcx/gpio_chip.h +++ b/chip/npcx/gpio_chip.h @@ -6,6 +6,12 @@ #ifndef __CROS_EC_GPIO_CHIP_H #define __CROS_EC_GPIO_CHIP_H +struct npcx_wui { + uint8_t table : 2; + uint8_t group : 3; + uint8_t bit : 3; +}; + /* Macros to initialize the MIWU mapping table. */ #define NPCX_WUI_GPIO_PIN(port, index) NPCX_WUI_GPIO_##port##_##index #define WUI(tbl, grp, idx) ((struct npcx_wui) { .table = tbl, .group = grp, \ diff --git a/chip/npcx/registers.h b/chip/npcx/registers.h index 9e3ee1938d..94c34f34f6 100644 --- a/chip/npcx/registers.h +++ b/chip/npcx/registers.h @@ -87,7 +87,6 @@ #define NPCX_MTC_BASE_ADDR 0x400B7000 #define NPCX_MSWC_BASE_ADDR 0x400C1000 #define NPCX_SCFG_BASE_ADDR 0x400C3000 -#define NPCX_CR_UART_BASE_ADDR 0x400C4000 #define NPCX_KBC_BASE_ADDR 0x400C7000 #define NPCX_ADC_BASE_ADDR 0x400D1000 #define NPCX_SPI_BASE_ADDR 0x400D2000 @@ -101,6 +100,7 @@ #define NPCX_ITIM32_BASE_ADDR 0x400BC000 #define NPCX_MIWU_BASE_ADDR(mdl) (0x400BB000 + ((mdl) * 0x2000L)) #define NPCX_MFT_BASE_ADDR(mdl) (0x400E1000 + ((mdl) * 0x2000L)) +#define NPCX_CR_UART_BASE_ADDR(mdl) (0x400C4000 + ((mdl) * 0x2000L)) #define NPCX_PM_CH_BASE_ADDR(mdl) (0x400C9000 + ((mdl) * 0x2000L)) #if defined(CHIP_FAMILY_NPCX7) #define NPCX_SMB_BASE_ADDR(mdl) (((mdl) < 2) ? \ @@ -217,7 +217,7 @@ #define NPCX_IRQ29_NOUSED NPCX_IRQ_29 #define NPCX_IRQ30_NOUSED NPCX_IRQ_30 #define NPCX_IRQ_TWD_WKINTB_0 NPCX_IRQ_31 -#define NPCX_IRQ32_NOUSED NPCX_IRQ_32 +#define NPCX_IRQ_UART2 NPCX_IRQ_32 #define NPCX_IRQ_UART NPCX_IRQ_33 #define NPCX_IRQ34_NOUSED NPCX_IRQ_34 #define NPCX_IRQ35_NOUSED NPCX_IRQ_35 @@ -294,20 +294,20 @@ /******************************************************************************/ /* CR UART Register */ -#define NPCX_UTBUF REG8(NPCX_CR_UART_BASE_ADDR + 0x000) -#define NPCX_URBUF REG8(NPCX_CR_UART_BASE_ADDR + 0x002) -#define NPCX_UICTRL REG8(NPCX_CR_UART_BASE_ADDR + 0x004) -#define NPCX_USTAT REG8(NPCX_CR_UART_BASE_ADDR + 0x006) -#define NPCX_UFRS REG8(NPCX_CR_UART_BASE_ADDR + 0x008) -#define NPCX_UMDSL REG8(NPCX_CR_UART_BASE_ADDR + 0x00A) -#define NPCX_UBAUD REG8(NPCX_CR_UART_BASE_ADDR + 0x00C) -#define NPCX_UPSR REG8(NPCX_CR_UART_BASE_ADDR + 0x00E) +#define NPCX_UTBUF(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x000) +#define NPCX_URBUF(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x002) +#define NPCX_UICTRL(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x004) +#define NPCX_USTAT(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x006) +#define NPCX_UFRS(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x008) +#define NPCX_UMDSL(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x00A) +#define NPCX_UBAUD(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x00C) +#define NPCX_UPSR(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x00E) #ifdef NPCX_UART_FIFO_SUPPORT /* UART registers only used for FIFO mode */ -#define NPCX_UFTSTS REG8(NPCX_CR_UART_BASE_ADDR + 0x020) -#define NPCX_UFRSTS REG8(NPCX_CR_UART_BASE_ADDR + 0x022) -#define NPCX_UFTCTL REG8(NPCX_CR_UART_BASE_ADDR + 0x024) -#define NPCX_UFRCTL REG8(NPCX_CR_UART_BASE_ADDR + 0x026) +#define NPCX_UFTSTS(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x020) +#define NPCX_UFRSTS(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x022) +#define NPCX_UFTCTL(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x024) +#define NPCX_UFRCTL(n) REG8(NPCX_CR_UART_BASE_ADDR(n) + 0x026) /* UART FIFO register fields */ #define NPCX_UMDSL_FIFO_MD 0 @@ -333,6 +333,23 @@ #endif +#if defined(CHIP_FAMILY_NPCX5) +enum { + NPCX_UART_PORT0 = 0, /* UART port 0 */ + NPCX_UART_COUNT +}; +#elif defined(CHIP_FAMILY_NPCX7) +enum { + NPCX_UART_PORT0 = 0, /* UART port 0 */ +#ifdef NPCX_SECOND_UART + NPCX_UART_PORT1 = 1, /* UART port 1 */ +#endif + NPCX_UART_COUNT +}; +#else +#error "Unsupported chip family for uart ports." +#endif + /******************************************************************************/ /* KBSCAN registers */ #define NPCX_KBSIN REG8(NPCX_KBSCAN_REGS_BASE + 0x04) @@ -713,6 +730,9 @@ enum { #define NPCX_DEVALTA_32KCLKIN_SL 3 #endif #define NPCX_DEVALTA_NO_VCC1_RST 4 +#ifdef NPCX_SECOND_UART +#define NPCX_DEVALTA_UART2_SL 5 +#endif #define NPCX_DEVALTA_NO_PECI_EN 6 #define NPCX_DEVALTA_UART_SL1 7 #define NPCX_DEVALTC_UART_SL2 0 @@ -930,8 +950,12 @@ enum { #define NPCX_PWDWN_CTL7_SMB5_PD 0 #define NPCX_PWDWN_CTL7_SMB6_PD 1 #define NPCX_PWDWN_CTL7_SMB7_PD 2 +#if defined(CHIP_VARIANT_NPCX7M6FB) || defined(CHIP_VARIANT_NPCX7M7WB) +#define NPCX_PWDWN_CTL7_ITIM64_PD 5 +#define NPCX_PWDWN_CTL7_UART2_PD 6 #define NPCX_PWDWN_CTL7_WOV_PD 7 #endif +#endif /* * PMC enumeration @@ -952,9 +976,12 @@ enum { CGC_OFFSET_ESPI = 5, #if defined(CHIP_FAMILY_NPCX7) CGC_OFFSET_I2C2 = 6, +#ifdef NPCX_SECOND_UART + CGC_OFFSET_UART2 = 6, #endif #ifdef NPCX_WOV_SUPPORT - CGC_OFFSET_WOV = 6, + CGC_OFFSET_WOV = 6, +#endif #endif }; @@ -991,10 +1018,13 @@ enum NPCX_PMC_PWDWN_CTL_T { #define CGC_I2C_MASK2 ((1 << NPCX_PWDWN_CTL7_SMB5_PD) | \ (1 << NPCX_PWDWN_CTL7_SMB6_PD) | \ (1 << NPCX_PWDWN_CTL7_SMB7_PD)) +#ifdef NPCX_SECOND_UART +#define CGC_UART2_MASK (1 << NPCX_PWDWN_CTL7_UART2_PD) #endif #ifdef NPCX_WOV_SUPPORT #define CGC_WOV_MASK (1 << NPCX_PWDWN_CTL7_WOV_PD) #endif +#endif #define CGC_ADC_MASK (1 << NPCX_PWDWN_CTL4_ADC_PD) #define CGC_PECI_MASK (1 << NPCX_PWDWN_CTL4_PECI_PD) #define CGC_SPI_MASK (1 << NPCX_PWDWN_CTL4_SPIP_PD) @@ -2061,7 +2091,6 @@ enum { #define NPCX_UART_DEVALT_SL NPCX_DEVALTC_UART_SL2 #define NPCX_UART_ALT_DEVALT NPCX_DEVALT(0x0A) #define NPCX_UART_ALT_DEVALT_SL NPCX_DEVALTA_UART_SL1 - #else /* !NPCX_UART_MODULE2 */ #ifdef CHIP_FAMILY_NPCX5 @@ -2073,12 +2102,16 @@ enum { #define NPCX_UART_DEVALT_SL NPCX_DEVALTA_UART_SL1 #define NPCX_UART_ALT_DEVALT NPCX_DEVALT(0x0C) #define NPCX_UART_ALT_DEVALT_SL NPCX_DEVALTC_UART_SL2 - #endif /* NPCX_UART_MODULE2 */ #ifdef CHIP_FAMILY_NPCX7 -#define NPCX_UART_WK_GROUP MIWU_GROUP_8 -#define NPCX_UART_WK_BIT 7 +#define NPCX_UART_WK_GROUP MIWU_GROUP_8 +#define NPCX_UART_WK_BIT 7 +#ifdef NPCX_SECOND_UART +#define NPCX_UART2_WK_GROUP MIWU_GROUP_1 +#define NPCX_UART2_WK_BIT 6 +#endif + #endif /* This routine checks pending bit of GPIO wake-up functionality */ diff --git a/chip/npcx/uart.c b/chip/npcx/uart.c index 384f71d8be..40d3ee391f 100644 --- a/chip/npcx/uart.c +++ b/chip/npcx/uart.c @@ -18,57 +18,15 @@ #include "task.h" #include "timer.h" #include "uart.h" +#include "uartn.h" #include "util.h" -#ifdef NPCX_UART_FIFO_SUPPORT -/* Enable UART Tx FIFO empty interrupt */ -#define NPCX_UART_TX_EMPTY_INT_EN() \ - (SET_BIT(NPCX_UFTCTL, NPCX_UFTCTL_TEMPTY_EN)) -/* True if UART Tx FIFO empty interrupt is enabled */ -#define NPCX_UART_TX_EMPTY_INT_IS_EN() \ - (IS_BIT_SET(NPCX_UFTCTL, NPCX_UFTCTL_TEMPTY_EN)) -/* Disable UART Tx FIFO empty interrupt */ -#define NPCX_UART_TX_EMPTY_INT_DIS() \ - (CLEAR_BIT(NPCX_UFTCTL, NPCX_UFTCTL_TEMPTY_EN)) -/* True if the Tx FIFO is not completely full */ -#define NPCX_UART_TX_IS_READY() \ - (!(GET_FIELD(NPCX_UFTSTS, NPCX_UFTSTS_TEMPTY_LVL) == 0)) -/* - * True if Tx is in progress - * (i.e. FIFO is not empty or last byte in TSFT (Transmit Shift register) - * is not sent) - */ -#define NPCX_UART_TX_IN_XMIT() \ - (!IS_BIT_SET(NPCX_UFTSTS, NPCX_UFTSTS_NXMIP)) +#define CONSOLE_UART CONFIG_CONSOLE_UART -/* - * Enable to generate interrupt when there is at least one byte - * in the receive FIFO - */ -#define NPCX_UART_RX_INT_EN() \ - (SET_BIT(NPCX_UFRCTL, NPCX_UFRCTL_RNEMPTY_EN)) -/* True if at least one byte is in the receive FIFO */ -#define NPCX_UART_RX_IS_AVAILABLE() \ - (IS_BIT_SET(NPCX_UFRSTS, NPCX_UFRSTS_RFIFO_NEMPTY_STS)) +#if CONSOLE_UART +#define CONSOLE_UART_IRQ NPCX_IRQ_UART2 #else -/* Enable UART Tx buffer empty interrupt */ -#define NPCX_UART_TX_EMPTY_INT_EN() (NPCX_UICTRL |= 0x20) -/* True if UART Tx buffer empty interrupt is enabled */ -#define NPCX_UART_TX_EMPTY_INT_IS_EN() (NPCX_UICTRL & 0x20) -/* Disable UART Tx buffer empty interrupt */ -#define NPCX_UART_TX_EMPTY_INT_DIS() (NPCX_UICTRL &= ~0x20) -/* True if 1-byte Tx buffer is empty */ -#define NPCX_UART_TX_IS_READY() (NPCX_UICTRL & 0x01) -/* - * True if Tx is in progress - * (i.e. Tx buffer is not empty or last byte in TSFT (Transmit Shift register) - * is not sent) - */ -#define NPCX_UART_TX_IN_XMIT() (NPCX_USTAT & 0x40) - /* Enable to generate interrupt when there is data in the receive buffer */ -#define NPCX_UART_RX_INT_EN() (NPCX_UICTRL = 0x40) -/* True if there is data in the 1-byte Receive buffer */ -#define NPCX_UART_RX_IS_AVAILABLE() (NPCX_UICTRL & 0x02) +#define CONSOLE_UART_IRQ NPCX_IRQ_UART #endif static int init_done; @@ -149,7 +107,6 @@ 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() && pad == UART_DEFAULT_PAD) { /* disable MIWU */ @@ -161,57 +118,35 @@ void uart_tx_start(void) } #endif - /* If interrupt is already enabled, nothing to do */ - if (NPCX_UART_TX_EMPTY_INT_IS_EN()) - return; - - /* Do not allow deep sleep while transmit in progress */ - disable_sleep(SLEEP_MASK_UART); - - /* - * Re-enable the transmit interrupt, then forcibly trigger the - * interrupt. This works around a hardware problem with the - * UART where the FIFO only triggers the interrupt when its - * threshold is _crossed_, not just met. - */ - NPCX_UART_TX_EMPTY_INT_EN(); - - task_trigger_irq(NPCX_IRQ_UART); + uartn_tx_start(CONSOLE_UART); } void uart_tx_stop(void) { - /* Disable TX interrupt */ - NPCX_UART_TX_EMPTY_INT_DIS(); + uint8_t sleep_ena; - /* - * Re-allow deep sleep when transmiting on the default pad (deep sleep - * is always disabled when alternate pad is selected). - */ - if (pad == UART_DEFAULT_PAD) - enable_sleep(SLEEP_MASK_UART); + sleep_ena = (pad == UART_DEFAULT_PAD) ? 1 : 0; + uartn_tx_stop(CONSOLE_UART, sleep_ena); } void uart_tx_flush(void) { - /* Wait for transmit FIFO empty and last byte is sent */ - while (NPCX_UART_TX_IN_XMIT()) - ; + uartn_tx_flush(CONSOLE_UART); } int uart_tx_ready(void) { - return NPCX_UART_TX_IS_READY(); + return uartn_tx_ready(CONSOLE_UART); } int uart_tx_in_progress(void) { - return NPCX_UART_TX_IN_XMIT(); + return uartn_tx_in_progress(CONSOLE_UART); } int uart_rx_available(void) { - int rx_available = NPCX_UART_RX_IS_AVAILABLE(); + int rx_available = uartn_rx_available(CONSOLE_UART); if (rx_available && pad == UART_DEFAULT_PAD) { #ifdef CONFIG_LOW_POWER_IDLE @@ -232,44 +167,29 @@ int uart_rx_available(void) void uart_write_char(char c) { - /* Wait for space in transmit FIFO. */ - while (!uart_tx_ready()) - ; - - NPCX_UTBUF = c; + uartn_write_char(CONSOLE_UART, c); } int uart_read_char(void) { - return NPCX_URBUF; -} - -void uart_clear_rx_fifo(int channel) -{ - int scratch __attribute__ ((unused)); - if (channel == 0) { /* suppose '0' is EC UART*/ - /*if '1' that mean have a RX data on the FIFO register*/ - while (NPCX_UART_RX_IS_AVAILABLE()) - scratch = NPCX_URBUF; - } + return uartn_read_char(CONSOLE_UART); } -/** - * Interrupt handler for UART0 - */ +/* Interrupt handler for Console UART */ void uart_ec_interrupt(void) { #ifdef CONFIG_UART_PAD_SWITCH if (pad == UART_ALTERNATE_PAD) { - if (uart_rx_available()) { - uint8_t c = uart_read_char(); + if (uartn_rx_available(NPCX_UART_PORT0)) { + uint8_t c = uartn_read_char(NPCX_UART_PORT0); if (altpad_rx_pos < altpad_rx_len) altpad_rx_buf[altpad_rx_pos++] = c; } - if (uart_tx_ready()) { + if (uartn_tx_ready(NPCX_UART_PORT0)) { if (altpad_tx_pos < altpad_tx_len) - uart_write_char(altpad_tx_buf[altpad_tx_pos++]); + uartn_write_char(NPCX_UART_PORT0, + altpad_tx_buf[altpad_tx_pos++]); else uart_tx_stop(); } @@ -283,9 +203,9 @@ void uart_ec_interrupt(void) uart_process_output(); } #ifdef NPCX_UART_FIFO_SUPPORT -DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 4); +DECLARE_IRQ(CONSOLE_UART_IRQ, uart_ec_interrupt, 4); #else -DECLARE_IRQ(NPCX_IRQ_UART, uart_ec_interrupt, 1); +DECLARE_IRQ(CONSOLE_UART_IRQ, uart_ec_interrupt, 1); #endif #ifdef CONFIG_UART_PAD_SWITCH @@ -308,15 +228,15 @@ void uart_reset_default_pad_panic(void) static void uart_set_pad(enum uart_pad newpad) { #ifdef NPCX_UART_FIFO_SUPPORT - NPCX_UFTCTL &= ~0xE0; - NPCX_UFRCTL &= ~0xE0; + NPCX_UFTCTL(NPCX_UART_PORT0) &= ~0xE0; + NPCX_UFRCTL(NPCX_UART_PORT0) &= ~0xE0; #else - NPCX_UICTRL = 0x00; + NPCX_UICTRL(NPCX_UART_PORT0) = 0x00; #endif task_disable_irq(NPCX_IRQ_UART); /* Flush the last byte */ - uart_tx_flush(); + uartn_tx_flush(NPCX_UART_PORT0); uart_tx_stop(); /* @@ -334,7 +254,7 @@ static void uart_set_pad(enum uart_pad newpad) npcx_gpio2uart(); /* Re-enable receive interrupt. */ - NPCX_UART_RX_INT_EN(); + uartn_rx_int_en(NPCX_UART_PORT0); /* * If pad is switched while a byte is being received, the last byte may @@ -342,7 +262,7 @@ static void uart_set_pad(enum uart_pad newpad) * then flush the FIFO. See b/65526215. */ udelay(100); - uart_clear_rx_fifo(0); + uartn_clear_rx_fifo(NPCX_UART_PORT0); task_enable_irq(NPCX_IRQ_UART); } @@ -393,7 +313,7 @@ int uart_alt_pad_write_read(uint8_t *tx, int tx_len, uint8_t *rx, int rx_len, uart_set_pad(UART_ALTERNATE_PAD); gpio_clear_pending_interrupt(GPIO_UART_MAIN_RX); gpio_enable_interrupt(GPIO_UART_MAIN_RX); - uart_tx_start(); + uartn_tx_start(NPCX_UART_PORT0); do { usleep(100); @@ -430,85 +350,9 @@ out: return ret; } #endif - -#ifdef NPCX_UART_FIFO_SUPPORT -static void uart_set_fifo_mode(void) -{ - /* Enable the UART FIFO mode */ - SET_BIT(NPCX_UMDSL, NPCX_UMDSL_FIFO_MD); - /* Disable all Tx interrupts */ - NPCX_UFTCTL &= ~((1 << NPCX_UFTCTL_TEMPTY_LVL_EN) | - (1 << NPCX_UFTCTL_TEMPTY_EN) | - (1 << NPCX_UFTCTL_NXIMPEN)); -} - -#endif - -static void uart_config(void) -{ - /* Configure pins from GPIOs to CR_UART */ - gpio_config_module(MODULE_UART, 1); - - /* Enable MIWU IRQ of UART */ - task_enable_irq(NPCX_UART_MIWU_IRQ); - -#ifdef CONFIG_LOW_POWER_IDLE - /* - * Configure the UART wake-up event triggered from a falling edge - * on CR_SIN pin. - */ - SET_BIT(NPCX_WKEDG(1, NPCX_UART_WK_GROUP), NPCX_UART_WK_BIT); -#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 this value is modified, please also - * modify the delay in uart_set_pad and uart_reset_default_pad_panic. - */ - NPCX_UPSR = 0x38; - NPCX_UBAUD = 0x01; - - /* - * 8-N-1, FIFO enabled. Must be done after setting - * the divisor for the new divisor to take effect. - */ - NPCX_UFRS = 0x00; -#ifdef NPCX_UART_FIFO_SUPPORT - uart_set_fifo_mode(); -#endif - NPCX_UART_RX_INT_EN(); -} - void uart_init(void) { - uint32_t mask = 0; - - /* - * Enable UART0 in run, sleep, and deep sleep modes. Enable the Host - * UART in run and sleep modes. - */ - mask = 0x10; /* bit 4 */ - clock_enable_peripheral(CGC_OFFSET_UART, mask, CGC_MODE_ALL); - - /* Set pin-mask for UART */ - npcx_gpio2uart(); - - /* Configure UARTs (identically) */ - uart_config(); - - /* - * Enable interrupts for UART0 only. Host UART will have to wait - * until the LPC bus is initialized. - */ - uart_clear_rx_fifo(0); - task_enable_irq(NPCX_IRQ_UART); + uartn_init(CONSOLE_UART); init_done = 1; } diff --git a/chip/npcx/uartn.c b/chip/npcx/uartn.c new file mode 100644 index 0000000000..d7d46e849f --- /dev/null +++ b/chip/npcx/uartn.c @@ -0,0 +1,261 @@ +/* + * Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* UART module for Chrome EC */ + +#include <clock.h> +#include "common.h" +#include <gpio.h> +#include <gpio_chip.h> +#include "registers.h" +#include "system.h" +#include "task.h" +#include "util.h" + +#ifdef NPCX_UART_FIFO_SUPPORT +/* Enable UART Tx FIFO empty interrupt */ +#define NPCX_UART_TX_EMPTY_INT_EN(n) \ + (SET_BIT(NPCX_UFTCTL(n), NPCX_UFTCTL_TEMPTY_EN)) +/* True if UART Tx FIFO empty interrupt is enabled */ +#define NPCX_UART_TX_EMPTY_INT_IS_EN(n) \ + (IS_BIT_SET(NPCX_UFTCTL(n), NPCX_UFTCTL_TEMPTY_EN)) +/* Disable UART Tx FIFO empty interrupt */ +#define NPCX_UART_TX_EMPTY_INT_DIS(n) \ + (CLEAR_BIT(NPCX_UFTCTL(n), NPCX_UFTCTL_TEMPTY_EN)) +/* True if the Tx FIFO is not completely full */ +#define NPCX_UART_TX_IS_READY(n) \ + (!(GET_FIELD(NPCX_UFTSTS(n), NPCX_UFTSTS_TEMPTY_LVL) == 0)) +/* + * True if Tx is in progress + * (i.e. FIFO is not empty or last byte in TSFT (Transmit Shift register) + * is not sent) + */ +#define NPCX_UART_TX_IN_XMIT(n) \ + (!IS_BIT_SET(NPCX_UFTSTS(n), NPCX_UFTSTS_NXMIP)) + +/* + * Enable to generate interrupt when there is at least one byte + * in the receive FIFO + */ +#define NPCX_UART_RX_INT_EN(n) \ + (SET_BIT(NPCX_UFRCTL(n), NPCX_UFRCTL_RNEMPTY_EN)) +/* True if at least one byte is in the receive FIFO */ +#define NPCX_UART_RX_IS_AVAILABLE(n) \ + (IS_BIT_SET(NPCX_UFRSTS(n), NPCX_UFRSTS_RFIFO_NEMPTY_STS)) +#else +/* Enable UART Tx buffer empty interrupt */ +#define NPCX_UART_TX_EMPTY_INT_EN(n) (NPCX_UICTRL(n) |= 0x20) +/* True if UART Tx buffer empty interrupt is enabled */ +#define NPCX_UART_TX_EMPTY_INT_IS_EN(n) (NPCX_UICTRL(n) & 0x20) +/* Disable UART Tx buffer empty interrupt */ +#define NPCX_UART_TX_EMPTY_INT_DIS(n) (NPCX_UICTRL(n) &= ~0x20) +/* True if 1-byte Tx buffer is empty */ +#define NPCX_UART_TX_IS_READY(n) (NPCX_UICTRL(n) & 0x01) +/* + * True if Tx is in progress + * (i.e. Tx buffer is not empty or last byte in TSFT (Transmit Shift register) + * is not sent) + */ +#define NPCX_UART_TX_IN_XMIT(n) (NPCX_USTAT(n) & 0x40) + /* Enable to generate interrupt when there is data in the receive buffer */ +#define NPCX_UART_RX_INT_EN(n) (NPCX_UICTRL(n) = 0x40) +/* True if there is data in the 1-byte Receive buffer */ +#define NPCX_UART_RX_IS_AVAILABLE(n) (NPCX_UICTRL(n) & 0x02) +#endif + +struct uart_configs { + uint32_t irq; + uint32_t clk_en_offset; + uint32_t clk_en_msk; +}; +static const struct uart_configs uart_cfg[] = { + {NPCX_IRQ_UART, CGC_OFFSET_UART, CGC_UART_MASK}, +#ifdef NPCX_SECOND_UART + {NPCX_IRQ_UART2, CGC_OFFSET_UART2, CGC_UART2_MASK}, +#endif +}; +BUILD_ASSERT(ARRAY_SIZE(uart_cfg) == UART_MODULE_COUNT); + +#ifdef CONFIG_LOW_POWER_IDLE +static const struct npcx_wui uart_wui[] = { + WUI(1, NPCX_UART_WK_GROUP, NPCX_UART_WK_BIT), +#ifdef NPCX_SECOND_UART + WUI(0, NPCX_UART2_WK_GROUP, NPCX_UART2_WK_BIT), +#endif +}; +BUILD_ASSERT(ARRAY_SIZE(uart_wui) == UART_MODULE_COUNT); + +void uartn_wui_en(uint8_t uart_num) +{ + struct npcx_wui wui; + + wui = uart_wui[uart_num]; + /* Clear pending bit before enable uart wake-up */ + SET_BIT(NPCX_WKPCL(wui.table, wui.group), wui.bit); + /* Enable UART1 wake-up and interrupt request */ + SET_BIT(NPCX_WKEN(wui.table, wui.group), wui.bit); +} +#endif + +void uartn_rx_int_en(uint8_t uart_num) +{ + NPCX_UART_RX_INT_EN(uart_num); +} + +void uartn_tx_start(uint8_t uart_num) +{ + /* If interrupt is already enabled, nothing to do */ + if (NPCX_UART_TX_EMPTY_INT_IS_EN(uart_num)) + return; + + /* Do not allow deep sleep while transmit in progress */ + disable_sleep(SLEEP_MASK_UART); + + /* + * Re-enable the transmit interrupt, then forcibly trigger the + * interrupt. This works around a hardware problem with the + * UART where the FIFO only triggers the interrupt when its + * threshold is _crossed_, not just met. + */ + NPCX_UART_TX_EMPTY_INT_EN(uart_num); + + task_trigger_irq(uart_cfg[uart_num].irq); +} + +void uartn_tx_stop(uint8_t uart_num, uint8_t sleep_ena) +{ + /* Disable TX interrupt */ + NPCX_UART_TX_EMPTY_INT_DIS(uart_num); + /* + * Re-allow deep sleep when transmiting on the default pad (deep sleep + * is always disabled when alternate pad is selected). + */ + if (sleep_ena == 1) + enable_sleep(SLEEP_MASK_UART); +} + +void uartn_tx_flush(uint8_t uart_num) +{ + /* Wait for transmit FIFO empty and last byte is sent */ + while (NPCX_UART_TX_IN_XMIT(uart_num)) + ; +} + +int uartn_tx_ready(uint8_t uart_num) +{ + return NPCX_UART_TX_IS_READY(uart_num); +} + +int uartn_tx_in_progress(uint8_t uart_num) +{ + return NPCX_UART_TX_IN_XMIT(uart_num); +} + +int uartn_rx_available(uint8_t uart_num) +{ + return NPCX_UART_RX_IS_AVAILABLE(uart_num); +} + +void uartn_write_char(uint8_t uart_num, char c) +{ + /* Wait for space in transmit FIFO. */ + while (!uartn_tx_ready(uart_num)) + ; + + NPCX_UTBUF(uart_num) = c; +} + +int uartn_read_char(uint8_t uart_num) +{ + return NPCX_URBUF(uart_num); +} + +void uartn_clear_rx_fifo(int channel) +{ + int scratch __attribute__ ((unused)); + + /* If '1', that means there is RX data on the FIFO register */ + while (NPCX_UART_RX_IS_AVAILABLE(channel)) + scratch = NPCX_URBUF(channel); +} + +#ifdef NPCX_UART_FIFO_SUPPORT +static void uartn_set_fifo_mode(uint8_t uart_num) +{ + /* Enable the UART FIFO mode */ + SET_BIT(NPCX_UMDSL(uart_num), NPCX_UMDSL_FIFO_MD); + /* Disable all Tx interrupts */ + NPCX_UFTCTL(uart_num) &= ~((1 << NPCX_UFTCTL_TEMPTY_LVL_EN) | + (1 << NPCX_UFTCTL_TEMPTY_EN) | + (1 << NPCX_UFTCTL_NXIMPEN)); +} + +#endif + +static void uartn_config(uint8_t uart_num) +{ +#ifdef CONFIG_LOW_POWER_IDLE + struct npcx_wui wui; +#endif + + /* Configure pins from GPIOs to CR_UART */ + gpio_config_module(MODULE_UART, 1); + +#ifdef CONFIG_LOW_POWER_IDLE + /* + * Configure the UART wake-up event triggered from a falling edge + * on CR_SIN pin. + */ + wui = uart_wui[uart_num]; + SET_BIT(NPCX_WKEDG(wui.table, wui.group), wui.bit); +#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 this value is modified, please also + * modify the delay in uart_set_pad and uart_reset_default_pad_panic. + */ + NPCX_UPSR(uart_num) = 0x38; + NPCX_UBAUD(uart_num) = 0x01; + + /* + * 8-N-1, FIFO enabled. Must be done after setting + * the divisor for the new divisor to take effect. + */ + NPCX_UFRS(uart_num) = 0x00; +#ifdef NPCX_UART_FIFO_SUPPORT + uartn_set_fifo_mode(uart_num); +#endif + NPCX_UART_RX_INT_EN(uart_num); +} + +void uartn_init(uint8_t uart_num) +{ + uint32_t offset, mask; + + offset = uart_cfg[uart_num].clk_en_offset; + mask = uart_cfg[uart_num].clk_en_msk; + clock_enable_peripheral(offset, mask, CGC_MODE_ALL); + + if (uart_num == NPCX_UART_PORT0) + npcx_gpio2uart(); + + /* Configure UARTs (identically) */ + uartn_config(uart_num); + + /* + * Enable interrupts for UART0 only. Host UART will have to wait + * until the LPC bus is initialized. + */ + uartn_clear_rx_fifo(uart_num); + task_enable_irq(uart_cfg[uart_num].irq); +} diff --git a/chip/npcx/uartn.h b/chip/npcx/uartn.h new file mode 100644 index 0000000000..fc5c2599d0 --- /dev/null +++ b/chip/npcx/uartn.h @@ -0,0 +1,63 @@ +/* + * Copyright 2018 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef __CROS_EC_UARTN_H +#define __CROS_EC_UARTN_H + +#include "common.h" + +/* + * Initialize the UART module. + */ +void uartn_init(uint8_t uart_num); + +/* + * Re-enable the UART transmit interrupt. + * + * This also forces triggering a UART interrupt, if the transmit interrupt was + * disabled. + */ +void uartn_tx_start(uint8_t uart_num); + + /* Disable the UART transmit interrupt. */ +void uartn_tx_stop(uint8_t uart_num, uint8_t sleep_ena); + +/* Flush the transmit FIFO. */ +void uartn_tx_flush(uint8_t uart_num); + +/* Return non-zero if there is room to transmit a character immediately. */ +int uartn_tx_ready(uint8_t uart_num); + +/* Return non-zero if a transmit is in progress. */ +int uartn_tx_in_progress(uint8_t uart_num); + +/* Return non-zero if the UART has a character available to read. */ +int uartn_rx_available(uint8_t uart_num); + +/* + * Send a character to the UART data register. + * + * If the transmit FIFO is full, blocks until there is space. + * + * @param c Character to send. + */ +void uartn_write_char(uint8_t uart_num, char c); + +/* + * Read one char from the UART data register. + * + * @return The character read. + */ +int uartn_read_char(uint8_t uart_num); + +/* Clear all data in the UART Rx FIFO */ +void uartn_clear_rx_fifo(int channel); + +/* Enable the UART Rx interrupt */ +void uartn_rx_int_en(uint8_t uart_num); +/* Enable the UART Wake-up */ +void uartn_wui_en(uint8_t uart_num); +#endif /* __CROS_EC_UARTN_H */ |