Browse Source

Support cards such as natsemi which treat the data as little-endian

(i.e. LSB transmitted first on the wire), even though SPI commands and
addresses always have to be big-endian.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
95cb7aaacf
2 changed files with 39 additions and 17 deletions
  1. 24
    17
      src/drivers/bitbash/spi_bit.c
  2. 15
    0
      src/include/gpxe/spi_bit.h

+ 24
- 17
src/drivers/bitbash/spi_bit.c View File

@@ -73,6 +73,7 @@ static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
73 73
  * @v data_out		TX data buffer (or NULL)
74 74
  * @v data_in		RX data buffer (or NULL)
75 75
  * @v len		Length of transfer (in @b bits)
76
+ * @v endianness	Endianness of this data transfer
76 77
  *
77 78
  * This issues @c len clock cycles on the SPI bus, shifting out data
78 79
  * from the @c data_out buffer to the MOSI line and shifting in data
@@ -82,31 +83,34 @@ static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit,
82 83
  */
83 84
 static void spi_bit_transfer ( struct spi_bit_basher *spibit,
84 85
 			       const void *data_out, void *data_in,
85
-			       unsigned int len ) {
86
+			       unsigned int len, int endianness ) {
86 87
 	struct spi_bus *bus = &spibit->bus;
87 88
 	struct bit_basher *basher = &spibit->basher;
88 89
 	unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 );
89 90
 	unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 );
90
-	unsigned int offset;
91
-	unsigned int mask;
91
+	unsigned int bit_offset;
92
+	unsigned int byte_offset;
93
+	unsigned int byte_mask;
92 94
 	unsigned int bit;
93
-	int step;
95
+	unsigned int step;
94 96
 
95 97
 	DBG ( "Transferring %d bits in mode %x\n", len, bus->mode );
96 98
 
97
-	for ( step = ( ( len * 2 ) - 1 ) ; step >= 0 ; step-- ) {
98
-		/* Calculate byte offset within data and bit mask */
99
-		offset = ( step / 16 );
100
-		mask = ( 1 << ( ( step % 16 ) / 2 ) );
101
-		
99
+	for ( step = 0 ; step < ( len * 2 ) ; step++ ) {
100
+		/* Calculate byte offset and byte mask */
101
+		bit_offset = ( ( endianness == SPI_BIT_BIG_ENDIAN ) ?
102
+			       ( len - ( step / 2 ) - 1 ) : ( step / 2 ) );
103
+		byte_offset = ( bit_offset / 8 );
104
+		byte_mask = ( 1 << ( bit_offset % 8 ) );
105
+
102 106
 		/* Shift data in or out */
103 107
 		if ( sclk == cpha ) {
104 108
 			const uint8_t *byte;
105 109
 
106 110
 			/* Shift data out */
107 111
 			if ( data_out ) {
108
-				byte = ( data_out + offset );
109
-				bit = ( *byte & mask );
112
+				byte = ( data_out + byte_offset );
113
+				bit = ( *byte & byte_mask );
110 114
 			} else {
111 115
 				bit = 0;
112 116
 			}
@@ -117,9 +121,9 @@ static void spi_bit_transfer ( struct spi_bit_basher *spibit,
117 121
 			/* Shift data in */
118 122
 			bit = read_bit ( basher, SPI_BIT_MISO );
119 123
 			if ( data_in ) {
120
-				byte = ( data_in + offset );
121
-				*byte &= ~mask;
122
-				*byte |= ( bit & mask );
124
+				byte = ( data_in + byte_offset );
125
+				*byte &= ~byte_mask;
126
+				*byte |= ( bit & byte_mask );
123 127
 			}
124 128
 		}
125 129
 
@@ -155,17 +159,20 @@ static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device,
155 159
 	/* Transmit command */
156 160
 	assert ( device->command_len <= ( 8 * sizeof ( tmp ) ) );
157 161
 	tmp = cpu_to_le32 ( command );
158
-	spi_bit_transfer ( spibit, &tmp, NULL, device->command_len );
162
+	spi_bit_transfer ( spibit, &tmp, NULL, device->command_len,
163
+			   SPI_BIT_BIG_ENDIAN );
159 164
 
160 165
 	/* Transmit address, if present */
161 166
 	if ( address >= 0 ) {
162 167
 		assert ( device->address_len <= ( 8 * sizeof ( tmp ) ) );
163 168
 		tmp = cpu_to_le32 ( address );
164
-		spi_bit_transfer ( spibit, &tmp, NULL, device->address_len );
169
+		spi_bit_transfer ( spibit, &tmp, NULL, device->address_len,
170
+				   SPI_BIT_BIG_ENDIAN );
165 171
 	}
166 172
 
167 173
 	/* Transmit/receive data */
168
-	spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ) );
174
+	spi_bit_transfer ( spibit, data_out, data_in, ( len * 8 ),
175
+			   spibit->endianness );
169 176
 
170 177
 	/* Deassert chip select on specified slave */
171 178
 	spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE );

+ 15
- 0
src/include/gpxe/spi_bit.h View File

@@ -16,6 +16,15 @@ struct spi_bit_basher {
16 16
 	struct spi_bus bus;
17 17
 	/** Bit-bashing interface */
18 18
 	struct bit_basher basher;
19
+	/** Endianness of data
20
+	 *
21
+	 * SPI commands and addresses are always big-endian (i.e. MSB
22
+	 * transmitted first on the wire), but some cards
23
+	 * (e.g. natsemi) choose to regard the data stored in the
24
+	 * EEPROM as little-endian (i.e. LSB transmitted first on the
25
+	 * wire).
26
+	 */
27
+	int endianness;
19 28
 };
20 29
 
21 30
 /** Bit indices used for SPI bit-bashing interface */
@@ -41,6 +50,12 @@ enum {
41 50
 /** Delay between SCLK transitions */
42 51
 #define SPI_BIT_UDELAY 1
43 52
 
53
+/** SPI bit basher treats data as big-endian */
54
+#define SPI_BIT_BIG_ENDIAN 0
55
+
56
+/** SPI bit basher treats data as little-endian */
57
+#define SPI_BIT_LITTLE_ENDIAN 1
58
+
44 59
 extern void init_spi_bit_basher ( struct spi_bit_basher *spibit );
45 60
 
46 61
 #endif /* _GPXE_SPI_BIT_H */

Loading…
Cancel
Save