示例#1
0
void do_or ( unsigned int ra, unsigned int rb, unsigned int rc, unsigned int rd, unsigned int re )
{
    //c = a or b:
    //d = b nand b
    //e = c nand c
    //a = d nand e
    do_nand(rd,rb,rb);
    do_nand(re,rc,rc);
    do_nand(ra,rd,re);
}
示例#2
0
static void save_env(struct fastboot_ptentry *ptn,
		     char *var, char *val)
{
	char start[32], length[32];
	char ecc_type[32];

	char *lock[5]    = { "nand", "lock",   NULL, NULL, NULL, };
	char *unlock[5]  = { "nand", "unlock", NULL, NULL, NULL, };
	char *ecc[4]     = { "nand", "ecc",    NULL, NULL, };
	char *saveenv[2] = { "setenv", NULL, };

	lock[2] = unlock[2] = start;
	lock[3] = unlock[3] = length;

	set_env (var, val);

	/* 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
	}
	sprintf(start, "0x%x", ptn->start);
	sprintf(length, "0x%x", ptn->length);

	/* This could be a problem is there is an outstanding lock */
#if 0
	do_nand(NULL, 0, 4, unlock);
#endif
	do_saveenv(NULL, 0, 1, saveenv);
#if 0
	do_nand(NULL, 0, 4, lock);
#endif
}
示例#3
0
static void set_ptn_ecc(struct fastboot_ptentry *ptn)
{
	char ecc_type[32];
	char *ecc[4] = {"nand", "ecc", NULL, NULL, };

	/* 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");
		do_nand(NULL, 0, 3, ecc);
	} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) {
		sprintf(ecc_type, "sw");
		do_nand(NULL, 0, 3, ecc);
	}
}
	void nand_boot(int nand_boot_select)
	{
		unsigned int offset;
		void (*kernel)(int, char **, char *) =
				(void (*)(int, char **, char *))CFG_KERNEL_DST;

		serial_puts_info("Enter nand_boot for zImage...\n");

		do_nand(CFG_BOOT_OFFS, 6 * 0x100000, CFG_KERNEL_DST);
		flush_cache_all();

		serial_puts_info("Jump to kernel entry...\n");

		(*kernel)(0, (char **)(PARAM_BASE + 16), (char *)PARAM_BASE);
	}
int mv_man_test_nand(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{

	printf("*****Testing NAND now*********\n");
	argv[1]="info"; //for testing nand flash ID info
	do_nand(cmdtp,flag,2,argv);
	printf("******************************\n");

	if(strncmp(nand_info[0].name,NAND_DEVICE_NAME,5) == 0)
	{	
		printf("NAND Flash Works!!\n");
		g_testReport|= (0x01<<MAN_FUNC_ID_NAND);
		
	}
	else
	{
		printf("NAND Flash Failed!!\n");
		return 1;

	}

	return 1;
}
示例#6
0
static int rx_handler(const unsigned char *buffer, unsigned int buffer_size)
{
	int ret = 1;

	/* Use 65 instead of 64
	   null gets dropped  
	   strcpy's need the extra byte */
	char response[65];
	/* Cast to make compiler happy with string functions */
	const char *cmdbuf = (char *) buffer;
	/* Padding is required only if storage medium is NAND */
	if (interface.storage_medium == NAND) {
		download_bytes = interface.data_to_flash_size;
		/* Pad to block length
		   In most cases, padding the download to be
		   block aligned is correct. The exception is
		   when the following flash writes to the oob
		   area.  This happens when the image is a
		   YAFFS image.  Since we do not know what
		   the download is until it is flashed,
		   go ahead and pad it, but save the true
		   size in case if should have
		   been unpadded */
		download_bytes_unpadded = download_bytes;
		if (interface.nand_block_size) {
			if (download_bytes % interface.nand_block_size) {
				unsigned int pad = interface.nand_block_size - (download_bytes % interface.nand_block_size);
				unsigned int i;

				for (i = 0; i < pad; i++) {
					if (download_bytes >= interface.transfer_buffer_size)
						break;

					interface.transfer_buffer[download_bytes] = 0;
					download_bytes++;
				}
			}
		}

		/* Provide some feedback */
		if (download_bytes && 0 == (download_bytes %
			  (16 * interface.nand_block_size))) {
			/* Some feeback that the
			   download is happening */
			if (download_error)
				printf("X");
			else
				printf(".");
			if (0 == (download_bytes %
				  (80 * 16 *
				   interface.nand_block_size)))
				printf("\n");
		}
		ret = 0;
	} else {
		/* A command */
        fastboot_confirmed=1;
		/* Generic failed response */
		sprintf(response, "FAIL");

		/* reboot 
		   Reboot the board. */
		if(memcmp(cmdbuf, "reboot-bootloader", 17) == 0)
		{
			sprintf(response,"OKAY");
			fastboot_tx_status(response, strlen(response));

			/* Clear all reset reasons */
			__raw_writel(0xfff, PRM_RSTST);

			strcpy(PUBLIC_SAR_RAM_1_FREE, "bootloader");

			/* now warm reset the silicon */
			__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT,
					PRM_RSTCTRL);
			return 0;
		}

		if(memcmp(cmdbuf, "reboot", 6) == 0) 
		{
			sprintf(response,"OKAY");
			fastboot_tx_status(response, strlen(response));

			do_reset (NULL, 0, 0, NULL);
			
			/* This code is unreachable,
			   leave it to make the compiler happy */
			return 0;
		}
		
		/* getvar
		   Get common fastboot variables
		   Board has a chance to handle other variables */
		if(memcmp(cmdbuf, "getvar:", 7) == 0) {
			fastboot_getvar(cmdbuf + 7, response);
			return 0;
		}

		/* %fastboot oem <cmd> */
		if (memcmp(cmdbuf, "oem ", 4) == 0) {
			ret = 0;
			cmdbuf += 4;

			if (memcmp(cmdbuf, "shutdown", 8) == 0) {
				sprintf(response,"OKAY");
				fastboot_tx_status(response, strlen(response));
				twl6030_shutdown();
			}
			if (memcmp(cmdbuf, "idme ", 5) == 0) {
				ret = fastboot_idme(cmdbuf + 5);
	    			strcpy(response,"OKAY");
    				ret = 0;
    				goto done;
			}
			/* fastboot oem format */
			if(memcmp(cmdbuf, "format", 6) == 0){
				ret = fastboot_oem(cmdbuf);
				if (ret < 0) {
					strcpy(response,"FAIL");
				} else {
					strcpy(response,"OKAY");
				}
				goto done;
			}

			/* fastboot oem recovery */
			if(memcmp(cmdbuf, "recovery", 8) == 0){
				sprintf(response,"OKAY");
				fastboot_tx_status(response, strlen(response));

				/* Clear all reset reasons */
				__raw_writel(0xfff, PRM_RSTST);
				strcpy(PUBLIC_SAR_RAM_1_FREE, "recovery");
				/* now warm reset the silicon */
				__raw_writel(PRM_RSTCTRL_RESET_WARM_BIT,
					PRM_RSTCTRL);
				/* Never returns */
				while(1);
			}

			/* fastboot oem unlock */
			if(memcmp(cmdbuf, "unlock", 6) == 0){
				sprintf(response,"FAIL");
				printf("\nfastboot: oem unlock "\
						"not implemented yet!!\n");
				goto done;
			}

			/* fastboot oem [xxx] */
			printf("\nfastboot: do not understand oem %s\n", cmdbuf);
			strcpy(response,"FAIL");
			goto done;
		} /* end: %fastboot oem <cmd> */

		/* erase
		   Erase a register flash partition
		   Board has to set up flash partitions */
		if(memcmp(cmdbuf, "erase:", 6) == 0){
			if (interface.storage_medium == NAND) {
				/* storage medium is NAND */

				struct fastboot_ptentry *ptn;

				ptn = fastboot_flash_find_ptn(cmdbuf + 6);
				if (ptn == 0)
				{
					sprintf(response, "FAILpartition does not exist");
				}
				else
				{
					char start[32], length[32];
					int status = 0, repeat, repeat_max;

					printf("erasing '%s'\n", ptn->name);

					char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
					char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
					char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };

					lock[2] = unlock[2] = erase[2] = start;
					lock[3] = unlock[3] = erase[3] = length;

					repeat_max = 1;
					if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK)
						repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;

					sprintf (length, "0x%x", ptn->length);
					for (repeat = 0; repeat < repeat_max; repeat++)
					{
						sprintf (start, "0x%x", ptn->start + (repeat * ptn->length));
#if 0
						do_nand (NULL, 0, 4, unlock);
						status = do_nand (NULL, 0, 4, erase);
						do_nand (NULL, 0, 4, lock);
#endif

						if (status)
							break;
					}

					if (status)
					{
						sprintf(response, "FAILfailed to erase partition");
					}
					else
					{
						printf("partition '%s' erased\n", ptn->name);
						sprintf(response, "OKAY");
					}
				}
			} else if (interface.storage_medium == EMMC) {
				/* storage medium is EMMC */

				struct fastboot_ptentry *ptn;

				/* Save the MMC controller number */
#if  defined(CONFIG_4430PANDA)
				/* panda board does not have eMMC on mmc1 */
				mmc_controller_no = 0;
#else
				/* blaze has emmc on mmc1 */
				mmc_controller_no = 1;
#endif

				/* Find the partition and erase it */
				ptn = fastboot_flash_find_ptn(cmdbuf + 6);

				if (ptn == 0) {
					sprintf(response,
					"FAIL: partition doesn't exist");
				} else {
					/* Call MMC erase function here */
					char start[32], length[32];
					char slot_no[32];

					char *erase[5]  = { "mmc", NULL, "erase",
							NULL, NULL, };
					char *mmc_init[2] = {"mmcinit", NULL,};

					mmc_init[1] = slot_no;
					erase[1] = slot_no;
					erase[3] = start;
					erase[4] = length;

					sprintf(slot_no, "%d", mmc_controller_no);
					sprintf(length, "0x%x", ptn->length);
					sprintf(start, "0x%x", ptn->start);

					printf("Initializing '%s'\n", ptn->name);
					if (do_mmc(NULL, 0, 2, mmc_init))
						sprintf(response, "FAIL: Init of MMC card");
					else
						sprintf(response, "OKAY");


					printf("Erasing '%s'\n", ptn->name);
					if (do_mmc(NULL, 0, 5, erase)) {
						printf("Erasing '%s' FAILED!\n", ptn->name);
						sprintf(response, "FAIL: Erase partition");
					} else {
						printf("Erasing '%s' DONE!\n", ptn->name);
						sprintf(response, "OKAY");
					}
				}
			}

			ret = 0;
		}


		/* EMMC Erase
		   Erase a register flash partition on MMC
		   Board has to set up flash partitions */
		if (memcmp(cmdbuf, "mmcerase:", 9) == 0) {
			struct fastboot_ptentry *ptn;

			/* Save the MMC controller number */
			mmc_controller_no = simple_strtoul(cmdbuf + 9,
								NULL, 10);
			/* Find the partition and erase it */
			ptn = fastboot_flash_find_ptn(cmdbuf + 11);

			if (ptn == 0) {
				sprintf(response,
					"FAIL: partition doesn't exist");
			} else {
				/* Call MMC erase function here */
				/* This is not complete */
				char start[32], length[32];
				char slot_no[32];

				char *erase[5]  = { "mmc", NULL, "erase",
								NULL, NULL, };
				char *mmc_init[2] = {"mmcinit", NULL,};

				mmc_init[1] = slot_no;
				erase[1] = slot_no;
				erase[3] = start;
				erase[4] = length;

				sprintf(slot_no, "%d", mmc_controller_no);
				sprintf(length, "0x%x", ptn->length);
				sprintf(start, "0x%x", ptn->start);

				printf("Initializing '%s'\n", ptn->name);
				if (do_mmc(NULL, 0, 2, mmc_init)) {
					sprintf(response, "FAIL: Init of MMC card");
				} else {
					sprintf(response, "OKAY");
				}

				printf("Erasing '%s'\n", ptn->name);
				if (do_mmc(NULL, 0, 5, erase)) {
					sprintf(response, "FAIL: Erase partition");
				} else {
					sprintf(response, "OKAY");
				}
			}
		}

		/* download
		   download something .. 
		   What happens to it depends on the next command after data */
		if(memcmp(cmdbuf, "download:", 9) == 0) {
			/* save the size */
			download_size = simple_strtoul(cmdbuf + 9, NULL, 16);
			/* Reset the bytes count, now it is safe */
			download_bytes = 0;
			/* Reset error */
			download_error = 0;

			printf("Starting download of %d bytes\n",
							download_size);

			if (0 == download_size) {
				/* bad user input */
				sprintf(response, "FAILdata invalid size");
			} else if (download_size >
						interface.transfer_buffer_size)
			{
				/* set download_size to 0
				 * because this is an error */
				download_size = 0;
				sprintf(response, "FAILdata too large");
			} else {
				/* The default case, the transfer fits
				   completely in the interface buffer */
				sprintf(response, "DATA%08x", download_size);
			}
			ret = download_size;
		}

		/* boot
		   boot what was downloaded
		   **
		   ** +-----------------+
		   ** | boot header     | 1 page
		   ** +-----------------+
		   ** | kernel          | n pages
		   ** +-----------------+
		   ** | ramdisk         | m pages
		   ** +-----------------+
		   ** | second stage    | o pages
		   ** +-----------------+
		   **
		   Pagesize has default value of
		   CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE
		*/

		if(memcmp(cmdbuf, "boot", 4) == 0) {
			download_bytes = interface.data_to_flash_size;
			if ((download_bytes) &&
			    (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes))
			{
				char start[32];
				char *booti_args[4] = { "booti", NULL, "boot", NULL };

				/* Skip the mkbootimage header */
				//boot_img_hdr *hdr =
				//	(boot_img_hdr *)
				//	&interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE];

				booti_args[1] = start;
				sprintf (start, "0x%x", interface.transfer_buffer);

				/* Execution should jump to kernel so send the response
				   now and wait a bit.  */
				sprintf(response, "OKAY");
				fastboot_tx_status(response, strlen(response));

				printf ("Booting kernel..\n");

				/* For Future use
				 *	if (strlen ((char *) &fb_hdr->cmdline[0]))
				 *		set_env ("bootargs", (char *) &fb_hdr->cmdline[0]);
				 */
				/* boot the boot.img */
				do_booti(NULL, 0, 3, booti_args);
			}
			sprintf(response, "FAILinvalid boot image");
			ret = 0;
		}

		/* mmcwrite
		   write what was downloaded on MMC*/
				/* Write to MMC whatever was downloaded */
		if (memcmp(cmdbuf, "mmcwrite:", 9) == 0) {
			download_bytes = interface.data_to_flash_size;
			if (download_bytes) {

				struct fastboot_ptentry *ptn;

				/* Save the MMC controller number */
				mmc_controller_no = simple_strtoul(cmdbuf + 9, NULL, 10);

				/* Next is the partition name */
				ptn = fastboot_flash_find_ptn(cmdbuf + 11);

				if (ptn == 0) {
					sprintf(response, "FAILpartition does not exist");
				} else {
					write_to_ptn_emmc(ptn, 0, response);
				}

			} else {
				sprintf(response, "FAILno image downloaded");
			}
		}
		/* flash
		   Flash what was downloaded */
		if(memcmp(cmdbuf, "flash:", 6) == 0) {
			download_bytes = interface.data_to_flash_size;
			if (interface.storage_medium == NAND) {
				/* storage medium is NAND */

				if (download_bytes)
				{
					struct fastboot_ptentry *ptn;

					ptn = fastboot_flash_find_ptn(cmdbuf + 6);
					if (ptn == 0) {
						sprintf(response, "FAILpartition does not exist");
					} else if ((download_bytes > ptn->length) &&
						   !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
						sprintf(response, "FAILimage too large for partition");
						/* TODO : Improve check for yaffs write */
					} else {
						/* Check if this is not really a flash write
						   but rather a saveenv */
						if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
							/* Since the response can only be 64 bytes,
							   there is no point in having a large error message. */
							char err_string[32];
							if (saveenv_to_ptn(ptn, &err_string[0])) {
								printf("savenv '%s' failed : %s\n", ptn->name, err_string);
								sprintf(response, "FAIL%s", err_string);
							} else {
								printf("partition '%s' saveenv-ed\n", ptn->name);
								sprintf(response, "OKAY");
							}
						} else {
							/* Normal case */
							if (write_to_ptn(ptn)) {
								printf("flashing '%s' failed\n", ptn->name);
								sprintf(response, "FAILfailed to flash partition");
							} else {
								printf("partition '%s' flashed\n", ptn->name);
								sprintf(response, "OKAY");
							}
						}
					}
				}
				else
				{
					sprintf(response, "FAILno image downloaded");
				}
			} else if (interface.storage_medium == EMMC) {
				/* storage medium is EMMC */
				if (download_bytes) {

					struct fastboot_ptentry *ptn;
					char *argv[2] = {NULL, "-f"};

					/* Next is the partition name */
					if(memcmp(cmdbuf+6, "all:", 4) == 0){
						printf("Factory image testing.\n");
						ptn=malloc(sizeof(struct fastboot_ptentry));
						sprintf(ptn->name,"%s","all");
						ptn->length=download_bytes;
						ptn->start=simple_strtoul(cmdbuf + 10, NULL, 16);
						printf("length=%x",ptn->length);
						printf(" offset=%x\n",ptn->start);
					}else{
						ptn = fastboot_flash_find_ptn(cmdbuf + 6);
					}

					if (ptn == 0) {
						printf("Partition:'%s' does not exist\n", ptn->name);
						sprintf(response, "FAILpartition does not exist");
					} else if ((download_bytes > ptn->length) &&
						!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
						printf("Image too large for the partition\n");
						sprintf(response, "FAILimage too large for partition");
						} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
						/* Check if this is not really a flash write,
						 * but instead a saveenv
						 */
						unsigned int i = 0;
						/* Env file is expected with a NULL delimeter between
						 * env variables So replace New line Feeds (0x0a) with
						 * NULL (0x00)
						 */
						for (i = 0; i < download_bytes; i++) {
							if (interface.transfer_buffer[i] == 0x0a)
								interface.transfer_buffer[i] = 0x00;
						}
						memset(env_ptr->data, 0, ENV_SIZE);
						memcpy(env_ptr->data, interface.transfer_buffer, download_bytes);
						do_saveenv(NULL, 0, 2, argv);
						printf("saveenv to '%s' DONE!\n", ptn->name);
						sprintf(response, "OKAY");
					} else {
						write_to_ptn_emmc(ptn, 0, response);
					} /* Normal Case */

				} else {
					sprintf(response, "FAILno image downloaded");
				}
			} /* EMMC */

			ret = 0;
		} /* fastboot flash ... */

	/* multi-flash support */

		if(memcmp(cmdbuf, "multiflash:", 11) == 0) {
			download_bytes=interface.data_to_flash_size;
			if (interface.storage_medium == NAND) {
				sprintf(response, "FAILmultiflash is not supported for NAND");
			} else if (interface.storage_medium == EMMC) {
				/* storage medium is EMMC */

				if (download_bytes) {

					struct fastboot_ptentry *ptn;
					/* Next is the partition name */
					ptn = fastboot_flash_find_ptn(cmdbuf + 13);

					if(ptn != multiflash_ptn) {
						// If we start flashing a new partitionn reset
						// multi flash statics
						multiflash_ptn    = ptn;
						multiflash_offset = 0;
					}

					if (ptn == 0) {
						printf("Partition:'%s' does not exist\n", ptn->name);
						sprintf(response, "FAILpartition does not exist");
					} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
						printf("Multiflash canno be used with partition :'%s'\n",
						       ptn->name);
						sprintf(response, "FAILpartition not supported with multiflash");
                                        } else if((download_bytes+multiflash_offset) > ptn->length) {
						printf("Image too large for the partition\n");
						sprintf(response, "FAILimage too large for partition");
					} else {
						printf("\nflash image chunk: offset=@0x%08X size=0x%04X\n",
						       multiflash_offset, download_bytes);

						if(!write_to_ptn_emmc(ptn, multiflash_offset, response)) {
							if(memcmp(cmdbuf + 11, "1", 1) == 0) {
								// it was the last chunk
								multiflash_offset = 0;
								multiflash_ptn    = NULL;
							} else {
								multiflash_offset += download_bytes;
							}
						}
					} /* Normal Case */

				} else {
					sprintf(response, "FAILno image downloaded");
				}
			} /* EMMC */

			ret = 0;
		} /* fastboot multiflash ... */


