File indexing completed on 2025-05-11 08:24:05
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <bsp.h>
0030
0031 #include <rtems/irq-extension.h>
0032 #include <sys/param.h> /* MAX() */
0033
0034 #include <dev/spi/spi.h>
0035 #include <dev/spi/xilinx-axi-spi.h>
0036 #include <dev/spi/xilinx-axi-spi-regs.h>
0037
0038 #define XILINX_AXI_SPI_CS_NONE 0xFF
0039
0040 typedef struct xilinx_axi_spi_bus xilinx_axi_spi_bus;
0041
0042 struct xilinx_axi_spi_bus {
0043 spi_bus base;
0044 volatile xilinx_axi_spi *regs;
0045 uint32_t fifo_size;
0046 uint32_t num_cs;
0047 uint32_t msg_todo;
0048 const spi_ioc_transfer *msg;
0049 uint32_t todo;
0050 uint32_t in_transfer;
0051 uint8_t *rx_buf;
0052 const uint8_t *tx_buf;
0053 rtems_id task_id;
0054 rtems_vector_number irq;
0055 };
0056
0057
0058 static void xilinx_axi_spi_disable_interrupts(volatile xilinx_axi_spi *regs)
0059 {
0060 regs->globalirq = 0;
0061 regs->irqenable = 0;
0062 }
0063
0064 static bool xilinx_axi_spi_rx_fifo_not_empty(volatile xilinx_axi_spi *regs)
0065 {
0066 return (regs->status & XILINX_AXI_SPI_STATUS_RXEMPTY) == 0;
0067 }
0068
0069 static void xilinx_axi_spi_reset(xilinx_axi_spi_bus *bus)
0070 {
0071 volatile xilinx_axi_spi *regs = bus->regs;
0072 uint32_t control;
0073
0074
0075 regs->reset = XILINX_AXI_SPI_RESET;
0076
0077
0078 control = regs->control;
0079 control |= XILINX_AXI_SPI_CONTROL_MSTREN;
0080 regs->control = control;
0081 }
0082
0083 static void xilinx_axi_spi_done(xilinx_axi_spi_bus *bus)
0084 {
0085 volatile xilinx_axi_spi *regs = bus->regs;
0086 uint32_t control = regs->control;
0087 control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
0088 regs->control = control;
0089
0090 xilinx_axi_spi_disable_interrupts(regs);
0091 rtems_event_transient_send(bus->task_id);
0092 }
0093
0094 static void xilinx_axi_spi_push(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
0095 {
0096 while (bus->todo > 0 && bus->in_transfer < bus->fifo_size) {
0097 uint8_t val = 0;
0098 if (bus->tx_buf != NULL) {
0099 val = *bus->tx_buf;
0100 ++bus->tx_buf;
0101 }
0102
0103 --bus->todo;
0104 regs->txdata = val;
0105 ++bus->in_transfer;
0106 }
0107 }
0108
0109 static void
0110 xilinx_axi_spi_set_chipsel(xilinx_axi_spi_bus *bus, uint32_t cs)
0111 {
0112
0113 volatile xilinx_axi_spi *regs = bus->regs;
0114 uint32_t cs_bit = XILINX_AXI_SPI_CS_NONE;
0115
0116 if (cs != SPI_NO_CS && cs < bus->num_cs) {
0117 cs_bit &= ~(1<<cs);
0118 }
0119 bus->base.cs = cs;
0120
0121 regs->cs = cs_bit;
0122 }
0123
0124 static void xilinx_axi_spi_config(
0125 xilinx_axi_spi_bus *bus,
0126 volatile xilinx_axi_spi *regs,
0127 uint32_t mode,
0128 uint8_t cs
0129 )
0130 {
0131 spi_bus *base = &bus->base;
0132 uint32_t control = regs->control;
0133
0134 control &= ~XILINX_AXI_SPI_CONTROL_SPIEN;
0135 regs->control = control;
0136
0137 if ((mode & SPI_CPHA) != 0) {
0138 control |= XILINX_AXI_SPI_CONTROL_CPHA;
0139 } else {
0140 control &= ~XILINX_AXI_SPI_CONTROL_CPHA;
0141 }
0142
0143 if ((mode & SPI_CPOL) != 0) {
0144 control |= XILINX_AXI_SPI_CONTROL_CPOL;
0145 } else {
0146 control &= ~XILINX_AXI_SPI_CONTROL_CPOL;
0147 }
0148
0149 if ((mode & SPI_LOOP) != 0) {
0150 control |= XILINX_AXI_SPI_CONTROL_LOOP;
0151 } else {
0152 control &= ~XILINX_AXI_SPI_CONTROL_LOOP;
0153 }
0154
0155 regs->control = control;
0156 xilinx_axi_spi_set_chipsel(bus, cs);
0157
0158 base->mode = mode;
0159 base->cs = cs;
0160
0161 }
0162
0163 static void
0164 xilinx_axi_spi_next_msg(xilinx_axi_spi_bus *bus, volatile xilinx_axi_spi *regs)
0165 {
0166 uint32_t control = regs->control;
0167 control |= XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT
0168 | XILINX_AXI_SPI_CONTROL_RX_FIFO_RESET
0169 | XILINX_AXI_SPI_CONTROL_TX_FIFO_RESET;
0170 regs->control = control;
0171
0172 if (bus->msg_todo > 0) {
0173 const spi_ioc_transfer *msg;
0174 spi_bus *base = &bus->base;
0175
0176 msg = bus->msg;
0177
0178 if (
0179 msg->mode != base->mode
0180 || msg->cs != base->cs
0181 ) {
0182 xilinx_axi_spi_config(
0183 bus,
0184 regs,
0185 msg->mode,
0186 msg->cs
0187 );
0188 }
0189
0190 if ((msg->mode & SPI_NO_CS) != 0) {
0191 xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
0192 }
0193
0194 bus->todo = msg->len;
0195 bus->rx_buf = msg->rx_buf;
0196 bus->tx_buf = msg->tx_buf;
0197 xilinx_axi_spi_push(bus, regs);
0198
0199 xilinx_axi_spi_disable_interrupts(regs);
0200 if (
0201 bus->todo < bus->fifo_size
0202 || bus->fifo_size == 1) {
0203
0204 regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
0205
0206 } else {
0207
0208 regs->irqenable = XILINX_AXI_SPI_IRQ_TXHALF;
0209 }
0210 regs->globalirq = XILINX_AXI_SPI_GLOBAL_IRQ_ENABLE;
0211 control = regs->control;
0212 control |= XILINX_AXI_SPI_CONTROL_SPIEN;
0213 control &= ~XILINX_AXI_SPI_CONTROL_MST_TRANS_INHIBIT;
0214 regs->control = control;
0215 } else {
0216 xilinx_axi_spi_done(bus);
0217 }
0218 }
0219
0220 static void xilinx_axi_spi_interrupt(void *arg)
0221 {
0222 xilinx_axi_spi_bus *bus;
0223 volatile xilinx_axi_spi *regs;
0224
0225 bus = arg;
0226 regs = bus->regs;
0227
0228
0229 regs->irqstatus = regs->irqenable;
0230
0231 while (xilinx_axi_spi_rx_fifo_not_empty(regs)) {
0232 uint32_t val = regs->rxdata;
0233 if (bus->rx_buf != NULL) {
0234 *bus->rx_buf = (uint8_t)val;
0235 ++bus->rx_buf;
0236 }
0237 --bus->in_transfer;
0238 }
0239
0240 if (bus->todo > 0) {
0241 xilinx_axi_spi_push(bus, regs);
0242 } else if (bus->in_transfer > 0) {
0243
0244 regs->irqenable = XILINX_AXI_SPI_IRQ_TXEMPTY;
0245 } else {
0246 --bus->msg_todo;
0247 ++bus->msg;
0248 xilinx_axi_spi_next_msg(bus, regs);
0249 }
0250 }
0251
0252 static int xilinx_axi_spi_check_messages(
0253 xilinx_axi_spi_bus *bus,
0254 const spi_ioc_transfer *msg,
0255 uint32_t size)
0256 {
0257 while(size > 0) {
0258 if (msg->bits_per_word != 8) {
0259 return -EINVAL;
0260 }
0261 if ((msg->mode &
0262 ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
0263 return -EINVAL;
0264 }
0265 if ((msg->mode & SPI_NO_CS) == 0 &&
0266 (msg->cs > bus->num_cs)) {
0267 return -EINVAL;
0268 }
0269
0270 ++msg;
0271 --size;
0272 }
0273
0274 return 0;
0275 }
0276
0277 static int xilinx_axi_spi_transfer(
0278 spi_bus *base,
0279 const spi_ioc_transfer *msgs,
0280 uint32_t n
0281 )
0282 {
0283 xilinx_axi_spi_bus *bus;
0284 int rv;
0285
0286 bus = (xilinx_axi_spi_bus *) base;
0287
0288 rv = xilinx_axi_spi_check_messages(bus, msgs, n);
0289
0290 if (rv == 0) {
0291 bus->msg_todo = n;
0292 bus->msg = &msgs[0];
0293 bus->task_id = rtems_task_self();
0294
0295 xilinx_axi_spi_next_msg(bus, bus->regs);
0296 rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0297 xilinx_axi_spi_set_chipsel(bus, XILINX_AXI_SPI_CS_NONE);
0298 }
0299 return rv;
0300 }
0301
0302 static void xilinx_axi_spi_destroy(spi_bus *base)
0303 {
0304 xilinx_axi_spi_bus *bus;
0305
0306 bus = (xilinx_axi_spi_bus *) base;
0307 rtems_interrupt_handler_remove(bus->irq, xilinx_axi_spi_interrupt, bus);
0308 spi_bus_destroy_and_free(&bus->base);
0309 }
0310
0311 static int xilinx_axi_spi_setup(spi_bus *base)
0312 {
0313 xilinx_axi_spi_bus *bus;
0314 uint32_t mode = base->mode;
0315
0316 bus = (xilinx_axi_spi_bus *) base;
0317
0318 if (bus->base.bits_per_word > 8) {
0319 return -EINVAL;
0320 }
0321
0322
0323 if (mode & SPI_CS_HIGH) {
0324 return -EINVAL;
0325 }
0326
0327 xilinx_axi_spi_config(
0328 bus,
0329 bus->regs,
0330 base->mode,
0331 base->cs
0332 );
0333 return 0;
0334 }
0335
0336 int spi_bus_register_xilinx_axi(
0337 const char *bus_path,
0338 uintptr_t register_base,
0339 uint32_t fifo_size,
0340 uint32_t num_cs,
0341 rtems_vector_number irq)
0342 {
0343 xilinx_axi_spi_bus *bus;
0344 spi_bus *base;
0345 int sc;
0346
0347 if (fifo_size != 0 && fifo_size != 16 && fifo_size != 256) {
0348 return -1;
0349 }
0350
0351 if (num_cs > 32) {
0352 return -1;
0353 }
0354
0355 bus = (xilinx_axi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
0356 if (bus == NULL){
0357 return -1;
0358 }
0359
0360 base = &bus->base;
0361 bus->regs = (volatile xilinx_axi_spi *) register_base;
0362 bus->irq = irq;
0363 bus->num_cs = num_cs;
0364
0365
0366
0367
0368 if (fifo_size == 0) {
0369 bus->fifo_size = 1;
0370 } else {
0371 bus->fifo_size = fifo_size;
0372 }
0373
0374 base->cs = SPI_NO_CS;
0375
0376 xilinx_axi_spi_reset(bus);
0377 xilinx_axi_spi_config(
0378 bus,
0379 bus->regs,
0380 base->mode,
0381 base->cs
0382 );
0383
0384
0385 sc = rtems_interrupt_handler_install(
0386 bus->irq,
0387 "XSPI",
0388 RTEMS_INTERRUPT_UNIQUE,
0389 xilinx_axi_spi_interrupt,
0390 bus
0391 );
0392 if (sc != RTEMS_SUCCESSFUL) {
0393 (*bus->base.destroy)(&bus->base);
0394 rtems_set_errno_and_return_minus_one(EAGAIN);
0395 }
0396
0397 bus->base.transfer = xilinx_axi_spi_transfer;
0398 bus->base.destroy = xilinx_axi_spi_destroy;
0399 bus->base.setup = xilinx_axi_spi_setup;
0400
0401 return spi_bus_register(&bus->base, bus_path);
0402 }