Skip to content
Snippets Groups Projects
fdtdec.c 31.2 KiB
Newer Older
/*
 * Copyright (c) 2011 The Chromium OS Authors.
 * SPDX-License-Identifier:	GPL-2.0+
#ifndef USE_HOSTCC
#include <common.h>
#include <serial.h>
#include <libfdt.h>
#include <fdtdec.h>
#include <asm/sections.h>
#include <linux/ctype.h>

DECLARE_GLOBAL_DATA_PTR;

/*
 * Here are the type we know about. One day we might allow drivers to
 * register. For now we just put them here. The COMPAT macro allows us to
 * turn this into a sparse list later, and keeps the ID with the name.
 *
 * NOTE: This list is basically a TODO list for things that need to be
 * converted to driver model. So don't add new things here unless there is a
 * good reason why driver-model conversion is infeasible. Examples include
 * things which are used before driver model is available.
 */
#define COMPAT(id, name) name
static const char * const compat_names[COMPAT_COUNT] = {
	COMPAT(UNKNOWN, "<none>"),
	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
	COMPAT(NVIDIA_TEGRA20_NAND, "nvidia,tegra20-nand"),
	COMPAT(NVIDIA_TEGRA124_PMC, "nvidia,tegra124-pmc"),
	COMPAT(NVIDIA_TEGRA186_SDMMC, "nvidia,tegra186-sdhci"),
	COMPAT(NVIDIA_TEGRA210_SDMMC, "nvidia,tegra210-sdhci"),
	COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
	COMPAT(NVIDIA_TEGRA124_XUSB_PADCTL, "nvidia,tegra124-xusb-padctl"),
	COMPAT(NVIDIA_TEGRA210_XUSB_PADCTL, "nvidia,tegra210-xusb-padctl"),
	COMPAT(SMSC_LAN9215, "smsc,lan9215"),
	COMPAT(SAMSUNG_EXYNOS5_SROMC, "samsung,exynos-sromc"),
	COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
	COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"),
	COMPAT(SAMSUNG_EXYNOS5_USB3_PHY, "samsung,exynos5250-usb3-phy"),
	COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"),
	COMPAT(SAMSUNG_EXYNOS_MIPI_DSI, "samsung,exynos-mipi-dsi"),
	COMPAT(SAMSUNG_EXYNOS_DWMMC, "samsung,exynos-dwmmc"),
	COMPAT(SAMSUNG_EXYNOS_MMC, "samsung,exynos-mmc"),
	COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"),
	COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
	COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
	COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
	COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
	COMPAT(INTEL_MICROCODE, "intel,microcode"),
	COMPAT(AMS_AS3722, "ams,as3722"),
	COMPAT(INTEL_QRK_MRC, "intel,quark-mrc"),
	COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"),
	COMPAT(ALTERA_SOCFPGA_DWMMC, "altr,socfpga-dw-mshc"),
	COMPAT(ALTERA_SOCFPGA_DWC2USB, "snps,dwc2"),
	COMPAT(INTEL_BAYTRAIL_FSP, "intel,baytrail-fsp"),
	COMPAT(INTEL_BAYTRAIL_FSP_MDP, "intel,baytrail-fsp-mdp"),
	COMPAT(INTEL_IVYBRIDGE_FSP, "intel,ivybridge-fsp"),
	COMPAT(COMPAT_SUNXI_NAND, "allwinner,sun4i-a10-nand"),
	COMPAT(ALTERA_SOCFPGA_CLK, "altr,clk-mgr"),
	COMPAT(ALTERA_SOCFPGA_PINCTRL_SINGLE, "pinctrl-single"),
	COMPAT(ALTERA_SOCFPGA_H2F_BRG, "altr,socfpga-hps2fpga-bridge"),
	COMPAT(ALTERA_SOCFPGA_LWH2F_BRG, "altr,socfpga-lwhps2fpga-bridge"),
	COMPAT(ALTERA_SOCFPGA_F2H_BRG, "altr,socfpga-fpga2hps-bridge"),
	COMPAT(ALTERA_SOCFPGA_F2SDR0, "altr,socfpga-fpga2sdram0-bridge"),
	COMPAT(ALTERA_SOCFPGA_F2SDR1, "altr,socfpga-fpga2sdram1-bridge"),
	COMPAT(ALTERA_SOCFPGA_F2SDR2, "altr,socfpga-fpga2sdram2-bridge"),
const char *fdtdec_get_compatible(enum fdt_compat_id id)
{
	/* We allow reading of the 'unknown' ID for testing purposes */
	assert(id >= 0 && id < COMPAT_COUNT);
	return compat_names[id];
}

fdt_addr_t fdtdec_get_addr_size_fixed(const void *blob, int node,
		const char *prop_name, int index, int na, int ns,
		fdt_size_t *sizep, bool translate)
	const fdt32_t *prop, *prop_end;
	const fdt32_t *prop_addr, *prop_size, *prop_after_size;
	fdt_addr_t addr;
	debug("%s: %s: ", __func__, prop_name);

	if (na > (sizeof(fdt_addr_t) / sizeof(fdt32_t))) {
		debug("(na too large for fdt_addr_t type)\n");
		return FDT_ADDR_T_NONE;
	}

	if (ns > (sizeof(fdt_size_t) / sizeof(fdt32_t))) {
		debug("(ns too large for fdt_size_t type)\n");
		return FDT_ADDR_T_NONE;
	}

	prop = fdt_getprop(blob, node, prop_name, &len);
	if (!prop) {
		debug("(not found)\n");
		return FDT_ADDR_T_NONE;
	}
	prop_end = prop + (len / sizeof(*prop));

	prop_addr = prop + (index * (na + ns));
	prop_size = prop_addr + na;
	prop_after_size = prop_size + ns;
	if (prop_after_size > prop_end) {
		debug("(not enough data: expected >= %d cells, got %d cells)\n",
		      (u32)(prop_after_size - prop), ((u32)(prop_end - prop)));
		return FDT_ADDR_T_NONE;
	}

#if CONFIG_IS_ENABLED(OF_TRANSLATE)
	if (translate)
		addr = fdt_translate_address(blob, node, prop_addr);
	else
#endif
		addr = fdtdec_get_number(prop_addr, na);

	if (sizep) {
		*sizep = fdtdec_get_number(prop_size, ns);
		debug("addr=%08llx, size=%llx\n", (unsigned long long)addr,
		      (unsigned long long)*sizep);
		debug("addr=%08llx\n", (unsigned long long)addr);
	}

	return addr;
}

