Exemple #1
1
/**
 * Check for some event triggering the shutdown.
 *
 * It can be either a long power button press or a shutdown triggered from the
 * AP and detected by reading POWER_GOOD.
 *
 * @return non-zero if a shutdown should happen, 0 if not
 */
static int check_for_power_off_event(void)
{
	timestamp_t now;
	int pressed = 0;
	int ret = 0;

	/*
	 * Check for power button press.
	 */
	if (power_button_is_pressed()) {
		pressed = 1;
	} else if (power_request == POWER_REQ_OFF) {
		power_request = POWER_REQ_NONE;
		return 4;  /* return non-zero for shudown down */
	}

#ifdef HAS_TASK_KEYSCAN
	/* Dis/Enable keyboard scanning when the power button state changes */
	if (!pressed || pressed != power_button_was_pressed)
		keyboard_scan_enable(!pressed, KB_SCAN_DISABLE_POWER_BUTTON);
#endif

	now = get_time();
	if (pressed) {
		if (!power_button_was_pressed) {
			power_off_deadline.val = now.val + DELAY_FORCE_SHUTDOWN;
			CPRINTS("power waiting for long press %u",
				power_off_deadline.le.lo);
			/* Ensure we will wake up to check the power key */
			timer_arm(power_off_deadline, TASK_ID_CHIPSET);
		} else if (timestamp_expired(power_off_deadline, &now)) {
			power_off_deadline.val = 0;
			CPRINTS("power off after long press now=%u, %u",
				now.le.lo, power_off_deadline.le.lo);
			return 2;
		}
	} else if (power_button_was_pressed) {
		CPRINTS("power off cancel");
		timer_cancel(TASK_ID_CHIPSET);
	}

	/* POWER_GOOD released by AP : shutdown immediately */
	if (!power_has_signals(IN_POWER_GOOD)) {
		if (power_button_was_pressed)
			timer_cancel(TASK_ID_CHIPSET);
		ret = 3;
	}

	power_button_was_pressed = pressed;

	return ret;
}
Exemple #2
0
/**
 * Update status of non-debounced switches.
 *
 * Note that deferred functions are called in the same context as lid and
 * power button changes, so we don't need a mutex.
 */
static void switch_update(void)
{
	static uint8_t prev;

	/* Make sure this is safe to call before power_button_init() */
	if (!memmap_switches)
		return;

	prev = *memmap_switches;

	if (power_button_is_pressed())
		*memmap_switches |= EC_SWITCH_POWER_BUTTON_PRESSED;
	else
		*memmap_switches &= ~EC_SWITCH_POWER_BUTTON_PRESSED;

	if (lid_is_open())
		*memmap_switches |= EC_SWITCH_LID_OPEN;
	else
		*memmap_switches &= ~EC_SWITCH_LID_OPEN;

	if ((flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED) == 0)
		*memmap_switches |= EC_SWITCH_WRITE_PROTECT_DISABLED;
	else
		*memmap_switches &= ~EC_SWITCH_WRITE_PROTECT_DISABLED;

#ifdef CONFIG_SWITCH_DEDICATED_RECOVERY
	if (gpio_get_level(GPIO_RECOVERY_L) == 0)
		*memmap_switches |= EC_SWITCH_DEDICATED_RECOVERY;
	else
		*memmap_switches &= ~EC_SWITCH_DEDICATED_RECOVERY;
#endif

	if (prev != *memmap_switches)
		CPRINTS("SW 0x%02x", *memmap_switches);
}
Exemple #3
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);
}
static void fake_hibernate_power_button_hook(void)
{
	if (fake_hibernate && lid_is_open() && !power_button_is_pressed()) {
		ccprints("%s() resets EC", __func__);
		cflush();
		system_reset(SYSTEM_RESET_HARD);
	}
}
static void hang_detect_power_button(void)
{
	if (power_button_is_pressed()) {
		if (hdparams.flags & EC_HANG_START_ON_POWER_PRESS)
			hang_detect_start("power button");
	} else {
		if (hdparams.flags & EC_HANG_STOP_ON_POWER_RELEASE)
			hang_detect_stop("power button");
	}
}
Exemple #6
0
void power_button_pch_release(void)
{
	CPRINTS("PB PCH force release");

	/* Deassert power button signal to PCH */
	set_pwrbtn_to_pch(1);

	/*
	 * If power button is actually pressed, eat the next release so we
	 * don't send an extra release.
	 */
	if (power_button_is_pressed())
		pwrbtn_state = PWRBTN_STATE_EAT_RELEASE;
	else
		pwrbtn_state = PWRBTN_STATE_IDLE;
}
Exemple #7
0
/**
 * Check if there has been a power-on event
 *
 * This checks all power-on event signals and returns non-zero if any have been
 * triggered (with debounce taken into account).
 *
 * @return non-zero if there has been a power-on event, 0 if not.
 */
