diff options
| -rw-r--r-- | include/fdt.h | 60 | ||||
| -rw-r--r-- | include/libfdt.h | 135 | ||||
| -rw-r--r-- | include/libfdt_env.h | 22 | ||||
| -rw-r--r-- | libfdt/Makefile | 88 | ||||
| -rw-r--r-- | libfdt/README | 23 | ||||
| -rw-r--r-- | libfdt/fdt.c | 124 | ||||
| -rw-r--r-- | libfdt/fdt_strerror.c | 64 | ||||
| -rw-r--r-- | libfdt/libfdt_internal.h | 41 | 
8 files changed, 557 insertions, 0 deletions
| diff --git a/include/fdt.h b/include/fdt.h new file mode 100644 index 000000000..e00559ad6 --- /dev/null +++ b/include/fdt.h @@ -0,0 +1,60 @@ +#ifndef _FDT_H +#define _FDT_H + +#ifndef __ASSEMBLY__ + +struct fdt_header { +	uint32_t magic;                  /* magic word FDT_MAGIC */ +	uint32_t totalsize;              /* total size of DT block */ +	uint32_t off_dt_struct;          /* offset to structure */ +	uint32_t off_dt_strings;         /* offset to strings */ +	uint32_t off_mem_rsvmap;         /* offset to memory reserve map */ +	uint32_t version;                /* format version */ +	uint32_t last_comp_version;      /* last compatible version */ + +        /* version 2 fields below */ +	uint32_t boot_cpuid_phys;        /* Which physical CPU id we're +					    booting on */ +	/* version 3 fields below */ +        uint32_t size_dt_strings;        /* size of the strings block */ + +	/* version 17 fields below */ +	uint32_t size_dt_struct;         /* size of the structure block */ +}; + +struct fdt_reserve_entry { +	uint64_t address; +	uint64_t size; +}; + +struct fdt_node_header { +	uint32_t tag; +	char name[0]; +}; + +struct fdt_property { +	uint32_t tag; +	uint32_t len; +	uint32_t nameoff; +	char data[0]; +}; + +#endif /* !__ASSEMBLY */ + +#define FDT_MAGIC	0xd00dfeed      /* 4: version, 4: total size */ +#define FDT_TAGSIZE	sizeof(uint32_t) + +#define FDT_BEGIN_NODE	0x1             /* Start node: full name */ +#define FDT_END_NODE	0x2             /* End node */ +#define FDT_PROP	0x3             /* Property: name off, +					   size, content */ +#define FDT_NOP		0x4		/* nop */ +#define FDT_END		0x9 + +#define FDT_V1_SIZE	(7*sizeof(uint32_t)) +#define FDT_V2_SIZE	(FDT_V1_SIZE + sizeof(uint32_t)) +#define FDT_V3_SIZE	(FDT_V2_SIZE + sizeof(uint32_t)) +#define FDT_V16_SIZE	FDT_V3_SIZE +#define FDT_V17_SIZE	(FDT_V16_SIZE + sizeof(uint32_t)) + +#endif /* _FDT_H */ diff --git a/include/libfdt.h b/include/libfdt.h new file mode 100644 index 000000000..acdc72eac --- /dev/null +++ b/include/libfdt.h @@ -0,0 +1,135 @@ +#ifndef _LIBFDT_H +#define _LIBFDT_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <fdt.h> +#include <libfdt_env.h> + +#define FDT_FIRST_SUPPORTED_VERSION	0x10 +#define FDT_LAST_SUPPORTED_VERSION	0x11 + +/* Error codes: informative error codes */ +#define FDT_ERR_NOTFOUND	1 +#define FDT_ERR_EXISTS		2 +#define FDT_ERR_NOSPACE		3 + +/* Error codes: codes for bad parameters */ +#define FDT_ERR_BADOFFSET	4 +#define FDT_ERR_BADPATH		5 +#define FDT_ERR_BADSTATE	6 + +/* Error codes: codes for bad device tree blobs */ +#define FDT_ERR_TRUNCATED	7 +#define FDT_ERR_BADMAGIC	8 +#define FDT_ERR_BADVERSION	9 +#define FDT_ERR_BADSTRUCTURE	10 +#define FDT_ERR_BADLAYOUT	11 + +#define FDT_ERR_MAX		11 + +#define fdt_get_header(fdt, field) \ +	(fdt32_to_cpu(((struct fdt_header *)(fdt))->field)) +#define fdt_magic(fdt) 			(fdt_get_header(fdt, magic)) +#define fdt_totalsize(fdt)		(fdt_get_header(fdt, totalsize)) +#define fdt_off_dt_struct(fdt)		(fdt_get_header(fdt, off_dt_struct)) +#define fdt_off_dt_strings(fdt)		(fdt_get_header(fdt, off_dt_strings)) +#define fdt_off_mem_rsvmap(fdt)		(fdt_get_header(fdt, off_mem_rsvmap)) +#define fdt_version(fdt)		(fdt_get_header(fdt, version)) +#define fdt_last_comp_version(fdt) 	(fdt_get_header(fdt, last_comp_version)) +#define fdt_boot_cpuid_phys(fdt) 	(fdt_get_header(fdt, boot_cpuid_phys)) +#define fdt_size_dt_strings(fdt) 	(fdt_get_header(fdt, size_dt_strings)) +#define fdt_size_dt_struct(fdt)		(fdt_get_header(fdt, size_dt_struct)) + +#define fdt_set_header(fdt, field, val) \ +	((struct fdt_header *)(fdt))->field = cpu_to_fdt32(val) + +void *fdt_offset_ptr(const void *fdt, int offset, int checklen); + +#define fdt_offset_ptr_typed(fdt, offset, var) \ +	((typeof(var))(fdt_offset_ptr((fdt), (offset), sizeof(*(var))))) + +int fdt_move(const void *fdt, void *buf, int bufsize); + +/* Read-only functions */ +char *fdt_string(const void *fdt, int stroffset); + +int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, +			       const char *name, int namelen); +int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); + +int fdt_path_offset(const void *fdt, const char *path); + +struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, +				      const char *name, int *lenp); +void *fdt_getprop(const void *fdt, int nodeoffset, +		  const char *name, int *lenp); + +/* Write-in-place functions */ +int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, +			const void *val, int len); + +#define fdt_setprop_inplace_typed(fdt, nodeoffset, name, val) \ +	({ \ +		typeof(val) x = val; \ +		fdt_setprop_inplace(fdt, nodeoffset, name, &x, sizeof(x)); \ +	}) + +int fdt_nop_property(void *fdt, int nodeoffset, const char *name); +int fdt_nop_node(void *fdt, int nodeoffset); + +/* Sequential-write functions */ +int fdt_create(void *buf, int bufsize); +int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); +int fdt_finish_reservemap(void *fdt); +int fdt_begin_node(void *fdt, const char *name); +int fdt_property(void *fdt, const char *name, const void *val, int len); +#define fdt_property_typed(fdt, name, val) \ +	({ \ +		typeof(val) x = (val); \ +		fdt_property((fdt), (name), &x, sizeof(x)); \ +	}) +#define fdt_property_string(fdt, name, str) \ +	fdt_property(fdt, name, str, strlen(str)+1) +int fdt_end_node(void *fdt); +int fdt_finish(void *fdt); + +/* Read-write functions */ +int fdt_open_into(void *fdt, void *buf, int bufsize); +int fdt_pack(void *fdt); + +int fdt_setprop(void *fdt, int nodeoffset, const char *name, +		const void *val, int len); +#define fdt_setprop_typed(fdt, nodeoffset, name, val) \ +	({ \ +		typeof(val) x = (val); \ +		fdt_setprop((fdt), (nodeoffset), (name), &x, sizeof(x)); \ +	}) +#define fdt_setprop_string(fdt, nodeoffset, name, str) \ +	fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) +int fdt_delprop(void *fdt, int nodeoffset, const char *name); +int fdt_add_subnode_namelen(void *fdt, int parentoffset, +			    const char *name, int namelen); +int fdt_add_subnode(void *fdt, int parentoffset, const char *name); +int fdt_del_node(void *fdt, int nodeoffset); + +/* Extra functions */ +const char *fdt_strerror(int errval); + +#endif /* _LIBFDT_H */ diff --git a/include/libfdt_env.h b/include/libfdt_env.h new file mode 100644 index 000000000..59f2536d2 --- /dev/null +++ b/include/libfdt_env.h @@ -0,0 +1,22 @@ +#ifndef _LIBFDT_ENV_H +#define _LIBFDT_ENV_H + +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#include <endian.h> +#include <byteswap.h> + +#if __BYTE_ORDER == __BIG_ENDIAN +#define fdt32_to_cpu(x)		(x) +#define cpu_to_fdt32(x)		(x) +#define fdt64_to_cpu(x)		(x) +#define cpu_to_fdt64(x)		(x) +#else +#define fdt32_to_cpu(x)		(bswap_32((x))) +#define cpu_to_fdt32(x)		(bswap_32((x))) +#define fdt64_to_cpu(x)		(bswap_64((x))) +#define cpu_to_fdt64(x)		(bswap_64((x))) +#endif + +#endif /* _LIBFDT_ENV_H */ diff --git a/libfdt/Makefile b/libfdt/Makefile new file mode 100644 index 000000000..c8240bba3 --- /dev/null +++ b/libfdt/Makefile @@ -0,0 +1,88 @@ +PREFIX = /usr/local +TARGETLIBS = libfdt.a +LIBOBJS = fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o fdt_strerror.o + +SOURCE = $(shell find . -maxdepth 1 ! -name version.h -a -name '*.[h]') +SOURCE += *.c Makefile +NODEPTARGETS=<clean> + +CPPFLAGS = -I. +CFLAGS = -Wall -g + +LIBDIR = $(PREFIX)/$(LIB32) + +EXTRA_DIST = \ +	README \ +	HOWTO \ +	LGPL-2.1 + +ifdef V +VECHO = : +else +VECHO = echo "	" +ARFLAGS = rc +.SILENT: +endif + +DEPFILES = $(LIBOBJS:%.o=%.d) + +all:	libs tests + +.PHONY:	tests libs + +libs:	$(TARGETLIBS) + +tests:	tests/all + +tests/%: libs +	$(MAKE) -C tests $* + +check:	all +	cd tests; ./run_tests.sh + +checkv:	all +	cd tests; ./run_tests.sh -v + +func:	all +	cd tests; ./run_tests.sh -t func + +funcv:	all +	cd tests; ./run_tests.sh -t func -v + +stress:	all +	cd tests; ./run_tests.sh -t stress + +stressv: all +	cd tests; ./run_tests.sh -t stress -v + +%.o: %.c +	@$(VECHO) CC $@ +	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $< + +libfdt.a: $(LIBOBJS) +	@$(VECHO) AR $@ +	$(AR) $(ARFLAGS) $@ $^ + +%.i:	%.c +	@$(VECHO) CPP $@ +	$(CC) $(CPPFLAGS) -E $< > $@ + +%.s:	%.c +	@$(VECHO) CC -S $@ +	$(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -S $< + +clean: +	@$(VECHO) CLEAN +	rm -f *~ *.o *.so *.a *.d *.i *.s core a.out $(VERSION) +	$(MAKE) -C tests clean + +%.d: %.c +	@$(CC) $(CPPFLAGS) -MM -MT "$*.o $@" $< > $@ + +# Workaround: Don't build dependencies for certain targets +#    When the include below is executed, make will use the %.d target above to +# generate missing files.  For certain targets (clean, version.h, etc) we don't +# need or want these dependency files, so don't include them in this case. +ifeq (,$(findstring <$(MAKECMDGOALS)>,$(NODEPTARGETS))) +-include $(DEPFILES) +endif diff --git a/libfdt/README b/libfdt/README new file mode 100644 index 000000000..f4cca3499 --- /dev/null +++ b/libfdt/README @@ -0,0 +1,23 @@ +The libfdt functionality was written by David Gibson.  The original +source came from the git repository: + +URL: 		git://ozlabs.org/home/dgibson/git/libfdt.git + +author		David Gibson <dgibson@sneetch.(none)> +		Fri, 23 Mar 2007 04:16:54 +0000 (15:16 +1100) +committer	David Gibson <dgibson@sneetch.(none)> +	 	Fri, 23 Mar 2007 04:16:54 +0000 (15:16 +1100) +commit		857f54e79f74429af20c2b5ecc00ee98af6a3b8b +tree		2f648f0f88225a51ded452968d28b4402df8ade0 +parent		07a12a08005f3b5cd9337900a6551e450c07b515 + +To adapt for u-boot usage, only the applicable files were copied and +imported into the u-boot git repository. +Omitted: +* GPL - u-boot comes with a copy of the GPL license +* test subdirectory - not directly useful for u-boot + +After importing, other customizations were performed.  See the git log +for details. + +Jerry Van Baren diff --git a/libfdt/fdt.c b/libfdt/fdt.c new file mode 100644 index 000000000..772da46a7 --- /dev/null +++ b/libfdt/fdt.c @@ -0,0 +1,124 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +int _fdt_check_header(const void *fdt) +{ +	if (fdt_magic(fdt) == FDT_MAGIC) { +		/* Complete tree */ +		if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) +			return -FDT_ERR_BADVERSION; +		if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) +			return -FDT_ERR_BADVERSION; +	} else if (fdt_magic(fdt) == SW_MAGIC) { +		/* Unfinished sequential-write blob */ +		if (fdt_size_dt_struct(fdt) == 0) +			return -FDT_ERR_BADSTATE; +	} else { +		return -FDT_ERR_BADMAGIC; +	} + +	return 0; +} + +void *fdt_offset_ptr(const void *fdt, int offset, int len) +{ +	void *p; + +	if (fdt_version(fdt) >= 0x11) +		if (((offset + len) < offset) +		    || ((offset + len) > fdt_size_dt_struct(fdt))) +			return NULL; + +	p = _fdt_offset_ptr(fdt, offset); + +	if (p + len < p) +		return NULL; +	return p; +} + +uint32_t _fdt_next_tag(const void *fdt, int offset, int *nextoffset) +{ +	const uint32_t *tagp, *lenp; +	uint32_t tag; +	const char *p; + +	if (offset % FDT_TAGSIZE) +		return -1; + +	tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); +	if (! tagp) +		return FDT_END; /* premature end */ +	tag = fdt32_to_cpu(*tagp); +	offset += FDT_TAGSIZE; + +	switch (tag) { +	case FDT_BEGIN_NODE: +		/* skip name */ +		do { +			p = fdt_offset_ptr(fdt, offset++, 1); +		} while (p && (*p != '\0')); +		if (! p) +			return FDT_END; +		break; +	case FDT_PROP: +		lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); +		if (! lenp) +			return FDT_END; +		/* skip name offset, length and value */ +		offset += 2*FDT_TAGSIZE + fdt32_to_cpu(*lenp); +		break; +	} + +	if (nextoffset) +		*nextoffset = ALIGN(offset, FDT_TAGSIZE); + +	return tag; +} + +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s) +{ +	int len = strlen(s) + 1; +	const char *last = strtab + tabsize - len; +	const char *p; + +	for (p = strtab; p <= last; p++) +		if (memeq(p, s, len)) +			return p; +	return NULL; +} + +int fdt_move(const void *fdt, void *buf, int bufsize) +{ +	int err = _fdt_check_header(fdt); + +	if (err) +		return err; + +	if (fdt_totalsize(fdt) > bufsize) +		return -FDT_ERR_NOSPACE; + +	memmove(buf, fdt, fdt_totalsize(fdt)); +	return 0; +} diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c new file mode 100644 index 000000000..7f231ce46 --- /dev/null +++ b/libfdt/fdt_strerror.c @@ -0,0 +1,64 @@ +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "libfdt_env.h" + +#include <fdt.h> +#include <libfdt.h> + +#include "libfdt_internal.h" + +struct errtabent { +	const char *str; +}; + +#define ERRTABENT(val) \ +	[(val)] = { .str = #val, } + +static struct errtabent errtable[] = { +	ERRTABENT(FDT_ERR_NOTFOUND), +	ERRTABENT(FDT_ERR_EXISTS), +	ERRTABENT(FDT_ERR_NOSPACE), + +	ERRTABENT(FDT_ERR_BADOFFSET), +	ERRTABENT(FDT_ERR_BADPATH), +	ERRTABENT(FDT_ERR_BADSTATE), + +	ERRTABENT(FDT_ERR_TRUNCATED), +	ERRTABENT(FDT_ERR_BADMAGIC), +	ERRTABENT(FDT_ERR_BADVERSION), +	ERRTABENT(FDT_ERR_BADSTRUCTURE), +	ERRTABENT(FDT_ERR_BADLAYOUT), +}; +#define ERRTABSIZE	(sizeof(errtable) / sizeof(errtable[0])) + +const char *fdt_strerror(int errval) +{ +	if (errval > 0) +		return "<valid offset/length>"; +	else if (errval == 0) +		return "<no error>"; +	else if (errval > -ERRTABSIZE) { +		const char *s = errtable[-errval].str; + +		if (s) +			return s; +	} + +	return "<unknown error>"; +} diff --git a/libfdt/libfdt_internal.h b/libfdt/libfdt_internal.h new file mode 100644 index 000000000..124bef78e --- /dev/null +++ b/libfdt/libfdt_internal.h @@ -0,0 +1,41 @@ +#ifndef _LIBFDT_INTERNAL_H +#define _LIBFDT_INTERNAL_H +/* + * libfdt - Flat Device Tree manipulation + * Copyright (C) 2006 David Gibson, IBM Corporation. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include <fdt.h> + +#define ALIGN(x, a)	(((x) + (a) - 1) & ~((a) - 1)) +#define PALIGN(p, a)	((void *)ALIGN((unsigned long)(p), (a))) + +#define memeq(p, q, n)	(memcmp((p), (q), (n)) == 0) +#define streq(p, q)	(strcmp((p), (q)) == 0) + +int _fdt_check_header(const void *fdt); +uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset); +const char *_fdt_find_string(const char *strtab, int tabsize, const char *s); +int _fdt_node_end_offset(void *fdt, int nodeoffset); + +static inline void *_fdt_offset_ptr(const struct fdt_header *fdt, int offset) +{ +	return (void *)fdt + fdt_off_dt_struct(fdt) + offset; +} + +#define SW_MAGIC		(~FDT_MAGIC) + +#endif /* _LIBFDT_INTERNAL_H */ |