Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:42

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsAArch64Raspberrypi4
0007  *
0008  * @brief SPI Driver
0009  */
0010 
0011 /*
0012  * Copyright (C) 2024 Ning Yang
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #include <bsp/irq.h>
0037 #include <bsp/raspberrypi.h>
0038 #include <bsp/raspberrypi-spi.h>
0039 #include <bsp/rpi-gpio.h>
0040 
0041 #include <dev/spi/spi.h>
0042 #include <bspopts.h>
0043 
0044 typedef struct {
0045   spi_bus base;
0046   volatile raspberrypi_spi *regs;
0047   const spi_ioc_transfer *msg;
0048   uint32_t msg_todo;
0049   uint8_t *rx_buf;
0050   const uint8_t *tx_buf;
0051   uint32_t todo;
0052   uint8_t num_cs;
0053   uint32_t in_transfer;
0054   rtems_id task_id;
0055   rtems_vector_number irq;
0056 }raspberrypi_spi_bus;
0057 
0058 static int raspberrypi_spi_check_msg(
0059   raspberrypi_spi_bus *bus,
0060   const spi_ioc_transfer *msg,
0061   uint32_t n
0062 )
0063 {
0064   while (n > 0) {
0065     if (msg->bits_per_word != 8) {
0066       return -EINVAL;
0067     }
0068 
0069     if ((msg->mode &
0070       ~(SPI_CPHA | SPI_CPOL | SPI_NO_CS)) != 0) {
0071       return -EINVAL;
0072     }
0073 
0074     if (msg->cs >= bus->num_cs) {
0075       return -EINVAL;
0076     }
0077 
0078     ++msg;
0079     --n;
0080   }
0081 
0082   return 0;
0083 }
0084 
0085 /* Calculates a clock divider to be used with the GPU core clock rate
0086  * to set a SPI clock rate the closest (<=) to a desired frequency. */
0087 static rtems_status_code rpi_spi_calculate_clock_divider(
0088   uint32_t clock_hz,
0089   uint16_t *clock_divider
0090 )
0091 {
0092   uint16_t divider;
0093   uint32_t clock_rate;
0094 
0095   /* Calculates an initial clock divider. */
0096   divider = GPU_CORE_CLOCK_RATE / clock_hz;
0097 
0098   /* Because the divider must be a power of two (as per the BCM2835 datasheet),
0099    * calculate the next greater power of two. */
0100   --divider;
0101 
0102   divider |= (divider >> 1);
0103   divider |= (divider >> 2);
0104   divider |= (divider >> 4);
0105   divider |= (divider >> 8);
0106 
0107   ++divider;
0108 
0109   clock_rate = GPU_CORE_CLOCK_RATE / divider;
0110 
0111   /* If the resulting clock rate is greater than the desired frequency,
0112    * try the next greater power of two divider. */
0113   while (clock_rate > clock_hz) {
0114     divider = (divider << 1);
0115 
0116     clock_rate = GPU_CORE_CLOCK_RATE / divider;
0117   }
0118 
0119   *clock_divider = divider;
0120 
0121   return RTEMS_SUCCESSFUL;
0122 }
0123 
0124 static int raspberrypi_spi_config(
0125   raspberrypi_spi_bus *bus,
0126   volatile raspberrypi_spi *regs,
0127   uint32_t speed_hz,
0128   uint32_t mode,
0129   uint8_t cs
0130 )
0131 {
0132   spi_bus *base = &bus->base;
0133   uint32_t spics = regs->spics;
0134   rtems_status_code sc;
0135   uint16_t clock_divider;
0136 
0137   /* Calculate the most appropriate clock divider. */
0138   sc = rpi_spi_calculate_clock_divider(speed_hz, &clock_divider);
0139   if (sc != RTEMS_SUCCESSFUL) {
0140     return sc;
0141   }
0142   /* Set the bus clock divider. */
0143   regs->spiclk = RPI_SPICLK_CDIV_SET(regs->spiclk, clock_divider);
0144 
0145   if ((mode & SPI_CPHA) != 0) {
0146     spics |= RPI_SPICS_CPHA;
0147   } else {
0148     spics &= ~RPI_SPICS_CPHA;
0149   }
0150 
0151   if ((mode & SPI_CPOL) != 0) {
0152     spics |= RPI_SPICS_CPOL;
0153   } else {
0154     spics &= ~RPI_SPICS_CPOL;
0155   }
0156 
0157   if ((mode & SPI_CS_HIGH) != 0) {
0158     spics |= RPI_SPICS_CSPOL;
0159   } else {
0160     spics &= ~RPI_SPICS_CSPOL;
0161   }
0162 
0163   spics = RPI_SPICS_CS_SET(spics, cs);
0164 
0165   regs->spics = spics;
0166 
0167   base->speed_hz = speed_hz;
0168   base->mode = mode;
0169   base->cs = cs;
0170   return 0;
0171 }
0172 
0173 #ifdef BSP_SPI_USE_INTERRUPTS
0174 static void raspberrypi_spi_done(raspberrypi_spi_bus *bus)
0175 {
0176   volatile raspberrypi_spi *regs;
0177   regs = bus->regs;
0178   regs->spics = regs->spics & ~RPI_SPICS_TA;
0179   rtems_event_transient_send(bus->task_id);
0180 }
0181 
0182 static bool raspberrpi_spi_TX_FULL(volatile raspberrypi_spi *regs)
0183 {
0184   return !(regs->spics & RPI_SPICS_TXD);
0185 }
0186 
0187 static void raspberrypi_spi_push(
0188   raspberrypi_spi_bus *bus, 
0189   volatile raspberrypi_spi *regs
0190 )
0191 {
0192   uint8_t val;
0193   while (bus->todo > 0 && !raspberrpi_spi_TX_FULL(regs)) {
0194     val = 0;
0195     if (bus->tx_buf != NULL) {
0196         val = *bus->tx_buf;
0197         ++bus->tx_buf;
0198     }
0199 
0200     --bus->todo;
0201     regs->spififo = val;
0202     ++bus->in_transfer;
0203   }
0204 }
0205 
0206 static void raspberrypi_spi_next_msg(raspberrypi_spi_bus *bus)
0207 {
0208   const spi_ioc_transfer *msg;
0209   spi_bus *base;
0210   volatile raspberrypi_spi *regs;
0211   regs=bus->regs;
0212 
0213   if (bus->msg_todo > 0) {
0214     base = &bus->base;
0215     msg = bus->msg;
0216 
0217     if (
0218       msg->speed_hz != base->speed_hz
0219       || msg->mode != base->mode
0220       || msg->cs != base->cs
0221       ) {
0222       raspberrypi_spi_config(
0223         bus,
0224         regs,
0225         msg->speed_hz,
0226         msg->mode,
0227         msg->cs
0228       );
0229     }
0230 
0231     bus->todo = msg->len;
0232     bus->rx_buf = msg->rx_buf;
0233     bus->tx_buf = msg->tx_buf;
0234     raspberrypi_spi_push(bus, regs);
0235   } else {
0236     raspberrypi_spi_done(bus);
0237   }
0238 }
0239 
0240 static void raspberrypi_spi_start(raspberrypi_spi_bus *bus)
0241 {
0242   volatile raspberrypi_spi *regs;
0243   regs = bus->regs;
0244 
0245   regs->spics = regs->spics | RPI_SPICS_INTR | RPI_SPICS_INTD;
0246   /* 
0247    * Set TA = 1. This will immediately trigger a first interrupt with 
0248    * DONE = 1. 
0249    */
0250   regs->spics = regs->spics | RPI_SPICS_TA;
0251 }
0252 
0253 static bool raspberrypi_spi_irq(volatile raspberrypi_spi *regs)
0254 {
0255   /* Check whether the interrupt is generated by this SPI device */
0256   if(regs->spics & RPI_SPICS_INTD && regs->spics & RPI_SPICS_DONE) {
0257     return 1;
0258   }
0259 
0260   if(regs->spics & RPI_SPICS_INTR && regs->spics & RPI_SPICS_RXR) {
0261     return 1;
0262   }
0263 
0264   return 0;
0265 }
0266 
0267 static void raspberrypi_spi_interrupt(void *arg)
0268 {
0269   raspberrypi_spi_bus *bus;
0270   volatile raspberrypi_spi *regs;
0271   uint32_t val;
0272   
0273   bus = arg;
0274   regs = bus->regs;
0275 
0276   if (raspberrypi_spi_irq(regs)) {
0277     
0278     if (bus->todo > 0) {
0279       raspberrypi_spi_push(bus, regs);
0280     } else {
0281       --bus->msg_todo;
0282       ++bus->msg;
0283       raspberrypi_spi_next_msg(bus);
0284     }
0285 
0286     while (regs->spics & RPI_SPICS_RXD && bus->in_transfer > 0) {
0287       /*  RX FIFO contains at least 1 byte. */
0288       val = regs->spififo;
0289       if (bus->rx_buf != NULL) {
0290           *bus->rx_buf = (uint8_t)val;
0291           ++bus->rx_buf;
0292       }
0293       --bus->in_transfer;
0294     }
0295         
0296   }
0297 }
0298 #else
0299 static void raspberrypi_spi_polling_tx_rx(raspberrypi_spi_bus *bus)
0300 {
0301   volatile raspberrypi_spi *regs = bus->regs;
0302 
0303   const unsigned char *sbuffer = bus->tx_buf;
0304   unsigned char *rbuffer;
0305   unsigned int size;
0306   unsigned int read_count, write_count;
0307   unsigned int data;
0308 
0309   while (bus->msg_todo) {
0310     rbuffer = bus->rx_buf;
0311     size = bus->todo;
0312 
0313     regs->spics = regs->spics | RPI_SPICS_CLEAR_RX | RPI_SPICS_CLEAR_TX 
0314                               | RPI_SPICS_TA;
0315 
0316     read_count = 0;
0317     write_count = 0;
0318 
0319     while (read_count < size || write_count < size) {
0320       if (write_count < size && regs->spics & RPI_SPICS_TXD) {
0321         if (sbuffer) {
0322           regs->spififo = *sbuffer++;
0323         } else {
0324           regs->spififo = 0;
0325         }
0326 
0327         write_count++;
0328       }
0329 
0330       if (read_count < size && regs->spics & RPI_SPICS_RXD) {
0331         data = regs->spififo;
0332 
0333         if (rbuffer) {
0334           *rbuffer++ = data;
0335         }
0336 
0337         read_count++;
0338       }
0339     }
0340 
0341     while (!(regs->spics & RPI_SPICS_DONE)) {
0342       /*wait*/
0343     }
0344     regs->spics = (regs->spics & ~RPI_SPICS_TA);
0345 
0346     bus->msg_todo--;
0347 
0348     bus->msg++;
0349     bus->rx_buf = bus->msg->rx_buf;
0350     bus->tx_buf = bus->msg->tx_buf;
0351     bus->todo = bus->msg->len;
0352   }
0353 }
0354 
0355 static void raspberrypi_spi_transfer_msg(
0356   raspberrypi_spi_bus *bus
0357 )
0358 {
0359   volatile raspberrypi_spi *regs = bus->regs;
0360   uint32_t msg_todo = bus->msg_todo;
0361   const spi_ioc_transfer *msg = bus->msg;
0362 
0363   if (msg_todo > 0) {
0364     if (
0365       msg->speed_hz != bus->base.speed_hz
0366       || msg->mode != bus->base.mode
0367       || msg->cs != bus->base.cs
0368       ) {
0369       raspberrypi_spi_config(
0370         bus,
0371         regs,
0372         msg->speed_hz,
0373         msg->mode,
0374         msg->cs
0375       );
0376     }
0377 
0378     bus->todo = msg->len;
0379     bus->rx_buf = msg->rx_buf;
0380     bus->tx_buf = msg->tx_buf;
0381     raspberrypi_spi_polling_tx_rx(bus);
0382   }
0383 }
0384 #endif
0385 
0386 static int raspberrypi_spi_transfer(
0387   spi_bus *base,
0388   const spi_ioc_transfer *msgs,
0389   uint32_t msg_count
0390 )
0391 {
0392   int rv = 0;
0393   raspberrypi_spi_bus *bus;
0394   bus = (raspberrypi_spi_bus *) base;
0395 
0396   rv = raspberrypi_spi_check_msg(bus, msgs, msg_count);
0397   if (rv == 0) {
0398     bus->msg_todo = msg_count;
0399     bus->msg = msgs;
0400 #ifdef BSP_SPI_USE_INTERRUPTS
0401     bus->task_id = rtems_task_self();
0402     
0403     raspberrypi_spi_start(bus);
0404     rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
0405 #else
0406     raspberrypi_spi_transfer_msg(bus);
0407 #endif
0408   }
0409 
0410   return rv;
0411 }
0412 
0413 static void raspberrypi_spi_destroy(spi_bus *base)
0414 {
0415   raspberrypi_spi_bus *bus;
0416   bus = (raspberrypi_spi_bus *) base;
0417 
0418 #ifdef BSP_SPI_USE_INTERRUPTS
0419   rtems_interrupt_handler_remove(
0420     bus->irq,
0421     raspberrypi_spi_interrupt,
0422     bus
0423   );
0424 #endif
0425 
0426   spi_bus_destroy_and_free(&bus->base);
0427 }
0428 
0429 static int raspberrypi_spi_setup(spi_bus *base)
0430 {
0431   raspberrypi_spi_bus *bus;
0432   uint32_t mode = base->mode;
0433 
0434   bus = (raspberrypi_spi_bus *) base;
0435 
0436   if (mode & SPI_LOOP) {
0437     return -EINVAL;
0438   }
0439 
0440   return raspberrypi_spi_config(
0441     bus,
0442     bus->regs,
0443     bus->base.speed_hz,
0444     bus->base.mode,
0445     bus->base.cs
0446   );
0447 }
0448 
0449 static rtems_status_code raspberrypi_spi_init_gpio(
0450   raspberrypi_spi_device device
0451 )
0452 {
0453   switch (device) {
0454     case raspberrypi_SPI0:
0455       raspberrypi_gpio_set_function(7, GPIO_AF0);      /* CS1 */
0456       raspberrypi_gpio_set_pull(7, GPIO_PULL_NONE);
0457       raspberrypi_gpio_set_function(8, GPIO_AF0);      /* CS0 */
0458       raspberrypi_gpio_set_pull(8, GPIO_PULL_NONE);
0459       raspberrypi_gpio_set_function(9, GPIO_AF0);      /* MISO */
0460       raspberrypi_gpio_set_function(10, GPIO_AF0);     /* MOSI */
0461       raspberrypi_gpio_set_function(11, GPIO_AF0);     /* SCLK */
0462       break;
0463     case raspberrypi_SPI3:
0464       raspberrypi_gpio_set_function(24, GPIO_AF5);
0465       raspberrypi_gpio_set_pull(24, GPIO_PULL_NONE);
0466       raspberrypi_gpio_set_function(0, GPIO_AF3);    
0467       raspberrypi_gpio_set_pull(0, GPIO_PULL_NONE);
0468       raspberrypi_gpio_set_function(1, GPIO_AF3);      
0469       raspberrypi_gpio_set_function(2, GPIO_AF3);      
0470       raspberrypi_gpio_set_function(3, GPIO_AF3);      
0471       break;
0472     case raspberrypi_SPI4:
0473       raspberrypi_gpio_set_function(25, GPIO_AF5);     
0474       raspberrypi_gpio_set_pull(25, GPIO_PULL_NONE);
0475       raspberrypi_gpio_set_function(4, GPIO_AF3);      
0476       raspberrypi_gpio_set_pull(4, GPIO_PULL_NONE);
0477       raspberrypi_gpio_set_function(5, GPIO_AF3);      
0478       raspberrypi_gpio_set_function(6, GPIO_AF3);      
0479       raspberrypi_gpio_set_function(7, GPIO_AF3);      
0480       break;
0481     case raspberrypi_SPI5:
0482       raspberrypi_gpio_set_function(26, GPIO_AF5);     
0483       raspberrypi_gpio_set_pull(26, GPIO_PULL_NONE);
0484       raspberrypi_gpio_set_function(12, GPIO_AF3);     
0485       raspberrypi_gpio_set_pull(12, GPIO_PULL_NONE);
0486       raspberrypi_gpio_set_function(13, GPIO_AF3);     
0487       raspberrypi_gpio_set_function(14, GPIO_AF3);     
0488       raspberrypi_gpio_set_function(15, GPIO_AF3);     
0489       break;
0490     case raspberrypi_SPI6:
0491       raspberrypi_gpio_set_function(27, GPIO_AF5);    
0492       raspberrypi_gpio_set_pull(27, GPIO_PULL_NONE);
0493       raspberrypi_gpio_set_function(18, GPIO_AF3);     
0494       raspberrypi_gpio_set_pull(18, GPIO_PULL_NONE);
0495       raspberrypi_gpio_set_function(19, GPIO_AF3);     
0496       raspberrypi_gpio_set_function(20, GPIO_AF3);     
0497       raspberrypi_gpio_set_function(21, GPIO_AF3); 
0498       break;
0499   default:
0500     return RTEMS_INVALID_NUMBER;
0501     break;
0502   }
0503   return RTEMS_SUCCESSFUL;
0504 }
0505 
0506 rtems_status_code raspberrypi_spi_init(raspberrypi_spi_device device)
0507 {
0508   raspberrypi_spi_bus *bus;
0509   int eno;
0510   volatile raspberrypi_spi *regs;
0511   const char *bus_path;
0512 
0513   bus = (raspberrypi_spi_bus *) spi_bus_alloc_and_init(sizeof(*bus));
0514   if (bus == NULL) {
0515     return RTEMS_UNSATISFIED;
0516   }
0517 
0518   switch (device) {
0519     case raspberrypi_SPI0:
0520       regs = (volatile raspberrypi_spi *) BCM2711_SPI0_BASE;
0521       bus_path = "/dev/spidev0";
0522       break;
0523     case raspberrypi_SPI3:
0524       regs = (volatile raspberrypi_spi *) BCM2711_SPI3_BASE;
0525       bus_path = "/dev/spidev3";
0526       break;
0527     case raspberrypi_SPI4:
0528       regs = (volatile raspberrypi_spi *) BCM2711_SPI4_BASE;
0529       bus_path = "/dev/spidev4";
0530       break;
0531     case raspberrypi_SPI5:
0532       regs = (volatile raspberrypi_spi *) BCM2711_SPI5_BASE;
0533       bus_path = "/dev/spidev5";
0534       break;
0535     case raspberrypi_SPI6:
0536       regs = (volatile raspberrypi_spi *) BCM2711_SPI6_BASE;
0537       bus_path = "/dev/spidev6";
0538       break;
0539     default:
0540       spi_bus_destroy_and_free(&bus->base);
0541       return RTEMS_INVALID_NUMBER;
0542       break;
0543   }
0544 
0545   bus->regs = regs;
0546   bus->num_cs = 2;
0547 
0548   bus->base.transfer = raspberrypi_spi_transfer;
0549   bus->base.destroy = raspberrypi_spi_destroy;
0550   bus->base.setup = raspberrypi_spi_setup;
0551   bus->base.bits_per_word = 8;
0552   bus->base.max_speed_hz = 250000000;
0553   bus->base.cs = 0;
0554 #ifdef BSP_SPI_USE_INTERRUPTS
0555   bus->irq = BCM2711_IRQ_SPI;
0556 
0557   eno = rtems_interrupt_handler_install(
0558     bus->irq,
0559     "SPI",
0560     RTEMS_INTERRUPT_SHARED,
0561     raspberrypi_spi_interrupt,
0562     bus
0563   );
0564   if (eno != RTEMS_SUCCESSFUL) {
0565     return EAGAIN;
0566   }
0567 #endif
0568 
0569   eno = spi_bus_register(&bus->base, bus_path);
0570   if (eno != 0) {
0571     spi_bus_destroy_and_free(&bus->base);
0572     return RTEMS_UNSATISFIED;
0573   }
0574 
0575   eno = raspberrypi_spi_init_gpio(device);
0576   if (eno != 0) {
0577     spi_bus_destroy_and_free(&bus->base);
0578     return RTEMS_INVALID_NUMBER;
0579   }
0580 
0581   return RTEMS_SUCCESSFUL;
0582 }