summaryrefslogtreecommitdiff
path: root/common/throttle_ap.c
blob: cfa97d93a509c2e2ea971c9bfc4074e4ecebc366 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/* Copyright 2013 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.
 */

/* Common chipset throttling code for Chrome EC */

#include "chipset.h"
#include "common.h"
#include "console.h"
#include "dptf.h"
#include "hooks.h"
#include "host_command.h"
#include "task.h"
#include "throttle_ap.h"
#include "timer.h"
#include "util.h"

/* Console output macros */
#define CPUTS(outstr) cputs(CC_THERMAL, outstr)
#define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args)

#define PROCHOT_IN_DEBOUNCE_US		(100 * MSEC)

/*****************************************************************************/
/* This enforces the virtual OR of all throttling sources. */
K_MUTEX_DEFINE(throttle_mutex);
static uint32_t throttle_request[NUM_THROTTLE_TYPES];
static int debounced_prochot_in;
static enum gpio_signal gpio_prochot_in = GPIO_COUNT;

void throttle_ap(enum throttle_level level,
		 enum throttle_type type,
		 enum throttle_sources source)
{
	uint32_t tmpval, bitmask;

	mutex_lock(&throttle_mutex);

	bitmask = BIT(source);

	switch (level) {
	case THROTTLE_ON:
		throttle_request[type] |= bitmask;
		break;
	case THROTTLE_OFF:
		throttle_request[type] &= ~bitmask;
		break;
	}

	tmpval = throttle_request[type];	/* save for printing */

	switch (type) {
	case THROTTLE_SOFT:
#ifdef HAS_TASK_HOSTCMD
		host_throttle_cpu(tmpval);
#endif
		break;
	case THROTTLE_HARD:
#ifdef CONFIG_CHIPSET_CAN_THROTTLE
		chipset_throttle_cpu(tmpval);
#endif
		break;

	case NUM_THROTTLE_TYPES:
		/* Make the compiler shut up. Don't use 'default', because
		 * we still want to catch any new types.
		 */
		break;
	}

	mutex_unlock(&throttle_mutex);

	/* print outside the mutex */
	CPRINTS("set AP throttling type %d to %s (0x%08x)",
		type, tmpval ? "on" : "off", tmpval);

}

static void prochot_input_deferred(void)
{
	int prochot_in;

	/*
	 * Shouldn't be possible, but better to protect against buffer
	 * overflow
	 */
	ASSERT(signal_is_gpio(gpio_prochot_in));

	prochot_in = gpio_get_level(gpio_prochot_in);

	if (IS_ENABLED(CONFIG_CPU_PROCHOT_ACTIVE_LOW))
		prochot_in = !prochot_in;

	if (prochot_in == debounced_prochot_in)
		return;

	/*
	 * b/173180788 Confirmed from Intel internal that SLP_S3# asserts low
	 * about 10us before PROCHOT# asserts low, which means that
	 * the CPU is already in reset and therefore the PROCHOT#
	 * asserting low is normal behavior and not a concern
	 * for PROCHOT# event.  Ignore all PROCHOT changes while the AP is off
	 */
	if (chipset_in_state(CHIPSET_STATE_ANY_OFF))
		return;

	debounced_prochot_in = prochot_in;

	if (debounced_prochot_in) {
		CPRINTS("External PROCHOT assertion detected");
#ifdef CONFIG_FANS
		dptf_set_fan_duty_target(100);
#endif
	} else {
		CPRINTS("External PROCHOT condition cleared");
#ifdef CONFIG_FANS
		/* Revert to automatic control of the fan */
		dptf_set_fan_duty_target(-1);
#endif
	}
}
DECLARE_DEFERRED(prochot_input_deferred);

void throttle_ap_prochot_input_interrupt(enum gpio_signal signal)
{
	/*
	 * Save the PROCHOT signal that generated the interrupt so we don't
	 * rely on a specific pin name.
	 */
	if (gpio_prochot_in == GPIO_COUNT)
		gpio_prochot_in = signal;

	/*
	 * Trigger deferred notification of PROCHOT change so we can ignore
	 * any pulses that are too short.
	 */
	hook_call_deferred(&prochot_input_deferred_data,
		PROCHOT_IN_DEBOUNCE_US);
}

/*****************************************************************************/
/* Console commands */
#ifdef CONFIG_CMD_APTHROTTLE
static int command_apthrottle(int argc, char **argv)
{
	int i;
	uint32_t tmpval;

	for (i = 0; i < NUM_THROTTLE_TYPES; i++) {
		mutex_lock(&throttle_mutex);
		tmpval = throttle_request[i];
		mutex_unlock(&throttle_mutex);

		ccprintf("AP throttling type %d is %s (0x%08x)\n", i,
			 tmpval ? "on" : "off", tmpval);
	}

	return EC_SUCCESS;
}
DECLARE_CONSOLE_COMMAND(apthrottle, command_apthrottle,
			NULL,
			"Display the AP throttling state");
#endif