summaryrefslogtreecommitdiff
path: root/zephyr/test/ap_power/src/signals.c
blob: 4eae187564749eaa231da1d32be576783bf00e4a (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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
/* Copyright 2022 The ChromiumOS Authors
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @file
 * @brief Unit Tests for power signals API
 */

#include "ec_tasks.h"
#include "emul/emul_stub_device.h"
#include "gpio.h"
#include "gpio/gpio.h"
#include "gpio/gpio_int.h"
#include "power_signals.h"
#include "test_state.h"

#include <zephyr/device.h>
#include <zephyr/drivers/espi.h>
#include <zephyr/drivers/espi_emul.h>
#include <zephyr/drivers/gpio/gpio_emul.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <zephyr/ztest.h>

extern bool gpio_test_interrupt_triggered;

static const struct device *emul_port;

/*
 * Map of signal to GPIO pin.
 * This must match overlay.dts
 */
static struct {
	enum power_signal signal;
	int pin;
} signal_to_pin_table[] = {
	{ PWR_EN_PP5000_A, 10 }, { PWR_EN_PP3300_A, 11 },
	{ PWR_RSMRST, 12 },	 { PWR_EC_PCH_RSMRST, 13 },
	{ PWR_SLP_S0, 14 },	 { PWR_SLP_S3, 15 },
	{ PWR_SLP_SUS, 16 },	 { PWR_EC_SOC_DSW_PWROK, 17 },
	{ PWR_VCCST_PWRGD, 18 }, { PWR_IMVP9_VRRDY, 19 },
	{ PWR_PCH_PWROK, 20 },	 { PWR_EC_PCH_SYS_PWROK, 21 },
	{ PWR_SYS_RST, 22 },
};

/*
 * Retrieve the GPIO pin number corresponding to this signal.
 */
static int signal_to_pin(enum power_signal signal)
{
	for (int i = 0; i < ARRAY_SIZE(signal_to_pin_table); i++) {
		if (signal_to_pin_table[i].signal == signal) {
			return signal_to_pin_table[i].pin;
		}
	}
	zassert_unreachable("Unknown signal");
	return -1;
}

/*
 * Set the raw input of the corresponding GPIO
 */
static void emul_set(enum power_signal signal, int value)
{
	gpio_emul_input_set(emul_port, signal_to_pin(signal), value);
}

/*
 * Get the raw output of the corresponding GPIO
 */
static int emul_get(enum power_signal signal)
{
	return gpio_emul_output_get(emul_port, signal_to_pin(signal));
}

/**
 * @brief TestPurpose: Check input/output validation
 *
 * @details
 * Validate that input/output GPIOs do not accept invalidate requests.
 *
 * Expected Results
 *  - Error when invalid requests are made.
 */
ZTEST(signals, test_validate_request)
{
	/* Can't set output on input */
	zassert_equal(-EINVAL, power_signal_set(PWR_SLP_S0, 1),
		      "power_signal_set on input pin should not succeed");
	/* Can't enable interrupt on output */
	zassert_equal(-EINVAL, power_signal_enable(PWR_VCCST_PWRGD),
		      "enable interrupt on output pin should not succeed");
	/* Can't disable interrupt on output */
	zassert_equal(-EINVAL, power_signal_disable(PWR_VCCST_PWRGD),
		      "disable interrupt on output pin should not succeed");
	/* Can't enable interrupt on input with no interrupt flags */
	zassert_equal(-EINVAL, power_signal_enable(PWR_IMVP9_VRRDY),
		      "enable interrupt on input pin without interrupt config");
	/* Can't disable interrupt on input with no interrupt flags */
	zassert_equal(
		-EINVAL, power_signal_disable(PWR_IMVP9_VRRDY),
		"disable interrupt on input pin without interrupt config");
	/* Invalid signal - should be rejectde */
	zassert_equal(-EINVAL, power_signal_get(-1),
		      "power_signal_get with -1 signal should fail");
	zassert_equal(-EINVAL, power_signal_set(-1, 1),
		      "power_signal_set with -1 signal should fail");
	zassert_equal(-EINVAL, power_signal_enable(-1),
		      "enable interrupt with -1 signal should fail");
	zassert_equal(-EINVAL, power_signal_disable(-1),
		      "disable interrupt with -1 signal should fail");
}

/**
 * @brief TestPurpose: Verify board specific signals
 *
 * @details
 * Validate access to board specific signals
 *
 * Expected Results
 *  - Can set and get board specific signals.
 */
ZTEST(signals, test_board_signals)
{
	/*
	 * Check that the board level signals get correctly invoked.
	 */
	zassert_ok(power_signal_set(PWR_ALL_SYS_PWRGD, 1),
		   "power_signal_set on board signal failed");
	zassert_equal(1, power_signal_get(PWR_ALL_SYS_PWRGD),
		      "power_signal_get on board signal should return 1");
}

/**
 * @brief TestPurpose: Check name retrieval
 *
 * @details
 * Validate out of bounds request
 *
 * Expected Results
 *  - Retrieve name or null for request.
 */
ZTEST(signals, test_signal_name)
{
	for (int signal = 0; signal < POWER_SIGNAL_COUNT; signal++) {
		zassert_not_null(power_signal_name(signal),
				 "Signal name for %d should be not null",
				 signal);
	}
	zassert_is_null(power_signal_name(-1),
			"Out of bounds signal name should be null");
	zassert_is_null(power_signal_name(POWER_SIGNAL_COUNT),
			"Out of bounds signal name should be null");
}

/**
 * @brief TestPurpose: Verify output signals are de-asserted at startup.
 *
 * @details
 * Confirm that output signals are initialised correctly.
 * Output pins are by default set to a de-asserted state at start-up, so
 * signals that are active-low should be set to physical high, signals
 * that are active-high should be set to physical low.
 * In overlay.dts, the only output power signal that is active-low is
 * PWR_SYS_RST
 *
 * Expected Results
 *  - Output signals are initialised as de-asserted.
 */
ZTEST(signals, test_init_outputs)
{
	static const enum power_signal active_high[] = {
		PWR_EN_PP5000_A, PWR_EN_PP3300_A, PWR_EC_PCH_RSMRST,
		PWR_EC_SOC_DSW_PWROK, PWR_PCH_PWROK
	};
	static const enum power_signal active_low[] = { PWR_SYS_RST };

	for (int i = 0; i < ARRAY_SIZE(active_high); i++) {
		zassert_equal(0, emul_get(active_high[i]),
			      "Signal %d (%s) init to de-asserted state failed",
			      active_high[i],
			      power_signal_name(active_high[i]));
	}
	for (int i = 0; i < ARRAY_SIZE(active_low); i++) {
		zassert_equal(1, emul_get(active_low[i]),
			      "Signal %d (%s) init to de-asserted state failed",
			      active_low[i], power_signal_name(active_low[i]));
	}
}

/**
 * @brief TestPurpose: Verify input signals are read correctly
 *
 * @details
 * Confirm that input signals are read correctly. Signal values
 * are set via the GPIO emul driver.
 *
 * Expected Results
 *  - Input signals are read correctly.
 */
ZTEST(signals, test_gpio_input)
{
	emul_set(PWR_RSMRST, 1);
	zassert_equal(1, power_signal_get(PWR_RSMRST),
		      "power_signal_get of PWR_RSMRST should be 1");
	emul_set(PWR_RSMRST, 0);
	zassert_equal(0, power_signal_get(PWR_RSMRST),
		      "power_signal_get of PWR_RSMRST should be 0");
	/* ACTIVE_LOW input */
	emul_set(PWR_SLP_S0, 0);
	zassert_equal(
		1, power_signal_get(PWR_SLP_S0),
		"power_signal_get of active-low signal PWR_SLP_S0 should be 1");
	emul_set(PWR_SLP_S0, 1);
	zassert_equal(0, power_signal_get(PWR_SLP_S0),
		      "power_signal_get of active-low PWR_SLP_S0 should be 0");
}

/**
 * @brief TestPurpose: Verify output signals are written correctly
 *
 * @details
 * Confirm that output signals are written correctly.
 *
 * Expected Results
 *  - Set signals are written correctly
 */
ZTEST(signals, test_gpio_output)
{
	power_signal_set(PWR_PCH_PWROK, 1);
	zassert_equal(1, emul_get(PWR_PCH_PWROK),
		      "power_signal_set of PWR_PCH_PWROK should be 1");
	power_signal_set(PWR_PCH_PWROK, 0);
	zassert_equal(0, emul_get(PWR_PCH_PWROK),
		      "power_signal_set of PWR_PCH_PWROK should be 0");
	/* ACTIVE_LOW output */
	power_signal_set(PWR_SYS_RST, 0);
	zassert_equal(1, emul_get(PWR_SYS_RST),
		      "power_signal_set of PWR_SYS_RST should be 1");
	power_signal_set(PWR_SYS_RST, 1);
	zassert_equal(0, emul_get(PWR_SYS_RST),
		      "power_signal_set of PWR_SYS_RST should be 0");
}

/**
 * @brief TestPurpose: Verify signal mask handling
 *
 * @details
 * Confirm that signal mask processing works as expected,
 * such as checking that pin changes send interrupts that
 * modifies the power signal mask.
 *
 * Expected Results
 *  - Multiple signal mask processing works
 */
ZTEST(signals, test_signal_mask)
{
	power_signal_mask_t vm = POWER_SIGNAL_MASK(PWR_IMVP9_VRRDY);
	power_signal_mask_t bm = POWER_SIGNAL_MASK(PWR_ALL_SYS_PWRGD);
	power_signal_mask_t m;

	/*
	 * Set board level (polled) signal.
	 */
	power_signal_set(PWR_ALL_SYS_PWRGD, 1);
	zassert_equal(
		bm, (power_get_signals() & bm),
		"Expected PWR_ALL_SYS_PWRGD signal to be present in mask");
	/*
	 * Use GPIO that does not interrupt to confirm that a pin change
	 * will not update the power signal mask.
	 */
	emul_set(PWR_IMVP9_VRRDY, 0);
	m = power_get_signals() & vm;
	zassert_equal(0, (power_get_signals() & vm), "Expected mask to be 0");
	emul_set(PWR_IMVP9_VRRDY, 1);
	zassert_equal(0, (power_get_signals() & vm), "Expected mask to be 0");
	zassert_equal(true, power_signals_match(bm, bm),
		      "Expected match of mask to signal match");
	zassert_equal(-ETIMEDOUT, power_wait_mask_signals_timeout(bm, 0, 5),
		      "Expected timeout waiting for mask to be 0");
	zassert_ok(power_wait_mask_signals_timeout(0, vm, 5),
		   "expected match with a 0 mask (always true)");
}

/**
 * @brief TestPurpose: Verify set/get of debug mask
 *
 * @details
 * Confirm that debug mask setting works
 *
 * Expected Results
 *  - Can set/get debug mask
 */
ZTEST(signals, test_debug_mask)
{
	power_signal_mask_t old;
	power_signal_mask_t dm = 0xDEADBEEF;

	old = power_get_debug();
	power_set_debug(dm);
	zassert_equal(dm, power_get_debug(),
		      "Debug mask does not match set value");
	/*
	 * Reset back to default.
	 */
	power_set_debug(old);
}

/**
 * @brief TestPurpose: Verify interrupts work as expected
 *
 * @details
 * For no-enable interrupts, ensure that they are not enabled at the start.
 * For default, ensure that the interrupts are enabled.
 * Check that enable/disable interrupt works.
 *
 * Expected Results
 *  - interrupt enabling/disabling works
 */
ZTEST(signals, test_gpio_interrupts)
{
	power_signal_mask_t rsm = POWER_SIGNAL_MASK(PWR_RSMRST);
	power_signal_mask_t s3 = POWER_SIGNAL_MASK(PWR_SLP_S3);
	power_signal_mask_t s0 = POWER_SIGNAL_MASK(PWR_SLP_S0);

	/* Check that GPIO pin changes update the signal mask. */
	emul_set(PWR_RSMRST, 1);
	zassert_equal(true, power_signals_on(rsm),
		      "PWR_RSMRST not updated in mask");
	emul_set(PWR_RSMRST, 0);
	zassert_equal(true, power_signals_off(rsm),
		      "PWR_RSMRST not updated in mask");

	/*
	 * Check that an ACTIVE_LOW signal gets asserted in
	 * the mask (physical value of GPIO pin 0 is set as 1 in mask)
	 */
	emul_set(PWR_SLP_S3, 0);
	zassert_equal(true, power_signals_on(s3),
		      "SLP_S3 signal should be on in mask");
	emul_set(PWR_SLP_S3, 1);
	zassert_equal(true, power_signals_off(s3),
		      "SLP_S3 should be off in mask");

	/*
	 * Check that disabled interrupt on the GPIO does not trigger
	 * and update the mask.
	 */
	emul_set(PWR_SLP_S0, 0);
	zassert_equal(false, power_signals_on(s0),
		      "SLP_S0 should not have updated");
	emul_set(PWR_SLP_S0, 1);
	zassert_equal(false, power_signals_on(s0),
		      "SLP_S0 should not have updated");

	power_signal_enable(PWR_SLP_S0);
	emul_set(PWR_SLP_S0, 0);
	zassert_equal(true, power_signals_on(s0),
		      "SLP_S0 should have updated the mask");
	emul_set(PWR_SLP_S0, 1);
	zassert_equal(true, power_signals_off(s0),
		      "SLP_S0 should have updated the mask");

	/*
	 * Disable the GPIO interrupt again.
	 */
	power_signal_disable(PWR_SLP_S0);
	emul_set(PWR_SLP_S0, 0);
	zassert_equal(false, power_signals_on(s0),
		      "SLP_S0 should not have updated the mask");
	emul_set(PWR_SLP_S0, 1);
	zassert_equal(true, power_signals_off(s0),
		      "SLP_S0 should not have updated the mask");
}

/**
 * @brief TestPurpose: Verify reception of VW signals
 *
 * @details
 * Confirm that ESPI virtual wire signals can be received.
 *
 * Expected Results
 *  - Virtual wire signals are received.
 */
ZTEST(signals, test_espi_vw)
{
	const struct device *espi =
		DEVICE_DT_GET_ANY(zephyr_espi_emul_controller);

	zassert_not_null(espi, "Cannot get ESPI device");
	/*
	 * Send a VW signal, and check that it is received.
	 * The signal is configured as an inverted signal,
	 * so sending a 0 value should be received as a signal.
	 */
	emul_espi_host_send_vw(espi, ESPI_VWIRE_SIGNAL_SLP_S5, 0);
	zassert_equal(1, power_signal_get(PWR_SLP_S5), "VW SLP_S5 should be 1");
	emul_espi_host_send_vw(espi, ESPI_VWIRE_SIGNAL_SLP_S5, 1);
	zassert_equal(0, power_signal_get(PWR_SLP_S5), "VW SLP_S5 should be 0");
}

static void *init_dev(void)
{
	emul_port = DEVICE_DT_GET(DT_NODELABEL(gpio0));

	return NULL;
}

static void init_signals(void *data)
{
	power_signal_init();
}

/**
 * @brief Test Suite: Verifies power signal functionality.
 */
ZTEST_SUITE(signals, ap_power_predicate_post_main, init_dev, init_signals, NULL,
	    NULL);

/* These 2 lines are needed because we don't define an espi host driver */
#define DT_DRV_COMPAT zephyr_espi_emul_espi_host
DT_INST_FOREACH_STATUS_OKAY(EMUL_STUB_DEVICE);