2 * Copyright 2014 Broadcom Corporation.
3 * Copyright 2015 Free Electrons.
5 * SPDX-License-Identifier: GPL-2.0+
12 #include <image-sparse.h>
13 #include <sparse_format.h>
15 #include <linux/mtd/mtd.h>
16 #include <jffs2/jffs2.h>
19 static char *response_str
;
21 struct fb_nand_sparse
{
23 struct part_info
*part
;
26 __weak
int board_fastboot_erase_partition_setup(char *name
)
31 __weak
int board_fastboot_write_partition_setup(char *name
)
36 static int fb_nand_lookup(const char *partname
, char *response
,
38 struct part_info
**part
)
40 struct mtd_device
*dev
;
44 ret
= mtdparts_init();
46 error("Cannot initialize MTD partitions\n");
47 fastboot_fail(response_str
, "cannot init mtdparts");
51 ret
= find_dev_and_part(partname
, &dev
, &pnum
, part
);
53 error("cannot find partition: '%s'", partname
);
54 fastboot_fail(response_str
, "cannot find partition");
58 if (dev
->id
->type
!= MTD_DEV_TYPE_NAND
) {
59 error("partition '%s' is not stored on a NAND device",
61 fastboot_fail(response_str
, "not a NAND device");
65 *nand
= &nand_info
[dev
->id
->num
];
70 static int _fb_nand_erase(nand_info_t
*nand
, struct part_info
*part
)
72 nand_erase_options_t opts
;
75 memset(&opts
, 0, sizeof(opts
));
76 opts
.offset
= part
->offset
;
77 opts
.length
= part
->size
;
80 printf("Erasing blocks 0x%llx to 0x%llx\n",
81 part
->offset
, part
->offset
+ part
->size
);
83 ret
= nand_erase_opts(nand
, &opts
);
87 printf("........ erased 0x%llx bytes from '%s'\n",
88 part
->size
, part
->name
);
93 static int _fb_nand_write(nand_info_t
*nand
, struct part_info
*part
,
94 void *buffer
, unsigned int offset
,
95 unsigned int length
, size_t *written
)
97 int flags
= WITH_WR_VERIFY
;
99 #ifdef CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS
100 flags
|= WITH_DROP_FFS
;
103 return nand_write_skip_bad(nand
, offset
, &length
, written
,
104 part
->size
- (offset
- part
->offset
),
108 static int fb_nand_sparse_write(struct sparse_storage
*storage
,
114 struct fb_nand_sparse
*sparse
= priv
;
118 ret
= _fb_nand_write(sparse
->nand
, sparse
->part
, data
,
119 offset
* storage
->block_sz
,
120 size
* storage
->block_sz
, &written
);
122 printf("Failed to write sparse chunk\n");
126 return written
/ storage
->block_sz
;
129 void fb_nand_flash_write(const char *partname
, unsigned int session_id
,
130 void *download_buffer
, unsigned int download_bytes
,
133 struct part_info
*part
;
134 nand_info_t
*nand
= NULL
;
137 /* initialize the response buffer */
138 response_str
= response
;
140 ret
= fb_nand_lookup(partname
, response
, &nand
, &part
);
142 error("invalid NAND device");
143 fastboot_fail(response_str
, "invalid NAND device");
147 ret
= board_fastboot_write_partition_setup(part
->name
);
151 if (is_sparse_image(download_buffer
)) {
152 struct fb_nand_sparse sparse_priv
;
153 sparse_storage_t sparse
;
155 sparse_priv
.nand
= nand
;
156 sparse_priv
.part
= part
;
158 sparse
.block_sz
= nand
->writesize
;
159 sparse
.start
= part
->offset
/ sparse
.block_sz
;
160 sparse
.size
= part
->size
/ sparse
.block_sz
;
161 sparse
.name
= part
->name
;
162 sparse
.write
= fb_nand_sparse_write
;
164 ret
= store_sparse_image(&sparse
, &sparse_priv
, session_id
,
167 printf("Flashing raw image at offset 0x%llx\n",
170 ret
= _fb_nand_write(nand
, part
, download_buffer
, part
->offset
,
171 download_bytes
, NULL
);
173 printf("........ wrote %u bytes to '%s'\n",
174 download_bytes
, part
->name
);
178 fastboot_fail(response_str
, "error writing the image");
182 fastboot_okay(response_str
, "");
185 void fb_nand_erase(const char *partname
, char *response
)
187 struct part_info
*part
;
188 nand_info_t
*nand
= NULL
;
191 /* initialize the response buffer */
192 response_str
= response
;
194 ret
= fb_nand_lookup(partname
, response
, &nand
, &part
);
196 error("invalid NAND device");
197 fastboot_fail(response_str
, "invalid NAND device");
201 ret
= board_fastboot_erase_partition_setup(part
->name
);
205 ret
= _fb_nand_erase(nand
, part
);
207 error("failed erasing from device %s", nand
->name
);
208 fastboot_fail(response_str
, "failed erasing from device");
212 fastboot_okay(response_str
, "");