From 2090854cd2f228bab546f2718ccdbe1664830d3c Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 24 Jul 2019 19:37:54 -0700 Subject: common: Move bootm_decomp_image() to image.c (as image_decomp()) Upcoming patches want to add decompression to use cases that are no longer directly related to booting. It makes sense to retain a single decompression routine, but it should no longer be in bootm.c (which is not compiled for all configurations). This patch moves bootm_decomp_image() to image.c and renames it to image_decomp() in preparation of those upcoming patches. Signed-off-by: Julius Werner Reviewed-by: Simon Goldschmidt [trini: Fix warning around handle_decomp_error being unused] Signed-off-by: Tom Rini --- common/bootm.c | 150 +++++++++------------------------------------------------ common/image.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 128 deletions(-) (limited to 'common') diff --git a/common/bootm.c b/common/bootm.c index bea516025fd..4629cdd82d4 100644 --- a/common/bootm.c +++ b/common/bootm.c @@ -7,17 +7,12 @@ #ifndef USE_HOSTCC #include #include -#include #include #include #include #include #include #include -#include -#include -#include -#include #if defined(CONFIG_CMD_USB) #include #endif @@ -299,23 +294,7 @@ static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, } #endif /* USE_HOSTC */ -/** - * print_decomp_msg() - Print a suitable decompression/loading message - * - * @type: OS type (IH_OS_...) - * @comp_type: Compression type being used (IH_COMP_...) - * @is_xip: true if the load address matches the image start - */ -static void print_decomp_msg(int comp_type, int type, bool is_xip) -{ - const char *name = genimg_get_type_name(type); - - if (comp_type == IH_COMP_NONE) - printf(" %s %s ... ", is_xip ? "XIP" : "Loading", name); - else - printf(" Uncompressing %s ... ", name); -} - +#if !defined(USE_HOSTCC) || defined(CONFIG_FIT_SIGNATURE) /** * handle_decomp_error() - display a decompression error * @@ -325,16 +304,18 @@ static void print_decomp_msg(int comp_type, int type, bool is_xip) * * @comp_type: Compression type being used (IH_COMP_...) * @uncomp_size: Number of bytes uncompressed - * @unc_len: Amount of space available for decompression - * @ret: Error code to report - * @return BOOTM_ERR_RESET, indicating that the board must be reset + * @ret: errno error code received from compression library + * @return Appropriate BOOTM_ERR_ error code */ -static int handle_decomp_error(int comp_type, size_t uncomp_size, - size_t unc_len, int ret) +static int handle_decomp_error(int comp_type, size_t uncomp_size, int ret) { const char *name = genimg_get_comp_name(comp_type); - if (uncomp_size >= unc_len) + /* ENOSYS means unimplemented compression type, don't reset. */ + if (ret == -ENOSYS) + return BOOTM_ERR_UNIMPLEMENTED; + + if (uncomp_size >= CONFIG_SYS_BOOTM_LEN) printf("Image too large: increase CONFIG_SYS_BOOTM_LEN\n"); else printf("%s: uncompress error %d\n", name, ret); @@ -351,93 +332,7 @@ static int handle_decomp_error(int comp_type, size_t uncomp_size, return BOOTM_ERR_RESET; } - -int bootm_decomp_image(int comp, ulong load, ulong image_start, int type, - void *load_buf, void *image_buf, ulong image_len, - uint unc_len, ulong *load_end) -{ - int ret = 0; - - *load_end = load; - print_decomp_msg(comp, type, load == image_start); - - /* - * Load the image to the right place, decompressing if needed. After - * this, image_len will be set to the number of uncompressed bytes - * loaded, ret will be non-zero on error. - */ - switch (comp) { - case IH_COMP_NONE: - if (load == image_start) - break; - if (image_len <= unc_len) - memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); - else - ret = 1; - break; -#ifdef CONFIG_GZIP - case IH_COMP_GZIP: { - ret = gunzip(load_buf, unc_len, image_buf, &image_len); - break; - } -#endif /* CONFIG_GZIP */ -#ifdef CONFIG_BZIP2 - case IH_COMP_BZIP2: { - uint size = unc_len; - - /* - * If we've got less than 4 MB of malloc() space, - * use slower decompression algorithm which requires - * at most 2300 KB of memory. - */ - ret = BZ2_bzBuffToBuffDecompress(load_buf, &size, - image_buf, image_len, - CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); - image_len = size; - break; - } -#endif /* CONFIG_BZIP2 */ -#ifdef CONFIG_LZMA - case IH_COMP_LZMA: { - SizeT lzma_len = unc_len; - - ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, - image_buf, image_len); - image_len = lzma_len; - break; - } -#endif /* CONFIG_LZMA */ -#ifdef CONFIG_LZO - case IH_COMP_LZO: { - size_t size = unc_len; - - ret = lzop_decompress(image_buf, image_len, load_buf, &size); - image_len = size; - break; - } -#endif /* CONFIG_LZO */ -#ifdef CONFIG_LZ4 - case IH_COMP_LZ4: { - size_t size = unc_len; - - ret = ulz4fn(image_buf, image_len, load_buf, &size); - image_len = size; - break; - } -#endif /* CONFIG_LZ4 */ - default: - printf("Unimplemented compression type %d\n", comp); - return BOOTM_ERR_UNIMPLEMENTED; - } - - if (ret) - return handle_decomp_error(comp, image_len, unc_len, ret); - *load_end = load + image_len; - - puts("OK\n"); - - return 0; -} +#endif #ifndef USE_HOSTCC static int bootm_load_os(bootm_headers_t *images, int boot_progress) @@ -456,10 +351,11 @@ static int bootm_load_os(bootm_headers_t *images, int boot_progress) load_buf = map_sysmem(load, 0); image_buf = map_sysmem(os.image_start, image_len); - err = bootm_decomp_image(os.comp, load, os.image_start, os.type, - load_buf, image_buf, image_len, - CONFIG_SYS_BOOTM_LEN, &load_end); + err = image_decomp(os.comp, load, os.image_start, os.type, + load_buf, image_buf, image_len, + CONFIG_SYS_BOOTM_LEN, &load_end); if (err) { + err = handle_decomp_error(os.comp, load_end - load, err); bootstage_error(BOOTSTAGE_ID_DECOMP_IMAGE); return err; } @@ -919,11 +815,6 @@ void __weak switch_to_non_secure_mode(void) #else /* USE_HOSTCC */ -void memmove_wd(void *to, void *from, size_t len, ulong chunksz) -{ - memmove(to, from, len); -} - #if defined(CONFIG_FIT_SIGNATURE) static int bootm_host_load_image(const void *fit, int req_image_type) { @@ -957,13 +848,16 @@ static int bootm_host_load_image(const void *fit, int req_image_type) /* Allow the image to expand by a factor of 4, should be safe */ load_buf = malloc((1 << 20) + len * 4); - ret = bootm_decomp_image(imape_comp, 0, data, image_type, load_buf, - (void *)data, len, CONFIG_SYS_BOOTM_LEN, - &load_end); + ret = image_decomp(imape_comp, 0, data, image_type, load_buf, + (void *)data, len, CONFIG_SYS_BOOTM_LEN, + &load_end); free(load_buf); - if (ret && ret != BOOTM_ERR_UNIMPLEMENTED) - return ret; + if (ret) { + ret = handle_decomp_error(imape_comp, load_end - 0, ret); + if (ret != BOOTM_ERR_UNIMPLEMENTED) + return ret; + } return 0; } diff --git a/common/image.c b/common/image.c index 9f9538fac2f..495883185d4 100644 --- a/common/image.c +++ b/common/image.c @@ -32,6 +32,12 @@ #include #include +#include +#include +#include +#include +#include + #ifdef CONFIG_CMD_BDI extern int do_bdinfo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif @@ -375,6 +381,106 @@ void image_print_contents(const void *ptr) } } +/** + * print_decomp_msg() - Print a suitable decompression/loading message + * + * @type: OS type (IH_OS_...) + * @comp_type: Compression type being used (IH_COMP_...) + * @is_xip: true if the load address matches the image start + */ +static void print_decomp_msg(int comp_type, int type, bool is_xip) +{ + const char *name = genimg_get_type_name(type); + + if (comp_type == IH_COMP_NONE) + printf(" %s %s\n", is_xip ? "XIP" : "Loading", name); + else + printf(" Uncompressing %s\n", name); +} + +int image_decomp(int comp, ulong load, ulong image_start, int type, + void *load_buf, void *image_buf, ulong image_len, + uint unc_len, ulong *load_end) +{ + int ret = 0; + + *load_end = load; + print_decomp_msg(comp, type, load == image_start); + + /* + * Load the image to the right place, decompressing if needed. After + * this, image_len will be set to the number of uncompressed bytes + * loaded, ret will be non-zero on error. + */ + switch (comp) { + case IH_COMP_NONE: + if (load == image_start) + break; + if (image_len <= unc_len) + memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); + else + ret = -ENOSPC; + break; +#ifdef CONFIG_GZIP + case IH_COMP_GZIP: { + ret = gunzip(load_buf, unc_len, image_buf, &image_len); + break; + } +#endif /* CONFIG_GZIP */ +#ifdef CONFIG_BZIP2 + case IH_COMP_BZIP2: { + uint size = unc_len; + + /* + * If we've got less than 4 MB of malloc() space, + * use slower decompression algorithm which requires + * at most 2300 KB of memory. + */ + ret = BZ2_bzBuffToBuffDecompress(load_buf, &size, + image_buf, image_len, + CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); + image_len = size; + break; + } +#endif /* CONFIG_BZIP2 */ +#ifdef CONFIG_LZMA + case IH_COMP_LZMA: { + SizeT lzma_len = unc_len; + + ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, + image_buf, image_len); + image_len = lzma_len; + break; + } +#endif /* CONFIG_LZMA */ +#ifdef CONFIG_LZO + case IH_COMP_LZO: { + size_t size = unc_len; + + ret = lzop_decompress(image_buf, image_len, load_buf, &size); + image_len = size; + break; + } +#endif /* CONFIG_LZO */ +#ifdef CONFIG_LZ4 + case IH_COMP_LZ4: { + size_t size = unc_len; + + ret = ulz4fn(image_buf, image_len, load_buf, &size); + image_len = size; + break; + } +#endif /* CONFIG_LZ4 */ + default: + printf("Unimplemented compression type %d\n", comp); + return -ENOSYS; + } + + *load_end = load + image_len; + + return ret; +} + #ifndef USE_HOSTCC #if CONFIG_IS_ENABLED(LEGACY_IMAGE_FORMAT) @@ -551,6 +657,11 @@ void memmove_wd(void *to, void *from, size_t len, ulong chunksz) memmove(to, from, len); #endif /* CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG */ } +#else /* USE_HOSTCC */ +void memmove_wd(void *to, void *from, size_t len, ulong chunksz) +{ + memmove(to, from, len); +} #endif /* !USE_HOSTCC */ void genimg_print_size(uint32_t size) -- cgit v1.3.1 From b1307f884a913f52a201491053b6d221c4204f60 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 24 Jul 2019 19:37:55 -0700 Subject: fit: Support compression for non-kernel components (e.g. FDT) This patch adds support for compressing non-kernel image nodes in a FIT image (kernel nodes could already be compressed previously). This can reduce the size of FIT images and therefore improve boot times (especially when an image bundles many different kernel FDTs). The images will automatically be decompressed on load. This patch does not support extracting compatible strings from compressed FDTs, so it's not very helpful in conjunction with CONFIG_FIT_BEST_MATCH yet, but it can already be used in environments that select the configuration to load explicitly. Signed-off-by: Julius Werner Reviewed-by: Simon Glass Reviewed-by: Simon Goldschmidt --- common/image-fit.c | 86 ++++++++++++++++++++++++++++------------------- test/py/tests/test_fit.py | 29 +++++++++++++--- 2 files changed, 77 insertions(+), 38 deletions(-) (limited to 'common') diff --git a/common/image-fit.c b/common/image-fit.c index a74b44f2982..c9ffc441aa6 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -22,6 +22,7 @@ DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ +#include #include #include #include @@ -1576,6 +1577,13 @@ int fit_conf_find_compat(const void *fit, const void *fdt) kfdt_name); continue; } + + if (!fit_image_check_comp(fit, kfdt_noffset, IH_COMP_NONE)) { + debug("Can't extract compat from \"%s\" (compressed)\n", + kfdt_name); + continue; + } + /* * Get a pointer to this configuration's fdt. */ @@ -1795,11 +1803,12 @@ int fit_image_load(bootm_headers_t *images, ulong addr, const char *fit_uname_config; const char *fit_base_uname_config; const void *fit; - const void *buf; + void *buf; + void *loadbuf; size_t size; int type_ok, os_ok; - ulong load, data, len; - uint8_t os; + ulong load, load_end, data, len; + uint8_t os, comp; #ifndef USE_HOSTCC uint8_t os_arch; #endif @@ -1895,12 +1904,6 @@ int fit_image_load(bootm_headers_t *images, ulong addr, images->os.arch = os_arch; #endif - if (image_type == IH_TYPE_FLATDT && - !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) { - puts("FDT image is compressed"); - return -EPROTONOSUPPORT; - } - bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); type_ok = fit_image_check_type(fit, noffset, image_type) || fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE) || @@ -1931,7 +1934,8 @@ int fit_image_load(bootm_headers_t *images, ulong addr, bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK); /* get image data address and length */ - if (fit_image_get_data_and_size(fit, noffset, &buf, &size)) { + if (fit_image_get_data_and_size(fit, noffset, + (const void **)&buf, &size)) { printf("Could not find %s subimage data!\n", prop_name); bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); return -ENOENT; @@ -1939,30 +1943,15 @@ int fit_image_load(bootm_headers_t *images, ulong addr, #if !defined(USE_HOSTCC) && defined(CONFIG_FIT_IMAGE_POST_PROCESS) /* perform any post-processing on the image data */ - board_fit_image_post_process((void **)&buf, &size); + board_fit_image_post_process(&buf, &size); #endif len = (ulong)size; - /* verify that image data is a proper FDT blob */ - if (image_type == IH_TYPE_FLATDT && fdt_check_header(buf)) { - puts("Subimage data is not a FDT"); - return -ENOEXEC; - } - bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK); - /* - * Work-around for eldk-4.2 which gives this warning if we try to - * cast in the unmap_sysmem() call: - * warning: initialization discards qualifiers from pointer target type - */ - { - void *vbuf = (void *)buf; - - data = map_to_sysmem(vbuf); - } - + data = map_to_sysmem(buf); + load = data; if (load_op == FIT_LOAD_IGNORED) { /* Don't load */ } else if (fit_image_get_load(fit, noffset, &load)) { @@ -1974,8 +1963,6 @@ int fit_image_load(bootm_headers_t *images, ulong addr, } } else if (load_op != FIT_LOAD_OPTIONAL_NON_ZERO || load) { ulong image_start, image_end; - ulong load_end; - void *dst; /* * move image data to the load address, @@ -1993,14 +1980,45 @@ int fit_image_load(bootm_headers_t *images, ulong addr, printf(" Loading %s from 0x%08lx to 0x%08lx\n", prop_name, data, load); + } else { + load = data; /* No load address specified */ + } + + comp = IH_COMP_NONE; + loadbuf = buf; + /* Kernel images get decompressed later in bootm_load_os(). */ + if (!(image_type == IH_TYPE_KERNEL || + image_type == IH_TYPE_KERNEL_NOLOAD) && + !fit_image_get_comp(fit, noffset, &comp) && + comp != IH_COMP_NONE) { + ulong max_decomp_len = len * 20; + if (load == data) { + loadbuf = malloc(max_decomp_len); + load = map_to_sysmem(loadbuf); + } else { + loadbuf = map_sysmem(load, max_decomp_len); + } + if (image_decomp(comp, load, data, image_type, + loadbuf, buf, len, max_decomp_len, &load_end)) { + printf("Error decompressing %s\n", prop_name); - dst = map_sysmem(load, len); - memmove(dst, buf, len); - data = load; + return -ENOEXEC; + } + len = load_end - load; + } else if (load != data) { + loadbuf = map_sysmem(load, len); + memcpy(loadbuf, buf, len); } + + /* verify that image data is a proper FDT blob */ + if (image_type == IH_TYPE_FLATDT && fdt_check_header(loadbuf)) { + puts("Subimage data is not a FDT"); + return -ENOEXEC; + } + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD); - *datap = data; + *datap = load; *lenp = len; if (fit_unamep) *fit_unamep = (char *)fit_uname; diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index 49d6fea5716..8009d2907b1 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py @@ -24,7 +24,7 @@ base_its = ''' type = "kernel"; arch = "sandbox"; os = "linux"; - compression = "none"; + compression = "%(compression)s"; load = <0x40000>; entry = <0x8>; }; @@ -39,11 +39,11 @@ base_its = ''' }; fdt@1 { description = "snow"; - data = /incbin/("u-boot.dtb"); + data = /incbin/("%(fdt)s"); type = "flat_dt"; arch = "sandbox"; %(fdt_load)s - compression = "none"; + compression = "%(compression)s"; signature@1 { algo = "sha1,rsa2048"; key-name-hint = "dev"; @@ -56,7 +56,7 @@ base_its = ''' arch = "sandbox"; os = "linux"; %(ramdisk_load)s - compression = "none"; + compression = "%(compression)s"; }; ramdisk@2 { description = "snow"; @@ -221,6 +221,10 @@ def test_fit(u_boot_console): print(data, file=fd) return fname + def make_compressed(filename): + util.run_and_log(cons, ['gzip', '-f', '-k', filename]) + return filename + '.gz' + def find_matching(text, match): """Find a match in a line of text, and return the unmatched line portion @@ -312,6 +316,7 @@ def test_fit(u_boot_console): loadables1 = make_kernel('test-loadables1.bin', 'lenrek') loadables2 = make_ramdisk('test-loadables2.bin', 'ksidmar') kernel_out = make_fname('kernel-out.bin') + fdt = make_fname('u-boot.dtb') fdt_out = make_fname('fdt-out.dtb') ramdisk_out = make_fname('ramdisk-out.bin') loadables1_out = make_fname('loadables1-out.bin') @@ -326,6 +331,7 @@ def test_fit(u_boot_console): 'kernel_addr' : 0x40000, 'kernel_size' : filesize(kernel), + 'fdt' : fdt, 'fdt_out' : fdt_out, 'fdt_addr' : 0x80000, 'fdt_size' : filesize(control_dtb), @@ -351,6 +357,7 @@ def test_fit(u_boot_console): 'loadables2_load' : '', 'loadables_config' : '', + 'compression' : 'none', } # Make a basic FIT and a script to load it @@ -417,6 +424,20 @@ def test_fit(u_boot_console): check_equal(loadables2, loadables2_out, 'Loadables2 (ramdisk) not loaded') + # Kernel, FDT and Ramdisk all compressed + with cons.log.section('(Kernel + FDT + Ramdisk) compressed'): + params['compression'] = 'gzip' + params['kernel'] = make_compressed(kernel) + params['fdt'] = make_compressed(fdt) + params['ramdisk'] = make_compressed(ramdisk) + fit = make_fit(mkimage, params) + cons.restart_uboot() + output = cons.run_command_list(cmd.splitlines()) + check_equal(kernel, kernel_out, 'Kernel not loaded') + check_equal(control_dtb, fdt_out, 'FDT not loaded') + check_equal(ramdisk, ramdisk_out, 'Ramdisk not loaded') + + cons = u_boot_console try: # We need to use our own device tree file. Remember to restore it -- cgit v1.3.1 From 18cfa612a9f80249062297befbca7dfa90264622 Mon Sep 17 00:00:00 2001 From: Julius Werner Date: Wed, 24 Jul 2019 19:37:56 -0700 Subject: fit: Support compat string property in configuration node This patch adds support for an optional optimization to compatible string matching where the compatible string property from the root node of the kernel FDT can be copied into the configuration node of the FIT image. This is most useful when using compressed FDTs or when using FDT overlays, where the traditional extraction of the compatible string from the kernel FDT itself is not easily possible. Signed-off-by: Julius Werner Reviewed-by: Simon Glass --- common/image-fit.c | 67 ++++++++++++++++------------ doc/uImage.FIT/kernel_fdts_compressed.its | 73 +++++++++++++++++++++++++++++++ doc/uImage.FIT/source_file_format.txt | 7 +++ 3 files changed, 119 insertions(+), 28 deletions(-) create mode 100644 doc/uImage.FIT/kernel_fdts_compressed.its (limited to 'common') diff --git a/common/image-fit.c b/common/image-fit.c index c9ffc441aa6..e346fed550e 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -1522,6 +1522,10 @@ int fit_check_format(const void *fit) * compatible list, "foo,bar", matches a compatible string in the root of fdt1. * "bim,bam" in fdt2 matches the second string which isn't as good as fdt1. * + * As an optimization, the compatible property from the FDT's root node can be + * copied into the configuration node in the FIT image. This is required to + * match configurations with compressed FDTs. + * * returns: * offset to the configuration to use if one was found * -1 otherwise @@ -1554,55 +1558,62 @@ int fit_conf_find_compat(const void *fit, const void *fdt) for (noffset = fdt_next_node(fit, confs_noffset, &ndepth); (noffset >= 0) && (ndepth > 0); noffset = fdt_next_node(fit, noffset, &ndepth)) { - const void *kfdt; + const void *fdt; const char *kfdt_name; - int kfdt_noffset; + int kfdt_noffset, compat_noffset; const char *cur_fdt_compat; int len; - size_t size; + size_t sz; int i; if (ndepth > 1) continue; - kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); - if (!kfdt_name) { - debug("No fdt property found.\n"); - continue; - } - kfdt_noffset = fdt_subnode_offset(fit, images_noffset, - kfdt_name); - if (kfdt_noffset < 0) { - debug("No image node named \"%s\" found.\n", - kfdt_name); - continue; - } + /* If there's a compat property in the config node, use that. */ + if (fdt_getprop(fit, noffset, "compatible", NULL)) { + fdt = fit; /* search in FIT image */ + compat_noffset = noffset; /* search under config node */ + } else { /* Otherwise extract it from the kernel FDT. */ + kfdt_name = fdt_getprop(fit, noffset, "fdt", &len); + if (!kfdt_name) { + debug("No fdt property found.\n"); + continue; + } + kfdt_noffset = fdt_subnode_offset(fit, images_noffset, + kfdt_name); + if (kfdt_noffset < 0) { + debug("No image node named \"%s\" found.\n", + kfdt_name); + continue; + } - if (!fit_image_check_comp(fit, kfdt_noffset, IH_COMP_NONE)) { - debug("Can't extract compat from \"%s\" (compressed)\n", - kfdt_name); - continue; - } + if (!fit_image_check_comp(fit, kfdt_noffset, + IH_COMP_NONE)) { + debug("Can't extract compat from \"%s\" " + "(compressed)\n", kfdt_name); + continue; + } - /* - * Get a pointer to this configuration's fdt. - */ - if (fit_image_get_data(fit, kfdt_noffset, &kfdt, &size)) { - debug("Failed to get fdt \"%s\".\n", kfdt_name); - continue; + /* search in this config's kernel FDT */ + if (fit_image_get_data(fit, kfdt_noffset, &fdt, &sz)) { + debug("Failed to get fdt \"%s\".\n", kfdt_name); + continue; + } + + compat_noffset = 0; /* search kFDT under root node */ } len = fdt_compat_len; cur_fdt_compat = fdt_compat; /* * Look for a match for each U-Boot compatibility string in - * turn in this configuration's fdt. + * turn in the compat string property. */ for (i = 0; len > 0 && (!best_match_offset || best_match_pos > i); i++) { int cur_len = strlen(cur_fdt_compat) + 1; - if (!fdt_node_check_compatible(kfdt, 0, + if (!fdt_node_check_compatible(fdt, compat_noffset, cur_fdt_compat)) { best_match_offset = noffset; best_match_pos = i; diff --git a/doc/uImage.FIT/kernel_fdts_compressed.its b/doc/uImage.FIT/kernel_fdts_compressed.its new file mode 100644 index 00000000000..8f81106efc7 --- /dev/null +++ b/doc/uImage.FIT/kernel_fdts_compressed.its @@ -0,0 +1,73 @@ +/* + * U-Boot uImage source file with a kernel and multiple compressed FDT blobs. + * Since the FDTs are compressed, configurations must provide a compatible + * string to match directly. + */ + +/dts-v1/; + +/ { + description = "Image with single Linux kernel and compressed FDT blobs"; + #address-cells = <1>; + + images { + kernel { + description = "Vanilla Linux kernel"; + data = /incbin/("./vmlinux.bin.gz"); + type = "kernel"; + arch = "ppc"; + os = "linux"; + compression = "gzip"; + load = <00000000>; + entry = <00000000>; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + }; + fdt@1 { + description = "Flattened Device Tree blob 1"; + data = /incbin/("./myboard-var1.dtb"); + type = "flat_dt"; + arch = "ppc"; + compression = "gzip"; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + }; + fdt@2 { + description = "Flattened Device Tree blob 2"; + data = /incbin/("./myboard-var2.dtb"); + type = "flat_dt"; + arch = "ppc"; + compression = "lzma"; + hash-1 { + algo = "crc32"; + }; + hash-2 { + algo = "sha1"; + }; + }; + }; + + configurations { + default = "conf@1"; + conf@1 { + description = "Boot Linux kernel with FDT blob 1"; + kernel = "kernel"; + fdt = "fdt@1"; + compatible = "myvendor,myboard-variant1"; + }; + conf@2 { + description = "Boot Linux kernel with FDT blob 2"; + kernel = "kernel"; + fdt = "fdt@2"; + compatible = "myvendor,myboard-variant2"; + }; + }; +}; diff --git a/doc/uImage.FIT/source_file_format.txt b/doc/uImage.FIT/source_file_format.txt index d701b9bb760..f8e27ed34e8 100644 --- a/doc/uImage.FIT/source_file_format.txt +++ b/doc/uImage.FIT/source_file_format.txt @@ -240,6 +240,7 @@ o config-1 |- fdt = "fdt sub-node unit-name" [, "fdt overlay sub-node unit-name", ...] |- fpga = "fpga sub-node unit-name" |- loadables = "loadables sub-node unit-name" + |- compatible = "vendor,board-style device tree compatible string" Mandatory properties: @@ -263,6 +264,12 @@ o config-1 of strings. U-Boot will load each binary at its given start-address and may optionaly invoke additional post-processing steps on this binary based on its component image node type. + - compatible : The root compatible string of the U-Boot device tree that + this configuration shall automatically match when CONFIG_FIT_BEST_MATCH is + enabled. If this property is not provided, the compatible string will be + extracted from the fdt blob instead. This is only possible if the fdt is + not compressed, so images with compressed fdts that want to use compatible + string matching must always provide this property. The FDT blob is required to properly boot FDT based kernel, so the minimal configuration for 2.6 FDT kernel is (kernel, fdt) pair. -- cgit v1.3.1 From 49b10cb4926285b856b207c1f5bb40c75487f08b Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Wed, 17 Jul 2019 06:59:51 +0200 Subject: gpio: fixes for gpio-hog support recently added gpio hog patch was "in discussion" state with Simon Glass. This patch now adds most of comments from Simon Glass. Signed-off-by: Heiko Schocher --- common/board_r.c | 4 +- doc/device-tree-bindings/gpio/gpio.txt | 17 ++++-- drivers/gpio/Kconfig | 2 +- drivers/gpio/gpio-uclass.c | 103 ++++++++++++++++++++++++--------- include/asm-generic/gpio.h | 12 ++-- 5 files changed, 96 insertions(+), 42 deletions(-) (limited to 'common') diff --git a/common/board_r.c b/common/board_r.c index ee4dcedd5fa..84aec7fc71c 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -49,7 +49,7 @@ #include #include #include -#if defined(CONFIG_DM_GPIO_HOG) +#if defined(CONFIG_GPIO_HOG) #include #endif @@ -799,7 +799,7 @@ static init_fnc_t init_sequence_r[] = { #ifdef CONFIG_CMD_NET initr_ethaddr, #endif -#if defined(CONFIG_DM_GPIO_HOG) +#if defined(CONFIG_GPIO_HOG) gpio_hog_probe_all, #endif #ifdef CONFIG_BOARD_LATE_INIT diff --git a/doc/device-tree-bindings/gpio/gpio.txt b/doc/device-tree-bindings/gpio/gpio.txt index e7744393697..e146917ff33 100644 --- a/doc/device-tree-bindings/gpio/gpio.txt +++ b/doc/device-tree-bindings/gpio/gpio.txt @@ -252,6 +252,7 @@ Example: boot_rescue { gpio-hog; input; + line-name = "foo-bar-gpio"; gpios = <7 GPIO_ACTIVE_LOW>; }; }; @@ -259,9 +260,13 @@ Example: For the above Example you can than access the gpio in your boardcode with: - desc = gpio_hog_lookup_name("boot_rescue.gpio-hog"); - if (desc) { - if (dm_gpio_get_value(desc)) - printf("\nBooting into Rescue System\n"); - else - printf("\nBoot normal\n"); + struct gpio_desc *desc; + int ret; + + ret = gpio_hog_lookup_name("boot_rescue", &desc); + if (ret) + return; + if (dm_gpio_get_value(desc) == 1) + printf("\nBooting into Rescue System\n"); + else if (dm_gpio_get_value(desc) == 0) + printf("\nBoot normal\n"); diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 800584f5122..7d9c97f5379 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -14,7 +14,7 @@ config DM_GPIO particular GPIOs that they provide. The uclass interface is defined in include/asm-generic/gpio.h. -config DM_GPIO_HOG +config GPIO_HOG bool "Enable GPIO hog support" depends on DM_GPIO default n diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 308d0863ada..01cfa2f7884 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -144,7 +144,7 @@ static int gpio_find_and_xlate(struct gpio_desc *desc, return gpio_xlate_offs_flags(desc->dev, desc, args); } -#if defined(CONFIG_DM_GPIO_HOG) +#if defined(CONFIG_GPIO_HOG) struct gpio_hog_priv { struct gpio_desc gpiod; @@ -181,9 +181,8 @@ static int gpio_hog_ofdata_to_platdata(struct udevice *dev) return ret; } nodename = dev_read_string(dev, "line-name"); - if (!nodename) - nodename = dev_read_name(dev); - device_set_name(dev, nodename); + if (nodename) + device_set_name(dev, nodename); return 0; } @@ -202,9 +201,15 @@ static int gpio_hog_probe(struct udevice *dev) dev->name); return ret; } - dm_gpio_set_dir(&priv->gpiod); - if (plat->gpiod_flags == GPIOD_IS_OUT) - dm_gpio_set_value(&priv->gpiod, plat->value); + + if (plat->gpiod_flags == GPIOD_IS_OUT) { + ret = dm_gpio_set_value(&priv->gpiod, plat->value); + if (ret < 0) { + debug("%s: node %s could not set gpio.\n", __func__, + dev->name); + return ret; + } + } return 0; } @@ -213,32 +218,38 @@ int gpio_hog_probe_all(void) { struct udevice *dev; int ret; + int retval = 0; for (uclass_first_device(UCLASS_NOP, &dev); dev; uclass_find_next_device(&dev)) { if (dev->driver == DM_GET_DRIVER(gpio_hog)) { ret = device_probe(dev); - if (ret) - return ret; + if (ret) { + printf("Failed to probe device %s err: %d\n", + dev->name, ret); + retval = ret; + } } } - return 0; + return retval; } -struct gpio_desc *gpio_hog_lookup_name(const char *name) +int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc) { struct udevice *dev; + *desc = NULL; gpio_hog_probe_all(); if (!uclass_get_device_by_name(UCLASS_NOP, name, &dev)) { struct gpio_hog_priv *priv = dev_get_priv(dev); - return &priv->gpiod; + *desc = &priv->gpiod; + return 0; } - return NULL; + return -ENODEV; } U_BOOT_DRIVER(gpio_hog) = { @@ -250,9 +261,9 @@ U_BOOT_DRIVER(gpio_hog) = { .platdata_auto_alloc_size = sizeof(struct gpio_hog_data), }; #else -struct gpio_desc *gpio_hog_lookup_name(const char *name) +int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc) { - return NULL; + return 0; } #endif @@ -755,13 +766,45 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count) return vector; } +/** + * gpio_request_tail: common work for requesting a gpio. + * + * ret: return value from previous work in function which calls + * this function. + * This seems bogus (why calling this function instead not + * calling it and end caller function instead?). + * Because on error in caller function we want to set some + * default values in gpio desc and have a common error + * debug message, which provides this function. + * nodename: Name of node for which gpio gets requested + * used for gpio label name. + * args: pointer to output arguments structure + * list_name: Name of GPIO list + * used for gpio label name. + * index: gpio index in gpio list + * used for gpio label name. + * desc: pointer to gpio descriptor, filled from this + * function. + * flags: gpio flags to use. + * add_index: should index added to gpio label name + * gpio_dev: pointer to gpio device from which the gpio + * will be requested. If NULL try to get the + * gpio device with uclass_get_device_by_ofnode() + * + * return: In error case this function sets default values in + * gpio descriptor, also emmits a debug message. + * On success it returns 0 else the error code from + * function calls, or the error code passed through + * ret to this function. + * + */ static int gpio_request_tail(int ret, const char *nodename, struct ofnode_phandle_args *args, const char *list_name, int index, struct gpio_desc *desc, int flags, - bool add_index, struct udevice *dev) + bool add_index, struct udevice *gpio_dev) { - desc->dev = dev; + desc->dev = gpio_dev; desc->offset = 0; desc->flags = 0; if (ret) @@ -771,7 +814,8 @@ static int gpio_request_tail(int ret, const char *nodename, ret = uclass_get_device_by_ofnode(UCLASS_GPIO, args->node, &desc->dev); if (ret) { - debug("%s: uclass_get_device_by_ofnode failed\n", __func__); + debug("%s: uclass_get_device_by_ofnode failed\n", + __func__); goto err; } } @@ -989,10 +1033,8 @@ int gpio_dev_request_index(struct udevice *dev, const char *nodename, static int gpio_post_bind(struct udevice *dev) { -#if defined(CONFIG_DM_GPIO_HOG) struct udevice *child; ofnode node; -#endif #if defined(CONFIG_NEEDS_MANUAL_RELOC) struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev); @@ -1024,16 +1066,21 @@ static int gpio_post_bind(struct udevice *dev) } #endif -#if defined(CONFIG_DM_GPIO_HOG) - dev_for_each_subnode(node, dev) { - if (ofnode_read_bool(node, "gpio-hog")) { - const char *name = ofnode_get_name(node); - - device_bind_driver_to_node(dev, "gpio_hog", name, - node, &child); + if (IS_ENABLED(CONFIG_GPIO_HOG)) { + dev_for_each_subnode(node, dev) { + if (ofnode_read_bool(node, "gpio-hog")) { + const char *name = ofnode_get_name(node); + int ret; + + ret = device_bind_driver_to_node(dev, + "gpio_hog", + name, node, + &child); + if (ret) + return ret; + } } } -#endif return 0; } diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index 37f71e5708e..d6cf18744fd 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -352,9 +352,10 @@ int dm_gpio_lookup_name(const char *name, struct gpio_desc *desc); * gpio_hog_lookup_name() - Look up a named GPIO and return the gpio descr. * * @name: Name to look up - * @return: Returns gpio_desc for gpio + * @desc: Returns GPIO description, on success, else NULL + * @return: Returns 0 if OK, else -ENODEV */ -struct gpio_desc *gpio_hog_lookup_name(const char *name); +int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc); /** * gpio_hog_probe_all() - probe all gpio devices with @@ -523,12 +524,13 @@ int gpio_request_list_by_name_nodev(ofnode node, const char *list_name, * gpio_dev_request_index() - request single GPIO from gpio device * * @dev: GPIO device - * @nodename: Name of node + * @nodename: Name of node for which gpio gets requested, used + * for the gpio label name * @list_name: Name of GPIO list (e.g. "board-id-gpios") * @index: Index number of the GPIO in that list use request (0=first) * @flags: GPIOD_* flags - * @dtflags: GPIO flags read from DT - * @desc: GPIO descriotor filled from this function + * @dtflags: GPIO flags read from DT defined see GPIOD_* + * @desc: returns GPIO descriptor filled from this function * @return: return value from gpio_request_tail() */ int gpio_dev_request_index(struct udevice *dev, const char *nodename, -- cgit v1.3.1