diff options
Diffstat (limited to 'chip/mec1322/lpc.c')
-rw-r--r-- | chip/mec1322/lpc.c | 520 |
1 files changed, 0 insertions, 520 deletions
diff --git a/chip/mec1322/lpc.c b/chip/mec1322/lpc.c deleted file mode 100644 index 020cd0e23e..0000000000 --- a/chip/mec1322/lpc.c +++ /dev/null @@ -1,520 +0,0 @@ -/* Copyright 2013 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 MEC1322 */ - -#include "acpi.h" -#include "console.h" -#include "gpio.h" -#include "hooks.h" -#include "host_command.h" -#include "keyboard_protocol.h" -#include "lpc.h" -#include "port80.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "chipset.h" - -/* Console output macros */ -#define CPUTS(outstr) cputs(CC_LPC, outstr) -#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args) - -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; - -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 -} - -/** - * 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) -{ - gpio_set_level(GPIO_PCH_SMI_L, 0); - udelay(65); - gpio_set_level(GPIO_PCH_SMI_L, 1); -} - -static void lpc_generate_sci(void) -{ -#ifdef CONFIG_SCI_GPIO - gpio_set_level(CONFIG_SCI_GPIO, 0); - udelay(65); - gpio_set_level(CONFIG_SCI_GPIO, 1); -#else - MEC1322_ACPI_PM_STS |= 1; - udelay(65); - MEC1322_ACPI_PM_STS &= ~1; -#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); - - /* 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 mem_mapped + 0x100; -} - -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; - - if (!init_done) - return; - - /* Disable LPC interrupt while updating status register */ - task_disable_irq(MEC1322_IRQ_ACPIEC0_IBF); - - if (lpc_get_host_events_by_type(LPC_HOST_EVENT_SMI)) { - /* Only generate SMI for first event */ - if (!(MEC1322_ACPI_EC_STATUS(0) & EC_LPC_STATUS_SMI_PENDING)) - need_smi = 1; - MEC1322_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_SMI_PENDING; - } else { - MEC1322_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; - MEC1322_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_SCI_PENDING; - } else { - MEC1322_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_SCI_PENDING; - } - - /* Copy host events to mapped memory */ - *(host_event_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) = - lpc_get_host_events(); - - task_enable_irq(MEC1322_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_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. */ - MEC1322_ACPI_EC_EC2OS(1, 0) = pkt->driver_result; - - /* Clear the busy bit, so the host knows the EC is done. */ - MEC1322_ACPI_EC_STATUS(1) &= ~EC_LPC_STATUS_PROCESSING; -} - -/* - * 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. - */ -static void setup_lpc(void) -{ - gpio_config_module(MODULE_LPC, 1); - - /* Set up interrupt on LRESET# deassert */ - MEC1322_INT_SOURCE(19) = BIT(1); - MEC1322_INT_ENABLE(19) |= BIT(1); - MEC1322_INT_BLK_EN |= BIT(19); - task_enable_irq(MEC1322_IRQ_GIRQ19); - - /* Set up ACPI0 for 0x62/0x66 */ - MEC1322_LPC_ACPI_EC0_BAR = 0x00628304; - MEC1322_INT_ENABLE(15) |= BIT(6); - MEC1322_INT_BLK_EN |= BIT(15); - /* Clear STATUS_PROCESSING bit in case it was set during sysjump */ - MEC1322_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_PROCESSING; - task_enable_irq(MEC1322_IRQ_ACPIEC0_IBF); - - /* Set up ACPI1 for 0x200/0x204 */ - MEC1322_LPC_ACPI_EC1_BAR = 0x02008407; - MEC1322_INT_ENABLE(15) |= BIT(8); - MEC1322_INT_BLK_EN |= BIT(15); - MEC1322_ACPI_EC_STATUS(1) &= ~EC_LPC_STATUS_PROCESSING; - task_enable_irq(MEC1322_IRQ_ACPIEC1_IBF); - - /* Set up 8042 interface at 0x60/0x64 */ - MEC1322_LPC_8042_BAR = 0x00608104; - - /* Set up indication of Auxiliary sts */ - MEC1322_8042_KB_CTRL |= BIT(7); - - MEC1322_8042_ACT |= 1; - MEC1322_INT_ENABLE(15) |= (BIT(13) | BIT(14)); - MEC1322_INT_BLK_EN |= BIT(15); - task_enable_irq(MEC1322_IRQ_8042EM_IBF); - task_enable_irq(MEC1322_IRQ_8042EM_OBF); - -#ifndef CONFIG_KEYBOARD_IRQ_GPIO - /* Set up SERIRQ for keyboard */ - MEC1322_8042_KB_CTRL |= BIT(5); - MEC1322_LPC_SIRQ(1) = 0x01; -#endif - - /* Set up EMI module for memory mapped region, base address 0x800 */ - MEC1322_LPC_EMI_BAR = 0x0800800f; - MEC1322_INT_ENABLE(15) |= BIT(2); - MEC1322_INT_BLK_EN |= BIT(15); - task_enable_irq(MEC1322_IRQ_EMI); - - /* Access data RAM through alias address */ - MEC1322_EMI_MBA0 = (uint32_t)mem_mapped - 0x118000 + 0x20000000; - - /* - * Limit EMI read / write range. First 256 bytes are RW for host - * commands. Second 256 bytes are RO for mem-mapped data. - */ - MEC1322_EMI_MRL0 = 0x200; - MEC1322_EMI_MWL0 = 0x100; - - /* Set up Mailbox for Port80 trapping */ - MEC1322_MBX_INDEX = 0xff; - MEC1322_LPC_MAILBOX_BAR = 0x00808901; - - /* 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; - - /* Sufficiently initialized */ - init_done = 1; - - /* Update host events now that we can copy them to memmap */ - lpc_update_host_event_status(); -} -DECLARE_HOOK(HOOK_CHIPSET_STARTUP, setup_lpc, HOOK_PRIO_FIRST); - -static void lpc_init(void) -{ - /* Activate LPC interface */ - MEC1322_LPC_ACT |= 1; - - /* - * Ring Oscillator not permitted to shut down - * until LPC activate bit is cleared - */ - MEC1322_LPC_CLK_CTRL |= 3; - - /* 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); - - setup_lpc(); -} -/* - * 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); - -#ifdef CONFIG_CHIPSET_RESET_HOOK -static void lpc_chipset_reset(void) -{ - hook_notify(HOOK_CHIPSET_RESET); -} -DECLARE_DEFERRED(lpc_chipset_reset); -#endif - -void girq19_interrupt(void) -{ - /* Check interrupt result for LRESET# trigger */ - if (MEC1322_INT_RESULT(19) & BIT(1)) { - /* Initialize LPC module when LRESET# is deasserted */ - 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 - } - - CPRINTS("LPC RESET# %sasserted", - lpc_get_pltrst_asserted() ? "" : "de"); - - /* Clear interrupt source */ - MEC1322_INT_SOURCE(19) = BIT(1); - } -} -DECLARE_IRQ(MEC1322_IRQ_GIRQ19, girq19_interrupt, 1); - -void emi_interrupt(void) -{ - port_80_write(MEC1322_EMI_H2E_MBX); -} -DECLARE_IRQ(MEC1322_IRQ_EMI, emi_interrupt, 1); - -/* - * Port80 POST code polling limitation: - * - POST code 0xFF is ignored. - */ -int port_80_read(void) -{ - int data; - - /* read MBX_INDEX for POST code */ - data = MEC1322_MBX_INDEX; - - /* clear MBX_INDEX for next POST code*/ - MEC1322_MBX_INDEX = 0xff; - - /* mark POST code 0xff as invalid */ - if (data == 0xff) - data = PORT_80_IGNORE; - - return data; -} - -void acpi_0_interrupt(void) -{ - uint8_t value, result, is_cmd; - - is_cmd = MEC1322_ACPI_EC_STATUS(0) & EC_LPC_STATUS_LAST_CMD; - - /* Set the bust bi */ - MEC1322_ACPI_EC_STATUS(0) |= EC_LPC_STATUS_PROCESSING; - - /* Read command/data; this clears the FRMH bit. */ - value = MEC1322_ACPI_EC_OS2EC(0, 0); - - /* Handle whatever this was. */ - if (acpi_ap_to_ec(is_cmd, value, &result)) - MEC1322_ACPI_EC_EC2OS(0, 0) = result; - - /* Clear the busy bit */ - MEC1322_ACPI_EC_STATUS(0) &= ~EC_LPC_STATUS_PROCESSING; - - /* - * 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(MEC1322_IRQ_ACPIEC0_IBF, acpi_0_interrupt, 1); - -void acpi_1_interrupt(void) -{ - uint8_t st = MEC1322_ACPI_EC_STATUS(1); - if (!(st & EC_LPC_STATUS_FROM_HOST) || - !(st & EC_LPC_STATUS_LAST_CMD)) - return; - - /* Set the busy bit */ - MEC1322_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 = MEC1322_ACPI_EC_OS2EC(1, 0); - - host_cmd_args.result = EC_RES_SUCCESS; - 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); - return; - } 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(MEC1322_IRQ_ACPIEC1_IBF, acpi_1_interrupt, 1); - -#ifdef HAS_TASK_KEYPROTO -void kb_ibf_interrupt(void) -{ - if (lpc_keyboard_input_pending()) - keyboard_host_write(MEC1322_8042_H2E, - MEC1322_8042_STS & BIT(3)); - task_wake(TASK_ID_KEYPROTO); -} -DECLARE_IRQ(MEC1322_IRQ_8042EM_IBF, kb_ibf_interrupt, 1); - -void kb_obf_interrupt(void) -{ - task_wake(TASK_ID_KEYPROTO); -} -DECLARE_IRQ(MEC1322_IRQ_8042EM_OBF, kb_obf_interrupt, 1); -#endif - -int lpc_keyboard_has_char(void) -{ - return (MEC1322_8042_STS & BIT(0)) ? 1 : 0; -} - -int lpc_keyboard_input_pending(void) -{ - return (MEC1322_8042_STS & BIT(1)) ? 1 : 0; -} - -void lpc_keyboard_put_char(uint8_t chr, int send_irq) -{ - MEC1322_8042_E2H = chr; - if (send_irq) - keyboard_irq_assert(); -} - -void lpc_keyboard_clear_buffer(void) -{ - volatile char unused __attribute__((unused)); - - unused = MEC1322_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) -{ - MEC1322_ACPI_EC_STATUS(0) |= mask; -} - -void lpc_clear_acpi_status_mask(uint8_t mask) -{ - MEC1322_ACPI_EC_STATUS(0) &= ~mask; -} - -int lpc_get_pltrst_asserted(void) -{ - return (MEC1322_LPC_BUS_MONITOR & (1<<1)) ? 1 : 0; -} - -/* Enable LPC ACPI-EC0 interrupts */ -void lpc_enable_acpi_interrupts(void) -{ - task_enable_irq(MEC1322_IRQ_ACPIEC0_IBF); -} - -/* Disable LPC ACPI-EC0 interrupts */ -void lpc_disable_acpi_interrupts(void) -{ - task_disable_irq(MEC1322_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; - - 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)); |