📄 cmd_doc.c.svn-base
字号:
volatile int dummy; int modulus = 0xffff; unsigned long docptr; int i; docptr = doc->virtadr; if (len <= 0) return; if (DoC_is_Millennium(doc)) { /* Read the data via the internal pipeline through CDSN IO register, see Pipelined Read Operations 11.3 */ dummy = ReadDOC(docptr, ReadPipeInit); /* Millennium should use the LastDataRead register - Pipeline Reads */ len--; /* This is needed for correctly ECC calculation */ modulus = 0xff; } for (i = 0; i < len; i++) buf[i] = ReadDOC_(docptr, doc->ioreg + (i & modulus)); if (DoC_is_Millennium(doc)) { buf[i] = ReadDOC(docptr, LastDataRead); }}/* Write a buffer to DoC, taking care of Millennium oddities */static void DoC_WriteBuf(struct DiskOnChip *doc, const u_char * buf, int len){ unsigned long docptr; int i; docptr = doc->virtadr; if (len <= 0) return; for (i = 0; i < len; i++) WriteDOC_(buf[i], docptr, doc->ioreg + i); if (DoC_is_Millennium(doc)) { WriteDOC(0x00, docptr, WritePipeTerm); }}/* DoC_SelectChip: Select a given flash chip within the current floor */static inline int DoC_SelectChip(struct DiskOnChip *doc, int chip){ unsigned long docptr = doc->virtadr; /* Software requirement 11.4.4 before writing DeviceSelect */ /* Deassert the CE line to eliminate glitches on the FCE# outputs */ WriteDOC(CDSN_CTRL_WP, docptr, CDSNControl); DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ /* Select the individual flash chip requested */ WriteDOC(chip, docptr, CDSNDeviceSelect); DoC_Delay(doc, 4); /* Reassert the CE line */ WriteDOC(CDSN_CTRL_CE | CDSN_CTRL_FLASH_IO | CDSN_CTRL_WP, docptr, CDSNControl); DoC_Delay(doc, 4); /* Software requirement 11.4.3 for Millennium */ /* Wait for it to be ready */ return DoC_WaitReady(doc);}/* DoC_SelectFloor: Select a given floor (bank of flash chips) */static inline int DoC_SelectFloor(struct DiskOnChip *doc, int floor){ unsigned long docptr = doc->virtadr; /* Select the floor (bank) of chips required */ WriteDOC(floor, docptr, FloorSelect); /* Wait for the chip to be ready */ return DoC_WaitReady(doc);}/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip){ int mfr, id, i; volatile char dummy; /* Page in the required floor/chip */ DoC_SelectFloor(doc, floor); DoC_SelectChip(doc, chip); /* Reset the chip */ if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) {#ifdef DOC_DEBUG printf("DoC_Command (reset) for %d,%d returned true\n", floor, chip);#endif return 0; } /* Read the NAND chip ID: 1. Send ReadID command */ if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) {#ifdef DOC_DEBUG printf("DoC_Command (ReadID) for %d,%d returned true\n", floor, chip);#endif return 0; } /* Read the NAND chip ID: 2. Send address byte zero */ DoC_Address(doc, ADDR_COLUMN, 0, CDSN_CTRL_WP, 0); /* Read the manufacturer and device id codes from the device */ /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ dummy = ReadDOC(doc->virtadr, CDSNSlowIO); DoC_Delay(doc, 2); mfr = ReadDOC_(doc->virtadr, doc->ioreg); /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ dummy = ReadDOC(doc->virtadr, CDSNSlowIO); DoC_Delay(doc, 2); id = ReadDOC_(doc->virtadr, doc->ioreg); /* No response - return failure */ if (mfr == 0xff || mfr == 0) return 0; /* Check it's the same as the first chip we identified. * M-Systems say that any given DiskOnChip device should only * contain _one_ type of flash part, although that's not a * hardware restriction. */ if (doc->mfr) { if (doc->mfr == mfr && doc->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 DOC_DEBUG printf("Flash chip found: Manufacturer ID: %2.2X, " "Chip ID: %2.2X (%s)\n", mfr, id, nand_flash_ids[i].name);#endif if (!doc->mfr) { doc->mfr = mfr; doc->id = id; doc->chipshift = nand_flash_ids[i].chipshift; doc->page256 = nand_flash_ids[i].page256; doc->pageadrlen = nand_flash_ids[i].pageadrlen; doc->erasesize = nand_flash_ids[i].erasesize; doc->chips_name = nand_flash_ids[i].name; return 1; } return 0; } }#ifdef DOC_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;}/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */static void DoC_ScanChips(struct DiskOnChip *this){ int floor, chip; int numchips[MAX_FLOORS]; int maxchips = MAX_CHIPS; int ret = 1; this->numchips = 0; this->mfr = 0; this->id = 0; if (DoC_is_Millennium(this)) maxchips = MAX_CHIPS_MIL; /* For each floor, find the number of valid chips it contains */ for (floor = 0; floor < MAX_FLOORS; floor++) { ret = 1; numchips[floor] = 0; for (chip = 0; chip < maxchips && ret != 0; chip++) { ret = DoC_IdentChip(this, floor, chip); if (ret) { numchips[floor]++; this->numchips++; } } } /* If there are none at all that we recognise, bail */ if (!this->numchips) { puts ("No flash chips recognised.\n"); return; } /* Allocate an array to hold the information for each chip */ this->chips = malloc(sizeof(struct Nand) * this->numchips); if (!this->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 < MAX_FLOORS; floor++) { for (chip = 0; chip < numchips[floor]; chip++) { this->chips[ret].floor = floor; this->chips[ret].chip = chip; this->chips[ret].curadr = 0; this->chips[ret].curmode = 0x50; ret++; } } /* Calculate and print the total size of the device */ this->totlen = this->numchips * (1 << this->chipshift);#ifdef DOC_DEBUG printf("%d flash chips found. Total DiskOnChip size: %ld MB\n", this->numchips, this->totlen >> 20);#endif}/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c */static int find_boot_record(struct NFTLrecord *nftl){ struct nftl_uci1 h1; struct nftl_oob oob; unsigned int block, boot_record_count = 0; int retlen; u8 buf[SECTORSIZE]; struct NFTLMediaHeader *mh = &nftl->MediaHdr; unsigned int i; nftl->MediaUnit = BLOCK_NIL; nftl->SpareMediaUnit = BLOCK_NIL; /* search for a valid boot record */ for (block = 0; block < nftl->nb_blocks; block++) { int ret; /* Check for ANAND header first. Then can whinge if it's found but later checks fail */ if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf, NULL))) { static int warncount = 5; if (warncount) { printf("Block read at 0x%x failed\n", block * nftl->EraseSize); if (!--warncount) puts ("Further failures for this block will not be printed\n"); } continue; } if (retlen < 6 || memcmp(buf, "ANAND", 6)) { /* ANAND\0 not found. Continue */#ifdef PSYCHO_DEBUG printf("ANAND header not found at 0x%x\n", block * nftl->EraseSize);#endif continue; }#ifdef NFTL_DEBUG printf("ANAND header found at 0x%x\n", block * nftl->EraseSize);#endif /* To be safer with BIOS, also use erase mark as discriminant */ if ((ret = doc_read_oob(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) {#ifdef NFTL_DEBUG printf("ANAND header found at 0x%x, but OOB data read failed\n", block * nftl->EraseSize);#endif continue; } /* OK, we like it. */ if (boot_record_count) { /* We've already processed one. So we just check if this one is the same as the first one we found */ if (memcmp(mh, buf, sizeof(struct NFTLMediaHeader))) {#ifdef NFTL_DEBUG printf("NFTL Media Headers at 0x%x and 0x%x disagree.\n", nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize);#endif /* if (debug) Print both side by side */ return -1; } if (boot_record_count == 1) nftl->SpareMediaUnit = block; boot_record_count++; continue; } /* This is the first we've seen. Copy the media header structure into place */ memcpy(mh, buf, sizeof(struct NFTLMediaHeader)); /* Do some sanity checks on it */ if (mh->UnitSizeFactor == 0) {#ifdef NFTL_DEBUG puts ("UnitSizeFactor 0x00 detected.\n" "This violates the spec but we think we know what it means...\n");#endif } else if (mh->UnitSizeFactor != 0xff) { printf ("Sorry, we don't support UnitSizeFactor " "of != 1 yet.\n"); return -1; } nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { printf ("NFTL Media Header sanity check failed:\n" "nb_boot_blocks (%d) + 2 > nb_blocks (%d)\n", nftl->nb_boot_blocks, nftl->nb_blocks); return -1; } nftl->numvunits = le32_to_cpu(mh->FormattedSize) / nftl->EraseSize; if (nftl->numvunits > (nftl->nb_blocks - nftl->nb_boot_blocks - 2)) { printf ("NFTL Media Header sanity check failed:\n" "numvunits (%d) > nb_blocks (%d) - nb_boot_blocks(%d) - 2\n", nftl->numvunits, nftl->nb_blocks, nftl->nb_boot_blocks); return -1; } nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); /* If we're not using the last sectors in the device for some reason, reduce nb_blocks accordingly so we forget they're there */ nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN); /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */ for (i = 0; i < nftl->nb_blocks; i++) { if ((i & (SECTORSIZE - 1)) == 0) { /* read one sector for every SECTORSIZE of blocks */ if ((ret = doc_read_ecc(nftl->mtd, block * nftl->EraseSize + i + SECTORSIZE, SECTORSIZE, &retlen, buf, (char *)&oob)) < 0) { puts ("Read of bad sector table failed\n"); return -1; } } /* mark the Bad Erase Unit as RESERVED in ReplUnitTable */ if (buf[i & (SECTORSIZE - 1)] != 0xff) nftl->ReplUnitTable[i] = BLOCK_RESERVED; } nftl->MediaUnit = block; boot_record_count++; } /* foreach (block) */ return boot_record_count?0:-1;}/* This routine is made available to other mtd code via * inter_module_register. It must only be accessed through * inter_module_get which will bump the use count of this module. The * addresses passed back in mtd are valid as long as the use count of * this module is non-zero, i.e. between inter_module_get and * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000. */static void DoC2k_init(struct DiskOnChip* this){ struct NFTLrecord *nftl; switch (this->ChipID) { case DOC_ChipID_Doc2k: this->name = "DiskOnChip 2000"; this->ioreg = DoC_2k_CDSN_IO; break; case DOC_ChipID_DocMil: this->name = "DiskOnChip Millennium"; this->ioreg = DoC_Mil_CDSN_IO; break; }#ifdef DOC_DEBUG printf("%s found at address 0x%lX\n", this->name, this->physadr);#endif this->totlen = 0; this->numchips = 0; this->curfloor = -1; this->curchip = -1; /* Ident all the chips present. */ DoC_ScanChips(this); if ((!this->numchips) || (!this->chips)) return; nftl = &this->nftl; /* Get physical parameters */ nftl->EraseSize = this->erasesize; nftl->nb_blocks = this->totlen / this->erasesize; nftl->mtd = this; if (find_boot_record(nftl) != 0) this->nftl_found = 0; else this->nftl_found = 1; printf("%s @ 0x%lX, %ld MB\n", this->name, this->physadr, this->totlen >> 20);}int doc_read_ecc(struct DiskOnChip* this, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * eccbuf){ unsigned long docptr; struct Nand *mychip; unsigned char syndrome[6]; volatile char dummy; int i, len256 = 0, ret=0; docptr = this->virtadr; /* Don't allow read past end of device */ if (from >= this->totlen) { puts ("Out of flash\n"); return DOC_EINVAL; } /* Don't allow a single read to cross a 512-byte block boundary */ if (from + len > ((from | 0x1ff) + 1)) len = ((from | 0x1ff) + 1) - from; /* The ECC will not be calculated correctly if less than 512 is read */ if (len != 0x200 && eccbuf) printf("ECC needs a full sector read (adr: %lx size %lx)\n", (long) from, (long) len);#ifdef PSYCHO_DEBUG printf("DoC_Read (adr: %lx size %lx)\n", (long) from, (long) len);#endif /* Find the chip which is to be used and select it */ mychip = &this->chips[shr(from, this->chipshift)]; if (this->curfloor != mychip->floor) { DoC_SelectFloor(this, mychip->floor); DoC_SelectChip(this, mychip->chip); } else if (this->curchip != mychip->chip) { DoC_SelectChip(this, mychip->chip); } this->curfloor = mychip->floor; this->curchip = mychip->chip; DoC_Command(this, (!this->page256 && (from & 0x100)) ? NAND_CMD_READ1 : NAND_CMD_READ0, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, from, CDSN_CTRL_WP, CDSN_CTRL_ECC_IO); if (eccbuf) { /* Prime the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_EN, docptr, ECCConf); } else { /* disable the ECC engine */ WriteDOC(DOC_ECC_RESET, docptr, ECCConf); WriteDOC(DOC_ECC_DIS, docptr, ECCConf); } /* treat crossing 256-byte sector for 2M x 8bits devices */ if (this->page256 && from + len > (from | 0xff) + 1) { len256 = (from | 0xff) + 1 - from; DoC_ReadBuf(this, buf, len256); DoC_Command(this, NAND_CMD_READ0, CDSN_CTRL_WP); DoC_Address(this, ADDR_COLUMN_PAGE, from + len256, CDSN_CTRL_WP, CDSN_CTRL_ECC_IO); } DoC_ReadBuf(this, &buf[len256], len - len256); /* Let the caller know we completed it */ *retlen = len; if (eccbuf) { /* Read the ECC data through the DiskOnChip ECC logic */ /* Note: this will work even with 2M x 8bit devices as */ /* they have 8 bytes of OOB per 256 page. mf. */ DoC_ReadBuf(this, eccbuf, 6); /* Flush the pipeline */ if (DoC_is_Millennium(this)) { dummy = ReadDOC(docptr, ECCConf); dummy = ReadDOC(docptr, ECCConf);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -