Beispiel #1
0
/**
 * 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;
}
Beispiel #2
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;
}
Beispiel #3
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;
}
Beispiel #4
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;
}