static int command_powerbtn(int argc, char **argv) { int ms = 200; /* Press duration in ms */ char *e; if (argc > 1) { ms = strtoi(argv[1], &e, 0); if (*e) return EC_ERROR_PARAM1; } ccprintf("Simulating %d ms power button press.\n", ms); simulate_power_pressed = 1; power_button_is_stable = 0; hook_call_deferred(power_button_change_deferred, 0); msleep(ms); ccprintf("Simulating power button release.\n"); simulate_power_pressed = 0; power_button_is_stable = 0; hook_call_deferred(power_button_change_deferred, 0); return EC_SUCCESS; }
void usb_stream_reset(struct usb_stream_config const *config) { config->out_desc->flags = DOEPDMA_RXBYTES(config->tx_size) | DOEPDMA_LAST | DOEPDMA_BS_HOST_RDY | DOEPDMA_IOC; config->out_desc->addr = config->rx_ram; GR_USB_DOEPDMA(config->endpoint) = (uint32_t)config->out_desc; config->in_desc->flags = DIEPDMA_LAST | DIEPDMA_BS_HOST_BSY | DIEPDMA_IOC; config->in_desc->addr = config->tx_ram; GR_USB_DIEPDMA(config->endpoint) = (uint32_t)config->in_desc; GR_USB_DOEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_BULK | DXEPCTL_CNAK | DXEPCTL_EPENA; GR_USB_DIEPCTL(config->endpoint) = DXEPCTL_MPS(64) | DXEPCTL_USBACTEP | DXEPCTL_EPTYPE_BULK | DXEPCTL_TXFNUM(config->endpoint); GR_USB_DAINTMSK |= DAINT_INEP(config->endpoint) | DAINT_OUTEP(config->endpoint); *config->is_reset = 1; /* Flush any queued data */ hook_call_deferred(config->deferred_tx, 0); hook_call_deferred(config->deferred_rx, 0); }
void hpd_event(enum gpio_signal signal) { timestamp_t now = get_time(); int level = gpio_get_level(signal); uint64_t cur_delta = now.val - hpd_prev_ts; /* store current time */ hpd_prev_ts = now.val; /* All previous hpd level events need to be re-triggered */ hook_call_deferred(hpd_lvl_deferred, -1); /* It's a glitch. Previous time moves but level is the same. */ if (cur_delta < HPD_USTREAM_DEBOUNCE_IRQ) return; if ((!hpd_prev_level && level) && (cur_delta < HPD_USTREAM_DEBOUNCE_LVL)) /* It's an irq */ hook_call_deferred(hpd_irq_deferred, 0); else if (cur_delta >= HPD_USTREAM_DEBOUNCE_LVL) hook_call_deferred(hpd_lvl_deferred, HPD_USTREAM_DEBOUNCE_LVL); hpd_prev_level = level; }
static void ep_reset(void) { epN_reset(USB_EP_CONSOLE); is_reset = 1; /* Flush any queued data */ hook_call_deferred(&tx_fifo_handler_data, 0); hook_call_deferred(&rx_fifo_handler_data, 0); usb_enable_rx(USB_MAX_PACKET_SIZE); }
static void usb_spi_written(struct consumer const *consumer, size_t count) { struct usb_spi_config const *config = DOWNCAST(consumer, struct usb_spi_config, consumer); hook_call_deferred(config->deferred, 0); }
static int svdm_dp_attention(int port, uint32_t *payload) { int cur_lvl; int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); enum gpio_signal hpd = PORT_TO_HPD(port); cur_lvl = gpio_get_level(hpd); dp_status[port] = payload[1]; /* Its initial DP status message prior to config */ if (!(dp_flags[port] & DP_FLAGS_DP_ON)) { if (lvl) dp_flags[port] |= DP_FLAGS_HPD_HI_PENDING; return 1; } if (irq & cur_lvl) { gpio_set_level(hpd, 0); hook_call_deferred(PORT_TO_HPD_IRQ_DEFERRED(port), HPD_DSTREAM_DEBOUNCE_IRQ); } else if (irq & !cur_lvl) { CPRINTF("ERR:HPD:IRQ&LOW\n"); return 0; /* nak */ } else { gpio_set_level(hpd, lvl); } /* ack */ return 1; }
/** * Do next chunk of hashing work, if any. */ static void vboot_hash_next_chunk(void) { int size; /* Handle abort */ if (want_abort) { in_progress = 0; vboot_hash_abort(); return; } /* Compute the next chunk of hash */ size = MIN(CHUNK_SIZE, data_size - curr_pos); SHA256_update(&ctx, (const uint8_t *)(CONFIG_FLASH_BASE + data_offset + curr_pos), size); curr_pos += size; if (curr_pos >= data_size) { /* Store the final hash */ hash = SHA256_final(&ctx); CPRINTS("hash done %.*h", SHA256_DIGEST_SIZE, hash); in_progress = 0; /* Handle receiving abort during finalize */ if (want_abort) vboot_hash_abort(); return; } /* If we're still here, more work to do; come back later */ hook_call_deferred(vboot_hash_next_chunk, WORK_INTERVAL_US); }
/* Initialize host settings by interrupt */ void lpc_lreset_pltrst_handler(void) { int pltrst_asserted; /* Clear pending bit of WUI */ SET_BIT(NPCX_WKPCL(MIWU_TABLE_0 , MIWU_GROUP_5), 7); /* Ignore PLTRST# from SOC if it is not valid */ if (chipset_pltrst_is_valid && !chipset_pltrst_is_valid()) return; pltrst_asserted = lpc_get_pltrst_asserted(); ccprintf("LPC RESET# %sasserted", pltrst_asserted ? "" : "de"); /* * Once LRESET is de-asserted (low -> high), we need to initialize lpc * settings once. If RSTCTL_LRESET_PLTRST_MODE is active, LPC registers * won't be reset by Host domain reset but Core domain does. */ if (!pltrst_asserted) host_register_init(); else { #ifdef CONFIG_CHIPSET_RESET_HOOK /* Notify HOOK_CHIPSET_RESET */ hook_call_deferred(&lpc_chipset_reset_data, MSEC); #endif } }
static int read_and_hash_chunk(int offset, int size) { char *buf; int rv; if (size == 0) return EC_SUCCESS; rv = shared_mem_acquire(size, &buf); if (rv == EC_ERROR_BUSY) { /* Couldn't update hash right now; try again later */ hook_call_deferred(vboot_hash_next_chunk, WORK_INTERVAL_US); return rv; } else if (rv != EC_SUCCESS) { vboot_hash_abort(); return rv; } rv = flash_read(offset, size, buf); if (rv == EC_SUCCESS) SHA256_update(&ctx, (const uint8_t *)buf, size); else vboot_hash_abort(); shared_mem_release(buf); return rv; }
/** * Start computing a hash of <size> bytes of data at flash offset <offset>. * * If nonce_size is non-zero, prefixes the <nonce> onto the data to be hashed. * Returns non-zero if error. */ static int vboot_hash_start(uint32_t offset, uint32_t size, const uint8_t *nonce, int nonce_size) { /* Fail if hash computation is already in progress */ if (in_progress) return EC_ERROR_BUSY; /* * Make sure request fits inside flash. That is, you can't use this * command to peek at other memory. */ if (offset > CONFIG_FLASH_SIZE || size > CONFIG_FLASH_SIZE || offset + size > CONFIG_FLASH_SIZE || nonce_size < 0) { return EC_ERROR_INVAL; } /* Save new hash request */ data_offset = offset; data_size = size; curr_pos = 0; hash = NULL; want_abort = 0; in_progress = 1; /* Restart the hash computation */ CPRINTS("hash start 0x%08x 0x%08x", offset, size); SHA256_init(&ctx); if (nonce_size) SHA256_update(&ctx, nonce, nonce_size); hook_call_deferred(vboot_hash_next_chunk, 0); return EC_SUCCESS; }
void usb_spi_board_disable(struct usb_spi_config const *config) { CPRINTS("usb_spi disable"); spi_enable(CONFIG_SPI_FLASH_PORT, 0); disable_ec_ap_spi(); /* Disconnect SPI peripheral to tri-state pads */ /* Disable internal pull up */ GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 0); /* TODO: Implement way to get the gpio */ ASSERT(GREAD(PINMUX, GPIO0_GPIO7_SEL) == GC_PINMUX_DIOA4_SEL); ASSERT(GREAD(PINMUX, GPIO0_GPIO8_SEL) == GC_PINMUX_DIOA8_SEL); ASSERT(GREAD(PINMUX, GPIO0_GPIO9_SEL) == GC_PINMUX_DIOA14_SEL); /* Set SPI MOSI, CLK, and CS_L as inputs */ GWRITE(PINMUX, DIOA4_SEL, GC_PINMUX_GPIO0_GPIO7_SEL); GWRITE(PINMUX, DIOA8_SEL, GC_PINMUX_GPIO0_GPIO8_SEL); GWRITE(PINMUX, DIOA14_SEL, GC_PINMUX_GPIO0_GPIO9_SEL); /* * TODO(crosbug.com/p/52366): remove once sys_rst just resets the TPM * instead of cr50. * Resetting the EC and AP cause sys_rst to be asserted currently that * will cause cr50 to do a soft reset. Delay the end of the transaction * to prevent cr50 from resetting during a series of usb_spi calls. */ hook_call_deferred(&update_finished_data, 1 * SECOND); }
static void usb_read(struct producer const *producer, size_t count) { struct usb_stream_config const *config = DOWNCAST(producer, struct usb_stream_config, producer); hook_call_deferred(config->deferred_rx, 0); }
static void siglog_deferred(void) { const struct gpio_info *g = gpio_list; unsigned int i; timestamp_t tdiff = {.val = 0}; /* Disable interrupts for input signals while we print stuff.*/ for (i = 0; i < POWER_SIGNAL_COUNT; i++) gpio_disable_interrupt(power_signal_list[i].gpio); CPRINTF("%d signal changes:\n", siglog_entries); for (i = 0; i < siglog_entries; i++) { if (i) tdiff.val = siglog[i].time.val - siglog[i-1].time.val; CPRINTF(" %.6ld +%.6ld %s => %d\n", siglog[i].time.val, tdiff.val, g[siglog[i].signal].name, siglog[i].level); } if (siglog_truncated) CPRINTF(" SIGNAL LOG TRUNCATED...\n"); siglog_entries = siglog_truncated = 0; /* Okay, turn 'em on again. */ for (i = 0; i < POWER_SIGNAL_COUNT; i++) gpio_enable_interrupt(power_signal_list[i].gpio); } DECLARE_DEFERRED(siglog_deferred); static void siglog_add(enum gpio_signal signal) { if (siglog_entries >= MAX_SIGLOG_ENTRIES) { siglog_truncated = 1; return; } siglog[siglog_entries].time = get_time(); siglog[siglog_entries].signal = signal; siglog[siglog_entries].level = gpio_get_level(signal); siglog_entries++; hook_call_deferred(siglog_deferred, SECOND); } #define SIGLOG(S) siglog_add(S) #else #define SIGLOG(S) #endif /* CONFIG_BRINGUP */ void power_signal_interrupt(enum gpio_signal signal) { SIGLOG(signal); /* Shadow signals and compare with our desired signal state. */ power_update_signals(); /* Wake up the task */ task_wake(TASK_ID_CHIPSET); }
void usb_spi_board_enable(struct usb_spi_config const *config) { hook_call_deferred(&update_finished_data, -1); update_in_progress = 1; disable_ec_ap_spi(); if (config->state->enabled_host == USB_SPI_EC) enable_ec_spi(); else if (config->state->enabled_host == USB_SPI_AP) enable_ap_spi(); else { CPRINTS("DEVICE NOT SUPPORTED"); return; } /* Connect DIO A4, A8, and A14 to the SPI peripheral */ GWRITE(PINMUX, DIOA4_SEL, 0); /* SPI_MOSI */ GWRITE(PINMUX, DIOA8_SEL, 0); /* SPI_CS_L */ GWRITE(PINMUX, DIOA14_SEL, 0); /* SPI_CLK */ /* Set SPI_CS to be an internal pull up */ GWRITE_FIELD(PINMUX, DIOA14_CTL, PU, 1); CPRINTS("usb_spi enable %s", gpio_get_level(GPIO_AP_FLASH_SELECT) ? "AP" : "EC"); spi_enable(CONFIG_SPI_FLASH_PORT, 1); }
/** * Handle the hang detect timer expiring. */ static void hang_detect_deferred(void) { /* If we're no longer active, nothing to do */ if (!active) return; /* If we're rebooting the AP, stop hang detection */ if (timeout_will_reboot) { CPRINTS("hang detect triggering warm reboot"); host_set_single_event(EC_HOST_EVENT_HANG_REBOOT); chipset_reset(0); active = 0; return; } /* Otherwise, we're starting with the host event */ CPRINTS("hang detect sending host event"); host_set_single_event(EC_HOST_EVENT_HANG_DETECT); /* If we're also rebooting, defer for the remaining delay */ if (hdparams.warm_reboot_timeout_msec) { CPRINTS("hang detect continuing (for reboot)"); timeout_will_reboot = 1; hook_call_deferred(hang_detect_deferred, (hdparams.warm_reboot_timeout_msec - hdparams.host_event_timeout_msec) * MSEC); } else { /* Not rebooting, so go back to idle */ active = 0; } }
/* Rx/OUT interrupt handler */ void usb_stream_rx(struct usb_stream_config const *config) { /* Wake up the Rx FIFO handler */ hook_call_deferred(config->deferred_rx, 0); GR_USB_DOEPINT(config->endpoint) = 0xffffffff; }
static int svdm_dp_attention(int port, uint32_t *payload) { int cur_lvl; int lvl = PD_VDO_DPSTS_HPD_LVL(payload[1]); int irq = PD_VDO_DPSTS_HPD_IRQ(payload[1]); cur_lvl = gpio_get_level(GPIO_USBC_DP_HPD); dp_status = payload[1]; /* Its initial DP status message prior to config */ if (!(dp_flags & DP_FLAGS_DP_ON)) { if (lvl) dp_flags |= DP_FLAGS_HPD_HI_PENDING; return 1; } if (irq & cur_lvl) { gpio_set_level(GPIO_USBC_DP_HPD, 0); hook_call_deferred(&hpd_irq_deferred_data, HPD_DSTREAM_DEBOUNCE_IRQ); } else if (irq & !cur_lvl) { CPRINTF("ERR:HPD:IRQ&LOW\n"); return 0; /* nak */ } else { gpio_set_level(GPIO_USBC_DP_HPD, lvl); } /* ack */ return 1; }
/* Called on AP S5 -> S3 transition */ static void board_chipset_startup(void) { /* Enable USB-A port. */ gpio_set_level(GPIO_USB1_ENABLE, 1); hook_call_deferred(&enable_input_devices_data, 0); }
/** * Select an 'override port', a port which is always the preferred charge port. * Returns EC_SUCCESS on success, ec_error_list status on failure. * * @param port Charge port to select as override, or * OVERRIDE_OFF to select no override port, * or OVERRIDE_DONT_CHARGE to specifc that no * charge port should be selected. */ int charge_manager_set_override(int port) { int retval = EC_SUCCESS; ASSERT(port >= OVERRIDE_DONT_CHARGE && port < CONFIG_USB_PD_PORT_COUNT); CPRINTS("Charge Override: %d", port); /* Supersede any pending delayed overrides. */ if (delayed_override_port != OVERRIDE_OFF) { if (delayed_override_port != port) charge_manager_cleanup_override_port( delayed_override_port); delayed_override_port = OVERRIDE_OFF; hook_call_deferred( charge_override_timeout, -1); } /* Set the override port if it's a sink. */ if (port < 0 || pd_get_role(port) == PD_ROLE_SINK) { if (override_port != port) { charge_manager_cleanup_override_port(override_port); override_port = port; if (charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } } /* * If the attached device is capable of being a sink, request a * power swap and set the delayed override for swap completion. */ else if (pd_get_role(port) != PD_ROLE_SINK && dualrole_capability[port] == CAP_DUALROLE) { delayed_override_deadline.val = get_time().val + POWER_SWAP_TIMEOUT; delayed_override_port = port; hook_call_deferred( charge_override_timeout, POWER_SWAP_TIMEOUT); pd_request_power_swap(port); /* Can't charge from requested port -- return error. */ } else retval = EC_ERROR_INVAL; return retval; }
/* Tx/IN interrupt handler */ static void con_ep_tx(void) { /* Wake up the Tx FIFO handler */ hook_call_deferred(&tx_fifo_handler_data, 0); /* clear the Tx/IN interrupts */ GR_USB_DIEPINT(USB_EP_CONSOLE) = 0xffffffff; }
void backlight_interrupt(enum gpio_signal signal) { /* * PCH indicates it is turning on backlight so we should * attempt to put the backlight controller into PWM mode. */ hook_call_deferred(&lp8555_enable_pwm_mode_data, 0); }
/* Rx/OUT interrupt handler */ static void con_ep_rx(void) { /* Wake up the Rx FIFO handler */ hook_call_deferred(rx_fifo_handler, 0); /* clear the RX/OUT interrupts */ GR_USB_DOEPINT(USB_EP_BLOB) = 0xffffffff; }
/* Tx/IN interrupt handler */ void usb_stream_tx(struct usb_stream_config const *config) { /* Wake up the Tx FIFO handler */ hook_call_deferred(config->deferred_tx, 0); /* clear the Tx/IN interrupts */ GR_USB_DIEPINT(config->endpoint) = 0xffffffff; }
/** * Select an 'override port', a port which is always the preferred charge port. * Returns EC_SUCCESS on success, ec_error_list status on failure. * * @param port Charge port to select as override, or * OVERRIDE_OFF to select no override port, * or OVERRIDE_DONT_CHARGE to specifc that no * charge port should be selected. */ int charge_manager_set_override(int port) { int retval = EC_SUCCESS; ASSERT(port >= OVERRIDE_DONT_CHARGE && port < CONFIG_USB_PD_PORT_COUNT); CPRINTS("Charge Override: %d", port); /* * If attempting to change the override port, then return * error. Since we may be in the middle of a power swap on * the original override port, it's too complicated to * guarantee that the original override port is switched back * to source. */ if (delayed_override_port != OVERRIDE_OFF) return EC_ERROR_BUSY; /* Set the override port if it's a sink. */ if (port < 0 || pd_get_role(port) == PD_ROLE_SINK) { if (override_port != port) { override_port = port; if (charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } } /* * If the attached device is capable of being a sink, request a * power swap and set the delayed override for swap completion. */ else if (pd_get_role(port) != PD_ROLE_SINK && dualrole_capability[port] == CAP_DUALROLE) { delayed_override_deadline.val = get_time().val + POWER_SWAP_TIMEOUT; delayed_override_port = port; hook_call_deferred( charge_override_timeout, POWER_SWAP_TIMEOUT); pd_request_power_swap(port); /* Can't charge from requested port -- return error. */ } else retval = EC_ERROR_INVAL; return retval; }
/* Called on AP S3 -> S5 transition */ static void board_chipset_shutdown(void) { /* Disable USB-A port. */ gpio_set_level(GPIO_USB1_ENABLE, 0); hook_call_deferred(&enable_input_devices_data, 0); /* FIXME(dhendrix): Drive USB_PD_RST_ODL low to prevent leakage? (see comment in schematic) */ }
static void inductive_charging_lid_update(void) { /* * When the lid close signal changes, the coils might still be * unaligned. Delay here to give the coils time to align before * we try to clear CHARGE_DONE. */ hook_call_deferred(inductive_charging_deferred_update, 5 * SECOND); }
/** * Update backlight state. */ static void update_backlight(void) { /* * Enable backlight if lid is open; this is AND'd with the request from * the AP in hardware. */ gpio_set_level(GPIO_ENABLE_BACKLIGHT, lid_is_open()); if (lid_is_open()) hook_call_deferred(&lp8555_enable_pwm_mode_data, 0); }
/** * Update charge ceiling for a given port. The ceiling can be set independently * for several requestors, and the min. ceil will be enforced. * * @param port Charge port to update. * @param requestor Charge ceiling requestor. * @param ceil Charge ceiling (mA). */ void charge_manager_set_ceil(int port, enum ceil_requestor requestor, int ceil) { ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT && requestor >= 0 && requestor < CEIL_REQUESTOR_COUNT); if (charge_ceil[port][requestor] != ceil) { charge_ceil[port][requestor] = ceil; if (port == charge_port && charge_manager_is_seeded()) hook_call_deferred(charge_manager_refresh, 0); } }
void power_signal_interrupt_S0(enum gpio_signal signal) { if (gpio_get_level(GPIO_PCH_SLP_S0_L)) { slp_s0_debounce.required = 1; hook_call_deferred(slp_s0_assertion_deferred, 3 * MSEC); } else if (slp_s0_debounce.required == 0) { slp_s0_debounce.done = 0; slp_s0_assertion_deferred(); } }
/** * Start the hang detect timers. */ static void hang_detect_start(const char *why) { /* If already active, don't restart timer */ if (active) return; if (hdparams.host_event_timeout_msec) { CPRINTS("hang detect started on %s (for event)", why); timeout_will_reboot = 0; active = 1; hook_call_deferred(hang_detect_deferred, hdparams.host_event_timeout_msec * MSEC); } else if (hdparams.warm_reboot_timeout_msec) { CPRINTS("hang detect started on %s (for reboot)", why); timeout_will_reboot = 1; active = 1; hook_call_deferred(hang_detect_deferred, hdparams.warm_reboot_timeout_msec * MSEC); } }