fdt_addr_t fdtdec_get_addr_size_auto_parent(const void *blob, int parent,
		int node, const char *prop_name, int index, fdt_size_t *sizep,
		bool translate)
{
	int na, ns;

	debug("%s: ", __func__);

	na = fdt_address_cells(blob, parent);
	if (na < 1) {
		debug("(bad #address-cells)\n");
		return FDT_ADDR_T_NONE;
	}

	ns = fdt_size_cells(blob, parent);
		debug("(bad #size-cells)\n");
		return FDT_ADDR_T_NONE;
	}

	debug("na=%d, ns=%d, ", na, ns);

	return fdtdec_get_addr_size_fixed(blob, node, prop_name, index, na,
}

fdt_addr_t fdtdec_get_addr_size_auto_noparent(const void *blob, int node,
		const char *prop_name, int index, fdt_size_t *sizep,
		bool translate)
{
	int parent;

	debug("%s: ", __func__);

	parent = fdt_parent_offset(blob, node);
	if (parent < 0) {
		debug("(no parent found)\n");
		return FDT_ADDR_T_NONE;

	return fdtdec_get_addr_size_auto_parent(blob, parent, node, prop_name,
}

fdt_addr_t fdtdec_get_addr_size(const void *blob, int node,
		const char *prop_name, fdt_size_t *sizep)
{
	int ns = sizep ? (sizeof(fdt_size_t) / sizeof(fdt32_t)) : 0;

	return fdtdec_get_addr_size_fixed(blob, node, prop_name, 0,
					  sizeof(fdt_addr_t) / sizeof(fdt32_t),
fdt_addr_t fdtdec_get_addr(const void *blob, int node,
		const char *prop_name)
{
	return fdtdec_get_addr_size(blob, node, prop_name, NULL);
}
Loading
Loading full blame...