diff options
| author | mattis fjallstrom <mattis@acm.org> | 2015-09-06 11:09:39 -0700 |
|---|---|---|
| committer | mattis fjallstrom <mattis@acm.org> | 2015-09-06 11:09:39 -0700 |
| commit | ee87ec4d2c955c929a4c27ce8a56f918444cf955 (patch) | |
| tree | c18141755ad893eddd5b504e4cf096ad4e7062b9 /drivers/usb/gadget/u_fastboot_nand.c | |
| parent | 2c25de1ed5c6f8f6bba3b5ec506f430d8a883a83 (diff) | |
| download | olio-uboot-2014.01-ee87ec4d2c955c929a4c27ce8a56f918444cf955.tar.xz olio-uboot-2014.01-ee87ec4d2c955c929a4c27ce8a56f918444cf955.zip | |
First fastboot commit, MLO built here wont work so be careful.
Change-Id: Ic8d65a92da82896282eee71cf0d0515f64c939bc
Diffstat (limited to 'drivers/usb/gadget/u_fastboot_nand.c')
| -rw-r--r-- | drivers/usb/gadget/u_fastboot_nand.c | 838 |
1 files changed, 838 insertions, 0 deletions
diff --git a/drivers/usb/gadget/u_fastboot_nand.c b/drivers/usb/gadget/u_fastboot_nand.c new file mode 100644 index 000000000..29da46dd0 --- /dev/null +++ b/drivers/usb/gadget/u_fastboot_nand.c @@ -0,0 +1,838 @@ +/* + * Copyright (C) 2013 Texas Instruments + * + * Author : Pankaj Bharadiya <pankaj.bharadiya@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Fastboot is implemented using gadget stack, many of the ideas are + * derived from fastboot implemented in OmapZoom by + * Tom Rix <Tom.Rix@windriver.com> and Sitara 2011 u-boot by + * Mohammed Afzal M A <afzal@ti.com> + * + * Part of OmapZoom was copied from Android project, Android source + * (legacy bootloader) was used indirectly here by using OmapZoom. + * + * This is Android's Copyright: + * + * Copyright (C) 2008 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <common.h> +#include <command.h> +#include <usb/fastboot.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include "g_fastboot.h" + +#include <nand.h> +#include <environment.h> + +#define MAX_PTN 11 + +/* Initialize the name of fastboot flash name mappings */ +fastboot_ptentry omap3h1_nand_ptn[MAX_PTN] = { + { + .name = "X-Loader", + .start = 0x0000000, + .length = 0x0020000, /* 256 K */ + /* Written into the first 0x40000 blocks + Use HW ECC */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC + /* FASTBOOT_PTENTRY_FLAGS_REPEAT_4, */ + }, + { + .name = "uboot", + .start = 0x0080000, + .length = 0x01E0000, /* 1.875 M */ + /* Skip bad blocks on write + Use HW ECC */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC, + }, + { + .name = "U-Boot Env", + .start = NAND_ENV_OFFSET, /* set in config file */ + .length = 0x0020000, + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_ENV | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "kernel", + .start = 0x0280000, + .length = 0x0500000, /* 5 M */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "initramfs", + .start = 0x0780000, + .length = 0x0A00000, /* 10 M */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "devicetree", + .start = 0x1180000, + .length = 0x020000, /* 128k */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "ramdisk", + .start = 0x1180000, + .length = 0x0C80000, /* 13 M */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "system", + .start = 0x1E80000, + .length = 0x800 * 0x20000, /* >256 M */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "cache", + .start = 0x11E80000, + .length = 0x400 * 0x20000, /* ~50Mb */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "recovery", + .start = 0x14A80000, + .length = 0x200 * 0x20000, /* ~26Mb */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, + { + .name = "userdata", + .start = 0x2f80000, + .length = 0x28CC0000, /* ~660 Mb */ + .flags = FASTBOOT_PTENTRY_FLAGS_WRITE_I | + FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC, + }, +}; + + +struct fastboot_config fastboot_cfg; + +extern int do_env_save (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); +extern int do_switch_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]); + +static void set_env(char *var, char *val) +{ + char *setenv[4] = { "setenv", NULL, NULL, NULL, }; + + setenv[1] = var; + setenv[2] = val; + + do_env_set(NULL, 0, 3, setenv); +} + +static void set_ecc(int hw) +{ + char ecc_type[2]; + char ecc_provider[3]; /* make sure there's space */ + char *ecc[4] = { "nandecc", "hw", "0" , NULL }; + + ecc[2] = ecc_type; + ecc[1] = ecc_provider; + + if (hw) + { + /*for hardware ecc : set BCH8*/ + sprintf(ecc_provider, "hw"); + } + else + { + sprintf(ecc_provider, "sw"); + } + +/* OLIO: HW = 1bit ECC, SW = BCH8 */ + + do_switch_ecc(NULL, 0, 2, ecc); +} + +static void save_env(struct fastboot_ptentry *ptn, + char *var, char *val) +{ + char *saveenv[2] = { "setenv", NULL, }; + set_env (var, val); + + if ((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) && + (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) { + /* Both can not be true */ + FBTWARN("can not do hw and sw ecc for partition '%s'\n", ptn->name); + FBTWARN("Ignoring these flags\n"); +#ifdef OLIO_INVALID + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) { + setecc(1); + + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) { + set_ecc(0); +#endif /* OLIO_INVALID */ + } + + /* OLIO: env always saved with SW */ + + set_ecc(0); + do_env_save(NULL, 0, 1, saveenv); +} + +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 *setenv[4] = { "setenv", NULL, NULL, NULL, }; + char *saveenv[2] = { "setenv", NULL, }; + + setenv[1] = var; + setenv[2] = val; + + FBTINFO ("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_env_set (NULL, 0, 3, setenv); + + sprintf (var, "%s_nand_size", ptn->name); + sprintf (val, ""); + do_env_set (NULL, 0, 3, setenv); + } else { + /* Normal case */ + + sprintf (var, "%s_nand_offset", ptn->name); + sprintf (val, "0x%x", offset); + + FBTINFO("%s %s %s\n", setenv[0], setenv[1], setenv[2]); + + do_env_set (NULL, 0, 3, setenv); + + sprintf(var, "%s_nand_size", ptn->name); + + sprintf (val, "0x%x", size); + + FBTINFO("%s %s %s\n", setenv[0], setenv[1], setenv[2]); + + do_env_set (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 */ + if ((env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) && + (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) + { + /* Both can not be true */ + FBTWARN("can not do hw and sw ecc for partition '%s'\n", ptn->name); + FBTWARN("Ignoring these flags\n"); + } + else if (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) + { + set_ecc(1); + } + else if (env_ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) + { + set_ecc(0); + } + + sprintf (start, "0x%x", env_ptn->start); + sprintf (length, "0x%x", env_ptn->length); + + } + + do_env_save (NULL, 0, 1, saveenv); +} + +/* When save = 0, just parse. The input is unchanged + When save = 1, parse and do the save. The input is changed */ +static int parse_env(void *ptn, char *err_string, int save, int debug) +{ + int ret = 1; + unsigned int sets = 0; + unsigned int comment_start = 0; + char *var = NULL; + char *var_end = NULL; + char *val = NULL; + char *val_end = NULL; + unsigned int i; + + char *buff = (char *)fastboot_cfg.transfer_buffer; + unsigned int size = fastboot_cfg.download_bytes_unpadded; + + /* The input does not have to be null terminated. + This will cause a problem in the corner case + where the last line does not have a new line. + Put a null after the end of the input. + + WARNING : Input buffer is assumed to be bigger + than the size of the input */ + if (save) + buff[size] = 0; + + for (i = 0; i < size; i++) { + + if (NULL == var) { + + /* + * Check for comments, comment ok only on + * mostly empty lines + */ + if (buff[i] == '#') + comment_start = 1; + + if (comment_start) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + comment_start = 0; + } + } else { + if (!((buff[i] == ' ') || + (buff[i] == '\t') || + (buff[i] == '\r') || + (buff[i] == '\n'))) { + /* + * Normal whitespace before the + * variable + */ + var = &buff[i]; + } + } + + } else if (((NULL == var_end) || (NULL == val)) && + ((buff[i] == '\r') || (buff[i] == '\n'))) { + + /* This is the case when a variable + is unset. */ + + if (save) { + /* Set the var end to null so the + normal string routines will work + + WARNING : This changes the input */ + buff[i] = '\0'; + + save_env(ptn, var, val); + + FBTDBG("Unsetting %s\n", var); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + sets++; + } else if (NULL == var_end) { + if ((buff[i] == ' ') || + (buff[i] == '\t')) + var_end = &buff[i]; + } else if (NULL == val) { + if (!((buff[i] == ' ') || + (buff[i] == '\t'))) + val = &buff[i]; + } else if (NULL == val_end) { + if ((buff[i] == '\r') || + (buff[i] == '\n')) { + /* look for escaped cr or ln */ + if ('\\' == buff[i - 1]) { + /* check for dos */ + if ((buff[i] == '\r') && + (buff[i+1] == '\n')) + buff[i + 1] = ' '; + buff[i - 1] = buff[i] = ' '; + } else { + val_end = &buff[i]; + } + } + } else { + sprintf(err_string, "Internal Error"); + + FBTDBG("Internal error at %s %d\n", + __FILE__, __LINE__); + return 1; + } + /* Check if a var / val pair is ready */ + if (NULL != val_end) { + if (save) { + /* Set the end's with nulls so + normal string routines will + work. + + WARNING : This changes the input */ + *var_end = '\0'; + *val_end = '\0'; + + save_env(ptn, var, val); + + FBTDBG("Setting %s %s\n", var, val); + } + + /* Clear the variable so state is parse is back + to initial. */ + var = NULL; + var_end = NULL; + val = NULL; + val_end = NULL; + + sets++; + } + } + + /* Corner case + Check for the case that no newline at end of the input */ + if ((NULL != var) && + (NULL == val_end)) { + if (save) { + /* case of val / val pair */ + if (var_end) + *var_end = '\0'; + /* else case handled by setting 0 past + the end of buffer. + Similar for val_end being null */ + save_env(ptn, var, val); + + if (var_end) + FBTDBG("Trailing Setting %s %s\n", var, val); + else + FBTDBG("Trailing Unsetting %s\n", var); + } + sets++; + } + /* Did we set anything ? */ + if (0 == sets) + sprintf(err_string, "No variables set"); + else + ret = 0; + + return ret; +} + +static int saveenv_to_ptn(struct fastboot_ptentry *ptn, char *err_string) +{ + int ret = 1; + int save = 0; + int debug = 0; + + /* err_string is only 32 bytes + Initialize with a generic error message. */ + sprintf(err_string, "%s", "Unknown Error"); + + /* Parse the input twice. + Only save to the enviroment if the entire input if correct */ + save = 0; + if (0 == parse_env(ptn, err_string, save, debug)) { + save = 1; + ret = parse_env(ptn, err_string, save, debug); + } + return ret; +} + +static void set_ptn_ecc(struct fastboot_ptentry *ptn) +{ + if (((ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC) || + (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC)) && + (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC)) { + /* Both can not be true */ + FBTERR("can not do hw and sw ecc for partition '%s'\n", + ptn->name); + FBTERR("Ignoring these flags\n"); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_BCH8_ECC) { + set_ecc(1); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_HW_ECC) { + set_ecc(1); + } else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_SW_ECC) { + set_ecc(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 write_type[32]; + int repeat, repeat_max; + + char *write[6] = { "nand", "write", NULL, NULL, NULL, NULL, }; + char *erase[5] = { "nand", "erase", NULL, NULL, NULL, }; + + erase[2] = start; + erase[3] = length; + + write[1] = write_type; + write[2] = addr; + write[3] = wstart; + write[4] = wlength; + + FBTINFO("flashing '%s'\n", ptn->name); + + /* Which flavor of write to use */ + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_I) + sprintf(write_type, "write.i"); + else if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2) + sprintf(write_type, "write.jffs2"); + else + sprintf(write_type, "write"); + + /* Some flashing requires writing the same data in multiple, + consecutive flash partitions */ + repeat_max = 1; + if (FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(ptn->flags)) { + if (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { + FBTWARN("can not do both 'contiguous block' and 'repeat' writes for for partition '%s'\n", ptn->name); + FBTWARN("Ignoring repeat flag\n"); + } else { + repeat_max = (FASTBOOT_PTENTRY_FLAGS_REPEAT_MASK(ptn->flags)); + } + } + + sprintf(length, "0x%x", ptn->length); + + for (repeat = 0; repeat < repeat_max; repeat++) { + + set_ptn_ecc(ptn); + sprintf(start, "0x%x", ptn->start + (repeat * ptn->length)); + + do_nand(NULL, 0, 4, erase); + + if ((ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_NEXT_GOOD_BLOCK) && + (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK)) { + /* Both can not be true */ + FBTWARN("can not do 'next good block' and 'contiguous block' for partition '%s'\n", ptn->name); + FBTWARN("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 (fastboot_cfg.nand_block_size) { + unsigned int blocks = fastboot_cfg.download_bytes / + fastboot_cfg.nand_block_size; + unsigned int i = 0; + unsigned int offset = 0; + + sprintf(wlength, "0x%x", + fastboot_cfg.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", + fastboot_cfg.transfer_buffer + + (i * fastboot_cfg.nand_block_size)); + + /* nand's address always advances */ + sprintf(wstart, "0x%x", + ptn->start + (repeat * ptn->length) + offset); + + ret = do_nand(NULL, 0, 5, write); + if (ret) + break; + else + i++; + + /* Go to next nand block */ + offset += fastboot_cfg.nand_block_size; + } + } else { + FBTWARN("nand block size can not be 0 when using 'next good block' for partition '%s'\n", ptn->name); + FBTWARN("Ignoring write request\n"); + } + } else if (ptn->flags & + FASTBOOT_PTENTRY_FLAGS_WRITE_CONTIGUOUS_BLOCK) { + /* Keep writing until you get a good block + transfer_buffer should already be aligned */ + if (fastboot_cfg.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]; + + FBTINFO("\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) >= + fastboot_cfg.download_bytes) + break; + } + + /* Check if there is enough space */ + if (ok_start + fastboot_cfg.download_bytes <= + ptn->start + ptn->length) { + sprintf(addr, "0x%x", fastboot_cfg.transfer_buffer); + sprintf(wstart, "0x%x", ok_start); + sprintf(wlength, "0x%x", fastboot_cfg.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, fastboot_cfg.download_bytes); + } + } else { + FBTERR("could not find enough contiguous space in partition '%s' \n", ptn->name); + FBTERR("Ignoring write request\n"); + } + } else { + /* TBD : Generalize flash handling */ + FBTERR("only handling 1 NAND per board"); + FBTERR("Ignoring write request\n"); + } + } else { + FBTWARN("nand block size can not be 0 when using 'continuous block' for partition '%s'\n", ptn->name); + FBTWARN("Ignoring write request\n"); + } + } else { + /* Normal case */ + sprintf(addr, "0x%x", fastboot_cfg.transfer_buffer); + sprintf(wstart, "0x%x", ptn->start + + (repeat * ptn->length)); + sprintf(wlength, "0x%x", fastboot_cfg.download_bytes); + if (ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_JFFS2) + sprintf(wlength, "0x%x", + fastboot_cfg.download_bytes_unpadded); + + ret = do_nand(NULL, 0, 5, write); + + if (0 == repeat) { + if (ret) /* failed */ + save_block_values(ptn, 0, 0); + else /* success */ + save_block_values(ptn, ptn->start, + fastboot_cfg.download_bytes); + } + } + + + if (ret) + break; + } + + return ret; +} + +int handle_flash(char *part_name , char *response) +{ + int status = 0; + + + fastboot_cfg.download_bytes_unpadded = fastboot_cfg.download_size; + /* XXX: Revisit padding handling */ + if (fastboot_cfg.nand_block_size) { + if (fastboot_cfg.download_bytes % fastboot_cfg.nand_block_size) { + unsigned int pad = fastboot_cfg.nand_block_size - (fastboot_cfg.download_bytes % fastboot_cfg.nand_block_size); + unsigned int i; + + for (i = 0; i < pad; i++) { + if (fastboot_cfg.download_bytes >= fastboot_cfg.transfer_buffer_size) + break; + + fastboot_cfg.transfer_buffer[fastboot_cfg.download_bytes] = 0; + fastboot_cfg.download_bytes++; + } + } + } + + + if (fastboot_cfg.download_bytes) { + struct fastboot_ptentry *ptn; + + ptn = fastboot_flash_find_ptn(part_name); + if (ptn == 0) { + sprintf(response, "FAILpartition does not exist"); + } else if ((fastboot_cfg.download_bytes > ptn->length) && + !(ptn->flags & FASTBOOT_PTENTRY_FLAGS_WRITE_ENV)) { + sprintf(response, "FAILimage too large for partition"); + } 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])) { + FBTINFO("savenv '%s' failed : %s\n", ptn->name, err_string); + sprintf(response, "FAIL%s", err_string); + } else { + FBTINFO("partition '%s' saveenv-ed\n", ptn->name); + sprintf(response, "OKAY"); + } + } else { + /* Normal case */ + if (write_to_ptn(ptn)) { + FBTINFO("flashing '%s' failed\n", ptn->name); + sprintf(response, "FAILfailed to flash partition"); + } else { + FBTINFO("partition '%s' flashed\n", ptn->name); + sprintf(response, "OKAY"); + } + } + } + } else { + sprintf(response, "FAILno image downloaded"); + } + + return status; +} + +/*This function does nothing with NAND partitioning. +It only adds partition info to fastboot partition table. +*/ +int do_format() +{ + int indx; + + fastboot_flash_reset_ptn(); + + for (indx = 0; indx < MAX_PTN; indx++) + { + fastboot_flash_add_ptn(&omap3h1_nand_ptn[indx]); + } + + fastboot_flash_dump_ptn(); + + return 0; +} + + +static int do_format_nand(void) +{ + struct ptable *ptbl = NULL; //&the_ptable; + unsigned next; + int n; + block_dev_desc_t *dev_desc; + unsigned long blocks_to_write, result; + + dev_desc = get_dev_by_name(FASTBOOT_BLKDEV); + if (!dev_desc) { + printf("error getting device %s\n", FASTBOOT_BLKDEV); + return -1; + } + if (!dev_desc->lba) { + printf("device %s has no space\n", FASTBOOT_BLKDEV); + return -1; + } + + printf("blocks %lu\n", dev_desc->lba); + + #if 0 + start_ptbl(ptbl, dev_desc->lba); + for (n = 0, next = 0; fbt_partitions[n].name; n++) { + u64 sz = fbt_partitions[n].size_kb * 2; + if (fbt_partitions[n].name[0] == '-') { + next += sz; + continue; + } + if (sz == 0) + sz = dev_desc->lba - next; + if (add_ptn(ptbl, next, next + sz - 1, fbt_partitions[n].name)) + return -1; + next += sz; + } + end_ptbl(ptbl); + + blocks_to_write = DIV_ROUND_UP(sizeof(struct ptable), dev_desc->blksz); + result = dev_desc->block_write(dev_desc->dev, 0, blocks_to_write, ptbl); + if (result != blocks_to_write) { + printf("\nFormat failed, block_write() returned %lu instead of %lu\n", result, blocks_to_write); + return -1; + } + + printf("\nnew partition table of %lu %lu-byte blocks\n", + blocks_to_write, dev_desc->blksz); + fbt_reset_ptn(); + #endif + + return 0; +} |