Ladislav Michl | c6a4200 | 2017-04-16 15:31:59 +0200 | [diff] [blame] | 1 | int nand_spl_load_image(uint32_t offs, unsigned int size, void *dst) |
| 2 | { |
| 3 | unsigned int block, lastblock; |
| 4 | unsigned int page, page_offset; |
| 5 | |
| 6 | /* offs has to be aligned to a page address! */ |
| 7 | block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; |
| 8 | lastblock = (offs + size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; |
| 9 | page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; |
| 10 | page_offset = offs % CONFIG_SYS_NAND_PAGE_SIZE; |
| 11 | |
| 12 | while (block <= lastblock) { |
| 13 | if (!nand_is_bad_block(block)) { |
| 14 | /* Skip bad blocks */ |
| 15 | while (page < CONFIG_SYS_NAND_PAGE_COUNT) { |
| 16 | nand_read_page(block, page, dst); |
| 17 | /* |
| 18 | * When offs is not aligned to page address the |
| 19 | * extra offset is copied to dst as well. Copy |
| 20 | * the image such that its first byte will be |
| 21 | * at the dst. |
| 22 | */ |
| 23 | if (unlikely(page_offset)) { |
| 24 | memmove(dst, dst + page_offset, |
| 25 | CONFIG_SYS_NAND_PAGE_SIZE); |
| 26 | dst = (void *)((int)dst - page_offset); |
| 27 | page_offset = 0; |
| 28 | } |
| 29 | dst += CONFIG_SYS_NAND_PAGE_SIZE; |
| 30 | page++; |
| 31 | } |
| 32 | |
| 33 | page = 0; |
| 34 | } else { |
| 35 | lastblock++; |
| 36 | } |
| 37 | |
| 38 | block++; |
| 39 | } |
| 40 | |
| 41 | return 0; |
| 42 | } |
| 43 | |
| 44 | #ifdef CONFIG_SPL_UBI |
| 45 | /* |
| 46 | * Temporary storage for non NAND page aligned and non NAND page sized |
| 47 | * reads. Note: This does not support runtime detected FLASH yet, but |
| 48 | * that should be reasonably easy to fix by making the buffer large |
| 49 | * enough :) |
| 50 | */ |
| 51 | static u8 scratch_buf[CONFIG_SYS_NAND_PAGE_SIZE]; |
| 52 | |
| 53 | /** |
| 54 | * nand_spl_read_block - Read data from physical eraseblock into a buffer |
| 55 | * @block: Number of the physical eraseblock |
| 56 | * @offset: Data offset from the start of @peb |
| 57 | * @len: Data size to read |
| 58 | * @dst: Address of the destination buffer |
| 59 | * |
| 60 | * This could be further optimized if we'd have a subpage read |
| 61 | * function in the simple code. On NAND which allows subpage reads |
| 62 | * this would spare quite some time to readout e.g. the VID header of |
| 63 | * UBI. |
| 64 | * |
| 65 | * Notes: |
| 66 | * @offset + @len are not allowed to be larger than a physical |
| 67 | * erase block. No sanity check done for simplicity reasons. |
| 68 | * |
| 69 | * To support runtime detected flash this needs to be extended by |
| 70 | * information about the actual flash geometry, but thats beyond the |
| 71 | * scope of this effort and for most applications where fast boot is |
| 72 | * required it is not an issue anyway. |
| 73 | */ |
| 74 | int nand_spl_read_block(int block, int offset, int len, void *dst) |
| 75 | { |
| 76 | int page, read; |
| 77 | |
| 78 | /* Calculate the page number */ |
| 79 | page = offset / CONFIG_SYS_NAND_PAGE_SIZE; |
| 80 | |
| 81 | /* Offset to the start of a flash page */ |
| 82 | offset = offset % CONFIG_SYS_NAND_PAGE_SIZE; |
| 83 | |
| 84 | while (len) { |
| 85 | /* |
| 86 | * Non page aligned reads go to the scratch buffer. |
| 87 | * Page aligned reads go directly to the destination. |
| 88 | */ |
| 89 | if (offset || len < CONFIG_SYS_NAND_PAGE_SIZE) { |
| 90 | nand_read_page(block, page, scratch_buf); |
| 91 | read = min(len, CONFIG_SYS_NAND_PAGE_SIZE - offset); |
| 92 | memcpy(dst, scratch_buf + offset, read); |
| 93 | offset = 0; |
| 94 | } else { |
| 95 | nand_read_page(block, page, dst); |
| 96 | read = CONFIG_SYS_NAND_PAGE_SIZE; |
| 97 | } |
| 98 | page++; |
| 99 | len -= read; |
| 100 | dst += read; |
| 101 | } |
| 102 | return 0; |
| 103 | } |
| 104 | #endif |