1 /* 2 * Copyright 2014 Broadcom Corporation. 3 * Copyright 2015 Free Electrons. 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <config.h> 9 #include <common.h> 10 11 #include <aboot.h> 12 #include <fastboot.h> 13 #include <sparse_format.h> 14 15 #include <linux/mtd/mtd.h> 16 #include <jffs2/jffs2.h> 17 #include <nand.h> 18 19 static char *response_str; 20 21 struct fb_nand_sparse { 22 nand_info_t *nand; 23 struct part_info *part; 24 }; 25 26 static int fb_nand_lookup(const char *partname, char *response, 27 nand_info_t **nand, 28 struct part_info **part) 29 { 30 struct mtd_device *dev; 31 int ret; 32 u8 pnum; 33 34 ret = mtdparts_init(); 35 if (ret) { 36 error("Cannot initialize MTD partitions\n"); 37 fastboot_fail(response_str, "cannot init mtdparts"); 38 return ret; 39 } 40 41 ret = find_dev_and_part(partname, &dev, &pnum, part); 42 if (ret) { 43 error("cannot find partition: '%s'", partname); 44 fastboot_fail(response_str, "cannot find partition"); 45 return ret; 46 } 47 48 if (dev->id->type != MTD_DEV_TYPE_NAND) { 49 error("partition '%s' is not stored on a NAND device", 50 partname); 51 fastboot_fail(response_str, "not a NAND device"); 52 return -EINVAL; 53 } 54 55 *nand = &nand_info[dev->id->num]; 56 57 return 0; 58 } 59 60 static int _fb_nand_erase(nand_info_t *nand, struct part_info *part) 61 { 62 nand_erase_options_t opts; 63 int ret; 64 65 memset(&opts, 0, sizeof(opts)); 66 opts.offset = part->offset; 67 opts.length = part->size; 68 opts.quiet = 1; 69 70 printf("Erasing blocks 0x%llx to 0x%llx\n", 71 part->offset, part->offset + part->size); 72 73 ret = nand_erase_opts(nand, &opts); 74 if (ret) 75 return ret; 76 77 printf("........ erased 0x%llx bytes from '%s'\n", 78 part->size, part->name); 79 80 return 0; 81 } 82 83 static int _fb_nand_write(nand_info_t *nand, struct part_info *part, 84 void *buffer, unsigned int offset, 85 unsigned int length, size_t *written) 86 { 87 int flags = WITH_WR_VERIFY; 88 89 #ifdef CONFIG_FASTBOOT_FLASH_NAND_TRIMFFS 90 flags |= WITH_DROP_FFS; 91 #endif 92 93 return nand_write_skip_bad(nand, offset, &length, written, 94 part->size - (offset - part->offset), 95 buffer, flags); 96 } 97 98 static int fb_nand_sparse_write(struct sparse_storage *storage, 99 void *priv, 100 unsigned int offset, 101 unsigned int size, 102 char *data) 103 { 104 struct fb_nand_sparse *sparse = priv; 105 size_t written; 106 int ret; 107 108 ret = _fb_nand_write(sparse->nand, sparse->part, data, 109 offset * storage->block_sz, 110 size * storage->block_sz, &written); 111 if (ret < 0) { 112 printf("Failed to write sparse chunk\n"); 113 return ret; 114 } 115 116 return written / storage->block_sz; 117 } 118 119 void fb_nand_flash_write(const char *partname, unsigned int session_id, 120 void *download_buffer, unsigned int download_bytes, 121 char *response) 122 { 123 struct part_info *part; 124 nand_info_t *nand = NULL; 125 int ret; 126 127 /* initialize the response buffer */ 128 response_str = response; 129 130 ret = fb_nand_lookup(partname, response, &nand, &part); 131 if (ret) { 132 error("invalid NAND device"); 133 fastboot_fail(response_str, "invalid NAND device"); 134 return; 135 } 136 137 if (is_sparse_image(download_buffer)) { 138 struct fb_nand_sparse sparse_priv; 139 sparse_storage_t sparse; 140 141 sparse_priv.nand = nand; 142 sparse_priv.part = part; 143 144 sparse.block_sz = nand->writesize; 145 sparse.start = part->offset / sparse.block_sz; 146 sparse.size = part->size / sparse.block_sz; 147 sparse.name = part->name; 148 sparse.write = fb_nand_sparse_write; 149 150 ret = store_sparse_image(&sparse, &sparse_priv, session_id, 151 download_buffer); 152 } else { 153 printf("Flashing raw image at offset 0x%llx\n", 154 part->offset); 155 156 ret = _fb_nand_write(nand, part, download_buffer, part->offset, 157 download_bytes, NULL); 158 159 printf("........ wrote %u bytes to '%s'\n", 160 download_bytes, part->name); 161 } 162 163 if (ret) { 164 fastboot_fail(response_str, "error writing the image"); 165 return; 166 } 167 168 fastboot_okay(response_str, ""); 169 } 170 171 void fb_nand_erase(const char *partname, char *response) 172 { 173 struct part_info *part; 174 nand_info_t *nand = NULL; 175 int ret; 176 177 /* initialize the response buffer */ 178 response_str = response; 179 180 ret = fb_nand_lookup(partname, response, &nand, &part); 181 if (ret) { 182 error("invalid NAND device"); 183 fastboot_fail(response_str, "invalid NAND device"); 184 return; 185 } 186 187 ret = _fb_nand_erase(nand, part); 188 if (ret) { 189 error("failed erasing from device %s", nand->name); 190 fastboot_fail(response_str, "failed erasing from device"); 191 return; 192 } 193 194 fastboot_okay(response_str, ""); 195 } 196