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); }
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); }
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); }
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 lpc_clear_acpi_status_mask(uint8_t mask) { pm_set_status(LPC_ACPI_CMD, mask, 0); }
void lpc_set_acpi_status_mask(uint8_t mask) { pm_set_status(LPC_ACPI_CMD, mask, 1); }
static void lpc_init(void) { enum ec2i_message ec2i_r; /* SPI slave interface is disabled */ IT83XX_GCTRL_SSCR = 0; /* * DLM 52k~56k size select enable. * For mapping LPC I/O cycle 800h ~ 9FFh to DLM 8D800 ~ 8D9FF. */ IT83XX_GCTRL_MCCR2 |= 0x10; /* The register pair to access PNPCFG is 004Eh and 004Fh */ IT83XX_GCTRL_BADRSEL = 0x01; /* Disable KBC IRQ */ IT83XX_KBC_KBIRQR = 0x00; /* * bit2, Output Buffer Empty CPU Interrupt Enable. * bit3, Input Buffer Full CPU Interrupt Enable. * bit5, IBF/OBF EC clear mode. * 0b: IBF cleared if EC read data register, EC reset, or host reset. * OBF cleared if host read data register, or EC reset. * 1b: IBF cleared if EC write-1 to bit7 at related registers, * EC reset, or host reset. * OBF cleared if host read data register, EC write-1 to bit6 at * related registers, or EC reset. */ IT83XX_KBC_KBHICR |= 0x2C; /* 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); p80l_index = P80L_P80LC; if (ec2i_write(HOST_INDEX_LDN, LDN_RTCT) == EC2I_WRITE_SUCCESS) { /* get P80L current index */ ec2i_r = ec2i_read(HOST_INDEX_DSLDC6); /* read OK */ if ((ec2i_r & 0xff00) == EC2I_READ_SUCCESS) p80l_index = ec2i_r & P80L_BRAM_BANK1_SIZE_MASK; } /* * bit[7], enable P80L function. * bit[6], accept port 80h cycle. * bit[1-0], 10b: I2EC is read-only. */ IT83XX_GCTRL_SPCTRL1 |= 0xC2; 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); pm_set_status(LPC_ACPI_CMD, EC_LPC_STATUS_PROCESSING, 0); task_enable_irq(IT83XX_IRQ_PMC_IN); task_clear_pending_irq(IT83XX_IRQ_PMC2_IN); pm_set_status(LPC_HOST_CMD, EC_LPC_STATUS_PROCESSING, 0); task_enable_irq(IT83XX_IRQ_PMC2_IN); task_clear_pending_irq(IT83XX_IRQ_PMC3_IN); task_enable_irq(IT83XX_IRQ_PMC3_IN); /* Restore event masks if needed */ lpc_post_sysjump(); /* Sufficiently initialized */ init_done = 1; /* Update host events now that we can copy them to memmap */ update_host_event_status(); }