U-Boot从dtb获取内存布局并传递到内核

1. U-Boot获取布局内存

在DDR控制器初始化完成之后,就要确定系统中有多少可用内存,这通常是由dram_init_banksize来实现的,而不同的板级文件会实现不同的dram_init_banksize,这也就决定了不同的板级可以定义不同的获取内存布局的方法。这里介绍一种从dtb中获取内存布局的实现,这可以通过简单的调用fdtdec_setup_memory_banksize来实现。而在使能了CONFIG_OF_LIBFDT的情况下,U-Boot又会通过fdt_fixup_memory_banks来为内核dtb添加或修改memory节点,这样就可以只在U-Boot中定义memory信息,内核dtb省略memory定义,从而可以使其更加简洁通用。相信这也是后续U-Boot推荐使用的方式。

这里涉及的函数逻辑都比较简单,下面简单介绍一下。

1.1. fdtdec_setup_memory_banksize:从dtb获取内存布局

fdtdec_setup_memory_banksize的逻辑很简单,就是从dtb中解析memory节点,然后将内存的start和size填充到gd->bd->bi_dram数组。

1.2. arch_fixup_fdt:转换gd->bd->bi_dram

arch_fixup_fdt是一个处理器或板级相关的函数,默认实现为一个空的weak函数。这里以ARM的实现举例。

bi_dram本质是一个结构体数组,而fdt_fixup_memory_banks的参数是start数组和size数组,arch_fixup_fdt完成一个简单的转换。

	struct {			/* RAM configuration */
		phys_addr_t start;
		phys_size_t size;
	} bi_dram[CONFIG_NR_DRAM_BANKS];

1.3. fdt_fixup_memory_banks:修改内核dtb

fdt_fixup_memory_banks的主要逻辑如下:

  1. 找到内核dtb的memory节点,如果没有则创建一个memory节点
  2. 设置节点的属性为device_type
  3. 将所有的memory的start和size信息写到内核dtb

这里需要注意的是,如果内核dtb中已有memory节点,fdt_fixup_memory_banks只修改第一个memory节点。

2. 函数源码

U-Boot版本:v2023.04

2.1. dram_init_banksize

如下只是dram_init_banksize的一个示例,不同的板级会不同的实现。

int dram_init_banksize(void)
{
	return fdtdec_setup_memory_banksize();
}

2.2. fdtdec_setup_memory_banksize

/**
 * fdtdec_setup_memory_banksize() - decode and populate gd->bd->bi_dram
 *
 * Decode the /memory 'reg' property to determine the address and size of the
 * memory banks. Use this data to populate the global data board info with the
 * phys address and size of memory banks.
 *
 * This function should be called from a boards dram_init_banksize(). This
 * helper function allows for boards to query the device tree for memory bank
 * information instead of hard coding the information in cases where it cannot
 * be detected automatically.
 *
 * Return: 0 if OK, -EINVAL if the /memory node or reg property is missing or
 * invalid
 */

int fdtdec_setup_memory_banksize(void)
{
	int bank, ret, reg = 0;
	struct resource res;
	ofnode mem = ofnode_null();

	mem = get_next_memory_node(mem);
	if (!ofnode_valid(mem)) {
		debug("%s: Missing /memory node\n", __func__);
		return -EINVAL;
	}

	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
		ret = ofnode_read_resource(mem, reg++, &res);
		if (ret < 0) {
			reg = 0;
			mem = get_next_memory_node(mem);
			if (!ofnode_valid(mem))
				break;

			ret = ofnode_read_resource(mem, reg++, &res);
			if (ret < 0)
				break;
		}

		if (ret != 0)
			return -EINVAL;

		gd->bd->bi_dram[bank].start = (phys_addr_t)res.start;
		gd->bd->bi_dram[bank].size =
			(phys_size_t)(res.end - res.start + 1);

		debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n",
		      __func__, bank,
		      (unsigned long long)gd->bd->bi_dram[bank].start,
		      (unsigned long long)gd->bd->bi_dram[bank].size);
	}

	return 0;
}

