diff --git a/config/kernel/linux-rockchip-default.config b/config/kernel/linux-rockchip-default.config index 9d9f2e99fc..83078a066c 100644 --- a/config/kernel/linux-rockchip-default.config +++ b/config/kernel/linux-rockchip-default.config @@ -1277,15 +1277,18 @@ CONFIG_PROC_EVENTS=y # CONFIG_MTD is not set CONFIG_DTC=y CONFIG_OF=y -# CONFIG_OF_UNITTEST is not set +CONFIG_OF_UNITTEST=y CONFIG_OF_FLATTREE=y CONFIG_OF_EARLY_FLATTREE=y +CONFIG_OF_DYNAMIC=y CONFIG_OF_ADDRESS=y CONFIG_OF_IRQ=y CONFIG_OF_NET=y CONFIG_OF_MDIO=y CONFIG_OF_RESERVED_MEM=y -# CONFIG_OF_OVERLAY is not set +CONFIG_OF_RESOLVE=y +CONFIG_OF_OVERLAY=y +CONFIG_OF_CONFIGFS=y CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y # CONFIG_PARPORT is not set CONFIG_BLK_DEV=y @@ -3613,9 +3616,9 @@ CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS=2 # CONFIG_USB_NET2272 is not set # CONFIG_USB_GADGET_XILINX is not set # CONFIG_USB_DUMMY_HCD is not set -CONFIG_USB_LIBCOMPOSITE=y -CONFIG_USB_F_FS=y -CONFIG_USB_CONFIGFS=y +CONFIG_USB_LIBCOMPOSITE=m +CONFIG_USB_F_FS=m +CONFIG_USB_CONFIGFS=m # CONFIG_USB_CONFIGFS_SERIAL is not set # CONFIG_USB_CONFIGFS_ACM is not set # CONFIG_USB_CONFIGFS_OBEX is not set diff --git a/patch/kernel/rockchip-default/180_simple_dtoverlay.patch b/patch/kernel/rockchip-default/180_simple_dtoverlay.patch new file mode 100644 index 0000000000..88a5e43895 --- /dev/null +++ b/patch/kernel/rockchip-default/180_simple_dtoverlay.patch @@ -0,0 +1,426 @@ +From f875ad99fe6d44c7683954b3023209d3d84dbf2d Mon Sep 17 00:00:00 2001 +From: andy_chi +Date: Wed, 21 Jun 2017 15:52:19 +0800 +Subject: [PATCH] Enable a simple user-space driven DT overlay interface + +Change-Id: I6e9f71d8b46df65abd698378b8994988c7fa5651 +--- + drivers/of/Kconfig | 7 + + drivers/of/Makefile | 1 + + drivers/of/dtbocfg.c | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 389 insertions(+) + create mode 100644 drivers/of/dtbocfg.c + +diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig +index e2a48415d969..7e5e6c4e77e0 100644 +--- a/drivers/of/Kconfig ++++ b/drivers/of/Kconfig +@@ -112,4 +112,11 @@ 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 ++ select OF_OVERLAY ++ help ++ Enable a simple user-space driven DT overlay interface. ++ + endif # OF +diff --git a/drivers/of/Makefile b/drivers/of/Makefile +index 156c072b3117..413b0fe675c4 100644 +--- a/drivers/of/Makefile ++++ b/drivers/of/Makefile +@@ -1,4 +1,5 @@ + obj-y = base.o device.o platform.o property.o ++obj-$(CONFIG_OF_CONFIGFS) += dtbocfg.o + obj-$(CONFIG_OF_DYNAMIC) += dynamic.o + obj-$(CONFIG_OF_FLATTREE) += fdt.o + obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o +diff --git a/drivers/of/dtbocfg.c b/drivers/of/dtbocfg.c +new file mode 100644 +index 000000000000..1f715ea3895c +--- /dev/null ++++ b/drivers/of/dtbocfg.c +@@ -0,0 +1,381 @@ ++/********************************************************************************* ++ * ++ * Copyright (C) 2016-2017 Ichiro Kawazome ++ * All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ ********************************************************************************/ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * Device Tree Overlay Item Structure ++ */ ++struct dtbocfg_overlay_item { ++ struct config_item item; ++ struct device_node* node; ++ int id; ++ void* dtbo; ++ int dtbo_size; ++}; ++ ++/** ++ * dtbocfg_overlay_create() - Create Device Tree Overlay ++ * @overlay: Pointer to Device Tree Overlay Item ++ * return Success(0) or Error Status. ++ */ ++static int dtbocfg_overlay_item_create(struct dtbocfg_overlay_item *overlay) ++{ ++ int ret_val; ++ ++#if (LINUX_VERSION_CODE >= 0x040700) ++ of_fdt_unflatten_tree(overlay->dtbo, NULL, &overlay->node); ++#else ++ of_fdt_unflatten_tree(overlay->dtbo, &overlay->node); ++#endif ++ if (overlay->node == NULL) { ++ pr_err("%s: failed to unflatten tree\n", __func__); ++ ret_val = -EINVAL; ++ goto failed; ++ } ++ pr_debug("%s: unflattened OK\n", __func__); ++ ++ of_node_set_flag(overlay->node, OF_DETACHED); ++ ++ ret_val = of_resolve_phandles(overlay->node); ++ if (ret_val != 0) { ++ pr_err("%s: Failed to resolve tree\n", __func__); ++ goto failed; ++ } ++ pr_debug("%s: resolved OK\n", __func__); ++ ++ ret_val = of_overlay_create(overlay->node); ++ if (ret_val < 0) { ++ pr_err("%s: Failed to create overlay (ret_val=%d)\n", __func__, ret_val); ++ goto failed; ++ } ++ overlay->id = ret_val; ++ pr_debug("%s: create OK\n", __func__); ++ return 0; ++ ++ failed: ++ return ret_val; ++} ++ ++/** ++ * dtbocfg_overlay_item_release() - Relase Device Tree Overlay ++ * @overlay: Pointer to Device Tree Overlay Item ++ * return none ++ */ ++static void dtbocfg_overlay_item_release(struct dtbocfg_overlay_item *overlay) ++{ ++ if (overlay->id >= 0) { ++ of_overlay_destroy(overlay->id); ++ overlay->id = -1; ++ } ++} ++ ++/** ++ * container_of_dtbocfg_overlay_item() - Get Device Tree Overlay Item Pointer from Configuration Item ++ * @item: Pointer to Configuration Item ++ * return Pointer to Device Tree Overlay Item ++ */ ++static inline struct dtbocfg_overlay_item* container_of_dtbocfg_overlay_item(struct config_item *item) ++{ ++ return item ? container_of(item, struct dtbocfg_overlay_item, item) : NULL; ++} ++ ++/** ++ * dtbocfg_overlay_item_status_store() - Set Status Attibute ++ * @item: Pointer to Configuration Item ++ * @page: Pointer to Value Buffer ++ * @count: Size of Value Buffer Size ++ * return Stored Size or Error Status. ++ */ ++static ssize_t dtbocfg_overlay_item_status_store(struct config_item *item, const char *buf, size_t count) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ ssize_t status; ++ unsigned long value; ++ if (0 != (status = kstrtoul(buf, 10, &value))) { ++ goto failed; ++ } ++ if (value == 0) { ++ if (overlay->id >= 0) { ++ dtbocfg_overlay_item_release(overlay); ++ } ++ } else { ++ if (overlay->id < 0) { ++ dtbocfg_overlay_item_create(overlay); ++ } ++ } ++ return count; ++ failed: ++ return -EPERM; ++} ++ ++/** ++ * dtbocfg_overlay_item_status_show() - Show Status Attibute ++ * @item : Pointer to Configuration Item ++ * @page : Pointer to Value for Store ++ * return String Size or Error Status. ++ */ ++static ssize_t dtbocfg_overlay_item_status_show(struct config_item *item, char *page) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ return sprintf(page, "%d\n", overlay->id >= 0 ? 1 : 0); ++} ++ ++/** ++ * dtbocfg_overlay_item_dtbo_store() - Store Device Tree Blob to Configuration Item ++ * @item : Pointer to Configuration Item ++ * @page : Pointer to Value Buffer ++ * @count: Size of Value Buffer ++ * return Stored Size or Error Status. ++ */ ++static ssize_t dtbocfg_overlay_item_dtbo_store(struct config_item *item, const char *buf, size_t count) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ ++ if (overlay->dtbo_size > 0) { ++ if (overlay->id >= 0) { ++ return -EPERM; ++ } ++ kfree(overlay->dtbo); ++ overlay->dtbo = NULL; ++ overlay->dtbo_size = 0; ++ } ++ ++ overlay->dtbo = kmemdup(buf, count, GFP_KERNEL); ++ if (overlay->dtbo == NULL) { ++ overlay->dtbo_size = 0; ++ return -ENOMEM; ++ } else { ++ overlay->dtbo_size = count; ++ return count; ++ } ++} ++ ++/** ++ * dtbocfg_overlay_item_dtbo_show() - Read Device Tree Blob from Configuration Item ++ * @item : Pointer to Configuration Item ++ * @page : Pointer to Value for Store ++ * return Read Size ++ */ ++static ssize_t dtbocfg_overlay_item_dtbo_show(struct config_item *item, char *buf) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ ++ if (overlay->dtbo == NULL) ++ return 0; ++ ++ if (overlay->dtbo_size > PAGE_SIZE) ++ return -EINVAL; ++ ++ if (buf != NULL) ++ memcpy(buf, overlay->dtbo, overlay->dtbo_size); ++ ++ return overlay->dtbo_size; ++} ++ ++/** ++ * Device Tree Blob Overlay Attribute Structure ++ */ ++CONFIGFS_ATTR(dtbocfg_overlay_item_, dtbo ); ++CONFIGFS_ATTR(dtbocfg_overlay_item_, status); ++ ++static struct configfs_attribute *dtbocfg_overlay_attrs[] = { ++ &dtbocfg_overlay_item_attr_status, ++ &dtbocfg_overlay_item_attr_dtbo, ++ NULL, ++}; ++ ++/** ++ * dtbocfg_overlay_release() - Release Device Tree Overlay Item ++ * @item : Pointer to Configuration Item ++ * Return None ++ */ ++static void dtbocfg_overlay_release(struct config_item *item) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ ++ pr_debug("%s\n", __func__); ++ ++ dtbocfg_overlay_item_release(overlay); ++ ++ if (overlay->dtbo) { ++ kfree(overlay->dtbo); ++ overlay->dtbo = NULL; ++ overlay->dtbo_size = 0; ++ } ++ ++ kfree(overlay); ++} ++ ++/** ++ * Device Tree Blob Overlay Item Structure ++ */ ++static struct configfs_item_operations dtbocfg_overlay_item_ops = { ++ .release = dtbocfg_overlay_release, ++}; ++ ++static struct config_item_type dtbocfg_overlay_item_type = { ++ .ct_item_ops = &dtbocfg_overlay_item_ops, ++ .ct_attrs = dtbocfg_overlay_attrs, ++ .ct_owner = THIS_MODULE, ++}; ++ ++/** ++ * dtbocfg_overlay_group_make_item() - Make Device Tree Overlay Group Item ++ * @group: Pointer to Configuration Group ++ * @name : Pointer to Group Name ++ * Return Pointer to Device Tree Overlay Group Item ++ */ ++static struct config_item *dtbocfg_overlay_group_make_item(struct config_group *group, const char *name) ++{ ++ struct dtbocfg_overlay_item *overlay; ++ ++ pr_debug("%s\n", __func__); ++ ++ overlay = kzalloc(sizeof(*overlay), GFP_KERNEL); ++ ++ if (!overlay) ++ return ERR_PTR(-ENOMEM); ++ overlay->id = -1; ++ overlay->dtbo = NULL; ++ overlay->dtbo_size = 0; ++ ++ config_item_init_type_name(&overlay->item, name, &dtbocfg_overlay_item_type); ++ return &overlay->item; ++} ++ ++/** ++ * dtbocfg_overlay_group_drop_item() - Drop Device Tree Overlay Group Item ++ * @group: Pointer to Configuration Group ++ * @item : Pointer to Device Tree Overlay Group Item ++ */ ++static void dtbocfg_overlay_group_drop_item(struct config_group *group, struct config_item *item) ++{ ++ struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item); ++ ++ pr_debug("%s\n", __func__); ++ ++ config_item_put(&overlay->item); ++} ++ ++/** ++ * Device Tree Blob Overlay Sub Group Structures ++ */ ++static struct configfs_group_operations dtbocfg_overlays_ops = { ++ .make_item = dtbocfg_overlay_group_make_item, ++ .drop_item = dtbocfg_overlay_group_drop_item, ++}; ++ ++static struct config_item_type dtbocfg_overlays_type = { ++ .ct_group_ops = &dtbocfg_overlays_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct config_group dtbocfg_overlay_group; ++ ++/** ++ * Device Tree Blob Overlay Root Sub System Structures ++ */ ++static struct configfs_group_operations dtbocfg_root_ops = { ++ /* empty - we don't allow anything to be created */ ++}; ++ ++static struct config_item_type dtbocfg_root_type = { ++ .ct_group_ops = &dtbocfg_root_ops, ++ .ct_owner = THIS_MODULE, ++}; ++ ++static struct configfs_subsystem dtbocfg_root_subsys = { ++ .su_group = { ++ .cg_item = { ++ .ci_namebuf = "device-tree", ++ .ci_type = &dtbocfg_root_type, ++ }, ++ }, ++ .su_mutex = __MUTEX_INITIALIZER(dtbocfg_root_subsys.su_mutex), ++}; ++ ++/** ++ * dtbocfg_module_init() ++ */ ++static int __init dtbocfg_module_init(void) ++{ ++ int retval = 0; ++ ++ pr_info("%s\n", __func__); ++ ++ config_group_init(&dtbocfg_root_subsys.su_group); ++ config_group_init_type_name(&dtbocfg_overlay_group, "overlays", &dtbocfg_overlays_type); ++ ++ retval = configfs_register_subsystem(&dtbocfg_root_subsys); ++ if (retval != 0) { ++ pr_err( "%s: couldn't register subsys\n", __func__); ++ goto register_subsystem_failed; ++ } ++ ++ retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group); ++ if (retval != 0) { ++ pr_err( "%s: couldn't register group\n", __func__); ++ goto register_group_failed; ++ } ++ ++ pr_info("%s: OK\n", __func__); ++ return 0; ++ ++ register_group_failed: ++ configfs_unregister_subsystem(&dtbocfg_root_subsys); ++ register_subsystem_failed: ++ return retval; ++} ++ ++/** ++ * dtbocfg_module_exit() ++ */ ++static void __exit dtbocfg_module_exit(void) ++{ ++ configfs_unregister_group(&dtbocfg_overlay_group); ++ configfs_unregister_subsystem(&dtbocfg_root_subsys); ++} ++ ++module_init(dtbocfg_module_init); ++module_exit(dtbocfg_module_exit); ++ ++MODULE_AUTHOR("ikwzm"); ++MODULE_DESCRIPTION("Device Tree Overlay Configuration File System"); ++MODULE_LICENSE("Dual BSD/GPL");