Commit c6631764c2a64efc91c84077ca65f4fee153f133

Authored by Pantelis Antoniou
Committed by Marek Vasut
1 parent c4df2f4100

dfu: NAND specific routines for DFU operation

Support for NAND storage devices to work with the DFU framework.

Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com>
Signed-off-by: Tom Rini <trini@ti.com>
Acked-by: Scott Wood <scottwood@freescale.com>

Showing 5 changed files with 222 additions and 0 deletions Side-by-side Diff

... ... @@ -1357,6 +1357,9 @@
1357 1357 CONFIG_DFU_MMC
1358 1358 This enables support for exposing (e)MMC devices via DFU.
1359 1359  
  1360 + CONFIG_DFU_NAND
  1361 + This enables support for exposing NAND devices via DFU.
  1362 +
1360 1363 CONFIG_SYS_DFU_MAX_FILE_SIZE
1361 1364 When updating files rather than the raw storage device,
1362 1365 we use a static buffer to copy the file into and then write
drivers/dfu/Makefile
... ... @@ -27,6 +27,7 @@
27 27  
28 28 COBJS-$(CONFIG_DFU_FUNCTION) += dfu.o
29 29 COBJS-$(CONFIG_DFU_MMC) += dfu_mmc.o
  30 +COBJS-$(CONFIG_DFU_NAND) += dfu_nand.o
30 31  
31 32 SRCS := $(COBJS-y:.o=.c)
32 33 OBJS := $(addprefix $(obj),$(COBJS-y))
... ... @@ -85,6 +85,7 @@
85 85 /* initial state */
86 86 dfu->crc = 0;
87 87 dfu->offset = 0;
  88 + dfu->bad_skip = 0;
88 89 dfu->i_blk_seq_num = 0;
89 90 dfu->i_buf_start = dfu_buf;
90 91 dfu->i_buf_end = dfu_buf + sizeof(dfu_buf);
... ... @@ -233,6 +234,8 @@
233 234 dfu->i_buf = dfu->i_buf_start;
234 235 dfu->b_left = 0;
235 236  
  237 + dfu->bad_skip = 0;
  238 +
236 239 dfu->inited = 1;
237 240 }
238 241  
... ... @@ -262,6 +265,8 @@
262 265 dfu->i_buf = dfu->i_buf_start;
263 266 dfu->b_left = 0;
264 267  
  268 + dfu->bad_skip = 0;
  269 +
