summaryrefslogtreecommitdiffstats
path: root/bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c')
-rw-r--r--bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c b/bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c
new file mode 100644
index 0000000000..cfcb9cd27e
--- /dev/null
+++ b/bsps/arm/lpc32xx/nand/nand-mlc-write-blocks.c
@@ -0,0 +1,111 @@
+/**
+ * @file
+ *
+ * @ingroup lpc32xx_nand_mlc
+ *
+ * @brief lpc32xx_mlc_write_blocks() implementation.
+ */
+
+/*
+ * Copyright (c) 2010-2011 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Obere Lagerstr. 30
+ * 82178 Puchheim
+ * Germany
+ * <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <bsp/nand-mlc.h>
+
+#include <string.h>
+
+static const uint32_t ones_spare [MLC_LARGE_SPARE_WORD_COUNT] = {
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff,
+ 0xffffffff
+};
+
+rtems_status_code lpc32xx_mlc_write_blocks(
+ uint32_t block_begin,
+ uint32_t block_end,
+ const void *src,
+ size_t src_size,
+ uint32_t *page_data_buffer
+)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ uint32_t pages_per_block = lpc32xx_mlc_pages_per_block();
+ uint32_t block_count = lpc32xx_mlc_block_count();
+ uint32_t page_size = lpc32xx_mlc_page_size();
+ uint32_t block = 0;
+ const uint8_t *current = src;
+ const uint8_t *last = current;
+ const uint8_t *end = current + src_size;
+
+ if (block_begin > block_end || block_end > block_count) {
+ return RTEMS_INVALID_ID;
+ }
+
+ for (block = block_begin; block != block_end; ++block) {
+ uint32_t page_begin = block * pages_per_block;
+ uint32_t page_end = page_begin + pages_per_block;
+ uint32_t page = 0;
+
+ sc = lpc32xx_mlc_erase_block_safe_3(block, page_begin, page_end);
+ if (sc != RTEMS_SUCCESSFUL) {
+ continue;
+ }
+
+ for (page = page_begin; page < page_end; ++page) {
+ uintptr_t remainder = (uintptr_t) end - (uintptr_t) current;
+ size_t delta = remainder < page_size ? remainder : page_size;
+
+ if (remainder > 0) {
+ memcpy(page_data_buffer, current, delta);
+ sc = lpc32xx_mlc_write_page_with_ecc(
+ page,
+ page_data_buffer,
+ ones_spare
+ );
+ if (sc != RTEMS_SUCCESSFUL) {
+ lpc32xx_mlc_erase_block(block);
+ lpc32xx_mlc_zero_pages(page_begin, page_end);
+ current = last;
+ continue;
+ }
+
+ current += delta;
+ } else {
+ goto done;
+ }
+ }
+
+ last = current;
+ }
+
+done:
+
+ if (current != end) {
+ return RTEMS_IO_ERROR;
+ }
+
+ return RTEMS_SUCCESSFUL;
+}