diff --git a/config/kernel/linux-sun50i-dev.config b/config/kernel/linux-sun50i-dev.config index b7dd3c5b76..666f18a8cc 100644 --- a/config/kernel/linux-sun50i-dev.config +++ b/config/kernel/linux-sun50i-dev.config @@ -1311,6 +1311,7 @@ CONFIG_OF_MDIO=y CONFIG_OF_RESERVED_MEM=y CONFIG_OF_RESOLVE=y CONFIG_OF_OVERLAY=y +CONFIG_OF_CONFIGFS=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_NULL_BLK is not set diff --git a/patch/kernel/sun50iw2-dev/add_configfs_overlay_for_v4.10.x.patch b/patch/kernel/sun50iw2-dev/add_configfs_overlay_for_v4.10.x.patch new file mode 100644 index 0000000000..006766a229 --- /dev/null +++ b/patch/kernel/sun50iw2-dev/add_configfs_overlay_for_v4.10.x.patch @@ -0,0 +1,360 @@ +diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig +index bc07ad3..e9da9cf 100644 +--- a/drivers/of/Kconfig ++++ b/drivers/of/Kconfig +@@ -113,6 +113,13 @@ config OF_OVERLAY + While this option is selected automatically when needed, you can + enable it manually to improve device tree unit test coverage. + ++config OF_CONFIGFS ++ bool "Device Tree Overlay ConfigFS interface" ++ select CONFIGFS_FS ++ depends on OF_OVERLAY ++ help ++ Enable a simple user-space driven DT overlay interface. ++ + config OF_NUMA + bool + +diff --git a/drivers/of/Makefile b/drivers/of/Makefile +index d7efd9d..a06cc35 100644 +--- a/drivers/of/Makefile ++++ b/drivers/of/Makefile +@@ -13,6 +13,7 @@ obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o + obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o + obj-$(CONFIG_OF_RESOLVE) += resolver.o + obj-$(CONFIG_OF_OVERLAY) += overlay.o ++obj-$(CONFIG_OF_CONFIGFS) += configfs.o + obj-$(CONFIG_OF_NUMA) += of_numa.o + + obj-$(CONFIG_OF_UNITTEST) += unittest-data/ +diff --git a/drivers/of/configfs.c b/drivers/of/configfs.c +new file mode 100644 +index 0000000..68f889d +--- /dev/null ++++ b/drivers/of/configfs.c +@@ -0,0 +1,311 @@ ++/* ++ * Configfs entries for device-tree ++ * ++ * Copyright (C) 2013 - Pantelis Antoniou ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "of_private.h" ++ ++struct cfs_overlay_item { ++ struct config_item item; ++ ++ char path[PATH_MAX]; ++ ++ const struct firmware *fw; ++ struct device_node *overlay; ++ int ov_id; ++ ++ void *dtbo; ++ int dtbo_size; ++}; ++ ++static int create_overlay(struct cfs_overlay_item *overlay, void *blob) ++{ ++ int err; ++ ++ /* unflatten the tree */ ++ of_fdt_unflatten_tree(blob, NULL, &overlay->overlay); ++ if (overlay->overlay == NULL) { ++ pr_err("%s: failed to unflatten tree\n", __func__); ++ err = -EINVAL; ++ goto out_err; ++ } ++ pr_debug("%s: unflattened OK\n", __func__); ++ ++ /* mark it as detached */ ++ of_node_set_flag(overlay->overlay, OF_DETACHED); ++ ++ /* perform resolution */ ++ err = of_resolve_phandles(overlay->overlay); ++ if (err != 0) { ++ pr_err("%s: Failed to resolve tree\n", __func__); ++ goto out_err; ++ } ++ pr_debug("%s: resolved OK\n", __func__); ++ ++ err = of_overlay_create(overlay->overlay); ++ if (err < 0) { ++ pr_err("%s: Failed to create overlay (err=%d)\n", ++ __func__, err); ++ goto out_err; ++ } ++ overlay->ov_id = err; ++ ++out_err: ++ return err; ++} ++ ++static inline struct cfs_overlay_item *to_cfs_overlay_item( ++ struct config_item *item) ++{ ++ return item ? container_of(item, struct cfs_overlay_item, item) : NULL; ++} ++ ++static ssize_t cfs_overlay_item_path_show(struct config_item *item, ++ char *page) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ return sprintf(page, "%s\n", overlay->path); ++} ++ ++static ssize_t cfs_overlay_item_path_store(struct config_item *item, ++ const char *page, size_t count) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ const char *p = page; ++ char *s; ++ int err; ++ ++ /* if it's set do not allow changes */ ++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) ++ return -EPERM; ++ ++ /* copy to path buffer (and make sure it's always zero terminated */ ++ count = snprintf(overlay->path, sizeof(overlay->path) - 1, "%s", p); ++ overlay->path[sizeof(overlay->path) - 1] = '\0'; ++ ++ /* strip trailing newlines */ ++ s = overlay->path + strlen(overlay->path); ++ while (s > overlay->path && *--s == '\n') ++ *s = '\0'; ++ ++ pr_debug("%s: path is '%s'\n", __func__, overlay->path); ++ ++ err = request_firmware(&overlay->fw, overlay->path, NULL); ++ if (err != 0) ++ goto out_err; ++ ++ err = create_overlay(overlay, (void *)overlay->fw->data); ++ if (err != 0) ++ goto out_err; ++ ++ return count; ++ ++out_err: ++ ++ release_firmware(overlay->fw); ++ overlay->fw = NULL; ++ ++ overlay->path[0] = '\0'; ++ return err; ++} ++ ++static ssize_t cfs_overlay_item_status_show(struct config_item *item, ++ char *page) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ ++ return sprintf(page, "%s\n", ++ overlay->ov_id >= 0 ? "applied" : "unapplied"); ++} ++ ++CONFIGFS_ATTR(cfs_overlay_item_, path); ++CONFIGFS_ATTR_RO(cfs_overlay_item_, status); ++ ++static struct configfs_attribute *cfs_overlay_attrs[] = { ++ &cfs_overlay_item_attr_path, ++ &cfs_overlay_item_attr_status, ++ NULL, ++}; ++ ++ssize_t cfs_overlay_item_dtbo_read(struct config_item *item, ++ void *buf, size_t max_count) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ ++ pr_debug("%s: buf=%p max_count=%zu\n", __func__, ++ buf, max_count); ++ ++ if (overlay->dtbo == NULL) ++ return 0; ++ ++ /* copy if buffer provided */ ++ if (buf != NULL) { ++ /* the buffer must be large enough */ ++ if (overlay->dtbo_size > max_count) ++ return -ENOSPC; ++ ++ memcpy(buf, overlay->dtbo, overlay->dtbo_size); ++ } ++ ++ return overlay->dtbo_size; ++} ++ ++ssize_t cfs_overlay_item_dtbo_write(struct config_item *item, ++ const void *buf, size_t count) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ int err; ++ ++ /* if it's set do not allow changes */ ++ if (overlay->path[0] != '\0' || overlay->dtbo_size > 0) ++ return -EPERM; ++ ++ /* copy the contents */ ++ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL); ++ if (overlay->dtbo == NULL) ++ return -ENOMEM; ++ ++ overlay->dtbo_size = count; ++ ++ err = create_overlay(overlay, overlay->dtbo); ++ if (err != 0) ++ goto out_err; ++ ++ return count; ++ ++out_err: ++ kfree(overlay->dtbo); ++ overlay->dtbo = NULL; ++ overlay->dtbo_size = 0; ++ ++ return err; ++} ++ ++CONFIGFS_BIN_ATTR(cfs_overlay_item_, dtbo, NULL, SZ_1M); ++ ++static struct configfs_bin_attribute *cfs_overlay_bin_attrs[] = { ++ &cfs_overlay_item_attr_dtbo, ++ NULL, ++}; ++ ++static void cfs_overlay_release(struct config_item *item) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ ++ if (overlay->ov_id >= 0) ++ of_overlay_destroy(overlay->ov_id); ++ if (overlay->fw) ++ release_firmware(overlay->fw); ++ /* kfree with NULL is safe */ ++ kfree(overlay->dtbo); ++ kfree(overlay); ++} ++ ++static struct configfs_item_operations cfs_overlay_item_ops = { ++ .release = cfs_overlay_release, ++}; ++ ++static struct config_item_type cfs_overlay_type = { ++ .ct_item_ops = &cfs_overlay_item_ops, ++ .ct_attrs = cfs_overlay_attrs, ++ .ct_bin_attrs = cfs_overlay_bin_attrs, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct config_item *cfs_overlay_group_make_item( ++ struct config_group *group, const char *name) ++{ ++ struct cfs_overlay_item *overlay; ++ ++ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); ++ if (!overlay) ++ return ERR_PTR(-ENOMEM); ++ overlay->ov_id = -1; ++ ++ config_item_init_type_name(&overlay->item, name, &cfs_overlay_type); ++ return &overlay->item; ++} ++ ++static void cfs_overlay_group_drop_item(struct config_group *group, ++ struct config_item *item) ++{ ++ struct cfs_overlay_item *overlay = to_cfs_overlay_item(item); ++ ++ config_item_put(&overlay->item); ++} ++ ++static struct configfs_group_operations overlays_ops = { ++ .make_item = cfs_overlay_group_make_item, ++ .drop_item = cfs_overlay_group_drop_item, ++}; ++ ++static struct config_item_type overlays_type = { ++ .ct_group_ops = &overlays_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct configfs_group_operations of_cfs_ops = { ++ /* empty - we don't allow anything to be created */ ++}; ++ ++static struct config_item_type of_cfs_type = { ++ .ct_group_ops = &of_cfs_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++struct config_group of_cfs_overlay_group; ++ ++static struct configfs_subsystem of_cfs_subsys = { ++ .su_group = { ++ .cg_item = { ++ .ci_namebuf = "device-tree", ++ .ci_type = &of_cfs_type, ++ }, ++ }, ++ .su_mutex = __MUTEX_INITIALIZER(of_cfs_subsys.su_mutex), ++}; ++ ++static int __init of_cfs_init(void) ++{ ++ int ret; ++ ++ pr_info("%s\n", __func__); ++ ++ config_group_init(&of_cfs_subsys.su_group); ++ config_group_init_type_name(&of_cfs_overlay_group, "overlays", ++ &overlays_type); ++ configfs_add_default_group(&of_cfs_overlay_group, ++ &of_cfs_subsys.su_group); ++ ++ ret = configfs_register_subsystem(&of_cfs_subsys); ++ if (ret != 0) { ++ pr_err("%s: failed to register subsys\n", __func__); ++ goto out; ++ } ++ pr_info("%s: OK\n", __func__); ++out: ++ return ret; ++} ++late_initcall(of_cfs_init); +diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c +index dca8f9b..ec7e167 100644 +--- a/drivers/of/fdt_address.c ++++ b/drivers/of/fdt_address.c +@@ -161,7 +161,7 @@ static int __init fdt_translate_one(const void *blob, int parent, + * that can be mapped to a cpu physical address). This is not really specified + * that way, but this is traditionally the way IBM at least do things + */ +-static u64 __init fdt_translate_address(const void *blob, int node_offset) ++u64 __init fdt_translate_address(const void *blob, int node_offset) + { + int parent, len; + const struct of_bus *bus, *pbus; diff --git a/patch/kernel/sun50iw2-dev/scripts-dtc-Update-to-version-with-overlays.patch b/patch/kernel/sun50iw2-dev/scripts-dtc-Update-to-version-with-overlays.patch new file mode 100644 index 0000000000..bc3f71600a --- /dev/null +++ b/patch/kernel/sun50iw2-dev/scripts-dtc-Update-to-version-with-overlays.patch @@ -0,0 +1,16 @@ +diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib +index ddf83d0..a0fb9e3 100644 +--- a/scripts/Makefile.lib ++++ b/scripts/Makefile.lib +@@ -275,7 +275,11 @@ cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ + + # DTC + # --------------------------------------------------------------------------- ++ifeq ($(CONFIG_OF_CONFIGFS),y) ++DTC ?= $(objtree)/scripts/dtc/dtc -@ ++else + DTC ?= $(objtree)/scripts/dtc/dtc ++endif + + # Generate an assembly file to wrap the output of the device tree compiler + quiet_cmd_dt_S_dtb= DTB $@