>> + >> +/* create a new spi bus */ >> +spi_bus *spi_init_bus(DeviceState *parent, int num_slaves, const char >> *name); >> +int spi_attach_slave(spi_bus *bus, SPISlave *s, int cs); >> + >> +/* change the chip select. Return 1 on failure. */ >> +int spi_set_cs(spi_bus *bus, int cs); >> +int spi_get_cs(spi_bus *bus); >> +SpiSlaveState spi_get_state(spi_bus *bus); >> + >> +SpiSlaveState spi_send(spi_bus *bus, uint32_t data, int len); >> +SpiSlaveState spi_recv(spi_bus *bus, uint32_t *data); > > I'm no SPI expert, but a bit of googling suggests that it's > a synchronous duplex bus, so you always send a byte of data > to the slave and get one back in return (even if for some slaves > it might be random garbage).
Hi Peter, Thats not correct, SPI txs can trigger rxs of arbitrary length. Heres the data sheet for the m25p80 spi flash device: www.datasheetcatalog.org/datasheet/stmicroelectronics/8495.pdf. Figure 12, page 15 is a good example of this, the master transmits 4 bytes back to back for a opcode and an addresses, and the slave bursts the entire playload back. To hack around this, Edgar had to put escape sequences in that txrx api to flag all the txs and rxs for devices and controllers respecitvely, ive attached a file (xilinx_spi.h) which is Eds original hack of the txrx interface that im trying to fix here by changing the API. This api allows controllers to manage that without dummy txs or invalid rxs. The current OMAP SPI devices in QEMU > master have an API that reflects this: eg tsc210x_txrx() which > takes an input value and returns an output value. This API > seems to have separate send and recv methods -- can you explain > how this works? > Each send or receive command will return a enum SPISlaveState. If SPI_DATA_PENDING the master can receive a byte back from the slave with recv. If that recv returns SPI_DATA_PENDING then the master should recieve again i.e. recv should be looped. Heres how its handled in the xilinx_spi controller: uint32_t value; SpiSlaveState st; while (!txfifo_empty(s)) { value = txfifo_get(s); DB_PRINT("data transfer:%x\n", value); st = spi_send(s->spi, value, 8); while (st == SPI_DATA_PENDING) { uint32_t d; st = spi_recv(s->spi, &d); rxfifo_put(s, d); } } The inner loop is basically a poll, waiting for the recv to return != SPI_DATA_PENDING. > (Incidentally if we're going to qdevify the SPI interface we > should also convert the existing omap SPI devices...) Yes I havent looked into the details, but shouldnt be too much work. I can provide the diff for the m25p80 to change it over from txrx style to this, to give an idea of the change pattern. Little bit of this that and the other in the machine models too. If we really want to minimise work, the old txrx function can be added (to spi.c) as something like: uint32_t spi_txrx(spi_bus *bus, uint32_t data) { uint32_t ret; assert(spi_send(bus, data) == SPI_DATA_PENDING); assert(spi_recv(bus, &ret) == SPI_DATA_IDLE); return ret; } > > thanks > -- PMM Regards, Peter
/* SPI connection. */ #define SPI_LEN_UNSELECT -1 /* Used to simulate CS. */ #define SPI_LEN_NODATA 0 /* Used to read data without writing. */ #define SPI_DATA_EMPTY (1 << 31) #define SPI_DATA_PENDING (1 << 30) static inline int xlx_spi_valid_data(uint32_t data) { return !(data & SPI_DATA_EMPTY); } static inline int xlx_spi_data_pending(uint32_t data) { return data & SPI_DATA_PENDING; } typedef uint32_t (*spi_push_fn)(void *opaque, uint32_t data, int len); struct xlx_spi_ch { void *slave[32]; spi_push_fn txrx[32]; }; struct xlx_spi_device { void * (*init) (void); spi_push_fn txrx; const char * device_name; }; static inline void xlx_spi_connect_slave(struct xlx_spi_ch *spich, int nr, void *slave, spi_push_fn f) { spich->slave[nr] = slave; spich->txrx[nr] = f; } static inline uint32_t xlx_spi_txrx(struct xlx_spi_ch *spich, int nr, uint32_t data, int len) { return spich->txrx[nr](spich->slave[nr], data, len); }