done:
		fastboot_tx_status(response, strlen(response));

	}  /* End of command */
	
	return ret;
}
示例#7
0
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;
}
示例#8
0
static void save_block_values(struct fastboot_ptentry *ptn,
			      unsigned int offset,
			      unsigned int size)
{
	struct fastboot_ptentry *env_ptn;

	char var[64], val[32];
	char start[32], length[32];
	char ecc_type[32];

	char *lock[5]    = { "nand", "lock",   NULL, NULL, NULL, };
	char *unlock[5]  = { "nand", "unlock", NULL, NULL, NULL, };
	char *ecc[4]     = { "nand", "ecc",    NULL, NULL, };	
	char *setenv[4]  = { "setenv", NULL, NULL, NULL, };
	char *saveenv[2] = { "setenv", NULL, };
	
	setenv[1] = var;
	setenv[2] = val;
	lock[2] = unlock[2] = start;
	lock[3] = unlock[3] = length;

	printf ("saving it..\n");

	if (size == 0)
	{
		/* The error case, where the variables are being unset */
		
		sprintf (var, "%s_nand_offset", ptn->name);
		sprintf (val, "");
		do_setenv (NULL, 0, 3, setenv);

		sprintf (var, "%s_nand_size", ptn->name);
		sprintf (val, "");
		do_setenv (NULL, 0, 3, setenv);
	}
	else
	{
		/* Normal case */

		sprintf (var, "%s_nand_offset", ptn->name);
		sprintf (val, "0x%x", offset);

		printf ("%s %s %s\n", setenv[0], setenv[1], setenv[2]);
		
		do_setenv (NULL, 0, 3, setenv);

		sprintf (var, "%s_nand_size", ptn->name);

		sprintf (val, "0x%x", size);

		printf ("%s %s %s\n", setenv[0], setenv[1], setenv[2]);

		do_setenv (NULL, 0, 3, setenv);
	}


	/* Warning : 
	   The environment is assumed to be in a partition named 'enviroment'.
	   It is very possible that your board stores the enviroment 
	   someplace else. */
	env_ptn = fastboot_flash_find_ptn("environment");

	if (env_ptn)
	{
		/* Some flashing requires the nand's ecc to be set */
		ecc[2] = ecc_type;
		if ((env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) &&
		    (env_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 (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC)
		{
			sprintf (ecc_type, "hw");
#if 0
			do_nand (NULL, 0, 3, ecc);
#endif
		}
		else if (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)
		{
			sprintf (ecc_type, "sw");
#if 0
			do_nand (NULL, 0, 3, ecc);
#endif
		}
		
		sprintf (start, "0x%x", env_ptn->start);
		sprintf (length, "0x%x", env_ptn->length);			
#if 0
		/* This could be a problem is there is an outstanding lock */
		do_nand (NULL, 0, 4, unlock);
#endif
	}

	do_saveenv (NULL, 0, 1, saveenv);
	
	if (env_ptn)
	{
#if 0
		do_nand (NULL, 0, 4, lock);
#endif
	}
}
示例#9
0
static int rx_handler (const unsigned char *buffer, unsigned int buffer_size)
{
	int ret = 1;

	/* Use 65 instead of 64
	   null gets dropped  
	   strcpy's need the extra byte */
	char response[65];

	if (download_size) 
	{
		/* Something to download */

		if (buffer_size)
		{
			/* Handle possible overflow */
			unsigned int transfer_size = 
				download_size - download_bytes;

			if (buffer_size < transfer_size)
				transfer_size = buffer_size;
			
			/* Save the data to the transfer buffer */
			memcpy (interface.transfer_buffer + download_bytes, 
				buffer, transfer_size);

			download_bytes += transfer_size;
			
			/* Check if transfer is done */
			if (download_bytes >= download_size) {
				/* Reset global transfer variable,
				   Keep download_bytes because it will be
				   used in the next possible flashing command */
				download_size = 0;

				if (download_error) {
					/* There was an earlier error */
					sprintf(response, "ERROR");
				} else {
					/* Everything has transferred,
					   send the OK response */
					sprintf(response, "OKAY");
				}
				fastboot_tx_status(response, strlen(response));

				printf ("\ndownloading of %d bytes finished\n",
					download_bytes);

#if defined(CONFIG_STORAGE_NAND)
				/* Pad to block length
				   In most cases, padding the download to be
				   block aligned is correct. The exception is
				   when the following flash writes to the oob
				   area.  This happens when the image is a
				   YAFFS image.  Since we do not know what
				   the download is until it is flashed,
				   go ahead and pad it, but save the true
				   size in case if should have
				   been unpadded */
				download_bytes_unpadded = download_bytes;
				if (interface.nand_block_size)
				{
					if (download_bytes % 
					    interface.nand_block_size)
					{
						unsigned int pad = interface.nand_block_size - (download_bytes % interface.nand_block_size);
						unsigned int i;
						
						for (i = 0; i < pad; i++) 
						{
							if (download_bytes >= interface.transfer_buffer_size)
								break;
							
							interface.transfer_buffer[download_bytes] = 0;
							download_bytes++;
						}
					}
				}
#endif
			}

			/* Provide some feedback */
			if (download_bytes &&
			    0 == (download_bytes %
				  (16 * interface.nand_block_size)))
			{
				/* Some feeback that the
				   download is happening */
				if (download_error)
					printf("X");
				else
					printf(".");
				if (0 == (download_bytes %
					  (80 * 16 *
					   interface.nand_block_size)))
					printf("\n");
				
			}
		}
		else
		{
			/* Ignore empty buffers */
			printf ("Warning empty download buffer\n");
			printf ("Ignoring\n");
		}
		ret = 0;
	}
	else
	{
		/* A command */

		/* Cast to make compiler happy with string functions */
		const char *cmdbuf = (char *) buffer;

		/* Generic failed response */
		sprintf(response, "FAIL");

		/* reboot 
		   Reboot the board. */

		if(memcmp(cmdbuf, "reboot", 6) == 0) 
		{
			sprintf(response,"OKAY");
			fastboot_tx_status(response, strlen(response));
			udelay (1000000); /* 1 sec */
			
			do_reset (NULL, 0, 0, NULL);
			
			/* This code is unreachable,
			   leave it to make the compiler happy */
			return 0;
		}
		
		/* getvar
		   Get common fastboot variables
		   Board has a chance to handle other variables */
		if(memcmp(cmdbuf, "getvar:", 7) == 0) 
		{
			strcpy(response,"OKAY");
        
			if(!strcmp(cmdbuf + strlen("version"), "version")) 
			{
				strcpy(response + 4, FASTBOOT_VERSION);
			} 
			else if(!strcmp(cmdbuf + strlen("product"), "product")) 
			{
				if (interface.product_name) 
					strcpy(response + 4, interface.product_name);
			
			} else if(!strcmp(cmdbuf + strlen("serialno"), "serialno")) {
				if (interface.serial_no) 
					strcpy(response + 4, interface.serial_no);

			} else if(!strcmp(cmdbuf + strlen("downloadsize"), "downloadsize")) {
				if (interface.transfer_buffer_size) 
					sprintf(response + 4, "08x", interface.transfer_buffer_size);
			} 
			else 
			{
				fastboot_getvar(cmdbuf + 7, response + 4);
			}
			ret = 0;

		}

		/* erase
		   Erase a register flash partition
		   Board has to set up flash partitions */

		if(memcmp(cmdbuf, "erase:", 6) == 0){
#if defined(CONFIG_STORAGE_NAND)
			struct fastboot_ptentry *ptn;

			ptn = fastboot_flash_find_ptn(cmdbuf + 6);
			if(ptn == 0) 
			{
				sprintf(response, "FAILpartition does not exist");
			}
			else
			{
				char start[32], length[32];
				int status, repeat, repeat_max;
			
				printf("erasing '%s'\n", ptn->name);   

				char *lock[5]   = { "nand", "lock",   NULL, NULL, NULL, };
				char *unlock[5] = { "nand", "unlock", NULL, NULL, NULL,	};
				char *erase[5]  = { "nand", "erase",  NULL, NULL, NULL, };
			
				lock[2] = unlock[2] = erase[2] = start;
				lock[3] = unlock[3] = erase[3] = length;

				repeat_max = 1;
				if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK)
					repeat_max = ptn->flags & FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK;

				sprintf (length, "0x%x", ptn->length);
				for (repeat = 0; repeat < repeat_max; repeat++) 
				{
					sprintf (start, "0x%x", ptn->start + (repeat * ptn->length));
				
					do_nand (NULL, 0, 4, unlock);
					status = do_nand (NULL, 0, 4, erase);
					do_nand (NULL, 0, 4, lock);

					if (status)
						break;
				}

				if (status)
				{
					sprintf(response,"FAILfailed to erase partition");
				} 
				else 
				{
					printf("partition '%s' erased\n", ptn->name);
					sprintf(response, "OKAY");
				}
			
			}
#elif defined(CONFIG_STORAGE_EMMC)
			struct fastboot_ptentry *ptn;

			/* Save the MMC controller number */
			mmc_controller_no = CFG_FASTBOOT_MMC_NO;

			/* Find the partition and erase it */
			ptn = fastboot_flash_find_ptn(cmdbuf + 6);

			if (ptn == 0) {
				sprintf(response, "FAIL: partition doesn't exist");
			} else {
				/* Call MMC erase function here */
				char start[32], length[32];
				char slot_no[32];

				char *erase[5]  = { "mmc", NULL, "erase", NULL, NULL, };
				char *mmc_init[2] = {"mmcinit", NULL,};

				mmc_init[1] = slot_no;
				erase[1] = slot_no;
				erase[3] = start;
				erase[4] = length;

				sprintf(slot_no, "%d", mmc_controller_no);
				sprintf(length, "0x%x", ptn->length);
				sprintf(start, "0x%x", ptn->start);

				printf("Initializing '%s'\n", ptn->name);
				if (do_mmc(NULL, 0, 2, mmc_init))
					sprintf(response, "FAIL: Init of MMC card");
				else
					sprintf(response, "OKAY");

				printf("Erasing '%s'\n", ptn->name);
				if (do_mmc(NULL, 0, 5, erase)) {
					printf("Erasing '%s' FAILED!\n", ptn->name);
					sprintf(response, "FAIL: Erase partition");
				} else {
					printf("Erasing '%s' DONE!\n", ptn->name);
					sprintf(response, "OKAY");
				}
			}
#endif
			ret = 0;
		}

		/* download
		   download something .. 
		   What happens to it depends on the next command after data */

		if(memcmp(cmdbuf, "download:", 9) == 0) {

			/* save the size */
			download_size = simple_strtoul (cmdbuf + 9, NULL, 16);
			/* Reset the bytes count, now it is safe */
			download_bytes = 0;
			/* Reset error */
			download_error = 0;

			printf ("Starting download of %d bytes\n", download_size);

			if (0 == download_size)
			{
				/* bad user input */
				sprintf(response, "FAILdata invalid size");
			}
			else if (download_size > interface.transfer_buffer_size)
			{
				/* set download_size to 0 because this is an error */
				download_size = 0;
				sprintf(response, "FAILdata too large");
			}
			else
			{
				/* The default case, the transfer fits
				   completely in the interface buffer */
				sprintf(response, "DATA%08x", download_size);
			}
			ret = 0;
		}

		/* boot
		   boot what was downloaded

		   WARNING WARNING WARNING

		   This is not what you expect.
		   The fastboot client does its own packaging of the
		   kernel.  The layout is defined in the android header
		   file bootimage.h.  This layeout is copiedlooks like this,

		   **
		   ** +-----------------+
		   ** | boot header     | 1 page
		   ** +-----------------+
		   ** | kernel          | n pages
		   ** +-----------------+
		   ** | ramdisk         | m pages
		   ** +-----------------+
		   ** | second stage    | o pages
		   ** +-----------------+
		   **

		   We only care about the kernel.
		   So we have to jump past a page.

		   What is a page size ?
		   The fastboot client uses 2048

		   The is the default value of

		   CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE

		*/

		if(memcmp(cmdbuf, "boot", 4) == 0) {

			if ((download_bytes) &&
			    (CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE < download_bytes))
			{
				char start[32];
				char *bootm[3] = { "bootm", NULL, NULL, };
				char *go[3]    = { "go",    NULL, NULL, };

				/*
				 * Use this later to determine if a command line was passed
				 * for the kernel.
				 */
				struct fastboot_boot_img_hdr *fb_hdr =
					(struct fastboot_boot_img_hdr *) interface.transfer_buffer;

				/* Skip the mkbootimage header */
				image_header_t *hdr =
					(image_header_t *)
					&interface.transfer_buffer[CFG_FASTBOOT_MKBOOTIMAGE_PAGE_SIZE];

				bootm[1] = go[1] = start;
				sprintf (start, "0x%x", hdr);

				/* Execution should jump to kernel so send the response
				   now and wait a bit.  */
				sprintf(response, "OKAY");
				fastboot_tx_status(response, strlen(response));
				udelay (1000000); /* 1 sec */

				if (ntohl(hdr->ih_magic) == IH_MAGIC) {
					/* Looks like a kernel.. */
					printf ("Booting kernel..\n");

					/*
					 * Check if the user sent a bootargs down.
					 * If not, do not override what is already there
					 */
					if (strlen ((char *) &fb_hdr->cmdline[0]))
						set_env ("bootargs", (char *) &fb_hdr->cmdline[0]);

					do_bootm (NULL, 0, 2, bootm);
				} else {
					/* Raw image, maybe another uboot */
					printf ("Booting raw image..\n");

					do_go (NULL, 0, 2, go);
				}
				printf ("ERROR : bootting failed\n");
				printf ("You should reset the board\n");
			}
			sprintf(response, "FAILinvalid boot image");
			ret = 0;
		}

		/* flash
		   Flash what was downloaded */

		if(memcmp(cmdbuf, "flash:", 6) == 0) {
#if defined(CONFIG_STORAGE_NAND)
			if (download_bytes) 
			{
				struct fastboot_ptentry *ptn;
			
				ptn = fastboot_flash_find_ptn(cmdbuf + 6);
				if (ptn == 0) {
					sprintf(response, "FAILpartition does not exist");
				} else if ((download_bytes > ptn->length) &&
					   !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
					sprintf(response, "FAILimage too large for partition");
					/* TODO : Improve check for yaffs write */
				} else {
					/* Check if this is not really a flash write
					   but rather a saveenv */
					if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
						/* Since the response can only be 64 bytes,
						   there is no point in having a large error message. */
						char err_string[32];
						if (saveenv_to_ptn(ptn, &err_string[0])) {
							printf("savenv '%s' failed : %s\n", ptn->name, err_string);
							sprintf(response, "FAIL%s", err_string);
						} else {
							printf("partition '%s' saveenv-ed\n", ptn->name);
							sprintf(response, "OKAY");
						}
					} else {
						/* Normal case */
						if (write_to_ptn(ptn)) {
							printf("flashing '%s' failed\n", ptn->name);
							sprintf(response, "FAILfailed to flash partition");
						} else {
							printf("partition '%s' flashed\n", ptn->name);
							sprintf(response, "OKAY");
						}
					}
				}
			}
			else
			{
				sprintf(response, "FAILno image downloaded");
			}
#elif defined(CONFIG_STORAGE_EMMC)
			if (download_bytes) {

				struct fastboot_ptentry *ptn;

				/* Save the MMC controller number */
				mmc_controller_no = CFG_FASTBOOT_MMC_NO;

				/* Next is the partition name */
				ptn = fastboot_flash_find_ptn(cmdbuf + 6);

				if (ptn == 0) {
					printf("Partition:'%s' does not exist\n", ptn->name);
					sprintf(response, "FAILpartition does not exist");
				} else if ((download_bytes > ptn->length) &&
						!(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) {
					printf("Image too large for the partition\n");
					sprintf(response, "FAILimage too large for partition");
				} else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV) {
					/* Check if this is not really a flash write,
					 * but instead a saveenv
					 */
					unsigned int i = 0;
					/* Env file is expected with a NULL delimeter between
					 * env variables So replace New line Feeds (0x0a) with
					 * NULL (0x00)
					 */
					for (i = 0; i < download_bytes; i++) {
						if (interface.transfer_buffer[i] == 0x0a)
							interface.transfer_buffer[i] = 0x00;
					}
					memset(env_ptr->data, 0, ENV_SIZE);
					memcpy(env_ptr->data, interface.transfer_buffer, download_bytes);
					do_saveenv(NULL, 0, 1, NULL);
					printf("saveenv to '%s' DONE!\n", ptn->name);
					sprintf(response, "OKAY");
				} else {
				/* Normal case */

					char source[32], dest[32], length[32];
					char slot_no[32];

					printf("writing to partition '%s'\n", ptn->name);
					char *mmc_write[6]  = {"mmc", NULL, "write", NULL, NULL, NULL};
					char *mmc_init[2] = {"mmcinit", NULL,};

					mmc_init[1] = slot_no;
					mmc_write[1] = slot_no;
					mmc_write[3] = source;
					mmc_write[4] = dest;
					mmc_write[5] = length;

					sprintf(slot_no, "%d", mmc_controller_no);
					sprintf(source, "0x%x", interface.transfer_buffer);
					sprintf(dest, "0x%x", ptn->start);
					sprintf(length, "0x%x", download_bytes);

					printf("Initializing '%s'\n", ptn->name);
					if (do_mmc(NULL, 0, 2, mmc_init))
						sprintf(response, "FAIL:Init of MMC card");
					else
						sprintf(response, "OKAY");


					printf("Writing '%s'\n", ptn->name);
					if (do_mmc(NULL, 0, 6, mmc_write)) {
						printf("Writing '%s' FAILED!\n", ptn->name);
						sprintf(response, "FAIL: Write partition");
					} else {
						printf("Writing '%s' DONE!\n", ptn->name);
						sprintf(response, "OKAY");
					}
				}

		} else {
			sprintf(response, "FAILno image downloaded");
		}
#endif
			ret = 0;
		}

		/* continue
		   Stop doing fastboot */
		if (memcmp(cmdbuf, "continue", 8) == 0) {
			sprintf(response, "OKAY");
			continue_booting = 1;
			ret = 0;
		}

		/* upload
		   Upload just the data in a partition */
		if ((memcmp(cmdbuf, "upload:", 7) == 0) ||
		    (memcmp(cmdbuf, "uploadraw:", 10) == 0)) {
#if defined(CONFIG_STORAGE_NAND)
			unsigned int adv, delim_index, len;
			struct fastboot_ptentry *ptn;
			unsigned int is_raw = 0;

			/* Is this a raw read ? */
			if (memcmp(cmdbuf, "uploadraw:", 10) == 0) {
				is_raw = 1;
				adv = 10;
			} else {
				adv = 7;
			}

			/* Scan to the next ':' to find when the size starts */
			len = strlen(cmdbuf);
			for (delim_index = adv;
			     delim_index < len; delim_index++) {
				if (cmdbuf[delim_index] == ':') {
					/* WARNING, cmdbuf is being modified. */
					*((char *) &cmdbuf[delim_index]) = 0;
					break;
				}
			}

			ptn = fastboot_flash_find_ptn(cmdbuf + adv);
			if (ptn == 0) {
				sprintf(response,
					"FAILpartition does not exist");
			} else {
				/* This is how much the user is expecting */
				unsigned int user_size;
				/*
				 * This is the maximum size needed for
				 * this partition
				 */
				unsigned int size;
				/* This is the length of the data */
				unsigned int length;
				/*
				 * Used to check previous write of
				 * the parition
				 */
				char env_ptn_length_var[128];
				char *env_ptn_length_val;

				user_size = 0;
				if (delim_index < len)
					user_size =
					  simple_strtoul(cmdbuf + delim_index +
							 1, NULL, 16);

				/* Make sure output is padded to block size */
				length = ptn->length;
				sprintf(env_ptn_length_var,
					"%s_nand_size", ptn->name);
				env_ptn_length_val = getenv(env_ptn_length_var);
				if (env_ptn_length_val) {
					length =
					  simple_strtoul(env_ptn_length_val,
							 NULL, 16);
					/* Catch possible problems */
					if (!length)
						length = ptn->length;
				}

				size = length / interface.nand_block_size;
				size *= interface.nand_block_size;
				if (length % interface.nand_block_size)
					size += interface.nand_block_size;

				if (is_raw)
					size += (size /
						 interface.nand_block_size) *
						interface.nand_oob_size;

				if (size > interface.transfer_buffer_size) {

					sprintf(response, "FAILdata too large");

				} else if (user_size == 0) {

					/* Send the data response */
					sprintf(response, "DATA%08x", size);

				} else if (user_size != size) {
					/* This is the wrong size */
					sprintf(response, "FAIL");
				} else {
					/*
					 * This is where the transfer
					 * buffer is populated
					 */
					unsigned char *buf =
					  interface.transfer_buffer;
					char start[32], length[32], type[32],
					  addr[32];
					char *read[6] = { "nand", NULL, NULL,
							  NULL, NULL, NULL, };

					/*
					 * Setting upload_size causes
					 * transfer to happen in main loop
					 */
					upload_size = size;
					upload_bytes = 0;
					upload_error = 0;

					/*
					 * Poison the transfer buffer, 0xff
					 * is erase value of nand
					 */
					memset(buf, 0xff, upload_size);

					/* Which flavor of read to use */
					if (is_raw)
						sprintf(type, "read.raw");
					else
						sprintf(type, "read.i");

					sprintf(addr, "0x%x",
						interface.transfer_buffer);
					sprintf(start, "0x%x", ptn->start);
					sprintf(length, "0x%x", upload_size);

					read[1] = type;
					read[2] = addr;
					read[3] = start;
					read[4] = length;

					set_ptn_ecc(ptn);

					do_nand(NULL, 0, 5, read);

					/* Send the data response */
					sprintf(response, "DATA%08x", size);
				}
			}
#endif
			ret = 0;
		}

		fastboot_tx_status(response, strlen(response));

	} /* End of command */
	
	return ret;
}
	void nand_boot(int nand_boot_select)
	{
		unsigned int offset, size;
		void (*kernel)(int, char **, char *);

		int i;
		static u32 *param_addr = 0;
		static u8 *tmpbuf = 0;
		static u8 cmdline[256] = CFG_CMDLINE;

		serial_puts_info("Enter nand_boot routine ...\n");

		switch (nand_boot_select) {
		case NORMAL_BOOT:
			offset = CFG_BOOT_OFFS;
			size = CFG_BOOT_SIZE;
	#ifdef BOOTARGS_NORMAL
			strcpy((char *)cmdline, BOOTARGS_NORMAL);
	#endif
			serial_puts_info("Normal boot ...\n");
			break;
		case RECOVERY_BOOT:
			offset = CFG_RECOVERY_OFFS;
			size = CFG_RECOVERY_SIZE;
	#ifdef BOOTARGS_RECOVERY
			strcpy((char *)cmdline, BOOTARGS_RECOVERY);
	#endif
			serial_puts_info("Recovery boot ...\n");
			break;
	#if defined(CONFIG_JZ4760_PT701_8)
		case PRETEST_BOOT:
			offset = CFG_PRETEST_OFFS;
			size = CFG_PRETEST_SIZE;
			serial_puts_info("Pretest boot ...\n");
			break;
	#endif
		default:
			serial_puts_info("Get nand boot select failed, defualt normal boot ...\n");
			offset = CFG_BOOT_OFFS;
			size = CFG_BOOT_SIZE;
			break;
		}

		serial_puts_info("Load kernel from NAND ...\n");
		/* Load kernel and ramdisk */
		do_nand(offset,CFG_NAND_PAGE_SIZE,(u8 *)CFG_KERNEL_DST);

		struct boot_img_hdr *bootimginfo;
		int kernel_actual;
		int ramdisk_actual;
		unsigned int page_mask;
		if(2048 < sizeof(struct boot_img_hdr)){
			serial_puts_info("size too small");
		}

		bootimginfo = (struct boot_img_hdr *)CFG_KERNEL_DST;
		page_mask = CFG_NAND_PAGE_SIZE - 1;
		kernel_actual = (bootimginfo->kernel_size + page_mask) & (~page_mask);
		ramdisk_actual = (bootimginfo->ramdisk_size + page_mask) & (~page_mask);
		size = kernel_actual + ramdisk_actual + M; // ' + M' to make sure including the special data.

		do_nand(offset + CFG_NAND_PAGE_SIZE,
				size, (u8 *)(CFG_KERNEL_DST + CFG_NAND_PAGE_SIZE));

#ifdef CONFIG_SECURITY_ENABLE
                // Special data is 4M from head.
                if(data_verify((unsigned char *)CFG_KERNEL_DST, 4 * M, ENV_BOOTLOADER) < 0) {
                    serial_puts_spl("kernel verify failed, power off\n");
                    //powerdown();
                    while(1);
                }
#endif

	#if  0
		serial_puts_info("CRC32 = 0x");
		serial_put_hex(CRC_32(CFG_KERNEL_DST,2973696));
		serial_put_hex(*((unsigned int *)(CFG_KERNEL_DST+0)));
		serial_put_hex(*((unsigned int *)(CFG_KERNEL_DST+4)));
		serial_put_hex(*((unsigned int *)(CFG_KERNEL_DST+8)));
		serial_put_hex(*((unsigned int *)(CFG_KERNEL_DST+12)));
	#endif

		serial_puts_info("Prepare kernel parameters ...\n");
		/* init kernel, ramdisk and prepare parameters */
		if (init_boot_linux((unsigned char*)CFG_KERNEL_DST, size) == 0) {
			serial_puts_info("Jump to kernel start Addr 0x");
			dump_uint(CFG_KERNEL_DST);
			serial_puts("\n\n");
			kernel = (void (*)(int, char **, char *))CFG_KERNEL_DST;
			flush_cache_all();
	#if CONFIG_XBOOT_LOGO_FILE
			//__lcd_display_off();
	#endif
			/* Jump to kernel image */
			(*kernel)(2, (char **)(PARAM_BASE + 16), (char *)PARAM_BASE);
			serial_puts_info("We should not come here ... \n");
		} else
			serial_puts_info("Magic number error,boot error...\n");
	}