static int nand_read_buffer(struct nfc_config *conf, uint32_t offs, unsigned int size, void *dest) { int first_seed, page, ret; size = ALIGN(size, conf->page_size); page = offs / conf->page_size; first_seed = page % conf->nseeds; for (; size; size -= conf->page_size) { if (nand_load_page(conf, offs)) return -1; ret = nand_read_page(conf, offs, dest, conf->page_size); /* * The ->nseeds value should be equal to the number of pages * in an eraseblock. Since we don't know this information in * advance we might have picked a wrong value. */ if (ret < 0 && conf->randomize) { int cur_seed = page % conf->nseeds; /* * We already tried all the seed values => we are * facing a real corruption. */ if (cur_seed < first_seed) return -EIO; /* Try to adjust ->nseeds and read the page again... */ conf->nseeds = cur_seed; if (nand_reset_column()) return -EIO; /* ... it still fails => it's a real corruption. */ if (nand_read_page(conf, offs, dest, conf->page_size)) return -EIO; } else if (ret && conf->randomize) { memset(dest, 0xff, conf->page_size); } page++; offs += conf->page_size; dest += conf->page_size; } return 0; }
void copy_nand2sdram() { unsigned long bootSize = (unsigned long)(&bss_start) - 0x30000000; //uboot代码长度 unsigned long blockTotal,pageTotal; blockTotal = ( (bootSize + NAND_BLOCK_MASK ) & (~NAND_BLOCK_MASK) ) / NAND_BLOCK_SIZE; pageTotal = ( (bootSize + NAND_PAGE_MASK ) & (~NAND_PAGE_MASK) ) / NAND_PAGE_SIZE; //烧录进FLASH,不带坏块检测 unsigned char *lpdstData = (unsigned char *)0x30000000; //SDRAM 0x30000000地址的代码 unsigned int off_data,page_addr; int pcPoint; //查看PC指针位置,如果指针在0~4096表示在SRAM中运行,拷贝Nand到SDRAM //否则表示代码在SDRAM中,跳过Nand拷贝 pcPoint = _where_lr(); if(pcPoint < 4096) { nand_init(); off_data = 0; page_addr = 0; while(off_data < bootSize) { nand_read_page( page_addr, (unsigned char*)(lpdstData + off_data)); // printk("colum 0x%8.8x write data off %d page_addr %d\r\n",off_data,off_data,page_addr); // PrintNandFlash((unsigned char*)(lpsrcData + off_data),16); off_data += NAND_PAGE_SIZE; page_addr += NAND_PAGE_ADDR; } } }
static int nand_load(unsigned int offs, unsigned int uboot_size, uchar *dst) { unsigned int block, lastblock, page; /* offs has to be aligned to a page address! */ block = offs / CONFIG_SYS_NAND_BLOCK_SIZE; lastblock = (offs + uboot_size - 1) / CONFIG_SYS_NAND_BLOCK_SIZE; page = (offs % CONFIG_SYS_NAND_BLOCK_SIZE) / CONFIG_SYS_NAND_PAGE_SIZE; while (block <= lastblock) { while (page < CONFIG_SYS_NAND_PAGE_COUNT) { nand_read_page(block, page, dst); dst += CONFIG_SYS_NAND_PAGE_SIZE; page++; } page = 0; block++; } return; }
/* read a block data to buf * return 1 if the block is bad or ECC error can't be corrected for any page * return 0 on sucess */ int nand_read_block(unsigned char *buf, ulong block_addr) { int i, offset = 0; uchar oob_buf[16]; /* check bad block */ /* 0th and 5th words need be 0xffff */ if (nand_read_oob(oob_buf, block_addr) || // oob_buf[0] != 0xff || oob_buf[1] != 0xff || // oob_buf[10] != 0xff || oob_buf[11] != 0xff ){ oob_buf[5] != 0xff){ printf("Skipped bad block at 0x%x\n", block_addr); return NAND_READ_SKIPPED_BAD_BLOCK; /* skip bad block */ } /* read the block page by page*/ for (i=0; i<32; i++){ if (nand_read_page(buf+offset, block_addr + offset)) return NAND_READ_ECC_FAILURE; offset += PAGE_SIZE; } return NAND_READ_SUCCESS; }
void nand_spl_init(void) { ulong buffer[6]; u8 page_buf[CONFIG_NAND_PAGE_SIZE]; ulong ddr_magic=0x88888888; ulong erase_addr1=0, erase_addr2=0; ulong ecc; int i; erase_addr1 = IFX_CFG_FLASH_DDR_CFG_START_ADDR; erase_addr2 = IFX_CFG_FLASH_DDR_CFG_START_ADDR + IFX_CFG_FLASH_DDR_CFG_SIZE; serial_init(); buffer[0] = 0; asm("sync"); nand_read_page((131072/CONFIG_NAND_PAGE_SIZE)-1,page_buf); asm("sync"); for(i=0; i<6; i++) { buffer[i] = *(volatile u32*)(page_buf+CONFIG_NAND_PAGE_SIZE-24+i*4); /*last 24 bytes of 16k bytes*/ } if(buffer[0]==ddr_magic) { ecc=buffer[1]^buffer[2]^buffer[3]^buffer[4]; if(ecc!=buffer[5]) { REG32(0xBe1a7f20)=0xff; } else { REG32(0xBe1a7f20)=0; } } else { REG32(0xBe1a7f20)=0xff; } /* Clear Error log registers */ REG32(MC_ERRCAUSE)= 0; REG32(MC_ERRADDR) = 0; asm("sync"); /* Enable DDR module in memory controller */ REG32(MC_CON)= REG32(MC_CON)|MC_DDRRAM_ENABLE; asm("sync"); if(REG32(0xBe1a7f20)==0xff) { REG32(MC_DC21)= 0; REG32(MC_DC22)=0; } else { REG32(MC_DC15)= buffer[1]; REG32(MC_DC21)= buffer[2]; REG32(MC_DC22)= buffer[3]; REG32(MC_DC24)= buffer[4]; } asm("sync"); REG32(MC_DC03) = 0x00000100; while((REG32(0xbf800070)& 0x08)!=0x08); asm("sync"); tune_ddr(); asm("sync"); nand_boot(); }
static int nand_detect_ecc_config(struct nfc_config *conf, u32 offs, void *dest) { /* NAND with pages > 4k will likely require 1k sector size. */ int min_ecc_size = conf->page_size > 4096 ? 1024 : 512; int page = offs / conf->page_size; int ret; /* * In most cases, 1k sectors are preferred over 512b ones, start * testing this config first. */ for (conf->ecc_size = 1024; conf->ecc_size >= min_ecc_size; conf->ecc_size >>= 1) { int max_ecc_strength = nand_max_ecc_strength(conf); nand_apply_config(conf); /* * We are starting from the maximum ECC strength because * most of the time NAND vendors provide an OOB area that * barely meets the ECC requirements. */ for (conf->ecc_strength = max_ecc_strength; conf->ecc_strength >= 0; conf->ecc_strength--) { conf->randomize = false; if (nand_reset_column()) return -EIO; /* * Only read the first sector to speedup detection. */ ret = nand_read_page(conf, offs, dest, conf->ecc_size); if (!ret) { return 0; } else if (ret > 0) { /* * If page is empty we can't deduce anything * about the ECC config => stop the detection. */ return -EINVAL; } conf->randomize = true; conf->nseeds = ARRAY_SIZE(random_seed); do { if (nand_reset_column()) return -EIO; if (!nand_read_page(conf, offs, dest, conf->ecc_size)) return 0; /* * Find the next ->nseeds value that would * change the randomizer seed for the page * we're trying to read. */ while (conf->nseeds >= 16) { int seed = page % conf->nseeds; conf->nseeds >>= 1; if (seed != page % conf->nseeds) break; } } while (conf->nseeds >= 16); } } return -EINVAL; }