Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:39

0001 /*
0002  * Copyright (C) 2024 Contemporary Software
0003  *
0004  * Redistribution and use in source and binary forms, with or without
0005  * modification, are permitted provided that the following conditions
0006  * are met:
0007  * 1. Redistributions of source code must retain the above copyright
0008  *    notice, this list of conditions and the following disclaimer.
0009  * 2. Redistributions in binary form must reproduce the above copyright
0010  *    notice, this list of conditions and the following disclaimer in the
0011  *    documentation and/or other materials provided with the distribution.
0012  *
0013  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS
0014  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0015  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0016  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0017  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0018  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0019  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0020  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0021  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0022  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0023  * POSSIBILITY OF SUCH DAMAGE.
0024  */
0025 
0026 #include <rtems.h>
0027 #include <stdint.h>
0028 
0029 #include <dev/spi/zynq-qspi-flash-defs.h>
0030 
0031 /*
0032  * The following variables are shared between non-interrupt processing and
0033  * interrupt processing such that they must be global.
0034  */
0035 rtems_id transfer_task;
0036 
0037 __attribute__((weak)) void zqspi_write_unlock(zqspiflash *driver)
0038 {
0039 }
0040 
0041 __attribute__((weak)) void zqspi_write_lock(zqspiflash *driver)
0042 {
0043 }
0044 
0045 static void qspi_flash_rx(void) {
0046   while (true) {
0047     if (
0048       (qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS) &
0049         ZQSPI_QSPI_IXR_RXNEMPTY) == 0
0050     )
0051     {
0052       break;
0053     }
0054     qspi_reg_read(ZQSPI_QSPI_REG_RX_DATA);
0055   }
0056 }
0057 
0058 zqspi_error zqspi_transfer(
0059   zqspi_transfer_buffer* transfer,
0060   bool *initialised
0061 )
0062 {
0063   uint32_t tx_reg;
0064   uint32_t sr;
0065   rtems_status_code sc;
0066   transfer_task = rtems_task_self();
0067 
0068   if (*initialised == false)
0069   {
0070     qspi_reg_write(ZQSPI_QSPI_REG_EN, 0);
0071     qspi_reg_write(ZQSPI_QSPI_REG_LSPI_CFG, 0x00a002eb);
0072     qspi_flash_rx();
0073     qspi_reg_write(
0074       ZQSPI_QSPI_REG_CONFIG,
0075       ZQSPI_QSPI_CR_SSFORCE | ZQSPI_QSPI_CR_MANSTRTEN | ZQSPI_QSPI_CR_HOLDB_DR |
0076         ZQSPI_QSPI_CR_BAUD_RATE | ZQSPI_QSPI_CR_MODE_SEL
0077     );
0078     *initialised = true;
0079   }
0080 
0081   zqspi_transfer_trace("transfer:TX", transfer);
0082 
0083   /*
0084    * Set the chip select.
0085    */
0086   qspi_reg_write(ZQSPI_QSPI_REG_CONFIG,
0087            qspi_reg_read(ZQSPI_QSPI_REG_CONFIG) & ~ZQSPI_QSPI_CR_PCS);
0088 
0089   /*
0090    * Enable SPI.
0091    */
0092   qspi_reg_write(ZQSPI_QSPI_REG_EN, ZQSPI_QSPI_EN_SPI_ENABLE);
0093 
0094   /*
0095    * The RX pointer can never catch up and overtake the TX pointer.
0096    */
0097   transfer->tx_data = (uint32_t*) transfer->buffer;
0098   transfer->rx_data = (uint32_t*) transfer->buffer;
0099   transfer->tx_length = transfer->length;
0100   transfer->rx_length = transfer->length;
0101 
0102   /*
0103    * The buffer to right aligned, that is padding is add to the front of the
0104    * buffer to get the correct aligment for the instruction size. This means
0105    * the data in the first "transfer" is not aligned in the correct bits for
0106    * the keyhole access to the FIFO.
0107    */
0108   switch (transfer->padding)
0109   {
0110     case 3:
0111       *(transfer->tx_data) >>= 24;
0112       tx_reg = ZQSPI_QSPI_REG_TXD1;
0113       transfer->tx_length -= 1;
0114       transfer->sending += 1;
0115       transfer->start = true;
0116       break;
0117     case 2:
0118       *(transfer->tx_data) >>= 16;
0119       tx_reg = ZQSPI_QSPI_REG_TXD2;
0120       transfer->tx_length -= 2;
0121       transfer->sending += 2;
0122       transfer->start = true;
0123       break;
0124     case 1:
0125       *(transfer->tx_data) >>= 8;
0126       tx_reg = ZQSPI_QSPI_REG_TXD3;
0127       transfer->tx_length -= 3;
0128       transfer->sending += 3;
0129       transfer->start = true;
0130       break;
0131     default:
0132       tx_reg = ZQSPI_QSPI_REG_TXD0;
0133       transfer->tx_length -= 4;
0134       transfer->sending += 4;
0135       if (transfer->tx_length == 0)
0136         transfer->start = true;
0137       break;
0138   }
0139 
0140   qspi_reg_write (tx_reg, *(transfer->tx_data));
0141   ++(transfer->tx_data);
0142 
0143   if (transfer->start)
0144   {
0145     qspi_reg_write(ZQSPI_QSPI_REG_CONFIG,
0146              qspi_reg_read(ZQSPI_QSPI_REG_CONFIG) | ZQSPI_QSPI_CR_MANSTRT);
0147 
0148     sr = qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS);
0149     while ((sr & ZQSPI_QSPI_IXR_TXOW) == 0)
0150     {
0151       sr = qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS);
0152     }
0153   }
0154 
0155   /* Enable Interrupts */
0156   qspi_reg_write(ZQSPI_QSPI_REG_INTR_DISABLE,
0157     ~(ZQSPI_QSPI_IXR_RXNEMPTY | ZQSPI_QSPI_IXR_TXUF));
0158   qspi_reg_write(ZQSPI_QSPI_REG_INTR_ENABLE,
0159     (ZQSPI_QSPI_IXR_RXNEMPTY | ZQSPI_QSPI_IXR_TXUF));
0160 
0161   /* Wait for transfer to complete */
0162   sc = rtems_event_transient_receive(RTEMS_WAIT, ZQSPI_TIMEOUT_TICKS);
0163   if (sc != RTEMS_SUCCESSFUL) {
0164     rtems_event_transient_clear();
0165     return ZQPSI_FLASH_TRANSFER_FAILED;
0166   }
0167 
0168   /*
0169    * skip the command byte.
0170    */
0171   zqspi_transfer_buffer_skip(transfer, 1);
0172 
0173   /*
0174    * Disable the chip select.
0175    */
0176   qspi_reg_write(ZQSPI_QSPI_REG_CONFIG,
0177            qspi_reg_read(ZQSPI_QSPI_REG_CONFIG) | ZQSPI_QSPI_CR_PCS);
0178 
0179   /*
0180    * Disable SPI.
0181    */
0182   qspi_reg_write(ZQSPI_QSPI_REG_EN, 0);
0183 
0184   zqspi_transfer_trace("transfer:RX", transfer);
0185 
0186   return ZQSPI_FLASH_NO_ERROR;
0187 }
0188 
0189 void zqspi_transfer_intr(zqspiflash *driver)
0190 {
0191   uint32_t sr;
0192   zqspi_transfer_buffer* transfer = &(driver->buf);
0193 
0194   /* Disable and clear interrupts */
0195   qspi_reg_write(ZQSPI_QSPI_REG_INTR_DISABLE, 0xFFFFFFFF);
0196   qspi_reg_write(ZQSPI_QSPI_REG_INTR_STATUS, 0xFFFFFFFF);
0197   sr = qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS);
0198 
0199   if (transfer->rx_length)
0200   {
0201     while (transfer->start && transfer->sending)
0202     {
0203       if ((sr & ZQSPI_QSPI_IXR_RXNEMPTY) != 0)
0204       {
0205         *(transfer->rx_data) = qspi_reg_read(ZQSPI_QSPI_REG_RX_DATA);
0206         ++(transfer->rx_data);
0207         if (transfer->rx_length > sizeof(uint32_t)) {
0208           transfer->rx_length -= sizeof(uint32_t);
0209         } else {
0210           transfer->rx_length = 0;
0211         }
0212         if (transfer->sending > sizeof(uint32_t)) {
0213           transfer->sending -= sizeof(uint32_t);
0214         } else {
0215           transfer->sending = 0;
0216         }
0217       }
0218 
0219       sr = qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS);
0220     }
0221   }
0222 
0223   if (transfer->tx_length)
0224   {
0225     transfer->start = false;
0226     while (transfer->tx_length && ((sr & ZQSPI_QSPI_IXR_TXFULL) == 0))
0227     {
0228       qspi_reg_write (ZQSPI_QSPI_REG_TXD0, *(transfer->tx_data));
0229       ++(transfer->tx_data);
0230       if (transfer->tx_length > sizeof(uint32_t)) {
0231         transfer->tx_length -= sizeof(uint32_t);
0232       } else {
0233         transfer->tx_length = 0;
0234       }
0235       transfer->sending += sizeof(uint32_t);
0236       transfer->start = true;
0237 
0238       sr = qspi_reg_read(ZQSPI_QSPI_REG_INTR_STATUS);
0239     }
0240 
0241     if (transfer->start)
0242     {
0243       qspi_reg_write(ZQSPI_QSPI_REG_CONFIG,
0244                qspi_reg_read(ZQSPI_QSPI_REG_CONFIG) | ZQSPI_QSPI_CR_MANSTRT);
0245     }
0246   }
0247 
0248   if (transfer->tx_length) {
0249     qspi_reg_write(ZQSPI_QSPI_REG_INTR_ENABLE,
0250       qspi_reg_read(ZQSPI_QSPI_REG_INTR_ENABLE) | ZQSPI_QSPI_IXR_TXUF);
0251   }
0252   if (transfer->rx_length) {
0253     qspi_reg_write(ZQSPI_QSPI_REG_INTR_ENABLE,
0254       qspi_reg_read(ZQSPI_QSPI_REG_INTR_ENABLE) | ZQSPI_QSPI_IXR_RXNEMPTY);
0255   }
0256   if (transfer->tx_length == 0 && transfer->rx_length == 0) {
0257     (void) rtems_event_transient_send(transfer_task);
0258   }
0259 }