summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <dino.li@ite.com.tw>2015-06-16 12:01:08 +0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-06-17 13:11:07 +0000
commit3eb04bb57ed9c82b277fd16c0722665def273f1e (patch)
tree270f02f3efeb877b1196a77f626bde04e84be966
parentcca70a517b21d32e45880d1296997436d026e7b7 (diff)
downloadchrome-ec-3eb04bb57ed9c82b277fd16c0722665def273f1e.tar.gz
it8380dev: add pmc control module
Add pmc(LPC ACPI) control module for emulation board. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=1. 62h/66h port. 1-a. out 66h 80h, out 62h 00h, in 62h 02h 1-b. out 66h 81h, out 62h 01h, out 62h 55h 1-c. out 66h 80h, out 62h 01h, in 62h 55h 1-d. out 66h 80h, out 62h 02h, in 62h aah 2. H2RAM LPC I/O cycle 900h ~ 9FFh = DLM 0x8D900 ~ 0x8D9FF and host read only. 3. 80h port, console command port80. 4. host command. 4-a. host request (LPC I/O 800h ~ 807h) 03 FD 00 00, 00 00 00 00 out 204h DAh, in 200h 00h host response (LPC I/O 800h ~ 80Bh) 03 F7 00 00, 04 00 00 00, 02 00 00 00 4-b. host request 03 EE 01 00, 00 00 04 00, 01 02 03 04 out 204h DAh, in 200h 00h host response 03 E5 00 00, 04 00 00 00, 05 05 05 05 Change-Id: I5c3bac66306dfba380548a74a64536ea606ddd3e Reviewed-on: https://chromium-review.googlesource.com/269271 Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Tested-by: Dino Li <dino.li@ite.com.tw> Commit-Queue: Dino Li <dino.li@ite.com.tw>
-rw-r--r--board/it8380dev/board.c34
-rw-r--r--board/it8380dev/board.h19
-rw-r--r--board/it8380dev/gpio.inc3
-rw-r--r--chip/it83xx/build.mk2
-rw-r--r--chip/it83xx/config_chip.h11
-rw-r--r--chip/it83xx/gpio.c2
-rw-r--r--chip/it83xx/intc.c33
-rw-r--r--chip/it83xx/intc.h6
-rw-r--r--chip/it83xx/lpc.c512
-rw-r--r--chip/it83xx/registers.h27
-rw-r--r--core/nds32/build.mk2
-rw-r--r--core/nds32/ec.lds.S17
12 files changed, 650 insertions, 18 deletions
diff --git a/board/it8380dev/board.c b/board/it8380dev/board.c
index 8448c98e30..12240c88ff 100644
--- a/board/it8380dev/board.c
+++ b/board/it8380dev/board.c
@@ -21,6 +21,7 @@
#include "keyboard_scan.h"
#include "timer.h"
#include "lpc.h"
+#include "intc.h"
/* Test GPIO interrupt function that toggles one LED. */
void test_interrupt(enum gpio_signal signal)
@@ -70,6 +71,39 @@ const struct ec2i_t pnpcfg_settings[] = {
{HOST_INDEX_IRQNUMX, 0x00},
/* Enable logical device */
{HOST_INDEX_LDA, 0x01},
+
+ /* Select logical device 12h(PM2) */
+ {HOST_INDEX_LDN, LDN_PMC2},
+ /* I/O Port Base Address 200h/204h */
+ {HOST_INDEX_IOBAD0_MSB, 0x02},
+ {HOST_INDEX_IOBAD0_LSB, 0x00},
+ {HOST_INDEX_IOBAD1_MSB, 0x02},
+ {HOST_INDEX_IOBAD1_LSB, 0x04},
+ /* Set IRQ=00h for logical device */
+ {HOST_INDEX_IRQNUMX, 0x00},
+ /* Enable logical device */
+ {HOST_INDEX_LDA, 0x01},
+
+ /* Select logical device 0Fh(SMFI) */
+ {HOST_INDEX_LDN, LDN_SMFI},
+ /* H2RAM LPC I/O cycle Dxxx */
+ {HOST_INDEX_DSLDC6, 0x00},
+ /* Enable H2RAM LPC I/O cycle */
+ {HOST_INDEX_DSLDC7, 0x01},
+ /* Enable logical device */
+ {HOST_INDEX_LDA, 0x01},
+
+ /* Select logical device 17h(PM3) */
+ {HOST_INDEX_LDN, LDN_PMC3},
+ /* I/O Port Base Address 80h */
+ {HOST_INDEX_IOBAD0_MSB, 0x00},
+ {HOST_INDEX_IOBAD0_LSB, 0x80},
+ {HOST_INDEX_IOBAD1_MSB, 0x00},
+ {HOST_INDEX_IOBAD1_LSB, 0x00},
+ /* Set IRQ=00h for logical device */
+ {HOST_INDEX_IRQNUMX, 0x00},
+ /* Enable logical device */
+ {HOST_INDEX_LDA, 0x01},
};
BUILD_ASSERT(ARRAY_SIZE(pnpcfg_settings) == EC2I_SETTING_COUNT);
diff --git a/board/it8380dev/board.h b/board/it8380dev/board.h
index 14523d4a1a..405966d70a 100644
--- a/board/it8380dev/board.h
+++ b/board/it8380dev/board.h
@@ -61,7 +61,24 @@ enum ec2i_setting {
EC2I_SET_PMC1_LDN,
EC2I_SET_PMC1_IRQ,
EC2I_SET_PMC1_ENABLE,
-
+ EC2I_SET_PMC2_LDN,
+ EC2I_SET_PMC2_BASE0_MSB,
+ EC2I_SET_PMC2_BASE0_LSB,
+ EC2I_SET_PMC2_BASE1_MSB,
+ EC2I_SET_PMC2_BASE1_LSB,
+ EC2I_SET_PMC2_IRQ,
+ EC2I_SET_PMC2_ENABLE,
+ EC2I_SET_SMFI_LDN,
+ EC2I_SET_SMFI_H2RAM_IO_BASE,
+ EC2I_SET_SMFI_H2RAM_MAP_LPC_IO,
+ EC2I_SET_SMFI_ENABLE,
+ EC2I_SET_PMC3_LDN,
+ EC2I_SET_PMC3_BASE0_MSB,
+ EC2I_SET_PMC3_BASE0_LSB,
+ EC2I_SET_PMC3_BASE1_MSB,
+ EC2I_SET_PMC3_BASE1_LSB,
+ EC2I_SET_PMC3_IRQ,
+ EC2I_SET_PMC3_ENABLE,
/* Number of EC2I settings */
EC2I_SETTING_COUNT
};
diff --git a/board/it8380dev/gpio.inc b/board/it8380dev/gpio.inc
index 8401f8bc51..858bd42705 100644
--- a/board/it8380dev/gpio.inc
+++ b/board/it8380dev/gpio.inc
@@ -6,6 +6,7 @@
*/
GPIO_INT(POWER_BUTTON_L, PIN(E, 4), GPIO_INT_BOTH | GPIO_PULL_UP, power_button_interrupt)
+GPIO_INT(PCH_PLTRST_L, PIN(E, 3), GPIO_INT_BOTH | GPIO_PULL_UP, lpcrst_interrupt)
GPIO_INT(LID_OPEN, PIN(E, 2), GPIO_INT_BOTH | GPIO_PULL_DOWN, lid_interrupt)
GPIO(H_LED0, PIN(A, 0), GPIO_ODR_HIGH)
@@ -25,12 +26,12 @@ GPIO(L_LED6, PIN(I, 6), GPIO_ODR_HIGH)
GPIO(BUSY_LED, PIN(J, 0), GPIO_OUT_LOW)
GPIO(GOOD_LED, PIN(J, 1), GPIO_OUT_HIGH)
GPIO(FAIL_LED, PIN(J, 2), GPIO_OUT_LOW)
-GPIO(PCH_PLTRST_L, PIN(E, 3), GPIO_INPUT)
GPIO(PCH_SMI_L, PIN(D, 3), GPIO_OUT_HIGH)
GPIO(PCH_SCI_L, PIN(D, 4), GPIO_OUT_HIGH)
GPIO(GATE_A20_H, PIN(B, 5), GPIO_OUT_HIGH)
GPIO(PCH_RCIN_L, PIN(B, 6), GPIO_OUT_HIGH)
GPIO(LPC_CLKRUN_L, PIN(H, 0), GPIO_OUT_LOW)
+GPIO(PCH_WAKE_L, PIN(B, 7), GPIO_ODR_HIGH) /* Wake signal from EC to PCH */
/* Unimplemented signals which we need to emulate for now */
UNIMPLEMENTED(ENTERING_RW)
diff --git a/chip/it83xx/build.mk b/chip/it83xx/build.mk
index f94257fb0e..af4ce15cfa 100644
--- a/chip/it83xx/build.mk
+++ b/chip/it83xx/build.mk
@@ -9,6 +9,8 @@
# IT83xx SoC family has an Andes N801 core.
CORE:=nds32
+CFLAGS_CPU+=-mno-gp-direct
+
# Required chip modules
chip-y=hwtimer.o uart.o gpio.o system.o jtag.o clock.o irq.o intc.o
diff --git a/chip/it83xx/config_chip.h b/chip/it83xx/config_chip.h
index 0d688f7eb3..b6b8239e96 100644
--- a/chip/it83xx/config_chip.h
+++ b/chip/it83xx/config_chip.h
@@ -59,6 +59,17 @@
#include "config_std_internal_flash.h"
/****************************************************************************/
+/* H2RAM memory mapping */
+
+/*
+ * Only it839x series and IT838x DX support mapping LPC I/O cycle 800h ~ 9FFh
+ * to 0x8D800h ~ 0x8D9FFh of DLM13.
+ */
+#define CONFIG_H2RAM_BASE 0x0008D000
+#define CONFIG_H2RAM_SIZE 0x00001000
+#define CONFIG_H2RAM_HOST_LPC_IO_BASE 0x800
+
+/****************************************************************************/
/* Customize the build */
/* Use hardware specific udelay() for this chip */
diff --git a/chip/it83xx/gpio.c b/chip/it83xx/gpio.c
index 09f7ff2492..49c31fb871 100644
--- a/chip/it83xx/gpio.c
+++ b/chip/it83xx/gpio.c
@@ -343,7 +343,7 @@ static void gpio_interrupt(int port, uint8_t mask)
const struct gpio_info *g = gpio_list;
for (i = 0; i < GPIO_IH_COUNT; i++, g++) {
- if (port == g->port && (mask & g->mask))
+ if (port == g->port && (mask & g->mask)) {
gpio_irq_handlers[i](i);
return;
}
diff --git a/chip/it83xx/intc.c b/chip/it83xx/intc.c
index f4ddd86ac1..e09f3694c2 100644
--- a/chip/it83xx/intc.c
+++ b/chip/it83xx/intc.c
@@ -34,3 +34,36 @@ void intc_cpu_int_group_5(void)
}
}
DECLARE_IRQ(CPU_INT_GROUP_5, intc_cpu_int_group_5, 2);
+
+void intc_cpu_int_group_4(void)
+{
+ /* Determine interrupt number. */
+ int intc_group_4 = IT83XX_INTC_IVCT4 - 16;
+
+ switch (intc_group_4) {
+#ifdef CONFIG_LPC
+ case IT83XX_IRQ_PMC_IN:
+ pm1_ibf_interrupt();
+ break;
+
+ case IT83XX_IRQ_PMC2_IN:
+ pm2_ibf_interrupt();
+ break;
+
+ case IT83XX_IRQ_PMC3_IN:
+ pm3_ibf_interrupt();
+ break;
+
+ case IT83XX_IRQ_PMC4_IN:
+ pm4_ibf_interrupt();
+ break;
+
+ case IT83XX_IRQ_PMC5_IN:
+ pm5_ibf_interrupt();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+DECLARE_IRQ(CPU_INT_GROUP_4, intc_cpu_int_group_4, 2);
diff --git a/chip/it83xx/intc.h b/chip/it83xx/intc.h
index 488331f2a9..8d125eb943 100644
--- a/chip/it83xx/intc.h
+++ b/chip/it83xx/intc.h
@@ -10,5 +10,11 @@
void lpc_kbc_ibf_interrupt(void);
void lpc_kbc_obe_interrupt(void);
+void pm1_ibf_interrupt(void);
+void pm2_ibf_interrupt(void);
+void pm3_ibf_interrupt(void);
+void pm4_ibf_interrupt(void);
+void pm5_ibf_interrupt(void);
+void lpcrst_interrupt(enum gpio_signal signal);
#endif /* __CROS_EC_IT83XX_INTC_H */
diff --git a/chip/it83xx/lpc.c b/chip/it83xx/lpc.c
index 1968761fbf..9db2719b87 100644
--- a/chip/it83xx/lpc.c
+++ b/chip/it83xx/lpc.c
@@ -24,7 +24,221 @@
#include "util.h"
#include "irq_chip.h"
-static uint8_t acpi_ec_memmap[EC_MEMMAP_SIZE] __aligned(4);
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+
+/* LPC PM channels */
+enum lpc_pm_ch {
+ LPC_PM1 = 0,
+ LPC_PM2,
+ LPC_PM3,
+ LPC_PM4,
+ LPC_PM5,
+};
+
+enum pm_ctrl_mask {
+ /* Input Buffer Full Interrupt Enable. */
+ PM_CTRL_IBFIE = 0x01,
+ /* Output Buffer Empty Interrupt Enable. */
+ PM_CTRL_OBEIE = 0x02,
+};
+
+#define LPC_ACPI_CMD LPC_PM1 /* ACPI commands 62h/66h port */
+#define LPC_HOST_CMD LPC_PM2 /* Host commands 200h/204h port */
+#define LPC_HOST_PORT_80H LPC_PM3 /* Host 80h port */
+
+static uint8_t acpi_ec_memmap[EC_MEMMAP_SIZE]
+ __attribute__((section(".h2ram.pool.acpiec")));
+static uint8_t host_cmd_memmap[256]
+ __attribute__((section(".h2ram.pool.hostcmd")));
+
+static uint32_t host_events; /* Currently pending SCI/SMI events */
+static uint32_t event_mask[3]; /* Event masks for each type */
+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 */
+
+/* Params must be 32-bit aligned */
+static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4);
+static int init_done;
+
+static uint8_t * const cmd_params = (uint8_t *)host_cmd_memmap +
+ EC_LPC_ADDR_HOST_PARAM - EC_LPC_ADDR_HOST_ARGS;
+static struct ec_lpc_host_args * const lpc_host_args =
+ (struct ec_lpc_host_args *)host_cmd_memmap;
+
+static void pm_set_ctrl(enum lpc_pm_ch ch, enum pm_ctrl_mask ctrl, int set)
+{
+ if (set)
+ IT83XX_PMC_PMCTL(ch) |= ctrl;
+ else
+ IT83XX_PMC_PMCTL(ch) &= ~ctrl;
+}
+
+static void pm_set_status(enum lpc_pm_ch ch, uint8_t status, int set)
+{
+ if (set)
+ IT83XX_PMC_PMSTS(ch) |= status;
+ else
+ IT83XX_PMC_PMSTS(ch) &= ~status;
+}
+
+static uint8_t pm_get_status(enum lpc_pm_ch ch)
+{
+ return IT83XX_PMC_PMSTS(ch);
+}
+
+static uint8_t pm_get_data_in(enum lpc_pm_ch ch)
+{
+ return IT83XX_PMC_PMDI(ch);
+}
+
+static void pm_put_data_out(enum lpc_pm_ch ch, uint8_t out)
+{
+ IT83XX_PMC_PMDO(ch) = out;
+}
+
+/**
+ * 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)
+{
+ gpio_set_level(GPIO_PCH_SCI_L, 0);
+ udelay(65);
+ gpio_set_level(GPIO_PCH_SCI_L, 1);
+}
+
+/**
+ * Update the level-sensitive wake signal to the AP.
+ *
+ * @param wake_events Currently asserted wake events
+ */
+static void lpc_update_wake(uint32_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);
+}
+
+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 OBF status bit. */
+ pm_put_data_out(LPC_HOST_CMD, args->result);
+
+ /* Clear the busy bit, so the host knows the EC is done. */
+ pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 0);
+}
+
+static void update_host_event_status(void)
+{
+ int need_sci = 0;
+ int need_smi = 0;
+
+ if (!init_done)
+ return;
+
+ /* Disable PMC1 interrupt while updating status register */
+ task_disable_irq(IT83XX_IRQ_PMC_IN);
+
+ if (host_events & event_mask[LPC_HOST_EVENT_SMI]) {
+ /* Only generate SMI for first event */
+ if (!(pm_get_status(LPC_ACPI_CMD) & EC_LPC_STATUS_SMI_PENDING))
+ need_smi = 1;
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_SMI_PENDING, 1);
+ } else {
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_SMI_PENDING, 0);
+ }
+
+ if (host_events & event_mask[LPC_HOST_EVENT_SCI]) {
+ /* Generate SCI for every event */
+ need_sci = 1;
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_SCI_PENDING, 1);
+ } else {
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_SCI_PENDING, 0);
+ }
+
+ /* Copy host events to mapped memory */
+ *(uint32_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) = host_events;
+
+ task_enable_irq(IT83XX_IRQ_PMC_IN);
+
+ /* Process the wake events. */
+ lpc_update_wake(host_events & event_mask[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. */
+ pm_put_data_out(LPC_HOST_CMD, pkt->driver_result);
+
+ /* Clear the busy bit, so the host knows the EC is done. */
+ pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 0);
+}
uint8_t *lpc_get_memmap_range(void)
{
@@ -95,24 +309,60 @@ void lpc_keyboard_resume_irq(void)
void lpc_set_host_event_state(uint32_t mask)
{
- /* --- (not implemented yet) --- */
+ if (mask != host_events) {
+ host_events = mask;
+ update_host_event_status();
+ }
}
int lpc_query_host_event_state(void)
{
- /* --- (not implemented yet) --- */
- return -1;
+ const uint32_t any_mask = event_mask[0] | event_mask[1] | event_mask[2];
+ int evt_index = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ const uint32_t e = (1 << i);
+
+ if (host_events & e) {
+ host_clear_events(e);
+
+ /*
+ * If host hasn't unmasked this event, drop it. We do
+ * this at query time rather than event generation time
+ * so that the host has a chance to unmask events
+ * before they're dropped by a query.
+ */
+ if (!(e & any_mask))
+ continue;
+
+ evt_index = i + 1; /* Events are 1-based */
+ break;
+ }
+ }
+
+ return evt_index;
}
void lpc_set_host_event_mask(enum lpc_host_event_type type, uint32_t mask)
{
- /* --- (not implemented yet) --- */
+ event_mask[type] = mask;
+ update_host_event_status();
}
uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
{
- /* --- (not implemented yet) --- */
- return 0;
+ return event_mask[type];
+}
+
+void lpc_set_acpi_status_mask(uint8_t mask)
+{
+ pm_set_status(LPC_ACPI_CMD, mask, 1);
+}
+
+void lpc_clear_acpi_status_mask(uint8_t mask)
+{
+ pm_set_status(LPC_ACPI_CMD, mask, 0);
}
int lpc_get_pltrst_asserted(void)
@@ -144,8 +394,128 @@ void lpc_kbc_obe_interrupt(void)
}
}
+void pm1_ibf_interrupt(void)
+{
+ int is_cmd;
+ uint8_t value, result;
+
+ if (pm_get_status(LPC_ACPI_CMD) & EC_LPC_STATUS_FROM_HOST) {
+ /* Set the busy bit */
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_PROCESSING, 1);
+
+ /* data from command port or data port */
+ is_cmd = pm_get_status(LPC_ACPI_CMD) & EC_LPC_STATUS_LAST_CMD;
+
+ /* Get command or data */
+ value = pm_get_data_in(LPC_ACPI_CMD);
+
+ /* Handle whatever this was. */
+ if (acpi_ap_to_ec(is_cmd, value, &result))
+ pm_put_data_out(LPC_ACPI_CMD, result);
+
+ /* Clear the busy bit */
+ pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_PROCESSING, 0);
+
+ /*
+ * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty
+ * Output Buffer Full condition on the kernel channel.
+ */
+ lpc_generate_sci();
+ }
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC_IN);
+}
+
+void pm2_ibf_interrupt(void)
+{
+ uint8_t value __attribute__((unused)) = 0;
+ uint8_t status;
+
+ status = pm_get_status(LPC_HOST_CMD);
+ /* IBE */
+ if (!(status & EC_LPC_STATUS_FROM_HOST)) {
+ task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+ return;
+ }
+
+ /* IBF and data port */
+ if (!(status & EC_LPC_STATUS_LAST_CMD)) {
+ /* R/C IBF*/
+ value = pm_get_data_in(LPC_HOST_CMD);
+ task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+ return;
+ }
+
+ /* Set the busy bit */
+ pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 1);
+
+ /*
+ * Read the command byte. This clears the FRMH bit in
+ * the status byte.
+ */
+ host_cmd_args.command = pm_get_data_in(LPC_HOST_CMD);
+
+ host_cmd_args.result = EC_RES_SUCCESS;
+ if (host_cmd_args.command != EC_COMMAND_PROTOCOL_3)
+ 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 *)host_cmd_memmap;
+ 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 *)host_cmd_memmap;
+ 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);
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+ 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);
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+}
+
+void pm3_ibf_interrupt(void)
+{
+ if (pm_get_status(LPC_HOST_PORT_80H) & EC_LPC_STATUS_FROM_HOST)
+ port_80_write(pm_get_data_in(LPC_HOST_PORT_80H));
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC3_IN);
+}
+
+void pm4_ibf_interrupt(void)
+{
+ task_clear_pending_irq(IT83XX_IRQ_PMC4_IN);
+}
+
+void pm5_ibf_interrupt(void)
+{
+ task_clear_pending_irq(IT83XX_IRQ_PMC5_IN);
+}
+
static void lpc_init(void)
{
+ /*
+ * DLM 52k~56k size select enable.
+ * For mapping LPC I/O cycle 800h ~ 9FFh to DLM 8D800 ~ 8D9FF.
+ */
+ IT83XX_GCTRL_MCCR2 |= 0x10;
+
IT83XX_GPIO_GCR = 0x06;
/* The register pair to access PNPCFG is 002Eh and 002Fh */
@@ -160,21 +530,141 @@ static void lpc_init(void)
*/
IT83XX_KBC_KBHICR |= 0x0C;
- /* Input Buffer Full Interrupt Enable */
- IT83XX_PMC_PM1CTL |= 0x01;
+ /* PM1 Input Buffer Full Interrupt Enable for 62h/66 port */
+ pm_set_ctrl(LPC_ACPI_CMD, PM_CTRL_IBFIE, 1);
+
+ /* PM2 Input Buffer Full Interrupt Enable for 200h/204 port */
+ pm_set_ctrl(LPC_HOST_CMD, PM_CTRL_IBFIE, 1);
memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE);
+ memset(lpc_host_args, 0, sizeof(*lpc_host_args));
- task_clear_pending_irq(IT83XX_IRQ_KBC_OUT);
+ /* Host LPC I/O cycle mapping to RAM */
+ /*
+ * bit[4], H2RAM through LPC IO cycle.
+ * bit[1], H2RAM window 1 enabled.
+ * bit[0], H2RAM window 0 enabled.
+ */
+ IT83XX_SMFI_HRAMWC |= 0x13;
+
+ /*
+ * bit[7:6]
+ * Host RAM Window[x] Read Protect Enable
+ * 00b: Disabled
+ * 01b: Lower half of RAM window protected
+ * 10b: Upper half of RAM window protected
+ * 11b: All protected
+ *
+ * bit[5:4]
+ * Host RAM Window[x] Write Protect Enable
+ * 00b: Disabled
+ * 01b: Lower half of RAM window protected
+ * 10b: Upper half of RAM window protected
+ * 11b: All protected
+ *
+ * bit[2:0]
+ * Host RAM Window 1 Size (HRAMW1S)
+ * 0h: 16 bytes
+ * 1h: 32 bytes
+ * 2h: 64 bytes
+ * 3h: 128 bytes
+ * 4h: 256 bytes
+ * 5h: 512 bytes
+ * 6h: 1024 bytes
+ * 7h: 2048 bytes
+ */
+
+ /* H2RAM Win 0 Base Address 800h allow r/w for host_cmd_memmap */
+ IT83XX_SMFI_HRAMW0BA = 0x80;
+ IT83XX_SMFI_HRAMW0AAS = 0x04;
+
+ /* H2RAM Win 1 Base Address 900h allow r for acpi_ec_memmap */
+ IT83XX_SMFI_HRAMW1BA = 0x90;
+ IT83XX_SMFI_HRAMW1AAS = 0x34;
+ /* 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;
+
+ /*
+ * bit[5], Dedicated interrupt
+ * INT3: PMC1 Output Buffer Empty Int
+ * INT25: PMC1 Input Buffer Full Int
+ * INT26: PMC2 Output Buffer Empty Int
+ * INT27: PMC2 Input Buffer Full Int
+ */
+ IT83XX_PMC_MBXCTRL |= 0x20;
+
+ /* PM3 Input Buffer Full Interrupt Enable for 80h port */
+ pm_set_ctrl(LPC_HOST_PORT_80H, PM_CTRL_IBFIE, 1);
+
+ gpio_enable_interrupt(GPIO_PCH_PLTRST_L);
+
+ task_clear_pending_irq(IT83XX_IRQ_KBC_OUT);
task_disable_irq(IT83XX_IRQ_KBC_OUT);
task_clear_pending_irq(IT83XX_IRQ_KBC_IN);
-
task_enable_irq(IT83XX_IRQ_KBC_IN);
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC_IN);
+ task_enable_irq(IT83XX_IRQ_PMC_IN);
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC2_IN);
+ task_enable_irq(IT83XX_IRQ_PMC2_IN);
+
+ task_clear_pending_irq(IT83XX_IRQ_PMC3_IN);
+ task_enable_irq(IT83XX_IRQ_PMC3_IN);
+
+ /* Sufficiently initialized */
+ init_done = 1;
+
+ /* Update host events now that we can copy them to memmap */
+ update_host_event_status();
}
/*
* 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);
+
+void lpcrst_interrupt(enum gpio_signal signal)
+{
+ if (lpc_get_pltrst_asserted())
+ /* Store port 80 reset event */
+ port_80_write(PORT_80_EVENT_RESET);
+
+ CPRINTS("LPC RESET# %sasserted",
+ lpc_get_pltrst_asserted() ? "" : "de");
+}
+
+static void lpc_resume(void)
+{
+ /* Mask all host events until the host unmasks them itself. */
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SMI, 0);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, 0);
+ lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, 0);
+
+ /* Store port 80 event so we know where resume happened */
+ port_80_write(PORT_80_EVENT_RESUME);
+}
+DECLARE_HOOK(HOOK_CHIPSET_RESUME, lpc_resume, HOOK_PRIO_DEFAULT);
+
+/* Get protocol information */
+static int 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 = (1 << 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));
diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h
index 9e5d115f81..cf9b227711 100644
--- a/chip/it83xx/registers.h
+++ b/chip/it83xx/registers.h
@@ -295,6 +295,9 @@
#define CPU_INT_GROUP_5 254
#define IT83XX_CPU_INT_IRQ_254 5
+#define CPU_INT_GROUP_4 252
+#define IT83XX_CPU_INT_IRQ_252 4
+
#define CPU_INT(irq) CONCAT2(IT83XX_CPU_INT_IRQ_, irq)
/* --- INTC --- */
@@ -571,6 +574,7 @@ enum clock_gate_offsets {
#define IT83XX_GCTRL_WNCKR REG8(IT83XX_GCTRL_BASE+0x0B)
#define IT83XX_GCTRL_RSTS REG8(IT83XX_GCTRL_BASE+0x06)
#define IT83XX_GCTRL_BADRSEL REG8(IT83XX_GCTRL_BASE+0x0A)
+#define IT83XX_GCTRL_MCCR2 REG8(IT83XX_GCTRL_BASE+0x44)
/* --- Pulse Width Modulation (PWM) --- */
#define IT83XX_PWM_BASE 0x00F01800
@@ -731,6 +735,12 @@ enum clock_gate_offsets {
#define IT83XX_PMC_MBXEC_13 REG8(IT83XX_PMC_BASE+0xFD)
#define IT83XX_PMC_MBXEC_14 REG8(IT83XX_PMC_BASE+0xFE)
#define IT83XX_PMC_MBXEC_15 REG8(IT83XX_PMC_BASE+0xFF)
+#define IT83XX_PMC_PMSTS(ch) REG8(IT83XX_PMC_BASE + 0x00 + (ch << 4))
+#define IT83XX_PMC_PMDO(ch) REG8(IT83XX_PMC_BASE + 0x01 + (ch << 4))
+#define IT83XX_PMC_PMDI(ch) \
+REG8(IT83XX_PMC_BASE + (ch > LPC_PM2 ? 2 : 4) + (ch << 4))
+#define IT83XX_PMC_PMCTL(ch) \
+REG8(IT83XX_PMC_BASE + (ch > LPC_PM2 ? 3 : 6) + (ch << 4))
/* Keyboard Matrix Scan control (KBS) */
#define IT83XX_KBS_BASE 0x00F01D00
@@ -774,9 +784,24 @@ enum clock_gate_offsets {
#define IT83XX_KBS_SDC3R REG8(IT83XX_KBS_BASE+0x24)
#define IT83XX_KBS_SDSR REG8(IT83XX_KBS_BASE+0x25)
+/* Shared Memory Flash Interface Bridge (SMFI) */
+#define IT83XX_SMFI_BASE 0x00F01000
+
+#define IT83XX_SMFI_HRAMWC REG8(IT83XX_SMFI_BASE+0x5A)
+#define IT83XX_SMFI_HRAMW0BA REG8(IT83XX_SMFI_BASE+0x5B)
+#define IT83XX_SMFI_HRAMW1BA REG8(IT83XX_SMFI_BASE+0x5C)
+#define IT83XX_SMFI_HRAMW0AAS REG8(IT83XX_SMFI_BASE+0x5D)
+#define IT83XX_SMFI_HRAMW1AAS REG8(IT83XX_SMFI_BASE+0x5E)
+#define IT83XX_SMFI_HRAMW2BA REG8(IT83XX_SMFI_BASE+0x76)
+#define IT83XX_SMFI_HRAMW3BA REG8(IT83XX_SMFI_BASE+0x77)
+#define IT83XX_SMFI_HRAMW2AAS REG8(IT83XX_SMFI_BASE+0x78)
+#define IT83XX_SMFI_HRAMW3AAS REG8(IT83XX_SMFI_BASE+0x79)
+#define IT83XX_SMFI_H2RAMECSIE REG8(IT83XX_SMFI_BASE+0x7A)
+#define IT83XX_SMFI_H2RAMECSA REG8(IT83XX_SMFI_BASE+0x7B)
+#define IT83XX_SMFI_H2RAMHSS REG8(IT83XX_SMFI_BASE+0x7C)
+
/* --- MISC (not implemented yet) --- */
-#define IT83XX_SMFI_BASE 0x00F01000
#define IT83XX_PS2_BASE 0x00F01700
#define IT83XX_DAC_BASE 0x00F01A00
#define IT83XX_WUC_BASE 0x00F01B00
diff --git a/core/nds32/build.mk b/core/nds32/build.mk
index 810d5b8dd3..df89e3c8ac 100644
--- a/core/nds32/build.mk
+++ b/core/nds32/build.mk
@@ -10,6 +10,6 @@
CROSS_COMPILE?=nds32le-cros-elf-
# CPU specific compilation flags
-CFLAGS_CPU=-march=v3m -Os
+CFLAGS_CPU+=-march=v3m -Os
core-y=cpu.o init.o panic.o task.o switch.o
diff --git a/core/nds32/ec.lds.S b/core/nds32/ec.lds.S
index 8a8927f11a..57cf6512d3 100644
--- a/core/nds32/ec.lds.S
+++ b/core/nds32/ec.lds.S
@@ -4,10 +4,10 @@
*/
#include "config.h"
-#define FW_OFF_(section) CONFIG_FW_##section##_OFF
+#define FW_OFF_(section) CONFIG_##section##_MEM_OFF
#define FW_OFF(section) (CONFIG_FLASH_BASE + FW_OFF_(section))
-#define FW_SIZE_(section) CONFIG_FW_##section##_SIZE
+#define FW_SIZE_(section) CONFIG_##section##_SIZE
#define FW_SIZE(section) FW_SIZE_(section)
@@ -18,6 +18,9 @@ MEMORY
{
FLASH (rx) : ORIGIN = FW_OFF(SECTION), LENGTH = FW_SIZE(SECTION)
IRAM (rw) : ORIGIN = CONFIG_RAM_BASE, LENGTH = CONFIG_RAM_SIZE
+#ifdef CONFIG_LPC
+ H2RAM (rw) : ORIGIN = CONFIG_H2RAM_BASE, LENGTH = CONFIG_H2RAM_SIZE
+#endif
}
SECTIONS
{
@@ -207,6 +210,16 @@ SECTIONS
BYTE(0xea);
/* NOTHING MAY GO IN FLASH AFTER THIS! */
} >FLASH
+
+#ifdef CONFIG_LPC
+ .h2ram (NOLOAD) : {
+ . += CONFIG_H2RAM_HOST_LPC_IO_BASE;
+ *(.h2ram.pool.hostcmd)
+ . = ALIGN(256);
+ *(.h2ram.pool.acpiec)
+ } > H2RAM
+#endif
+
#if !(defined(SECTION_IS_RO) && defined(CONFIG_FLASH))
/DISCARD/ : {
*(.google)