diff --git a/drivers/espi/CMakeLists.txt b/drivers/espi/CMakeLists.txt index fe3fda211be..7fdd637e777 100644 --- a/drivers/espi/CMakeLists.txt +++ b/drivers/espi/CMakeLists.txt @@ -4,4 +4,5 @@ zephyr_library() zephyr_library_sources_ifdef(CONFIG_ESPI_XEC espi_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX espi_npcx.c) +zephyr_library_sources_ifdef(CONFIG_ESPI_NPCX host_subs_npcx.c) zephyr_library_sources_ifdef(CONFIG_USERSPACE espi_handlers.c) diff --git a/drivers/espi/Kconfig b/drivers/espi/Kconfig index 15620b5f731..d1b078b78ba 100644 --- a/drivers/espi/Kconfig +++ b/drivers/espi/Kconfig @@ -112,6 +112,12 @@ config ESPI_PERIPHERAL_DEBUG_PORT_80 help Enables debug Port 80 over eSPI peripheral channel. +config ESPI_PERIPHERAL_EC_HOST_CMD + bool "Host peripheral device support EC host command subsystem" + help + Enables Embedded Controller (EC) host command subsystem via eSPI + peripheral channel. + endif # ESPI_PERIPHERAL_CHANNEL endif # ESPI diff --git a/drivers/espi/espi_npcx.c b/drivers/espi/espi_npcx.c index 8b57dcfc9b3..642f2c01662 100644 --- a/drivers/espi/espi_npcx.c +++ b/drivers/espi/espi_npcx.c @@ -14,6 +14,7 @@ #include #include #include "espi_utils.h" +#include "soc_host.h" #include "soc_miwu.h" #include @@ -386,6 +387,8 @@ static void espi_vw_notify_plt_rst(const struct device *dev) if (wire) { /* Set Peripheral Channel ready when PLTRST is de-asserted */ inst->ESPICFG |= BIT(NPCX_ESPICFG_PCHANEN); + /* Configure all host sub-modules in host doamin */ + soc_host_init_subs_host_domain(); } /* PLT_RST will be received several times */ @@ -623,9 +626,12 @@ static int espi_npcx_read_lpc_request(const struct device *dev, uint32_t *data) { ARG_UNUSED(dev); + struct espi_reg *const inst = HAL_INSTANCE(dev); - /* TODO: Implement it in next commit */ - return 0; + if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_PCHANEN)) + return -ENOTSUP; + + return soc_host_periph_read_request(op, data); } static int espi_npcx_write_lpc_request(const struct device *dev, @@ -633,9 +639,12 @@ static int espi_npcx_write_lpc_request(const struct device *dev, uint32_t *data) { ARG_UNUSED(dev); + struct espi_reg *const inst = HAL_INSTANCE(dev); - /* TODO: Implement it in next commit */ - return 0; + if (!IS_BIT_SET(inst->ESPICFG, NPCX_ESPICFG_PCHANEN)) + return -ENOTSUP; + + return soc_host_periph_write_request(op, data); } #if defined(CONFIG_ESPI_OOB_CHANNEL) @@ -767,6 +776,7 @@ static int espi_npcx_receive_oob(const struct device *dev, /* Read remaining bytes of package */ if (sz_oob_rx % 4) { int i; + oob_data = inst->OOBRXBUF[idx_rx_buf + 1]; for (i = 0; i < sz_oob_rx % 4; i++) *(oob_buf++) = (oob_data >> (8 * i)) & 0xFF; @@ -853,6 +863,9 @@ static int espi_npcx_init(const struct device *dev) /* Configure pin-mux for eSPI bus device */ soc_pinctrl_mux_configure(config->alts_list, config->alts_size, 1); + /* Configure host sub-modules which HW blocks belong to core domain */ + soc_host_init_subs_core_domain(dev, &data->callbacks); + /* eSPI Bus interrupt installation */ IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), diff --git a/drivers/espi/host_subs_npcx.c b/drivers/espi/host_subs_npcx.c new file mode 100644 index 00000000000..a30693f5e49 --- /dev/null +++ b/drivers/espi/host_subs_npcx.c @@ -0,0 +1,832 @@ +/* + * Copyright (c) 2020 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nuvoton_npcx_host_sub + +/** + * @file + * @brief Nuvoton NPCX host sub modules driver + * + * This file contains the drivers of NPCX Host Sub-Modules that serve as an + * interface between the Host and Core domains. Please refer the block diagram. + * + * +------------+ + * | Serial |---> TXD + * +<--->| Port |<--- RXD + * | | |<--> ... + * | +------------+ + * | +------------+ | + * +------------+ |<--->| KBC & PM |<--->| + * eSPI_CLK --->| eSPI Bus | | | Channels | | + * eSPI_RST --->| Controller | | +------------+ | + * eSPI_IO3-0 <-->| |<-->| +------------+ | + * eSPI_CS --->| (eSPI mode)| | | Shared | | + * eSPI_ALERT <-->| | |<--->| Memory |<--->| + * +------------+ | +------------+ | + * | +------------+ | + * |<--->| MSWC |<--->| + * | +------------+ | + * | +------------+ | + * | | Core | | + * |<--->| to Host |<--->| + * | | Access | | + * | +------------+ | + * HMIB | Core Bus + * (Host Modules Internal Bus) +------------ + * + * + * For most of them, the Host can configure these modules via eSPI(Peripheral + * Channel)/LPC by accessing 'Configuration and Control register Set' which IO + * base address is 0x4E as default. (The table below illustrates structure of + * 'Configuration and Control Register Set') And the interrupts in core domain + * help handling any events from host side. + * + * Index | Configuration and Control Register Set + * --------|--------------------------------------------------+ Bank Select + * 07h | Logical Device Number Register (LDN) |---------+ + * --------|--------------------------------------------------- | + * 20-2Fh | SuperI/O Configuration Registers | | + * ------------------------------------------------------------ | + * --------|---------------------------------------------------_ | + * 30h | Logical Device Control Register | |_ | + * --------|--------------------------------------------------- | |_ | + * 60-63h | I/O Space Configuration Registers | | | | | + * --------|--------------------------------------------------- | | | | + * 70-71h | Interrupt Configuration Registers | | | | | + * --------|--------------------------------------------------- | | | | + * 73-74h | DMA Configuration Registers (No support in NPCX) | | | | | + * --------|--------------------------------------------------- | | |<--+ + * F0-FFh | Special Logical Device Configuration Registers | | | | + * --------|--------------------------------------------------- | | | + * |--------------------------------------------------- | | + * |--------------------------------------------------- | + * |--------------------------------------------------- + * + * + * This driver introduces six host sub-modules. It includes: + * + * 1. Keyboard and Mouse Controller (KBC) interface. + * ● Intel 8051SL-compatible Host interface + * — 8042 KBD standard interface (ports 60h, 64h) + * — Legacy IRQ: IRQ1 (KBD) and IRQ12 (mouse) support + * ● Configured by two logical devices: Keyboard and Mouse (LDN 0x06/0x05) + * + * 2. Power Management (PM) channels. + * ● PM channel registers + * — Command/Status register + * — Data register + * channel 1: legacy 62h, 66h; channel 2: legacy 68h, 6Ch; + * channel 3: legacy 6Ah, 6Eh; channel 4: legacy 6Bh, 6Fh; + * ● PM interrupt using: + * — Serial IRQ + * — SMI + * — EC_SCI + * ● Configured by four logical devices: PM1/2/3/4 (LDN 0x11/0x12/0x17/0x1E) + * + * 3. Shared Memory mechanism (SHM). + * This module allows sharing of the on-chip RAM by both Core and the Host. + * It also supports the following features: + * ● Four Core/Host communication windows for direct RAM access + * ● Eight Protection regions for each access window + * ● Host IRQ and SMI generation + * ● Port 80 debug support + * ● Configured by one logical device: SHM (LDN 0x0F) + * + * 4. Core Access to Host Modules (C2H). + * ● A interface to access module registers in host domain. + * It enables the Core to access the registers in host domain (i.e., Host + * Configuration, Serial Port, SHM, and MSWC), through HMIB. + * + * 5. Mobile System Wake-Up functions (MSWC). + * It detects and handles wake-up events from various sources in the Host + * modules and alerts the Core for better power consumption. + * + * 6. Serial Port (Legacy UART) + * It provides UART functionality by supporting serial data communication + * with a remote peripheral device or a modem. + * + * INCLUDE FILES: soc_host.h + * + */ + +#include +#include +#include +#include +#include +#include +#include "espi_utils.h" +#include "soc_host.h" +#include "soc_miwu.h" + +#include +LOG_MODULE_REGISTER(host_sub_npcx, LOG_LEVEL_ERR); + +struct host_sub_npcx_config { + /* host module instances */ + struct mswc_reg *const inst_mswc; + struct shm_reg *const inst_shm; + struct c2h_reg *const inst_c2h; + struct kbc_reg *const inst_kbc; + struct pmch_reg *const inst_pm_acpi; + struct pmch_reg *const inst_pm_hcmd; + /* clock configuration */ + const uint8_t clks_size; + const struct npcx_clk_cfg *clks_list; + /* mapping table between host access signals and wake-up input */ + struct npcx_wui host_acc_wui; +}; + +struct host_sub_npcx_data { + sys_slist_t *callbacks; /* pointer on the espi callback list */ + uint8_t plt_rst_asserted; /* current PLT_RST# status */ + uint8_t espi_rst_asserted; /* current ESPI_RST# status */ + const struct device *host_bus_dev; /* device for eSPI/LPC bus */ +}; + +static const struct npcx_clk_cfg host_dev_clk_cfg[] = + DT_NPCX_CLK_CFG_ITEMS_LIST(0); + +struct host_sub_npcx_config host_sub_cfg = { + .inst_mswc = (struct mswc_reg *)DT_INST_REG_ADDR_BY_NAME(0, mswc), + .inst_shm = (struct shm_reg *)DT_INST_REG_ADDR_BY_NAME(0, shm), + .inst_c2h = (struct c2h_reg *)DT_INST_REG_ADDR_BY_NAME(0, c2h), + .inst_kbc = (struct kbc_reg *)DT_INST_REG_ADDR_BY_NAME(0, kbc), + .inst_pm_acpi = (struct pmch_reg *)DT_INST_REG_ADDR_BY_NAME(0, pm_acpi), + .inst_pm_hcmd = (struct pmch_reg *)DT_INST_REG_ADDR_BY_NAME(0, pm_hcmd), + .host_acc_wui = DT_NPCX_ESPI_WUI_ITEM(host_acc_wui), + .clks_size = ARRAY_SIZE(host_dev_clk_cfg), + .clks_list = host_dev_clk_cfg, +}; + +struct host_sub_npcx_data host_sub_data; + +/* Application shouldn't touch these flags in KBC status register directly */ +#define NPCX_KBC_STS_MASK (BIT(NPCX_HIKMST_IBF) | BIT(NPCX_HIKMST_OBF) \ + | BIT(NPCX_HIKMST_A2)) + +/* IO base address of EC Logical Device Configuration */ +#define NPCX_EC_CFG_IO_ADDR 0x4E + +/* 8042 event data */ +#define NPCX_8042_DATA_POS 8U +#define NPCX_8042_TYPE_POS 0U + +/* Timeout to wait for Core-to-Host transaction to be completed. */ +#define NPCX_C2H_TRANSACTION_TIMEOUT_US 200 + +/* Logical Device Number Assignments */ +#define EC_CFG_LDN_MOUSE 0x05 +#define EC_CFG_LDN_KBC 0x06 +#define EC_CFG_LDN_SHM 0x0F +#define EC_CFG_LDN_ACPI 0x11 /* PM Channel 1 */ +#define EC_CFG_LDN_HCMD 0x12 /* PM Channel 2 */ + +/* Index of EC (4E/4F) Configuration Register */ +#define EC_CFG_IDX_LDN 0x07 +#define EC_CFG_IDX_CTRL 0x30 +#define EC_CFG_IDX_CMD_IO_ADDR_H 0x60 +#define EC_CFG_IDX_CMD_IO_ADDR_L 0x61 +#define EC_CFG_IDX_DATA_IO_ADDR_H 0x62 +#define EC_CFG_IDX_DATA_IO_ADDR_L 0x63 + +/* Index of Special Logical Device Configuration (Shared Memory Module) */ +#define EC_CFG_IDX_SHM_CFG 0xF1 +#define EC_CFG_IDX_SHM_WND1_ADDR_0 0xF4 +#define EC_CFG_IDX_SHM_WND1_ADDR_1 0xF5 +#define EC_CFG_IDX_SHM_WND1_ADDR_2 0xF6 +#define EC_CFG_IDX_SHM_WND1_ADDR_3 0xF7 +#define EC_CFG_IDX_SHM_WND2_ADDR_0 0xF8 +#define EC_CFG_IDX_SHM_WND2_ADDR_1 0xF9 +#define EC_CFG_IDX_SHM_WND2_ADDR_2 0xFA +#define EC_CFG_IDX_SHM_WND2_ADDR_3 0xFB + +/* Host KBC sub-device local functions */ +#if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC) +static void host_kbc_ibf_isr(void *arg) +{ + ARG_UNUSED(arg); + struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; + struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, + ESPI_PERIPHERAL_8042_KBC, ESPI_PERIPHERAL_NODATA + }; + + /* + * The high byte contains information from the host, and the lower byte + * indicates if the host sent a command or data. 1 = Command. + */ + evt.evt_data = (inst_kbc->HIKMDI << NPCX_8042_DATA_POS) | + (IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_A2) << + NPCX_8042_TYPE_POS); + + LOG_DBG("%s: kbc data 0x%02x", __func__, evt.evt_data); + espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, + evt); +} + +static void host_kbc_obe_isr(void *arg) +{ + ARG_UNUSED(arg); + struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; + + /* Disable KBC OBE interrupt first */ + inst_kbc->HICTRL &= ~BIT(NPCX_HICTRL_OBECIE); + + LOG_DBG("%s: kbc status 0x%02x", __func__, inst_kbc->HIKMST); + + /* TODO: notify application that host already read out data here? */ +} + +static void host_kbc_init(void) +{ + struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; + + /* Make sure the previous OBF and IRQ has been sent out. */ + k_busy_wait(4); + /* Set FW_OBF to clear OBF flag in both STATUS and HIKMST to 0 */ + inst_kbc->HICTRL |= BIT(NPCX_HICTRL_FW_OBF); + /* Ensure there is no OBF set in this period. */ + k_busy_wait(4); + + /* + * Init KBC with: + * 1. Enable Input Buffer Full (IBF) core interrupt for Keyboard/mouse. + * 2. Enable Output Buffer Full Mouse(OBFM) SIRQ 12. + * 3. Enable Output Buffer Full Keyboard (OBFK) SIRQ 1. + */ + inst_kbc->HICTRL = BIT(NPCX_HICTRL_IBFCIE) | BIT(NPCX_HICTRL_OBFMIE) + | BIT(NPCX_HICTRL_OBFKIE); + + /* Configure SIRQ 1/12 type (level + high) */ + inst_kbc->HIIRQC = 0x00; +} +#endif + +/* Host ACPI sub-device local functions */ +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) +static void host_acpi_process_input_data(uint8_t data) +{ + struct espi_event evt = { + .evt_type = ESPI_BUS_PERIPHERAL_NOTIFICATION, + .evt_details = ESPI_PERIPHERAL_HOST_IO, + .evt_data = ESPI_PERIPHERAL_NODATA + }; + + LOG_DBG("%s: acpi data 0x%02x", __func__, data); + evt.evt_data = data; + espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, + evt); +} + +static void host_acpi_init(void) +{ + struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi; + + /* Use SMI/SCI postive polarity by default */ + inst_acpi->HIPMCTL &= ~BIT(NPCX_HIPMCTL_SCIPOL); + inst_acpi->HIPMIC &= ~BIT(NPCX_HIPMIC_SMIPOL); + + /* Set SMIB/SCIB bits to make sure SMI#/SCI# are driven to high */ + inst_acpi->HIPMIC |= BIT(NPCX_HIPMIC_SMIB) | BIT(NPCX_HIPMIC_SCIB); + + /* + * Allow SMI#/SCI# generated from PM module. + * On eSPI bus, we suggest set VW value of SCI#/SMI# directly. + */ + inst_acpi->HIPMIE |= BIT(NPCX_HIPMIE_SCIE); + inst_acpi->HIPMIE |= BIT(NPCX_HIPMIE_SMIE); + + /* + * Init ACPI PM channel (Host IO) with: + * 1. Enable Input-Buffer Full (IBF) core interrupt. + * 2. BIT 7 must be 1. + */ + inst_acpi->HIPMCTL |= BIT(7) | BIT(NPCX_HIPMCTL_IBFIE); +} +#endif + +#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) +/* Host command argument and memory map buffers */ +static uint8_t shm_mem_host_cmd[256] __aligned(8); +static uint8_t shm_memmap[256] __aligned(8); + +/* Host command sub-device local functions */ +static void host_hcmd_process_input_data(uint8_t data) +{ + /* TODO: Handle host request data here */ +} + +static void host_hcmd_init(void) +{ + struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd; + struct shm_reg *const inst_shm = host_sub_cfg.inst_shm; + + /* Don't stall SHM transactions */ + inst_shm->SHM_CTL &= ~0x40; + /* Disable Window 1 & 2 protection */ + inst_shm->WIN1_WR_PROT = 0; + inst_shm->WIN2_WR_PROT = 0; + inst_shm->WIN1_RD_PROT = 0; + inst_shm->WIN2_RD_PROT = 0; + /* Configure Win1/2 for Host CMD and MEMMAP. Their sizes are 256B */ + inst_shm->WIN_SIZE = 0x88; + inst_shm->WIN_BASE1 = (uint32_t)shm_mem_host_cmd; + inst_shm->WIN_BASE2 = (uint32_t)shm_memmap; + /* Enable write protect of Share memory window 2 */ + inst_shm->WIN2_WR_PROT = 0xFF; + + /* TODO: Initialize shm_memmap buffer for host command flags here */ + + /* + * Clear processing flag before enabling host's interrupts in case + * it's set by the other command during sysjump. + */ + inst_hcmd->HIPMST &= ~BIT(NPCX_HIPMST_F0); + + /* + * Init Host Command PM channel (Host IO) with: + * 1. Enable Input-Buffer Full (IBF) core interrupt. + * 2. BIT 7 must be 1. + */ + inst_hcmd->HIPMCTL |= BIT(7) | BIT(NPCX_HIPMCTL_IBFIE); + +} +#endif + +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) || \ + defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) +/* Host pm (host io) sub-module isr function for all channels such as ACPI. */ +static void host_pmch_ibf_isr(void *arg) +{ + ARG_UNUSED(arg); + struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi; + struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd; + uint8_t in_data; + + /* Host put data on input buffer of ACPI channel */ + if (IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_IBF)) { + /* Set processing flag before reading command byte */ + inst_acpi->HIPMST |= BIT(NPCX_HIPMST_F0); + /* Read out input data and clear IBF pending bit */ + in_data = inst_acpi->HIPMDI; +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) + host_acpi_process_input_data(in_data); +#endif + } + + /* Host put data on input buffer of HOSTCMD channel */ + if (IS_BIT_SET(inst_hcmd->HIPMST, NPCX_HIPMST_IBF)) { + /* Set processing flag before reading command byte */ + inst_hcmd->HIPMST |= BIT(NPCX_HIPMST_F0); + /* Read out input data and clear IBF pending bit */ + in_data = inst_hcmd->HIPMDI; +#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) + host_hcmd_process_input_data(in_data); +#endif + } +} +#endif + +/* Host port80 sub-device local functions */ +#if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80) +static void host_port80_isr(void *arg) +{ + ARG_UNUSED(arg); + struct shm_reg *const inst_shm = host_sub_cfg.inst_shm; + struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, + (ESPI_PERIPHERAL_INDEX_0 << 16) | ESPI_PERIPHERAL_DEBUG_PORT80, + ESPI_PERIPHERAL_NODATA + }; + uint8_t status = inst_shm->DP80STS; + + LOG_DBG("%s: p80 status 0x%02X", __func__, status); + + /* Read out port80 data continuously if FIFO is not empty */ + while (IS_BIT_SET(inst_shm->DP80STS, NPCX_DP80STS_FNE)) { + LOG_DBG("p80: %04x", inst_shm->DP80BUF); + evt.evt_data = inst_shm->DP80BUF; + espi_send_callbacks(host_sub_data.callbacks, + host_sub_data.host_bus_dev, evt); + } + + /* If FIFO is overflow, show error msg */ + if (IS_BIT_SET(status, NPCX_DP80STS_FOR)) { + inst_shm->DP80STS |= BIT(NPCX_DP80STS_FOR); + LOG_ERR("Port80 FIFO Overflow!"); + } + + /* Clear all pending bit indicates that FIFO was written by host */ + inst_shm->DP80STS |= BIT(NPCX_DP80STS_FWR); +} + +static void host_port80_init(void) +{ + struct shm_reg *const inst_shm = host_sub_cfg.inst_shm; + + /* + * Init PORT80 which includes: + * Enables a Core interrupt on every Host write to the FIFO, + * SYNC mode (It must be 1 in eSPI mode), Read Auto Advance mode, and + * Port80 module itself. + */ + inst_shm->DP80CTL = BIT(NPCX_DP80CTL_CIEN) | BIT(NPCX_DP80CTL_RAA) + | BIT(NPCX_DP80CTL_DP80EN) | BIT(NPCX_DP80CTL_SYNCEN); +} +#endif + +#if defined(CONFIG_ESPI_PERIPHERAL_UART) +/* host uart pinmux configuration */ +static const struct npcx_alt host_uart_alts[] = + DT_NPCX_ALT_ITEMS_LIST(0); +/* Host UART sub-device local functions */ +void host_uart_init(void) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + + /* Configure pin-mux for serial port device */ + soc_pinctrl_mux_configure(host_uart_alts, ARRAY_SIZE(host_uart_alts), + 1); + /* Make sure unlock host access of serial port */ + inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKSPHA); + /* Clear 'Host lock violation occurred' bit of serial port initially */ + inst_c2h->SIOLV |= BIT(NPCX_SIOLV_SPLV); +} +#endif + +/* host core-to-host interface local functions */ +static void host_c2h_wait_write_done(void) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + uint32_t elapsed_cycles; + uint32_t start_cycles = k_cycle_get_32(); + uint32_t max_wait_cycles = + k_us_to_cyc_ceil32(NPCX_C2H_TRANSACTION_TIMEOUT_US); + + while (IS_BIT_SET(inst_c2h->SIBCTRL, NPCX_SIBCTRL_CSWR)) { + elapsed_cycles = k_cycle_get_32() - start_cycles; + if (elapsed_cycles > max_wait_cycles) { + LOG_ERR("c2h write transaction expired!"); + break; + } + } +} + +static void host_c2h_wait_read_done(void) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + uint32_t elapsed_cycles; + uint32_t start_cycles = k_cycle_get_32(); + uint32_t max_wait_cycles = + k_us_to_cyc_ceil32(NPCX_C2H_TRANSACTION_TIMEOUT_US); + + while (IS_BIT_SET(inst_c2h->SIBCTRL, NPCX_SIBCTRL_CSRD)) { + elapsed_cycles = k_cycle_get_32() - start_cycles; + if (elapsed_cycles > max_wait_cycles) { + LOG_ERR("c2h read transaction expired!"); + break; + } + } +} + +void host_c2h_write_io_cfg_reg(uint8_t reg_index, uint8_t reg_data) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + + /* Disable interrupts */ + int key = irq_lock(); + + /* Lock host access EC configuration registers (0x4E/0x4F) */ + inst_c2h->LKSIOHA |= BIT(NPCX_LKSIOHA_LKCFG); + /* Enable Core-to-Host access CFG module */ + inst_c2h->CRSMAE |= BIT(NPCX_CRSMAE_CFGAE); + + /* Verify core-to-host modules is not in progress */ + host_c2h_wait_read_done(); + host_c2h_wait_write_done(); + + /* + * Specifying the in-direct IO address which A0 = 0 indicates the index + * register is accessed. Then write index address directly and it starts + * a write transaction to host sub-module on LPC/eSPI bus. + */ + inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR; + inst_c2h->IHD = reg_index; + host_c2h_wait_write_done(); + + /* + * Specifying the in-direct IO address which A0 = 1 indicates the data + * register is accessed. Then write data directly and it starts a write + * transaction to host sub-module on LPC/eSPI bus. + */ + inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR + 1; + inst_c2h->IHD = reg_data; + host_c2h_wait_write_done(); + + /* Disable Core-to-Host access CFG module */ + inst_c2h->CRSMAE &= ~BIT(NPCX_CRSMAE_CFGAE); + /* Unlock host access EC configuration registers (0x4E/0x4F) */ + inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKCFG); + + /* Enable interrupts */ + irq_unlock(key); +} + +uint8_t host_c2h_read_io_cfg_reg(uint8_t reg_index) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + uint8_t data_val; + + /* Disable interrupts */ + int key = irq_lock(); + + /* Lock host access EC configuration registers (0x4E/0x4F) */ + inst_c2h->LKSIOHA |= BIT(NPCX_LKSIOHA_LKCFG); + /* Enable Core-to-Host access CFG module */ + inst_c2h->CRSMAE |= BIT(NPCX_CRSMAE_CFGAE); + + /* Verify core-to-host modules is not in progress */ + host_c2h_wait_read_done(); + host_c2h_wait_write_done(); + + /* + * Specifying the in-direct IO address which A0 = 0 indicates the index + * register is accessed. Then write index address directly and it starts + * a write transaction to host sub-module on LPC/eSPI bus. + */ + inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR; + inst_c2h->IHD = reg_index; + host_c2h_wait_write_done(); + + /* + * Specifying the in-direct IO address which A0 = 1 indicates the data + * register is accessed. Then write CSRD bit in SIBCTRL to issue a read + * transaction to host sub-module on LPC/eSPI bus. Once it was done, + * read data out from IHD. + */ + inst_c2h->IHIOA = NPCX_EC_CFG_IO_ADDR + 1; + inst_c2h->SIBCTRL |= BIT(NPCX_SIBCTRL_CSRD); + host_c2h_wait_read_done(); + data_val = inst_c2h->IHD; + + /* Disable Core-to-Host access CFG module */ + inst_c2h->CRSMAE &= ~BIT(NPCX_CRSMAE_CFGAE); + /* Unlock host access EC configuration registers (0x4E/0x4F) */ + inst_c2h->LKSIOHA &= ~BIT(NPCX_LKSIOHA_LKCFG); + + /* Enable interrupts */ + irq_unlock(key); + + return data_val; +} + +/* Soc specific host sub modules functions */ +int soc_host_periph_read_request(enum lpc_peripheral_opcode op, + uint32_t *data) +{ + struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; + + if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { + /* Make sure kbc 8042 is on */ + if (!IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFKIE) || + !IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFMIE)) { + return -ENOTSUP; + } + + switch (op) { + case E8042_OBF_HAS_CHAR: + /* EC has written data back to host. OBF is + * automatically cleared after host reads + * the data + */ + *data = IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_OBF); + break; + case E8042_IBF_HAS_CHAR: + *data = IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_IBF); + break; + case E8042_READ_KB_STS: + *data = inst_kbc->HIKMST; + break; + default: + return -EINVAL; + } + } else { + /* TODO: Support more op code besides 8042 here */ + return -ENOTSUP; + } + + return 0; +} + +int soc_host_periph_write_request(enum lpc_peripheral_opcode op, + uint32_t *data) +{ + volatile uint32_t __attribute__((unused)) dummy; + struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; + + if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { + /* Make sure kbc 8042 is on */ + if (!IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFKIE) || + !IS_BIT_SET(inst_kbc->HICTRL, NPCX_HICTRL_OBFMIE)) { + return -ENOTSUP; + } + if (data) + LOG_INF("%s: op 0x%x data %x", __func__, op, *data); + else + LOG_INF("%s: op 0x%x only", __func__, op); + + switch (op) { + case E8042_WRITE_KB_CHAR: + inst_kbc->HIKDO = *data & 0xff; + /* + * Enable KBC OBE interrupt after putting data in + * keyboard data register. + */ + inst_kbc->HICTRL |= BIT(NPCX_HICTRL_OBECIE); + break; + case E8042_WRITE_MB_CHAR: + inst_kbc->HIMDO = *data & 0xff; + /* + * Enable KBC OBE interrupt after putting data in + * mouse data register. + */ + inst_kbc->HICTRL |= BIT(NPCX_HICTRL_OBECIE); + break; + case E8042_RESUME_IRQ: + /* Enable KBC IBF interrupt */ + inst_kbc->HICTRL |= BIT(NPCX_HICTRL_IBFCIE); + break; + case E8042_PAUSE_IRQ: + /* Disable KBC IBF interrupt */ + inst_kbc->HICTRL &= ~BIT(NPCX_HICTRL_IBFCIE); + break; + case E8042_CLEAR_OBF: + /* Clear OBF flag in both STATUS and HIKMST to 0 */ + inst_kbc->HICTRL |= BIT(NPCX_HICTRL_FW_OBF); + break; + case E8042_SET_FLAG: + /* FW shouldn't modify these flags directly */ + *data &= ~NPCX_KBC_STS_MASK; + inst_kbc->HIKMST |= *data; + break; + case E8042_CLEAR_FLAG: + /* FW shouldn't modify these flags directly */ + *data &= ~NPCX_KBC_STS_MASK; + inst_kbc->HIKMST &= ~(*data); + break; + default: + return -EINVAL; + } + } else { + /* TODO: Support more op code besides 8042 here! */ + return -ENOTSUP; + } + + return 0; +} + +void soc_host_init_subs_host_domain(void) +{ + struct c2h_reg *const inst_c2h = host_sub_cfg.inst_c2h; + + /* Enable Core-to-Host access module */ + inst_c2h->SIBCTRL |= BIT(NPCX_SIBCTRL_CSAE); + +#if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC) + /* + * Select Keyboard/Mouse banks which LDN are 0x06/05 and enable modules + * by setting bit 0 in its Control (index is 0x30) register. + */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_KBC); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_MOUSE); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); +#endif + +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) + /* + * Select ACPI bank which LDN are 0x11 (PM Channel 1) and enable + * module by setting bit 0 in its Control (index is 0x30) register. + */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_ACPI); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); +#endif + +#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) + /* Select 'Host Command' bank which LDN are 0x12 (PM Channel 2) */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_HCMD); + /* Configure IO address of CMD port (0x200) */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_H, 0x02); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_L, 0x00); + /* Configure IO address of Data port (0x204) */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_H, 0x02); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_L, 0x04); + /* Enable 'Host Command' io port (PM Channel 2) */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); + + /* Select 'Shared Memory' bank which LDN are 0x0F */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_SHM); + /* WIN 1 & 2 mapping to IO space */ + host_c2h_write_io_cfg_reg(0xF1, + host_c2h_read_io_cfg_reg(0xF1) | 0x30); + /* WIN1 as Host Command on the IO address 0x0800 */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_1, 0x08); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_0, 0x00); + /* WIN2 as MEMMAP on the IO address 0x900 */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_1, 0x09); + host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_0, 0x00); + /* Enable SHM direct memory access */ + host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); +#endif + LOG_DBG("Hos sub-modules configurations are done!"); +} + +int soc_host_init_subs_core_domain(const struct device *host_bus_dev, + sys_slist_t *callbacks) +{ + struct mswc_reg *const inst_mswc = host_sub_cfg.inst_mswc; + struct shm_reg *const inst_shm = host_sub_cfg.inst_shm; + const struct device *const clk_dev = + device_get_binding(NPCX_CLK_CTRL_NAME); + int i; + + host_sub_data.callbacks = callbacks; + host_sub_data.host_bus_dev = host_bus_dev; + + /* Turn on all host necessary sub-module clocks first */ + for (i = 0; i < host_sub_cfg.clks_size; i++) + if (clock_control_on(clk_dev, (clock_control_subsys_t *) + &host_sub_cfg.clks_list[i]) != 0) { + return -EIO; + } + + /* Configure EC legacy configuration IO base address to 0x4E. */ + if (!IS_BIT_SET(inst_mswc->MSWCTL1, NPCX_MSWCTL1_VHCFGA)) { + inst_mswc->HCBAL = NPCX_EC_CFG_IO_ADDR; + inst_mswc->HCBAH = 0x0; + } + + /* + * Set HOSTWAIT bit and avoid the other settings, then host can freely + * communicate with slave (EC). + */ + inst_shm->SMC_CTL &= BIT(NPCX_SMC_CTL_HOSTWAIT); + /* Clear shared memory status */ + inst_shm->SMC_STS = inst_shm->SMC_STS; + + /* host sub-module initialization in core domain */ +#if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC) + host_kbc_init(); +#endif +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) + host_acpi_init(); +#endif +#if defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) + host_hcmd_init(); +#endif +#if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80) + host_port80_init(); +#endif +#if defined(CONFIG_ESPI_PERIPHERAL_UART) + host_uart_init(); +#endif + + /* Host KBC sub-device interrupt installation */ +#if defined(CONFIG_ESPI_PERIPHERAL_8042_KBC) + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq), + DT_INST_IRQ_BY_NAME(0, kbc_ibf, priority), + host_kbc_ibf_isr, + NULL, 0); + irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq)); + + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq), + DT_INST_IRQ_BY_NAME(0, kbc_obe, priority), + host_kbc_obe_isr, + NULL, 0); + irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq)); +#endif + + /* Host PM channel (Host IO) sub-device interrupt installation */ +#if defined(CONFIG_ESPI_PERIPHERAL_HOST_IO) || \ + defined(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq), + DT_INST_IRQ_BY_NAME(0, pmch_ibf, priority), + host_pmch_ibf_isr, + NULL, 0); + irq_enable(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq)); +#endif + + /* Host Port80 sub-device interrupt installation */ +#if defined(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80) + IRQ_CONNECT(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq), + DT_INST_IRQ_BY_NAME(0, p80_fifo, priority), + host_port80_isr, + NULL, 0); + irq_enable(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq)); +#endif + + return 0; +} diff --git a/dts/arm/nuvoton/npcx7m6fb.dtsi b/dts/arm/nuvoton/npcx7m6fb.dtsi index 3d9c738d7bb..22b10236917 100644 --- a/dts/arm/nuvoton/npcx7m6fb.dtsi +++ b/dts/arm/nuvoton/npcx7m6fb.dtsi @@ -309,6 +309,45 @@ #vw-cells = <3>; status = "disabled"; }; + + host_sub: lpc@400c1000 { + compatible = "nuvoton,npcx-host-sub"; + /* host sub-module register address & size */ + reg = <0x400c1000 0x2000 + 0x40010000 0x2000 + 0x4000e000 0x2000 + 0x400c7000 0x2000 + 0x400c9000 0x2000 + 0x400cb000 0x2000>; + reg-names = "mswc", "shm", "c2h", "kbc", "pm_acpi", + "pm_hcmd"; + + /* host sub-module IRQ and priority */ + interrupts = <25 3>, /* KBC Input-Buf-Full (IBF) */ + <56 3>, /* KBC Output-Buf-Empty (OBE) */ + <26 3>, /* PMCH Input-Buf-Full (IBF) */ + <3 3>, /* PMCH Output-Buf-Empty (OBE) */ + <6 3>; /* Port80 FIFO Not Empty */ + interrupt-names = "kbc_ibf", "kbc_obe", "pmch_ibf", + "pmch_obe", "p80_fifo"; + + /* Host serial port pinmux PIN75 86 36 33 42 C7 B3 B2 */ + pinctrl = <&altb_rxd_sl &altb_txd_sl + &altb_rts_sl &altb_cts_sl + &altb_ri_sl &altb_dtr_bout_sl + &altb_dcd_sl &altb_dsr_sl>; + + /* WUI map for accessing host sub-modules */ + host_acc_wui = <&wui_host_acc>; + + /* clocks for host sub-modules */ + clocks = <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 3>, + <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 4>, + <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 5>, + <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 6>, + <&pcc NPCX_CLOCK_BUS_APB3 NPCX_PWDWN_CTL5 7>; + label = "HOST_SUBS"; + }; }; }; diff --git a/dts/bindings/espi/nuvoton,npcx-host-sub.yaml b/dts/bindings/espi/nuvoton,npcx-host-sub.yaml new file mode 100644 index 00000000000..048fcf50d2a --- /dev/null +++ b/dts/bindings/espi/nuvoton,npcx-host-sub.yaml @@ -0,0 +1,32 @@ +# Copyright (c) 2020 Nuvoton Technology Corporation. +# SPDX-License-Identifier: Apache-2.0 + +description: Nuvoton, NPCX-Host Sub-Modules node + +compatible: "nuvoton,npcx-host-sub" + +include: [base.yaml] + +properties: + reg: + description: mmio register space + required: true + + clocks: + required: true + description: configurations of device source clock controller + + pinctrl: + type: phandles + required: true + description: configurations of host uart pinmux controllers + + host_acc_wui: + type: phandle + required: true + description: | + Mapping table between Wake-Up Input (WUI) and any legacy host + access transactions. + + For example the WUI mapping on NPCX7 would be + host_acc_wui = <&wui_host_acc>; diff --git a/soc/arm/nuvoton_npcx/common/reg/reg_def.h b/soc/arm/nuvoton_npcx/common/reg/reg_def.h index 5e3f2ee2b75..0154cf05df0 100644 --- a/soc/arm/nuvoton_npcx/common/reg/reg_def.h +++ b/soc/arm/nuvoton_npcx/common/reg/reg_def.h @@ -467,4 +467,296 @@ struct espi_reg { #define NPCX_FLASHCTL_CHKSUMSEL 15 #define NPCX_FLASHCTL_AMTEN 16 +/* + * Mobile System Wake-Up Control (MSWC) device registers + */ +struct mswc_reg { + /* 0x000: MSWC Control Status 1 */ + volatile uint8_t MSWCTL1; + volatile uint8_t reserved1; + /* 0x002: MSWC Control Status 2 */ + volatile uint8_t MSWCTL2; + volatile uint8_t reserved2[5]; + /* 0x008: Host Configuration Base Address Low */ + volatile uint8_t HCBAL; + volatile uint8_t reserved3; + /* 0x00A: Host Configuration Base Address High */ + volatile uint8_t HCBAH; + volatile uint8_t reserved4; + /* 0X00C: MSWC INTERRUPT ENABLE 2 */ + volatile uint8_t MSIEN2; + volatile uint8_t reserved5; + /* 0x00E: MSWC Host Event Status 0 */ + volatile uint8_t MSHES0; + volatile uint8_t reserved6; + /* 0x010: MSWC Host Event Interrupt Enable */ + volatile uint8_t MSHEIE0; + volatile uint8_t reserved7; + /* 0x012: Host Control */ + volatile uint8_t HOST_CTL; + volatile uint8_t reserved8; + /* 0x014: SMI Pulse Length */ + volatile uint8_t SMIP_LEN; + volatile uint8_t reserved9; + /* 0x016: SCI Pulse Length */ + volatile uint8_t SCIP_LEN; + volatile uint8_t reserved10[5]; + /* 0x01C: SRID Core Access */ + volatile uint8_t SRID_CR; + volatile uint8_t reserved11[3]; + /* 0x020: SID Core Access */ + volatile uint8_t SID_CR; + volatile uint8_t reserved12; + /* 0x022: DEVICE_ID Core Access */ + volatile uint8_t DEVICE_ID_CR; + volatile uint8_t reserved13[5]; + /* 0x028: Chip Revision Core Access */ + volatile uint8_t CHPREV_CR; + volatile uint8_t reserved14[5]; + /* 0x02E: Virtual Wire Sleep States */ + volatile uint8_t VW_SLPST1; + volatile uint8_t reserved15; +}; + +/* MSWC register fields */ +#define NPCX_MSWCTL1_HRSTOB 0 +#define NPCS_MSWCTL1_HWPRON 1 +#define NPCX_MSWCTL1_PLTRST_ACT 2 +#define NPCX_MSWCTL1_VHCFGA 3 +#define NPCX_MSWCTL1_HCFGLK 4 +#define NPCX_MSWCTL1_PWROFFB 6 +#define NPCX_MSWCTL1_A20MB 7 + +/* + * Shared Memory (SHM) device registers + */ +struct shm_reg { + /* 0x000: Shared Memory Core Status */ + volatile uint8_t SMC_STS; + /* 0x001: Shared Memory Core Control */ + volatile uint8_t SMC_CTL; + /* 0x002: Shared Memory Host Control */ + volatile uint8_t SHM_CTL; + volatile uint8_t reserved1[2]; + /* 0x005: Indirect Memory Access Window Size */ + volatile uint8_t IMA_WIN_SIZE; + volatile uint8_t reserved2; + /* 0x007: Shared Access Windows Size */ + volatile uint8_t WIN_SIZE; + /* 0x008: Shared Access Window 1, Semaphore */ + volatile uint8_t SHAW1_SEM; + /* 0x009: Shared Access Window 2, Semaphore */ + volatile uint8_t SHAW2_SEM; + volatile uint8_t reserved3; + /* 0x00B: Indirect Memory Access, Semaphore */ + volatile uint8_t IMA_SEM; + volatile uint8_t reserved4[2]; + /* 0x00E: Shared Memory Configuration */ + volatile uint16_t SHCFG; + /* 0x010: Shared Access Window 1 Write Protect */ + volatile uint8_t WIN1_WR_PROT; + /* 0x011: Shared Access Window 1 Read Protect */ + volatile uint8_t WIN1_RD_PROT; + /* 0x012: Shared Access Window 2 Write Protect */ + volatile uint8_t WIN2_WR_PROT; + /* 0x013: Shared Access Window 2 Read Protect */ + volatile uint8_t WIN2_RD_PROT; + volatile uint8_t reserved5[2]; + /* 0x016: Indirect Memory Access Write Protect */ + volatile uint8_t IMA_WR_PROT; + /* 0x017: Indirect Memory Access Read Protect */ + volatile uint8_t IMA_RD_PROT; + volatile uint8_t reserved6[8]; + /* 0x020: Shared Access Window 1 Base */ + volatile uint32_t WIN_BASE1; + /* 0x024: Shared Access Window 2 Base */ + volatile uint32_t WIN_BASE2; + volatile uint32_t reserved7; + /* 0x02C: Indirect Memory Access Base */ + volatile uint32_t IMA_BASE; + volatile uint8_t reserved8[10]; + /* 0x03A: Reset Configuration */ + volatile uint8_t RST_CFG; + volatile uint8_t reserved9[5]; + /* 0x040: Debug Port 80 Buffered Data */ + volatile uint16_t DP80BUF; + /* 0x042: Debug Port 80 Status */ + volatile uint8_t DP80STS; + volatile uint8_t reserved10; + /* 0x044: Debug Port 80 Control */ + volatile uint8_t DP80CTL; + volatile uint8_t reserved11[3]; + /* 0x048: Host_Offset in Windows 1, 2 Status */ + volatile uint8_t HOFS_STS; + /* 0x049: Host_Offset in Windows 1, 2 Control */ + volatile uint8_t HOFS_CTL; + /* 0x04A: Core_Offset in Window 2 Address */ + volatile uint16_t COFS2; + /* 0x04C: Core_Offset in Window 1 Address */ + volatile uint16_t COFS1; + volatile uint16_t reserved12; +}; + +/* SHM register fields */ +#define NPCX_SMC_STS_HRERR 0 +#define NPCX_SMC_STS_HWERR 1 +#define NPCX_SMC_STS_HSEM1W 4 +#define NPCX_SMC_STS_HSEM2W 5 +#define NPCX_SMC_STS_SHM_ACC 6 +#define NPCX_SMC_CTL_HERR_IE 2 +#define NPCX_SMC_CTL_HSEM1_IE 3 +#define NPCX_SMC_CTL_HSEM2_IE 4 +#define NPCX_SMC_CTL_ACC_IE 5 +#define NPCX_SMC_CTL_PREF_EN 6 +#define NPCX_SMC_CTL_HOSTWAIT 7 +#define NPCX_FLASH_SIZE_STALL_HOST 6 +#define NPCX_FLASH_SIZE_RD_BURST 7 +#define NPCX_WIN_PROT_RW1L_RP 0 +#define NPCX_WIN_PROT_RW1L_WP 1 +#define NPCX_WIN_PROT_RW1H_RP 2 +#define NPCX_WIN_PROT_RW1H_WP 3 +#define NPCX_WIN_PROT_RW2L_RP 4 +#define NPCX_WIN_PROT_RW2L_WP 5 +#define NPCX_WIN_PROT_RW2H_RP 6 +#define NPCX_WIN_PROT_RW2H_WP 7 +#define NPCX_PWIN_SIZEI_RPROT 13 +#define NPCX_PWIN_SIZEI_WPROT 14 +#define NPCX_CSEM2 6 +#define NPCX_CSEM3 7 +#define NPCX_DP80STS_FWR 5 +#define NPCX_DP80STS_FNE 6 +#define NPCX_DP80STS_FOR 7 +#define NPCX_DP80CTL_DP80EN 0 +#define NPCX_DP80CTL_SYNCEN 1 +#define NPCX_DP80CTL_ADV 2 +#define NPCX_DP80CTL_RAA 3 +#define NPCX_DP80CTL_RFIFO 4 +#define NPCX_DP80CTL_CIEN 5 +#define NPCX_DP80CTL_DP80_HF_CFG 7 + +/* + * Keyboard and Mouse Controller (KBC) device registers + */ +struct kbc_reg { + /* 0x000h: Host Interface Control */ + volatile uint8_t HICTRL; + volatile uint8_t reserved1; + /* 0x002h: Host Interface IRQ Control */ + volatile uint8_t HIIRQC; + volatile uint8_t reserved2; + /* 0x004h: Host Interface Keyboard/Mouse Status */ + volatile uint8_t HIKMST; + volatile uint8_t reserved3; + /* 0x006h: Host Interface Keyboard Data Out Buffer */ + volatile uint8_t HIKDO; + volatile uint8_t reserved4; + /* 0x008h: Host Interface Mouse Data Out Buffer */ + volatile uint8_t HIMDO; + volatile uint8_t reserved5; + /* 0x00Ah: Host Interface Keyboard/Mouse Data In Buffer */ + volatile uint8_t HIKMDI; + /* 0x00Bh: Host Interface Keyboard/Mouse Shadow Data In Buffer */ + volatile uint8_t SHIKMDI; +}; + +/* KBC register field */ +#define NPCX_HICTRL_OBFKIE 0 +#define NPCX_HICTRL_OBFMIE 1 +#define NPCX_HICTRL_OBECIE 2 +#define NPCX_HICTRL_IBFCIE 3 +#define NPCX_HICTRL_PMIHIE 4 +#define NPCX_HICTRL_PMIOCIE 5 +#define NPCX_HICTRL_PMICIE 6 +#define NPCX_HICTRL_FW_OBF 7 +#define NPCX_HIKMST_OBF 0 +#define NPCX_HIKMST_IBF 1 +#define NPCX_HIKMST_F0 2 +#define NPCX_HIKMST_A2 3 +#define NPCX_HIKMST_ST0 4 +#define NPCX_HIKMST_ST1 5 +#define NPCX_HIKMST_ST2 6 +#define NPCX_HIKMST_ST3 7 + +/* + * Power Management Channel (PMCH) device registers + */ +struct pmch_reg { + /* 0x000: Host Interface PM Status */ + volatile uint8_t HIPMST; + volatile uint8_t reserved1; + /* 0x002: Host Interface PM Data Out Buffer */ + volatile uint8_t HIPMDO; + volatile uint8_t reserved2; + /* 0x004: Host Interface PM Data In Buffer */ + volatile uint8_t HIPMDI; + /* 0x005: Host Interface PM Shadow Data In Buffer */ + volatile uint8_t SHIPMDI; + /* 0x006: Host Interface PM Data Out Buffer with SCI */ + volatile uint8_t HIPMDOC; + volatile uint8_t reserved3; + /* 0x008: Host Interface PM Data Out Buffer with SMI */ + volatile uint8_t HIPMDOM; + volatile uint8_t reserved4; + /* 0x00A: Host Interface PM Data In Buffer with SCI */ + volatile uint8_t HIPMDIC; + volatile uint8_t reserved5; + /* 0x00C: Host Interface PM Control */ + volatile uint8_t HIPMCTL; + /* 0x00D: Host Interface PM Control 2 */ + volatile uint8_t HIPMCTL2; + /* 0x00E: Host Interface PM Interrupt Control */ + volatile uint8_t HIPMIC; + volatile uint8_t reserved6; + /* 0x010: Host Interface PM Interrupt Enable */ + volatile uint8_t HIPMIE; + volatile uint8_t reserved7; +}; + +/* PMCH register field */ +#define NPCX_HIPMIE_SCIE 1 +#define NPCX_HIPMIE_SMIE 2 +#define NPCX_HIPMCTL_IBFIE 0 +#define NPCX_HIPMCTL_SCIPOL 6 +#define NPCX_HIPMST_OBF 0 +#define NPCX_HIPMST_IBF 1 +#define NPCX_HIPMST_F0 2 +#define NPCX_HIPMST_CMD 3 +#define NPCX_HIPMST_ST0 4 +#define NPCX_HIPMST_ST1 5 +#define NPCX_HIPMST_ST2 6 +#define NPCX_HIPMIC_SMIB 1 +#define NPCX_HIPMIC_SCIB 2 +#define NPCX_HIPMIC_SMIPOL 6 + +/* + * Core Access to Host (C2H) device registers + */ +struct c2h_reg { + /* 0x000: Indirect Host I/O Address */ + volatile uint16_t IHIOA; + /* 0x002: Indirect Host Data */ + volatile uint8_t IHD; + volatile uint8_t reserved1; + /* 0x004: Lock Host Access */ + volatile uint16_t LKSIOHA; + /* 0x006: Access Lock Violation */ + volatile uint16_t SIOLV; + /* 0x008: Core-to-Host Modules Access Enable */ + volatile uint16_t CRSMAE; + /* 0x00A: Module Control */ + volatile uint8_t SIBCTRL; + volatile uint8_t reserved3; +}; + +/* C2H register fields */ +#define NPCX_LKSIOHA_LKCFG 0 +#define NPCX_LKSIOHA_LKSPHA 2 +#define NPCX_LKSIOHA_LKHIKBD 11 +#define NPCX_CRSMAE_CFGAE 0 +#define NPCX_CRSMAE_HIKBDAE 11 +#define NPCX_SIOLV_SPLV 2 +#define NPCX_SIBCTRL_CSAE 0 +#define NPCX_SIBCTRL_CSRD 1 +#define NPCX_SIBCTRL_CSWR 2 + #endif /* _NUVOTON_NPCX_REG_DEF_H */ diff --git a/soc/arm/nuvoton_npcx/common/soc_host.h b/soc/arm/nuvoton_npcx/common/soc_host.h new file mode 100644 index 00000000000..1bcfd4f3324 --- /dev/null +++ b/soc/arm/nuvoton_npcx/common/soc_host.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020 Nuvoton Technology Corporation. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NUVOTON_NPCX_SOC_HOST_H_ +#define _NUVOTON_NPCX_SOC_HOST_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initializes all host sub-modules in Core domain. + * + * This routine initalizes all host sub-modules which HW blocks belong to + * Core domain. And it also saves the pointer of eSPI callback list to report + * any peripheral events application layer. + * + * @param dev Pointer to the device structure for the host bus driver instance. + * @param callbacks A pointer to the list of espi callback functions. + * + * @retval 0 If successful. + * @retval -EIO if cannot turn on host sub-module source clocks in core domain. + */ +int soc_host_init_subs_core_domain(const struct device *host_bus_dev, + sys_slist_t *callbacks); + +/** + * @brief Initializes all host sub-modules in Host domain. + * + * This routine initalizes all host sub-modules which HW blocks belong to + * Host domain. Please notcie it must be executed after receiving PLT_RST + * de-asserted signal and eSPI peripheral channel is enabled and ready. + */ +void soc_host_init_subs_host_domain(void); + +/** + * @brief Reads data from a host sub-module which is updated via eSPI. + * + * This routine provides a generic interface to read a host sub-module which + * information was updated by an eSPI transaction through peripheral channel. + * + * @param op Enum representing opcode for peripheral type and read request. + * @param data Parameter to be read from to the host sub-module. + * + * @retval 0 If successful. + * @retval -ENOTSUP if eSPI peripheral is off or not supported. + * @retval -EINVAL for unimplemented lpc opcode, but in range. + */ +int soc_host_periph_read_request(enum lpc_peripheral_opcode op, + uint32_t *data); + +/** + * @brief Writes data to a host sub-module which generates an eSPI transaction. + * + * This routine provides a generic interface to write data to a host sub-module + * which triggers an eSPI transaction through peripheral channel. + * + * @param op Enum representing an opcode for peripheral type and write request. + * @param data Represents the parameter passed to the host sub-module. + * + * @retval 0 If successful. + * @retval -ENOTSUP if eSPI peripheral is off or not supported. + * @retval -EINVAL for unimplemented lpc opcode, but in range. + */ +int soc_host_periph_write_request(enum lpc_peripheral_opcode op, + uint32_t *data); + +#ifdef __cplusplus +} +#endif + +#endif /* _NUVOTON_NPCX_SOC_HOST_H_ */ diff --git a/soc/arm/nuvoton_npcx/npcx7/soc.c b/soc/arm/nuvoton_npcx/npcx7/soc.c index ee97c5916a1..664b1347439 100644 --- a/soc/arm/nuvoton_npcx/npcx7/soc.c +++ b/soc/arm/nuvoton_npcx/npcx7/soc.c @@ -56,3 +56,46 @@ NPCX_REG_OFFSET_CHECK(espi_reg, OOBTXBUF, 0x380); NPCX_REG_OFFSET_CHECK(espi_reg, OOBCTL_DIRECT, 0x3FC); NPCX_REG_OFFSET_CHECK(espi_reg, FLASHTXBUF, 0x480); NPCX_REG_OFFSET_CHECK(espi_reg, FLASHCTL_DIRECT, 0x4FC); + +/* MSWC register structure check */ +NPCX_REG_SIZE_CHECK(mswc_reg, 0x030); +NPCX_REG_OFFSET_CHECK(mswc_reg, HCBAL, 0x008); +NPCX_REG_OFFSET_CHECK(mswc_reg, HCBAH, 0x00A); +NPCX_REG_OFFSET_CHECK(mswc_reg, SRID_CR, 0x01C); +NPCX_REG_OFFSET_CHECK(mswc_reg, SID_CR, 0x020); +NPCX_REG_OFFSET_CHECK(mswc_reg, VW_SLPST1, 0x2E); + +/* SHM register structure check */ +NPCX_REG_SIZE_CHECK(shm_reg, 0x050); +NPCX_REG_OFFSET_CHECK(shm_reg, IMA_WIN_SIZE, 0x005); +NPCX_REG_OFFSET_CHECK(shm_reg, WIN_SIZE, 0x007); +NPCX_REG_OFFSET_CHECK(shm_reg, IMA_SEM, 0x00B); +NPCX_REG_OFFSET_CHECK(shm_reg, SHCFG, 0x00E); +NPCX_REG_OFFSET_CHECK(shm_reg, WIN1_WR_PROT, 0x010); +NPCX_REG_OFFSET_CHECK(shm_reg, IMA_WR_PROT, 0x016); +NPCX_REG_OFFSET_CHECK(shm_reg, WIN_BASE1, 0x020); +NPCX_REG_OFFSET_CHECK(shm_reg, WIN_BASE2, 0x024); +NPCX_REG_OFFSET_CHECK(shm_reg, RST_CFG, 0x03A); +NPCX_REG_OFFSET_CHECK(shm_reg, DP80BUF, 0x040); +NPCX_REG_OFFSET_CHECK(shm_reg, DP80CTL, 0x044); +NPCX_REG_OFFSET_CHECK(shm_reg, HOFS_STS, 0x048); +NPCX_REG_OFFSET_CHECK(shm_reg, COFS1, 0x04C); + +/* KBC register structure check */ +NPCX_REG_SIZE_CHECK(kbc_reg, 0x00C); +NPCX_REG_OFFSET_CHECK(kbc_reg, HIKMDI, 0x00A); +NPCX_REG_OFFSET_CHECK(kbc_reg, SHIKMDI, 0x00B); + +/* PMCH register structure check */ +NPCX_REG_SIZE_CHECK(pmch_reg, 0x012); +NPCX_REG_OFFSET_CHECK(pmch_reg, HIPMDO, 0x002); +NPCX_REG_OFFSET_CHECK(pmch_reg, HIPMDOC, 0x006); +NPCX_REG_OFFSET_CHECK(pmch_reg, HIPMDOM, 0x008); +NPCX_REG_OFFSET_CHECK(pmch_reg, HIPMDIC, 0x00A); +NPCX_REG_OFFSET_CHECK(pmch_reg, HIPMIE, 0x010); + +/* C2H register structure check */ +NPCX_REG_SIZE_CHECK(c2h_reg, 0x00C); +NPCX_REG_OFFSET_CHECK(c2h_reg, LKSIOHA, 0x004); +NPCX_REG_OFFSET_CHECK(c2h_reg, CRSMAE, 0x008); +NPCX_REG_OFFSET_CHECK(c2h_reg, SIBCTRL, 0x00A);