summaryrefslogtreecommitdiff
path: root/chip/g/usb_spi_v2.c
blob: abc234c70812702e879c04f0a9c188ee6c895201 (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
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
/* Copyright 2021 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 "ccd_config.h"
#include "common.h"
#include "gpio.h"
#include "link_defs.h"
#include "registers.h"
#include "shared_mem.h"
#include "spi.h"
#include "spi_controller.h"
#include "spi_flash.h"
#include "timer.h"
#include "usb_descriptor.h"
#include "usb_spi.h"
#include "util.h"

/*
 * This module implements support for SPI programming driven by the flashrom
 * utility over USB.
 *
 * Flashrom connects to the specific SPI USB endpoint and sends commands to
 * this driver to control the external SPI flash chip attached to the H1's SPI
 * host port.
 *
 * Some configuration actions might have to be performed before SPI
 * programming is possible (say asserting the AP reset, enabling a
 * multiplexer, etc.), these actions are not controlled/performed by this
 * module, it expects the 'H2<=>SPI flash' connection provisioned and the
 * flash chip ready to be programmed.
 *
 * The below protocol specification was copied from raiden_debug_spi.c in the
 * flashrom tree with addition of some clarifications.
 *
 * Note that this implementation imposes additional limits on SPI transactions
 * which include both read and write portions: the write size of such
 * transactions case can not exceed 60, the size of the payload of the first
 * USB packet carrying the transaction PDU.
 *
 * USB SPI Version 2:
 *
 *     USB SPI version 2 adds support for larger SPI transfers which reduces
 *     the number of USB packets transferred. This improves performance when
 *     writing or reading large chunks of memory from a device. Larger
 *     quantities are transferred in PDUs split into USB packets.
 *
 *     A packet ID field is used to distinguish the different USB packet
 *     types. Additional packets have been included to query the device for
 *     its configuration allowing the interface to be used on platforms with
 *     different SPI limitations. It includes validation and a packet to
 *     recover from the situations where USB packets are lost.
 *
 *     The device advertises the supported protocol version in the
 *     bInterfaceProtocol field of the USB descriptor, this allows the USB SPI
 *     hosts to be backwards compatible with version 1.
 *
 *
 * Example: USB SPI request with 128 byte write and 0 byte read.
 *
 *      Packet #1 Host to Device:
 *           packet id   = USB_SPI_PKT_ID_CMD_TRANSFER_START
 *           write count = 128
 *           read count  = 0
 *           payload     = First 58 bytes from the write buffer,
 *                         starting at byte 0 in the buffer
 *           packet size = 64 bytes
 *
 *      Packet #2 Host to Device:
 *           packet id   = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE
 *           data index  = 58
 *           payload     = Next 60 bytes from the write buffer,
 *                         starting at byte 58 in the buffer
 *           packet size = 64 bytes
 *
 *      Packet #3 Host to Device:
 *           packet id   = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE
 *           data index  = 118
 *           payload     = Next 10 bytes from the write buffer,
 *                         starting at byte 118 in the buffer
 *           packet size = 14 bytes
 *
 *      Packet #4 Device to Host:
 *           packet id   = USB_SPI_PKT_ID_RSP_TRANSFER_START
 *           status code = status code from device
 *           payload     = 0 bytes
 *           packet size = 4 bytes
 *
 * Example: USB SPI request with 2 byte write and 100 byte read.
 *
 *      Packet #1 Host to Device:
 *           packet id   = USB_SPI_PKT_ID_CMD_TRANSFER_START
 *           write count = 2
 *           read count  = 100
 *           payload     = The 2 byte write buffer
 *           packet size = 8 bytes
 *
 *      Packet #2 Device to Host:
 *           packet id   = USB_SPI_PKT_ID_RSP_TRANSFER_START
 *           status code = status code from device
 *           payload     = First 60 bytes from the read buffer,
 *                         starting at byte 0 in the buffer
 *           packet size = 64 bytes
 *
 *      Packet #3 Device to Host:
 *           packet id   = USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE
 *           data index  = 60
 *           payload     = Next 40 bytes from the read buffer,
 *                         starting at byte 60 in the buffer
 *           packet size = 44 bytes
 *
 *
 * Message Packets:
 *
 * Note that all 16 bit fields are transferred in little endian mode.
 *
 * Command Start Packet (Host to Device):
 *
 *      Start of the USB SPI command, contains the number of bytes to write
 *      and read on SPI and up to the first 58 bytes of write payload.
 *      Longer writes will use the continue packets with packet id
 *      USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE to transmit the remaining data.
 *
 *      The write part of the transaction is executed first; in case the
 *      packet includes both read and write requests, the write portion is
 *      required to fit into the first USB packet.
 *
 *     +----------------+------------------+-----------------+---------------+
 *     | packet id : 2B | write count : 2B | read count : 2B | w.p. : <= 58B |
 *     +----------------+------------------+-----------------+---------------+
 *
 *     packet id:     2 byte enum defined by packet_id_type
 *                    Valid values packet id = USB_SPI_PKT_ID_CMD_TRANSFER_START
 *
 *     write count:   2 byte, zero based count of bytes to write
 *
 *     read count:    2 byte, zero based count of bytes to read
 *                    UINT16_MAX indicates full duplex mode with a read count
 *                    equal to the write count.
 *
 *     write payload: Up to 58 bytes of data to write to SPI, the total
 *                    length of all TX packets must match write count.
 *                    Due to data alignment constraints, this must be an
 *                    even number of bytes unless this is the final packet.
 *
 *
 * Response Start Packet (Device to Host):
 *
 *      Start of the USB SPI response, contains the status code and up to
 *      the first 60 bytes of read payload. Longer reads will use the
 *      continue packets with packet id USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE
 *      to transmit the remaining data.
 *
 *     +----------------+------------------+-----------------------+
 *     | packet id : 2B | status code : 2B | read payload : <= 60B |
 *     +----------------+------------------+-----------------------+
 *
 *     packet id:     2 byte enum defined by packet_id_type
 *                    Valid values packet id = USB_SPI_PKT_ID_RSP_TRANSFER_START
 *
 *     status code: 2 byte status code
 *         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. The byte limit is platform specific
 *             and is set during the configure USB SPI response.
 *         0x0004: Read count invalid. The byte limit is platform specific
 *             and is set during the configure USB SPI response.
 *         0x0005: The SPI bridge is disabled.
 *         0x0006: The RX continue packet's data index is invalid. This
 *             can indicate a USB transfer failure to the device.
 *         0x0007: The RX endpoint has received more data than write count.
 *             This can indicate a USB transfer failure to the device.
 *         0x0008: An unexpected packet arrived that the device could not
 *             process.
 *         0x0009: The device does not support full duplex mode.
 *         0x8000: Unknown error mask
 *             The bottom 15 bits will contain the bottom 15 bits from the EC
 *             error code.
 *
 *     read payload: Up to 60 bytes of data read from SPI, the total
 *                   length of all RX packets must match read count
 *                   unless an error status was returned. Due to data
 *                   alignment constraints, this must be a even number
 *                   of bytes unless this is the final packet.
 *
 *
 * Continue Packet (Bidirectional):
 *
 *      Continuation packet for the writes and read buffers. Both packets
 *      follow the same format, a data index counts the number of bytes
 *      previously transferred in the USB SPI transfer and a payload of bytes.
 *
 *     +----------------+-----------------+-------------------------------+
 *     | packet id : 2B | data index : 2B | write / read payload : <= 60B |
 *     +----------------+-----------------+-------------------------------+
 *
 *     packet id:     2 byte enum defined by packet_id_type
 *                    The packet id has 2 values depending on direction:
 *                    packet id = USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE
 *                    indicates the packet is being transmitted from the host
 *                    to the device and contains SPI write payload.
 *                    packet id = USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE
 *                    indicates the packet is being transmitted from the device
 *                    to the host and contains SPI read payload.
 *
 *     data index:    The data index indicates the number of bytes in the
 *                    read or write buffers that have already been transmitted.
 *                    It is used to validate that no packets have been dropped
 *                    and that the prior packets have been correctly decoded.
 *                    This value corresponds to the offset bytes in the buffer
 *                    to start copying the payload into.
 *
 *     read and write payload:
 *                    Contains up to 60 bytes of payload data to transfer to
 *                    the SPI write buffer or from the SPI read buffer.
 *
 *
 * Command Get Configuration Packet (Host to Device):
 *
 *      Query the device to request its USB SPI configuration indicating
 *      the number of bytes it can write and read.
 *
 *     +----------------+
 *     | packet id : 2B |
 *     +----------------+
 *
 *     packet id:     2 byte enum USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG
 *
 * Response Configuration Packet (Device to Host):
 *
 *      Response packet form the device to report the maximum write and
 *      read size supported by the device.
 *
 *     +----------------+----------------+---------------+----------------+
 *     | packet id : 2B | max write : 2B | max read : 2B | feature bitmap |
 *     +----------------+----------------+---------------+----------------+
 *
 *     packet id:         2 byte enum USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG
 *
 *     max write count:   2 byte count of the maximum number of bytes
 *                        the device can write to SPI in one transaction.
 *
 *     max read count:    2 byte count of the maximum number of bytes
 *                        the device can read from SPI in one transaction.
 *
 *     feature bitmap:    Bitmap of supported features.
 *                        BIT(0): Full duplex SPI mode is supported
 *                        BIT(1:15): Reserved for future use
 *
 * Command Restart Response Packet (Host to Device):
 *
 *      Command to restart the response transfer from the device. This enables
 *      the host to recover from a lost packet when reading the response
 *      without restarting the SPI transfer.
 *
 *     +----------------+
 *     | packet id : 2B |
 *     +----------------+
 *
 *     packet id:         2 byte enum USB_SPI_PKT_ID_CMD_RESTART_RESPONSE
 *
 * USB Error Codes:
 *
 * send_command return codes have the following format:
 *
 *     0x00000:         Status code success.
 *     0x00001-0x0FFFF: Error code returned by the USB SPI device.
 *     0x10001-0x1FFFF: Error code returned by the USB SPI host.
 *     0x20001-0x20063  Lower bits store the positive value representation
 *                      of the libusb_error enum. See the libusb documentation:
 *                      http://libusb.sourceforge.net/api-1.0/group__misc.html
 *
 */


#define CPUTS(outstr) cputs(CC_USB, outstr)
#define CPRINTS(format, args...) cprints(CC_USB, format, ## args)

static int16_t usb_spi_map_error(int error)
{
	switch (error) {
	case EC_SUCCESS:
		return USB_SPI_SUCCESS;
	case EC_ERROR_TIMEOUT:
		return USB_SPI_TIMEOUT;
	case EC_ERROR_BUSY:
		return USB_SPI_BUSY;
	default:
		return USB_SPI_UNKNOWN_ERROR | (error & 0x7fff);
	}
}

static uint16_t usb_spi_read_packet(struct usb_spi_config const *config)
{
	return QUEUE_REMOVE_UNITS(config->consumer.queue, config->buffer,
		queue_count(config->consumer.queue));
}

/*
 * Put a packet on USB TX queue.
 *
 * Return EC_SUCCESS if there was enough room on the queue or EC_ERROR_TIMEOUT
 * if the queue is full for longer than 500 ms
 */
static enum ec_error_list usb_spi_write_packet(
	struct usb_spi_config const *config,
	uint8_t count)
{
#define QUEUE_BACKOFF_TIMEOUT_MS 1
#define MAX_QUEUE_WAIT_MS 500
	int i = (MAX_QUEUE_WAIT_MS/QUEUE_BACKOFF_TIMEOUT_MS);

	/*
	 * Experiments show that while reading a 16M flash time spent waiting
	 * is less than 30 ms, which is negligible in this case, as the AP is
	 * held in reset.
	 */
	while (queue_space(config->tx_queue) < count) {
		if (i-- == 0)
			return EC_ERROR_TIMEOUT;
		msleep(1);
	}

	QUEUE_ADD_UNITS(config->tx_queue, config->buffer, count);

	return EC_SUCCESS;
}

enum packet_id_type {
	/* Request USB SPI configuration data from device. */
	USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG = 0,
	/* USB SPI configuration data from device. */
	USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG = 1,
	/*
	 * Start a USB SPI transfer specifying number of bytes to write,
	 * read and deliver first packet of data to write.
	 */
	USB_SPI_PKT_ID_CMD_TRANSFER_START = 2,
	/* Additional packets containing write payload. */
	USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE = 3,
	/*
	 * Request the device restart the response enabling us to recover
	 * from packet loss without another SPI transfer.
	 */
	USB_SPI_PKT_ID_CMD_RESTART_RESPONSE = 4,
	/*
	 * First packet of USB SPI response with the status code
	 * and read payload if it was successful.
	 */
	USB_SPI_PKT_ID_RSP_TRANSFER_START = 5,
	/* Additional packets containing read payload. */
	USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE = 6,
	/* Inform the device that transfer is over. */
	USB_SPI_PKT_ID_CMD_HOST_DONE = 7,
	/* Inform the host that processing is finished. */
	USB_SPI_PKT_ID_RSP_DEVICE_DONE = 8,
};

enum feature_bitmap {
	/* Indicates the platform supports full duplex mode. */
	USB_SPI_FEATURE_FULL_DUPLEX_SUPPORTED = BIT(0)
};

/* Helper structures defining various PDU headers. */
struct raiden_response_hdr {
	uint16_t packet_id;
	uint16_t value; /* Either offset into the PDU or error code. */
};

struct raiden_cmd_start_hdr {
	uint16_t packet_id;
	uint16_t write_count;
	uint16_t read_count;
};

struct raiden_cmd_continue_hdr {
	uint16_t packet_id;
	uint16_t offset;
};

union raiden_cmd_hdr {
	struct raiden_cmd_start_hdr s;
	struct raiden_cmd_continue_hdr c;
};

#define START_PAYLOAD_SIZE \
	(USB_MAX_PACKET_SIZE - sizeof(struct raiden_cmd_start_hdr))
#define CONT_PAYLOAD_SIZE \
	(USB_MAX_PACKET_SIZE - sizeof(struct raiden_cmd_continue_hdr))
#define RESP_PAYLOAD_SIZE \
	(USB_MAX_PACKET_SIZE - sizeof(struct raiden_response_hdr))

BUILD_ASSERT(START_PAYLOAD_SIZE < SPI_BUF_SIZE);
/*
 * Hardcoded values used to communicate to the host maximum sizes of read and
 * write transactions.
 */
/*
 * Six bytes header, one byte command, up to four byte addr, 256 bytes data
 * page and then some in case there is a chip which uses a multibyte command.
 */
#define USB_SPI_MAX_WRITE_COUNT 270
/*
 * Flashrom deducts 5 from this value, remaining 2040 bytes size results in 34
 * USB packets of 4 byte header and 60 bytes data, getting the PDU size close
 * to 2K. Decreasing this size would decrease flashrom read efficiency,
 * increasing it would put more pressure on the heap size.
 */
#define USB_SPI_MAX_READ_COUNT (5 + 34 * RESP_PAYLOAD_SIZE)

BUILD_ASSERT(USB_SPI_MAX_READ_COUNT < (CONFIG_SHAREDMEM_MINIMUM_SIZE/2));

/* Hadrdcoded response to the config request packet. */
static const struct {
	uint16_t rsp_id;
	uint16_t max_write;
	uint16_t max_read;
	uint16_t features;
} config_rsp = { USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG, USB_SPI_MAX_WRITE_COUNT,
		 USB_SPI_MAX_READ_COUNT, 0 };

/*
 * Prepare an error message to be sent back to the host and switch to
 * RAIDEN_IDLE state.
 *
 * The return value is the number of bytes to send to the controller.
 */
static uint8_t report_error(void *packet, uint16_t error,
			    struct usb_spi_state *state)
{
	/* Packet is guaranteed to be 2 bytes aligned. */
	struct raiden_response_hdr *rsp = (struct raiden_response_hdr *)packet;

	rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START;
	rsp->value = error;

	state->raiden_state = RAIDEN_IDLE;
	return sizeof(*rsp);
}

/*
 * Send buffer containing data read from AP flash to the host.
 *
 * The buffer is sent as a V2 PDU, split into as many USB packets as
 * necessary.
 */
static void ship_pdu(const struct usb_spi_config *config, const uint8_t *buf,
		     size_t size)
{
	struct raiden_response_hdr *rsp =
		(struct raiden_response_hdr *)config->buffer;
	size_t sent_so_far = 0;

	do {
		size_t this_count = size - sent_so_far;

		if (this_count > RESP_PAYLOAD_SIZE)
			this_count = RESP_PAYLOAD_SIZE;

		rsp->packet_id = sent_so_far ?
					 USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE :
					 USB_SPI_PKT_ID_RSP_TRANSFER_START;
		rsp->value = sent_so_far;

		memcpy(rsp + 1, buf + sent_so_far, this_count);
		if (usb_spi_write_packet(config, sizeof(*rsp) + this_count)
		    != EC_SUCCESS) {
			CPRINTS("%s: USB stuck, breaking out", __func__);
			return;
		}
		sent_so_far += this_count;

	} while (sent_so_far != size);
}

/*
 * Most recent SPI transaction request received from the host, used when it is
 * necessary to restart the transaction.
 */
static struct {
	uint16_t count; /* Actual size of the request packet. */
	union raiden_cmd_hdr hdr;
	uint8_t payload[6]; /* Enough for any SPI read command. */
} last_cmd;

/* Return length of the last response packet to send back to the host. */
static uint8_t process_raiden_packet(const struct usb_spi_config *config,
				     size_t count)
{
	/* Buffer is guaranteed to be 2 bytes aligned. */
	union raiden_cmd_hdr *packet = (union raiden_cmd_hdr *)config->buffer;
	struct raiden_response_hdr *rsp =
		(struct raiden_response_hdr *)config->buffer;
	uint16_t total_read_count;
	uint16_t read_so_far;
	uint16_t this_read_count = 0;
	uint16_t this_write_count = 0;
	bool last_sub_transaction;
	uint16_t res;
	uint16_t packet_id;
	struct usb_spi_state *state = config->state;

	if (count < sizeof(packet->s.packet_id))
		return report_error(config->buffer, USB_SPI_UNKNOWN_ERROR,
				    state);

	packet_id = packet->s.packet_id;
	switch (state->raiden_state) {
	case RAIDEN_IDLE: {
		char *read_buf;
		size_t read_limit;

		if ((packet_id == USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG) &&
		    (count == sizeof(uint16_t))) {
			last_cmd.count = 0;
			memcpy(config->buffer, &config_rsp, sizeof(config_rsp));
			return sizeof(config_rsp);
		}

		/*
		 * If this is a restart request and the most recent command is
		 * available - use the saved command to start over.
		 */
		if ((packet_id == USB_SPI_PKT_ID_CMD_RESTART_RESPONSE) &&
		    last_cmd.count) {
			packet = &last_cmd.hdr;
			packet_id = last_cmd.hdr.s.packet_id;
			count = last_cmd.count;
			CPRINTS("%s: will restart the response id %d count %d",
				__func__, packet_id, count);
		}

		if ((packet_id != USB_SPI_PKT_ID_CMD_TRANSFER_START) ||
		    (count < sizeof(struct raiden_cmd_start_hdr)))
			return report_error(config->buffer,
					    USB_SPI_RUNT_PACKET, state);

		/* Preserve the request in case host asks to restart. */
		if (count <= (sizeof(last_cmd) - sizeof(last_cmd.count))) {
			memcpy(&last_cmd.hdr, packet, count);
			last_cmd.count = count;
		} else {
			last_cmd.count = 0;
		}

		/* This is request to start a new transaction. */
		state->total_write_count = packet->s.write_count;
		total_read_count = packet->s.read_count;

		/* Some basic validity checks. */
		if (total_read_count > config_rsp.max_read)
			return report_error(config->buffer,
					    USB_SPI_READ_COUNT_INVALID, state);

		if (state->total_write_count > config_rsp.max_write)
			return report_error(config->buffer,
					    USB_SPI_WRITE_COUNT_INVALID, state);

		/*
		 * If write count fits into one USB packet, the size of packet
		 * must match.
		 */
		if ((state->total_write_count <=
		     (USB_MAX_PACKET_SIZE -
		      sizeof(struct raiden_cmd_start_hdr))) &&
		    (state->total_write_count !=
		     (count - sizeof(struct raiden_cmd_start_hdr))))
			return report_error(config->buffer,
					    USB_SPI_WRITE_COUNT_INVALID, state);

		/*
		 * Transactions with write count exceeding one USB packet AND
		 * requiring a read are not supported.
		 */
		if (total_read_count &&
		    (state->total_write_count > START_PAYLOAD_SIZE))
			return report_error(config->buffer,
					    USB_SPI_WRITE_COUNT_INVALID, state);

		read_so_far = 0;
		state->wrote_so_far = 0;

		if (state->total_write_count > START_PAYLOAD_SIZE)
			this_write_count = START_PAYLOAD_SIZE;
		else
			this_write_count = state->total_write_count;

		/* Allocate buffer to store the entire requested read size. */
		if (total_read_count) {
			if (shared_mem_acquire(total_read_count, &read_buf) !=
			    EC_SUCCESS) {
				ccprintf("%s: Failed to allocate %zd bytes!\n",
					 __func__, total_read_count);
				return report_error(config->buffer,
						    USB_SPI_UNKNOWN_ERROR,
						    state);
			}
		}

		last_sub_transaction = false;

		/*
		 * This will send the write portion and read the entire read
		 * portion in multiple SPI subtransactions.
		 *
		 * In case the write PDU is split into multiple USB packets
		 * this will send the first packet and change state to
		 * RAIDEN_WRITING, where it will process the rest of USB
		 * packets of this PDU.
		 */
		while (this_write_count || (read_so_far != total_read_count)) {

			this_read_count = total_read_count - read_so_far;


			/*
			 * If there is a write portion, read limit needs to be
			 * reduced.
			 */
			read_limit = SPI_BUF_SIZE - this_write_count;

			/* Limit read count by SPI driver capacity. */
			if (this_read_count > read_limit)
				this_read_count = read_limit;

			/*
			 * This transaction is over when we have read as much
			 * as requested (which could be zero), AND the entire
			 * write portion fit into the USB payload.
			 */
			if (((this_read_count + read_so_far) ==
			     total_read_count) &&
			    (state->total_write_count <= START_PAYLOAD_SIZE))
				last_sub_transaction = true;

			res = usb_spi_map_error(spi_sub_transaction(
				SPI_FLASH_DEVICE,
				config->buffer +
					sizeof(struct raiden_cmd_start_hdr),
				this_write_count, read_buf + read_so_far,
				this_read_count, last_sub_transaction));
			if (res) {
				if (total_read_count)
					shared_mem_release(read_buf);
				rsp->value = res;
				rsp->packet_id =
					USB_SPI_PKT_ID_RSP_TRANSFER_START;
				return sizeof(*rsp);
			}

			rsp->packet_id =
				read_so_far ?
					USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE :
					USB_SPI_PKT_ID_RSP_TRANSFER_START;
			rsp->value = read_so_far;

			state->wrote_so_far += this_write_count;
			read_so_far += this_read_count;

			if (state->total_write_count > state->wrote_so_far) {
				state->raiden_state = RAIDEN_WRITING;
				return 0;
			}

			if (last_sub_transaction) {
				if (total_read_count) {
					ship_pdu(config, read_buf,
						 total_read_count);
					shared_mem_release(read_buf);
				}
				break;
			}

			/*
			 * Make sure this does not keep the loop going, we
			 * wrote all there was to write.
			 */
			this_write_count = 0;
		}

		/*
		 * If this was a pure write transaction and it fit into one
		 * USB packet - send a response to the host.
		 */
		if (!total_read_count && state->total_write_count &&
		    (state->raiden_state == RAIDEN_IDLE))
			return sizeof(*rsp);
		return 0;
	}
	case RAIDEN_WRITING:
		if ((packet_id != USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE) ||
		    (count <= sizeof(struct raiden_cmd_continue_hdr)))
			return report_error(config->buffer,
					    USB_SPI_RX_UNEXPECTED_PACKET,
					    state);

		if (packet->c.offset != state->wrote_so_far)
			return report_error(config->buffer,
					    USB_SPI_RX_UNEXPECTED_PACKET,
					    state);

		this_write_count =
			count - sizeof(struct raiden_cmd_continue_hdr);

		/*
		 * This is the last sub transaction if the remainder of data
		 * to write fits into USB packet, CS will have to be
		 * deasserted.
		 */
		last_sub_transaction =
			(this_write_count + state->wrote_so_far) ==
			state->total_write_count;

		res = usb_spi_map_error(spi_sub_transaction(
			SPI_FLASH_DEVICE,
			config->buffer + sizeof(struct raiden_response_hdr),
			this_write_count, config->buffer, 0,
			last_sub_transaction));
		if (res) {
			rsp->value = res;
			rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START;
			state->raiden_state = RAIDEN_IDLE;
			return sizeof(*rsp);
		}

		if (last_sub_transaction) {
			state->raiden_state = RAIDEN_IDLE;
			rsp->value = 0;
			rsp->packet_id = USB_SPI_PKT_ID_RSP_TRANSFER_START;
			return sizeof(*rsp);
		}
		state->wrote_so_far += this_write_count;
		return 0;
	}

	return 0;
}

void usb_spi_deferred(struct usb_spi_config const *config)
{
	uint16_t count;
	int rv = EC_SUCCESS;

	/*
	 * If our overall enabled state has changed we call the board specific
	 * enable or disable routines and save our new state.
	 */
	int enabled = !!(config->state->enabled_host &
			 config->state->enabled_device);

	if (enabled ^ config->state->enabled) {
		if (enabled)
			rv = usb_spi_board_enable(config->state->enabled_host);

		else
			usb_spi_board_disable();

		/* Only update our state if we were successful. */
		if (rv == EC_SUCCESS)
			config->state->enabled = enabled;
	}

	/*
	 * And if there is a USB packet waiting we process it and generate a
	 * response.
	 */
	count = usb_spi_read_packet(config);
	if (count == 0)
		return;

	if (!config->state->enabled || usb_spi_shortcut_active()) {
		struct raiden_response_hdr rsp_hdr = {
			USB_SPI_PKT_ID_RSP_TRANSFER_START, USB_SPI_DISABLED
		};
		memcpy(config->buffer, &rsp_hdr, sizeof(rsp_hdr));
		usb_spi_write_packet(config, sizeof(rsp_hdr));
		return;
	}

	/*
	 * Call the protocol handler and send back the last message generated
	 * by the handler.
	 */
	usb_spi_write_packet(config, process_raiden_packet(config, count));
}

static void usb_spi_written(struct consumer const *consumer, size_t count)
{
	struct usb_spi_config const *config =
		DOWNCAST(consumer, struct usb_spi_config, consumer);

	hook_call_deferred(config->deferred, 0);
}

struct consumer_ops const usb_spi_consumer_ops = {
	.written = usb_spi_written,
};

void usb_spi_enable(struct usb_spi_config const *config, int enabled)
{
	config->state->enabled_device = 0;
	if (enabled) {
#ifdef CONFIG_CASE_CLOSED_DEBUG_V1
		if (ccd_is_cap_enabled(CCD_CAP_AP_FLASH))
			config->state->enabled_device |= USB_SPI_AP;
		if (ccd_is_cap_enabled(CCD_CAP_EC_FLASH))
			config->state->enabled_device |= USB_SPI_EC;
#else
		config->state->enabled_device = USB_SPI_ALL;
#endif
	}

	hook_call_deferred(config->deferred, 0);
}