123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- /*
- * Copyright (c) 2019-2022, STMicroelectronics - All Rights Reserved
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <assert.h>
- #include <errno.h>
- #include <stddef.h>
- #include <common/debug.h>
- #include <drivers/delay_timer.h>
- #include <drivers/nand.h>
- #include <lib/utils.h>
- #include <platform_def.h>
- /*
- * Define a single nand_device used by specific NAND frameworks.
- */
- static struct nand_device nand_dev;
- #pragma weak plat_get_scratch_buffer
- void plat_get_scratch_buffer(void **buffer_addr, size_t *buf_size)
- {
- static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE];
- assert(buffer_addr != NULL);
- assert(buf_size != NULL);
- *buffer_addr = (void *)scratch_buff;
- *buf_size = sizeof(scratch_buff);
- }
- int nand_read(unsigned int offset, uintptr_t buffer, size_t length,
- size_t *length_read)
- {
- unsigned int block = offset / nand_dev.block_size;
- unsigned int end_block = (offset + length - 1U) / nand_dev.block_size;
- unsigned int page_start =
- (offset % nand_dev.block_size) / nand_dev.page_size;
- unsigned int nb_pages = nand_dev.block_size / nand_dev.page_size;
- unsigned int start_offset = offset % nand_dev.page_size;
- unsigned int page;
- unsigned int bytes_read;
- int is_bad;
- int ret;
- uint8_t *scratch_buff;
- size_t scratch_buff_size;
- plat_get_scratch_buffer((void **)&scratch_buff, &scratch_buff_size);
- assert(scratch_buff != NULL);
- VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n",
- block, end_block, page_start, nb_pages, length, offset);
- *length_read = 0UL;
- if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) &&
- (scratch_buff_size < nand_dev.page_size)) {
- return -EINVAL;
- }
- while (block <= end_block) {
- is_bad = nand_dev.mtd_block_is_bad(block);
- if (is_bad < 0) {
- return is_bad;
- }
- if (is_bad == 1) {
- /* Skip the block */
- uint32_t max_block =
- nand_dev.size / nand_dev.block_size;
- block++;
- end_block++;
- if ((block < max_block) && (end_block < max_block)) {
- continue;
- }
- return -EIO;
- }
- for (page = page_start; page < nb_pages; page++) {
- if ((start_offset != 0U) ||
- (length < nand_dev.page_size)) {
- ret = nand_dev.mtd_read_page(
- &nand_dev,
- (block * nb_pages) + page,
- (uintptr_t)scratch_buff);
- if (ret != 0) {
- return ret;
- }
- bytes_read = MIN((size_t)(nand_dev.page_size -
- start_offset),
- length);
- memcpy((uint8_t *)buffer,
- scratch_buff + start_offset,
- bytes_read);
- start_offset = 0U;
- } else {
- ret = nand_dev.mtd_read_page(&nand_dev,
- (block * nb_pages) + page,
- buffer);
- if (ret != 0) {
- return ret;
- }
- bytes_read = nand_dev.page_size;
- }
- length -= bytes_read;
- buffer += bytes_read;
- *length_read += bytes_read;
- if (length == 0U) {
- break;
- }
- }
- page_start = 0U;
- block++;
- }
- return 0;
- }
- int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset)
- {
- unsigned int block;
- unsigned int offset_block;
- unsigned int max_block;
- int is_bad;
- size_t count_bb = 0U;
- block = base / nand_dev.block_size;
- if (offset != 0U) {
- offset_block = (base + offset - 1U) / nand_dev.block_size;
- } else {
- offset_block = block;
- }
- max_block = nand_dev.size / nand_dev.block_size;
- while (block <= offset_block) {
- if (offset_block >= max_block) {
- return -EIO;
- }
- is_bad = nand_dev.mtd_block_is_bad(block);
- if (is_bad < 0) {
- return is_bad;
- }
- if (is_bad == 1) {
- count_bb++;
- offset_block++;
- }
- block++;
- }
- *extra_offset = count_bb * nand_dev.block_size;
- return 0;
- }
- struct nand_device *get_nand_device(void)
- {
- return &nand_dev;
- }
|