/** * Try to register an environment storage on the attached MCI card * @return 0 on success * * We rely on the existence of a usable SD card, already attached to * our system, to get something like a persistent memory for our environment. * If this SD card is also the boot media, we can use the second partition * for our environment purpose (if present!). */ static int register_persistant_environment(void) { struct cdev *cdev; /* * The imx23-olinuxino only has one MCI card socket. * So, we expect its name as "disk0". */ cdev = cdev_by_name("disk0"); if (cdev == NULL) { pr_err("No MCI card preset\n"); return -ENODEV; } /* MCI card is present, also a useable partition on it? */ cdev = cdev_by_name("disk0.1"); if (cdev == NULL) { pr_err("No second partition available\n"); pr_info("Please create at least a second partition with" " 256 kiB...512 kiB in size (your choice)\n"); return -ENODEV; } /* use the full partition as our persistent environment storage */ cdev = devfs_add_partition("disk0.1", 0, cdev->size, DEVFS_PARTITION_FIXED, "env0"); if (IS_ERR(cdev)) return PTR_ERR(cdev); return 0; }
static int at91sam9263ek_devices_init(void) { /* * PB27 enables the 50MHz oscillator for Ethernet PHY * 1 - enable * 0 - disable */ at91_set_gpio_output(AT91_PIN_PB27, 1); at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ ek_add_device_nand(); at91_add_device_eth(0, &macb_pdata); add_cfi_flash_device(0, AT91_CHIPSELECT_0, 8 * 1024 * 1024, 0); ek_add_device_mci(); ek_device_add_leds(); ek_add_device_udc(); ek_add_device_buttons(); if (IS_ENABLED(CONFIG_DRIVER_CFI) && cdev_by_name("nor0")) { devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self"); devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); } else if (IS_ENABLED(CONFIG_NAND_ATMEL)) { devfs_add_partition("nand0", 0x00000, SZ_128K, PARTITION_FIXED, "at91bootstrap_raw"); dev_add_bb_dev("at91bootstrap_raw", "at91bootstrap"); devfs_add_partition("nand0", SZ_128K, SZ_256K, PARTITION_FIXED, "self_raw"); dev_add_bb_dev("self_raw", "self0"); devfs_add_partition("nand0", SZ_256K + SZ_128K, SZ_128K, PARTITION_FIXED, "env_raw"); dev_add_bb_dev("env_raw", "env0"); devfs_add_partition("nand0", SZ_512K, SZ_128K, PARTITION_FIXED, "env_raw1"); dev_add_bb_dev("env_raw1", "env1"); } armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); armlinux_set_architecture(MACH_TYPE_AT91SAM9263EK); return 0; }
static int do_nand(struct command *cmdtp, int argc, char *argv[]) { int opt; struct nand_bb *bb; int command = 0, badblock = 0; while((opt = getopt(argc, argv, "adb:")) > 0) { if (command) { printf("only one command may be given\n"); return 1; } switch (opt) { case 'a': command = NAND_ADD; break; case 'd': command = NAND_DEL; break; case 'b': command = NAND_MARKBAD; badblock = simple_strtoul(optarg, NULL, 0); } } if (command & NAND_ADD) { while (optind < argc) { if (dev_add_bb_dev(argv[optind], NULL)) return 1; optind++; } } if (command & NAND_DEL) { while (optind < argc) { struct cdev *cdev; cdev = cdev_by_name(basename(argv[optind])); if (!cdev) { printf("no such device: %s\n", argv[optind]); return 1; } bb = cdev->priv; close(bb->fd); devfs_remove(cdev); free(bb); optind++; } } if (command & NAND_MARKBAD) { if (optind < argc) { int ret = 0, fd; printf("marking block at 0x%08x on %s as bad\n", badblock, argv[optind]); fd = open(argv[optind], O_RDWR); if (fd < 0) { perror("open"); return 1; } ret = ioctl(fd, MEMSETBADBLOCK, (void *)badblock); if (ret) perror("ioctl"); close(fd); return ret; } } return 0; }
static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *data) { struct imx_nand_fcb_bbu_handler *imx_handler = container_of(handler, struct imx_nand_fcb_bbu_handler, handler); struct cdev *bcb_cdev; struct mtd_info *mtd; int ret, i; struct fcb_block *fcb = NULL; void *fw = NULL, *fw_orig = NULL; unsigned fw_size, partition_size; enum filetype filetype; unsigned num_blocks_fw; int pages_per_block; int used = 0; int fw_orig_len; int used_refresh = 0, unused_refresh = 0; if (data->image) { filetype = file_detect_type(data->image, data->len); if (filetype != imx_handler->filetype && !bbu_force(data, "Image is not of type %s but of type %s", file_type_to_string(imx_handler->filetype), file_type_to_string(filetype))) return -EINVAL; } bcb_cdev = cdev_by_name(handler->devicefile); if (!bcb_cdev) { pr_err("%s: No FCB device!\n", __func__); return -ENODEV; } mtd = bcb_cdev->mtd; partition_size = mtd->size; pages_per_block = mtd->erasesize / mtd->writesize; for (i = 0; i < 4; i++) { read_fcb(mtd, i, &fcb); if (fcb) break; } /* * This code uses the following layout in the Nand flash: * * fwmaxsize = (n_blocks - 4) / 2 * * block * * 0 ---------------------- * | FCB/DBBT 0 | * 1 ---------------------- * | FCB/DBBT 1 | * 2 ---------------------- * | FCB/DBBT 2 | * 3 ---------------------- * | FCB/DBBT 3 | * 4 ---------------------- * | Firmware slot 0 | * 4 + fwmaxsize ---------------------- * | Firmware slot 1 | * ---------------------- * * We want a robust update in which a power failure may occur * everytime without bricking the board, so here's the strategy: * * The FCBs contain pointers to the firmware slots in the * Firmware1_startingPage and Firmware2_startingPage fields. Note that * Firmware1_startingPage doesn't necessarily point to slot 0. We * exchange the pointers during update to atomically switch between the * old and the new firmware. * * - We read the first valid FCB and the firmware slots. * - We check which firmware slot is currently used by the ROM: * - if no FCB is found or its layout differs from the above layout, * continue without robust update * - if only one firmware slot is readable, the ROM uses it * - if both slots are readable, the ROM will use slot 0 * - Step 1: erase/update the slot currently unused by the ROM * - Step 2: Update FCBs/DBBTs, thereby letting Firmware1_startingPage * point to the slot we just updated. From this moment * on the new firmware will be used and running a * refresh/repair after a power failure after this * step will complete the update. * - Step 3: erase/update the other firmwre slot * - Step 4: Eventually write FCBs/DBBTs again. This may become * necessary when step 3 revealed new bad blocks. * * This robust update only works when the original FCBs on the device * uses the same layout as this code does. In other cases update will * also work, but it won't be robust against power failures. * * Refreshing the firmware which is needed when blocks become unreadable * due to read disturbance works the same way, only that the new firmware * is the same as the old firmware and that it will only be written when * reading from the device returns -EUCLEAN indicating that a block needs * to be rewritten. */ if (fcb) read_firmware_all(mtd, fcb, &fw_orig, &fw_orig_len, &used_refresh, &unused_refresh, &used); if (data->image) { /* * We have to write one additional page to make the ROM happy. * Maybe the PagesInFirmwarex fields are really the number of pages - 1. * kobs-ng has the same. */ fw_size = ALIGN(data->len + mtd->writesize, mtd->writesize); fw = xzalloc(fw_size); memcpy(fw, data->image, data->len); free(fw_orig); used_refresh = 1; unused_refresh = 1; free(fcb); fcb = xzalloc(sizeof(*fcb)); fcb->Firmware1_startingPage = imx_bbu_firmware_start_block(mtd, !used) * pages_per_block; fcb->Firmware2_startingPage = imx_bbu_firmware_start_block(mtd, used) * pages_per_block; fcb->PagesInFirmware1 = fw_size / mtd->writesize; fcb->PagesInFirmware2 = fcb->PagesInFirmware1; fcb_create(imx_handler, fcb, mtd); } else { if (!fcb) { pr_err("No FCB found on device, cannot refresh\n"); ret = -EINVAL; goto out; } if (!fw_orig) { pr_err("No firmware found on device, cannot refresh\n"); ret = -EINVAL; goto out; } fw = fw_orig; fw_size = fw_orig_len; pr_info("Refreshing existing firmware\n"); } num_blocks_fw = imx_bbu_firmware_max_blocks(mtd); if (num_blocks_fw * mtd->erasesize < fw_size) { pr_err("Not enough space for update\n"); return -ENOSPC; } ret = bbu_confirm(data); if (ret) goto out; /* Step 1: write firmware which is currently unused by the ROM */ if (unused_refresh) { pr_info("%sing slot %d\n", data->image ? "updat" : "refresh", !used); ret = imx_bbu_write_firmware(mtd, !used, fw, fw_size); if (ret < 0) goto out; } else { pr_info("firmware slot %d still ok, nothing to do\n", !used); } /* * Step 2: Write FCBs/DBBTs. This will use the firmware we have * just written as primary firmware. From now on the new * firmware will be booted. */ ret = imx_bbu_write_fcbs_dbbts(mtd, fcb); if (ret < 0) goto out; /* Step 3: Write the secondary firmware */ if (used_refresh) { pr_info("%sing slot %d\n", data->image ? "updat" : "refresh", used); ret = imx_bbu_write_firmware(mtd, used, fw, fw_size); if (ret < 0) goto out; } else { pr_info("firmware slot %d still ok, nothing to do\n", used); } /* * Step 4: If writing the secondary firmware discovered new bad * blocks, write the FCBs/DBBTs again with updated bad block * information. */ if (ret > 0) { pr_info("New bad blocks detected, writing FCBs/DBBTs again\n"); ret = imx_bbu_write_fcbs_dbbts(mtd, fcb); if (ret < 0) goto out; } out: free(fw); free(fcb); return ret; }