Norman James | 6a58a27 | 2015-10-07 14:34:16 -0500 | [diff] [blame] | 1 | #include <stdio.h>
|
| 2 | #include <stdlib.h>
|
| 3 | #include <string.h>
|
| 4 | #include <fcntl.h>
|
| 5 | #include <sys/mman.h>
|
| 6 | #include <sys/types.h>
|
| 7 | #include <sys/stat.h>
|
| 8 | #include <unistd.h>
|
| 9 | #include <byteswap.h>
|
| 10 | #include <stdint.h>
|
| 11 | #include <stdbool.h>
|
| 12 | #include <getopt.h>
|
| 13 | #include <limits.h>
|
| 14 | #include <arpa/inet.h>
|
| 15 | #include <assert.h>
|
| 16 |
|
| 17 | #include <libflash/libflash.h>
|
| 18 | #include <libflash/libffs.h>
|
| 19 | #include "progress.h"
|
| 20 | #include "io.h"
|
| 21 | #include "ast.h"
|
| 22 | #include "sfc-ctrl.h"
|
| 23 |
|
| 24 | #define __aligned(x) __attribute__((aligned(x)))
|
| 25 |
|
| 26 | #define PFLASH_VERSION "0.8.6"
|
| 27 |
|
| 28 | static bool must_confirm = false;
|
| 29 | static bool dummy_run;
|
| 30 | static bool need_relock;
|
| 31 | static bool bmc_flash;
|
| 32 | #ifdef __powerpc__
|
| 33 | static bool using_sfc;
|
| 34 | #endif
|
| 35 |
|
| 36 | #define FILE_BUF_SIZE 0x10000
|
| 37 | static uint8_t file_buf[FILE_BUF_SIZE] __aligned(0x1000);
|
| 38 |
|
| 39 | static struct spi_flash_ctrl *fl_ctrl;
|
| 40 | static struct flash_chip *fl_chip;
|
| 41 | static struct ffs_handle *ffsh;
|
| 42 | static uint32_t fl_total_size, fl_erase_granule;
|
| 43 | static const char *fl_name;
|
| 44 | static int32_t ffs_index = -1;
|
| 45 |
|
| 46 | static void check_confirm(void)
|
| 47 | {
|
| 48 | char yes[8], *p;
|
| 49 |
|
| 50 | if (!must_confirm)
|
| 51 | return;
|
| 52 |
|
| 53 | printf("WARNING ! This will modify your %s flash chip content !\n",
|
| 54 | bmc_flash ? "BMC" : "HOST");
|
| 55 | printf("Enter \"yes\" to confirm:");
|
| 56 | memset(yes, 0, sizeof(yes));
|
| 57 | if (!fgets(yes, 7, stdin))
|
| 58 | exit(1);
|
| 59 | p = strchr(yes, 10);
|
| 60 | if (p)
|
| 61 | *p = 0;
|
| 62 | p = strchr(yes, 13);
|
| 63 | if (p)
|
| 64 | *p = 0;
|
| 65 | if (strcmp(yes, "yes")) {
|
| 66 | printf("Operation cancelled !\n");
|
| 67 | exit(1);
|
| 68 | }
|
| 69 | must_confirm = false;
|
| 70 | }
|
| 71 |
|
| 72 | static void print_flash_info(void)
|
| 73 | {
|
| 74 | uint32_t i;
|
| 75 | int rc;
|
| 76 |
|
| 77 | printf("Flash info:\n");
|
| 78 | printf("-----------\n");
|
| 79 | printf("Name = %s\n", fl_name);
|
| 80 | printf("Total size = %dMB \n", fl_total_size >> 20);
|
| 81 | printf("Erase granule = %dKB \n", fl_erase_granule >> 10);
|
| 82 |
|
| 83 | if (bmc_flash)
|
| 84 | return;
|
| 85 |
|
| 86 | if (!ffsh) {
|
| 87 | rc = ffs_open_flash(fl_chip, 0, 0, &ffsh);
|
| 88 | if (rc) {
|
| 89 | fprintf(stderr, "Error %d opening ffs !\n", rc);
|
| 90 | ffsh = NULL;
|
| 91 | }
|
| 92 | }
|
| 93 | if (!ffsh)
|
| 94 | return;
|
| 95 |
|
| 96 | printf("\n");
|
| 97 | printf("Partitions:\n");
|
| 98 | printf("-----------\n");
|
| 99 |
|
| 100 | for (i = 0;; i++) {
|
| 101 | uint32_t start, size, act, end;
|
| 102 | char *name;
|
| 103 |
|
| 104 | rc = ffs_part_info(ffsh, i, &name, &start, &size, &act);
|
| 105 | if (rc == FFS_ERR_PART_NOT_FOUND)
|
| 106 | break;
|
| 107 | if (rc) {
|
| 108 | fprintf(stderr, "Error %d scanning partitions\n", rc);
|
| 109 | break;
|
| 110 | }
|
| 111 | end = start + size;
|
| 112 | printf("ID=%02d %15s %08x..%08x (actual=%08x)\n",
|
| 113 | i, name, start, end, act);
|
| 114 | free(name);
|
| 115 | }
|
| 116 | }
|
| 117 |
|
| 118 | static void lookup_partition(const char *name)
|
| 119 | {
|
| 120 | uint32_t index;
|
| 121 | int rc;
|
| 122 |
|
| 123 | /* Open libffs if needed */
|
| 124 | if (!ffsh) {
|
| 125 | rc = ffs_open_flash(fl_chip, 0, 0, &ffsh);
|
| 126 | if (rc) {
|
| 127 | fprintf(stderr, "Error %d opening ffs !\n", rc);
|
| 128 | exit(1);
|
| 129 | }
|
| 130 | }
|
| 131 |
|
| 132 | /* Find partition */
|
| 133 | rc = ffs_lookup_part(ffsh, name, &index);
|
| 134 | if (rc == FFS_ERR_PART_NOT_FOUND) {
|
| 135 | fprintf(stderr, "Partition '%s' not found !\n", name);
|
| 136 | exit(1);
|
| 137 | }
|
| 138 | if (rc) {
|
| 139 | fprintf(stderr, "Error %d looking for partition '%s' !\n",
|
| 140 | rc, name);
|
| 141 | exit(1);
|
| 142 | }
|
| 143 | ffs_index = index;
|
| 144 | }
|
| 145 |
|
| 146 | static void erase_chip(void)
|
| 147 | {
|
| 148 | int rc;
|
| 149 |
|
| 150 | printf("About to erase chip !\n");
|
| 151 | check_confirm();
|
| 152 |
|
| 153 | printf("Erasing... (may take a while !) ");
|
| 154 | fflush(stdout);
|
| 155 |
|
| 156 | if (dummy_run) {
|
| 157 | printf("skipped (dummy)\n");
|
| 158 | return;
|
| 159 | }
|
| 160 |
|
| 161 | rc = flash_erase_chip(fl_chip);
|
| 162 | if (rc) {
|
| 163 | fprintf(stderr, "Error %d erasing chip\n", rc);
|
| 164 | exit(1);
|
| 165 | }
|
| 166 |
|
| 167 | printf("done !\n");
|
| 168 | }
|
| 169 |
|
| 170 | static void erase_range(uint32_t start, uint32_t size, bool will_program)
|
| 171 | {
|
| 172 | uint32_t done = 0;
|
| 173 | int rc;
|
| 174 |
|
| 175 | printf("About to erase 0x%08x..0x%08x !\n", start, start + size);
|
| 176 | check_confirm();
|
| 177 |
|
| 178 | if (dummy_run) {
|
| 179 | printf("skipped (dummy)\n");
|
| 180 | return;
|
| 181 | }
|
| 182 |
|
| 183 | printf("Erasing...\n");
|
| 184 | progress_init(size >> 8);
|
| 185 | while(size) {
|
| 186 | /* If aligned to 64k and at least 64k, use 64k erase */
|
| 187 | if ((start & 0xffff) == 0 && size >= 0x10000) {
|
| 188 | rc = flash_erase(fl_chip, start, 0x10000);
|
| 189 | if (rc) {
|
| 190 | fprintf(stderr, "Error %d erasing 0x%08x\n",
|
| 191 | rc, start);
|
| 192 | exit(1);
|
| 193 | }
|
| 194 | start += 0x10000;
|
| 195 | size -= 0x10000;
|
| 196 | done += 0x10000;
|
| 197 | } else {
|
| 198 | rc = flash_erase(fl_chip, start, 0x1000);
|
| 199 | if (rc) {
|
| 200 | fprintf(stderr, "Error %d erasing 0x%08x\n",
|
| 201 | rc, start);
|
| 202 | exit(1);
|
| 203 | }
|
| 204 | start += 0x1000;
|
| 205 | size -= 0x1000;
|
| 206 | done += 0x1000;
|
| 207 | }
|
| 208 | progress_tick(done >> 8);
|
| 209 | }
|
| 210 | progress_end();
|
| 211 |
|
| 212 | /* If this is a flash partition, mark it empty if we aren't
|
| 213 | * going to program over it as well
|
| 214 | */
|
| 215 | if (ffsh && ffs_index >= 0 && !will_program) {
|
| 216 | printf("Updating actual size in partition header...\n");
|
| 217 | ffs_update_act_size(ffsh, ffs_index, 0);
|
| 218 | }
|
| 219 | }
|
| 220 |
|
| 221 | static void program_file(const char *file, uint32_t start, uint32_t size)
|
| 222 | {
|
| 223 | int fd, rc;
|
| 224 | ssize_t len;
|
| 225 | uint32_t actual_size = 0;
|
| 226 |
|
| 227 | fd = open(file, O_RDONLY);
|
| 228 | if (fd == -1) {
|
| 229 | perror("Failed to open file");
|
| 230 | exit(1);
|
| 231 | }
|
| 232 | printf("About to program \"%s\" at 0x%08x..0x%08x !\n",
|
| 233 | file, start, size);
|
| 234 | check_confirm();
|
| 235 |
|
| 236 | if (dummy_run) {
|
| 237 | printf("skipped (dummy)\n");
|
| 238 | return;
|
| 239 | }
|
| 240 |
|
| 241 | printf("Programming & Verifying...\n");
|
| 242 | progress_init(size >> 8);
|
| 243 | while(size) {
|
| 244 | len = read(fd, file_buf, FILE_BUF_SIZE);
|
| 245 | if (len < 0) {
|
| 246 | perror("Error reading file");
|
| 247 | exit(1);
|
| 248 | }
|
| 249 | if (len == 0)
|
| 250 | break;
|
| 251 | if (len > size)
|
| 252 | len = size;
|
| 253 | size -= len;
|
| 254 | actual_size += len;
|
| 255 | rc = flash_write(fl_chip, start, file_buf, len, true);
|
| 256 | if (rc) {
|
| 257 | if (rc == FLASH_ERR_VERIFY_FAILURE)
|
| 258 | fprintf(stderr, "Verification failed for"
|
| 259 | " chunk at 0x%08x\n", start);
|
| 260 | else
|
| 261 | fprintf(stderr, "Flash write error %d for"
|
| 262 | " chunk at 0x%08x\n", rc, start);
|
| 263 | exit(1);
|
| 264 | }
|
| 265 | start += len;
|
| 266 | progress_tick(actual_size >> 8);
|
| 267 | }
|
| 268 | progress_end();
|
| 269 | close(fd);
|
| 270 |
|
| 271 | /* If this is a flash partition, adjust its size */
|
| 272 | if (ffsh && ffs_index >= 0) {
|
| 273 | printf("Updating actual size in partition header...\n");
|
| 274 | ffs_update_act_size(ffsh, ffs_index, actual_size);
|
| 275 | }
|
| 276 | }
|
| 277 |
|
| 278 | static void do_read_file(const char *file, uint32_t start, uint32_t size)
|
| 279 | {
|
| 280 | int fd, rc;
|
| 281 | ssize_t len;
|
| 282 | uint32_t done = 0;
|
| 283 |
|
| 284 | fd = open(file, O_WRONLY | O_TRUNC | O_CREAT, 00666);
|
| 285 | if (fd == -1) {
|
| 286 | perror("Failed to open file");
|
| 287 | exit(1);
|
| 288 | }
|
| 289 | printf("Reading to \"%s\" from 0x%08x..0x%08x !\n",
|
| 290 | file, start, size);
|
| 291 |
|
| 292 | progress_init(size >> 8);
|
| 293 | while(size) {
|
| 294 | len = size > FILE_BUF_SIZE ? FILE_BUF_SIZE : size;
|
| 295 | rc = flash_read(fl_chip, start, file_buf, len);
|
| 296 | if (rc) {
|
| 297 | fprintf(stderr, "Flash read error %d for"
|
| 298 | " chunk at 0x%08x\n", rc, start);
|
| 299 | exit(1);
|
| 300 | }
|
| 301 | rc = write(fd, file_buf, len);
|
| 302 | if (rc < 0) {
|
| 303 | perror("Error writing file");
|
| 304 | exit(1);
|
| 305 | }
|
| 306 | start += len;
|
| 307 | size -= len;
|
| 308 | done += len;
|
| 309 | progress_tick(done >> 8);
|
| 310 | }
|
| 311 | progress_end();
|
| 312 | close(fd);
|
| 313 | }
|
| 314 |
|
| 315 | static void enable_4B_addresses(void)
|
| 316 | {
|
| 317 | int rc;
|
| 318 |
|
| 319 | printf("Switching to 4-bytes address mode\n");
|
| 320 |
|
| 321 | rc = flash_force_4b_mode(fl_chip, true);
|
| 322 | if (rc) {
|
| 323 | fprintf(stderr, "Error %d enabling 4b mode\n", rc);
|
| 324 | exit(1);
|
| 325 | }
|
| 326 | }
|
| 327 |
|
| 328 | static void disable_4B_addresses(void)
|
| 329 | {
|
| 330 | int rc;
|
| 331 |
|
| 332 | printf("Switching to 3-bytes address mode\n");
|
| 333 |
|
| 334 | rc = flash_force_4b_mode(fl_chip, false);
|
| 335 | if (rc) {
|
| 336 | fprintf(stderr, "Error %d disabling 4b mode\n", rc);
|
| 337 | exit(1);
|
| 338 | }
|
| 339 | }
|
| 340 |
|
| 341 | static void flash_access_cleanup_bmc(void)
|
| 342 | {
|
| 343 | if (ffsh)
|
| 344 | ffs_close(ffsh);
|
| 345 | flash_exit(fl_chip);
|
| 346 | ast_sf_close(fl_ctrl);
|
| 347 | close_devs();
|
| 348 | }
|
| 349 |
|
| 350 | static void flash_access_setup_bmc(bool use_lpc, bool need_write)
|
| 351 | {
|
| 352 | int rc;
|
| 353 |
|
| 354 | /* Open and map devices */
|
| 355 | open_devs(use_lpc, true);
|
| 356 |
|
| 357 | /* Create the AST flash controller */
|
| 358 | rc = ast_sf_open(AST_SF_TYPE_BMC, &fl_ctrl);
|
| 359 | if (rc) {
|
| 360 | fprintf(stderr, "Failed to open controller\n");
|
| 361 | exit(1);
|
| 362 | }
|
| 363 |
|
| 364 | /* Open flash chip */
|
| 365 | rc = flash_init(fl_ctrl, &fl_chip);
|
| 366 | if (rc) {
|
| 367 | fprintf(stderr, "Failed to open flash chip\n");
|
| 368 | exit(1);
|
| 369 | }
|
| 370 |
|
| 371 | /* Setup cleanup function */
|
| 372 | atexit(flash_access_cleanup_bmc);
|
| 373 | }
|
| 374 |
|
| 375 | static void flash_access_cleanup_pnor(void)
|
| 376 | {
|
| 377 | /* Re-lock flash */
|
| 378 | if (need_relock)
|
| 379 | set_wrprotect(true);
|
| 380 |
|
| 381 | if (ffsh)
|
| 382 | ffs_close(ffsh);
|
| 383 | flash_exit(fl_chip);
|
| 384 | #ifdef __powerpc__
|
| 385 | if (using_sfc)
|
| 386 | sfc_close(fl_ctrl);
|
| 387 | else
|
| 388 | ast_sf_close(fl_ctrl);
|
| 389 | #else
|
| 390 | ast_sf_close(fl_ctrl);
|
| 391 | #endif
|
| 392 | close_devs();
|
| 393 | }
|
| 394 |
|
| 395 | static void flash_access_setup_pnor(bool use_lpc, bool use_sfc, bool need_write)
|
| 396 | {
|
| 397 | int rc;
|
| 398 |
|
| 399 | /* Open and map devices */
|
| 400 | open_devs(use_lpc, false);
|
| 401 |
|
| 402 | #ifdef __powerpc__
|
| 403 | if (use_sfc) {
|
| 404 | /* Create the SFC flash controller */
|
| 405 | rc = sfc_open(&fl_ctrl);
|
| 406 | if (rc) {
|
| 407 | fprintf(stderr, "Failed to open controller\n");
|
| 408 | exit(1);
|
| 409 | }
|
| 410 | using_sfc = true;
|
| 411 | } else {
|
| 412 | #endif
|
| 413 | /* Create the AST flash controller */
|
| 414 | rc = ast_sf_open(AST_SF_TYPE_PNOR, &fl_ctrl);
|
| 415 | if (rc) {
|
| 416 | fprintf(stderr, "Failed to open controller\n");
|
| 417 | exit(1);
|
| 418 | }
|
| 419 | #ifdef __powerpc__
|
| 420 | }
|
| 421 | #endif
|
| 422 |
|
| 423 | /* Open flash chip */
|
| 424 | rc = flash_init(fl_ctrl, &fl_chip);
|
| 425 | if (rc) {
|
| 426 | fprintf(stderr, "Failed to open flash chip\n");
|
| 427 | exit(1);
|
| 428 | }
|
| 429 |
|
| 430 | /* Unlock flash (PNOR only) */
|
| 431 | if (need_write)
|
| 432 | need_relock = set_wrprotect(false);
|
| 433 |
|
| 434 | /* Setup cleanup function */
|
| 435 | atexit(flash_access_cleanup_pnor);
|
| 436 | }
|
| 437 |
|
| 438 | static void print_version(void)
|
| 439 | {
|
| 440 | printf("Palmetto Flash tool " PFLASH_VERSION "\n");
|
| 441 | }
|
| 442 |
|
| 443 | static void print_help(const char *pname)
|
| 444 | {
|
| 445 | printf("Usage: %s [options] commands...\n\n", pname);
|
| 446 | printf(" Options:\n");
|
| 447 | printf("\t-a address, --address=address\n");
|
| 448 | printf("\t\tSpecify the start address for erasing, reading\n");
|
| 449 | printf("\t\tor flashing\n\n");
|
| 450 | printf("\t-s size, --size=size\n");
|
| 451 | printf("\t\tSpecify the size in bytes for erasing, reading\n");
|
| 452 | printf("\t\tor flashing\n\n");
|
| 453 | printf("\t-P part_name, --partition=part_name\n");
|
| 454 | printf("\t\tSpecify the partition whose content is to be erased\n");
|
| 455 | printf("\t\tprogrammed or read. This is an alternative to -a and -s\n");
|
| 456 | printf("\t\tif both -P and -s are specified, the smallest of the\n");
|
| 457 | printf("\t\ttwo will be used\n\n");
|
| 458 | printf("\t-f, --force\n");
|
| 459 | printf("\t\tDon't ask for confirmation before erasing or flashing\n\n");
|
| 460 | printf("\t-d, --dummy\n");
|
| 461 | printf("\t\tDon't write to flash\n\n");
|
| 462 | #ifdef __powerpc__
|
| 463 | printf("\t-l, --lpc\n");
|
| 464 | printf("\t\tUse LPC accesses instead of PCI\n\n");
|
| 465 | #endif
|
| 466 | printf("\t-b, --bmc\n");
|
| 467 | printf("\t\tTarget BMC flash instead of host flash\n\n");
|
| 468 | printf(" Commands:\n");
|
| 469 | printf("\t-4, --enable-4B\n");
|
| 470 | printf("\t\tSwitch the flash and controller to 4-bytes address\n");
|
| 471 | printf("\t\tmode (no confirmation needed).\n\n");
|
| 472 | printf("\t-3, --disable-4B\n");
|
| 473 | printf("\t\tSwitch the flash and controller to 3-bytes address\n");
|
| 474 | printf("\t\tmode (no confirmation needed).\n\n");
|
| 475 | printf("\t-r file, --read=file\n");
|
| 476 | printf("\t\tRead flash content from address into file, use -s\n");
|
| 477 | printf("\t\tto specify the size to read (or it will use the source\n");
|
| 478 | printf("\t\tfile size if used in conjunction with -p and -s is not\n");
|
| 479 | printf("\t\tspecified). When using -r together with -e or -p, the\n");
|
| 480 | printf("\t\tread will be peformed first\n\n");
|
| 481 | printf("\t-E, --erase-all\n");
|
| 482 | printf("\t\tErase entire flash chip\n");
|
| 483 | printf("\t\t(Not supported on all chips/controllers)\n\n");
|
| 484 | printf("\t-e, --erase\n");
|
| 485 | printf("\t\tErase the specified region. If size or address are not\n");
|
| 486 | printf("\t\tspecified, but \'--program\' is used, then the file\n");
|
| 487 | printf("\t\tsize will be used (rounded to an erase block) and the\n");
|
| 488 | printf("\t\taddress defaults to 0.\n\n");
|
| 489 | printf("\t-p file, --program=file\n");
|
| 490 | printf("\t\tWill program the file to flash. If the address is not\n");
|
| 491 | printf("\t\tspecified, it will use 0. If the size is not specified\n");
|
| 492 | printf("\t\tit will use the file size. Otherwise it will limit to\n");
|
| 493 | printf("\t\tthe specified size (whatever is smaller). If used in\n");
|
| 494 | printf("\t\tconjunction with any erase command, the erase will\n");
|
| 495 | printf("\t\ttake place first.\n\n");
|
| 496 | printf("\t-t, --tune\n");
|
| 497 | printf("\t\tJust tune the flash controller & access size\n");
|
| 498 | printf("\t\t(Implicit for all other operations)\n\n");
|
| 499 | printf("\t-i, --info\n");
|
| 500 | printf("\t\tDisplay some information about the flash.\n\n");
|
| 501 | printf("\t-h, --help\n");
|
| 502 | printf("\t\tThis message.\n\n");
|
| 503 | }
|
| 504 |
|
Norman James | 93304b5 | 2015-10-31 17:35:54 -0500 | [diff] [blame] | 505 | int main(int argc, char *argv[])
|
Norman James | 6a58a27 | 2015-10-07 14:34:16 -0500 | [diff] [blame] | 506 | {
|
| 507 | const char *pname = argv[0];
|
| 508 | uint32_t address = 0, read_size = 0, write_size = 0;
|
| 509 | uint32_t erase_start = 0, erase_size = 0;
|
| 510 | bool erase = false;
|
| 511 | bool program = false, erase_all = false, info = false, do_read = false;
|
| 512 | bool enable_4B = false, disable_4B = false, use_lpc = true;
|
| 513 | bool show_help = false, show_version = false;
|
| 514 | bool has_sfc = false, has_ast = false;
|
| 515 | bool no_action = false, tune = false;
|
| 516 | char *write_file = NULL, *read_file = NULL, *part_name = NULL;
|
| 517 | int rc;
|
| 518 |
|
| 519 | while(1) {
|
| 520 | static struct option long_opts[] = {
|
| 521 | {"address", required_argument, NULL, 'a'},
|
| 522 | {"size", required_argument, NULL, 's'},
|
| 523 | {"partition", required_argument, NULL, 'P'},
|
| 524 | {"lpc", no_argument, NULL, 'l'},
|
| 525 | {"bmc", no_argument, NULL, 'b'},
|
| 526 | {"enable-4B", no_argument, NULL, '4'},
|
| 527 | {"disable-4B", no_argument, NULL, '3'},
|
| 528 | {"read", required_argument, NULL, 'r'},
|
| 529 | {"erase-all", no_argument, NULL, 'E'},
|
| 530 | {"erase", no_argument, NULL, 'e'},
|
| 531 | {"program", required_argument, NULL, 'p'},
|
| 532 | {"force", no_argument, NULL, 'f'},
|
| 533 | {"info", no_argument, NULL, 'i'},
|
| 534 | {"tune", no_argument, NULL, 't'},
|
| 535 | {"dummy", no_argument, NULL, 'd'},
|
| 536 | {"help", no_argument, NULL, 'h'},
|
| 537 | {"version", no_argument, NULL, 'v'},
|
| 538 | {"debug", no_argument, NULL, 'g'},
|
| 539 | };
|
| 540 | int c, oidx = 0;
|
| 541 |
|
| 542 | c = getopt_long(argc, argv, "a:s:P:r:43Eep:fdihlvbtg",
|
| 543 | long_opts, &oidx);
|
| 544 | if (c == EOF)
|
| 545 | break;
|
| 546 | switch(c) {
|
| 547 | case 'a':
|
| 548 | address = strtoul(optarg, NULL, 0);
|
| 549 | break;
|
| 550 | case 's':
|
| 551 | read_size = write_size = strtoul(optarg, NULL, 0);
|
| 552 | break;
|
| 553 | case 'P':
|
| 554 | part_name = strdup(optarg);
|
| 555 | break;
|
| 556 | case '4':
|
| 557 | enable_4B = true;
|
| 558 | break;
|
| 559 | case '3':
|
| 560 | disable_4B = true;
|
| 561 | break;
|
| 562 | case 'r':
|
| 563 | do_read = true;
|
| 564 | read_file = strdup(optarg);
|
| 565 | break;
|
| 566 | case 'E':
|
| 567 | erase_all = erase = true;
|
| 568 | break;
|
| 569 | case 'e':
|
| 570 | erase = true;
|
| 571 | break;
|
| 572 | case 'p':
|
| 573 | program = true;
|
| 574 | write_file = strdup(optarg);
|
| 575 | break;
|
| 576 | case 'f':
|
| 577 | must_confirm = false;
|
| 578 | break;
|
| 579 | case 'd':
|
| 580 | must_confirm = false;
|
| 581 | dummy_run = true;
|
| 582 | break;
|
| 583 | case 'i':
|
| 584 | info = true;
|
| 585 | break;
|
| 586 | case 'l':
|
| 587 | use_lpc = true;
|
| 588 | break;
|
| 589 | case 'b':
|
| 590 | bmc_flash = true;
|
| 591 | break;
|
| 592 | case 't':
|
| 593 | tune = true;
|
| 594 | break;
|
| 595 | case 'v':
|
| 596 | show_version = true;
|
| 597 | break;
|
| 598 | case 'h':
|
| 599 | show_help = show_version = true;
|
| 600 | break;
|
| 601 | case 'g':
|
| 602 | libflash_debug = true;
|
| 603 | break;
|
| 604 | default:
|
| 605 | exit(1);
|
| 606 | }
|
| 607 | }
|
| 608 |
|
| 609 | /* Check if we need to access the flash at all (which will
|
| 610 | * also tune them as a side effect
|
| 611 | */
|
| 612 | no_action = !erase && !program && !info && !do_read &&
|
| 613 | !enable_4B && !disable_4B && !tune;
|
| 614 |
|
| 615 | /* Nothing to do, if we didn't already, print usage */
|
| 616 | if (no_action && !show_version)
|
| 617 | show_help = show_version = true;
|
| 618 |
|
| 619 | if (show_version)
|
| 620 | print_version();
|
| 621 | if (show_help)
|
| 622 | print_help(pname);
|
| 623 |
|
| 624 | if (no_action)
|
| 625 | return 0;
|
| 626 |
|
| 627 | /* --enable-4B and --disable-4B are mutually exclusive */
|
| 628 | if (enable_4B && disable_4B) {
|
| 629 | fprintf(stderr, "--enable-4B and --disable-4B are mutually"
|
| 630 | " exclusive !\n");
|
| 631 | exit(1);
|
| 632 | }
|
| 633 |
|
| 634 | /* 4B not supported on BMC flash */
|
| 635 | if (enable_4B && bmc_flash) {
|
| 636 | fprintf(stderr, "--enable-4B not supported on BMC flash !\n");
|
| 637 | exit(1);
|
| 638 | }
|
| 639 |
|
| 640 | /* partitions not supported on BMC flash */
|
| 641 | if (part_name && bmc_flash) {
|
| 642 | fprintf(stderr, "--partition not supported on BMC flash !\n");
|
| 643 | exit(1);
|
| 644 | }
|
| 645 |
|
| 646 | /* part-name and erase-all make no sense together */
|
| 647 | if (part_name && erase_all) {
|
| 648 | fprintf(stderr, "--partition and --erase-all are mutually"
|
| 649 | " exclusive !\n");
|
| 650 | exit(1);
|
| 651 | }
|
| 652 |
|
| 653 | /* Read command should always come with a file */
|
| 654 | if (do_read && !read_file) {
|
| 655 | fprintf(stderr, "Read with no file specified !\n");
|
| 656 | exit(1);
|
| 657 | }
|
| 658 |
|
| 659 | /* Program command should always come with a file */
|
| 660 | if (program && !write_file) {
|
| 661 | fprintf(stderr, "Program with no file specified !\n");
|
| 662 | exit(1);
|
| 663 | }
|
| 664 |
|
| 665 | /* If both partition and address specified, error out */
|
| 666 | if (address && part_name) {
|
| 667 | fprintf(stderr, "Specify partition or address, not both !\n");
|
| 668 | exit(1);
|
| 669 | }
|
| 670 |
|
| 671 | /* If file specified but not size, get size from file
|
| 672 | */
|
| 673 | if (write_file && !write_size) {
|
| 674 | struct stat stbuf;
|
| 675 |
|
| 676 | if (stat(write_file, &stbuf)) {
|
| 677 | perror("Failed to get file size");
|
| 678 | exit(1);
|
| 679 | }
|
| 680 | write_size = stbuf.st_size;
|
| 681 | }
|
| 682 |
|
| 683 | /* Check platform */
|
| 684 | check_platform(&has_sfc, &has_ast);
|
| 685 |
|
| 686 | /* Prepare for access */
|
| 687 | if (bmc_flash) {
|
| 688 | if (!has_ast) {
|
| 689 | fprintf(stderr, "No BMC on this platform\n");
|
| 690 | exit(1);
|
| 691 | }
|
| 692 | flash_access_setup_bmc(use_lpc, erase || program);
|
| 693 | } else {
|
| 694 | if (!has_ast && !has_sfc) {
|
| 695 | fprintf(stderr, "No BMC nor SFC on this platform\n");
|
| 696 | exit(1);
|
| 697 | }
|
| 698 | flash_access_setup_pnor(use_lpc, has_sfc, erase || program);
|
| 699 | }
|
| 700 |
|
| 701 | rc = flash_get_info(fl_chip, &fl_name,
|
| 702 | &fl_total_size, &fl_erase_granule);
|
| 703 | if (rc) {
|
| 704 | fprintf(stderr, "Error %d getting flash info\n", rc);
|
| 705 | exit(1);
|
| 706 | }
|
| 707 |
|
| 708 | /* If -t is passed, then print a nice message */
|
| 709 | if (tune)
|
| 710 | printf("Flash and controller tuned\n");
|
| 711 |
|
| 712 | /* If read specified and no read_size, use flash size */
|
| 713 | if (do_read && !read_size && !part_name)
|
| 714 | read_size = fl_total_size;
|
| 715 |
|
| 716 | /* We have a partition specified, grab the details */
|
| 717 | if (part_name)
|
| 718 | lookup_partition(part_name);
|
| 719 |
|
| 720 | /* We have a partition, adjust read/write size if needed */
|
| 721 | if (ffsh && ffs_index >= 0) {
|
| 722 | uint32_t pstart, pmaxsz, pactsize;
|
| 723 | int rc;
|
| 724 |
|
| 725 | rc = ffs_part_info(ffsh, ffs_index, NULL,
|
| 726 | &pstart, &pmaxsz, &pactsize);
|
| 727 | if (rc) {
|
| 728 | fprintf(stderr,"Failed to get partition info\n");
|
| 729 | exit(1);
|
| 730 | }
|
| 731 |
|
| 732 | /* Read size is obtained from partition "actual" size */
|
| 733 | if (!read_size)
|
| 734 | read_size = pactsize;
|
| 735 |
|
| 736 | /* Write size is max size of partition */
|
| 737 | if (!write_size)
|
| 738 | write_size = pmaxsz;
|
| 739 |
|
| 740 | /* Crop write size to partition size */
|
| 741 | if (write_size > pmaxsz) {
|
| 742 | printf("WARNING: Size (%d bytes) larger than partition"
|
| 743 | " (%d bytes), cropping to fit\n",
|
| 744 | write_size, pmaxsz);
|
| 745 | write_size = pmaxsz;
|
| 746 | }
|
| 747 |
|
| 748 | /* If erasing, check partition alignment */
|
| 749 | if (erase && ((pstart | pmaxsz) & 0xfff)) {
|
| 750 | fprintf(stderr,"Partition not aligned properly\n");
|
| 751 | exit(1);
|
| 752 | }
|
| 753 |
|
| 754 | /* Set address */
|
| 755 | address = pstart;
|
| 756 | }
|
| 757 |
|
| 758 | /* Align erase boundaries */
|
| 759 | if (erase && !erase_all) {
|
| 760 | uint32_t mask = 0xfff;
|
| 761 | uint32_t erase_end;
|
| 762 |
|
| 763 | /* Dummy size for erase, will be adjusted later */
|
| 764 | if (!write_size)
|
| 765 | write_size = 1;
|
| 766 | erase_start = address & ~mask;
|
| 767 | erase_end = ((address + write_size) + mask) & ~mask;
|
| 768 | erase_size = erase_end - erase_start;
|
| 769 |
|
| 770 | if (erase_start != address || erase_size != write_size)
|
| 771 | fprintf(stderr, "WARNING: Erase region adjusted"
|
| 772 | " to 0x%08x..0x%08x\n",
|
| 773 | erase_start, erase_end);
|
| 774 | }
|
| 775 |
|
| 776 | /* Process commands */
|
| 777 | if (enable_4B)
|
| 778 | enable_4B_addresses();
|
| 779 | if (disable_4B)
|
| 780 | disable_4B_addresses();
|
| 781 | if (info)
|
| 782 | print_flash_info();
|
| 783 | if (do_read)
|
| 784 | do_read_file(read_file, address, read_size);
|
| 785 | if (erase_all)
|
| 786 | erase_chip();
|
| 787 | else if (erase)
|
| 788 | erase_range(erase_start, erase_size, program);
|
| 789 | if (program)
|
| 790 | program_file(write_file, address, write_size);
|
| 791 |
|
| 792 | return 0;
|
| 793 | }
|