Generalised the SPI abstraction layer to also be able to handle interfaces
authorMichael Brown <mcb30@etherboot.org>
Mon, 4 Dec 2006 15:36:51 +0000 (15:36 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 4 Dec 2006 15:36:51 +0000 (15:36 +0000)
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
src/drivers/bitbash/i2c_bit.c
src/drivers/bitbash/spi_bit.c
src/drivers/net/etherfabric.c
src/drivers/net/rtl8139.c
src/drivers/nvs/threewire.c
src/include/gpxe/bitbash.h
src/include/gpxe/spi.h
src/include/gpxe/spi_bit.h [new file with mode: 0644]
src/include/gpxe/threewire.h

index 19add4c..ec94fee 100644 (file)
@@ -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 );
 }
index f0a9b93..d8fbacc 100644 (file)
@@ -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 );
index 20ad412..462fd72 100644 (file)
 #include <stddef.h>
 #include <stdint.h>
 #include <string.h>
+#include <byteswap.h>
 #include <errno.h>
 #include <assert.h>
 #include <timer.h>
 #include <gpxe/bitbash.h>
-#include <gpxe/spi.h>
+#include <gpxe/spi_bit.h>
 
 /** @file
  *
  */
 
 /** 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();
-}
-
-/**
- * Select slave
- *
- * @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 );
+       spi_bit_delay();
 }
 
 /**
- * Deselect slave
+ * Transfer bits over SPI bit-bashing bus
  *
- * @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;
 }
index 1b5f29a..9afe65d 100644 (file)
@@ -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;
 }
index d42d3c2..c1a29e4 100644 (file)
@@ -77,7 +77,7 @@
 #include <gpxe/ethernet.h>
 #include <gpxe/pkbuff.h>
 #include <gpxe/netdevice.h>
-#include <gpxe/spi.h>
+#include <gpxe/spi_bit.h>
 #include <gpxe/threewire.h>
 
 #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" );
 }
index 92f9a24..fd36003 100644 (file)
@@ -17,8 +17,7 @@
  */
 
 #include <stddef.h>
-#include <byteswap.h>
-#include <gpxe/spi.h>
+#include <assert.h>
 #include <gpxe/threewire.h>
 
 /** @file
  *
  */
 
-/**
- * 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 );
 }
index f479b5a..62bdce0 100644 (file)
@@ -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 );
index 3ea8584..9321406 100644 (file)
@@ -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 (file)
index 0000000..46f6af7
--- /dev/null
@@ -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 */
index d9d8856..28cfea1 100644 (file)
  * 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 */