[U-Boot] [PATCH] Flex-OneNAND driver

Kyungmin Park kmpark at infradead.org
Fri Sep 26 03:27:20 CEST 2008


Hi,

In u-boot, I only comment the u-boot part only. others are same at mtd
mailing list.

generally looks good to me. except minor ones.

Thank you,
Kyungmin Park

> --- a/common/cmd_onenand.c
> +++ b/common/cmd_onenand.c
> @@ -20,9 +20,64 @@
>
>  extern struct mtd_info onenand_mtd;
>  extern struct onenand_chip onenand_chip;
> +loff_t flexonenand_get_addr(int block)

Should be static. maybe you use this one for drviers/mtd/onenand. but
it's not good idea.
I want to separate onenand command and driver codes.

> +{
> +       struct mtd_info *mtd = &onenand_mtd;
> +       struct onenand_chip *this = mtd->priv;
> +       loff_t ofs;
> +       int die = 0, boundary;
> +
> +       ofs = 0;
> +       if (this->dies == 2 && block >= this->density_mask) {
> +               block -= this->density_mask;
> +               die = 1;
> +               ofs = this->diesize[0];
> +       }
> +       boundary = this->boundary[die];
> +       ofs += block << (this->erase_shift - 1);
> +       if (block > (boundary + 1))
> +               ofs += (block - boundary - 1) << (this->erase_shift - 1);
> +       return ofs;
> +}
> +
> +static int do_erase(ulong start, ulong end)
> +{
> +       struct mtd_info *mtd = &onenand_mtd;
> +       struct onenand_chip *this = mtd->priv;
> +       struct erase_info instr = {
> +               .callback       = NULL,
> +       };
> +       int i, ret;
> +       ulong block;
> +
> +       printf("Erase block from %lu to %lu\n", start, end);
> +
> +       for (block = start; block <= end; block++) {
> +               if (FLEXONENAND(this))
> +                       instr.addr = flexonenand_get_addr(block);
> +               else
> +                       instr.addr = block << onenand_chip.erase_shift;
> +
> +               if (FLEXONENAND(this) && (mtd->numeraseregions > 1)) {
> +                       for (i = 0; i < mtd->numeraseregions &&
> +                               mtd->eraseregions[i].offset <= instr.addr;
> i++)
> +                               ;
> +                       i--;
> +                       instr.len =
> +                       mtd->eraseregions[i].erasesize;
> +               } else
> +                       instr.len = mtd->erasesize;
> +               ret = onenand_erase(&onenand_mtd, &instr);
> +               if (ret)
> +                       printf("erase failed %lu\n", block);
> +       }
> +       return 0;
> +}
>
>  int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
>  {
> +       struct mtd_info *mtd = &onenand_mtd;
> +       struct onenand_chip *this = mtd->priv;
>        int ret = 0;
>
>        switch (argc) {
> @@ -42,11 +97,7 @@
>        default:
>                /* At least 4 args */
>                if (strncmp(argv[1], "erase", 5) == 0) {
> -                       struct erase_info instr = {
> -                               .callback       = NULL,
> -                       };
>                        ulong start, end;
> -                       ulong block;
>                        char *endtail;
>
>                        if (strncmp(argv[2], "block", 5) == 0) {
> @@ -57,28 +108,18 @@
>                                start = simple_strtoul(argv[2], NULL, 10);
>                                end = simple_strtoul(argv[3], NULL, 10);
>
> -                               start >>= onenand_chip.erase_shift;
> -                               end >>= onenand_chip.erase_shift;
> +                               start = onenand_get_block(&onenand_mtd,
> +                                               start, NULL);
> +                               end = onenand_get_block(&onenand_mtd,
> +                                               end, NULL);
>                                /* Don't include the end block */
> -                               end--;
> +                               if (end > 0)
> +                                       end--;
>                        }
>
>                        if (!end || end < 0)
>                                end = start;
> -
> -                       printf("Erase block from %lu to %lu\n", start, end);
> -
> -                       for (block = start; block <= end; block++) {
> -                               instr.addr = block <<
> onenand_chip.erase_shift;
> -                               instr.len = 1 << onenand_chip.erase_shift;
> -                               ret = onenand_erase(&onenand_mtd, &instr);
> -                               if (ret) {
> -                                       printf("erase failed %lu\n", block);
> -                                       break;
> -                               }
> -                       }
> -
> -                       return 0;
> +                       return do_erase(start, end);
>                }
>
>                if (strncmp(argv[1], "read", 4) == 0) {
> @@ -134,15 +175,18 @@
>                        ops.mode = MTD_OOB_PLACE;
>
>
> -                       ofs = block << onenand_chip.erase_shift;
> +                       if (FLEXONENAND(this))
> +                               ofs = flexonenand_get_addr(block);
> +                       else
> +                               ofs = block << onenand_chip.erase_shift;
>                        if (page)
>                                ofs += page << onenand_chip.page_shift;
>
>                        if (!len) {
>                                if (oob)
> -                                       ops.ooblen = 64;
> +                                       ops.ooblen = FLEXONENAND(this) ? 128
> : 64;
>                                else
> -                                       ops.len = 512;
> +                                       ops.len = FLEXONENAND(this) ? 4096 :
> 512;
>                        }
>
>                        if (oob) {
> @@ -158,6 +202,39 @@
>                        return 0;
>                }
>
> +               if (strncmp(argv[1], "setboundary", 11) == 0) {
> +                       unsigned die = simple_strtoul(argv[2], NULL, 0);
> +                       unsigned bdry = simple_strtoul(argv[3], NULL, 0);
> +                       int lock = 0, old;
> +
> +                       if (!FLEXONENAND(this)) {
> +                               printf("Flex-OneNAND not found.\n");
> +                               return -1;
> +                       }
> +
> +                       if (argc == 5 && strncmp(argv[4], "LOCK", 4) == 0)
> +                               lock = 1;
> +
> +                       if (die >= this->dies) {
> +                               printf("Invalid die index\n");
> +                               return -1;
> +                       }
> +
> +                       if (!(bdry % 2)) {
> +                               printf("Attempt to set even boundary
> value.\n");

Typo, 'even' should be 'odd'.

> +                               bdry += 1;
> +                               printf("Setting boundary to %d\n", bdry);
> +                       }
> +
> +                       old = this->boundary[die] + (die *
> this->density_mask);
> +                       ret = flexonenand_set_boundary(mtd, die, bdry,
> lock);
> +                       if (!ret) {
> +                               int new = this->boundary[die] +
> +                                               (die * this->density_mask);
> +                               do_erase(min(old, new) + 1, max(old, new));
> +                       }
> +                       return 0;
> +               }
>                break;
>        }
>
> @@ -172,5 +249,7 @@
>        "onenand write addr ofs len - write data at ofs with len from
> addr\n"
>        "onenand erase saddr eaddr - erase block start addr to end addr\n"
>        "onenand block[.oob] addr block [page] [len] - "
> -               "read data with (block [, page]) to addr"
> +               "read data with (block [, page]) to addr\n"
> +       "onenand setboundary DIE BOUNDARY [LOCK] - "
> +       "Change SLC boundary of Flex-OneNAND"
>  );
> diff --git a/common/env_onenand.c b/common/env_onenand.c
> --- a/common/env_onenand.c
> +++ b/common/env_onenand.c
> @@ -58,11 +58,14 @@
>
>  void env_relocate_spec(void)
>  {
> +       struct onenand_chip *this = &onenand_chip;
>        unsigned long env_addr;
>        int use_default = 0;
>        size_t retlen;
>
>        env_addr = CONFIG_ENV_ADDR;
> +       if (FLEXONENAND(this))
> +               env_addr = CONFIG_ENV_ADDR_FLEX;

Umm do you have more fancy method to determine the environment address
whatever it's OneNAND or not.

>
>        /* Check OneNAND exist */
>        if (onenand_mtd.writesize)
> @@ -89,6 +92,7 @@
>
>  int saveenv(void)
>  {
> +       struct onenand_chip *this = &onenand_chip;
>        unsigned long env_addr = CONFIG_ENV_ADDR;
>        struct erase_info instr = {
>                .callback       = NULL,
> @@ -96,6 +100,12 @@
>        size_t retlen;
>
>        instr.len = CONFIG_ENV_SIZE;
> +       if (FLEXONENAND(this)) {
> +               env_addr = CONFIG_ENV_ADDR_FLEX;
> +               instr.len = CONFIG_ENV_SIZE_FLEX;
> +               instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
> +                               1 : 0;
> +       }

Ditto.

>        instr.addr = env_addr;
>        if (onenand_erase(&onenand_mtd, &instr)) {
>                printf("OneNAND: erase failed at 0x%08lx\n", env_addr);


More information about the U-Boot mailing list