1b114abb6SLionel Debieve /* 2*bc3eebb2SYann Gautier * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved 3b114abb6SLionel Debieve * 4b114abb6SLionel Debieve * SPDX-License-Identifier: BSD-3-Clause 5b114abb6SLionel Debieve */ 6b114abb6SLionel Debieve 7b114abb6SLionel Debieve #include <assert.h> 8b114abb6SLionel Debieve #include <errno.h> 9b114abb6SLionel Debieve #include <stddef.h> 10b114abb6SLionel Debieve 11b114abb6SLionel Debieve #include <platform_def.h> 12b114abb6SLionel Debieve 13b114abb6SLionel Debieve #include <common/debug.h> 14b114abb6SLionel Debieve #include <drivers/delay_timer.h> 15b114abb6SLionel Debieve #include <drivers/nand.h> 16b114abb6SLionel Debieve #include <lib/utils.h> 17b114abb6SLionel Debieve 18b114abb6SLionel Debieve /* 19b114abb6SLionel Debieve * Define a single nand_device used by specific NAND frameworks. 20b114abb6SLionel Debieve */ 21b114abb6SLionel Debieve static struct nand_device nand_dev; 22b114abb6SLionel Debieve static uint8_t scratch_buff[PLATFORM_MTD_MAX_PAGE_SIZE]; 23b114abb6SLionel Debieve 24b114abb6SLionel Debieve int nand_read(unsigned int offset, uintptr_t buffer, size_t length, 25b114abb6SLionel Debieve size_t *length_read) 26b114abb6SLionel Debieve { 27b114abb6SLionel Debieve unsigned int block = offset / nand_dev.block_size; 28b114abb6SLionel Debieve unsigned int end_block = (offset + length - 1U) / nand_dev.block_size; 29b114abb6SLionel Debieve unsigned int page_start = 30b114abb6SLionel Debieve (offset % nand_dev.block_size) / nand_dev.page_size; 31b114abb6SLionel Debieve unsigned int nb_pages = nand_dev.block_size / nand_dev.page_size; 32b114abb6SLionel Debieve unsigned int start_offset = offset % nand_dev.page_size; 33b114abb6SLionel Debieve unsigned int page; 34b114abb6SLionel Debieve unsigned int bytes_read; 35b114abb6SLionel Debieve int is_bad; 36b114abb6SLionel Debieve int ret; 37b114abb6SLionel Debieve 38b114abb6SLionel Debieve VERBOSE("Block %u - %u, page_start %u, nb %u, length %zu, offset %u\n", 39b114abb6SLionel Debieve block, end_block, page_start, nb_pages, length, offset); 40b114abb6SLionel Debieve 41b114abb6SLionel Debieve *length_read = 0UL; 42b114abb6SLionel Debieve 43b114abb6SLionel Debieve if (((start_offset != 0U) || (length % nand_dev.page_size) != 0U) && 44b114abb6SLionel Debieve (sizeof(scratch_buff) < nand_dev.page_size)) { 45b114abb6SLionel Debieve return -EINVAL; 46b114abb6SLionel Debieve } 47b114abb6SLionel Debieve 48b114abb6SLionel Debieve while (block <= end_block) { 49b114abb6SLionel Debieve is_bad = nand_dev.mtd_block_is_bad(block); 50b114abb6SLionel Debieve if (is_bad < 0) { 51b114abb6SLionel Debieve return is_bad; 52b114abb6SLionel Debieve } 53b114abb6SLionel Debieve 54b114abb6SLionel Debieve if (is_bad == 1) { 55b114abb6SLionel Debieve /* Skip the block */ 56b114abb6SLionel Debieve uint32_t max_block = 57b114abb6SLionel Debieve nand_dev.size / nand_dev.block_size; 58b114abb6SLionel Debieve 59b114abb6SLionel Debieve block++; 60b114abb6SLionel Debieve end_block++; 61b114abb6SLionel Debieve if ((block < max_block) && (end_block < max_block)) { 62b114abb6SLionel Debieve continue; 63b114abb6SLionel Debieve } 64b114abb6SLionel Debieve 65b114abb6SLionel Debieve return -EIO; 66b114abb6SLionel Debieve } 67b114abb6SLionel Debieve 68b114abb6SLionel Debieve for (page = page_start; page < nb_pages; page++) { 69b114abb6SLionel Debieve if ((start_offset != 0U) || 70b114abb6SLionel Debieve (length < nand_dev.page_size)) { 71b114abb6SLionel Debieve ret = nand_dev.mtd_read_page( 72b114abb6SLionel Debieve &nand_dev, 73b114abb6SLionel Debieve (block * nb_pages) + page, 74b114abb6SLionel Debieve (uintptr_t)scratch_buff); 75b114abb6SLionel Debieve if (ret != 0) { 76b114abb6SLionel Debieve return ret; 77b114abb6SLionel Debieve } 78b114abb6SLionel Debieve 79b114abb6SLionel Debieve bytes_read = MIN((size_t)(nand_dev.page_size - 80b114abb6SLionel Debieve start_offset), 81b114abb6SLionel Debieve length); 82b114abb6SLionel Debieve 83b114abb6SLionel Debieve memcpy((uint8_t *)buffer, 84b114abb6SLionel Debieve scratch_buff + start_offset, 85b114abb6SLionel Debieve bytes_read); 86b114abb6SLionel Debieve 87b114abb6SLionel Debieve start_offset = 0U; 88b114abb6SLionel Debieve } else { 89b114abb6SLionel Debieve ret = nand_dev.mtd_read_page(&nand_dev, 90b114abb6SLionel Debieve (block * nb_pages) + page, 91b114abb6SLionel Debieve buffer); 92b114abb6SLionel Debieve if (ret != 0) { 93b114abb6SLionel Debieve return ret; 94b114abb6SLionel Debieve } 95b114abb6SLionel Debieve 96b114abb6SLionel Debieve bytes_read = nand_dev.page_size; 97b114abb6SLionel Debieve } 98b114abb6SLionel Debieve 99b114abb6SLionel Debieve length -= bytes_read; 100b114abb6SLionel Debieve buffer += bytes_read; 101b114abb6SLionel Debieve *length_read += bytes_read; 102b114abb6SLionel Debieve 103b114abb6SLionel Debieve if (length == 0U) { 104b114abb6SLionel Debieve break; 105b114abb6SLionel Debieve } 106b114abb6SLionel Debieve } 107b114abb6SLionel Debieve 108b114abb6SLionel Debieve page_start = 0U; 109b114abb6SLionel Debieve block++; 110b114abb6SLionel Debieve } 111b114abb6SLionel Debieve 112b114abb6SLionel Debieve return 0; 113b114abb6SLionel Debieve } 114b114abb6SLionel Debieve 115*bc3eebb2SYann Gautier int nand_seek_bb(uintptr_t base, unsigned int offset, size_t *extra_offset) 116*bc3eebb2SYann Gautier { 117*bc3eebb2SYann Gautier unsigned int block; 118*bc3eebb2SYann Gautier unsigned int offset_block; 119*bc3eebb2SYann Gautier unsigned int max_block; 120*bc3eebb2SYann Gautier int is_bad; 121*bc3eebb2SYann Gautier size_t count_bb = 0U; 122*bc3eebb2SYann Gautier 123*bc3eebb2SYann Gautier block = base / nand_dev.block_size; 124*bc3eebb2SYann Gautier 125*bc3eebb2SYann Gautier if (offset != 0U) { 126*bc3eebb2SYann Gautier offset_block = (base + offset - 1U) / nand_dev.block_size; 127*bc3eebb2SYann Gautier } else { 128*bc3eebb2SYann Gautier offset_block = block; 129*bc3eebb2SYann Gautier } 130*bc3eebb2SYann Gautier 131*bc3eebb2SYann Gautier max_block = nand_dev.size / nand_dev.block_size; 132*bc3eebb2SYann Gautier 133*bc3eebb2SYann Gautier while (block <= offset_block) { 134*bc3eebb2SYann Gautier if (offset_block >= max_block) { 135*bc3eebb2SYann Gautier return -EIO; 136*bc3eebb2SYann Gautier } 137*bc3eebb2SYann Gautier 138*bc3eebb2SYann Gautier is_bad = nand_dev.mtd_block_is_bad(block); 139*bc3eebb2SYann Gautier if (is_bad < 0) { 140*bc3eebb2SYann Gautier return is_bad; 141*bc3eebb2SYann Gautier } 142*bc3eebb2SYann Gautier 143*bc3eebb2SYann Gautier if (is_bad == 1) { 144*bc3eebb2SYann Gautier count_bb++; 145*bc3eebb2SYann Gautier offset_block++; 146*bc3eebb2SYann Gautier } 147*bc3eebb2SYann Gautier 148*bc3eebb2SYann Gautier block++; 149*bc3eebb2SYann Gautier } 150*bc3eebb2SYann Gautier 151*bc3eebb2SYann Gautier *extra_offset = count_bb * nand_dev.block_size; 152*bc3eebb2SYann Gautier 153*bc3eebb2SYann Gautier return 0; 154*bc3eebb2SYann Gautier } 155*bc3eebb2SYann Gautier 156b114abb6SLionel Debieve struct nand_device *get_nand_device(void) 157b114abb6SLionel Debieve { 158b114abb6SLionel Debieve return &nand_dev; 159b114abb6SLionel Debieve } 160