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