Exemplo n.º 1
0
int board_init(void)
{
	struct fdt_memory mem_config;

	/* Record the time we spent before SPL */
	bootstage_add_record(BOOTSTAGE_ID_START_SPL, "spl_start", 0,
			     CONFIG_SPL_TIME_US);
	bootstage_mark_name(BOOTSTAGE_ID_BOARD_INIT, "board_init");

	if (fdtdec_decode_memory(gd->fdt_blob, &mem_config)) {
		debug("%s: Failed to decode memory\n", __func__);
		return -1;
	}

	gd->bd->bi_boot_params = mem_config.start + 0x100UL;

#ifdef CONFIG_OF_CONTROL
	gd->bd->bi_arch_number = fdtdec_get_config_int(gd->fdt_blob,
				"machine-arch-id", -1);
	if (gd->bd->bi_arch_number == -1U)
		debug("Warning: No /config/machine-arch-id defined in fdt\n");
#endif
#ifdef CONFIG_EXYNOS_SPI
	spi_init();
#endif

	if (board_i2c_arb_init(gd->fdt_blob))
		return -1;

	board_i2c_init(gd->fdt_blob);

#ifdef CONFIG_TPS65090_POWER
	tps65090_init();

	/*
	 * If we just reset, disable the backlight and lcd fets before
	 * [re-]initializing the lcd. This ensures we are always in the same
	 * state during lcd init. We've seen some oddities with these fets, so
	 * this removes a bit of uncertainty.
	 */
	if (board_is_processor_reset()) {
		tps65090_fet_disable(1);
		tps65090_fet_disable(6);
	}
#endif
	exynos_lcd_check_next_stage(gd->fdt_blob, 0);

	if (max77686_enable_32khz_cp()) {
		debug("%s: Failed to enable max77686 32khz coprocessor clock\n",
				 __func__);
		return -1;
	}

#if defined CONFIG_EXYNOS_CPUFREQ
	if (exynos5250_cpufreq_init(gd->fdt_blob)) {
		debug("%s: Failed to init CPU frequency scaling\n", __func__);
		return -1;
	}
#endif

#if defined CONFIG_EXYNOS_TMU
	if (tmu_init(gd->fdt_blob)) {
		debug("%s: Failed to init TMU\n", __func__);
		return -1;
	}
#endif

	/* Clock Gating all the unused IP's to save power */
	clock_gate();

	/* Disable USB3.0 PLL to save 250mW of power */
	disable_usb30_pll();

	if (board_init_mkbp_devices(gd->fdt_blob))
		return -1;

	board_configure_analogix();

	board_enable_audio_codec();

	exynos_lcd_check_next_stage(gd->fdt_blob, 0);

	bootstage_mark_name(BOOTSTAGE_ID_BOARD_INIT_DONE, "board_init_done");

	return 0;
}
static int
twostop_init(struct twostop_fmap *fmap, firmware_storage_t *file,
	     void **gbbp, size_t gbb_size, crossystem_data_t *cdata,
	     void *vb_shared_data)
{
	struct vboot_flag_details wpsw, recsw, devsw, oprom;
	GoogleBinaryBlockHeader *gbbh;
	uint8_t hardware_id[ID_LEN];
#ifndef CONFIG_HARDWARE_MAPPED_SPI
	uint8_t  readonly_firmware_id[ID_LEN];
#else
	uint8_t *readonly_firmware_id;
#endif
	int oprom_matters = 0;
	int ret = -1;
	void *gbb;

	bootstage_mark_name(BOOTSTAGE_VBOOT_TWOSTOP_INIT, "twostop_init");
	if (vboot_flag_fetch(VBOOT_FLAG_WRITE_PROTECT, &wpsw) ||
	    vboot_flag_fetch(VBOOT_FLAG_RECOVERY, &recsw) ||
	    vboot_flag_fetch(VBOOT_FLAG_DEVELOPER, &devsw) ||
	    vboot_flag_fetch(VBOOT_FLAG_OPROM_LOADED, &oprom)) {
		VBDEBUG("failed to fetch gpio\n");
		return -1;
	}
	vboot_flag_dump(VBOOT_FLAG_WRITE_PROTECT, &wpsw);
	vboot_flag_dump(VBOOT_FLAG_RECOVERY, &recsw);
	vboot_flag_dump(VBOOT_FLAG_DEVELOPER, &devsw);
	vboot_flag_dump(VBOOT_FLAG_OPROM_LOADED, &oprom);

	if (cros_fdtdec_config_has_prop(gd->fdt_blob, "oprom-matters")) {
		VBDEBUG("FDT says oprom-matters\n");
		oprom_matters = 1;
	}

	if (!fmap->readonly.fmap.length &&
	    cros_fdtdec_flashmap(gd->fdt_blob, fmap)) {
		VBDEBUG("failed to decode fmap\n");
		return -1;
	}
	dump_fmap(fmap);

	/* We revert the decision of using firmware_storage_open_twostop() */
	if (firmware_storage_open_spi(file)) {
		VBDEBUG("failed to open firmware storage\n");
		return -1;
	}

					/* Read read-only firmware ID */
	if (file->read(file, fmap->readonly.firmware_id.offset,
		       MIN(sizeof(readonly_firmware_id),
			   fmap->readonly.firmware_id.length),
		       BT_EXTRA readonly_firmware_id)) {
		VBDEBUG("failed to read firmware ID\n");
		readonly_firmware_id[0] = '\0';
	}
	VBDEBUG("read-only firmware id: \"%s\"\n", readonly_firmware_id);

					/* Load basic parts of gbb blob */
#ifdef CONFIG_HARDWARE_MAPPED_SPI
	if (gbb_init(gbbp, file, fmap->readonly.gbb.offset, gbb_size)) {
		VBDEBUG("failed to read gbb\n");
		goto out;
	}
	gbb = *gbbp;
#else
	gbb = *gbbp;
	if (gbb_init(gbb, file, fmap->readonly.gbb.offset, gbb_size)) {
		VBDEBUG("failed to read gbb\n");
		goto out;
	}
#endif

	gbbh = (GoogleBinaryBlockHeader *)gbb;
	memcpy(hardware_id, gbb + gbbh->hwid_offset,
	       MIN(sizeof(hardware_id), gbbh->hwid_size));
	VBDEBUG("hardware id: \"%s\"\n", hardware_id);

	/* Initialize crossystem data */
	/*
	 * TODO There is no readwrite EC firmware on our current ARM boards. But
	 * we should have a mechanism to probe (or acquire this information from
	 * the device tree) whether the active EC firmware is R/O or R/W.
	 */
	if (crossystem_data_init(cdata,
				 &wpsw, &recsw, &devsw, &oprom,
				 oprom_matters,
				 fmap->readonly.fmap.offset,
				 ACTIVE_EC_FIRMWARE_RO,
				 hardware_id,
				 readonly_firmware_id)) {
		VBDEBUG("failed to init crossystem data\n");
		goto out;
	}

	ret = 0;
#ifdef CONFIG_VIDEO_TEGRA
	tegra_lcd_check_next_stage(gd->fdt_blob, 0);
#endif
#ifdef CONFIG_EXYNOS_DISPLAYPORT
	exynos_lcd_check_next_stage(gd->fdt_blob, 0);
#endif

out:
	if (ret)
		file->close(file);

	return ret;
}
static uint32_t
twostop_main_firmware(struct twostop_fmap *fmap, void *gbb,
		      crossystem_data_t *cdata, void *vb_shared_data)
{
	VbError_t err;
	VbSelectAndLoadKernelParams kparams;
	VbCommonParams cparams;
	size_t size = 0;

#ifdef CONFIG_BOOTSTAGE_STASH
	bootstage_unstash((void *)CONFIG_BOOTSTAGE_STASH,
			CONFIG_BOOTSTAGE_STASH_SIZE);
#endif
	bootstage_mark_name(BOOTSTAGE_VBOOT_TWOSTOP_MAIN_FIRMWARE,
			"twostop_main_firmware");
	if (twostop_init_cparams(fmap, gbb, vb_shared_data, &cparams)) {
		VBDEBUG("failed to init cparams\n");
		return TWOSTOP_SELECT_ERROR;
	}

	/*
	 * Note that in case "kernel" is not found in the device tree, the
	 * "size" value is going to remain unchanged.
	 */
	kparams.kernel_buffer = cros_fdtdec_alloc_region(gd->fdt_blob,
		"kernel", &size);
	kparams.kernel_buffer_size = size;

	VBDEBUG("kparams:\n");
	VBDEBUG("- kernel_buffer:      : %p\n", kparams.kernel_buffer);
	VBDEBUG("- kernel_buffer_size: : %08x\n",
			kparams.kernel_buffer_size);

#ifdef CONFIG_EXYNOS_DISPLAYPORT
	/*
	 * Make sure the LCD is up before we load the kernel. Partly this
	 * is because VbSelectAndLoadKernel may do a software sync.
	 */
	exynos_lcd_check_next_stage(gd->fdt_blob, 1);
#endif

	if ((err = VbSelectAndLoadKernel(&cparams, &kparams))) {
		VBDEBUG("VbSelectAndLoadKernel: %d\n", err);
		switch (err) {
		case VBERROR_SHUTDOWN_REQUESTED:
			return TWOSTOP_SELECT_POWER_OFF;
		case VBERROR_BIOS_SHELL_REQUESTED:
			return TWOSTOP_SELECT_COMMAND_LINE;
		case VBERROR_EC_REBOOT_TO_RO_REQUIRED:
			request_ec_reboot_to_ro();
			return TWOSTOP_SELECT_POWER_OFF;
		}
		return TWOSTOP_SELECT_ERROR;
	}

	VBDEBUG("kparams:\n");
	VBDEBUG("- kernel_buffer:      : %p\n", kparams.kernel_buffer);
	VBDEBUG("- kernel_buffer_size: : %08x\n",
			kparams.kernel_buffer_size);
	VBDEBUG("- disk_handle:        : %p\n", kparams.disk_handle);
	VBDEBUG("- partition_number:   : %08x\n",
			kparams.partition_number);
	VBDEBUG("- bootloader_address: : %08llx\n",
			kparams.bootloader_address);
	VBDEBUG("- bootloader_size:    : %08x\n",
			kparams.bootloader_size);
	VBDEBUG("- partition_guid:     :");
#ifdef VBOOT_DEBUG
	int i;
	for (i = 0; i < 16; i++)
		VbExDebug(" %02x", kparams.partition_guid[i]);
	VbExDebug("\n");
#endif /* VBOOT_DEBUG */

	/* EC might jump between RO and RW during software sync. We need to
	 * update active EC copy in cdata. */
	set_active_ec_firmware(cdata);
	crossystem_data_dump(cdata);
#if defined(CONFIG_SANDBOX)
	return TWOSTOP_SELECT_COMMAND_LINE;
#else
	boot_kernel(&kparams, cdata);

	/* It is an error if boot_kenel returns */
	return TWOSTOP_SELECT_ERROR;
#endif
}
static VbError_t
twostop_init_vboot_library(firmware_storage_t *file, void *gbb,
			   uint32_t gbb_offset, size_t gbb_size,
			   crossystem_data_t *cdata, VbCommonParams *cparams)
{
	VbError_t err;
	VbInitParams iparams;
	int virtual_dev_switch =
		cros_fdtdec_config_has_prop(gd->fdt_blob,
					    "virtual-dev-switch");
#ifdef CONFIG_MKBP
	struct mkbp_dev *mdev = board_get_mkbp_dev();
#endif

	memset(&iparams, 0, sizeof(iparams));
	iparams.flags = check_ro_normal_support();

#ifdef CONFIG_MKBP
	if (mdev) {
		uint32_t ec_events = 0;
		const uint32_t kb_rec_mask =
			EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY);

		/* Read keyboard recovery flag from EC, then clear it */
		if (mkbp_get_host_events(mdev, &ec_events)) {
			/*
			 * TODO: what can we do if that fails?  Request
			 * recovery?  We don't simply want to fail, because
			 * that'll prevent us from going into recovery mode.
			 * We don't want to go into recovery mode
			 * automatically, because that'll break snow.
			 */
			VBDEBUG("VbInit: unable to read EC events\n");
			ec_events = 0;
		}
		if (ec_events & kb_rec_mask) {
			iparams.flags |= VB_INIT_FLAG_REC_BUTTON_PRESSED;
			if (mkbp_clear_host_events(mdev, kb_rec_mask))
				VBDEBUG("VbInit: unable to clear "
					"EC KB recovery event\n");
		}
	}
