|  | /* | 
|  | * 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 <assert.h> | 
|  | #include <drivers/espi.h> | 
|  | #include <drivers/gpio.h> | 
|  | #include <drivers/clock_control.h> | 
|  | #include <kernel.h> | 
|  | #include <soc.h> | 
|  | #include "espi_utils.h" | 
|  | #include "soc_host.h" | 
|  | #include "soc_espi.h" | 
|  | #include "soc_miwu.h" | 
|  |  | 
|  | #include <logging/log.h> | 
|  | 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[] = | 
|  | NPCX_DT_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 = NPCX_DT_WUI_ITEM_BY_NAME(0, 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 | 
|  |  | 
|  | /* 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 sub-device local inline functions */ | 
|  | static inline uint8_t host_shd_mem_wnd_size_sl(uint32_t size) | 
|  | { | 
|  | /* The minimum supported shared memory region size is 8 bytes */ | 
|  | if (size <= 8U) { | 
|  | size = 8U; | 
|  | } | 
|  |  | 
|  | /* The maximum supported shared memory region size is 4K bytes */ | 
|  | if (size >= 4096U) { | 
|  | size = 4096U; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * If window size is not a power-of-two, it is rounded-up to the next | 
|  | * power-of-two value, and return value corresponds to RWINx_SIZE field. | 
|  | */ | 
|  | return (32 - __builtin_clz(size - 1U)) & 0xff; | 
|  | } | 
|  |  | 
|  | /* 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 = NPCX_8042_EVT_DATA(NPCX_8042_EVT_IBF, inst_kbc->HIKMDI, | 
|  | IS_BIT_SET(inst_kbc->HIKMST, NPCX_HIKMST_A2)); | 
|  |  | 
|  | 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; | 
|  | struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, | 
|  | ESPI_PERIPHERAL_8042_KBC, ESPI_PERIPHERAL_NODATA | 
|  | }; | 
|  |  | 
|  | /* Disable KBC OBE interrupt first */ | 
|  | inst_kbc->HICTRL &= ~BIT(NPCX_HICTRL_OBECIE); | 
|  |  | 
|  | LOG_DBG("%s: kbc status 0x%02x", __func__, inst_kbc->HIKMST); | 
|  |  | 
|  | /* | 
|  | * Notify application that host already read out data. The application | 
|  | * might need to clear status register via espi_api_lpc_write_request() | 
|  | * with E8042_CLEAR_FLAG opcode in callback. | 
|  | */ | 
|  | evt.evt_data = NPCX_8042_EVT_DATA(NPCX_8042_EVT_OBE, 0, 0); | 
|  | espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, | 
|  | evt); | 
|  | } | 
|  |  | 
|  | 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 pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi; | 
|  | 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); | 
|  |  | 
|  | /* | 
|  | * 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 = (data << NPCX_ACPI_DATA_POS) | | 
|  | (IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_CMD) << | 
|  | NPCX_ACPI_TYPE_POS); | 
|  | 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_host_cmd[CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE] | 
|  | __aligned(8); | 
|  | /* Host command sub-device local functions */ | 
|  | static void host_hcmd_process_input_data(uint8_t data) | 
|  | { | 
|  | struct espi_event evt = { ESPI_BUS_PERIPHERAL_NOTIFICATION, | 
|  | ESPI_PERIPHERAL_EC_HOST_CMD, ESPI_PERIPHERAL_NODATA | 
|  | }; | 
|  |  | 
|  | evt.evt_data = data; | 
|  | LOG_DBG("%s: host cmd data 0x%02x", __func__, evt.evt_data); | 
|  | espi_send_callbacks(host_sub_data.callbacks, host_sub_data.host_bus_dev, | 
|  | evt); | 
|  | } | 
|  |  | 
|  | 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; | 
|  | uint32_t win_size = CONFIG_ESPI_NPCX_PERIPHERAL_HOST_CMD_PARAM_SIZE; | 
|  |  | 
|  | /* Don't stall SHM transactions */ | 
|  | inst_shm->SHM_CTL &= ~0x40; | 
|  | /* Disable Window 1 protection */ | 
|  | inst_shm->WIN1_WR_PROT = 0; | 
|  | inst_shm->WIN1_RD_PROT = 0; | 
|  |  | 
|  | /* Configure Win1 size for ec host command. */ | 
|  | SET_FIELD(inst_shm->WIN_SIZE, NPCX_WIN_SIZE_RWIN1_SIZE_FIELD, | 
|  | host_shd_mem_wnd_size_sl(win_size)); | 
|  | inst_shm->WIN_BASE1 = (uint32_t)shm_host_cmd; | 
|  |  | 
|  | /* | 
|  | * 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_ACPI_SHM_REGION) | 
|  | /* Host command argument and memory map buffers */ | 
|  | static uint8_t shm_acpi_mmap[CONFIG_ESPI_NPCX_PERIPHERAL_ACPI_SHD_MEM_SIZE] | 
|  | __aligned(8); | 
|  | static void host_shared_mem_region_init(void) | 
|  | { | 
|  | struct shm_reg *const inst_shm = host_sub_cfg.inst_shm; | 
|  | uint32_t win_size = CONFIG_ESPI_NPCX_PERIPHERAL_ACPI_SHD_MEM_SIZE; | 
|  |  | 
|  | /* Don't stall SHM transactions */ | 
|  | inst_shm->SHM_CTL &= ~0x40; | 
|  | /* Disable Window 2 protection */ | 
|  | inst_shm->WIN2_WR_PROT = 0; | 
|  | inst_shm->WIN2_RD_PROT = 0; | 
|  |  | 
|  | /* Configure Win2 size for ACPI shared mem region. */ | 
|  | SET_FIELD(inst_shm->WIN_SIZE, NPCX_WIN_SIZE_RWIN2_SIZE_FIELD, | 
|  | host_shd_mem_wnd_size_sl(win_size)); | 
|  | inst_shm->WIN_BASE2 = (uint32_t)shm_acpi_mmap; | 
|  | /* Enable write protect of Share memory window 2 */ | 
|  | inst_shm->WIN2_WR_PROT = 0xFF; | 
|  |  | 
|  | /* | 
|  | * TODO: Initialize shm_acpi_mmap buffer for host command flags. We | 
|  | * might use EACPI_GET_SHARED_MEMORY in espi_api_lpc_read_request() | 
|  | * instead of setting host command flags here directly. | 
|  | */ | 
|  | } | 
|  | #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_CUSTOM_OPCODE) | 
|  | static void host_cus_opcode_enable_interrupts(void) | 
|  | { | 
|  | /* Enable host KBC sub-device interrupt */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) { | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq)); | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq)); | 
|  | } | 
|  |  | 
|  | /* Enable host PM channel (Host IO) sub-device interrupt */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO) || | 
|  | IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) { | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq)); | 
|  | } | 
|  |  | 
|  | /* Enable host Port80 sub-device interrupt installation */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)) { | 
|  | irq_enable(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq)); | 
|  | } | 
|  |  | 
|  | /* Enable host interface interrupts if its interface is eSPI */ | 
|  | if (IS_ENABLED(CONFIG_ESPI)) { | 
|  | npcx_espi_enable_interrupts(host_sub_data.host_bus_dev); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void host_cus_opcode_disable_interrupts(void) | 
|  | { | 
|  | /* Disable host KBC sub-device interrupt */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_8042_KBC)) { | 
|  | irq_disable(DT_INST_IRQ_BY_NAME(0, kbc_ibf, irq)); | 
|  | irq_disable(DT_INST_IRQ_BY_NAME(0, kbc_obe, irq)); | 
|  | } | 
|  |  | 
|  | /* Disable host PM channel (Host IO) sub-device interrupt */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_HOST_IO) || | 
|  | IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD)) { | 
|  | irq_disable(DT_INST_IRQ_BY_NAME(0, pmch_ibf, irq)); | 
|  | } | 
|  |  | 
|  | /* Disable host Port80 sub-device interrupt installation */ | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_DEBUG_PORT_80)) { | 
|  | irq_disable(DT_INST_IRQ_BY_NAME(0, p80_fifo, irq)); | 
|  | } | 
|  |  | 
|  | /* Disable host interface interrupts if its interface is eSPI */ | 
|  | if (IS_ENABLED(CONFIG_ESPI)) { | 
|  | npcx_espi_disable_interrupts(host_sub_data.host_bus_dev); | 
|  | } | 
|  | } | 
|  | #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */ | 
|  |  | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_UART) | 
|  | /* host uart pinmux configuration */ | 
|  | static const struct npcx_alt host_uart_alts[] = | 
|  | NPCX_DT_IO_ALT_ITEMS_LIST(nuvoton_npcx_host_uart, 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 */ | 
|  | npcx_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; | 
|  | } | 
|  |  | 
|  | /* Platform specific host sub modules functions */ | 
|  | int npcx_host_periph_read_request(enum lpc_peripheral_opcode op, | 
|  | uint32_t *data) | 
|  | { | 
|  | if (op >= E8042_START_OPCODE && op <= E8042_MAX_OPCODE) { | 
|  | struct kbc_reg *const inst_kbc = host_sub_cfg.inst_kbc; | 
|  |  | 
|  | /* 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 if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) { | 
|  | struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi; | 
|  |  | 
|  | /* Make sure pm channel for apci is on */ | 
|  | if (!IS_BIT_SET(inst_acpi->HIPMCTL, NPCX_HIPMCTL_IBFIE)) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | switch (op) { | 
|  | case EACPI_OBF_HAS_CHAR: | 
|  | /* EC has written data back to host. OBF is | 
|  | * automatically cleared after host reads | 
|  | * the data | 
|  | */ | 
|  | *data = IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_OBF); | 
|  | break; | 
|  | case EACPI_IBF_HAS_CHAR: | 
|  | *data = IS_BIT_SET(inst_acpi->HIPMST, NPCX_HIPMST_IBF); | 
|  | break; | 
|  | case EACPI_READ_STS: | 
|  | *data = inst_acpi->HIPMST; | 
|  | break; | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION) | 
|  | case EACPI_GET_SHARED_MEMORY: | 
|  | *data = (uint32_t)shm_acpi_mmap; | 
|  | break; | 
|  | #endif /* CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION */ | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE) | 
|  | else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) { | 
|  | /* Other customized op codes */ | 
|  | switch (op) { | 
|  | case ECUSTOM_HOST_CMD_GET_PARAM_MEMORY: | 
|  | *data = (uint32_t)shm_host_cmd; | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  | #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */ | 
|  | else { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int npcx_host_periph_write_request(enum lpc_peripheral_opcode op, | 
|  | const 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 */ | 
|  | inst_kbc->HIKMST |= *data & ~NPCX_KBC_STS_MASK; | 
|  | break; | 
|  | case E8042_CLEAR_FLAG: | 
|  | /* FW shouldn't modify these flags directly */ | 
|  | inst_kbc->HIKMST &= ~(*data | NPCX_KBC_STS_MASK); | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } else if (op >= EACPI_START_OPCODE && op <= EACPI_MAX_OPCODE) { | 
|  | struct pmch_reg *const inst_acpi = host_sub_cfg.inst_pm_acpi; | 
|  |  | 
|  | /* Make sure pm channel for apci is on */ | 
|  | if (!IS_BIT_SET(inst_acpi->HIPMCTL, NPCX_HIPMCTL_IBFIE)) { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | switch (op) { | 
|  | case EACPI_WRITE_CHAR: | 
|  | inst_acpi->HIPMDO = (*data & 0xff); | 
|  | break; | 
|  | case EACPI_WRITE_STS: | 
|  | inst_acpi->HIPMST = (*data & 0xff); | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE) | 
|  | else if (op >= ECUSTOM_START_OPCODE && op <= ECUSTOM_MAX_OPCODE) { | 
|  | /* Other customized op codes */ | 
|  | struct pmch_reg *const inst_hcmd = host_sub_cfg.inst_pm_hcmd; | 
|  |  | 
|  | switch (op) { | 
|  | case ECUSTOM_HOST_SUBS_INTERRUPT_EN: | 
|  | if (*data != 0) { | 
|  | host_cus_opcode_enable_interrupts(); | 
|  | } else { | 
|  | host_cus_opcode_disable_interrupts(); | 
|  | } | 
|  | break; | 
|  | case ECUSTOM_HOST_CMD_SEND_RESULT: | 
|  | /* | 
|  | * Write result to the data byte.  This sets the TOH | 
|  | * status bit. | 
|  | */ | 
|  | inst_hcmd->HIPMDO = (*data & 0xff); | 
|  | /* Clear processing flag */ | 
|  | inst_hcmd->HIPMST &= ~BIT(NPCX_HIPMST_F0); | 
|  | break; | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | } | 
|  | #endif /* CONFIG_ESPI_PERIPHERAL_CUSTOM_OPCODE */ | 
|  | else { | 
|  | return -ENOTSUP; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void npcx_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 (IS_ENABLED(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) reg. | 
|  | */ | 
|  | 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); | 
|  | } | 
|  |  | 
|  | if (IS_ENABLED(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) reg. | 
|  | */ | 
|  | 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); | 
|  | } | 
|  |  | 
|  | if (IS_ENABLED(CONFIG_ESPI_PERIPHERAL_EC_HOST_CMD) || | 
|  | IS_ENABLED(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION)) { | 
|  | /* Select 'Host Command' bank which LDN are 0x12 (PM chan 2) */ | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_LDN, EC_CFG_LDN_HCMD); | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM) | 
|  | /* Configure IO address of CMD portt (default: 0x200) */ | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_H, | 
|  | (CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM >> 8) & 0xff); | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_CMD_IO_ADDR_L, | 
|  | CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM & 0xff); | 
|  | /* Configure IO address of Data portt (default: 0x204) */ | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_H, | 
|  | ((CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) >> 8) | 
|  | & 0xff); | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_DATA_IO_ADDR_L, | 
|  | (CONFIG_ESPI_PERIPHERAL_HOST_CMD_DATA_PORT_NUM + 4) & 0xff); | 
|  | #endif | 
|  | /* 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 (default: 0x0800) */ | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM) | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_1, | 
|  | (CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM >> 8) & 0xff); | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND1_ADDR_0, | 
|  | CONFIG_ESPI_PERIPHERAL_HOST_CMD_PARAM_PORT_NUM & 0xff); | 
|  | #endif | 
|  | /* Set WIN2 as MEMMAP on the configured IO address */ | 
|  | #if defined(CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM) | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_1, | 
|  | (CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM >> 8) & 0xff); | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_SHM_WND2_ADDR_0, | 
|  | CONFIG_ESPI_PERIPHERAL_ACPI_SHM_REGION_PORT_NUM & 0xff); | 
|  | #endif | 
|  | /* Enable SHM direct memory access */ | 
|  | host_c2h_write_io_cfg_reg(EC_CFG_IDX_CTRL, 0x01); | 
|  | } | 
|  | LOG_DBG("Hos sub-modules configurations are done!"); | 
|  | } | 
|  |  | 
|  | void npcx_host_enable_access_interrupt(void) | 
|  | { | 
|  | npcx_miwu_irq_enable(&host_sub_cfg.host_acc_wui); | 
|  | } | 
|  |  | 
|  | void npcx_host_disable_access_interrupt(void) | 
|  | { | 
|  | npcx_miwu_irq_disable(&host_sub_cfg.host_acc_wui); | 
|  | } | 
|  |  | 
|  | int npcx_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; | 
|  | uint8_t shm_sts; | 
|  |  | 
|  | 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++) { | 
|  | int ret; | 
|  |  | 
|  | ret = clock_control_on(clk_dev, (clock_control_subsys_t *) | 
|  | &host_sub_cfg.clks_list[i]); | 
|  | if (ret < 0) | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* 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 */ | 
|  | shm_sts = inst_shm->SMC_STS; | 
|  | inst_shm->SMC_STS = shm_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_ACPI_SHM_REGION) | 
|  | host_shared_mem_region_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 | 
|  |  | 
|  | if (IS_ENABLED(CONFIG_PM)) { | 
|  | /* | 
|  | * Configure the host access wake-up event triggered from a host | 
|  | * transaction on eSPI/LPC bus. Do not enable it here. Or plenty | 
|  | * of interrupts will jam the system in S0. | 
|  | */ | 
|  | npcx_miwu_interrupt_configure(&host_sub_cfg.host_acc_wui, | 
|  | NPCX_MIWU_MODE_EDGE, NPCX_MIWU_TRIG_HIGH); | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } |