summaryrefslogtreecommitdiffstats
path: root/debian/grub-extras/disabled/gpxe/src/include/gpxe/spi.h
blob: 8e4a6763b957a35fefe86e96e7fed33fdbdeba84 (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
#ifndef _GPXE_SPI_H
#define _GPXE_SPI_H

/** @file
 *
 * SPI interface
 *
 */

FILE_LICENCE ( GPL2_OR_LATER );

#include <gpxe/nvs.h>

/**
 * @defgroup spicmds SPI commands
 * @{
 */

/** Write status register */
#define SPI_WRSR 0x01

/** Write data to memory array */
#define SPI_WRITE 0x02

/** Read data from memory array */
#define SPI_READ 0x03

/** Reset write enable latch */
#define SPI_WRDI 0x04

/** Read status register */
#define SPI_RDSR 0x05

/** Set write enable latch */
#define SPI_WREN 0x06

/**
 * @defgroup atmelcmds Atmel-specific SPI commands
 * @{
 */

/** Erase one sector in memory array (Not supported on all devices) */
#define ATMEL_SECTOR_ERASE 0x52

/** Erase all sections in memory array (Not supported on all devices) */
#define ATMEL_CHIP_ERASE 0x62

/** Read manufacturer and product ID (Not supported on all devices) */
#define ATMEL_RDID 0x15

/** @} */

/** @} */

/**
 * @defgroup spistatus SPI status register bits (not present on all devices)
 * @{
 */

/** Write-protect pin enabled */
#define SPI_STATUS_WPEN 0x80

/** Block protection bit 2 */
#define SPI_STATUS_BP2 0x10

/** Block protection bit 1 */
#define SPI_STATUS_BP1 0x08

/** Block protection bit 0 */
#define SPI_STATUS_BP0 0x04

/** State of the write enable latch */
#define SPI_STATUS_WEN 0x02

/** Device busy flag */
#define SPI_STATUS_NRDY 0x01

/** @} */

/**
 * An SPI device
 *
 * This data structure represents a physical SPI device attached to an
 * SPI bus.
 */
struct spi_device {
	/** NVS device */
	struct nvs_device nvs;
	/** SPI bus to which device is attached */
	struct spi_bus *bus;
	/** Slave number */
	unsigned int slave;
	/** Command length, in bits */
	unsigned int command_len;
	/** Address length, in bits */
	unsigned int address_len;
	/** Address is munged
	 *
	 * Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
	 * use bit 3 of the command byte as address bit A8, rather
	 * than having a two-byte address.  If this flag is set, then
	 * commands should be munged in this way.
	 */
	unsigned int munge_address : 1;
};

/**
 * SPI magic autodetection address length
 *
 * Set @c spi_device::address_len to @c SPI_AUTODETECT_ADDRESS_LEN if
 * the address length should be autodetected.
 */
#define SPI_AUTODETECT_ADDRESS_LEN 0

static inline __attribute__ (( always_inline )) struct spi_device *
nvs_to_spi ( struct nvs_device *nvs ) {
	return container_of ( nvs, struct spi_device, nvs );
}

/**
 * An SPI bus
 *
 * This data structure represents an SPI bus controller capable of
 * issuing commands to attached SPI devices.
 */
struct spi_bus {
	/** SPI interface mode
	 *
	 * This is the bitwise OR of zero or more of @c SPI_MODE_CPHA
	 * and @c SPI_MODE_CPOL.  It is also the number conventionally
	 * used to describe the SPI interface mode.  For example, SPI
	 * mode 1 is the mode in which CPOL=0 and CPHA=1, which
	 * therefore corresponds to a mode value of (0|SPI_MODE_CPHA)
	 * which, happily, equals 1.
	 */
	unsigned int mode;
	/**
	 * Read/write data via SPI bus
	 *
	 * @v bus		SPI bus
	 * @v device		SPI device
	 * @v command		Command
	 * @v address		Address to read/write (<0 for no address)
	 * @v data_out		TX data buffer (or NULL)
	 * @v data_in		RX data buffer (or NULL)
	 * @v len		Length of data buffer(s)
	 *
	 * This issues the specified command and optional address to
	 * the SPI device, then reads and/or writes data to/from the
	 * data buffers.
	 */
	int ( * rw ) ( struct spi_bus *bus, struct spi_device *device,
		       unsigned int command, int address,
		       const void *data_out, void *data_in, size_t len );
};

/** Clock phase (CPHA) mode bit
 *
 * Phase 0 is sample on rising edge, shift data on falling edge.
 *
 * Phase 1 is shift data on rising edge, sample data on falling edge.
 */
#define SPI_MODE_CPHA 0x01

/** Clock polarity (CPOL) mode bit
 *
 * This bit reflects the idle state of the clock line (SCLK).
 */
#define SPI_MODE_CPOL 0x02

/** Slave select polarity mode bit
 *
 * This bit reflects that active state of the slave select lines.  It
 * is not part of the normal SPI mode number (which covers only @c
 * SPI_MODE_CPOL and @c SPI_MODE_CPHA), but is included here for
 * convenience.
 */
#define SPI_MODE_SSPOL 0x10

/** Microwire-compatible mode
 *
 * This is SPI mode 1 (i.e. CPOL=0, CPHA=1), and is compatible with
 * the original Microwire protocol.
 */
#define SPI_MODE_MICROWIRE 1

/** Microwire/Plus-compatible mode
 *
 * This is SPI mode 0 (i.e. CPOL=0, CPHA=0), and is compatible with
 * the Microwire/Plus protocol
 */
#define SPI_MODE_MICROWIRE_PLUS 0

/** Threewire-compatible mode
 *
 * This mode is compatible with Atmel's series of "three-wire"
 * interfaces.
 */
#define SPI_MODE_THREEWIRE ( SPI_MODE_MICROWIRE_PLUS | SPI_MODE_SSPOL )

extern int spi_read ( struct nvs_device *nvs, unsigned int address,
		      void *data, size_t len );
extern int spi_write ( struct nvs_device *nvs, unsigned int address,
		       const void *data, size_t len );

/**
 * @defgroup spidevs SPI device types
 * @{
 */

static inline __attribute__ (( always_inline )) void
init_spi ( struct spi_device *device ) {
	device->nvs.word_len_log2 = 0;
	device->command_len = 8,
	device->nvs.read = spi_read;
	device->nvs.write = spi_write;	
}

/** Atmel AT25F1024 serial flash */
static inline __attribute__ (( always_inline )) void
init_at25f1024 ( struct spi_device *device ) {
	device->address_len = 24;
	device->nvs.size = ( 128 * 1024 );
	device->nvs.block_size = 256;
	init_spi ( device );
}

/** Atmel 25040 serial EEPROM */
static inline __attribute__ (( always_inline )) void
init_at25040 ( struct spi_device *device ) {
	device->address_len = 8;
	device->munge_address = 1;
	device->nvs.size = 512;
	device->nvs.block_size = 8;
	init_spi ( device );
}

/** ST M25P32 serial flash */
static inline __attribute__ (( always_inline )) void
init_m25p32 ( struct spi_device *device ) {
	device->address_len = 24;
	device->nvs.size = ( 4 * 1024 * 1024 );
	device->nvs.block_size = 256;
	init_spi ( device );
}

/** Microchip 25XX640 serial EEPROM */
static inline __attribute__ (( always_inline )) void
init_mc25xx640 ( struct spi_device *device ) {
	device->address_len = 16;
	device->nvs.size = ( 8 * 1024 );
	device->nvs.block_size = 32;
	init_spi ( device );
}

/** @} */

#endif /* _GPXE_SPI_H */