Back to home page

LXR

 
 

    


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

0001 /*
0002  * SPDX-License-Identifier: BSD-2-Clause
0003  *
0004  * Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 /*
0029  * This file contains an implementation of a basic JFFS2 filesystem adapter for
0030  * the NandPsu peripheral that uses the entirety of the available NAND chip(s)
0031  * for a JFFS2 filesystem or up to the maximum size possible. If an
0032  * implementation would prefer to only use a portion of the NAND flash chip,
0033  * this template would need rework to account for a reduced size and possibly a
0034  * start offset while also taking into account the driver's handling of bad
0035  * blocks and how that might affect the offset.
0036  */
0037 
0038 #include <sys/stat.h>
0039 #include <sys/types.h>
0040 #include <string.h>
0041 #include <assert.h>
0042 #include <errno.h>
0043 #include <stdlib.h>
0044 
0045 #include <bsp/jffs2_xnandpsu.h>
0046 #include <rtems/libio.h>
0047 #include <rtems/libcsupport.h>
0048 #include <rtems/malloc.h>
0049 #include <rtems/thread.h>
0050 #include <dev/nand/xnandpsu_bbm.h>
0051 
0052 typedef struct {
0053   rtems_jffs2_flash_control super;
0054   XNandPsu *nandpsu;
0055   rtems_mutex access_lock;
0056 } flash_control;
0057 
0058 static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
0059 {
0060   return (flash_control *) super;
0061 }
0062 
0063 static int flash_read(
0064   rtems_jffs2_flash_control *super,
0065   uint32_t offset,
0066   unsigned char *buffer,
0067   size_t size_of_buffer
0068 )
0069 {
0070   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0071   rtems_status_code sc;
0072 
0073   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0074   sc = XNandPsu_Read(nandpsu, offset, size_of_buffer, buffer);
0075   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0076   if (sc) {
0077     return -EIO;
0078   }
0079   return 0;
0080 }
0081 
0082 static int flash_write(
0083   rtems_jffs2_flash_control *super,
0084   uint32_t offset,
0085   const unsigned char *buffer,
0086   size_t size_of_buffer
0087 )
0088 {
0089   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0090   rtems_status_code sc;
0091 
0092   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0093   sc = XNandPsu_Write(nandpsu, offset, size_of_buffer, (void *)buffer);
0094   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0095   if (sc) {
0096     return -EIO;
0097   }
0098   return 0;
0099 }
0100 
0101 static int flash_erase(
0102   rtems_jffs2_flash_control *super,
0103   uint32_t offset
0104 )
0105 {
0106   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0107   rtems_status_code sc;
0108   uint64_t BlockSize = nandpsu->Geometry.BlockSize;
0109 
0110   if (offset > nandpsu->Geometry.DeviceSize) {
0111     return -EIO;
0112   }
0113 
0114   /* Perform erase operation. */
0115   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0116   sc = XNandPsu_Erase(nandpsu, RTEMS_ALIGN_DOWN(offset, BlockSize), BlockSize);
0117   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0118   if (sc ) {
0119     return -EIO;
0120   }
0121 
0122   return 0;
0123 }
0124 
0125 static int flash_block_is_bad(
0126   rtems_jffs2_flash_control *super,
0127   uint32_t offset,
0128   bool *bad
0129 )
0130 {
0131   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0132   uint32_t BlockIndex;
0133   uint8_t BlockData;
0134   uint8_t BlockShift;
0135   uint8_t BlockType;
0136   uint32_t BlockOffset;
0137 
0138   assert(bad);
0139 
0140   if (offset > nandpsu->Geometry.DeviceSize) {
0141     return -EIO;
0142   }
0143 
0144   *bad = true;
0145 
0146   BlockIndex = offset / nandpsu->Geometry.BlockSize;
0147 
0148   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0149 
0150   /* XNandPsu_IsBlockBad() is insufficient for this use case */
0151   BlockOffset = BlockIndex >> XNANDPSU_BBT_BLOCK_SHIFT;
0152   BlockShift = XNandPsu_BbtBlockShift(BlockIndex);
0153   BlockData = nandpsu->Bbt[BlockOffset];
0154   BlockType = (BlockData >> BlockShift) & XNANDPSU_BLOCK_TYPE_MASK;
0155 
0156   if (BlockType == XNANDPSU_BLOCK_GOOD) {
0157     *bad = false;
0158   }
0159 
0160   int TargetBlockIndex = BlockIndex % nandpsu->Geometry.NumTargetBlocks;
0161   /* The last 4 blocks of every device target are reserved for the BBT */
0162   if (nandpsu->Geometry.NumTargetBlocks - TargetBlockIndex <= 4) {
0163     *bad = true;
0164   }
0165 
0166   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0167   return 0;
0168 }
0169 
0170 static int flash_block_mark_bad(
0171   rtems_jffs2_flash_control *super,
0172   uint32_t offset
0173 )
0174 {
0175   rtems_status_code sc;
0176   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0177   uint32_t BlockIndex;
0178 
0179   if (offset > nandpsu->Geometry.DeviceSize) {
0180     return -EIO;
0181   }
0182 
0183   BlockIndex = offset / nandpsu->Geometry.BlockSize;
0184 
0185   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0186   sc = XNandPsu_MarkBlockBad(nandpsu, BlockIndex);
0187   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0188   if ( sc != XST_SUCCESS ) {
0189     return -EIO;
0190   }
0191   return RTEMS_SUCCESSFUL;
0192 }
0193 
0194 static int flash_read_oob_locked(
0195   rtems_jffs2_flash_control *super,
0196   uint32_t offset,
0197   uint8_t *oobbuf,
0198   uint32_t ooblen
0199 )
0200 {
0201   uint8_t *spare_bytes;
0202   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0203   uint32_t SpareBytesPerPage = nandpsu->Geometry.SpareBytesPerPage;
0204 
0205   if (offset > nandpsu->Geometry.DeviceSize) {
0206     return -EIO;
0207   }
0208 
0209   /* Can't request more spare bytes than exist */
0210   if (ooblen > SpareBytesPerPage * nandpsu->Geometry.PagesPerBlock) {
0211     return -EIO;
0212   }
0213 
0214   /* Get page index */
0215   uint32_t PageIndex = offset / nandpsu->Geometry.BytesPerPage;
0216 
0217   spare_bytes = rtems_malloc(SpareBytesPerPage);
0218   if (spare_bytes == NULL) {
0219     return -ENOMEM;
0220   }
0221 
0222   while (ooblen) {
0223     int rv = XNandPsu_ReadSpareBytes(nandpsu, PageIndex, spare_bytes);
0224     /* no guarantee oobbuf can hold all of spare bytes, so read and then copy */
0225     uint32_t readlen = SpareBytesPerPage;
0226     if (ooblen < readlen) {
0227         readlen = ooblen;
0228     }
0229 
0230     if (rv) {
0231       free(spare_bytes);
0232       return -EIO;
0233     }
0234 
0235     memcpy(oobbuf, spare_bytes, readlen);
0236 
0237     PageIndex++;
0238     ooblen -= readlen;
0239     oobbuf += readlen;
0240   }
0241   free(spare_bytes);
0242   return RTEMS_SUCCESSFUL;
0243 }
0244 
0245 static int flash_read_oob(
0246   rtems_jffs2_flash_control *super,
0247   uint32_t offset,
0248   uint8_t *oobbuf,
0249   uint32_t ooblen
0250 )
0251 {
0252   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0253   int ret = flash_read_oob_locked(super, offset, oobbuf, ooblen);
0254   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0255   return ret;
0256 }
0257 
0258 static int flash_write_oob(
0259   rtems_jffs2_flash_control *super,
0260   uint32_t offset,
0261   uint8_t *oobbuf,
0262   uint32_t ooblen
0263 )
0264 {
0265   rtems_status_code sc;
0266   uint8_t *spare_bytes;
0267   uint8_t *buffer = oobbuf;
0268   XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
0269   uint32_t SpareBytesPerPage = nandpsu->Geometry.SpareBytesPerPage;
0270 
0271   if (offset > nandpsu->Geometry.DeviceSize) {
0272     return -EIO;
0273   }
0274 
0275   /* Writing a page spare area to large will result in ignored data.  */
0276   if (ooblen > SpareBytesPerPage) {
0277     return -EIO;
0278   }
0279 
0280   spare_bytes = rtems_malloc(SpareBytesPerPage);
0281   if (spare_bytes == NULL) {
0282     return -ENOMEM;
0283   }
0284 
0285   /* Writing a page spare area to small will result in invalid accesses */
0286   rtems_mutex_lock(&(get_flash_control(super)->access_lock));
0287   if (ooblen < SpareBytesPerPage) {
0288     int rv = flash_read_oob_locked(super, offset, spare_bytes, SpareBytesPerPage);
0289     if (rv) {
0290       free(spare_bytes);
0291       rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0292       return rv;
0293     }
0294     buffer = spare_bytes;
0295     memcpy(buffer, oobbuf, ooblen);
0296   }
0297 
0298   /* Get page index */
0299   uint32_t PageIndex = offset / nandpsu->Geometry.BytesPerPage;
0300 
0301   sc = XNandPsu_WriteSpareBytes(nandpsu, PageIndex, buffer);
0302   rtems_mutex_unlock(&(get_flash_control(super)->access_lock));
0303   free(spare_bytes);
0304 
0305   if ( sc != XST_SUCCESS ) {
0306     return -EIO;
0307   }
0308   return RTEMS_SUCCESSFUL;
0309 }
0310 
0311 static uint32_t flash_get_oob_size(
0312   rtems_jffs2_flash_control *super
0313 )
0314 {
0315   flash_control *self = get_flash_control(super);
0316 
0317   return self->nandpsu->Geometry.SpareBytesPerPage;
0318 }
0319 
0320 static flash_control flash_instance = {
0321   .super = {
0322     .read = flash_read,
0323     .write = flash_write,
0324     .erase = flash_erase,
0325     .block_is_bad = flash_block_is_bad,
0326     .block_mark_bad = flash_block_mark_bad,
0327     .oob_read = flash_read_oob,
0328     .oob_write = flash_write_oob,
0329     .get_oob_size = flash_get_oob_size,
0330   }
0331 };
0332 
0333 static rtems_jffs2_compressor_control compressor_instance = {
0334   .compress = rtems_jffs2_compressor_rtime_compress,
0335   .decompress = rtems_jffs2_compressor_rtime_decompress
0336 };
0337 
0338 static rtems_jffs2_mount_data mount_data;
0339 
0340 int xilinx_zynqmp_nand_jffs2_initialize(
0341   const char *mount_dir,
0342   XNandPsu *NandInstPtr
0343 )
0344 {
0345   flash_instance.super.block_size = NandInstPtr->Geometry.BlockSize;
0346 
0347   uint64_t max_size = 0x100000000LU - flash_instance.super.block_size;
0348 
0349   /* JFFS2 maximum FS size is one block less than 4GB */
0350   if (NandInstPtr->Geometry.DeviceSize > max_size) {
0351     flash_instance.super.flash_size = max_size;
0352   } else {
0353     flash_instance.super.flash_size = NandInstPtr->Geometry.DeviceSize;
0354   }
0355 
0356   flash_instance.super.write_size = NandInstPtr->Geometry.BytesPerPage;
0357   flash_instance.nandpsu = NandInstPtr;
0358   rtems_mutex_init(&flash_instance.access_lock, "XNandPsu JFFS2 adapter lock");
0359   mount_data.flash_control = &flash_instance.super;
0360   mount_data.compressor_control = &compressor_instance;
0361 
0362   int rv = 0;
0363   rv = mount(
0364     NULL,
0365     mount_dir,
0366     RTEMS_FILESYSTEM_TYPE_JFFS2,
0367     RTEMS_FILESYSTEM_READ_WRITE,
0368     &mount_data
0369   );
0370   if ( rv != 0 ) {
0371     return rv;
0372   }
0373 
0374   return 0;
0375 }