summaryrefslogtreecommitdiff
path: root/chip/mchp/lpc.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/mchp/lpc.c')
-rw-r--r--chip/mchp/lpc.c1022
1 files changed, 0 insertions, 1022 deletions
diff --git a/chip/mchp/lpc.c b/chip/mchp/lpc.c
deleted file mode 100644
index b5db07b88f..0000000000
--- a/chip/mchp/lpc.c
+++ /dev/null
@@ -1,1022 +0,0 @@
-/* Copyright 2017 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 MCHP MEC family */
-
-#include "common.h"
-#include "acpi.h"
-#include "console.h"
-#include "gpio.h"
-#include "hooks.h"
-#include "host_command.h"
-#include "keyboard_protocol.h"
-#include "lpc.h"
-#include "lpc_chip.h"
-#include "espi.h"
-#include "port80.h"
-#include "registers.h"
-#include "system.h"
-#include "task.h"
-#include "timer.h"
-#include "util.h"
-#include "chipset.h"
-#include "tfdp_chip.h"
-
-/* Console output macros */
-#ifdef CONFIG_MCHP_DEBUG_LPC
-#define CPUTS(outstr) cputs(CC_LPC, outstr)
-#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
-#else
-#define CPUTS(...)
-#define CPRINTS(...)
-#endif
-
-static uint8_t
-mem_mapped[0x200] __attribute__((section(".bss.big_align")));
-
-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 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 *)mem_mapped;
-
-#ifdef CONFIG_BOARD_ID_CMD_ACPI_EC1
-static uint8_t custom_acpi_cmd;
-static uint8_t custom_acpi_ec2os_cnt;
-static uint8_t custom_apci_ec2os[4];
-#endif
-
-
-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 pull up 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
-}
-
-/**
- * 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 60 ns. 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 65 us.
- */
-static void lpc_generate_smi(void)
-{
- CPUTS("LPC Pulse SMI");
-#ifdef CONFIG_HOSTCMD_ESPI
- /* eSPI: pulse SMI# Virtual Wire low */
- espi_vw_pulse_wire(VW_SMI_L, 0);
-#else
- gpio_set_level(GPIO_PCH_SMI_L, 0);
- udelay(65);
- gpio_set_level(GPIO_PCH_SMI_L, 1);
-#endif
-}
-
-static void lpc_generate_sci(void)
-{
- CPUTS("LPC Pulse SCI");
-#ifdef CONFIG_SCI_GPIO
- gpio_set_level(CONFIG_SCI_GPIO, 0);
- udelay(65);
- gpio_set_level(CONFIG_SCI_GPIO, 1);
-#else
-#ifdef CONFIG_HOSTCMD_ESPI
- espi_vw_pulse_wire(VW_SCI_L, 0);
-#else
- MCHP_ACPI_PM_STS |= 1;
- udelay(65);
- MCHP_ACPI_PM_STS &= ~1;
-#endif
-#endif
-}
-
-/**
- * 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);
-
-#ifdef CONFIG_HOSTCMD_ESPI
- espi_vw_set_wire(VW_WAKE_L, !wake_events);
-#else
- /* Signal is asserted low when wake events is non-zero */
- gpio_set_level(GPIO_PCH_WAKE_L, !wake_events);
-#endif
-}
-
-static uint8_t *lpc_get_hostcmd_data_range(void)
-{
- return mem_mapped;
-}
-
-
-/**
- * Update the host event status.
- *
- * Sends a pulse if masked event status becomes non-zero:
- * - SMI pulse via PCH_SMI_L GPIO
- * - SCI pulse via PCH_SCI_L GPIO
- */
-void lpc_update_host_event_status(void)
-{
- int need_sci = 0;
- int need_smi = 0;
-
- CPUTS("LPC update_host_event_status");
-
- if (!init_done)
- return;
-
- /* Disable LPC interrupt while updating status register */
- task_disable_irq(MCHP_IRQ_ACPIEC0_IBF);
-
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) {
- /* Only generate SMI for first event */
- if (!(MCHP_ACPI_EC_STATUS(0) & EC_LPC_STATUS_SMI_PENDING))
- need_smi = 1;
- MCHP_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_SMI_PENDING;
- } else {
- MCHP_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_SMI_PENDING;
- }
-
- if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SCI)) {
- /* Generate SCI for every event */
- need_sci = 1;
- MCHP_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_SCI_PENDING;
- } else {
- MCHP_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_SCI_PENDING;
- }
-
- /* Copy host events to mapped memory */
- *(uint32_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) =
- lpc_get_host_events();
-
- task_enable_irq(MCHP_IRQ_ACPIEC0_IBF);
-
- /* 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();
-}
-
-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 parameter buffer */
- if (size > EC_PROTO2_MAX_PARAM_SIZE)
- args->result = EC_RES_INVALID_RESPONSE;
-
- /* Write result to the data byte. */
- MCHP_ACPI_EC_EC2OS(1, 0) = args->result;
-
- /*
- * Clear processing flag in hardware and
- * sticky status in interrupt aggregator.
- */
- MCHP_ACPI_EC_STATUS(1) &= ~EC_LPC_STATUS_PROCESSING;
- MCHP_INT_SOURCE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_IBF_GIRQ_BIT(1);
-
-}
-
-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) {
- /* CPRINTS("LPC EC_RES_IN_PROGRESS"); */
- return;
- }
-
- CPRINTS("LPC Set EC2OS(1,0)=0x%02x", pkt->driver_result);
-
- /* Write result to the data byte. */
- MCHP_ACPI_EC_EC2OS(1, 0) = pkt->driver_result;
-
- /* Clear the busy bit, so the host knows the EC is done. */
- MCHP_ACPI_EC_STATUS(1) &= ~EC_LPC_STATUS_PROCESSING;
- MCHP_INT_SOURCE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_IBF_GIRQ_BIT(1);
-}
-
-uint8_t *lpc_get_memmap_range(void)
-{
- return mem_mapped + 0x100;
-}
-
-void lpc_mem_mapped_init(void)
-{
- /* We support LPC arguments 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;
-}
-
-const int acpi_ec_pcr_slp[] = {
- MCHP_PCR_ACPI_EC0,
- MCHP_PCR_ACPI_EC1,
- MCHP_PCR_ACPI_EC2,
- MCHP_PCR_ACPI_EC3,
-#ifndef CHIP_FAMILY_MEC152X
- MCHP_PCR_ACPI_EC4,
-#endif
-};
-BUILD_ASSERT(ARRAY_SIZE(acpi_ec_pcr_slp) == MCHP_ACPI_EC_INSTANCES);
-
-const int acpi_ec_nvic_ibf[] = {
- MCHP_IRQ_ACPIEC0_IBF,
- MCHP_IRQ_ACPIEC1_IBF,
- MCHP_IRQ_ACPIEC2_IBF,
- MCHP_IRQ_ACPIEC3_IBF,
-#ifndef CHIP_FAMILY_MEC152X
- MCHP_IRQ_ACPIEC4_IBF,
-#endif
-};
-BUILD_ASSERT(ARRAY_SIZE(acpi_ec_nvic_ibf) == MCHP_ACPI_EC_INSTANCES);
-
-#ifdef CONFIG_HOSTCMD_ESPI
-const int acpi_ec_espi_bar_id[] = {
- MCHP_ESPI_IO_BAR_ID_ACPI_EC0,
- MCHP_ESPI_IO_BAR_ID_ACPI_EC1,
- MCHP_ESPI_IO_BAR_ID_ACPI_EC2,
- MCHP_ESPI_IO_BAR_ID_ACPI_EC3,
-#ifndef CHIP_FAMILY_MEC152X
- MCHP_ESPI_IO_BAR_ID_ACPI_EC4,
-#endif
-};
-BUILD_ASSERT(ARRAY_SIZE(acpi_ec_espi_bar_id) == MCHP_ACPI_EC_INSTANCES);
-#endif
-
-void chip_acpi_ec_config(int instance, uint32_t io_base, uint8_t mask)
-{
- if (instance >= MCHP_ACPI_EC_INSTANCES) {
- CPUTS("ACPI EC CFG invalid");
- return;
- }
-
- MCHP_PCR_SLP_DIS_DEV(acpi_ec_pcr_slp[instance]);
-
-#ifdef CONFIG_HOSTCMD_ESPI
- MCHP_ESPI_IO_BAR_CTL_MASK(acpi_ec_espi_bar_id[instance]) =
- mask;
- MCHP_ESPI_IO_BAR(acpi_ec_espi_bar_id[instance]) =
- (io_base << 16) + 0x01ul;
-#else
- MCHP_LPC_ACPI_EC_BAR(instance) = (io_base << 16) +
- (1ul << 15) + mask;
-#endif
- MCHP_ACPI_EC_STATUS(instance) &= ~EC_LPC_STATUS_PROCESSING;
- MCHP_INT_ENABLE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_IBF_GIRQ_BIT(instance);
- task_enable_irq(acpi_ec_nvic_ibf[instance]);
-}
-
-/*
- * 8042EM hardware decodes with fixed mask of 0x04
- * Example: io_base == 0x60 -> decodes 0x60/0x64
- * Enable both IBF and OBE interrupts.
- */
-void chip_8042_config(uint32_t io_base)
-{
- MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_8042);
-
-#ifdef CONFIG_HOSTCMD_ESPI
- MCHP_ESPI_IO_BAR_CTL_MASK(MCHP_ESPI_IO_BAR_ID_8042) = 0x04;
- MCHP_ESPI_IO_BAR(MCHP_ESPI_IO_BAR_ID_8042) =
- (io_base << 16) + 0x01ul;
-#else
- /* Set up 8042 interface at 0x60/0x64 */
- MCHP_LPC_8042_BAR = (io_base << 16) + (1ul << 15);
-#endif
- /* Set up indication of Auxiliary status */
- MCHP_8042_KB_CTRL |= BIT(7);
-
- MCHP_8042_ACT |= 1;
-
- MCHP_INT_ENABLE(MCHP_8042_GIRQ) = MCHP_8042_OBE_GIRQ_BIT +
- MCHP_8042_IBF_GIRQ_BIT;
-
- task_enable_irq(MCHP_IRQ_8042EM_IBF);
- task_enable_irq(MCHP_IRQ_8042EM_OBE);
-
-#ifndef CONFIG_KEYBOARD_IRQ_GPIO
- /* Set up SERIRQ for keyboard */
- MCHP_8042_KB_CTRL |= BIT(5);
-#ifdef CONFIG_HOSTCMD_ESPI
- /* Delivery 8042 keyboard interrupt as IRQ1 using eSPI SERIRQ */
- MCHP_ESPI_IO_SERIRQ_REG(MCHP_ESPI_SIRQ_8042_KB) = 1;
-#else
- MCHP_LPC_SIRQ(1) = 0x01;
-#endif
-#endif
-}
-
-/*
- * Access data RAM
- * MCHP EMI Base address register = physical address of buffer
- * in SRAM. EMI hardware adds 16-bit offset Host programs into
- * EC_Address_LSB/MSB registers.
- * Limit EMI read / write range. First 256 bytes are RW for host
- * commands. Second 256 bytes are RO for memory-mapped data.
- * Hardware decodes a fixed 16 byte IO range.
- */
-void chip_emi0_config(uint32_t io_base)
-{
-#ifdef CONFIG_HOSTCMD_ESPI
- MCHP_ESPI_IO_BAR_CTL_MASK(MCHP_ESPI_IO_BAR_ID_EMI0) = 0x0F;
- MCHP_ESPI_IO_BAR(MCHP_ESPI_IO_BAR_ID_EMI0) =
- (io_base << 16) + 0x01ul;
-#else
- MCHP_LPC_EMI0_BAR = (io_base << 16) + (1ul << 15);
-#endif
-
- MCHP_EMI_MBA0(0) = (uint32_t)mem_mapped;
-
- MCHP_EMI_MRL0(0) = 0x200;
- MCHP_EMI_MWL0(0) = 0x100;
-
- MCHP_INT_ENABLE(MCHP_EMI_GIRQ) = MCHP_EMI_GIRQ_BIT(0);
- task_enable_irq(MCHP_IRQ_EMI0);
-}
-
-/* Setup Port 80 Debug Hardware ports.
- * First instance for I/O 80h only.
- * Clear FIFO's and time stamp.
- * Set FIFO interrupt threshold to maximum of 14 bytes.
- */
-#if defined(CHIP_FAMILY_MEC172X)
-void chip_port80_config(uint32_t io_base)
-{
- MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_BDP0);
-
- /* reset, configure, and enable */
- MCHP_BDP0_CONFIG = MCHP_BDP_CFG_SRST;
- MCHP_BDP0_CONFIG = MCHP_BDP_CFG_FIFO_THRH_28;
- MCHP_BDP0_INTR_EN = MCHP_BDP_IEN_THRH;
- MCHP_BDP0_ACTV = 1;
-
- MCHP_INT_SOURCE(15) = MCHP_INT15_BDP0;
- MCHP_INT_ENABLE(15) = MCHP_INT15_BDP0;
- task_enable_irq(MCHP_IRQ_BDP0);
-
- /* Last: Enable Host access via eSPI IO BAR */
- MCHP_ESPI_IO_BAR_CTL_MASK(MCHP_ESPI_IO_BAR_BDP0) = 0x00;
- MCHP_ESPI_IO_BAR(MCHP_ESPI_IO_BAR_BDP0) =
- (io_base << 16) + 0x01ul;
-}
-#else
-void chip_port80_config(uint32_t io_base)
-{
- MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_P80CAP0);
-
- MCHP_P80_CFG(0) = MCHP_P80_FLUSH_FIFO_WO +
- MCHP_P80_RESET_TIMESTAMP_WO;
-
-#ifdef CONFIG_HOSTCMD_ESPI
- MCHP_ESPI_IO_BAR_CTL_MASK(MCHP_ESPI_IO_BAR_P80_0) = 0x00;
- MCHP_ESPI_IO_BAR(MCHP_ESPI_IO_BAR_P80_0) =
- (io_base << 16) + 0x01ul;
-#else
- MCHP_LPC_P80DBG0_BAR = (io_base << 16) + (1ul << 15);
-#endif
- MCHP_P80_CFG(0) = MCHP_P80_FIFO_THRHOLD_14 +
- MCHP_P80_TIMEBASE_1500KHZ +
- MCHP_P80_TIMER_ENABLE;
-
- MCHP_P80_ACTIVATE(0) = 1;
-
- MCHP_INT_SOURCE(15) = MCHP_P80_GIRQ_BIT(0);
- MCHP_INT_ENABLE(15) = MCHP_P80_GIRQ_BIT(0);
- task_enable_irq(MCHP_IRQ_PORT80DBG0);
-}
-#endif
-
-#ifdef CONFIG_MCHP_DEBUG_LPC
-static void chip_lpc_iobar_debug(void)
-{
- CPRINTS("LPC ACPI EC0 IO BAR = 0x%08x", MCHP_LPC_ACPI_EC_BAR(0));
- CPRINTS("LPC ACPI EC1 IO BAR = 0x%08x", MCHP_LPC_ACPI_EC_BAR(1));
- CPRINTS("LPC 8042EM IO BAR = 0x%08x", MCHP_LPC_8042_BAR);
- CPRINTS("LPC EMI0 IO BAR = 0x%08x", MCHP_LPC_EMI0_BAR);
- CPRINTS("LPC Port80Dbg0 IO BAR = 0x%08x", MCHP_LPC_P80DBG0_BAR);
-}
-#endif
-
-/*
- * Most registers in LPC module are reset when the host is off.
- * We need to set up LPC again when the host is starting up.
- * MCHP LRESET# can be one of two pins
- * GPIO_0052 Function 2
- * GPIO_0064 Function 1
- * Use GPIO interrupt to detect LRESET# changes.
- * Use GPIO_0064 for LRESET#. Must update board/board_name/gpio.inc
- *
- * For eSPI PLATFORM_RESET# virtual wire is used as LRESET#
- *
- */
-#ifndef CONFIG_HOSTCMD_ESPI
-static void setup_lpc(void)
-{
- MCHP_LPC_CFG_BAR |= (1ul << 15);
-
- /* Set up ACPI0 for 0x62/0x66 */
- chip_acpi_ec_config(0, 0x62, 0x04);
-
- /* Set up ACPI1 for 0x200 - 0x207 */
- chip_acpi_ec_config(1, 0x200, 0x07);
-
- /* Set up 8042 interface at 0x60/0x64 */
- chip_8042_config(0x60);
-
-#ifndef CONFIG_KEYBOARD_IRQ_GPIO
- /* Set up SERIRQ for keyboard */
- MCHP_8042_KB_CTRL |= BIT(5);
- MCHP_LPC_SIRQ(1) = 0x01;
-#endif
- /* EMI0 at IO 0x800 */
- chip_emi0_config(0x800);
-
- chip_port80_config(0x80);
-
- lpc_mem_mapped_init();
-
- /* Activate LPC interface */
- MCHP_LPC_ACT |= 1;
-
- /* Sufficiently initialized */
- init_done = 1;
-
- /* Update host events now that we can copy them to memmap */
- lpc_update_host_event_status();
-
-#ifdef CONFIG_MCHP_DEBUG_LPC
- chip_lpc_iobar_debug();
-#endif
-}
-DECLARE_HOOK(HOOK_CHIPSET_STARTUP, setup_lpc, HOOK_PRIO_FIRST);
-#endif
-
-static void lpc_init(void)
-{
- CPUTS("LPC HOOK_INIT");
-
- /* Initialize host args and memory map to all zero */
- memset(lpc_host_args, 0, sizeof(*lpc_host_args));
- memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE);
-
- /*
- * Clear PCR sleep enables for peripherals we are using for
- * both LPC and eSPI.
- * Global Configuration, ACPI EC0/1, 8042 Keyboard controller.
- * NOTE: EMI doesn't have a sleep enable.
- */
- MCHP_PCR_SLP_DIS_DEV_MASK(2, MCHP_PCR_SLP_EN2_GCFG +
- MCHP_PCR_SLP_EN2_ACPI_EC0 +
- MCHP_PCR_SLP_EN2_ACPI_EC0 +
- MCHP_PCR_SLP_EN2_MIF8042);
-
-#ifdef CONFIG_HOSTCMD_ESPI
-
- espi_init();
-
-#else
- /* Clear PCR LPC sleep enable */
- MCHP_PCR_SLP_DIS_DEV(MCHP_PCR_LPC);
-
- /* configure pins */
- gpio_config_module(MODULE_LPC, 1);
-
- /*
- * MCHP LRESET# interrupt is GPIO interrupt
- * and configured by GPIO table in board level gpio.inc
- * Refer to lpcrst_interrupt() in this file.
- */
- gpio_enable_interrupt(GPIO_PCH_PLTRST_L);
-
- /*
- * b[8]=1(LRESET# is platform reset), b[0]=0 VCC_PWRGD is
- * asserted when LRESET# is 1(inactive)
- */
- MCHP_PCR_PWR_RST_CTL = 0x100ul;
-
- /*
- * Allow LPC sleep if Host CLKRUN# signals
- * clock stop and there are no pending SERIRQ
- * or LPC DMA.
- */
- MCHP_LPC_EC_CLK_CTRL =
- (MCHP_LPC_EC_CLK_CTRL & ~(0x03ul)) | 0x01ul;
-
- setup_lpc();
-#endif
-}
-/*
- * Set priority 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);
-
-#ifdef CONFIG_CHIPSET_RESET_HOOK
-static void lpc_chipset_reset(void)
-{
- hook_notify(HOOK_CHIPSET_RESET);
-}
-DECLARE_DEFERRED(lpc_chipset_reset);
-#endif
-
-void lpc_set_init_done(int val)
-{
- init_done = val;
-}
-
-/*
- * MCHP MCHP family allows selecting one of two GPIO pins alternate
- * functions as LRESET#.
- * LRESET# can be monitored as bit[1](read-only) of the
- * LPC Bus Monitor register. NOTE: Bus Monitor is synchronized with
- * LPC clock. We have observed APL configurations where LRESET#
- * changes while LPC clock is not running!
- * bit[1]==0 -> LRESET# is high
- * bit[1]==1 -> LRESET# is low (active)
- * LRESET# active causes the EC to activate internal signal RESET_HOST.
- * MCHP_PCR_PWR_RST_STS bit[3](read-only) = RESET_HOST_STATUS =
- * 0 = Reset active
- * 1 = Reset not active
- * MCHP is different than MEC1322 in that LRESET# is not connected
- * to a separate interrupt source.
- * If using LPC the board design must select on of the two GPIO pins
- * dedicated for LRESET# and this pin must be configured in the
- * board level gpio.inc
- */
-void lpcrst_interrupt(enum gpio_signal signal)
-{
-#ifndef CONFIG_HOSTCMD_ESPI
- /* Initialize LPC module when LRESET# is de-asserted */
- if (!lpc_get_pltrst_asserted()) {
- setup_lpc();
- } else {
- /* Store port 80 reset event */
- port_80_write(PORT_80_EVENT_RESET);
-
-#ifdef CONFIG_CHIPSET_RESET_HOOK
- /* Notify HOOK_CHIPSET_RESET */
- hook_call_deferred(&lpc_chipset_reset_data, MSEC);
-#endif
- }
-#ifdef CONFIG_MCHP_DEBUG_LPC
- CPRINTS("LPC RESET# %sasserted",
- lpc_get_pltrst_asserted() ? "" : "de");
-#endif
-#endif
-}
-
-/*
- * TODO - Is this only for debug of EMI host communication
- * or logging of EMI host communication? We don't observe
- * this ISR so Host is not writing to MCHP_EMI_H2E_MBX(0).
- */
-void emi0_interrupt(void)
-{
- uint8_t h2e;
-
- h2e = MCHP_EMI_H2E_MBX(0);
- CPRINTS("LPC Host 0x%02x -> EMI0 H2E(0)", h2e);
- port_80_write(h2e);
-}
-DECLARE_IRQ(MCHP_IRQ_EMI0, emi0_interrupt, 1);
-
-/*
- * ISR empties BIOS Debug 0 FIFO and
- * writes data to circular buffer. How can we be
- * sure this routine can read the last Port 80h byte?
- * MEC172x BDP capture data is different. It returns a
- * 16-bit value where bits [7:0] are the data and bits [15:7]
- * are flags indicating if the data is part of a multi-byte
- * write sequence by the host and read-only FIFO status bits.
- * The capture HW in previous chips included an optional time
- * stamp in bits[31:8] of the data register.
- */
-int port_80_read(void)
-{
- int data = PORT_80_IGNORE;
-
-#if defined(CHIP_FAMILY_MEC172X)
- if (MCHP_BDP0_STATUS & MCHP_BDP_STATUS_NOT_EMPTY)
- data = MCHP_BDP0_DATTR & 0xFFU;
-#else
- if (MCHP_P80_STS(0) & MCHP_P80_STS_NOT_EMPTY)
- data = MCHP_P80_CAP(0) & 0xFF;
-#endif
-
- return data;
-}
-
-#ifdef CONFIG_BOARD_ID_CMD_ACPI_EC1
-/*
- * Handle custom ACPI EC0 commands.
- * Some chipset CoreBoot will send read board ID command expecting
- * a two byte response.
- */
-static int acpi_ec0_custom(int is_cmd, uint8_t value,
- uint8_t *resultptr)
-{
- int rval;
-
- rval = 0;
- custom_acpi_ec2os_cnt = 0;
- *resultptr = 0x00;
-
- if (is_cmd && (value == 0x0d)) {
- MCHP_INT_SOURCE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_OBE_GIRQ_BIT(0);
- /* Write two bytes sequence 0xC2, 0x04 to Host */
- if (MCHP_ACPI_EC_BYTE_CTL(0) & 0x01) {
- /* Host enabled 4-byte mode */
- MCHP_ACPI_EC_EC2OS(0, 0) = 0x02;
- MCHP_ACPI_EC_EC2OS(0, 1) = 0x04;
- MCHP_ACPI_EC_EC2OS(0, 2) = 0x00;
- /* Sets OBF */
- MCHP_ACPI_EC_EC2OS(0, 3) = 0x00;
- } else {
- /* single byte mode */
- *resultptr = 0x02;
- custom_acpi_ec2os_cnt = 1;
- custom_apci_ec2os[0] = 0x04;
- MCHP_ACPI_EC_EC2OS(0, 0) = 0x02;
- MCHP_INT_ENABLE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_OBE_GIRQ_BIT(0);
- task_enable_irq(MCHP_IRQ_ACPIEC0_OBE);
- }
- custom_acpi_cmd = 0;
- rval = 1;
- }
-
- return rval;
-}
-#endif
-
-void acpi_0_interrupt(void)
-{
- uint8_t value, result, is_cmd;
-
- is_cmd = MCHP_ACPI_EC_STATUS(0);
-
- /* Set the bust bi */
- MCHP_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_PROCESSING;
-
- result = MCHP_ACPI_EC_BYTE_CTL(0);
-
- /* Read command/data; this clears the FRMH bit. */
- value = MCHP_ACPI_EC_OS2EC(0, 0);
-
- is_cmd &= EC_LPC_STATUS_LAST_CMD;
-
- /* Handle whatever this was. */
- result = 0;
- if (acpi_ap_to_ec(is_cmd, value, &result))
- MCHP_ACPI_EC_EC2OS(0, 0) = result;
-#ifdef CONFIG_BOARD_ID_CMD_ACPI_EC1
- else
- acpi_ec0_custom(is_cmd, value, &result);
-#endif
- /* Clear the busy bit */
- MCHP_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_PROCESSING;
-
- /* Clear R/W1C status bit in Aggregator */
- MCHP_INT_SOURCE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_IBF_GIRQ_BIT(0);
-
- /*
- * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty /
- * Output Buffer Full condition on the kernel channel/
- */
- lpc_generate_sci();
-}
-DECLARE_IRQ(MCHP_IRQ_ACPIEC0_IBF, acpi_0_interrupt, 1);
-
-#ifdef CONFIG_BOARD_ID_CMD_ACPI_EC1
-/*
- * ACPI EC0 output buffer empty ISR.
- * Used to handle custom ACPI EC0 command requiring
- * two byte response.
- */
-void acpi_0_obe_isr(void)
-{
- uint8_t sts, data;
-
- MCHP_INT_SOURCE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_OBE_GIRQ_BIT(0);
-
- sts = MCHP_ACPI_EC_STATUS(0);
- data = MCHP_ACPI_EC_BYTE_CTL(0);
- data = sts;
- if (custom_acpi_ec2os_cnt) {
- custom_acpi_ec2os_cnt--;
- data = custom_apci_ec2os[custom_acpi_ec2os_cnt];
- }
-
- if (custom_acpi_ec2os_cnt == 0) { /* was last byte? */
- MCHP_INT_DISABLE(MCHP_ACPI_EC_GIRQ) =
- MCHP_ACPI_EC_OBE_GIRQ_BIT(0);
- }
-
- lpc_generate_sci();
-}
-DECLARE_IRQ(MCHP_IRQ_ACPIEC0_OBE, acpi_0_obe_isr, 1);
-#endif
-
-void acpi_1_interrupt(void)
-{
- uint8_t st = MCHP_ACPI_EC_STATUS(1);
-
- if (!(st & EC_LPC_STATUS_FROM_HOST) ||
- !(st & EC_LPC_STATUS_LAST_CMD))
- return;
-
- /* Set the busy bit */
- MCHP_ACPI_EC_STATUS(1) |= EC_LPC_STATUS_PROCESSING;
-
- /*
- * Read the command byte. This clears the FRMH bit in
- * the status byte.
- */
- host_cmd_args.command = MCHP_ACPI_EC_OS2EC(1, 0);
-
- host_cmd_args.result = EC_RES_SUCCESS;
- host_cmd_args.send_response = lpc_send_response;
- host_cmd_flags = lpc_host_args->flags;
-
- /* We only support new style command (v3) now */
- if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
- lpc_packet.send_response = lpc_send_response_packet;
-
- lpc_packet.request =
- (const void *)lpc_get_hostcmd_data_range();
- 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 *)lpc_get_hostcmd_data_range();
- 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);
-
- } else {
- /* Old style command unsupported */
- host_cmd_args.result = EC_RES_INVALID_COMMAND;
-
- /* Hand off to host command handler */
- host_command_received(&host_cmd_args);
- }
-}
-DECLARE_IRQ(MCHP_IRQ_ACPIEC1_IBF, acpi_1_interrupt, 1);
-
-#ifdef HAS_TASK_KEYPROTO
-/*
- * Reading data out of input buffer clears read-only status
- * in 8042EM. Next, we must clear aggregator status.
- */
-void kb_ibf_interrupt(void)
-{
- if (lpc_keyboard_input_pending())
- keyboard_host_write(MCHP_8042_H2E,
- MCHP_8042_STS & BIT(3));
-
- MCHP_INT_SOURCE(MCHP_8042_GIRQ) = MCHP_8042_IBF_GIRQ_BIT;
- task_wake(TASK_ID_KEYPROTO);
-}
-DECLARE_IRQ(MCHP_IRQ_8042EM_IBF, kb_ibf_interrupt, 1);
-
-/*
- * Interrupt generated when Host reads data byte from 8042EM
- * output buffer. The 8042EM STATUS.OBF bit will clear when the
- * Host reads the data and assert its OBE signal to interrupt
- * aggregator. Clear aggregator 8042EM OBE R/WC status bit before
- * invoking task.
- */
-void kb_obe_interrupt(void)
-{
- MCHP_INT_SOURCE(MCHP_8042_GIRQ) = MCHP_8042_OBE_GIRQ_BIT;
- task_wake(TASK_ID_KEYPROTO);
-}
-DECLARE_IRQ(MCHP_IRQ_8042EM_OBE, kb_obe_interrupt, 1);
-#endif
-
-/*
- * Bit 0 of 8042EM STATUS register is OBF meaning EC has written
- * data to EC2HOST data register. OBF is cleared when the host
- * reads the data.
- */
-int lpc_keyboard_has_char(void)
-{
- return (MCHP_8042_STS & BIT(0)) ? 1 : 0;
-}
-
-int lpc_keyboard_input_pending(void)
-{
- return (MCHP_8042_STS & BIT(1)) ? 1 : 0;
-}
-
-/*
- * called from common/keyboard_8042.c
- */
-void lpc_keyboard_put_char(uint8_t chr, int send_irq)
-{
- MCHP_8042_E2H = chr;
- if (send_irq)
- keyboard_irq_assert();
-}
-
-/*
- * Read 8042 register and write to read-only register
- * insuring compiler does not optimize out the read.
- */
-void lpc_keyboard_clear_buffer(void)
-{
- MCHP_PCR_CHIP_OSC_ID = MCHP_8042_OBF_CLR;
-}
-
-void lpc_keyboard_resume_irq(void)
-{
- if (lpc_keyboard_has_char())
- keyboard_irq_assert();
-}
-
-void lpc_set_acpi_status_mask(uint8_t mask)
-{
- MCHP_ACPI_EC_STATUS(0) |= mask;
-}
-
-void lpc_clear_acpi_status_mask(uint8_t mask)
-{
- MCHP_ACPI_EC_STATUS(0) &= ~mask;
-}
-
-/*
- * Read hardware to determine state of platform reset signal.
- * LPC issue: Observed APL chipset changing LRESET# while LPC
- * clock is not running. This violates original LPC specification.
- * Unable to find information in APL chipset documentation
- * stating APL can change LRESET# with LPC clock not running.
- * Could this be a CoreBoot issue during CB LPC configuration?
- * We work-around this issue by reading the GPIO state.
- */
-int lpc_get_pltrst_asserted(void)
-{
-#ifdef CONFIG_HOSTCMD_ESPI
- /*
- * eSPI PLTRST# a VWire or side-band signal
- * Controlled by CONFIG_HOSTCMD_ESPI
- */
- return !espi_vw_get_wire(VW_PLTRST_L);
-#else
- /* returns 1 if LRESET# pin is asserted(low) else 0 */
-#ifdef CONFIG_CHIPSET_APL_GLK
- /* Use GPIO */
- return !gpio_get_level(GPIO_PCH_PLTRST_L);
-#else
- /* assumes LPC clock is running when host changes LRESET# */
- return (MCHP_LPC_BUS_MONITOR & (1<<1)) ? 1 : 0;
-#endif
-#endif
-}
-
-/* Enable LPC ACPI-EC0 interrupts */
-void lpc_enable_acpi_interrupts(void)
-{
- task_enable_irq(MCHP_IRQ_ACPIEC0_IBF);
-}
-
-/* Disable LPC ACPI-EC0 interrupts */
-void lpc_disable_acpi_interrupts(void)
-{
- task_disable_irq(MCHP_IRQ_ACPIEC0_IBF);
-}
-
-/* On boards without a host, this command is used to set up LPC */
-static int lpc_command_init(int argc, char **argv)
-{
- lpc_init();
- return EC_SUCCESS;
-}
-DECLARE_CONSOLE_COMMAND(lpcinit, lpc_command_init, NULL, NULL);
-
-/* 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;
-
- CPUTS("MEC1701 Handler EC_CMD_GET_PROTOCOL_INFO");
-
- 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));
-
-#ifdef CONFIG_MCHP_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
-