summaryrefslogtreecommitdiff
path: root/chip/g/usb_spi.h
blob: 4cf38742af53201e8ff937a180145129c3cb7110 (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
/* 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.
 */
#ifndef __CROS_EC_USB_SPI_H
#define __CROS_EC_USB_SPI_H

/* USB SPI driver for Chrome EC */

#include "compile_time_macros.h"
#include "dcrypto.h"
#include "hooks.h"
#include "queue.h"
#include "queue_policies.h"
#include "usb_descriptor.h"
#include "usb-stream.h"

#define HEADER_SIZE 2

/*
 * Command:
 *     +------------------+-----------------+------------------------+
 *     | write count : 1B | read count : 1B | write payload : <= 62B |
 *     +------------------+-----------------+------------------------+
 *
 *     write count:   1 byte, zero based count of bytes to write
 *
 *     read count:    1 byte, zero based count of bytes to read
 *
 *     write payload: up to 62 bytes of data to write, length must match
 *                    write count
 *
 * Response:
 *     +-------------+-----------------------+
 *     | status : 2B | read payload : <= 62B |
 *     +-------------+-----------------------+
 *
 *     status: 2 byte status
 *         0x0000: Success
 *         0x0001: SPI timeout
 *         0x0002: Busy, try again
 *             This can happen if someone else has acquired the shared memory
 *             buffer that the SPI driver uses as /dev/null
 *         0x0003: Write count invalid (> 62 bytes, or mismatch with payload)
 *         0x0004: Read count invalid (> 62 bytes)
 *         0x0005: The SPI bridge is disabled.
 *         0x8000: Unknown error mask
 *             The bottom 15 bits will contain the bottom 15 bits from the EC
 *             error code.
 *
 *     read payload: up to 62 bytes of data read from SPI, length will match
 *                   requested read count
 */

enum usb_spi_error {
	USB_SPI_SUCCESS             = 0x0000,
	USB_SPI_TIMEOUT             = 0x0001,
	USB_SPI_BUSY                = 0x0002,
	USB_SPI_WRITE_COUNT_INVALID = 0x0003,
	USB_SPI_READ_COUNT_INVALID  = 0x0004,
	USB_SPI_DISABLED            = 0x0005,
	USB_SPI_RX_BAD_DATA_INDEX   = 0x0006,
	USB_SPI_RX_DATA_OVERFLOW    = 0x0007,
	USB_SPI_RX_UNEXPECTED_PACKET = 0x0008,
	USB_SPI_UNSUPPORTED_FULL_DUPLEX = 0x0009,
	USB_SPI_RUNT_PACKET         = 0x000a,
	USB_SPI_UNKNOWN_ERROR       = 0x8000,
};

enum usb_spi_request {
	USB_SPI_REQ_ENABLE           = 0x0000,
	USB_SPI_REQ_DISABLE          = 0x0001,
	USB_SPI_REQ_ENABLE_AP        = 0x0002,
	USB_SPI_REQ_ENABLE_EC        = 0x0003,
	USB_SPI_REQ_ENABLE_H1        = 0x0004,
	USB_SPI_REQ_RESET            = 0x0005,
	USB_SPI_REQ_BOOT_CFG         = 0x0006,
	USB_SPI_REQ_SOCKET           = 0x0007,
	USB_SPI_REQ_SIGNING_START    = 0x0008,
	USB_SPI_REQ_SIGNING_SIGN     = 0x0009,
	USB_SPI_REQ_ENABLE_AP_CUSTOM = 0x000a,
};

/* USB SPI device bitmasks */
enum usb_spi {
	USB_SPI_DISABLE = 0,
	USB_SPI_AP = BIT(0),
	USB_SPI_EC = BIT(1),
	USB_SPI_H1 = BIT(2),
	USB_SPI_ALL = USB_SPI_AP | USB_SPI_EC | USB_SPI_H1
};


#ifdef CONFIG_USB_SPI_V2
/*
 * Raiden client can be in one of two states, IDLE, or WRITING.
 *
 * When in IDLE state the client accepts commands from the host and can either
 * perform the required action (report the configuration, or write a full
 * write transaction (fitting into one USB packet), or write the received
 * chunk and then repeatedly read the SPI flash and send the contents back in
 * USB packets until the full required read transaction is completed.
 *
 * In case the received chunk is less than the total write transaction size
 * the client moves into RAIDEN_WRITING state and expects all following
 * received USB packets to be continuation of the write transaction.
 */
enum raiden_state { RAIDEN_IDLE, RAIDEN_WRITING };
#endif

struct usb_spi_state {
	/*
	 * The SPI bridge must be enabled both locally and by the host to allow
	 * access to the SPI device.  The enabled_host flag is set and cleared
	 * by sending USB_SPI_REQ_ENABLE_EC, USB_SPI_REQ_ENABLE_HOST, and
	 * USB_SPI_REQ_DISABLE to the device control endpoint.  The
	 * enabled_device flag is set by calling usb_spi_enable.
	 */
	int enabled_host;
	int enabled_device;

	/*
	 * The current enabled state.  This is only updated in the deferred
	 * callback.  Whenever either of the host or device specific enable
	 * flags is changed the deferred callback is queued, and it will check
	 * their combined state against this flag.  If the combined state is
	 * different, then one of usb_spi_board_enable or usb_spi_board_disable
	 * is called and this flag is updated.  This ensures that the board
	 * specific state update routines are only called from the deferred
	 * callback.
	 */
	int enabled;

#ifdef CONFIG_USB_SPI_V2
	/* Variable helping to keep track of multi packet write PDUs. */
	uint16_t total_write_count;
	uint16_t wrote_so_far;
	enum raiden_state raiden_state;
#endif
};

/*
 * Compile time Per-USB gpio configuration stored in flash.  Instances of this
 * structure are provided by the user of the USB gpio.  This structure binds
 * together all information required to operate a USB gpio.
 */
struct usb_spi_config {
	/*
	 * In RAM state of the USB SPI bridge.
	 */
	struct usb_spi_state *state;

	/*
	 * Interface and endpoint indices.
	 */
	int interface;
	int endpoint;

	/*
	 * Deferred function to call to handle SPI request.
	 */
	const struct deferred_data *deferred;



	/*
	 * Pointer to tx and rx queues and bounce buffer.
	 */
	uint8_t *buffer;
	struct consumer const consumer;
	struct queue const *tx_queue;
};

extern struct consumer_ops const usb_spi_consumer_ops;

/*
 * Convenience macro for defining a USB SPI bridge driver.
 *
 * NAME is used to construct the names of the trampoline functions and the
 * usb_spi_config struct, the latter is just called NAME.
 *
 * INTERFACE is the index of the USB interface to associate with this
 * SPI driver.
 *
 * ENDPOINT is the index of the USB bulk endpoint used for receiving and
 * transmitting bytes.
 */

#define USB_SPI_CONFIG(NAME,						\
		       INTERFACE,					\
		       ENDPOINT)					\
									\
	static uint8_t CONCAT2(NAME, _buffer_)[USB_MAX_PACKET_SIZE]	\
		__aligned(2);						\
	static void CONCAT2(NAME, _deferred_)(void);			\
	DECLARE_DEFERRED(CONCAT2(NAME, _deferred_));			\
	static struct queue const CONCAT2(NAME, _to_usb_);		\
	static struct queue const CONCAT3(usb_to_, NAME, _);		\
	USB_STREAM_CONFIG_FULL(CONCAT2(NAME, _usb_),			\
			       INTERFACE,				\
			       USB_CLASS_VENDOR_SPEC,			\
			       USB_SUBCLASS_GOOGLE_SPI,			\
			       USB_PROTOCOL_GOOGLE_SPI,			\
			       USB_STR_SPI_NAME,			\
			       ENDPOINT,				\
			       USB_MAX_PACKET_SIZE,			\
			       USB_MAX_PACKET_SIZE,			\
			       CONCAT3(usb_to_, NAME, _),		\
			       CONCAT2(NAME, _to_usb_))			\
	static struct usb_spi_state CONCAT2(NAME, _state_);		\
	struct usb_spi_config const NAME = {				\
		.state     = &CONCAT2(NAME, _state_),			\
		.interface = INTERFACE,					\
		.endpoint  = ENDPOINT,					\
		.deferred  = &CONCAT2(NAME, _deferred__data),		\
		.buffer    = CONCAT2(NAME, _buffer_),			\
		.consumer  = {						\
			.queue = &CONCAT3(usb_to_, NAME, _),		\
			.ops   = &usb_spi_consumer_ops,			\
		},							\
		.tx_queue = &CONCAT2(NAME, _to_usb_),			\
	};								\
	static struct queue const CONCAT2(NAME, _to_usb_) =		\
		QUEUE_DIRECT(USB_MAX_PACKET_SIZE, uint8_t,		\
		null_producer, CONCAT2(NAME, _usb_).consumer);		\
	static struct queue const CONCAT3(usb_to_, NAME, _) =		\
		QUEUE_DIRECT(USB_MAX_PACKET_SIZE, uint8_t,		\
		CONCAT2(NAME, _usb_).producer, NAME.consumer);		\
	static int CONCAT2(NAME, _interface_)				\
		(struct usb_setup_packet *req)				\
	{								\
		return usb_spi_interface(&NAME, req);			\
	}								\
	USB_DECLARE_IFACE(INTERFACE, CONCAT2(NAME, _interface_));	\
	static void CONCAT2(NAME, _deferred_)(void)			\
	{								\
		usb_spi_deferred(&NAME);				\
	}

/*
 * Handle SPI request in a deferred callback.
 */
void usb_spi_deferred(struct usb_spi_config const *config);

/*
 * Set the enable state for the USB-SPI bridge.
 *
 * The bridge must be enabled from both the host and device side
 * before the SPI bus is usable.  This allows the bridge to be
 * available for host tools to use without forcing the device to
 * disconnect or disable whatever else might be using the SPI bus.
 */
void usb_spi_enable(struct usb_spi_config const *config, int enabled);

/*
 * This is used by the trampoline function defined above  interpret the USB
 * endpoint events with the generic USB GPIO driver.
 */
int usb_spi_interface(struct usb_spi_config const *config,
		      struct usb_setup_packet *req);

/*
 * These functions should be implemented by the board to provide any board
 * specific operations required to enable or disable access to the SPI device.
 * usb_spi_board_enable should return EC_SUCCESS on success or an error
 * otherwise.
 */
int usb_spi_board_enable(int host);
void usb_spi_board_disable(void);

#ifdef CONFIG_AP_RO_VERIFICATION
/* Returns true if AP RO verification is in progress. */
bool usb_spi_shortcut_active(void);
#else
/* Make sure other than Cr50 boards build fine. */
static inline bool usb_spi_shortcut_active(void) { return false; }
#endif

/* Functions to use to fast track AP RO flash verification. */
void enable_ap_spi_hash_shortcut(void);
void disable_ap_spi_hash_shortcut(void);

#endif /* __CROS_EC_USB_SPI_H */