1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright 2014 Broadcom Corporation.
4 * Copyright 2015 Free Electrons.
11 #include <image-sparse.h>
13 #include <linux/printk.h>
14 #include <linux/mtd/mtd.h>
15 #include <jffs2/jffs2.h>
18 struct fb_nand_sparse
{
20 struct part_info
*part
;
23 __weak
int board_fastboot_erase_partition_setup(char *name
)
28 __weak
int board_fastboot_write_partition_setup(char *name
)
33 static int fb_nand_lookup(const char *partname
,
34 struct mtd_info
**mtd
,
35 struct part_info
**part
,
38 struct mtd_device
*dev
;
42 ret
= mtdparts_init();
44 pr_err("Cannot initialize MTD partitions\n");
45 fastboot_fail("cannot init mtdparts", response
);
49 ret
= find_dev_and_part(partname
, &dev
, &pnum
, part
);
51 pr_err("cannot find partition: '%s'", partname
);
52 fastboot_fail("cannot find partition", response
);
56 if (dev
->id
->type
!= MTD_DEV_TYPE_NAND
) {
57 pr_err("partition '%s' is not stored on a NAND device",
59 fastboot_fail("not a NAND device", response
);
63 *mtd
= get_nand_dev_by_index(dev
->id
->num
);
68 static int _fb_nand_erase(struct mtd_info
*mtd
, struct part_info
*part
)
70 nand_erase_options_t opts
;
73 memset(&opts
, 0, sizeof(opts
));
74 opts
.offset
= part
->offset
;
75 opts
.length
= part
->size
;
78 printf("Erasing blocks 0x%llx to 0x%llx\n",
79 part
->offset
, part
->offset
+ part
->size
);
81 ret
= nand_erase_opts(mtd
, &opts
);
85 printf("........ erased 0x%llx bytes from '%s'\n",
86 part
->size
, part
->name
);
91 static int _fb_nand_write(struct mtd_info
*mtd
, struct part_info
*part
,
92 void *buffer
, u32 offset
,
93 size_t length
, size_t *written
)
95 int flags
= WITH_WR_VERIFY
;
97 #ifdef CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS
98 flags
|= WITH_DROP_FFS
;
101 return nand_write_skip_bad(mtd
, offset
, &length
, written
,
102 part
->size
- (offset
- part
->offset
),
106 static lbaint_t
fb_nand_sparse_write(struct sparse_storage
*info
,
107 lbaint_t blk
, lbaint_t blkcnt
, const void *buffer
)
109 struct fb_nand_sparse
*sparse
= info
->priv
;
113 ret
= _fb_nand_write(sparse
->mtd
, sparse
->part
, (void *)buffer
,
115 blkcnt
* info
->blksz
, &written
);
117 printf("Failed to write sparse chunk\n");
121 /* TODO - verify that the value "written" includes the "bad-blocks" ... */
124 * the return value must be 'blkcnt' ("good-blocks") plus the
125 * number of "bad-blocks" encountered within this space...
127 return written
/ info
->blksz
;
130 static lbaint_t
fb_nand_sparse_reserve(struct sparse_storage
*info
,
131 lbaint_t blk
, lbaint_t blkcnt
)
136 * TODO - implement a function to determine the total number
137 * of blocks which must be used in order to reserve the specified
138 * number ("blkcnt") of "good-blocks", starting at "blk"...
139 * ( possibly something like the "check_skip_len()" function )
143 * the return value must be 'blkcnt' ("good-blocks") plus the
144 * number of "bad-blocks" encountered within this space...
146 return blkcnt
+ bad_blocks
;
150 * fastboot_nand_get_part_info() - Lookup NAND partion by name
152 * @part_name: Named device to lookup
153 * @part_info: Pointer to returned part_info pointer
154 * @response: Pointer to fastboot response buffer
156 int fastboot_nand_get_part_info(const char *part_name
,
157 struct part_info
**part_info
, char *response
)
159 struct mtd_info
*mtd
= NULL
;
161 return fb_nand_lookup(part_name
, &mtd
, part_info
, response
);
165 * fastboot_nand_flash_write() - Write image to NAND for fastboot
167 * @cmd: Named device to write image to
168 * @download_buffer: Pointer to image data
169 * @download_bytes: Size of image data
170 * @response: Pointer to fastboot response buffer
172 void fastboot_nand_flash_write(const char *cmd
, void *download_buffer
,
173 u32 download_bytes
, char *response
)
175 struct part_info
*part
;
176 struct mtd_info
*mtd
= NULL
;
179 ret
= fb_nand_lookup(cmd
, &mtd
, &part
, response
);
181 pr_err("invalid NAND device");
182 fastboot_fail("invalid NAND device", response
);
186 ret
= board_fastboot_write_partition_setup(part
->name
);
190 if (is_sparse_image(download_buffer
)) {
191 struct fb_nand_sparse sparse_priv
;
192 struct sparse_storage sparse
;
194 sparse_priv
.mtd
= mtd
;
195 sparse_priv
.part
= part
;
197 sparse
.blksz
= mtd
->writesize
;
198 sparse
.start
= part
->offset
/ sparse
.blksz
;
199 sparse
.size
= part
->size
/ sparse
.blksz
;
200 sparse
.write
= fb_nand_sparse_write
;
201 sparse
.reserve
= fb_nand_sparse_reserve
;
202 sparse
.mssg
= fastboot_fail
;
204 printf("Flashing sparse image at offset " LBAFU
"\n",
207 sparse
.priv
= &sparse_priv
;
208 ret
= write_sparse_image(&sparse
, cmd
, download_buffer
,
211 fastboot_okay(NULL
, response
);
213 printf("Flashing raw image at offset 0x%llx\n",
216 ret
= _fb_nand_write(mtd
, part
, download_buffer
, part
->offset
,
217 download_bytes
, NULL
);
219 printf("........ wrote %u bytes to '%s'\n",
220 download_bytes
, part
->name
);
224 fastboot_fail("error writing the image", response
);
228 fastboot_okay(NULL
, response
);
232 * fastboot_nand_flash_erase() - Erase NAND for fastboot
234 * @cmd: Named device to erase
235 * @response: Pointer to fastboot response buffer
237 void fastboot_nand_erase(const char *cmd
, char *response
)
239 struct part_info
*part
;
240 struct mtd_info
*mtd
= NULL
;
243 ret
= fb_nand_lookup(cmd
, &mtd
, &part
, response
);
245 pr_err("invalid NAND device");
246 fastboot_fail("invalid NAND device", response
);
250 ret
= board_fastboot_erase_partition_setup(part
->name
);
254 ret
= _fb_nand_erase(mtd
, part
);
256 pr_err("failed erasing from device %s", mtd
->name
);
257 fastboot_fail("failed erasing from device", response
);
261 fastboot_okay(NULL
, response
);