Beispiel #1
0
enum cts_rc test_task_priority(void)
{
	uint32_t event;

	repeat_count = 2;

	task_wake(TASK_ID_A);
	task_wake(TASK_ID_C);

	event = task_wait_event(5 * SECOND);

	if (event != TASK_EVENT_WAKE) {
		CPRINTS("Woken up by unexpected event: 0x%08x", event);
		return CTS_RC_FAILURE;
	}

	if (wake_count[0] != repeat_count - 1
			|| wake_count[1] != repeat_count - 1) {
		CPRINTS("Unexpected counter values: %d %d %d",
			wake_count[0], wake_count[1], wake_count[2]);
		return CTS_RC_FAILURE;
	}

	/* TODO: Verify no tasks are ready, no events are pending. */
	if (*task_get_event_bitmap(TASK_ID_A)
			|| *task_get_event_bitmap(TASK_ID_B)
			|| *task_get_event_bitmap(TASK_ID_C)) {
		CPRINTS("Events are pending");
		return CTS_RC_FAILURE;
	}

	return CTS_RC_SUCCESS;
}
Beispiel #2
0
static int test_request(void)
{
	uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH);

	plug_in_source(0, 0);
	task_wake(PD_PORT_TO_TASK_ID(0));
	task_wait_event(2 * PD_T_CC_DEBOUNCE + 100 * MSEC);
	TEST_ASSERT(pd_port[0].polarity == 0);

	/* We're in SNK_DISCOVERY now. Let's send the source cap. */
	simulate_source_cap(0);
	task_wait_event(30 * MSEC);
	TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[0].msg_rx_id));

	/* Wait for the power request */
	task_wake(PD_PORT_TO_TASK_ID(0));
	task_wait_event(35 * MSEC); /* tSenderResponse: 24~30 ms */
	inc_rx_id(0);

	/* Process the request */
	TEST_ASSERT(pd_test_tx_msg_verify_sop(0));
	TEST_ASSERT(pd_test_tx_msg_verify_short(0,
			PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
				  pd_port[0].msg_tx_id, 1)));
	TEST_ASSERT(pd_test_tx_msg_verify_word(0, expected_rdo));
	TEST_ASSERT(pd_test_tx_msg_verify_crc(0));
	TEST_ASSERT(pd_test_tx_msg_verify_eop(0));
	inc_tx_id(0);

	/* We're done */
	unplug(0);
	return EC_SUCCESS;
}
Beispiel #3
0
static int test_sink(void)
{
	int i;

	plug_in_sink(1, 1);
	task_wake(PD_PORT_TO_TASK_ID(1));
	task_wait_event(250 * MSEC); /* tTypeCSinkWaitCap: 210~250 ms */
	TEST_ASSERT(pd_port[1].polarity == 1);

	/* The source cap should be sent */
	TEST_ASSERT(pd_test_tx_msg_verify_sop(1));
	TEST_ASSERT(pd_test_tx_msg_verify_short(1,
			PD_HEADER(PD_DATA_SOURCE_CAP, PD_ROLE_SOURCE,
				  PD_ROLE_DFP, pd_port[1].msg_tx_id,
				  pd_src_pdo_cnt)));
	for (i = 0; i < pd_src_pdo_cnt; ++i)
		TEST_ASSERT(pd_test_tx_msg_verify_word(1, pd_src_pdo[i]));
	TEST_ASSERT(pd_test_tx_msg_verify_crc(1));
	TEST_ASSERT(pd_test_tx_msg_verify_eop(1));

	/* Looks good. Ack the source cap. */
	simulate_goodcrc(1, PD_ROLE_SINK, pd_port[1].msg_tx_id);
	task_wake(PD_PORT_TO_TASK_ID(1));
	usleep(30 * MSEC);
	inc_tx_id(1);

	/* We're done */
	unplug(1);
	return EC_SUCCESS;
}
Beispiel #4
0
void tcpci_tcpc_alert(int port)
{
	int status;

	/* Read the Alert register from the TCPC */
	tcpm_alert_status(port, &status);

	/*
	 * Clear alert status for everything except RX_STATUS, which shouldn't
	 * be cleared until we have successfully retrieved message.
	 */
	if (status & ~TCPC_REG_ALERT_RX_STATUS)
		tcpc_write16(port, TCPC_REG_ALERT,
			     status & ~TCPC_REG_ALERT_RX_STATUS);

	if (status & TCPC_REG_ALERT_CC_STATUS) {
		/* CC status changed, wake task */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}
	if (status & TCPC_REG_ALERT_POWER_STATUS) {
		int reg = 0;

		tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, &reg);

		if (reg == TCPC_REG_POWER_STATUS_MASK_ALL) {
			/*
			 * If power status mask has been reset, then the TCPC
			 * has reset.
			 */
			task_set_event(PD_PORT_TO_TASK_ID(port),
				       PD_EVENT_TCPC_RESET, 0);
		} else {
			/* Read Power Status register */
			tcpci_tcpm_get_power_status(port, &reg);
			/* Update VBUS status */
			tcpc_vbus[port] = reg &
				TCPC_REG_POWER_STATUS_VBUS_PRES ? 1 : 0;
#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER)
			/* Update charge manager with new VBUS state */
			usb_charger_vbus_change(port, tcpc_vbus[port]);
			task_wake(PD_PORT_TO_TASK_ID(port));
#endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */
		}
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/* message received */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
	}
	if (status & TCPC_REG_ALERT_RX_HARD_RST) {
		/* hard reset received */
		pd_execute_hard_reset(port);
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
	if (status & TCPC_REG_ALERT_TX_COMPLETE) {
		/* transmit complete */
		pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ?
					   TCPC_TX_COMPLETE_SUCCESS :
					   TCPC_TX_COMPLETE_FAILED);
	}
}
Beispiel #5
0
/**
 * Handle debounced power button changing state.
 */
