Back to home page

LXR

 
 

    


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

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsMicroblaze
0007  *
0008  * @brief MicroBlaze AXI QSPI JFFS2 flash driver implementation
0009  */
0010 
0011 /*
0012  * Copyright (C) 2022 On-Line Applications Research Corporation (OAR)
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 <assert.h>
0037 #include <errno.h>
0038 #include <string.h>
0039 #include <fcntl.h>
0040 #include <sys/types.h>
0041 #include <sys/stat.h>
0042 
0043 #include <bspopts.h>
0044 #include <dev/spi/xilinx-axi-spi.h>
0045 #include <linux/spi/spidev.h>
0046 #include <rtems/jffs2.h>
0047 #include <rtems/libio.h>
0048 
0049 #include <bsp.h>
0050 #include <bsp/jffs2_qspi.h>
0051 
0052 #define BLOCK_SIZE (64UL * 1024UL)
0053 #define FLASH_SIZE (32UL * BLOCK_SIZE)
0054 #define FLASH_PAGE_SIZE        256
0055 #define FLASH_NUM_CS           2
0056 #define FLASH_DEVICE_ID        0xbb19 /* Type: 0xbb, Capacity: 0x19 */
0057 #define BUS_PATH          "/dev/spi-0"
0058 #define FLASH_MOUNT_POINT "/mnt"
0059 
0060 #define READ_WRITE_EXTRA_BYTES 4
0061 #define WRITE_ENABLE_BYTES     1
0062 #define SECTOR_ERASE_BYTES     4
0063 
0064 #define COMMAND_QUAD_WRITE     0x32
0065 #define COMMAND_SECTOR_ERASE   0xD8
0066 #define COMMAND_QUAD_READ      0x6B
0067 #define COMMAND_STATUSREG_READ 0x05
0068 #define COMMAND_WRITE_ENABLE   0x06
0069 #define FLASH_SR_IS_READY_MASK 0x01
0070 
0071 typedef struct {
0072   rtems_jffs2_flash_control super;
0073   int                       fd;
0074 } flash_control;
0075 
0076 static uint8_t ReadBuffer[FLASH_PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4];
0077 static uint8_t WriteBuffer[FLASH_PAGE_SIZE + READ_WRITE_EXTRA_BYTES + 4];
0078 
0079 static flash_control *get_flash_control( rtems_jffs2_flash_control *super )
0080 {
0081   return (flash_control *) super;
0082 }
0083 
0084 static int flash_wait_for_ready( flash_control *self )
0085 {
0086   uint8_t rv     = 0;
0087   uint8_t status = 0;
0088 
0089   WriteBuffer[0] = COMMAND_STATUSREG_READ;
0090 
0091   struct spi_ioc_transfer mesg = {
0092     .tx_buf        = WriteBuffer,
0093     .rx_buf        = ReadBuffer,
0094     .len           = 2,
0095     .bits_per_word = 8,
0096     .cs            = 0
0097   };
0098 
0099   do {
0100     rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg );
0101     if ( rv != 0 ) {
0102       return -EIO;
0103     }
0104 
0105     status = ReadBuffer[1];
0106   } while ( (status & FLASH_SR_IS_READY_MASK) != 0 );
0107 
0108   return 0;
0109 }
0110 
0111 static int flash_write_enable( flash_control *self )
0112 {
0113   uint8_t rv = 0;
0114 
0115   rv = flash_wait_for_ready( self );
0116   if ( rv != 0 ) {
0117     return rv;
0118   }
0119 
0120   WriteBuffer[0] = COMMAND_WRITE_ENABLE;
0121 
0122   struct spi_ioc_transfer mesg = {
0123     .tx_buf        = WriteBuffer,
0124     .len           = WRITE_ENABLE_BYTES,
0125     .bits_per_word = 8,
0126     .cs            = 0
0127   };
0128 
0129   rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg );
0130   if ( rv != 0 ) {
0131     return -EIO;
0132   }
0133 
0134   return 0;
0135 }
0136 
0137 static int flash_read(
0138   rtems_jffs2_flash_control *super,
0139   uint32_t                   offset,
0140   unsigned char             *buffer,
0141   size_t                     size_of_buffer
0142 )
0143 {
0144   int rv = 0;
0145   uint32_t current_offset = offset;
0146   uint32_t bytes_left     = size_of_buffer;
0147 
0148   flash_control *self = get_flash_control( super );
0149 
0150   rv = flash_wait_for_ready( self );
0151   if ( rv != 0 ) {
0152     return rv;
0153   }
0154 
0155   WriteBuffer[0] = COMMAND_QUAD_READ;
0156 
0157   /* Read in 256-byte chunks */
0158   do {
0159     uint32_t chunk_size = bytes_left > FLASH_PAGE_SIZE ? FLASH_PAGE_SIZE : bytes_left;
0160 
0161     struct spi_ioc_transfer mesg = {
0162       .tx_buf        = WriteBuffer,
0163       .rx_buf        = ReadBuffer,
0164       .len           = chunk_size + 8,
0165       .bits_per_word = 8,
0166       .cs            = 0
0167     };
0168 
0169     WriteBuffer[1] = (uint8_t) (current_offset >> 16);
0170     WriteBuffer[2] = (uint8_t) (current_offset >> 8);
0171     WriteBuffer[3] = (uint8_t) current_offset;
0172 
0173     rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg );
0174     if ( rv != 0 ) {
0175       return -EIO;
0176     }
0177 
0178     memcpy( &buffer[current_offset - offset], &ReadBuffer[8], chunk_size );
0179 
0180     current_offset += chunk_size;
0181     bytes_left     -= chunk_size;
0182   } while ( bytes_left > 0 );
0183 
0184   return 0;
0185 }
0186 
0187 static int flash_write(
0188   rtems_jffs2_flash_control *super,
0189   uint32_t                   offset,
0190   const unsigned char       *buffer,
0191   size_t                     size_of_buffer
0192 )
0193 {
0194   int rv = 0;
0195 
0196   flash_control *self = get_flash_control( super );
0197 
0198   rv = flash_write_enable( self );
0199   if ( rv != 0 ) {
0200     return rv;
0201   }
0202 
0203   rv = flash_wait_for_ready( self );
0204   if ( rv != 0 ) {
0205     return rv;
0206   }
0207 
0208   WriteBuffer[0] = COMMAND_QUAD_WRITE;
0209   WriteBuffer[1] = (uint8_t) (offset >> 16);
0210   WriteBuffer[2] = (uint8_t) (offset >> 8);
0211   WriteBuffer[3] = (uint8_t) offset;
0212 
0213   memcpy( &WriteBuffer[4], buffer, size_of_buffer );
0214 
0215   struct spi_ioc_transfer mesg = {
0216     .tx_buf        = WriteBuffer,
0217     .len           = size_of_buffer + 4,
0218     .bits_per_word = 8,
0219     .cs            = 0
0220   };
0221 
0222   rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg );
0223   if ( rv != 0 ) {
0224     return -EIO;
0225   }
0226 
0227   return 0;
0228 }
0229 
0230 static int flash_erase(
0231   rtems_jffs2_flash_control *super,
0232   uint32_t                   offset
0233 )
0234 {
0235   int rv = 0;
0236 
0237   flash_control *self = get_flash_control( super );
0238 
0239   rv = flash_write_enable( self );
0240   if ( rv != 0 ) {
0241     return rv;
0242   }
0243 
0244   rv = flash_wait_for_ready( self );
0245   if ( rv != 0 ) {
0246     return rv;
0247   }
0248 
0249   WriteBuffer[0] = COMMAND_SECTOR_ERASE;
0250   WriteBuffer[1] = (uint8_t) (offset >> 16);
0251   WriteBuffer[2] = (uint8_t) (offset >> 8);
0252   WriteBuffer[3] = (uint8_t) offset;
0253 
0254   struct spi_ioc_transfer mesg = {
0255     .tx_buf        = WriteBuffer,
0256     .len           = SECTOR_ERASE_BYTES,
0257     .bits_per_word = 8,
0258     .cs            = 0
0259   };
0260 
0261   rv = ioctl( self->fd, SPI_IOC_MESSAGE( 1 ), &mesg );
0262   if ( rv != 0 ) {
0263     return -EIO;
0264   }
0265 
0266   return 0;
0267 }
0268 
0269 static flash_control flash_instance = {
0270   .super = {
0271     .block_size        = BLOCK_SIZE,
0272     .flash_size        = FLASH_SIZE,
0273     .read              = flash_read,
0274     .write             = flash_write,
0275     .erase             = flash_erase,
0276     .device_identifier = FLASH_DEVICE_ID
0277   }
0278 };
0279 
0280 static rtems_jffs2_mount_data mount_data = {
0281   .flash_control      = &flash_instance.super,
0282   .compressor_control = NULL
0283 };
0284 
0285 int microblaze_jffs2_initialize( const char* mount_dir )
0286 {
0287   int rv = 0;
0288   int fd = -1;
0289 
0290   uintptr_t mblaze_spi_base = try_get_prop_from_device_tree(
0291     "xlnx,xps-spi-2.00.a",
0292     "reg",
0293     BSP_MICROBLAZE_FPGA_SPI_BASE
0294   );
0295 
0296   rtems_vector_number mblaze_spi_irq_num = try_get_prop_from_device_tree(
0297     "xlnx,xps-spi-2.00.a",
0298     "interrupts",
0299     BSP_MICROBLAZE_FPGA_SPI_IRQ_NUM
0300   );
0301 
0302   rv = spi_bus_register_xilinx_axi(
0303     BUS_PATH,
0304     mblaze_spi_base,
0305     FLASH_PAGE_SIZE,
0306     FLASH_NUM_CS,
0307     mblaze_spi_irq_num
0308   );
0309   if ( rv != 0 ) {
0310     return rv;
0311   }
0312 
0313   fd = open( BUS_PATH, O_RDWR );
0314   if ( fd < 0 ) {
0315     return -1;
0316   }
0317 
0318   flash_instance.fd = fd;
0319 
0320   rv = mount_and_make_target_path(
0321     NULL,
0322     mount_dir,
0323     RTEMS_FILESYSTEM_TYPE_JFFS2,
0324     RTEMS_FILESYSTEM_READ_WRITE,
0325     &mount_data
0326   );
0327   if ( rv != 0 ) {
0328     return rv;
0329   }
0330 
0331   return 0;
0332 }