Skip to content
Snippets Groups Projects
fdtdec.c 33.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • int fdtdec_decode_memory_region(const void *blob, int config_node,
    				const char *mem_type, const char *suffix,
    				fdt_addr_t *basep, fdt_size_t *sizep)
    {
    	char prop_name[50];
    	const char *mem;
    	fdt_size_t size, offset_size;
    	fdt_addr_t base, offset;
    	int node;
    
    	if (config_node == -1) {
    		config_node = fdt_path_offset(blob, "/config");
    		if (config_node < 0) {
    			debug("%s: Cannot find /config node\n", __func__);
    			return -ENOENT;
    		}
    	}
    	if (!suffix)
    		suffix = "";
    
    	snprintf(prop_name, sizeof(prop_name), "%s-memory%s", mem_type,
    		 suffix);
    	mem = fdt_getprop(blob, config_node, prop_name, NULL);
    	if (!mem) {
    		debug("%s: No memory type for '%s', using /memory\n", __func__,
    		      prop_name);
    		mem = "/memory";
    	}
    
    	node = fdt_path_offset(blob, mem);
    	if (node < 0) {
    		debug("%s: Failed to find node '%s': %s\n", __func__, mem,
    		      fdt_strerror(node));
    		return -ENOENT;
    	}
    
    	/*
    	 * Not strictly correct - the memory may have multiple banks. We just
    	 * use the first
    	 */
    	if (fdtdec_decode_region(blob, node, "reg", &base, &size)) {
    		debug("%s: Failed to decode memory region %s\n", __func__,
    		      mem);
    		return -EINVAL;
    	}
    
    	snprintf(prop_name, sizeof(prop_name), "%s-offset%s", mem_type,
    		 suffix);
    	if (fdtdec_decode_region(blob, config_node, prop_name, &offset,
    				 &offset_size)) {
    		debug("%s: Failed to decode memory region '%s'\n", __func__,
    		      prop_name);
    		return -EINVAL;
    	}
    
    	*basep = base + offset;
    	*sizep = offset_size;
    
    	return 0;
    }
    
    static int decode_timing_property(const void *blob, int node, const char *name,
    				  struct timing_entry *result)
    {
    	int length, ret = 0;
    	const u32 *prop;
    
    	prop = fdt_getprop(blob, node, name, &length);
    	if (!prop) {
    		debug("%s: could not find property %s\n",
    		      fdt_get_name(blob, node, NULL), name);
    		return length;
    	}
    
    	if (length == sizeof(u32)) {
    		result->typ = fdtdec_get_int(blob, node, name, 0);
    		result->min = result->typ;
    		result->max = result->typ;
    	} else {
    		ret = fdtdec_get_int_array(blob, node, name, &result->min, 3);
    	}
    
    	return ret;
    }
    
    int fdtdec_decode_display_timing(const void *blob, int parent, int index,
    				 struct display_timing *dt)
    {
    	int i, node, timings_node;
    	u32 val = 0;
    	int ret = 0;
    
    	timings_node = fdt_subnode_offset(blob, parent, "display-timings");
    	if (timings_node < 0)
    		return timings_node;
    
    	for (i = 0, node = fdt_first_subnode(blob, timings_node);
    	     node > 0 && i != index;
    	     node = fdt_next_subnode(blob, node))
    		i++;
    
    	if (node < 0)
    		return node;
    
    	memset(dt, 0, sizeof(*dt));
    
    	ret |= decode_timing_property(blob, node, "hback-porch",
    				      &dt->hback_porch);
    	ret |= decode_timing_property(blob, node, "hfront-porch",
    				      &dt->hfront_porch);
    	ret |= decode_timing_property(blob, node, "hactive", &dt->hactive);
    	ret |= decode_timing_property(blob, node, "hsync-len", &dt->hsync_len);
    	ret |= decode_timing_property(blob, node, "vback-porch",
    				      &dt->vback_porch);
    	ret |= decode_timing_property(blob, node, "vfront-porch",
    				      &dt->vfront_porch);
    	ret |= decode_timing_property(blob, node, "vactive", &dt->vactive);
    	ret |= decode_timing_property(blob, node, "vsync-len", &dt->vsync_len);
    	ret |= decode_timing_property(blob, node, "clock-frequency",
    				      &dt->pixelclock);
    
    	dt->flags = 0;
    	val = fdtdec_get_int(blob, node, "vsync-active", -1);
    	if (val != -1) {
    		dt->flags |= val ? DISPLAY_FLAGS_VSYNC_HIGH :
    				DISPLAY_FLAGS_VSYNC_LOW;
    	}
    	val = fdtdec_get_int(blob, node, "hsync-active", -1);
    	if (val != -1) {
    		dt->flags |= val ? DISPLAY_FLAGS_HSYNC_HIGH :
    				DISPLAY_FLAGS_HSYNC_LOW;
    	}
    	val = fdtdec_get_int(blob, node, "de-active", -1);
    	if (val != -1) {
    		dt->flags |= val ? DISPLAY_FLAGS_DE_HIGH :
    				DISPLAY_FLAGS_DE_LOW;
    	}
    	val = fdtdec_get_int(blob, node, "pixelclk-active", -1);
    	if (val != -1) {
    		dt->flags |= val ? DISPLAY_FLAGS_PIXDATA_POSEDGE :
    				DISPLAY_FLAGS_PIXDATA_NEGEDGE;
    	}
    
    	if (fdtdec_get_bool(blob, node, "interlaced"))
    		dt->flags |= DISPLAY_FLAGS_INTERLACED;
    	if (fdtdec_get_bool(blob, node, "doublescan"))
    		dt->flags |= DISPLAY_FLAGS_DOUBLESCAN;
    	if (fdtdec_get_bool(blob, node, "doubleclk"))
    		dt->flags |= DISPLAY_FLAGS_DOUBLECLK;
    
    
    int fdtdec_setup_memory_size(void)
    {
    	int ret, mem;
    	struct fdt_resource res;
    
    	mem = fdt_path_offset(gd->fdt_blob, "/memory");
    	if (mem < 0) {
    		debug("%s: Missing /memory node\n", __func__);
    		return -EINVAL;
    	}
    
    	ret = fdt_get_resource(gd->fdt_blob, mem, "reg", 0, &res);
    	if (ret != 0) {
    		debug("%s: Unable to decode first memory bank\n", __func__);
    		return -EINVAL;
    	}
    
    	gd->ram_size = (phys_size_t)(res.end - res.start + 1);
    
    	debug("%s: Initial DRAM size %llx\n", __func__,
    	      (unsigned long long)gd->ram_size);
    
    
    	return 0;
    }
    
    #if defined(CONFIG_NR_DRAM_BANKS)
    int fdtdec_setup_memory_banksize(void)
    {
    
    	int bank, ret, mem, reg = 0;
    
    	mem = fdt_node_offset_by_prop_value(gd->fdt_blob, -1, "device_type",
    					    "memory", 7);
    
    	if (mem < 0) {
    		debug("%s: Missing /memory node\n", __func__);
    		return -EINVAL;
    	}
    
    	for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) {
    
    		ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
    		if (ret == -FDT_ERR_NOTFOUND) {
    			reg = 0;
    			mem = fdt_node_offset_by_prop_value(gd->fdt_blob, mem,
    							    "device_type",
    							    "memory", 7);
    			if (mem == -FDT_ERR_NOTFOUND)
    				break;
    
    			ret = fdt_get_resource(gd->fdt_blob, mem, "reg", reg++, &res);
    			if (ret == -FDT_ERR_NOTFOUND)
    				break;
    		}
    		if (ret != 0) {
    
    
    		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;
    }
    #endif
    
    
    #if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
    # if CONFIG_IS_ENABLED(MULTI_DTB_FIT_GZIP) ||\
    	CONFIG_IS_ENABLED(MULTI_DTB_FIT_LZO)
    static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
    {
    	size_t sz_out = CONFIG_SPL_MULTI_DTB_FIT_UNCOMPRESS_SZ;
    	ulong sz_in = sz_src;
    	void *dst;
    	int rc;
    
    	if (CONFIG_IS_ENABLED(GZIP))
    		if (gzip_parse_header(src, sz_in) < 0)
    			return -1;
    	if (CONFIG_IS_ENABLED(LZO))
    		if (!lzop_is_valid_header(src))
    			return -EBADMSG;
    
    	if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC)) {
    		dst = malloc(sz_out);
    		if (!dst) {
    			puts("uncompress_blob: Unable to allocate memory\n");
    			return -ENOMEM;
    		}
    	} else  {
    #  if CONFIG_IS_ENABLED(MULTI_DTB_FIT_USER_DEFINED_AREA)
    		dst = (void *)CONFIG_VAL(MULTI_DTB_FIT_USER_DEF_ADDR);
    #  else
    		return -ENOTSUPP;
    #  endif
    	}
    
    	if (CONFIG_IS_ENABLED(GZIP))
    		rc = gunzip(dst, sz_out, (u8 *)src, &sz_in);
    	else if (CONFIG_IS_ENABLED(LZO))
    		rc = lzop_decompress(src, sz_in, dst, &sz_out);
    
    	if (rc < 0) {
    		/* not a valid compressed blob */
    		puts("uncompress_blob: Unable to uncompress\n");
    		if (CONFIG_IS_ENABLED(MULTI_DTB_FIT_DYN_ALLOC))
    			free(dst);
    		return -EBADMSG;
    	}
    	*dstp = dst;
    	return 0;
    }
    # else
    static int uncompress_blob(const void *src, ulong sz_src, void **dstp)
    {
    	return -ENOTSUPP;
    }
    # endif
    #endif
    
    
    #if defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
    /*
     * For CONFIG_OF_SEPARATE, the board may optionally implement this to
     * provide and/or fixup the fdt.
     */
    __weak void *board_fdt_blob_setup(void)
    {
    	void *fdt_blob = NULL;
    #ifdef CONFIG_SPL_BUILD
    	/* FDT is at end of BSS unless it is in a different memory region */
    	if (IS_ENABLED(CONFIG_SPL_SEPARATE_BSS))
    		fdt_blob = (ulong *)&_image_binary_end;
    	else
    		fdt_blob = (ulong *)&__bss_end;
    #else
    	/* FDT is at end of image */
    	fdt_blob = (ulong *)&_end;
    #endif
    	return fdt_blob;
    }
    #endif
    
    
    int fdtdec_setup(void)
    
    #if CONFIG_IS_ENABLED(OF_CONTROL)
    
    # if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
    	void *fdt_blob;
    # endif
    
    # ifdef CONFIG_OF_EMBED
    	/* Get a pointer to the FDT */
    
    #  ifdef CONFIG_SPL_BUILD
    	gd->fdt_blob = __dtb_dt_spl_begin;
    #  else
    
    	gd->fdt_blob = __dtb_dt_begin;
    
    # elif defined(CONFIG_OF_BOARD) || defined(CONFIG_OF_SEPARATE)
    
    	/* Allow the board to override the fdt address. */
    	gd->fdt_blob = board_fdt_blob_setup();
    
    # elif defined(CONFIG_OF_HOSTFILE)
    	if (sandbox_read_fdt_from_file()) {
    		puts("Failed to read control FDT\n");
    		return -1;
    	}
    # endif
    # ifndef CONFIG_SPL_BUILD
    	/* Allow the early environment to override the fdt address */
    
    	gd->fdt_blob = (void *)env_get_ulong("fdtcontroladdr", 16,
    
    						(uintptr_t)gd->fdt_blob);
    # endif
    
    
    # if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
    	/*
    	 * Try and uncompress the blob.
    	 * Unfortunately there is no way to know how big the input blob really
    	 * is. So let us set the maximum input size arbitrarily high. 16MB
    	 * ought to be more than enough for packed DTBs.
    	 */
    	if (uncompress_blob(gd->fdt_blob, 0x1000000, &fdt_blob) == 0)
    		gd->fdt_blob = fdt_blob;
    
    	/*
    	 * Check if blob is a FIT images containings DTBs.
    	 * If so, pick the most relevant
    	 */
    	fdt_blob = locate_dtb_in_fit(gd->fdt_blob);
    	if (fdt_blob)
    		gd->fdt_blob = fdt_blob;
    # endif
    
    	return fdtdec_prepare_fdt();