void lpc_pmc_ibf_interrupt(void){ /* Channel-1 for ACPI usage*/ /* Channel-2 for Host Command usage , so the argument data had been * put on the share memory firstly*/ if (NPCX_HIPMST(PM_CHAN_1) & 0x02) handle_acpi_write((NPCX_HIPMST(PM_CHAN_1)&0x08) ? 1 : 0); else if (NPCX_HIPMST(PM_CHAN_2)&0x02) handle_host_write((NPCX_HIPMST(PM_CHAN_2)&0x08) ? 1 : 0); }
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. This sets the TOH status bit. */ NPCX_HIPMDO(PMC_HOST_CMD) = pkt->driver_result; /* Clear processing flag */ CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2); }
/** * Update the host event status. * * Sends a pulse if masked event status becomes non-zero: * - SMI pulse via EC_SMI_L GPIO * - SCI pulse via LPC0SCI */ static void update_host_event_status(void) { int need_sci = 0; int need_smi = 0; if (!init_done) return; /* Disable LPC interrupt while updating status register */ lpc_task_disable_irq(); if (host_events & event_mask[LPC_HOST_EVENT_SMI]) { /* Only generate SMI for first event */ if (!(NPCX_HIPMST(PMC_ACPI) & NPCX_HIPMST_ST2)) need_smi = 1; SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST2); } else CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST2); if (host_events & event_mask[LPC_HOST_EVENT_SCI]) { /* Generate SCI for every event */ need_sci = 1; SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST1); } else CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_ST1); /* Copy host events to mapped memory */ *(uint32_t *)host_get_memmap(EC_MEMMAP_HOST_EVENTS) = host_events; lpc_task_enable_irq(); /* 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(); }
/** * Handle write to ACPI I/O port * * @param is_cmd Is write command (is_cmd=1) or data (is_cmd=0) */ static void handle_acpi_write(int is_cmd) { uint8_t value, result; /* Set processing flag before reading command byte */ SET_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_F0); /* Read command/data; this clears the FRMH status bit. */ value = NPCX_HIPMDI(PMC_ACPI); /* Handle whatever this was. */ if (acpi_ap_to_ec(is_cmd, value, &result)) NPCX_HIPMDO(PMC_ACPI) = result; /* Clear processing flag */ CLEAR_BIT(NPCX_HIPMST(PMC_ACPI), NPCX_HIPMST_F0); /* * ACPI 5.0-12.6.1: Generate SCI for Input Buffer Empty / Output Buffer * Full condition on the kernel channel. */ 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 param buffer */ if (size > EC_PROTO2_MAX_PARAM_SIZE) args->result = EC_RES_INVALID_RESPONSE; /* Write result to the data byte. This sets the TOH status bit. */ NPCX_HIPMDO(PMC_HOST_CMD) = args->result; /* Clear processing flag */ CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2); }
/** * Handle write to host command I/O ports. * * @param is_cmd Is write command (1) or data (0)? */ static void handle_host_write(int is_cmd) { /* Set processing flag before reading command byte */ SET_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2); /* * Read the command byte. This clears the FRMH bit in * the status byte. */ host_cmd_args.command = NPCX_HIPMDI(PMC_HOST_CMD); host_cmd_args.result = EC_RES_SUCCESS; host_cmd_args.send_response = lpc_send_response; host_cmd_flags = lpc_host_args->flags; /* See if we have an old or new style command */ if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) { lpc_packet.send_response = lpc_send_response_packet; lpc_packet.request = (const void *)shm_mem_host_cmd; 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 *)shm_mem_host_cmd; 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 if (host_cmd_flags & EC_HOST_ARGS_FLAG_FROM_HOST) { /* Version 2 (link) style command */ int size = lpc_host_args->data_size; int csum, i; /* Clear processing flag */ CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2); host_cmd_args.version = lpc_host_args->command_version; host_cmd_args.params = params_copy; host_cmd_args.params_size = size; host_cmd_args.response = cmd_params; host_cmd_args.response_max = EC_PROTO2_MAX_PARAM_SIZE; host_cmd_args.response_size = 0; /* Verify params size */ if (size > EC_PROTO2_MAX_PARAM_SIZE) { host_cmd_args.result = EC_RES_INVALID_PARAM; } else { const uint8_t *src = cmd_params; uint8_t *copy = params_copy; /* * Verify checksum and copy params out of LPC space. * This ensures the data acted on by the host command * handler can't be changed by host writes after the * checksum is verified. */ csum = host_cmd_args.command + host_cmd_flags + host_cmd_args.version + host_cmd_args.params_size; for (i = 0; i < size; i++) { csum += *src; *(copy++) = *(src++); } if ((uint8_t)csum != lpc_host_args->checksum) host_cmd_args.result = EC_RES_INVALID_CHECKSUM; } } else { /* Old style command, now unsupported */ host_cmd_args.result = EC_RES_INVALID_COMMAND; /* Clear processing flag */ CLEAR_BIT(NPCX_HIPMST(PMC_HOST_CMD), 2); } /* Hand off to host command handler */ host_command_received(&host_cmd_args); }
void lpc_clear_acpi_status_mask(uint8_t mask) { NPCX_HIPMST(PMC_ACPI) &= ~mask; }
void lpc_set_acpi_status_mask(uint8_t mask) { NPCX_HIPMST(PMC_ACPI) |= mask; }