From 931f94dca30b04f8303acdcfd08436e61a491a92 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Dec 2006 15:36:51 +0000 Subject: [PATCH] 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. --- src/drivers/bitbash/bitbash.c | 4 +- src/drivers/bitbash/i2c_bit.c | 4 +- src/drivers/bitbash/spi_bit.c | 125 ++++++++++-------- src/drivers/net/etherfabric.c | 8 +- src/drivers/net/rtl8139.c | 50 ++++--- src/drivers/nvs/threewire.c | 39 +++--- src/include/gpxe/bitbash.h | 12 +- src/include/gpxe/spi.h | 239 +++++++++++++++++++++++++--------- src/include/gpxe/spi_bit.h | 45 +++++++ src/include/gpxe/threewire.h | 82 ++++++------ 10 files changed, 397 insertions(+), 211 deletions(-) create mode 100644 src/include/gpxe/spi_bit.h diff --git a/src/drivers/bitbash/bitbash.c b/src/drivers/bitbash/bitbash.c index 19add4ce..ec94feee 100644 --- a/src/drivers/bitbash/bitbash.c +++ b/src/drivers/bitbash/bitbash.c @@ -37,7 +37,7 @@ */ void write_bit ( struct bit_basher *basher, unsigned int bit_id, unsigned long data ) { - basher->write ( basher, bit_id, ( data ? -1UL : 0 ) ); + basher->op->write ( basher, bit_id, ( data ? -1UL : 0 ) ); } /** @@ -52,5 +52,5 @@ void write_bit ( struct bit_basher *basher, unsigned int bit_id, * it needs to apply. */ int read_bit ( struct bit_basher *basher, unsigned int bit_id ) { - return ( basher->read ( basher, bit_id ) ? -1UL : 0 ); + return ( basher->op->read ( basher, bit_id ) ? -1UL : 0 ); } diff --git a/src/drivers/bitbash/i2c_bit.c b/src/drivers/bitbash/i2c_bit.c index f0a9b936..d8fbacc0 100644 --- a/src/drivers/bitbash/i2c_bit.c +++ b/src/drivers/bitbash/i2c_bit.c @@ -314,8 +314,8 @@ static int i2c_bit_write ( struct i2c_interface *i2c, void init_i2c_bit_basher ( struct i2c_bit_basher *i2cbit ) { struct bit_basher *basher = &i2cbit->basher; - assert ( basher->read != NULL ); - assert ( basher->write != NULL ); + assert ( basher->op->read != NULL ); + assert ( basher->op->write != NULL ); i2cbit->i2c.read = i2c_bit_read; i2cbit->i2c.write = i2c_bit_write; i2c_stop ( basher ); diff --git a/src/drivers/bitbash/spi_bit.c b/src/drivers/bitbash/spi_bit.c index 20ad412c..462fd72e 100644 --- a/src/drivers/bitbash/spi_bit.c +++ b/src/drivers/bitbash/spi_bit.c @@ -19,11 +19,12 @@ #include #include #include +#include #include #include #include #include -#include +#include /** @file * @@ -32,65 +33,43 @@ */ /** Delay between SCLK changes and around SS changes */ -static void spi_delay ( void ) { - udelay ( SPI_UDELAY ); +static void spi_bit_delay ( void ) { + udelay ( SPI_BIT_UDELAY ); } +/** Chip select line will be asserted */ +#define SELECT_SLAVE 0 + +/** Chip select line will be deasserted */ +#define DESELECT_SLAVE SPI_MODE_SSPOL + /** * Select/deselect slave * - * @v spi SPI bit-bashing interface + * @v spibit SPI bit-bashing interface * @v slave Slave number * @v state Slave select state * - * @c state must be set to zero to select the specified slave, or to - * @c SPI_MODE_SSPOL to deselect the slave. + * @c state must be @c SELECT_SLAVE or @c DESELECT_SLAVE. */ static void spi_bit_set_slave_select ( struct spi_bit_basher *spibit, unsigned int slave, unsigned int state ) { struct bit_basher *basher = &spibit->basher; - state ^= ( spibit->spi.mode & SPI_MODE_SSPOL ); + state ^= ( spibit->bus.mode & SPI_MODE_SSPOL ); DBG ( "Setting slave %d select %s\n", slave, ( state ? "high" : "low" ) ); - spi_delay(); + spi_bit_delay(); write_bit ( basher, SPI_BIT_SS ( slave ), state ); - spi_delay(); + spi_bit_delay(); } /** - * Select slave + * Transfer bits over SPI bit-bashing bus * - * @v spi SPI interface - * @v slave Slave number - */ -static void spi_bit_select_slave ( struct spi_interface *spi, - unsigned int slave ) { - struct spi_bit_basher *spibit - = container_of ( spi, struct spi_bit_basher, spi ); - - spibit->slave = slave; - spi_bit_set_slave_select ( spibit, slave, 0 ); -} - -/** - * Deselect slave - * - * @v spi SPI interface - */ -static void spi_bit_deselect_slave ( struct spi_interface *spi ) { - struct spi_bit_basher *spibit - = container_of ( spi, struct spi_bit_basher, spi ); - - spi_bit_set_slave_select ( spibit, spibit->slave, SPI_MODE_SSPOL ); -} - -/** - * Transfer bits over SPI bit-bashing interface - * - * @v spi SPI interface + * @v bus SPI bus * @v data_out TX data buffer (or NULL) * @v data_in RX data buffer (or NULL) * @v len Length of transfer (in @b bits) @@ -101,19 +80,19 @@ static void spi_bit_deselect_slave ( struct spi_interface *spi ) { * NULL, then the data sent will be all zeroes. If @c data_in is * NULL, then the incoming data will be discarded. */ -static void spi_bit_transfer ( struct spi_interface *spi, const void *data_out, - void *data_in, unsigned int len ) { - struct spi_bit_basher *spibit - = container_of ( spi, struct spi_bit_basher, spi ); +static void spi_bit_transfer ( struct spi_bit_basher *spibit, + const void *data_out, void *data_in, + unsigned int len ) { + struct spi_bus *bus = &spibit->bus; struct bit_basher *basher = &spibit->basher; - unsigned int sclk = ( ( spi->mode & SPI_MODE_CPOL ) ? 1 : 0 ); - unsigned int cpha = ( ( spi->mode & SPI_MODE_CPHA ) ? 1 : 0 ); + unsigned int sclk = ( ( bus->mode & SPI_MODE_CPOL ) ? 1 : 0 ); + unsigned int cpha = ( ( bus->mode & SPI_MODE_CPHA ) ? 1 : 0 ); unsigned int offset; unsigned int mask; unsigned int bit; int step; - DBG ( "Transferring %d bits in mode %x\n", len, spi->mode ); + DBG ( "Transferring %d bits in mode %x\n", len, bus->mode ); for ( step = ( ( len * 2 ) - 1 ) ; step >= 0 ; step-- ) { /* Calculate byte offset within data and bit mask */ @@ -145,21 +124,65 @@ static void spi_bit_transfer ( struct spi_interface *spi, const void *data_out, } /* Toggle clock line */ - spi_delay(); + spi_bit_delay(); sclk = ~sclk; write_bit ( basher, SPI_BIT_SCLK, sclk ); } } +/** + * Read/write data via SPI bit-bashing 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 transfer (in @b words) + * @ret rc Return status code + */ +static int spi_bit_rw ( struct spi_bus *bus, struct spi_device *device, + unsigned int command, int address, + const void *data_out, void *data_in, + unsigned int len ) { + struct spi_bit_basher *spibit + = container_of ( bus, struct spi_bit_basher, bus ); + struct spi_device_type *devtype = device->type; + uint32_t tmp; + + /* Assert chip select on specified slave */ + spi_bit_set_slave_select ( spibit, device->slave, SELECT_SLAVE ); + + /* Transmit command */ + assert ( devtype->command_len <= ( 8 * sizeof ( tmp ) ) ); + tmp = cpu_to_le32 ( command ); + spi_bit_transfer ( spibit, &tmp, NULL, devtype->command_len ); + + /* Transmit address, if present */ + if ( address >= 0 ) { + assert ( devtype->address_len <= ( 8 * sizeof ( tmp ) ) ); + tmp = cpu_to_le32 ( address ); + spi_bit_transfer ( spibit, &tmp, NULL, devtype->address_len ); + } + + /* Transmit/receive data */ + spi_bit_transfer ( spibit, data_out, data_in, + ( len * devtype->word_len ) ); + + /* Deassert chip select on specified slave */ + spi_bit_set_slave_select ( spibit, device->slave, DESELECT_SLAVE ); + + return 0; +} + /** * Initialise SPI bit-bashing interface * * @v spibit SPI bit-bashing interface */ void init_spi_bit_basher ( struct spi_bit_basher *spibit ) { - assert ( &spibit->basher.read != NULL ); - assert ( &spibit->basher.write != NULL ); - spibit->spi.select_slave = spi_bit_select_slave; - spibit->spi.deselect_slave = spi_bit_deselect_slave; - spibit->spi.transfer = spi_bit_transfer; + assert ( &spibit->basher.op->read != NULL ); + assert ( &spibit->basher.op->write != NULL ); + spibit->bus.rw = spi_bit_rw; } diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index 1b5f29a7..9afe65df 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -1058,9 +1058,13 @@ static int ef1002_i2c_read_bit ( struct bit_basher *basher, return ( EFAB_DWORD_FIELD ( reg, EF1_EEPROM ) & mask ); } +static struct bit_basher_operations ef1002_basher_ops = { + .read = ef1002_i2c_read_bit, + .write = ef1002_i2c_write_bit, +}; + static void ef1002_init_eeprom ( struct efab_nic *efab ) { - efab->ef1002_i2c.basher.write = ef1002_i2c_write_bit; - efab->ef1002_i2c.basher.read = ef1002_i2c_read_bit; + efab->ef1002_i2c.basher.op = &ef1002_basher_ops; init_i2c_bit_basher ( &efab->ef1002_i2c ); efab->ef1002_eeprom.address = EF1_EEPROM_I2C_ID; } diff --git a/src/drivers/net/rtl8139.c b/src/drivers/net/rtl8139.c index d42d3c2d..c1a29e4f 100644 --- a/src/drivers/net/rtl8139.c +++ b/src/drivers/net/rtl8139.c @@ -77,7 +77,7 @@ #include #include #include -#include +#include #include #define TX_RING_SIZE 4 @@ -97,7 +97,7 @@ struct rtl8139_nic { struct rtl8139_tx tx; struct rtl8139_rx rx; struct spi_bit_basher spibit; - struct threewire_device eeprom; + struct spi_device eeprom; }; /* Tuning Parameters */ @@ -204,11 +204,6 @@ enum RxConfigBits { /* Offsets within EEPROM (these are word offsets) */ #define EE_MAC 7 -static inline struct rtl8139_nic * -basher_to_rtl ( struct bit_basher *basher ) { - return container_of ( basher, struct rtl8139_nic, spibit.basher ); -} - static const uint8_t rtl_ee_bits[] = { [SPI_BIT_SCLK] = EE_SK, [SPI_BIT_MOSI] = EE_DI, @@ -218,7 +213,8 @@ static const uint8_t rtl_ee_bits[] = { static int rtl_spi_read_bit ( struct bit_basher *basher, unsigned int bit_id ) { - struct rtl8139_nic *rtl = basher_to_rtl ( basher ); + struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, + spibit.basher ); uint8_t mask = rtl_ee_bits[bit_id]; uint8_t eereg; @@ -228,7 +224,8 @@ static int rtl_spi_read_bit ( struct bit_basher *basher, static void rtl_spi_write_bit ( struct bit_basher *basher, unsigned int bit_id, unsigned long data ) { - struct rtl8139_nic *rtl = basher_to_rtl ( basher ); + struct rtl8139_nic *rtl = container_of ( basher, struct rtl8139_nic, + spibit.basher ); uint8_t mask = rtl_ee_bits[bit_id]; uint8_t eereg; @@ -238,6 +235,14 @@ static void rtl_spi_write_bit ( struct bit_basher *basher, outb ( eereg, rtl->ioaddr + Cfg9346 ); } +static struct bit_basher_operations rtl_basher_ops = { + .read = rtl_spi_read_bit, + .write = rtl_spi_write_bit, +}; + +static struct spi_device_type rtl_ee9346 = AT93C46 ( 16 ); +static struct spi_device_type rtl_ee9356 = AT93C56 ( 16 ); + /** * Set up for EEPROM access * @@ -247,19 +252,15 @@ static void rtl_init_eeprom ( struct rtl8139_nic *rtl ) { int ee9356; /* Initialise three-wire bus */ - rtl->spibit.basher.read = rtl_spi_read_bit; - rtl->spibit.basher.write = rtl_spi_write_bit; - rtl->spibit.spi.mode = SPI_MODE_THREEWIRE; + rtl->spibit.basher.op = &rtl_basher_ops; + rtl->spibit.bus.mode = SPI_MODE_THREEWIRE; init_spi_bit_basher ( &rtl->spibit ); /* Detect EEPROM type and initialise three-wire device */ ee9356 = ( inw ( rtl->ioaddr + RxConfig ) & Eeprom9356 ); - DBG ( "EEPROM is an %s\n", ee9356 ? "AT93C56" : "AT93C46" ); - rtl->eeprom.adrsize = - ( ee9356 ? AT93C56_ORG16_ADRSIZE : AT93C46_ORG16_ADRSIZE ); - rtl->eeprom.datasize = - ( ee9356 ? AT93C56_ORG16_DATASIZE : AT93C46_ORG16_DATASIZE ); - rtl->eeprom.spi = &rtl->spibit.spi; + DBG ( "EEPROM is an %s\n", ( ee9356 ? "AT93C56" : "AT93C46" ) ); + rtl->eeprom.type = ( ee9356 ? &rtl_ee9356 : &rtl_ee9346 ); + rtl->eeprom.bus = &rtl->spibit.bus; } /** @@ -269,18 +270,15 @@ static void rtl_init_eeprom ( struct rtl8139_nic *rtl ) { * @v mac_addr Buffer to contain MAC address (ETH_ALEN bytes) */ static void rtl_read_mac ( struct rtl8139_nic *rtl, uint8_t *mac_addr ) { - union { - uint16_t word; - uint8_t bytes[2]; - } u; + + struct spi_device *device = &rtl->eeprom; int i; DBG ( "MAC address is " ); for ( i = EE_MAC ; i < ( EE_MAC + ( ETH_ALEN / 2 ) ) ; i++ ) { - u.word = cpu_to_le16 ( threewire_read ( &rtl->eeprom, i ) ); - *mac_addr++ = u.bytes[0]; - *mac_addr++ = u.bytes[1]; - DBG ( "%02x%02x", u.bytes[0], u.bytes[1] ); + device->type->read ( device, i, mac_addr, 1 ); + DBG ( "%02x%02x", mac_addr[0], mac_addr[1] ); + mac_addr += 2; } DBG ( "\n" ); } diff --git a/src/drivers/nvs/threewire.c b/src/drivers/nvs/threewire.c index 92f9a24b..fd360037 100644 --- a/src/drivers/nvs/threewire.c +++ b/src/drivers/nvs/threewire.c @@ -17,8 +17,7 @@ */ #include -#include -#include +#include #include /** @file @@ -27,31 +26,23 @@ * */ -/** - * Read from a three-wire device +/** Read data from three-wire device * - * @v three Three-wire device - * @v address Address - * @ret data Data + * @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 */ -unsigned long threewire_read ( struct threewire_device *three, - unsigned long address ) { - struct spi_interface *spi = three->spi; - uint32_t data; +int threewire_read ( struct spi_device *device, unsigned int address, + void *data, unsigned int len ) { + struct spi_bus *bus = device->bus; - /* Activate chip select line */ - spi->select_slave ( spi, three->slave ); + assert ( bus->mode == SPI_MODE_THREEWIRE ); - /* Send command and address */ - data = cpu_to_le32 ( threewire_cmd_read ( three, address ) ); - spi->transfer ( spi, &data, NULL, threewire_cmd_len ( three ) ); - - /* Read back data */ - data = 0; - spi->transfer ( spi, NULL, &data, three->datasize ); + DBG ( "3wire %p reading words [%04x,%04x)\n", device, + address, ( address + len ) ); - /* Deactivate chip select line */ - spi->deselect_slave ( spi ); - - return le32_to_cpu ( data );; + return bus->rw ( bus, device, THREEWIRE_READ, address, + NULL, data, len ); } diff --git a/src/include/gpxe/bitbash.h b/src/include/gpxe/bitbash.h index f479b5ad..62bdce00 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 3ea85846..93214063 100644 --- a/src/include/gpxe/spi.h +++ b/src/include/gpxe/spi.h @@ -9,8 +9,170 @@ #include -/** 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 + * Read/write data via SPI bus * - * @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 - * - * @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 00000000..46f6af76 --- /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 + +/** 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 d9d88567..28cfea10 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 /** - * 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 +/** 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, \ + } -extern unsigned long threewire_read ( struct threewire_device *three, - unsigned long address ); +/** 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 */