📄 nand_legacy.c
字号:
NAND_ENABLE_CE(nand); /* set pin low */ /* Reset the chip */ if (NanD_Command(nand, NAND_CMD_RESET)) {#ifdef NAND_DEBUG printf("NanD_Command (reset) for %d,%d returned true\n", floor, chip);#endif NAND_DISABLE_CE(nand); /* set pin high */ return 0; } /* Read the NAND chip ID: 1. Send ReadID command */ if (NanD_Command(nand, NAND_CMD_READID)) {#ifdef NAND_DEBUG printf("NanD_Command (ReadID) for %d,%d returned true\n", floor, chip);#endif NAND_DISABLE_CE(nand); /* set pin high */ return 0; } /* Read the NAND chip ID: 2. Send address byte zero */ NanD_Address(nand, ADDR_COLUMN, 0); /* Read the manufacturer and device id codes from the device */ mfr = READ_NAND(nand->IO_ADDR); id = READ_NAND(nand->IO_ADDR); NAND_DISABLE_CE(nand); /* set pin high */#ifdef NAND_DEBUG printf("NanD_Command (ReadID) got %x %x\n", mfr, id);#endif if (mfr == 0xff || mfr == 0) { /* No response - return failure */ return 0; } /* Check it's the same as the first chip we identified. * M-Systems say that any given nand_chip device should only * contain _one_ type of flash part, although that's not a * hardware restriction. */ if (nand->mfr) { if (nand->mfr == mfr && nand->id == id) { return 1; /* This is another the same the first */ } else { printf("Flash chip at floor %d, chip %d is different:\n", floor, chip); } } /* Print and store the manufacturer and ID codes. */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { if (mfr == nand_flash_ids[i].manufacture_id && id == nand_flash_ids[i].model_id) {#ifdef NAND_DEBUG printf("Flash chip found:\n\t Manufacturer ID: 0x%2.2X, " "Chip ID: 0x%2.2X (%s)\n", mfr, id, nand_flash_ids[i].name);#endif if (!nand->mfr) { nand->mfr = mfr; nand->id = id; nand->chipshift = nand_flash_ids[i].chipshift; nand->page256 = nand_flash_ids[i].page256; nand->eccsize = 256; if (nand->page256) { nand->oobblock = 256; nand->oobsize = 8; nand->page_shift = 8; } else { nand->oobblock = 512; nand->oobsize = 16; nand->page_shift = 9; } nand->pageadrlen = nand_flash_ids[i].pageadrlen; nand->erasesize = nand_flash_ids[i].erasesize; nand->chips_name = nand_flash_ids[i].name; nand->bus16 = nand_flash_ids[i].bus16; return 1; } return 0; } }#ifdef NAND_DEBUG /* We haven't fully identified the chip. Print as much as we know. */ printf("Unknown flash chip found: %2.2X %2.2X\n", id, mfr);#endif return 0;}/* NanD_ScanChips: Find all NAND chips present in a nand_chip, and identify them */static void NanD_ScanChips(struct nand_chip *nand){ int floor, chip; int numchips[NAND_MAX_FLOORS]; int maxchips = NAND_MAX_CHIPS; int ret = 1; nand->numchips = 0; nand->mfr = 0; nand->id = 0; /* For each floor, find the number of valid chips it contains */ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { ret = 1; numchips[floor] = 0; for (chip = 0; chip < maxchips && ret != 0; chip++) { ret = NanD_IdentChip(nand, floor, chip); if (ret) { numchips[floor]++; nand->numchips++; } } } /* If there are none at all that we recognise, bail */ if (!nand->numchips) {#ifdef NAND_DEBUG puts ("No NAND flash chips recognised.\n");#endif return; } /* Allocate an array to hold the information for each chip */ nand->chips = malloc(sizeof(struct Nand) * nand->numchips); if (!nand->chips) { puts ("No memory for allocating chip info structures\n"); return; } ret = 0; /* Fill out the chip array with {floor, chipno} for each * detected chip in the device. */ for (floor = 0; floor < NAND_MAX_FLOORS; floor++) { for (chip = 0; chip < numchips[floor]; chip++) { nand->chips[ret].floor = floor; nand->chips[ret].chip = chip; nand->chips[ret].curadr = 0; nand->chips[ret].curmode = 0x50; ret++; } } /* Calculate and print the total size of the device */ nand->totlen = nand->numchips * (1 << nand->chipshift);#ifdef NAND_DEBUG printf("%d flash chips found. Total nand_chip size: %ld MB\n", nand->numchips, nand->totlen >> 20);#endif}/* we need to be fast here, 1 us per read translates to 1 second per meg */static void NanD_ReadBuf (struct nand_chip *nand, u_char * data_buf, int cntr){ unsigned long nandptr = nand->IO_ADDR; NanD_Command (nand, NAND_CMD_READ0); if (nand->bus16) { u16 val; while (cntr >= 16) { val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; cntr -= 16; } while (cntr > 0) { val = READ_NAND (nandptr); *data_buf++ = val & 0xff; *data_buf++ = val >> 8; cntr -= 2; } } else { while (cntr >= 16) { *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); *data_buf++ = READ_NAND (nandptr); cntr -= 16; } while (cntr > 0) { *data_buf++ = READ_NAND (nandptr); cntr--; } }}/* * NAND read with ECC */static int nand_read_ecc(struct nand_chip *nand, size_t start, size_t len, size_t * retlen, u_char *buf, u_char *ecc_code){ int col, page; int ecc_status = 0;#ifdef CONFIG_MTD_NAND_ECC int j; int ecc_failed = 0; u_char *data_poi; u_char ecc_calc[6];#endif /* Do not allow reads past end of device */ if ((start + len) > nand->totlen) { printf ("%s: Attempt read beyond end of device %x %x %x\n", __FUNCTION__, (uint) start, (uint) len, (uint) nand->totlen); *retlen = 0; return -1; } /* First we calculate the starting page */ /*page = shr(start, nand->page_shift);*/ page = start >> nand->page_shift; /* Get raw starting column */ col = start & (nand->oobblock - 1); /* Initialize return value */ *retlen = 0; /* Select the NAND device */ NAND_ENABLE_CE(nand); /* set pin low */ /* Loop until all data read */ while (*retlen < len) {#ifdef CONFIG_MTD_NAND_ECC /* Do we have this page in cache ? */ if (nand->cache_page == page) goto readdata; /* Send the read command */ NanD_Command(nand, NAND_CMD_READ0); if (nand->bus16) { NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + (col >> 1)); } else { NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); } /* Read in a page + oob data */ NanD_ReadBuf(nand, nand->data_buf, nand->oobblock + nand->oobsize); /* copy data into cache, for read out of cache and if ecc fails */ if (nand->data_cache) { memcpy (nand->data_cache, nand->data_buf, nand->oobblock + nand->oobsize); } /* Pick the ECC bytes out of the oob data */ for (j = 0; j < 6; j++) { ecc_code[j] = nand->data_buf[(nand->oobblock + oob_config.ecc_pos[j])]; } /* Calculate the ECC and verify it */ /* If block was not written with ECC, skip ECC */ if (oob_config.eccvalid_pos != -1 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0x0f) != 0x0f) { nand_calculate_ecc (&nand->data_buf[0], &ecc_calc[0]); switch (nand_correct_data (&nand->data_buf[0], &ecc_code[0], &ecc_calc[0])) { case -1: printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); ecc_failed++; break; case 1: case 2: /* transfer ECC corrected data to cache */ if (nand->data_cache) memcpy (nand->data_cache, nand->data_buf, 256); break; } } if (oob_config.eccvalid_pos != -1 && nand->oobblock == 512 && (nand->data_buf[nand->oobblock + oob_config.eccvalid_pos] & 0xf0) != 0xf0) { nand_calculate_ecc (&nand->data_buf[256], &ecc_calc[3]); switch (nand_correct_data (&nand->data_buf[256], &ecc_code[3], &ecc_calc[3])) { case -1: printf ("%s: Failed ECC read, page 0x%08x\n", __FUNCTION__, page); ecc_failed++; break; case 1: case 2: /* transfer ECC corrected data to cache */ if (nand->data_cache) memcpy (&nand->data_cache[256], &nand->data_buf[256], 256); break; } }readdata: /* Read the data from ECC data buffer into return buffer */ data_poi = (nand->data_cache) ? nand->data_cache : nand->data_buf; data_poi += col; if ((*retlen + (nand->oobblock - col)) >= len) { memcpy (buf + *retlen, data_poi, len - *retlen); *retlen = len; } else { memcpy (buf + *retlen, data_poi, nand->oobblock - col); *retlen += nand->oobblock - col; } /* Set cache page address, invalidate, if ecc_failed */ nand->cache_page = (nand->data_cache && !ecc_failed) ? page : -1; ecc_status += ecc_failed; ecc_failed = 0;#else /* Send the read command */ NanD_Command(nand, NAND_CMD_READ0); if (nand->bus16) { NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + (col >> 1)); } else { NanD_Address(nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + col); } /* Read the data directly into the return buffer */ if ((*retlen + (nand->oobblock - col)) >= len) { NanD_ReadBuf(nand, buf + *retlen, len - *retlen); *retlen = len; /* We're done */ continue; } else { NanD_ReadBuf(nand, buf + *retlen, nand->oobblock - col); *retlen += nand->oobblock - col; }#endif /* For subsequent reads align to page boundary. */ col = 0; /* Increment page address */ page++; } /* De-select the NAND device */ NAND_DISABLE_CE(nand); /* set pin high */ /* * Return success, if no ECC failures, else -EIO * fs driver will take care of that, because * retlen == desired len and result == -EIO */ return ecc_status ? -1 : 0;}/* * Nand_page_program function is used for write and writev ! * Change By www.arm9.net, if ecc_code is null, write without ECC */static int nand_write_page (struct nand_chip *nand, int page, int col, int last, u_char * ecc_code){ int i; unsigned long nandptr = nand->IO_ADDR; int writecnt;#ifdef CONFIG_MTD_NAND_ECC#ifdef CONFIG_MTD_NAND_VERIFY_WRITE int ecc_bytes = (nand->oobblock == 512) ? 6 : 3;#endif#endif /* pad oob area */ for (i = nand->oobblock; i < nand->oobblock + nand->oobsize; i++) nand->data_buf[i] = 0xff;#ifdef CONFIG_MTD_NAND_ECC /* Zero out the ECC array */ if (ecc_code) /* www.arm9.net */ for (i = 0; i < 6; i++) ecc_code[i] = 0x00; /* Read back previous written data, if col > 0 */ if (col) { NanD_Command (nand, NAND_CMD_READ0); if (nand->bus16) { NanD_Address (nand, ADDR_COLUMN_PAGE, (page << nand->page_shift) + (col >> 1));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -