diff options
| author | Michael Brown | 2006-12-04 16:36:51 +0100 |
|---|---|---|
| committer | Michael Brown | 2006-12-04 16:36:51 +0100 |
| commit | 931f94dca30b04f8303acdcfd08436e61a491a92 (patch) | |
| tree | b478b672436d696ce8d0a4d91c804d29a65db6a9 /src/include/gpxe | |
| parent | Force syntax-checking on assertions even in non-asserting builds. (diff) | |
| download | ipxe-931f94dca30b04f8303acdcfd08436e61a491a92.tar.gz ipxe-931f94dca30b04f8303acdcfd08436e61a491a92.tar.xz ipxe-931f94dca30b04f8303acdcfd08436e61a491a92.zip | |
Generalised the SPI abstraction layer to also be able to handle interfaces
that don't provide the full flexibility of a bit-bashing interface.
Temporarily hacked rtl8139.c to use the new interface.
Diffstat (limited to 'src/include/gpxe')
| -rw-r--r-- | src/include/gpxe/bitbash.h | 12 | ||||
| -rw-r--r-- | src/include/gpxe/spi.h | 239 | ||||
| -rw-r--r-- | src/include/gpxe/spi_bit.h | 45 | ||||
| -rw-r--r-- | src/include/gpxe/threewire.h | 84 |
4 files changed, 275 insertions, 105 deletions
diff --git a/src/include/gpxe/bitbash.h b/src/include/gpxe/bitbash.h index f479b5ad0..62bdce004 100644 --- a/src/include/gpxe/bitbash.h +++ b/src/include/gpxe/bitbash.h @@ -7,8 +7,10 @@ * */ -/** A bit-bashing interface */ -struct bit_basher { +struct bit_basher; + +/** Bit-bashing operations */ +struct bit_basher_operations { /** * Set/clear output bit * @@ -35,6 +37,12 @@ struct bit_basher { int ( * read ) ( struct bit_basher *basher, unsigned int bit_id ); }; +/** A bit-bashing interface */ +struct bit_basher { + /** Bit-bashing operations */ + struct bit_basher_operations *op; +}; + extern void write_bit ( struct bit_basher *basher, unsigned int bit_id, unsigned long data ); extern int read_bit ( struct bit_basher *basher, unsigned int bit_id ); diff --git a/src/include/gpxe/spi.h b/src/include/gpxe/spi.h index 3ea858467..93214063c 100644 --- a/src/include/gpxe/spi.h +++ b/src/include/gpxe/spi.h @@ -9,8 +9,170 @@ #include <gpxe/bitbash.h> -/** An SPI interface */ -struct spi_interface { +/** + * @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 + +/** @} */ + +struct spi_device; + +/** + * An SPI device type + * + * This data structure represents all the characteristics belonging to + * a particular type of SPI device, e.g. "an Atmel 251024 serial flash", + * or "a Microchip 25040 serial EEPROM". + */ +struct spi_device_type { + /** Word length, in bits */ + unsigned int word_len; + /** Device size (in words) */ + unsigned int size; + /** Data block size (in words) + * + * This is the block size used by the device. It must be a + * power of two. Data reads and writes must not cross a block + * boundary. + * + * Many devices allow reads to cross a block boundary, and + * restrict only writes. For the sake of simplicity, we + * assume that the same restriction applies to both reads and + * writes. + */ + unsigned int block_size; + /** 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; + /** Read data from device + * + * @v device SPI device + * @v address Address from which to read + * @v data Data buffer + * @v len Length of data to read, in @b words + * @ret rc Return status code + */ + int ( * read ) ( struct spi_device *device, unsigned int address, + void *data, unsigned int len ); + /** Write data to device + * + * @v device SPI device + * @v address Address to which to write + * @v data Data buffer + * @v len Length of data to write, in @b words + * @ret rc Return status code + */ + int ( * write ) ( struct spi_device *device, unsigned int address, + const void *data, unsigned int len ); +}; + +/** + * @defgroup spidevs SPI device types + * @{ + */ + +/** Atmel AT25010 serial EEPROM */ +#define AT25010 { \ + .word_len = 8, \ + .size = 128, \ + .block_size = 8, \ + .command_len = 8, \ + .address_len = 8, \ + } + +/** @} */ + +/** + * An SPI device + * + * This data structure represents a real, physical SPI device attached + * to an SPI controller. It comprises the device type plus + * instantiation-specific information such as the slave number. + */ +struct spi_device { + /** SPI device type */ + struct spi_device_type *type; + /** SPI bus to which device is attached */ + struct spi_bus *bus; + /** Slave number */ + unsigned int slave; +}; + +/** + * An SPI bus + * + * + */ +struct spi_bus { /** SPI interface mode * * This is the bitwise OR of zero or more of @c SPI_MODE_CPHA @@ -22,29 +184,26 @@ struct spi_interface { */ unsigned int mode; /** - * Select slave - * - * @v spi SPI interface - * @v slave Slave number - */ - void ( * select_slave ) ( struct spi_interface *spi, - unsigned int slave ); - /** - * Deselect slave - * - * @v spi SPI interface - */ - void ( * deselect_slave ) ( struct spi_interface *spi ); - /** - * Transfer bits over SPI bit-bashing interface + * Read/write data via SPI bus * - * @v spi SPI interface + * @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 transfer (in @b bits) + * @v len Length of transfer (in @b words) + * + * This issues the specified command and optional address to + * the SPI device, then reads and/or writes data to/from the + * data buffers. Note that the transfer length is measured in + * words, not in bytes. Some SPI devices have 16-bit word + * lengths; take care with these devices not to accidentally + * read or write twice as much data as intended. */ - void ( * transfer ) ( struct spi_interface *spi, const void *data_out, - void *data_in, unsigned int len ); + int ( * rw ) ( struct spi_bus *bus, struct spi_device *device, + unsigned int command, int address, + const void *data_out, void *data_in, unsigned int len ); }; /** Clock phase (CPHA) mode bit @@ -91,42 +250,4 @@ struct spi_interface { */ #define SPI_MODE_THREEWIRE ( SPI_MODE_MICROWIRE_PLUS | SPI_MODE_SSPOL ) -/** A bit-bashing SPI interface */ -struct spi_bit_basher { - /** SPI interface */ - struct spi_interface spi; - /** Bit-bashing interface */ - struct bit_basher basher; - /** Currently selected slave - * - * Valid only when a slave is actually selected. - */ - unsigned int slave; -}; - -/** Bit indices used for SPI bit-bashing interface */ -enum { - /** Serial clock */ - SPI_BIT_SCLK = 0, - /** Master Out Slave In */ - SPI_BIT_MOSI, - /** Master In Slave Out */ - SPI_BIT_MISO, - /** Slave 0 select */ - SPI_BIT_SS0, -}; - -/** - * Determine bit index for a particular slave - * - * @v slave Slave number - * @ret index Bit index (i.e. SPI_BIT_SSN, where N=slave) - */ -#define SPI_BIT_SS( slave ) ( SPI_BIT_SS0 + (slave) ) - -/** Delay between SCLK transitions */ -#define SPI_UDELAY 1 - -extern void init_spi_bit_basher ( struct spi_bit_basher *spibit ); - #endif /* _GPXE_SPI_H */ diff --git a/src/include/gpxe/spi_bit.h b/src/include/gpxe/spi_bit.h new file mode 100644 index 000000000..46f6af761 --- /dev/null +++ b/src/include/gpxe/spi_bit.h @@ -0,0 +1,45 @@ +#ifndef _GPXE_SPI_BIT_H +#define _GPXE_SPI_BIT_H + +/** @file + * + * SPI bit-bashing interface + * + */ + +#include <gpxe/spi.h> + +/** A bit-bashing SPI bus */ +struct spi_bit_basher { + /** SPI bus */ + struct spi_bus bus; + /** Bit-bashing interface */ + struct bit_basher basher; +}; + +/** Bit indices used for SPI bit-bashing interface */ +enum { + /** Serial clock */ + SPI_BIT_SCLK = 0, + /** Master Out Slave In */ + SPI_BIT_MOSI, + /** Master In Slave Out */ + SPI_BIT_MISO, + /** Slave 0 select */ + SPI_BIT_SS0, +}; + +/** + * Determine bit index for a particular slave + * + * @v slave Slave number + * @ret index Bit index (i.e. SPI_BIT_SSN, where N=slave) + */ +#define SPI_BIT_SS( slave ) ( SPI_BIT_SS0 + (slave) ) + +/** Delay between SCLK transitions */ +#define SPI_BIT_UDELAY 1 + +extern void init_spi_bit_basher ( struct spi_bit_basher *spibit ); + +#endif /* _GPXE_SPI_BIT_H */ diff --git a/src/include/gpxe/threewire.h b/src/include/gpxe/threewire.h index d9d885671..28cfea103 100644 --- a/src/include/gpxe/threewire.h +++ b/src/include/gpxe/threewire.h @@ -10,56 +10,52 @@ * support. */ -struct spi_interface; - -/** A three-wire device */ -struct threewire_device { - /** SPI interface to which device is attached */ - struct spi_interface *spi; - /** SPI slave number */ - unsigned int slave; - /** Address size (in bits) */ - unsigned int adrsize; - /** Data size (in bits) */ - unsigned int datasize; -}; +#include <gpxe/spi.h> /** - * Calculate read command for a specified address - * - * @v three Three-wire interface - * @v address Address - * @ret cmd Command + * @defgroup tcmds Three-wire commands + * @{ */ -static inline __attribute__ (( always_inline )) unsigned long -threewire_cmd_read ( struct threewire_device *three, unsigned long address ) { - return ( ( 0x6 << three->adrsize ) | address ); -} + +/** Read data from memory array */ +#define THREEWIRE_READ 0x6 + +/** @} */ /** - * Calculate command length - * - * @v three Three-wire interface - * @ret len Command length, in bits + * @defgroup spidevs SPI device types + * @{ */ -static inline __attribute__ (( always_inline )) unsigned int -threewire_cmd_len ( struct threewire_device *three ) { - return ( three->adrsize + 3 ); -} -/* Constants for some standard parts */ -#define AT93C46_ORG8_ADRSIZE 7 -#define AT93C46_ORG8_DATASIZE 8 -#define AT93C46_ORG16_ADRSIZE 6 -#define AT93C46_ORG16_DATASIZE 16 -#define AT93C46_UDELAY 1 -#define AT93C56_ORG8_ADRSIZE 9 -#define AT93C56_ORG8_DATASIZE 8 -#define AT93C56_ORG16_ADRSIZE 8 -#define AT93C56_ORG16_DATASIZE 16 -#define AT93C56_UDELAY 1 - -extern unsigned long threewire_read ( struct threewire_device *three, - unsigned long address ); +/** Atmel AT93C46 serial EEPROM + * + * @v org Word size (8 or 16) + */ +#define AT93C46( org ) { \ + .word_len = (org), \ + .size = ( 1024 / (org) ), \ + .block_size = 1, \ + .command_len = 3, \ + .address_len = ( ( (org) == 8 ) ? 7 : 6 ), \ + .read = threewire_read, \ + } + +/** Atmel AT93C56 serial EEPROM + * + * @v org Word size (8 or 16) + */ +#define AT93C56( org ) { \ + .word_len = (org), \ + .size = ( 2048 / (org) ), \ + .block_size = 1, \ + .command_len = 3, \ + .address_len = ( ( (org) == 8 ) ? 9 : 8 ), \ + .read = threewire_read, \ + } + +/** @} */ + +extern int threewire_read ( struct spi_device *device, unsigned int address, + void *data, unsigned int len ); #endif /* _GPXE_THREEWIRE_H */ |
