Abstracted out part of the concept of an SPI device to a generalised NVS

device.

Separated the mechanisms of non-volatile storage access and non-volatile
stored options.
This commit is contained in:
Michael Brown
2006-12-04 18:23:06 +00:00
parent dc06c895fc
commit 946967f09c
12 changed files with 275 additions and 240 deletions

21
src/include/gpxe/nvo.h Normal file
View File

@@ -0,0 +1,21 @@
#ifndef _GPXE_NVO_H
#define _GPXE_NVO_H
/** @file
*
* Non-volatile stored options
*
*/
struct nvs_device;
struct dhcp_option_block;
struct nvs_options {
struct nvs_device *nvs;
struct dhcp_option_block *options;
};
extern int nvo_register ( struct nvs_options *nvo );
extern void nvo_unregister ( struct nvs_options *nvo );
#endif /* _GPXE_NVO_H */

View File

@@ -9,22 +9,53 @@
#include <stdint.h>
struct nvs_operations;
/** A non-volatile storage device */
struct nvs_device {
struct dhcp_option_block *options;
size_t len;
struct nvs_operations *op;
};
struct nvs_operations {
int ( * read ) ( struct nvs_device *nvs, unsigned int offset,
/** 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;
/** Read data from device
*
* @v nvs NVS device
* @v address Address from which to read
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*
* Reads may not cross a block boundary.
*/
int ( * read ) ( struct nvs_device *nvs, unsigned int address,
void *data, size_t len );
int ( * write ) ( struct nvs_device *nvs, unsigned int offset,
/** Write data to device
*
* @v nvs NVS device
* @v address Address to which to write
* @v data Data buffer
* @v len Length of data buffer
* @ret rc Return status code
*
* Writes may not cross a block boundary.
*/
int ( * write ) ( struct nvs_device *nvs, unsigned int address,
const void *data, size_t len );
};
extern int nvs_register ( struct nvs_device *nvs );
extern void nvs_unregister ( struct nvs_device *nvs );
extern int nvs_read ( struct nvs_device *nvs, unsigned int address,
void *data, size_t len );
extern int nvs_write ( struct nvs_device *nvs, unsigned int address,
const void *data, size_t len );
#endif /* _GPXE_NVS_H */

View File

@@ -7,7 +7,7 @@
*
*/
#include <gpxe/bitbash.h>
#include <gpxe/nvs.h>
/**
* @defgroup spicmds SPI commands
@@ -75,32 +75,19 @@
/** @} */
struct spi_device;
/**
* An SPI device type
* An SPI device
*
* 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".
* This data structure represents a physical SPI device attached to an
* SPI bus.
*/
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;
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 */
@@ -113,64 +100,18 @@ struct spi_device_type {
* 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 buffer
* @ret rc Return status code
*/
int ( * read ) ( struct spi_device *device, unsigned int address,
void *data, size_t 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 buffer
* @ret rc Return status code
*/
int ( * write ) ( struct spi_device *device, unsigned int address,
const void *data, size_t 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;
};
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

View File

@@ -8,6 +8,7 @@
*/
#include <gpxe/spi.h>
#include <gpxe/bitbash.h>
/** A bit-bashing SPI bus */
struct spi_bit_basher {

View File

@@ -22,40 +22,48 @@
/** @} */
extern int threewire_read ( struct nvs_device *nvs, unsigned int address,
void *data, size_t len );
/**
* @defgroup spidevs SPI device types
* @defgroup tdevs Three-wire device types
* @{
*/
/** 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, \
}
static inline __attribute__ (( always_inline )) void
init_at93cx6 ( struct spi_device *device, unsigned int organisation ) {
device->nvs.word_len = organisation;
device->nvs.block_size = 1;
device->command_len = 3,
device->nvs.read = threewire_read;
}
/** Atmel AT93C56 serial EEPROM
/**
* Initialise Atmel AT93C46 serial EEPROM
*
* @v org Word size (8 or 16)
* @v device SPI device
* @v organisation Word organisation (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, \
}
static inline __attribute__ (( always_inline )) void
init_at93c46 ( struct spi_device *device, unsigned int organisation ) {
device->nvs.size = ( 1024 / organisation );
device->address_len = ( ( organisation == 8 ) ? 7 : 6 );
init_at93cx6 ( device, organisation );
}
/**
* Initialise Atmel AT93C56 serial EEPROM
*
* @v device SPI device
* @v organisation Word organisation (8 or 16)
*/
static inline __attribute__ (( always_inline )) void
init_at93c56 ( struct spi_device *device, unsigned int organisation ) {
device->nvs.size = ( 2048 / organisation );
device->address_len = ( ( organisation == 8 ) ? 9 : 8 );
init_at93cx6 ( device, organisation );
}
/** @} */
extern int threewire_read ( struct spi_device *device, unsigned int address,
void *data, size_t len );
#endif /* _GPXE_THREEWIRE_H */