2.3. arch_fixup_fdt

源码文件:arch/arm/lib/bootm-fdt.c

int arch_fixup_fdt(void *blob)
{
	__maybe_unused int ret = 0;
#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_OF_LIBFDT)
	struct bd_info *bd = gd->bd;
	int bank;
	u64 start[CONFIG_NR_DRAM_BANKS];
	u64 size[CONFIG_NR_DRAM_BANKS];

	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
		start[bank] = bd->bi_dram[bank].start;
		size[bank] = bd->bi_dram[bank].size;
#ifdef CONFIG_ARMV7_NONSEC
		ret = armv7_apply_memory_carveout(&start[bank], &size[bank]);
		if (ret)
			return ret;
#endif
	}

#ifdef CONFIG_OF_LIBFDT
	ret = fdt_fixup_memory_banks(blob, start, size, CONFIG_NR_DRAM_BANKS);
	if (ret)
		return ret;
#endif

#ifdef CONFIG_ARMV8_SPIN_TABLE
	ret = spin_table_update_dt(blob);
	if (ret)
		return ret;
#endif

#if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV8_PSCI) || \
	CONFIG_IS_ENABLED(SEC_FIRMWARE_ARMV8_PSCI)
	ret = psci_update_dt(blob);
	if (ret)
		return ret;
#endif
#endif

#ifdef CONFIG_FMAN_ENET
	ret = fdt_update_ethernet_dt(blob);
	if (ret)
		return ret;
#endif
	return 0;
}

2.4. fdt_fixup_memory_banks

/**
 * fdt_fixup_memory_banks - Update DT memory node
 * @blob: Pointer to DT blob
 * @start: Pointer to memory start addresses array
 * @size: Pointer to memory sizes array
 * @banks: Number of memory banks
 *
 * Return: 0 on success, negative value on failure
 *
 * Based on the passed number of banks and arrays, the function is able to
 * update existing DT memory nodes to match run time detected/changed memory
 * configuration. Implementation is handling one specific case with only one
 * memory node where multiple tuples could be added/updated.
 * The case where multiple memory nodes with a single tuple (base, size) are
 * used, this function is only updating the first memory node without removing
 * others.
 */
int fdt_fixup_memory_banks(void *blob, u64 start[], u64 size[], int banks)
{
	int err, nodeoffset;
	int len, i;
	u8 tmp[MEMORY_BANKS_MAX * 16]; /* Up to 64-bit address + 64-bit size */

	if (banks > MEMORY_BANKS_MAX) {
		printf("%s: num banks %d exceeds hardcoded limit %d."
		       " Recompile with higher MEMORY_BANKS_MAX?\n",
		       __FUNCTION__, banks, MEMORY_BANKS_MAX);
		return -1;
	}

	err = fdt_check_header(blob);
	if (err < 0) {
		printf("%s: %s\n", __FUNCTION__, fdt_strerror(err));
		return err;
	}

	/* find or create "/memory" node. */
	nodeoffset = fdt_find_or_add_subnode(blob, 0, "memory");
	if (nodeoffset < 0)
			return nodeoffset;

	err = fdt_setprop(blob, nodeoffset, "device_type", "memory",
			sizeof("memory"));
	if (err < 0) {
		printf("WARNING: could not set %s %s.\n", "device_type",
				fdt_strerror(err));
		return err;
	}

	for (i = 0; i < banks; i++) {
		if (start[i] == 0 && size[i] == 0)
			break;
	}

	banks = i;

	if (!banks)
		return 0;

	len = fdt_pack_reg(blob, tmp, start, size, banks);

	err = fdt_setprop(blob, nodeoffset, "reg", tmp, len);
	if (err < 0) {
		printf("WARNING: could not set %s %s.\n",
				"reg", fdt_strerror(err));
		return err;
	}
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值