static int check_for_power_on_event(void)
{
	int ap_off_flag;

	ap_off_flag = system_get_reset_flags() & RESET_FLAG_AP_OFF;
	system_clear_reset_flags(RESET_FLAG_AP_OFF);
	/* check if system is already ON */
	if (power_get_signals() & IN_POWER_GOOD) {
		if (ap_off_flag) {
			CPRINTS(
				"system is on, but "
				"RESET_FLAG_AP_OFF is on");
			return 0;
		} else {
			CPRINTS(
				"system is on, thus clear "
				"auto_power_on");
			/* no need to arrange another power on */
			auto_power_on = 0;
			return 1;
		}
	}

	/* power on requested at EC startup for recovery */
	if (auto_power_on) {
		auto_power_on = 0;
		return 2;
	}

	/* Check lid open */
	if (lid_opened) {
		lid_opened = 0;
		return 3;
	}

	/* check for power button press */
	if (power_button_is_pressed())
		return 4;

	if (power_request == POWER_REQ_ON) {
		power_request = POWER_REQ_NONE;
		return 5;
	}

	return 0;
}
Exemple #8
0
/**
 * Set initial power button state.
 */
static void set_initial_pwrbtn_state(void)
{
	uint32_t reset_flags = system_get_reset_flags();

	if (system_jumped_to_this_image() &&
	    chipset_in_state(CHIPSET_STATE_ON)) {
		/*
		 * Jumped to this image while the chipset was already on, so
		 * simply reflect the actual power button state.
		 */
		if (power_button_is_pressed()) {
			CPRINTS("PB init-jumped-held");
			set_pwrbtn_to_pch(0);
		} else {
			CPRINTS("PB init-jumped");
		}
	} else if ((reset_flags & RESET_FLAG_AP_OFF) ||
		   (keyboard_scan_get_boot_key() == BOOT_KEY_DOWN_ARROW)) {
		/*
		 * Reset triggered by keyboard-controlled reset, and down-arrow
		 * was held down.  Or reset flags request AP off.
		 *
		 * Leave the main processor off.  This is a fail-safe
		 * combination for debugging failures booting the main
		 * processor.
		 *
		 * Don't let the PCH see that the power button was pressed.
		 * Otherwise, it might power on.
		 */
		CPRINTS("PB init-off");
		power_button_pch_release();
	} else {
		/*
		 * All other EC reset conditions power on the main processor so
		 * it can verify the EC.
		 */
#ifdef CONFIG_BRINGUP
		CPRINTS("PB idle");
		pwrbtn_state = PWRBTN_STATE_IDLE;
#else
		CPRINTS("PB init-on");
		pwrbtn_state = PWRBTN_STATE_INIT_ON;
#endif
	}
}
Exemple #9
0
/**
 * Wait for the power button to be released
 *
 * @param timeout_us Timeout in microseconds, or -1 to wait forever
 * @return EC_SUCCESS if ok, or
 *         EC_ERROR_TIMEOUT if power button failed to release
 */
int power_button_wait_for_release(int timeout_us)
{
	timestamp_t deadline;
	timestamp_t now = get_time();

	deadline.val = now.val + timeout_us;

	while (!power_button_is_stable || power_button_is_pressed()) {
		now = get_time();
		if (timeout_us < 0) {
			task_wait_event(-1);
		} else if (timestamp_expired(deadline, &now) ||
			(task_wait_event(deadline.val - now.val) ==
			TASK_EVENT_TIMER)) {
			CPRINTS("power button not released in time");
			return EC_ERROR_TIMEOUT;
		}
	}

	CPRINTS("power button released in time");
	return EC_SUCCESS;
}
Exemple #10
0
/**
 * Power button state machine.
 *
 * @param tnow		Current time from usec counter
 */