static void powerbtn_x86_changed(void)
{
	if (pwrbtn_state == PWRBTN_STATE_BOOT_KB_RESET ||
	    pwrbtn_state == PWRBTN_STATE_INIT_ON ||
	    pwrbtn_state == PWRBTN_STATE_LID_OPEN ||
	    pwrbtn_state == PWRBTN_STATE_WAS_OFF) {
		/* Ignore all power button changes during an initial pulse */
		CPRINTS("PB ignoring change");
		return;
	}

	if (power_button_is_pressed()) {
		/* Power button pressed */
		power_button_pressed(get_time().val);
	} else {
		/* Power button released */
		if (pwrbtn_state == PWRBTN_STATE_EAT_RELEASE) {
			/*
			 * Ignore the first power button release if we already
			 * told the PCH the power button was released.
			 */
			CPRINTS("PB ignoring release");
			pwrbtn_state = PWRBTN_STATE_IDLE;
			return;
		}

		power_button_released(get_time().val);
	}

	/* Wake the power button task */
	task_wake(TASK_ID_POWERBTN);
}
Beispiel #6
0
static int command_power(int argc, char **argv)
{
	int v;

	if (argc < 2) {
		enum power_state_t state;

		state = PSTATE_UNKNOWN;
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
			state = PSTATE_OFF;
		if (chipset_in_state(CHIPSET_STATE_SUSPEND))
			state = PSTATE_SUSPEND;
		if (chipset_in_state(CHIPSET_STATE_ON))
			state = PSTATE_ON;
		ccprintf("%s\n", state_name[state]);

		return EC_SUCCESS;
	}

	if (!parse_bool(argv[1], &v))
		return EC_ERROR_PARAM1;

	power_request = v ? POWER_REQ_ON : POWER_REQ_OFF;
	ccprintf("Requesting power %s\n", power_req_name[power_request]);
	task_wake(TASK_ID_CHIPSET);

	return EC_SUCCESS;
}
Beispiel #7
0
void vbus_wake_interrupt(enum gpio_signal signal)
{
	CPRINTF("VBUS %d\n", !gpio_get_level(signal));
	gpio_set_level(GPIO_USB_PD_VBUS_WAKE,
		       !gpio_get_level(GPIO_VBUS_WAKE_L));
	/*
	 * TODO(crosbug.com/p/41226):
	 *   rev1/rev2 boards don't have vbus input on ec. vbus_wake is a
	 *   logical OR of two vbus status. to workaround the power status
	 *   issue, wake up both pd tasks on vbus_wake interrupt. a proper
	 *   hardware fix will be in rev3.
	 *   enable TCPC POWER_STATUS ALERT1 can solve this issue too.
	 */
	task_wake(TASK_ID_PD_C0);
	task_wake(TASK_ID_PD_C1);
}
Beispiel #8
0
void kb_ibf_interrupt(void)
{
	if (lpc_keyboard_input_pending())
		keyboard_host_write(MEC1322_8042_H2E,
				    MEC1322_8042_STS & (1 << 3));
	task_wake(TASK_ID_KEYPROTO);
}
Beispiel #9
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);
}
Beispiel #10
0
static int command_display_accel_info(int argc, char **argv)
{
	char *e;
	int val;

	if (argc > 3)
		return EC_ERROR_PARAM_COUNT;

	/* First argument is on/off whether to display accel data. */
	if (argc > 1) {
		if (!parse_bool(argv[1], &val))
			return EC_ERROR_PARAM1;

		accel_disp = val;
	}

	/*
	 * Second arg changes the accel task time interval. Note accel
	 * sampling interval will be clobbered when chipset suspends or
	 * resumes.
	 */
	if (argc > 2) {
		val = strtoi(argv[2], &e, 0);
		if (*e)
			return EC_ERROR_PARAM2;

		accel_interval = val * MSEC;
		task_wake(TASK_ID_MOTIONSENSE);

	}

	return EC_SUCCESS;
}
Beispiel #11
0
static int verify_variable_not_set(int *var)
{
	*var = 0;
	task_wake(TASK_ID_KEYSCAN);
	msleep(NO_KEYDOWN_DELAY_MS);
	return *var ? EC_ERROR_UNKNOWN : EC_SUCCESS;
}
Beispiel #12
0
static int expect_no_keychange(void)
{
	int old_count = fifo_add_count;
	task_wake(TASK_ID_KEYSCAN);
	msleep(NO_KEYDOWN_DELAY_MS);
	return (fifo_add_count == old_count) ? EC_SUCCESS : EC_ERROR_UNKNOWN;
}
Beispiel #13
0
void tcpc_alert(int port)
{
	int status;

	/* Read the Alert register from the TCPC */
	tcpm_alert_status(port, &status);

	/*
	 * Clear alert status for everything except RX_STATUS, which shouldn't
	 * be cleared until we have successfully retrieved message.
	 */
	if (status & ~TCPC_REG_ALERT_RX_STATUS)
		i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port),
			    TCPC_REG_ALERT, status & ~TCPC_REG_ALERT_RX_STATUS);

	if (status & TCPC_REG_ALERT_CC_STATUS) {
		/* CC status changed, wake task */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
	}
	if (status & TCPC_REG_ALERT_RX_STATUS) {
		/* message received */
		task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0);
	}
	if (status & TCPC_REG_ALERT_RX_HARD_RST) {
		/* hard reset received */
		pd_execute_hard_reset(port);
		task_wake(PD_PORT_TO_TASK_ID(port));
	}
	if (status & TCPC_REG_ALERT_TX_COMPLETE) {
		/* transmit complete */
		pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ?
					   TCPC_TX_COMPLETE_SUCCESS :
					   TCPC_TX_COMPLETE_FAILED);
	}
}
static void wake_pmu_task_if_necessary(void)
{
	if (has_pending_event) {
		has_pending_event = 0;
		task_wake(TASK_ID_CHARGER);
	}
}
Beispiel #15
0
/*---------------------------------------------------------------------------*/
void     kbd_isr (u8 key_press)
{
    /* If the Keypress is valid, give the Semaphore */
    if (kbd_char_get (key_press, &key) == GOOD)
       task_wake (task_id) ;

} /* End of function kbd_isr() */
Beispiel #16
0
static void unplug(int port)
{
	pd_port[port].has_vbus = 0;
	pd_port[port].partner_role = -1;
	task_wake(PD_PORT_TO_TASK_ID(port));
	usleep(30 * MSEC);
}
Beispiel #17
0
/*
 * motion_sense_set_accel_interval
 *
 * Set the wake up interval for the motion sense thread.
 * It is set to the highest frequency one of the sensors need to be polled at.
 *
 * Note: Not static to be tested.
 */
