summaryrefslogtreecommitdiff
path: root/power/apollolake.c
blob: feecd24f8ebd45798a7ff6f968a0b2607a7da2fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* Copyright 2016 The Chromium OS Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/* Apollolake chipset power control module for Chrome EC */

#include "apollolake.h"
#include "console.h"
#include "gpio.h"
#include "intel_x86.h"
#include "timer.h"

/* Console output macros */
#define CPRINTS(format, args...) cprints(CC_CHIPSET, format, ## args)

static int forcing_coldreset; /* Forced coldreset in progress? */

__attribute__((weak)) void chipset_do_shutdown(void)
{
	/* Need to implement board specific shutdown */
}

void chipset_force_shutdown(void)
{
	if (!forcing_coldreset)
		CPRINTS("%s()", __func__);

	chipset_do_shutdown();
}

enum power_state chipset_force_g3(void)
{
	chipset_force_shutdown();

	/* Power up the platform again for forced cold reset */
	if (forcing_coldreset) {
		forcing_coldreset = 0;
		return POWER_G3S5;
	}

	return POWER_G3;
}

void chipset_handle_espi_reset_assert(void)
{
}

void chipset_reset(int cold_reset)
{
	CPRINTS("%s(%d)", __func__, cold_reset);
	if (cold_reset) {
		/*
		 * Perform chipset_force_shutdown and mark forcing_coldreset.
		 * Once in S5G3 state, check forcing_coldreset to power up.
		 */
		forcing_coldreset = 1;

		chipset_force_shutdown();
	} else {
		/*
		 * Send a pulse to SOC PMU_RSTBTN_N to trigger a warm reset.
		 */
		gpio_set_level(GPIO_PCH_RCIN_L, 0);
		usleep(32 * MSEC);
		gpio_set_level(GPIO_PCH_RCIN_L, 1);
	}
}

static void handle_all_sys_pgood(enum power_state state)
{
	/*
	 * Pass through asynchronously, as SOC may not react
	 * immediately to power changes.
	 */
	int in_level = gpio_get_level(GPIO_ALL_SYS_PGOOD);
	int out_level = gpio_get_level(GPIO_PCH_SYS_PWROK);

	/* Nothing to do. */
	if (in_level == out_level)
		return;

	gpio_set_level(GPIO_PCH_SYS_PWROK, in_level);

	CPRINTS("Pass through GPIO_ALL_SYS_PGOOD: %d", in_level);
}

enum power_state power_handle_state(enum power_state state)
{
	enum power_state new_state;

	/* Process ALL_SYS_PGOOD state changes. */
	handle_all_sys_pgood(state);

	if (state == POWER_S5 && !power_has_signals(IN_PGOOD_ALL_CORE)) {
		/* Required rail went away */
		chipset_force_shutdown();

		new_state = POWER_S5G3;
		goto rsmrst_handle;

	} else if (state == POWER_G3S5) {
		/* Platform is powering up, clear forcing_coldreset */
		forcing_coldreset = 0;
	}

	new_state = common_intel_x86_power_handle_state(state);

rsmrst_handle:

	/*
	 * Process RSMRST_L state changes:
	 * RSMRST_L de-assertion is passed to SoC only on G3S5 to S5 transition.
	 * RSMRST_L is also checked in some states and, if asserted, will
	 * force shutdown.
	 */
	common_intel_x86_handle_rsmrst(new_state);

	return new_state;
}

/**
 * chipset check if PLTRST# is valid.
 *
 * @return non-zero if PLTRST# is valid, 0 if invalid.
 */
int chipset_pltrst_is_valid(void)
{
	/*
	 * Invalid PLTRST# from SOC unless RSMRST#
	 * from PMIC through EC to soc is deasserted.
	 */
	return (gpio_get_level(GPIO_RSMRST_L_PGOOD) &&
		gpio_get_level(GPIO_PCH_RSMRST_L));
}