summaryrefslogtreecommitdiff
path: root/chip/npcx/lpc.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /chip/npcx/lpc.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-release-R98-14388.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'chip/npcx/lpc.c')
-rw-r--r--chip/npcx/lpc.c991
1 files changed, 0 insertions, 991 deletions
diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c
deleted file mode 100644
index adf78b642d..0000000000
--- a/chip/npcx/lpc.c
+++ /dev/null
@@ -1,991 +0,0 @@
-/* Copyright 2014 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.
- */
-
-/* LPC module for Chrome EC */
-
-#include "acpi.h"
-#include "chipset.h"
-#include "clock.h"
-#include "common.h"
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "i8042_protocol.h"
-#include "keyboard_protocol.h"
-#include "lpc.h"
-#include "lpc_chip.h"
-#include "port80.h"
-#include "registers.h"
-#include "system.h"
-#include "sib_chip.h"
-#include "task.h"
-#include "uart.h"
-#include "util.h"
-#include "system_chip.h"
-
-/* Console output macros */
-#if !(DEBUG_LPC)
-#define CPUTS(...)
-#define CPRINTS(...)
-#else
-#define CPUTS(outstr) cputs(CC_LPC, outstr)
-#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
-#endif
-
-/* PM channel definitions */
-#define PMC_ACPI PM_CHAN_1
-#define PMC_HOST_CMD PM_CHAN_2
-
-#define PORT80_MAX_BUF_SIZE 16
-static uint16_t port80_buf[PORT80_MAX_BUF_SIZE];
-
-static struct host_packet lpc_packet;
-static struct host_cmd_handler_args host_cmd_args;
-static uint8_t host_cmd_flags; /* Flags from host command */
-static uint8_t shm_mem_host_cmd[256] __aligned(8);
-static uint8_t shm_memmap[256] __aligned(8);
-/* Params must be 32-bit aligned */
-static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4);
-static int init_done;
-
-static struct ec_lpc_host_args * const lpc_host_args =
- (struct ec_lpc_host_args *)shm_mem_host_cmd;
-
-/*****************************************************************************/
-/* IC specific low-level driver */
-static void keyboard_irq_assert(void)
-{
-#ifdef CONFIG_KEYBOARD_IRQ_GPIO
- /*
- * Enforce signal-high for long enough for the signal to be pulled high
- * by the external pullup resistor. This ensures the host will see the
- * following falling edge, regardless of the line state before this
- * function call.
- */
- gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
- udelay(4);
- /* Generate a falling edge */
- gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 0);
- udelay(4);
- /* Set signal high, now that we've generated the edge */
- gpio_set_level(CONFIG_KEYBOARD_IRQ_GPIO, 1);
-#else
- /*
- * SERIRQ is automatically sent by KBC
- */
-#endif
-}
-
-static void lpc_task_enable_irq(void)
-{
-#ifdef HAS_TASK_KEYPROTO
- task_enable_irq(NPCX_IRQ_KBC_IBF);
-#endif
- task_enable_irq(NPCX_IRQ_PM_CHAN_IBF);
- task_enable_irq(NPCX_IRQ_PORT80);
-#ifdef CONFIG_HOSTCMD_ESPI
- task_enable_irq(NPCX_IRQ_ESPI);
- /* Virtual Wire: SLP_S3/4/5, SUS_STAT, PLTRST, OOB_RST_WARN */
- task_enable_irq(NPCX_IRQ_WKINTA_2);
- /* Virtual Wire: HOST_RST_WARN, SUS_WARN, SUS_PWRDN_ACK, SLP_A */
- task_enable_irq(NPCX_IRQ_WKINTB_2);
- /* Enable eSPI module interrupts and wake-up functionalities */
- NPCX_ESPIIE |= (ESPIIE_GENERIC | ESPIIE_VW);
- NPCX_ESPIWE |= (ESPIWE_GENERIC | ESPIWE_VW);
-#endif
-}
-
-static void lpc_task_disable_irq(void)
-{
-#ifdef HAS_TASK_KEYPROTO
- task_disable_irq(NPCX_IRQ_KBC_IBF);
-#endif
- task_disable_irq(NPCX_IRQ_PM_CHAN_IBF);
- task_disable_irq(NPCX_IRQ_PORT80);
-#ifdef CONFIG_HOSTCMD_ESPI
- task_disable_irq(NPCX_IRQ_ESPI);
- /* Virtual Wire: SLP_S3/4/5, SUS_STAT, PLTRST, OOB_RST_WARN */
- task_disable_irq(NPCX_IRQ_WKINTA_2);
- /* Virtual Wire: HOST_RST_WARN,SUS_WARN, SUS_PWRDN_ACK, SLP_A */
- task_disable_irq(NPCX_IRQ_WKINTB_2);
- /* Disable eSPI module interrupts and wake-up functionalities */
- NPCX_ESPIIE &= ~(ESPIIE_GENERIC | ESPIIE_VW);
- NPCX_ESPIWE &= ~(ESPIWE_GENERIC | ESPIWE_VW);
-#endif
-}
-/**
- * Generate SMI pulse to the host chipset via GPIO.
- *
- * If the x86 is in S0, SMI# is sampled at 33MHz, so minimum pulse length is
- * 60ns. If the x86 is in S3, SMI# is sampled at 32.768KHz, so we need pulse
- * length >61us. Both are short enough and events are infrequent, so just
- * delay for 65us.
- */
-static void lpc_generate_smi(void)
-{
- host_event_t smi;
-
-#ifdef CONFIG_SCI_GPIO
- /* Enforce signal-high for long enough to debounce high */
- gpio_set_level(GPIO_PCH_SMI_L, 1);
- udelay(65);
- /* Generate a falling edge */
- gpio_set_level(GPIO_PCH_SMI_L, 0);
- udelay(65);
- /* Set signal high, now that we've generated the edge */
- gpio_set_level(GPIO_PCH_SMI_L, 1);
-#elif defined(CONFIG_HOSTCMD_ESPI)
- /*
- * Don't use SET_BIT/CLEAR_BIT macro to toggle SMIB/SCIB to generate
- * virtual wire. Use NPCX_VW_SMI/NPCX_VW_SCI macro instead.
- * The reason is - if GPIOC6/CPIO76 are not selected as SMI/SCI, reading
- * from SMIB/SCIB doesn't really reflect the SMI/SCI status. SMI/SCI
- * status should be read from bit 1/0 in eSPI VMEVSM(2) register.
- */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SMI(1);
- udelay(65);
- /* Generate a falling edge */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SMI(0);
- udelay(65);
- /* Set signal high */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SMI(1);
-#else
- /* SET SMIB bit to pull SMI_L to high.*/
- SET_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SMIB);
- udelay(65);
- /* Generate a falling edge */
- CLEAR_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SMIB);
- udelay(65);
- /* Set signal high */
- SET_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SMIB);
-#endif
- smi = lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI);
- if (smi)
- HOST_EVENT_CPRINTS("smi", smi);
-}
-
-/**
- * Generate SCI pulse to the host chipset via LPC0SCI.
- */
-static void lpc_generate_sci(void)
-{
- host_event_t sci;
-
-#ifdef CONFIG_SCI_GPIO
- /* Enforce signal-high for long enough to debounce high */
- gpio_set_level(CONFIG_SCI_GPIO, 1);
- udelay(65);
- /* Generate a falling edge */
- gpio_set_level(CONFIG_SCI_GPIO, 0);
- udelay(65);
- /* Set signal high, now that we've generated the edge */
- gpio_set_level(CONFIG_SCI_GPIO, 1);
-#elif defined(CONFIG_HOSTCMD_ESPI)
- /*
- * Don't use SET_BIT/CLEAR_BIT macro to toggle SMIB/SCIB to generate
- * virtual wire. Use NPCX_VW_SMI/NPCX_VW_SCI macro instead.
- * The reason is - if GPIOC6/CPIO76 are not selected as SMI/SCI, reading
- * from SMIB/SCIB doesn't really reflect the SMI/SCI status. SMI/SCI
- * status should be read from bit 1/0 in eSPI VMEVSM(2) register.
- */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SCI(1);
- udelay(65);
- /* Generate a falling edge */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SCI(0);
- udelay(65);
- /* Set signal high */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_VW_SCI(1);
-#else
- /* Set SCIB bit to pull SCI_L to high.*/
- SET_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SCIB);
- udelay(65);
- /* Generate a falling edge */
- CLEAR_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SCIB);
- udelay(65);
- /* Set signal high */
- SET_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SCIB);
-#endif
-
- sci = lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI);
- if (sci)
- HOST_EVENT_CPRINTS("sci", sci);
-}
-
-/**
- * Update the level-sensitive wake signal to the AP.
- *
- * @param wake_events Currently asserted wake events
- */
-static void lpc_update_wake(host_event_t wake_events)
-{
- /*
- * Mask off power button event, since the AP gets that through a
- * separate dedicated GPIO.
- */
- wake_events &= ~EC_HOST_EVENT_MASK(EC_HOST_EVENT_POWER_BUTTON);
-
- /* Signal is asserted low when wake events is non-zero */
- gpio_set_level(GPIO_PCH_WAKE_L, !wake_events);
-}
-
-uint8_t *lpc_get_memmap_range(void)
-{
- return (uint8_t *)shm_memmap;
-}
-
-static void lpc_send_response(struct host_cmd_handler_args *args)
-{
- uint8_t *out;
- int size = args->response_size;
- int csum;
- int i;
-
- /* Ignore in-progress on LPC since interface is synchronous anyway */
- if (args->result == EC_RES_IN_PROGRESS)
- return;
-
- /* Handle negative size */
- if (size < 0) {
- args->result = EC_RES_INVALID_RESPONSE;
- size = 0;
- }
-
- /* New-style response */
- lpc_host_args->flags =
- (host_cmd_flags & ~EC_HOST_ARGS_FLAG_FROM_HOST) |
- EC_HOST_ARGS_FLAG_TO_HOST;
-
- lpc_host_args->data_size = size;
-
- csum = args->command + lpc_host_args->flags +
- lpc_host_args->command_version +
- lpc_host_args->data_size;
-
- for (i = 0, out = (uint8_t *)args->response; i < size; i++, out++)
- csum += *out;
-
- lpc_host_args->checksum = (uint8_t)csum;
-
- /* Fail if response doesn't fit in the param buffer */
- if (size > EC_PROTO2_MAX_PARAM_SIZE)
- args->result = EC_RES_INVALID_RESPONSE;
-
- /* Write result to the data byte. This sets the TOH status bit. */
- NPCX_HIPMDO(PMC_HOST_CMD) = args->result;
- /* Clear processing flag */
- CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), NPCX_HIPMST_F0);
-}
-
-static void lpc_send_response_packet(struct host_packet *pkt)
-{
- /* Ignore in-progress on LPC since interface is synchronous anyway */
- if (pkt->driver_result == EC_RES_IN_PROGRESS)
- return;
-
- /* Write result to the data byte. This sets the TOH status bit. */
- NPCX_HIPMDO(PMC_HOST_CMD) = pkt->driver_result;
- /* Clear processing flag */
- CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), NPCX_HIPMST_F0);
-}
-
-int lpc_keyboard_has_char(void)
-{
- /* if OBF bit is '1', that mean still have a data in DBBOUT */
- return (NPCX_HIKMST&0x01) ? 1 : 0;
-}
-
-int lpc_keyboard_input_pending(void)
-{
- /* if IBF bit is '1', that mean still have a data in DBBIN */
- return (NPCX_HIKMST&0x02) ? 1 : 0;
-}
-
-/* Put a char to host buffer by HIKDO and send IRQ if specified. */
-void lpc_keyboard_put_char(uint8_t chr, int send_irq)
-{
- NPCX_HIKDO = chr;
- CPRINTS("KB put %02x", chr);
-
- /* Enable OBE interrupt to detect host read data out */
- SET_BIT(NPCX_HICTRL, NPCX_HICTRL_OBECIE);
- task_enable_irq(NPCX_IRQ_KBC_OBE);
- if (send_irq) {
- keyboard_irq_assert();
- }
-}
-
-/* Put an aux char to host buffer by HIMDO and assert status bit 5. */
-void lpc_aux_put_char(uint8_t chr, int send_irq)
-{
- if (send_irq)
- SET_BIT(NPCX_HICTRL, NPCX_HICTRL_OBFMIE);
- else
- CLEAR_BIT(NPCX_HICTRL, NPCX_HICTRL_OBFMIE);
-
- NPCX_HIKMST |= I8042_AUX_DATA;
- NPCX_HIMDO = chr;
- CPRINTS("AUX put %02x", chr);
-
- /* Enable OBE interrupt to detect host read data out */
- SET_BIT(NPCX_HICTRL, NPCX_HICTRL_OBECIE);
- task_enable_irq(NPCX_IRQ_KBC_OBE);
-}
-
-void lpc_keyboard_clear_buffer(void)
-{
- /*
- * Only npcx5 series need this bypass. The bug of FW_OBF is fixed in
- * npcx7 series and later npcx ec.
- */
-#ifdef CHIP_FAMILY_NPCX5
- /* Clear OBF flag in host STATUS and HIKMST regs */
- if (IS_BIT_SET(NPCX_HIKMST, NPCX_HIKMST_OBF)) {
- /*
- * Setting HICTRL.FW_OBF clears the HIKMST.OBF and STATUS.OBF
- * but it does not deassert IRQ1 when it was already asserted.
- * Emulate a host read to clear these two flags and also
- * deassert IRQ1
- */
- sib_read_kbc_reg(0x0);
- }
-#else
- /* Make sure the previous TOH and IRQ has been sent out. */
- udelay(4);
- /* Clear OBE flag in host STATUS and HIKMST regs*/
- SET_BIT(NPCX_HICTRL, NPCX_HICTRL_FW_OBF);
- /* Ensure there is no TOH set in this period. */
- udelay(4);
-#endif
-}
-
-void lpc_keyboard_resume_irq(void)
-{
- if (lpc_keyboard_has_char())
- keyboard_irq_assert();
-}
-
-/**
- * Update the host event status.
- *
- * Sends a pulse if masked event status becomes non-zero:
- * - SMI pulse via EC_SMI_L GPIO
- * - SCI pulse via LPC0SCI
- */
-void lpc_update_host_event_status(void)
-{
- int need_sci = 0;
- int need_smi = 0;
-
- if (!init_done)
- return;
-
- /* Disable LPC interrupt while updating status register */
- lpc_task_disable_irq();
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) {
- /* Only generate SMI for first event */
- if (!(NPCX_HIPMST(PMC_ACPI) & NPCX_HIPMST_ST2))
- need_smi = 1;
- SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST2);
- } else
- CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST2);
-
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI)) {
- /* Generate SCI for every event */
- need_sci = 1;
- SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST1);
- } else
- CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST1);
-
- /* Copy host events to mapped memory */
- *(host_event_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) =
- lpc_get_host_events();
-
- lpc_task_enable_irq();
-
- /* Process the wake events. */
- lpc_update_wake(lpc_get_host_events_by_type(LPC_HOST_EVENT_WAKE));
-
- /* Send pulse on SMI signal if needed */
- if (need_smi)
- lpc_generate_smi();
-
- /* ACPI 5.0-12.6.1: Generate SCI for SCI_EVT=1. */
- if (need_sci)
- lpc_generate_sci();
-}
-
-void lpc_set_acpi_status_mask(uint8_t mask)
-{
- NPCX_HIPMST(PMC_ACPI) |= mask;
-}
-
-void lpc_clear_acpi_status_mask(uint8_t mask)
-{
- NPCX_HIPMST(PMC_ACPI) &= ~mask;
-}
-
-/* Enable LPC ACPI-EC interrupts */
-void lpc_enable_acpi_interrupts(void)
-{
- SET_BIT(NPCX_HIPMCTL(PMC_ACPI), NPCX_HIPMCTL_IBFIE);
-}
-
-/* Disable LPC ACPI-EC interrupts */
-void lpc_disable_acpi_interrupts(void)
-{
- CLEAR_BIT(NPCX_HIPMCTL(PMC_ACPI), NPCX_HIPMCTL_IBFIE);
-}
-
-/**
- * Handle write to ACPI I/O port
- *
- * @param is_cmd Is write command (is_cmd=1) or data (is_cmd=0)
- */
-static void handle_acpi_write(int is_cmd)
-{
- uint8_t value, result;
-
- /* Set processing flag before reading command byte */
- SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_F0);
-
- /* Read command/data; this clears the FRMH status bit. */
- value = NPCX_HIPMDI(PMC_ACPI);
-
- /* Handle whatever this was. */
- if (acpi_ap_to_ec(is_cmd, value, &result))
- NPCX_HIPMDO(PMC_ACPI) = result;
-
- /* Clear processing flag */
- CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_F0);
-
- /*
- * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer
- * Full condition on the kernel channel.
- */
- lpc_generate_sci();
-}
-
-/**
- * Handle write to host command I/O ports.
- *
- * @param is_cmd Is write command (1) or data (0)?
- */
-static void handle_host_write(int is_cmd)
-{
- /* Set processing flag before reading command byte */
- SET_BIT(NPCX_HIPMST(PMC_HOST_CMD), NPCX_HIPMST_F0);
- /*
- * Read the command byte. This clears the FRMH bit in
- * the status byte.
- */
- host_cmd_args.command = NPCX_HIPMDI(PMC_HOST_CMD);
-
- host_cmd_args.result = EC_RES_SUCCESS;
- host_cmd_args.send_response = lpc_send_response;
- host_cmd_flags = lpc_host_args->flags;
-
- /* See if we have an old or new style command */
- if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
- lpc_packet.send_response = lpc_send_response_packet;
-
- lpc_packet.request = (const void *)shm_mem_host_cmd;
- lpc_packet.request_temp = params_copy;
- lpc_packet.request_max = sizeof(params_copy);
- /* Don't know the request size so pass in the entire buffer */
- lpc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;
-
- lpc_packet.response = (void *)shm_mem_host_cmd;
- lpc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
- lpc_packet.response_size = 0;
-
- lpc_packet.driver_result = EC_RES_SUCCESS;
-
- host_packet_receive(&lpc_packet);
- return;
-
- } else {
- /* Old style command, now unsupported */
- host_cmd_args.result = EC_RES_INVALID_COMMAND;
- }
-
- /* Hand off to host command handler */
- host_command_received(&host_cmd_args);
-}
-
-/*****************************************************************************/
-/* Interrupt handlers */
-#ifdef HAS_TASK_KEYPROTO
-/* KB controller input buffer full ISR */
-void lpc_kbc_ibf_interrupt(void)
-{
- uint8_t status;
- uint8_t ibf;
- /* If "command" input 0, else 1*/
- if (lpc_keyboard_input_pending()) {
- /*
- * Reading HIKMDI causes the IBF flag to deassert and allows
- * the host to write a new byte into the input buffer. So if we
- * don't capture the status before reading HIKMDI we will race
- * with the host and get an invalid value for HIKMST.A20.
- */
- status = NPCX_HIKMST;
- ibf = NPCX_HIKMDI;
- keyboard_host_write(ibf, (status & 0x08) ? 1 : 0);
- CPRINTS("ibf isr %02x", ibf);
- task_wake(TASK_ID_KEYPROTO);
- } else {
- CPRINTS("ibf isr spurious");
- }
-}
-DECLARE_IRQ(NPCX_IRQ_KBC_IBF, lpc_kbc_ibf_interrupt, 4);
-
-/* KB controller output buffer empty ISR */
-void lpc_kbc_obe_interrupt(void)
-{
- /* Disable KBC OBE interrupt */
- CLEAR_BIT(NPCX_HICTRL, NPCX_HICTRL_OBECIE);
- task_disable_irq(NPCX_IRQ_KBC_OBE);
-
- CPRINTS("obe isr %02x", NPCX_HIKMST);
-
- NPCX_HIKMST &= ~I8042_AUX_DATA;
-
- task_wake(TASK_ID_KEYPROTO);
-}
-DECLARE_IRQ(NPCX_IRQ_KBC_OBE, lpc_kbc_obe_interrupt, 4);
-#endif
-
-/* PM channel input buffer full ISR */
-void lpc_pmc_ibf_interrupt(void)
-{
- /* Channel-1 for ACPI usage*/
- /* Channel-2 for Host Command usage , so the argument data had been
- * put on the share memory firstly*/
- if (NPCX_HIPMST(PMC_ACPI) & 0x02)
- handle_acpi_write((NPCX_HIPMST(PMC_ACPI)&0x08) ? 1 : 0);
- else if (NPCX_HIPMST(PMC_HOST_CMD) & 0x02)
- handle_host_write((NPCX_HIPMST(PMC_HOST_CMD)&0x08) ? 1 : 0);
-}
-DECLARE_IRQ(NPCX_IRQ_PM_CHAN_IBF, lpc_pmc_ibf_interrupt, 4);
-
-/* PM channel output buffer empty ISR */
-void lpc_pmc_obe_interrupt(void)
-{
-}
-DECLARE_IRQ(NPCX_IRQ_PM_CHAN_OBE, lpc_pmc_obe_interrupt, 4);
-
-void lpc_port80_interrupt(void)
-{
- uint8_t i;
- uint8_t count = 0;
- uint32_t code = 0;
-
- /* buffer Port80 data to the local buffer if FIFO is not empty */
- while (IS_BIT_SET(NPCX_DP80STS, NPCX_DP80STS_FNE))
- port80_buf[count++] = NPCX_DP80BUF;
-
- for (i = 0; i < count; i++) {
- uint8_t offset;
- uint32_t buf_data;
-
- buf_data = port80_buf[i];
- offset = GET_FIELD(buf_data, NPCX_DP80BUF_OFFS_FIELD);
- code |= (buf_data & 0xFF) << (8 * offset);
-
- if (i == count - 1) {
- port_80_write(code);
- break;
- }
-
- /* peek the offset of the next byte */
- buf_data = port80_buf[i + 1];
- offset = GET_FIELD(buf_data, NPCX_DP80BUF_OFFS_FIELD);
- /*
- * If the peeked next byte's offset is 0 means it is the start
- * of the new code. Pass the current code to Port80
- * common layer.
- */
- if (offset == 0) {
- port_80_write(code);
- code = 0;
- }
- }
-
- /* If FIFO is overflow */
- if (IS_BIT_SET(NPCX_DP80STS, NPCX_DP80STS_FOR)) {
- SET_BIT(NPCX_DP80STS, NPCX_DP80STS_FOR);
- CPRINTS("DP80 FIFO Overflow!");
- }
-
- /* Clear pending bit of host writing */
- SET_BIT(NPCX_DP80STS, NPCX_DP80STS_FWR);
-}
-DECLARE_IRQ(NPCX_IRQ_PORT80, lpc_port80_interrupt, 4);
-
-/**
- * Preserve event masks across a sysjump.
- */
-static void lpc_sysjump(void)
-{
- lpc_task_disable_irq();
-
- /* Disable protect for Win 1 and 2. */
- NPCX_WIN_WR_PROT(0) = 0;
- NPCX_WIN_WR_PROT(1) = 0;
- NPCX_WIN_RD_PROT(0) = 0;
- NPCX_WIN_RD_PROT(1) = 0;
-
- /* Reset base address for Win 1 and 2. */
- NPCX_WIN_BASE(0) = 0xfffffff8;
- NPCX_WIN_BASE(1) = 0xfffffff8;
-}
-DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump, HOOK_PRIO_DEFAULT);
-
-/* For LPC host register initial via SIB module */
-void host_register_init(void)
-{
- /* Enable Core-to-Host Modules Access */
- SET_BIT(NPCX_SIBCTRL, NPCX_SIBCTRL_CSAE);
-
- /* enable ACPI*/
- sib_write_reg(SIO_OFFSET, 0x07, 0x11);
- sib_write_reg(SIO_OFFSET, 0x30, 0x01);
-
- /* Enable kbc and mouse */
-#ifdef HAS_TASK_KEYPROTO
- /* LDN = 0x06 : keyboard */
- sib_write_reg(SIO_OFFSET, 0x07, 0x06);
- sib_write_reg(SIO_OFFSET, 0x30, 0x01);
-
- /* LDN = 0x05 : mouse */
- if (IS_ENABLED(CONFIG_PS2)) {
- sib_write_reg(SIO_OFFSET, 0x07, 0x05);
- sib_write_reg(SIO_OFFSET, 0x30, 0x01);
- }
-#endif
-
- /* Setting PMC2 */
- /* LDN register = 0x12(PMC2) */
- sib_write_reg(SIO_OFFSET, 0x07, 0x12);
- /* CMD port is 0x200 */
- sib_write_reg(SIO_OFFSET, 0x60, 0x02);
- sib_write_reg(SIO_OFFSET, 0x61, 0x00);
- /* Data port is 0x204 */
- sib_write_reg(SIO_OFFSET, 0x62, 0x02);
- sib_write_reg(SIO_OFFSET, 0x63, 0x04);
- /* enable PMC2 */
- sib_write_reg(SIO_OFFSET, 0x30, 0x01);
-
- /* Setting SHM */
- /* LDN register = 0x0F(SHM) */
- sib_write_reg(SIO_OFFSET, 0x07, 0x0F);
- /* WIN1&2 mapping to IO */
- sib_write_reg(SIO_OFFSET, 0xF1,
- sib_read_reg(SIO_OFFSET, 0xF1) | 0x30);
- /* WIN1 as Host Command on the IO:0x0800 */
- sib_write_reg(SIO_OFFSET, 0xF5, 0x08);
- sib_write_reg(SIO_OFFSET, 0xF4, 0x00);
- /* WIN2 as MEMMAP on the IO:0x900 */
- sib_write_reg(SIO_OFFSET, 0xF9, 0x09);
- sib_write_reg(SIO_OFFSET, 0xF8, 0x00);
-
- /*
- * eSPI allows sending 4 bytes of Port80 code in a single PUT_IOWR_SHORT
- * transaction. When setting OFS0_SEL~OFS3_SEL in DPAR1 register to 1,
- * EC hardware will put those 4 bytes of Port80 code to DP80BUF FIFO.
- * This is only supported when CHIP_FAMILY >= NPCX9.
- */
- if (IS_ENABLED(CONFIG_HOSTCMD_ESPI))
- sib_write_reg(SIO_OFFSET, 0xFD, 0x0F);
- /* enable SHM */
- sib_write_reg(SIO_OFFSET, 0x30, 0x01);
-
- CPRINTS("Host settings are done!");
-
-}
-
-#ifdef CONFIG_CHIPSET_RESET_HOOK
-static void lpc_chipset_reset(void)
-{
- hook_notify(HOOK_CHIPSET_RESET);
-}
-DECLARE_DEFERRED(lpc_chipset_reset);
-#endif
-
-int lpc_get_pltrst_asserted(void)
-{
- /* Read current PLTRST status */
- return IS_BIT_SET(NPCX_MSWCTL1, NPCX_MSWCTL1_PLTRST_ACT);
-}
-
-#ifndef CONFIG_HOSTCMD_ESPI
-/* Initialize host settings by interrupt */
-void lpc_lreset_pltrst_handler(void)
-{
- int pltrst_asserted;
-
- /* Clear pending bit of WUI */
- SET_BIT(NPCX_WKPCL(MIWU_TABLE_0 , MIWU_GROUP_5), 7);
-
- /* Ignore PLTRST# from SOC if it is not valid */
- if (chipset_pltrst_is_valid && !chipset_pltrst_is_valid())
- return;
-
- pltrst_asserted = lpc_get_pltrst_asserted();
-
- CPRINTS("LPC RESET# %sasserted", pltrst_asserted ? "" : "de");
-
- /*
- * Once LRESET is de-asserted (low -> high), we need to initialize lpc
- * settings once. If RSTCTL_LRESET_PLTRST_MODE is active, LPC registers
- * won't be reset by Host domain reset but Core domain does.
- */
- if (!pltrst_asserted)
- host_register_init();
- else {
- /* Clear processing flag when LRESET is asserted */
- CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), NPCX_HIPMST_F0);
-#ifdef CONFIG_CHIPSET_RESET_HOOK
- /* Notify HOOK_CHIPSET_RESET */
- hook_call_deferred(&lpc_chipset_reset_data, MSEC);
-#endif
- }
-}
-#endif
-
-/*****************************************************************************/
-/* LPC/eSPI Initialization functions */
-
-static void lpc_init(void)
-{
- /* Enable clock for LPC peripheral */
- clock_enable_peripheral(CGC_OFFSET_LPC, CGC_LPC_MASK,
- CGC_MODE_RUN | CGC_MODE_SLEEP);
- /*
- * In npcx5/7, the host interface type (HIF_TYP_SEL in the DEVCNT
- * register) is updated by booter after VCC1 Power-Up reset according to
- * VHIF voltage.
- * In npcx9, the booter will not do this anymore. The HIF_TYP_SEL
- * field should be set by firmware.
- */
-#ifdef CONFIG_HOSTCMD_ESPI
- /* Initialize eSPI module */
- NPCX_DEVCNT |= 0x08;
- espi_init();
-#else
- /* Switching to LPC interface */
- NPCX_DEVCNT |= 0x04;
-#endif
- /* Enable 4E/4F */
- if (!IS_BIT_SET(NPCX_MSWCTL1, NPCX_MSWCTL1_VHCFGA)) {
- NPCX_HCBAL = 0x4E;
- NPCX_HCBAH = 0x0;
- }
- /* Clear Host Access Hold state */
- NPCX_SMC_CTL = 0xC0;
-
-#ifndef CONFIG_HOSTCMD_ESPI
- /*
- * Set alternative pin from GPIO to CLKRUN no matter SERIRQ is under
- * continuous or quiet mode.
- */
- SET_BIT(NPCX_DEVALT(1), NPCX_DEVALT1_CLKRN_SL);
-#endif
-
- /*
- * Set pin-mux from GPIOs to SCL/SMI to make sure toggling SCIB/SMIB is
- * valid if CONFIG_SCI_GPIO isn't defined. eSPI sends SMI/SCI through VW
- * automatically by toggling them, too. It's unnecessary to set pin mux.
- */
-#if !defined(CONFIG_SCI_GPIO) && !defined(CONFIG_HOSTCMD_ESPI)
- SET_BIT(NPCX_DEVALT(1), NPCX_DEVALT1_EC_SCI_SL);
- SET_BIT(NPCX_DEVALT(1), NPCX_DEVALT1_SMI_SL);
-#endif
-
- /* Initialize Hardware for UART Host */
-#ifdef CONFIG_UART_HOST
- /* Init COMx LPC UART */
- /* FMCLK have to using 50MHz */
- NPCX_DEVALT(0xB) = 0xFF;
- /* Make sure Host Access unlock */
- CLEAR_BIT(NPCX_LKSIOHA, 2);
- /* Clear Host Access Lock Violation */
- SET_BIT(NPCX_SIOLV, 2);
-#endif
-
- /* Don't stall SHM transactions */
- NPCX_SHM_CTL = NPCX_SHM_CTL & ~0x40;
- /* Disable Protect Win1&2*/
- NPCX_WIN_WR_PROT(0) = 0;
- NPCX_WIN_WR_PROT(1) = 0;
- NPCX_WIN_RD_PROT(0) = 0;
- NPCX_WIN_RD_PROT(1) = 0;
- /* Open Win1 256 byte for Host CMD, Win2 256 for MEMMAP*/
- NPCX_WIN_SIZE = 0x88;
- NPCX_WIN_BASE(0) = (uint32_t)shm_mem_host_cmd;
- NPCX_WIN_BASE(1) = (uint32_t)shm_memmap;
- /* Write protect of Share memory */
- NPCX_WIN_WR_PROT(1) = 0xFF;
-
- /* We support LPC args and version 3 protocol */
- *(lpc_get_memmap_range() + EC_MEMMAP_HOST_CMD_FLAGS) =
- EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED |
- EC_HOST_CMD_FLAG_VERSION_3;
-
- /*
- * Clear processing flag before enabling lpc's interrupts in case
- * it's set by the other command during sysjump.
- */
- CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), NPCX_HIPMST_F0);
-
- /* Turn on PMC2 for Host Command usage */
- SET_BIT(NPCX_HIPMCTL(PMC_HOST_CMD), 0);
-
- /*
- * Set required control value (avoid setting HOSTWAIT bit at this stage)
- */
- NPCX_SMC_CTL = NPCX_SMC_CTL&~0x7F;
- /* Clear status */
- NPCX_SMC_STS = NPCX_SMC_STS;
-
- /* Create mailbox */
-
- /*
- * Init KBC
- * Clear OBF status flag,
- * IBF(K&M) INT enable,
- * OBF Mouse Full INT enable and OBF KB Full INT enable
- */
-#ifdef HAS_TASK_KEYPROTO
- lpc_keyboard_clear_buffer();
- NPCX_HICTRL = 0x0B;
-#endif
-
- /*
- * Turn on enhance mode on PM channel-1,
- * enable IBF core interrupt
- */
- NPCX_HIPMCTL(PMC_ACPI) |= 0x81;
- /* Normally Polarity IRQ1,12 type (level + high) setting */
- NPCX_HIIRQC = 0x00;
-
- /*
- * Init PORT80
- * Enable Port80, Enable Port80 function & Interrupt & Read auto
- */
-#ifdef CONFIG_HOSTCMD_ESPI
- NPCX_DP80CTL = 0x2b;
-#else
- NPCX_DP80CTL = 0x29;
-#endif
- SET_BIT(NPCX_GLUE_SDP_CTS, 3);
-#if SUPPORT_P80_SEG
- SET_BIT(NPCX_GLUE_SDP_CTS, 0);
-#endif
-
- /*
- * Use SMI/SCI postive polarity as default.
- * Negative polarity must be enabled in the case that SMI/SCI is
- * generated automatically by hardware. In current design,
- * SMI/SCI is conntrolled by FW. Use postive polarity is more
- * intuitive.
- */
- CLEAR_BIT(NPCX_HIPMCTL(PMC_ACPI), NPCX_HIPMCTL_SCIPOL);
- CLEAR_BIT(NPCX_HIPMIC(PMC_ACPI), NPCX_HIPMIC_SMIPOL);
- /* Set SMIB/SCIB to make sure SMI/SCI are high at init */
- NPCX_HIPMIC(PMC_ACPI) = NPCX_HIPMIC(PMC_ACPI)
- | BIT(NPCX_HIPMIC_SMIB) | BIT(NPCX_HIPMIC_SCIB);
-#ifndef CONFIG_SCI_GPIO
- /*
- * Allow SMI/SCI generated from PM module.
- * Either hardware autimatically generates,
- * or set SCIB/SMIB bit in HIPMIC register.
- */
- SET_BIT(NPCX_HIPMIE(PMC_ACPI), NPCX_HIPMIE_SCIE);
- SET_BIT(NPCX_HIPMIE(PMC_ACPI), NPCX_HIPMIE_SMIE);
-#endif
- lpc_task_enable_irq();
-
- /* Sufficiently initialized */
- init_done = 1;
-
- /* Update host events now that we can copy them to memmap */
- lpc_update_host_event_status();
-
- /*
- * TODO: For testing LPC with Chromebox, please make sure LPC_CLK is
- * generated before executing this function. EC needs LPC_CLK to access
- * LPC register through SIB module. For Chromebook platform, this
- * functionality should be done by BIOS or executed in hook function of
- * HOOK_CHIPSET_STARTUP
- */
-#ifdef BOARD_NPCX_EVB
- /* initial IO port address via SIB-write modules */
- host_register_init();
-#else
-#ifndef CONFIG_HOSTCMD_ESPI
- /*
- * Initialize LRESET# interrupt only in case of LPC. For eSPI, there is
- * no dedicated GPIO pin for LRESET/PLTRST. PLTRST is indicated as a VW
- * signal instead. WUI57 of table 0 is set when EC receives
- * LRESET/PLTRST from either VW or GPIO. Since WUI57 of table 0 and
- * WUI15 of table 2 are issued at the same time in case of eSPI, there
- * is no need to indicate LRESET/PLTRST via two sources. Thus, do not
- * initialize LRESET# interrupt in case of eSPI.
- */
- /* Set detection mode to edge */
- CLEAR_BIT(NPCX_WKMOD(MIWU_TABLE_0, MIWU_GROUP_5), 7);
- /* Handle interrupting on any edge */
- SET_BIT(NPCX_WKAEDG(MIWU_TABLE_0, MIWU_GROUP_5), 7);
- /* Enable wake-up input sources */
- SET_BIT(NPCX_WKEN(MIWU_TABLE_0, MIWU_GROUP_5), 7);
-#endif
-#endif
-}
-/*
- * Set prio to higher than default; this way LPC memory mapped data is ready
- * before other inits try to initialize their memmap data.
- */
-DECLARE_HOOK(HOOK_INIT, lpc_init, HOOK_PRIO_INIT_LPC);
-
-/* Get protocol information */
-static enum ec_status lpc_get_protocol_info(struct host_cmd_handler_args *args)
-{
- struct ec_response_get_protocol_info *r = args->response;
-
- memset(r, 0, sizeof(*r));
- r->protocol_versions = BIT(3);
- r->max_request_packet_size = EC_LPC_HOST_PACKET_SIZE;
- r->max_response_packet_size = EC_LPC_HOST_PACKET_SIZE;
- r->flags = 0;
-
- args->response_size = sizeof(*r);
-
- return EC_SUCCESS;
-}
-DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO,
- lpc_get_protocol_info,
- EC_VER_MASK(0));
-
-#if DEBUG_LPC
-static int command_lpc(int argc, char **argv)
-{
- if (argc == 1)
- return EC_ERROR_PARAM1;
-
- if (!strcasecmp(argv[1], "sci"))
- lpc_generate_sci();
- else if (!strcasecmp(argv[1], "smi"))
- lpc_generate_smi();
- else if (!strcasecmp(argv[1], "wake"))
- lpc_update_wake(-1);
- else
- return EC_ERROR_PARAM1;
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(lpc, command_lpc, "[sci|smi|wake]", "Trigger SCI/SMI");
-
-#endif