int motion_sense_set_accel_interval(void)
{
	int i, sensor_ec_rate, ec_rate, wake_up = 0;
	struct motion_sensor_t *sensor;
	for (i = 0, ec_rate = 0; i < motion_sensor_count; ++i) {
		sensor = &motion_sensors[i];
		/*
		 * If the sensor is sleeping, no need to check it periodicaly.
		 */
		if ((sensor->state != SENSOR_INITIALIZED) ||
		    (sensor->drv->get_data_rate(sensor) == 0))
			continue;

		sensor_ec_rate = motion_sense_ec_rate(sensor);
		if ((ec_rate == 0 && sensor_ec_rate != 0) ||
		    (sensor_ec_rate != 0 && sensor_ec_rate < ec_rate))
			ec_rate = sensor_ec_rate;
	}
	/*
	 * Wake up the motion sense task: we want to sensor task to take
	 * in account the new period right away.
	 */
	if (accel_interval == 0 ||
	    (ec_rate > 0 && accel_interval > ec_rate))
		wake_up = 1;
	accel_interval = ec_rate;
	if (wake_up)
		task_wake(TASK_ID_MOTIONSENSE);
	return accel_interval;
}
Beispiel #18
0
void chipset_exit_hard_off(void)
{
	/*
	 * If not in the soft-off state, hard-off state, or headed there,
	 * nothing to do.
	 */
	if (state != POWER_G3 && state != POWER_S5G3 && state != POWER_S5)
		return;

	/*
	 * Set a flag to leave G3, then wake the task. If the power state is
	 * POWER_S5G3, or is POWER_S5 but the S5 inactivity timer has
	 * expired, set this flag can let system go to G3 and then exit G3
	 * immediately for powering on.
	 */
	want_g3_exit = 1;

	/*
	 * If the power state is in POWER_S5 and S5 inactivity timer is
	 * running, to wake the chipset task can cancel S5 inactivity timer and
	 * then restart the timer. This will give cpu a chance to start up if
	 * S5 inactivity timer is about to expire while power button is
	 * pressed. For other states here, to wake the chipset task to trigger
	 * the event for leaving G3 is necessary.
	 */
	if (task_start_called())
		task_wake(TASK_ID_CHIPSET);
}
Beispiel #19
0
void keyboard_raw_interrupt(void)
{
	/* Clear interrupt status bits */
	MEC1322_KS_KSI_STATUS = 0xff;

	/* Wake keyboard scan task to handle interrupt */
	task_wake(TASK_ID_KEYSCAN);
}
Beispiel #20
0
/* KB controller input buffer full ISR */
void lpc_kbc_ibf_interrupt(void)
{
	/* If "command" input 0, else 1*/
	if (lpc_keyboard_input_pending())
		keyboard_host_write(NPCX_HIKMDI, (NPCX_HIKMST & 0x08) ? 1 : 0);
	CPRINTS("ibf isr %02x", NPCX_HIKMDI);
	task_wake(TASK_ID_KEYPROTO);
}
static int wait_charging_state(void)
{
	enum charge_state state;
	task_wake(TASK_ID_CHARGER);
	msleep(WAIT_CHARGER_TASK);
	state = charge_get_state();
	ccprintf("[CHARGING TEST] state = %d\n", state);
	return state;
}
Beispiel #22
0
static void rockchip_lid_event(void)
{
	/* Power task only cares about lid-open events */
	if (!lid_is_open())
		return;

	lid_opened = 1;
	task_wake(TASK_ID_CHIPSET);
}
Beispiel #23
0
/**
 * Handle charge state changes
 */
