X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fmtd%2Fonenand%2Fonenand_spl.c;h=0b78067a23b63c295d5bbbc1cc48d041a4a9d4cc;hb=4bafceff0e9e5a36908031e41c69a6b37e82da58;hp=fe6b7d923ccc56bf75d9c07d116e50240f5c98be;hpb=aaf5e825606a70ddc8fca8e366d8c16a6fd3cc7c;p=oweals%2Fu-boot.git diff --git a/drivers/mtd/onenand/onenand_spl.c b/drivers/mtd/onenand/onenand_spl.c index fe6b7d923c..0b78067a23 100644 --- a/drivers/mtd/onenand/onenand_spl.c +++ b/drivers/mtd/onenand/onenand_spl.c @@ -23,11 +23,29 @@ enum onenand_spl_pagesize { PAGE_4K = 4096, }; +static unsigned int density_mask; + #define ONENAND_PAGES_PER_BLOCK 64 -#define onenand_block_address(block) (block) #define onenand_sector_address(page) (page << 2) #define onenand_buffer_address() ((1 << 3) << 8) -#define onenand_bufferram_address(block) (0) + +static inline int onenand_block_address(int block) +{ + /* Device Flash Core select, NAND Flash Block Address */ + if (block & density_mask) + return ONENAND_DDP_CHIP1 | (block ^ density_mask); + + return block; +} + +static inline int onenand_bufferram_address(int block) +{ + /* Device BufferRAM Select */ + if (block & density_mask) + return ONENAND_DDP_CHIP1; + + return ONENAND_DDP_CHIP0; +} static inline uint16_t onenand_readw(uint32_t addr) { @@ -41,7 +59,7 @@ static inline void onenand_writew(uint16_t value, uint32_t addr) static enum onenand_spl_pagesize onenand_spl_get_geometry(void) { - uint32_t dev_id, density; + unsigned int dev_id, density, size; if (!onenand_readw(ONENAND_REG_TECHNOLOGY)) { dev_id = onenand_readw(ONENAND_REG_DEVICE_ID); @@ -51,8 +69,11 @@ static enum onenand_spl_pagesize onenand_spl_get_geometry(void) if (density < ONENAND_DEVICE_DENSITY_4Gb) return PAGE_2K; - if (dev_id & ONENAND_DEVICE_IS_DDP) + if (dev_id & ONENAND_DEVICE_IS_DDP) { + size = onenand_readw(ONENAND_REG_DATA_BUFFER_SIZE); + density_mask = 1 << (18 + density - ffs(size)); return PAGE_2K; + } } return PAGE_4K; @@ -93,6 +114,57 @@ static int onenand_spl_read_page(uint32_t block, uint32_t page, uint32_t *buf, return 0; } +#ifdef CONFIG_SPL_UBI +/* Temporary storage for non page aligned and non page sized reads. */ +static u8 scratch_buf[PAGE_4K]; + +/** + * onenand_spl_read_block - Read data from physical eraseblock into a buffer + * @block: Number of the physical eraseblock + * @offset: Data offset from the start of @peb + * @len: Data size to read + * @dst: Address of the destination buffer + * + * Notes: + * @offset + @len are not allowed to be larger than a physical + * erase block. No sanity check done for simplicity reasons. + */ +int onenand_spl_read_block(int block, int offset, int len, void *dst) +{ + int page, read; + static int psize; + + if (!psize) + psize = onenand_spl_get_geometry(); + + /* Calculate the page number */ + page = offset / psize; + /* Offset to the start of a flash page */ + offset = offset % psize; + + while (len) { + /* + * Non page aligned reads go to the scratch buffer. + * Page aligned reads go directly to the destination. + */ + if (offset || len < psize) { + onenand_spl_read_page(block, page, + (uint32_t *)scratch_buf, psize); + read = min(len, psize - offset); + memcpy(dst, scratch_buf + offset, read); + offset = 0; + } else { + onenand_spl_read_page(block, page, dst, psize); + read = psize; + } + page++; + len -= read; + dst += read; + } + return 0; +} +#endif + void onenand_spl_load_image(uint32_t offs, uint32_t size, void *dst) { uint32_t *addr = (uint32_t *)dst;