#endif

	if (cdata->boot_write_protect_switch)
		iparams.flags |= VB_INIT_FLAG_WP_ENABLED;
	if (cdata->boot_recovery_switch)
		iparams.flags |= VB_INIT_FLAG_REC_BUTTON_PRESSED;
	if (cdata->boot_developer_switch)
		iparams.flags |= VB_INIT_FLAG_DEV_SWITCH_ON;
	if (cdata->boot_oprom_loaded)
		iparams.flags |= VB_INIT_FLAG_OPROM_LOADED;
	if (cdata->oprom_matters)
		iparams.flags |= VB_INIT_FLAG_OPROM_MATTERS;
	if (virtual_dev_switch)
		iparams.flags |= VB_INIT_FLAG_VIRTUAL_DEV_SWITCH;
	if (cros_fdtdec_config_has_prop(gd->fdt_blob, "ec-software-sync"))
		iparams.flags |= VB_INIT_FLAG_EC_SOFTWARE_SYNC;
	if (cros_fdtdec_config_has_prop(gd->fdt_blob, "ec-slow-update"))
		iparams.flags |= VB_INIT_FLAG_EC_SLOW_UPDATE;
	if (flash_sw_wp_is_enabled(file))
		iparams.flags |= VB_INIT_FLAG_SW_WP_ENABLED;
	VBDEBUG("iparams.flags: %08x\n", iparams.flags);

	if ((err = VbInit(cparams, &iparams))) {
		VBDEBUG("VbInit: %u\n", err);

		/*
		 * If vboot wants EC to reboot to RO, make request now,
		 * because there isn't a clear path to pass this request
		 * through to do_vboot_twostop().
		 */
		if (err == VBERROR_EC_REBOOT_TO_RO_REQUIRED)
			request_ec_reboot_to_ro();

		return err;
	}

