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 @@ -58,6 +58,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 */ 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)); + + /* 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)