source: rtems/bsps/aarch64/xilinx-zynqmp/jffs2_xnandpsu.c @ caffdc4

Last change on this file since caffdc4 was caffdc4, checked in by Kinsey Moore <kinsey.moore@…>, on 01/13/23 at 21:21:16

bsps/zynqmp: Add JFFS2 NAND adapter

This adds the glue code necessary to allow JFFS2 to operate on top of
NAND memory hosted by the XNandPsu peripheral/driver.

  • Property mode set to 100644
File size: 8.3 KB
Line 
1/*
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (C) 2023 On-Line Applications Research Corporation (OAR)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * This file contains an implementation of a basic JFFS2 filesystem adapter for
30 * the NandPsu peripheral that uses the entirety of the available NAND chip(s)
31 * for a JFFS2 filesystem or up to the maximum size possible. If an
32 * implementation would prefer to only use a portion of the NAND flash chip,
33 * this template would need rework to account for a reduced size and possibly a
34 * start offset while also taking into account the driver's handling of bad
35 * blocks and how that might affect the offset.
36 */
37
38#include <sys/stat.h>
39#include <sys/types.h>
40#include <string.h>
41#include <assert.h>
42#include <errno.h>
43#include <stdlib.h>
44
45#include <bsp/jffs2_xnandpsu.h>
46#include <rtems/libio.h>
47#include <rtems/libcsupport.h>
48#include <rtems/malloc.h>
49#include <dev/nand/xnandpsu_bbm.h>
50
51typedef struct {
52  rtems_jffs2_flash_control super;
53  XNandPsu *nandpsu;
54} flash_control;
55
56static flash_control *get_flash_control(rtems_jffs2_flash_control *super)
57{
58  return (flash_control *) super;
59}
60
61static int flash_read(
62  rtems_jffs2_flash_control *super,
63  uint32_t offset,
64  unsigned char *buffer,
65  size_t size_of_buffer
66)
67{
68  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
69  rtems_status_code sc;
70
71  sc = XNandPsu_Read(nandpsu, offset, size_of_buffer, buffer);
72  if (sc) {
73    return -EIO;
74  }
75  return 0;
76}
77
78static int flash_write(
79  rtems_jffs2_flash_control *super,
80  uint32_t offset,
81  const unsigned char *buffer,
82  size_t size_of_buffer
83)
84{
85  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
86  rtems_status_code sc;
87
88  sc = XNandPsu_Write(nandpsu, offset, size_of_buffer, (void *)buffer);
89  if (sc) {
90    return -EIO;
91  }
92  return 0;
93}
94
95static int flash_erase(
96  rtems_jffs2_flash_control *super,
97  uint32_t offset
98)
99{
100  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
101  rtems_status_code sc;
102  uint32_t BlockSize = nandpsu->Geometry.BlockSize;
103  uint32_t DeviceSize = nandpsu->Geometry.DeviceSize;
104  uint32_t BlockIndex;
105  uint32_t DeviceIndex;
106
107  if (offset > nandpsu->Geometry.DeviceSize) {
108    return -EIO;
109  }
110
111  DeviceIndex = offset / DeviceSize;
112  BlockIndex = (offset % DeviceSize) / BlockSize;
113
114  /* Perform erase operation. */
115  sc = XNandPsu_EraseBlock(nandpsu, DeviceIndex, BlockIndex);
116  if (sc ) {
117    return -EIO;
118  }
119
120  return 0;
121}
122
123static int flash_block_is_bad(
124  rtems_jffs2_flash_control *super,
125  uint32_t offset,
126  bool *bad
127)
128{
129  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
130  uint32_t BlockIndex;
131
132  assert(bad);
133
134  if (offset > nandpsu->Geometry.DeviceSize) {
135    return -EIO;
136  }
137
138  BlockIndex = offset / nandpsu->Geometry.BlockSize;
139
140  *bad = (XNandPsu_IsBlockBad(nandpsu, BlockIndex) == XST_SUCCESS);
141  return 0;
142}
143
144static int flash_block_mark_bad(
145  rtems_jffs2_flash_control *super,
146  uint32_t offset
147)
148{
149  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
150  uint32_t BlockIndex;
151
152  if (offset > nandpsu->Geometry.DeviceSize) {
153    return -EIO;
154  }
155
156  BlockIndex = offset / nandpsu->Geometry.BlockSize;
157
158  if ( XNandPsu_MarkBlockBad(nandpsu, BlockIndex) != XST_SUCCESS ) {
159    return -EIO;
160  }
161  return RTEMS_SUCCESSFUL;
162}
163
164static int flash_read_oob(
165  rtems_jffs2_flash_control *super,
166  uint32_t offset,
167  uint8_t *oobbuf,
168  uint32_t ooblen
169)
170{
171  uint8_t *spare_bytes;
172  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
173  uint32_t SpareBytesPerPage = nandpsu->Geometry.SpareBytesPerPage;
174
175  if (offset > nandpsu->Geometry.DeviceSize) {
176    return -EIO;
177  }
178
179  /* Can't request more spare bytes than exist */
180  if (ooblen > SpareBytesPerPage * nandpsu->Geometry.PagesPerBlock) {
181    return -EIO;
182  }
183
184  /* Get page index */
185  uint32_t PageIndex = offset / nandpsu->Geometry.BytesPerPage;
186
187  spare_bytes = rtems_malloc(SpareBytesPerPage);
188  if (spare_bytes == NULL) {
189    return -ENOMEM;
190  }
191
192  while (ooblen) {
193    int rv = XNandPsu_ReadSpareBytes(nandpsu, PageIndex, spare_bytes);
194    /* no guarantee oobbuf can hold all of spare bytes, so read and then copy */
195    uint32_t readlen = SpareBytesPerPage;
196    if (ooblen < readlen) {
197            readlen = ooblen;
198    }
199
200    if (rv) {
201      free(spare_bytes);
202      return -EIO;
203    }
204
205    memcpy(oobbuf, spare_bytes, readlen);
206
207    PageIndex++;
208    ooblen -= readlen;
209    oobbuf += readlen;
210  }
211  free(spare_bytes);
212  return RTEMS_SUCCESSFUL;
213}
214
215static int flash_write_oob(
216  rtems_jffs2_flash_control *super,
217  uint32_t offset,
218  uint8_t *oobbuf,
219  uint32_t ooblen
220)
221{
222  uint8_t *spare_bytes;
223  uint8_t *buffer = oobbuf;
224  XNandPsu *nandpsu = get_flash_control(super)->nandpsu;
225  uint32_t SpareBytesPerPage = nandpsu->Geometry.SpareBytesPerPage;
226
227  if (offset > nandpsu->Geometry.DeviceSize) {
228    return -EIO;
229  }
230
231  /* Writing a page spare area to large will result in ignored data.  */
232  if (ooblen > SpareBytesPerPage) {
233    return -EIO;
234  }
235
236  spare_bytes = rtems_malloc(SpareBytesPerPage);
237  if (spare_bytes == NULL) {
238    return -ENOMEM;
239  }
240
241  /* Writing a page spare area to small will result in invalid accesses */
242  if (ooblen < SpareBytesPerPage) {
243    int rv = flash_read_oob(super, offset, spare_bytes, SpareBytesPerPage);
244    if (rv) {
245      free(spare_bytes);
246      return rv;
247    }
248    buffer = spare_bytes;
249    memcpy(buffer, oobbuf, ooblen);
250  }
251
252  /* Get page index */
253  uint32_t PageIndex = offset / nandpsu->Geometry.BytesPerPage;
254
255  if ( XNandPsu_WriteSpareBytes(nandpsu, PageIndex, buffer) != XST_SUCCESS ) {
256    free(spare_bytes);
257    return -EIO;
258  }
259  free(spare_bytes);
260  return RTEMS_SUCCESSFUL;
261}
262
263static uint32_t flash_get_oob_size(
264  rtems_jffs2_flash_control *super
265)
266{
267  flash_control *self = get_flash_control(super);
268
269  return self->nandpsu->Geometry.SpareBytesPerPage;
270}
271
272static flash_control flash_instance = {
273  .super = {
274    .read = flash_read,
275    .write = flash_write,
276    .erase = flash_erase,
277    .block_is_bad = flash_block_is_bad,
278    .block_mark_bad = flash_block_mark_bad,
279    .oob_read = flash_read_oob,
280    .oob_write = flash_write_oob,
281    .get_oob_size = flash_get_oob_size,
282  }
283};
284
285static rtems_jffs2_compressor_control compressor_instance = {
286  .compress = rtems_jffs2_compressor_rtime_compress,
287  .decompress = rtems_jffs2_compressor_rtime_decompress
288};
289
290static rtems_jffs2_mount_data mount_data;
291
292int xilinx_zynqmp_nand_jffs2_initialize(
293  const char *mount_dir,
294  XNandPsu *NandInstPtr
295)
296{
297  flash_instance.super.block_size = NandInstPtr->Geometry.BlockSize;
298
299  uint64_t max_size = 0x100000000LU - flash_instance.super.block_size;
300
301  /* JFFS2 maximum FS size is one block less than 4GB */
302  if (NandInstPtr->Geometry.DeviceSize > max_size) {
303    flash_instance.super.flash_size = max_size;
304  } else {
305    flash_instance.super.flash_size = NandInstPtr->Geometry.DeviceSize;
306  }
307
308  flash_instance.super.write_size = NandInstPtr->Geometry.BytesPerPage;
309  flash_instance.nandpsu = NandInstPtr;
310  mount_data.flash_control = &flash_instance.super;
311  mount_data.compressor_control = &compressor_instance;
312
313  int rv = 0;
314  rv = mount(
315    NULL,
316    mount_dir,
317    RTEMS_FILESYSTEM_TYPE_JFFS2,
318    RTEMS_FILESYSTEM_READ_WRITE,
319    &mount_data
320  );
321  if ( rv != 0 ) {
322    return rv;
323  }
324
325  return 0;
326}
Note: See TracBrowser for help on using the repository browser.