265 270 dfu->inited = 0;
266 271 }
267 272  
... ... @@ -283,6 +288,9 @@
283 288 /* Specific for mmc device */
284 289 if (strcmp(interface, "mmc") == 0) {
285 290 if (dfu_fill_entity_mmc(dfu, s))
  291 + return -1;
  292 + } else if (strcmp(interface, "nand") == 0) {
  293 + if (dfu_fill_entity_nand(dfu, s))
286 294 return -1;
287 295 } else {
288 296 printf("%s: Device %s not (yet) supported!\n",
drivers/dfu/dfu_nand.c
  1 +/*
  2 + * dfu_nand.c -- DFU for NAND routines.
  3 + *
  4 + * Copyright (C) 2012-2013 Texas Instruments, Inc.
  5 + *
  6 + * Based on dfu_mmc.c which is:
  7 + * Copyright (C) 2012 Samsung Electronics
  8 + * author: Lukasz Majewski <l.majewski@samsung.com>
  9 + *
  10 + * This program is free software; you can redistribute it and/or modify
  11 + * it under the terms of the GNU General Public License as published by
  12 + * the Free Software Foundation; either version 2 of the License, or
  13 + * (at your option) any later version.
  14 + *
  15 + * This program is distributed in the hope that it will be useful,
  16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18 + * GNU General Public License for more details.
  19 + *
  20 + * You should have received a copy of the GNU General Public License
  21 + * along with this program; if not, write to the Free Software
  22 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23 + */
  24 +
  25 +#include <common.h>
  26 +#include <malloc.h>
  27 +#include <errno.h>
  28 +#include <div64.h>
  29 +#include <dfu.h>
  30 +#include <linux/mtd/mtd.h>
  31 +#include <jffs2/load_kernel.h>
  32 +#include <nand.h>
  33 +
  34 +enum dfu_nand_op {
  35 + DFU_OP_READ = 1,
  36 + DFU_OP_WRITE,
  37 +};
  38 +
  39 +static int nand_block_op(enum dfu_nand_op op, struct dfu_entity *dfu,
  40 + u64 offset, void *buf, long *len)
  41 +{
  42 + loff_t start, lim;
  43 + size_t count, actual;
  44 + int ret;
  45 + nand_info_t *nand;
  46 +
  47 + /* if buf == NULL return total size of the area */
  48 + if (buf == NULL) {
  49 + *len = dfu->data.nand.size;
  50 + return 0;
  51 + }
  52 +
  53 + start = dfu->data.nand.start + offset + dfu->bad_skip;
  54 + lim = dfu->data.nand.start + dfu->data.nand.size - start;
  55 + count = *len;
  56 +
  57 + if (nand_curr_device < 0 ||
  58 + nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
  59 + !nand_info[nand_curr_device].name) {
  60 + printf("%s: invalid nand device\n", __func__);
  61 + return -1;
  62 + }
  63 +
  64 + nand = &nand_info[nand_curr_device];
  65 +
  66 + if (op == DFU_OP_READ)
  67 + ret = nand_read_skip_bad(nand, start, &count, &actual,
  68 + lim, buf);
  69 + else
  70 + ret = nand_write_skip_bad(nand, start, &count, &actual,
  71 + lim, buf, 0);
  72 +
  73 + if (ret != 0) {
  74 + printf("%s: nand_%s_skip_bad call failed at %llx!\n",
  75 + __func__, op == DFU_OP_READ ? "read" : "write",
  76 + start);
  77 + return ret;
  78 + }
  79 +
  80 + /*
  81 + * Find out where we stopped writing data. This can be deeper into
  82 + * the NAND than we expected due to having to skip bad blocks. So
  83 + * we must take this into account for the next write, if any.
  84 + */
  85 + if (actual > count)
  86 + dfu->bad_skip += actual - count;
  87 +
  88 + return ret;
  89 +}
  90 +
  91 +static inline int nand_block_write(struct dfu_entity *dfu,
  92 + u64 offset, void *buf, long *len)
  93 +{
  94 + return nand_block_op(DFU_OP_WRITE, dfu, offset, buf, len);
  95 +}
  96 +
  97 +static inline int nand_block_read(struct dfu_entity *dfu,
  98 + u64 offset, void *buf, long *len)
  99 +{
  100 + return nand_block_op(DFU_OP_READ, dfu, offset, buf, len);
  101 +}
  102 +
  103 +static int dfu_write_medium_nand(struct dfu_entity *dfu,
  104 + u64 offset, void *buf, long *len)
  105 +{
  106 + int ret = -1;
  107 +
  108 + switch (dfu->layout) {
  109 + case DFU_RAW_ADDR:
  110 + ret = nand_block_write(dfu, offset, buf, len);
  111 + break;
  112 + default:
  113 + printf("%s: Layout (%s) not (yet) supported!\n", __func__,
  114 + dfu_get_layout(dfu->layout));
  115 + }
  116 +
  117 + return ret;
  118 +}
  119 +
  120 +static int dfu_read_medium_nand(struct dfu_entity *dfu, u64 offset, void *buf,
  121 + long *len)
  122 +{
  123 + int ret = -1;
  124 +
  125 + switch (dfu->layout) {
  126 + case DFU_RAW_ADDR:
  127 + ret = nand_block_read(dfu, offset, buf, len);
  128 + break;
  129 + default:
  130 + printf("%s: Layout (%s) not (yet) supported!\n", __func__,
  131 + dfu_get_layout(dfu->layout));
  132 + }
  133 +
  134 + return ret;
  135 +}
  136 +
  137 +int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
  138 +{
  139 + char *st;
  140 + int ret, dev, part;
  141 +
  142 + dfu->dev_type = DFU_DEV_NAND;
  143 + st = strsep(&s, " ");
  144 + if (!strcmp(st, "raw")) {
  145 + dfu->layout = DFU_RAW_ADDR;
  146 + dfu->data.nand.start = simple_strtoul(s, &s, 16);
  147 + s++;
  148 + dfu->data.nand.size = simple_strtoul(s, &s, 16);
  149 + } else if (!strcmp(st, "part")) {
  150 + char mtd_id[32];
  151 + struct mtd_device *mtd_dev;
  152 + u8 part_num;
  153 + struct part_info *pi;
  154 +
  155 + dfu->layout = DFU_RAW_ADDR;
  156 +
  157 + dev = simple_strtoul(s, &s, 10);
  158 + s++;
  159 + part = simple_strtoul(s, &s, 10);
  160 +
  161 + sprintf(mtd_id, "%s%d,%d", "nand", dev, part - 1);
  162 + printf("using id '%s'\n", mtd_id);
  163 +
  164 + mtdparts_init();
  165 +
  166 + ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi);
  167 + if (ret != 0) {
  168 + printf("Could not locate '%s'\n", mtd_id);
  169 + return -1;
  170 + }
  171 +
  172 + dfu->data.nand.start = pi->offset;
  173 + dfu->data.nand.size = pi->size;
  174 +
  175 + } else {
  176 + printf("%s: Memory layout (%s) not supported!\n", __func__, st);
  177 + return -1;
  178 + }
  179 +
  180 + dfu->read_medium = dfu_read_medium_nand;
  181 + dfu->write_medium = dfu_write_medium_nand;
  182 +
  183 + /* initial state */
  184 + dfu->inited = 0;
  185 +
  186 + return 0;
  187 +}
... ... @@ -52,6 +52,15 @@
52 52 unsigned int part;
53 53 };
54 54  
  55 +struct nand_internal_data {
  56 + /* RAW programming */
  57 + u64 start;
  58 + u64 size;
  59 +
  60 + unsigned int dev;
  61 + unsigned int part;
  62 +};
  63 +
55 64 static inline unsigned int get_mmc_blk_size(int dev)
56 65 {
57 66 return find_mmc_device(dev)->read_bl_len;
... ... @@ -74,6 +83,7 @@
74 83  
75 84 union {
76 85 struct mmc_internal_data mmc;
  86 + struct nand_internal_data nand;
77 87 } data;
78 88  
79 89 int (*read_medium)(struct dfu_entity *dfu,
... ... @@ -96,6 +106,8 @@
96 106 long r_left;
97 107 long b_left;
98 108  
  109 + u32 bad_skip; /* for nand use */
  110 +
99 111 unsigned int inited:1;
100 112 };
101 113  
... ... @@ -120,5 +132,16 @@
120 132 return -1;
121 133 }
122 134 #endif
  135 +
  136 +#ifdef CONFIG_DFU_NAND
  137 +extern int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s);
  138 +#else
  139 +static inline int dfu_fill_entity_nand(struct dfu_entity *dfu, char *s)
  140 +{
  141 + puts("NAND support not available!\n");
  142 + return -1;
  143 +}
  144 +#endif
  145 +
123 146 #endif /* __DFU_ENTITY_H_ */