static void state_machine(uint64_t tnow)
{
	/* Not the time to move onto next state */
	if (tnow < tnext_state)
		return;

	/* States last forever unless otherwise specified */
	tnext_state = 0;

	switch (pwrbtn_state) {
	case PWRBTN_STATE_PRESSED:
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF)) {
			/*
			 * Chipset is off, so wake the chipset and send it a
			 * long enough pulse to wake up.  After that we'll
			 * reflect the true power button state.  If we don't
			 * stretch the pulse here, the user may release the
			 * power button before the chipset finishes waking from
			 * hard off state.
			 */
			chipset_exit_hard_off();
			tnext_state = tnow + PWRBTN_INITIAL_US;
			pwrbtn_state = PWRBTN_STATE_WAS_OFF;
		} else {
			/* Chipset is on, so send the chipset a pulse */
			tnext_state = tnow + PWRBTN_DELAY_T0;
			pwrbtn_state = PWRBTN_STATE_T0;
		}
		set_pwrbtn_to_pch(0);
		break;
	case PWRBTN_STATE_T0:
		tnext_state = tnow + PWRBTN_DELAY_T1;
		pwrbtn_state = PWRBTN_STATE_T1;
		set_pwrbtn_to_pch(1);
		break;
	case PWRBTN_STATE_T1:
		/*
		 * If the chipset is already off, don't tell it the power
		 * button is down; it'll just cause the chipset to turn on
		 * again.
		 */
		if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
			CPRINTS("PB chipset already off");
		else
			set_pwrbtn_to_pch(0);
		pwrbtn_state = PWRBTN_STATE_HELD;
		break;
	case PWRBTN_STATE_RELEASED:
	case PWRBTN_STATE_LID_OPEN:
		set_pwrbtn_to_pch(1);
		pwrbtn_state = PWRBTN_STATE_IDLE;
		break;
	case PWRBTN_STATE_INIT_ON:
		/*
		 * Don't do anything until the charger knows the battery level.
		 * Otherwise we could power on the AP only to shut it right
		 * back down due to insufficient battery.
		 */
#ifdef HAS_TASK_CHARGER
		if (charge_get_state() == PWR_STATE_INIT)
			break;
#endif

		/*
		 * Power the system on if possible.  Gating due to insufficient
		 * battery is handled inside set_pwrbtn_to_pch().
		 */
		chipset_exit_hard_off();
		set_pwrbtn_to_pch(0);
		tnext_state = get_time().val + PWRBTN_INITIAL_US;

		if (power_button_is_pressed()) {
			if (system_get_reset_flags() & RESET_FLAG_RESET_PIN)
				pwrbtn_state = PWRBTN_STATE_BOOT_KB_RESET;
			else
				pwrbtn_state = PWRBTN_STATE_WAS_OFF;
		} else {
			pwrbtn_state = PWRBTN_STATE_RELEASED;
		}

		break;

	case PWRBTN_STATE_BOOT_KB_RESET:
		/* Initial forced pulse is done.  Ignore the actual power
		 * button until it's released, so that holding down the
		 * recovery combination doesn't cause the chipset to shut back
		 * down. */
		set_pwrbtn_to_pch(1);
		if (power_button_is_pressed())
			pwrbtn_state = PWRBTN_STATE_EAT_RELEASE;
		else
			pwrbtn_state = PWRBTN_STATE_IDLE;
		break;
	case PWRBTN_STATE_WAS_OFF:
		/* Done stretching initial power button signal, so show the
		 * true power button state to the PCH. */
		if (power_button_is_pressed()) {
			/* User is still holding the power button */
			pwrbtn_state = PWRBTN_STATE_HELD;
		} else {
			/* Stop stretching the power button press */
			power_button_released(tnow);
		}
		break;
	case PWRBTN_STATE_IDLE:
	case PWRBTN_STATE_HELD:
	case PWRBTN_STATE_EAT_RELEASE:
		/* Do nothing */
		break;
	}
}