static int write_to_ptn(struct fastboot_ptentry *ptn, unsigned int addr, unsigned int size) #if defined(CFG_FASTBOOT_ONENANDBSP) || defined(CFG_FASTBOOT_NANDBSP) { int ret = 1; char start[32], length[32]; char wstart[32], wlength[32], wbuffer[32]; char write_type[32]; /* do_nand and do_onenand do not check argv[0] */ char *argv_erase[5] = { NULL, "erase", NULL, NULL, NULL, }; char *argv_write[6] = { NULL, NULL, NULL, NULL, NULL, NULL, }; argv_erase[2] = start; argv_erase[3] = length; argv_write[1] = write_type; argv_write[2] = wbuffer; argv_write[3] = wstart; argv_write[4] = wlength; printf("flashing '%s'\n", ptn->name); sprintf(start, "0x%x", ptn->start); if (ptn->length == 0) { CFG_FASTBOOT_FLASHCMD(NULL, 0, 3, argv_erase); } else { sprintf(length, "0x%x", ptn->length); CFG_FASTBOOT_FLASHCMD(NULL, 0, 4, argv_erase); } /* Which flavor of write to use */ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS) { sprintf(write_type, "write.yaffs"); sprintf(wlength, "0x%x", size); } else { sprintf(write_type, "write"); if (interface.nand_block_size && (size % interface.nand_block_size)) { size = (size + interface.nand_block_size - 1) / interface.nand_block_size * interface.nand_block_size; } sprintf(wlength, "0x%x", size); } sprintf(wbuffer, "0x%x", addr); sprintf(wstart, "0x%x", ptn->start); ret = CFG_FASTBOOT_FLASHCMD(NULL, 0, 5, argv_write); #if 0 if (0 == repeat) { if (ret) /* failed */ save_block_values(ptn, 0, 0); else /* success */ save_block_values(ptn, ptn->start, download_bytes); } #endif return ret; }
static int write_to_ptn(struct fastboot_ptentry *ptn) { int ret = 1; char start[32], length[32]; char wstart[32], wlength[32], addr[32]; char ecc_type[32], write_type[32]; int repeat, repeat_max; char *lock[5] = { "nand", "lock", NULL, NULL, NULL, }; char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL, }; char *write[6] = { "nand", "write", NULL, NULL, NULL, NULL, }; char *ecc[4] = { "nand", "ecc", NULL, NULL, }; char *erase[5] = { "nand", "erase", NULL, NULL, NULL, }; lock[2] = unlock[2] = erase[2] = start; lock[3] = unlock[3] = erase[3] = length; write[1] = write_type; write[2] = addr; write[3] = wstart; write[4] = wlength; printf("flashing '%s'\n", ptn->name); /* Which flavor of write to use */ if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I) sprintf(write_type, "write.i"); #ifdef CFG_NAND_YAFFS_WRITE else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS) sprintf(write_type, "write.yaffs"); #endif else sprintf(write_type, "write"); /* Some flashing requires the nand's ecc to be set */ ecc[2] = ecc_type; if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) && (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) { /* Both can not be true */ printf("Warning can not do hw and sw ecc for partition '%s'\n", ptn->name); printf("Ignoring these flags\n"); } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) { sprintf(ecc_type, "hw"); #if 0 do_nand(NULL, 0, 3, ecc); #endif } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) { sprintf(ecc_type, "sw"); #if 0 do_nand(NULL, 0, 3, ecc); #endif } /* Some flashing requires writing the same data in multiple, consecutive flash partitions */ repeat_max = 1; if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK) { if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { printf("Warning can not do both 'contiguous block' and 'repeat' writes for for partition '%s'\n", ptn->name); printf("Ignoring repeat flag\n"); } else { repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK; } } /* Unlock the whole partition instead of trying to manage special cases */ sprintf(length, "0x%x", ptn->length * repeat_max); for (repeat = 0; repeat < repeat_max; repeat++) { sprintf(start, "0x%x", ptn->start + (repeat * ptn->length)); #if 0 do_nand(NULL, 0, 4, unlock); do_nand(NULL, 0, 4, erase); #endif if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) && (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) { /* Both can not be true */ printf("Warning can not do 'next good block' and 'contiguous block' for partition '%s'\n", ptn->name); printf("Ignoring these flags\n"); } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) { /* Keep writing until you get a good block transfer_buffer should already be aligned */ if (interface.nand_block_size) { unsigned int blocks = download_bytes / interface.nand_block_size; unsigned int i = 0; unsigned int offset = 0; sprintf(wlength, "0x%x", interface.nand_block_size); while (i < blocks) { /* Check for overflow */ if (offset >= ptn->length) break; /* download's address only advance if last write was successful */ sprintf(addr, "0x%x", interface.transfer_buffer + (i * interface.nand_block_size)); /* nand's address always advances */ sprintf(wstart, "0x%x", ptn->start + (repeat * ptn->length) + offset); #if 0 ret = do_nand(NULL, 0, 5, write); #endif if (ret) break; else i++; /* Go to next nand block */ offset += interface.nand_block_size; } } else { printf("Warning nand block size can not be 0 when using 'next good block' for partition '%s'\n", ptn->name); printf("Ignoring write request\n"); } } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { #if 0 /* Keep writing until you get a good block transfer_buffer should already be aligned */ if (interface.nand_block_size) { if (0 == nand_curr_device) { nand_info_t *nand; unsigned long off; unsigned int ok_start; nand = &nand_info[nand_curr_device]; printf("\nDevice %d bad blocks:\n", nand_curr_device); /* Initialize the ok_start to the start of the partition Then try to find a block large enough for the download */ ok_start = ptn->start; /* It is assumed that the start and length are multiples of block size */ for (off = ptn->start; off < ptn->start + ptn->length; off += nand->erasesize) { if (nand_block_isbad(nand, off)) { /* Reset the ok_start to the next block */ ok_start = off + nand->erasesize; } /* Check if we have enough blocks */ if ((ok_start - off) >= download_bytes) break; } /* Check if there is enough space */ if (ok_start + download_bytes <= ptn->start + ptn->length) { sprintf(addr, "0x%x", interface.transfer_buffer); sprintf(wstart, "0x%x", ok_start); sprintf(wlength, "0x%x", download_bytes); ret = do_nand(NULL, 0, 5, write); /* Save the results into an environment variable on the format ptn_name + 'offset' ptn_name + 'size' */ if (ret) { /* failed */ save_block_values(ptn, 0, 0); } else { /* success */ save_block_values(ptn, ok_start, download_bytes); } } else { printf("Error could not find enough contiguous space in partition '%s' \n", ptn->name); printf("Ignoring write request\n"); } } else { /* TBD : Generalize flash handling */ printf("Error only handling 1 NAND per board"); printf("Ignoring write request\n"); } } else { printf("Warning nand block size can not be 0 when using 'continuous block' for partition '%s'\n", ptn->name); printf("Ignoring write request\n"); } #endif } else { /* Normal case */ sprintf(addr, "0x%x", interface.transfer_buffer); sprintf(wstart, "0x%x", ptn->start + (repeat * ptn->length)); sprintf(wlength, "0x%x", download_bytes); #ifdef CFG_NAND_YAFFS_WRITE if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_YAFFS) sprintf(wlength, "0x%x", download_bytes_unpadded); #endif #if 0 ret = do_nand(NULL, 0, 5, write); #endif if (0 == repeat) { if (ret) /* failed */ save_block_values(ptn, 0, 0); else /* success */ save_block_values(ptn, ptn->start, download_bytes); } } #if 0 do_nand(NULL, 0, 4, lock); #endif if (ret) break; } return ret; }