static void powerbtn_x86_charge(void)
{
	/*
	 * If we were waiting for the charge state machine to init before we
	 * powered on the chipset, we can stop waiting.
	 */
	if (pwrbtn_state == PWRBTN_STATE_INIT_ON)
		task_wake(TASK_ID_POWERBTN);
}
Beispiel #24
0
/* KB controller output buffer empty ISR */
void lpc_kbc_obe_interrupt(void)
{
	/* Disable KBC OBE interrupt */
	CLEAR_BIT(NPCX_HICTRL, NPCX_HICTRL_OBECIE);
	task_disable_irq(NPCX_IRQ_KBC_OBE);

	CPRINTS("obe isr %02x", NPCX_HIKMST);
	task_wake(TASK_ID_KEYPROTO);
}
Beispiel #25
0
void power_button_pch_pulse(void)
{
	CPRINTS("PB PCH pulse");

	chipset_exit_hard_off();
	set_pwrbtn_to_pch(0);
	pwrbtn_state = PWRBTN_STATE_LID_OPEN;
	tnext_state = get_time().val + PWRBTN_INITIAL_US;
	task_wake(TASK_ID_POWERBTN);
}
void pmu_task_throttled_wake(void)
{
	timestamp_t now = get_time();
	if (now.val - last_waken.val >= HOOK_TICK_INTERVAL) {
		has_pending_event = 0;
		task_wake(TASK_ID_CHARGER);
	} else {
		has_pending_event = 1;
	}
}
Beispiel #27
0
void chipset_exit_hard_off(void)
{
    /* If not in the hard-off state nor headed there, nothing to do */
    if (state != POWER_G3 && state != POWER_S5G3)
        return;

    /* Set a flag to leave G3, then wake the task */
    want_g3_exit = 1;

    task_wake(TASK_ID_CHIPSET);
}
Beispiel #28
0
static int expect_keychange(void)
{
	int old_count = fifo_add_count;
	int retry = KEYDOWN_RETRY;
	task_wake(TASK_ID_KEYSCAN);
	while (retry--) {
		msleep(KEYDOWN_DELAY_MS);
		if (fifo_add_count > old_count)
			return EC_SUCCESS;
	}
	return EC_ERROR_UNKNOWN;
}
Beispiel #29
0
static int wait_variable_set(int *var)
{
	int retry = KEYDOWN_RETRY;
	*var = 0;
	task_wake(TASK_ID_KEYSCAN);
	while (retry--) {
		msleep(KEYDOWN_DELAY_MS);
		if (*var == 1)
			return EC_SUCCESS;
	}
	return EC_ERROR_UNKNOWN;
}
Beispiel #30
0
/*
 * Header: Run the task in three parts: wake - decode - execute
 *
 * Params: tsk    - task to run
 * Return: ETRSLP - task is still sleeping and yielded before run
 *         ETRPAU - task was paused and yielded before run
 *         ETRINS - invalid instruction, now in error state
 *         ETRPWM - invalid target, now in error state
 *         ETRNLP - encountered nested loop, now in error state
 *
 * Description:
 *
 * This function is decomposed into three (static) functions. First, we try to
 * wake the task from sleep (if necessary). If we cannot wake from sleep yet,
 * then we return immediately - we do not consider the task to have run at
 * all in that cycle.
 *
 * Before we run instruction decode, we transfer last cycle's target to this
 * cycle's current position. That is, if the last instruction was a MOV, we
 * are now at that position.
 *
 * Next is instruction decode. If any error occurs here, we throw the task 
 * into error state.
 *
 * Finally, the instruction itself is executed. In the case of an invalid 
 * target or encounter of a nested loop, we throw the task into error state.
 *
 * Overall, note this function deals primarly with two control variables:
 *
 *  - result: contains success or an error code
 *
 *  - increment_pc: some branches in this function require that $pc not be
 *    incremented. For example, when we return after not waking from sleep,
 *    we are still on the same instruction.
 */
char task_run(struct task *tsk)
{
	char result = 0; /* Initially assume function will succeed */
	char increment_pc = 1; /* Initially assume $pc will be incremented */

	char wake_result, decode_result, exe_result; /* intermediates */

	unsigned char opcode, params;

	/* This determines if the task should RUN or YIELD IMMEDIATELY */
	switch(wake_result = task_wake(tsk)) {
	case ETRSLP:
	case ETRPAU:
	case ETREND:
	case ETRCRT:
		increment_pc = 0; /* Do NOT increment PC! */
		result = wake_result;

		goto yield;
	}

	tsk->state = ST_RUNNING; 
	tsk->cur_pos = tsk->mov_pos; /* We're now at last cycle's target */

	/* If decode fails, the func will return ETRINS */
	switch(decode_result = task_instr_decode(tsk, &opcode, &params)) {
	case ETRINS:
		increment_pc = 0; /* Do NOT increment PC! */
		result = decode_result;

		goto yield;
	}

	switch(exe_result = task_instr_exe(tsk, opcode, params)) {
	case ETRPWM:
	case ETRNLP:
	case ETREND:
		increment_pc = 0; /* Do NOT increment PC! */
		result = exe_result;

		goto yield;
	}

	tsk->state = ST_SLEEPING;

yield:	if(increment_pc) tsk->pc++; /* (else: i.e. fail to wake from sleep) */

	if(tsk->state == ST_END && tsk->preempted) {
		task_fake_stack_pop(tsk);
	}
	
	return result;
}