#ifdef CONFIG_VIDEO_TEGRA
	tegra_lcd_check_next_stage(gd->fdt_blob, 0);
#endif
#ifdef CONFIG_EXYNOS_DISPLAYPORT
	exynos_lcd_check_next_stage(gd->fdt_blob, 0);
#endif
	VBDEBUG("iparams.out_flags: %08x\n", iparams.out_flags);

	if (virtual_dev_switch) {
		cdata->boot_developer_switch =
			(iparams.out_flags & VB_INIT_OUT_ENABLE_DEVELOPER) ?
			1 : 0;
		VBDEBUG("cdata->boot_developer_switch=%d\n",
				cdata->boot_developer_switch);
	}

	if (iparams.out_flags & VB_INIT_OUT_CLEAR_RAM)
		wipe_unused_memory(cdata, cparams);

	/* Load required information of GBB */
	if (iparams.out_flags & VB_INIT_OUT_ENABLE_DISPLAY) {
		if (gbb_read_bmp_block(gbb, file, gbb_offset, gbb_size))
			return VBERROR_INVALID_GBB;
		have_read_gbb_bmp_block = 1;
	}
	if (cdata->boot_developer_switch ||
			iparams.out_flags & VB_INIT_OUT_ENABLE_RECOVERY) {
		if (gbb_read_recovery_key(gbb, file, gbb_offset, gbb_size))
			return VBERROR_INVALID_GBB;
	}

	return VBERROR_SUCCESS;
}