summaryrefslogtreecommitdiff
path: root/cts/interrupt/dut.c
blob: 3c83e5701fdfb8f121b6bb78690c41292012eb18 (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
/* 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.
 */

#include <string.h>
#include "common.h"
#include "cts_common.h"
#include "gpio.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "watchdog.h"

static int got_interrupt;
static int wake_me_up;
static int state_index;
static char state[4];

/*
 * Raw busy loop. Returns 1 if loop finishes before interrupt is triggered.
 * Loop length is controlled by busy_loop_timeout. It has to be set to the
 * value which makes the loop last longer than CTS_INTERRUPT_TRIGGER_DELAY_US.
 */
static int busy_loop(void)
{
	/* TODO: Derive a proper value from clock speed */
	const uint32_t busy_loop_timeout = 0xfffff;
	uint32_t counter = 0;

	while (counter++ < busy_loop_timeout) {
		if (got_interrupt)
			break;
		watchdog_reload();
	}
	if (counter > busy_loop_timeout)
		return 1;

	return 0;
}

/*
 * Interrupt handler.
 */
void cts_irq1(enum gpio_signal signal)
{
	state[state_index++] = 'B';

	got_interrupt = in_interrupt_context();

	/* Wake up the CTS task */
	if (wake_me_up)
		task_wake(TASK_ID_CTS);

	busy_loop();

	state[state_index++] = 'C';
}

void cts_irq2(enum gpio_signal signal)
{
	state[state_index++] = 'A';
	busy_loop();
	state[state_index++] = 'D';
}

void clean_state(void)
{
	uint32_t *event;

	interrupt_enable();
	got_interrupt = 0;
	wake_me_up = 0;
	state_index = 0;
	memset(state, '_', sizeof(state));
	event = task_get_event_bitmap(TASK_ID_CTS);
	*event = 0;
}

enum cts_rc test_task_wait_event(void)
{
	uint32_t event;

	wake_me_up = 1;

	/* Sleep and wait for interrupt. This shouldn't time out. */
	event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2);
	if (event != TASK_EVENT_WAKE) {
		CPRINTS("Woken up by unexpected event: 0x%08x", event);
		return CTS_RC_FAILURE;
	}
	if (!got_interrupt) {
		CPRINTS("Interrupt context not detected");
		return CTS_RC_TIMEOUT;
	}

	return CTS_RC_SUCCESS;
}

enum cts_rc test_task_disable_irq(void)
{
	uint32_t event;

	wake_me_up = 1;

	task_disable_irq(CTS_IRQ_NUMBER);
	/* Sleep and wait for interrupt. This should time out. */
	event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 2);
	if (event != TASK_EVENT_TIMER) {
		CPRINTS("Woken up by unexpected event: 0x%08x", event);
		return CTS_RC_FAILURE;
	}
	task_enable_irq(CTS_IRQ_NUMBER);

	return CTS_RC_SUCCESS;
}

enum cts_rc test_interrupt_enable(void)
{
	if (busy_loop()) {
		CPRINTS("Timeout before interrupt");
		return CTS_RC_TIMEOUT;
	}
	return CTS_RC_SUCCESS;
}

enum cts_rc test_interrupt_disable(void)
{
	interrupt_disable();
	if (!busy_loop()) {
		CPRINTS("Expected timeout but didn't");
		return CTS_RC_FAILURE;
	}
	return CTS_RC_SUCCESS;
}

enum cts_rc test_nested_interrupt_low_high(void)
{
	uint32_t event;

	event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 4);
	if (event != TASK_EVENT_TIMER) {
		CPRINTS("Woken up by unexpected event: 0x%08x", event);
		return CTS_RC_FAILURE;
	}
	if (!got_interrupt) {
		CPRINTS("Interrupt context not detected");
		return CTS_RC_TIMEOUT;
	}
	if (memcmp(state, "ABCD", sizeof(state))) {
		CPRINTS("State transition differs from expectation");
		return CTS_RC_FAILURE;
	}

	return CTS_RC_SUCCESS;
}

enum cts_rc test_nested_interrupt_high_low(void)
{
	uint32_t event;

	event = task_wait_event(CTS_INTERRUPT_TRIGGER_DELAY_US * 4);
	if (event != TASK_EVENT_TIMER) {
		CPRINTS("Woken up by unexpected event: 0x%08x", event);
		return CTS_RC_FAILURE;
	}

	if (memcmp(state, "BCAD", sizeof(state))) {
		CPRINTS("State transition differs from expectation");
		return CTS_RC_FAILURE;
	}

	return CTS_RC_SUCCESS;
}

#include "cts_testlist.h"

void cts_task(void)
{
	gpio_enable_interrupt(GPIO_CTS_IRQ1);
	gpio_enable_interrupt(GPIO_CTS_IRQ2);
	cts_main_loop(tests, "Interrupt");
	task_wait_event(-1);
}