From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dcTLM-0006Sq-Qw for barebox@lists.infradead.org; Tue, 01 Aug 2017 09:20:06 +0000 From: Steffen Trumtrar Date: Tue, 1 Aug 2017 11:19:32 +0200 Message-Id: <20170801091934.3133-2-s.trumtrar@pengutronix.de> In-Reply-To: <20170801091934.3133-1-s.trumtrar@pengutronix.de> References: <20170801091934.3133-1-s.trumtrar@pengutronix.de> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "barebox" Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: [RFC PATCH 2/4] drivers: add fpga bridge framework To: barebox@lists.infradead.org Cc: Steffen Trumtrar Import the fpga bridge framework from linux v4.10-rc2. Signed-off-by: Steffen Trumtrar --- drivers/Kconfig | 1 + drivers/Makefile | 1 + drivers/fpga/Kconfig | 24 ++++ drivers/fpga/Makefile | 6 + drivers/fpga/fpga-bridge.c | 275 +++++++++++++++++++++++++++++++++++++++++++++ include/fpga-bridge.h | 57 ++++++++++ 6 files changed, 364 insertions(+) create mode 100644 drivers/fpga/Kconfig create mode 100644 drivers/fpga/Makefile create mode 100644 drivers/fpga/fpga-bridge.c create mode 100644 include/fpga-bridge.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 1e0246da6db1..3635e5a66e09 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -34,6 +34,7 @@ source "drivers/reset/Kconfig" source "drivers/pci/Kconfig" source "drivers/rtc/Kconfig" source "drivers/firmware/Kconfig" +source "drivers/fpga/Kconfig" source "drivers/phy/Kconfig" source "drivers/crypto/Kconfig" source "drivers/memory/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 767789d5418f..d76efad5e65e 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_RESET_CONTROLLER) += reset/ obj-$(CONFIG_PCI) += pci/ obj-y += rtc/ obj-$(CONFIG_FIRMWARE) += firmware/ +obj-$(CONFIG_FPGA) += fpga/ obj-$(CONFIG_GENERIC_PHY) += phy/ obj-$(CONFIG_HAB) += hab/ obj-$(CONFIG_CRYPTO_HW) += crypto/ diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig new file mode 100644 index 000000000000..cd3a5ba42552 --- /dev/null +++ b/drivers/fpga/Kconfig @@ -0,0 +1,24 @@ +# +# FPGA framework configuration +# + +menu "FPGA Configuration Support" + +config FPGA + tristate "FPGA Configuration Framework" + help + Say Y here if you want support for configuring FPGAs from the + kernel. The FPGA framework adds a FPGA manager class and FPGA + manager drivers. + +if FPGA + +config FPGA_BRIDGE + tristate "FPGA Bridge Framework" + help + Say Y here if you want to support bridges connected between host + processors and FPGAs or between FPGAs. + +endif # FPGA + +endmenu diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile new file mode 100644 index 000000000000..fc71a29d3b33 --- /dev/null +++ b/drivers/fpga/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the fpga framework and fpga manager drivers. +# + +# FPGA Bridge Drivers +obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o diff --git a/drivers/fpga/fpga-bridge.c b/drivers/fpga/fpga-bridge.c new file mode 100644 index 000000000000..818f4e62cf7c --- /dev/null +++ b/drivers/fpga/fpga-bridge.c @@ -0,0 +1,275 @@ +/* + * FPGA Bridge Framework Driver + * + * Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ +#include +#include + +/** + * fpga_bridge_enable - Enable transactions on the bridge + * + * @bridge: FPGA bridge + * + * Return: 0 for success, error code otherwise. + */ +int fpga_bridge_enable(struct fpga_bridge *bridge) +{ + dev_dbg(&bridge->dev, "enable\n"); + + if (bridge->br_ops && bridge->br_ops->enable_set) + return bridge->br_ops->enable_set(bridge, 1); + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_bridge_enable); + +/** + * fpga_bridge_disable - Disable transactions on the bridge + * + * @bridge: FPGA bridge + * + * Return: 0 for success, error code otherwise. + */ +int fpga_bridge_disable(struct fpga_bridge *bridge) +{ + dev_dbg(&bridge->dev, "disable\n"); + + if (bridge->br_ops && bridge->br_ops->enable_set) + return bridge->br_ops->enable_set(bridge, 0); + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_bridge_disable); + +/** + * of_fpga_bridge_get - get an exclusive reference to a fpga bridge + * + * @np: node pointer of a FPGA bridge + * @info: fpga image specific information + * + * Return fpga_bridge struct if successful. + * Return -EBUSY if someone already has a reference to the bridge. + * Return -ENODEV if @np is not a FPGA Bridge. + */ +struct fpga_bridge *of_fpga_bridge_get(struct device_node *np, + struct fpga_image_info *info) + +{ + struct device_d *dev; + struct fpga_bridge *bridge; + int ret = -ENODEV; + + dev = of_find_device_by_node(np); + if (!dev) + return ERR_PTR(ret); + + bridge = dev->priv; + + bridge->info = info; + + dev_dbg(&bridge->dev, "get\n"); + + return bridge; +} +EXPORT_SYMBOL_GPL(of_fpga_bridge_get); + +/** + * fpga_bridge_put - release a reference to a bridge + * + * @bridge: FPGA bridge + */ +void fpga_bridge_put(struct fpga_bridge *bridge) +{ + dev_dbg(&bridge->dev, "put\n"); + + bridge->info = NULL; +} +EXPORT_SYMBOL_GPL(fpga_bridge_put); + +/** + * fpga_bridges_enable - enable bridges in a list + * @bridge_list: list of FPGA bridges + * + * Enable each bridge in the list. If list is empty, do nothing. + * + * Return 0 for success or empty bridge list; return error code otherwise. + */ +int fpga_bridges_enable(struct list_head *bridge_list) +{ + struct fpga_bridge *bridge; + struct list_head *node; + int ret; + + list_for_each(node, bridge_list) { + bridge = list_entry(node, struct fpga_bridge, node); + ret = fpga_bridge_enable(bridge); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_bridges_enable); + +/** + * fpga_bridges_disable - disable bridges in a list + * + * @bridge_list: list of FPGA bridges + * + * Disable each bridge in the list. If list is empty, do nothing. + * + * Return 0 for success or empty bridge list; return error code otherwise. + */ +int fpga_bridges_disable(struct list_head *bridge_list) +{ + struct fpga_bridge *bridge; + struct list_head *node; + int ret; + + list_for_each(node, bridge_list) { + bridge = list_entry(node, struct fpga_bridge, node); + ret = fpga_bridge_disable(bridge); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_bridges_disable); + +/** + * fpga_bridges_put - put bridges + * + * @bridge_list: list of FPGA bridges + * + * For each bridge in the list, put the bridge and remove it from the list. + * If list is empty, do nothing. + */ +void fpga_bridges_put(struct list_head *bridge_list) +{ + struct fpga_bridge *bridge; + struct list_head *node, *next; + + list_for_each_safe(node, next, bridge_list) { + bridge = list_entry(node, struct fpga_bridge, node); + + fpga_bridge_put(bridge); + + list_del(&bridge->node); + } +} +EXPORT_SYMBOL_GPL(fpga_bridges_put); + +/** + * fpga_bridges_get_to_list - get a bridge, add it to a list + * + * @np: node pointer of a FPGA bridge + * @info: fpga image specific information + * @bridge_list: list of FPGA bridges + * + * Get an exclusive reference to the bridge and and it to the list. + * + * Return 0 for success, error code from of_fpga_bridge_get() othewise. + */ +int fpga_bridge_get_to_list(struct device_node *np, + struct fpga_image_info *info, + struct list_head *bridge_list) +{ + struct fpga_bridge *bridge; + + bridge = of_fpga_bridge_get(np, info); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + + list_add(&bridge->node, bridge_list); + + return 0; +} +EXPORT_SYMBOL_GPL(fpga_bridge_get_to_list); + +static int set_enable(struct param_d *p, void *priv) +{ + struct fpga_bridge *bridge = priv; + + if (bridge->enable) + fpga_bridge_enable(bridge); + else + fpga_bridge_disable(bridge); + + return 0; +} + +/** + * fpga_bridge_register - register a fpga bridge driver + * @dev: FPGA bridge device from pdev + * @name: FPGA bridge name + * @br_ops: pointer to structure of fpga bridge ops + * @priv: FPGA bridge private data + * + * Return: 0 for success, error code otherwise. + */ +int fpga_bridge_register(struct device_d *dev, const char *name, + const struct fpga_bridge_ops *br_ops, void *priv) +{ + struct fpga_bridge *bridge; + struct param_d *p; + int ret = 0; + + if (!name || !strlen(name)) { + dev_err(dev, "Attempt to register with no name!\n"); + return -EINVAL; + } + + bridge = xzalloc(sizeof(*bridge)); + if (!bridge) + return -ENOMEM; + + INIT_LIST_HEAD(&bridge->node); + + bridge->br_ops = br_ops; + bridge->priv = priv; + + bridge->dev.parent = dev; + bridge->dev.device_node = dev->device_node; + bridge->dev.id = DEVICE_ID_DYNAMIC; + + strcpy(bridge->dev.name, name); + + ret = register_device(&bridge->dev); + if (ret) + goto out; + + dev->priv = bridge; + + bridge->enable = 0; + p = dev_add_param_bool(&bridge->dev, "enable", set_enable, + NULL, &bridge->enable, bridge); + if (IS_ERR(p)) + return PTR_ERR(p); + + of_platform_populate(dev->device_node, NULL, dev); + + dev_info(bridge->dev.parent, "fpga bridge [%s] registered\n", + bridge->dev.name); + + return 0; + +out: + kfree(bridge); + + return ret; +} +EXPORT_SYMBOL_GPL(fpga_bridge_register); diff --git a/include/fpga-bridge.h b/include/fpga-bridge.h new file mode 100644 index 000000000000..91df9fa4b486 --- /dev/null +++ b/include/fpga-bridge.h @@ -0,0 +1,57 @@ +#include + +#ifndef _LINUX_FPGA_BRIDGE_H +#define _LINUX_FPGA_BRIDGE_H + +struct fpga_bridge; + +/** + * struct fpga_bridge_ops - ops for low level FPGA bridge drivers + * @enable_show: returns the FPGA bridge's status + * @enable_set: set a FPGA bridge as enabled or disabled + * @fpga_bridge_remove: set FPGA into a specific state during driver remove + */ +struct fpga_bridge_ops { + int (*enable_show)(struct fpga_bridge *bridge); + int (*enable_set)(struct fpga_bridge *bridge, bool enable); + void (*fpga_bridge_remove)(struct fpga_bridge *bridge); +}; + +/** + * struct fpga_bridge - FPGA bridge structure + * @name: name of low level FPGA bridge + * @dev: FPGA bridge device + * @mutex: enforces exclusive reference to bridge + * @br_ops: pointer to struct of FPGA bridge ops + * @info: fpga image specific information + * @node: FPGA bridge list node + * @priv: low level driver private date + */ +struct fpga_bridge { + struct device_d dev; + const struct fpga_bridge_ops *br_ops; + struct fpga_image_info *info; + struct list_head node; + unsigned int enable; + void *priv; +}; + +#define to_fpga_bridge(d) container_of(d, struct fpga_bridge, dev) + +struct fpga_bridge *of_fpga_bridge_get(struct device_node *node, + struct fpga_image_info *info); +void fpga_bridge_put(struct fpga_bridge *bridge); +int fpga_bridge_enable(struct fpga_bridge *bridge); +int fpga_bridge_disable(struct fpga_bridge *bridge); + +int fpga_bridges_enable(struct list_head *bridge_list); +int fpga_bridges_disable(struct list_head *bridge_list); +void fpga_bridges_put(struct list_head *bridge_list); +int fpga_bridge_get_to_list(struct device_node *np, + struct fpga_image_info *info, + struct list_head *bridge_list); + +int fpga_bridge_register(struct device_d *dev, const char *name, + const struct fpga_bridge_ops *br_ops, void *priv); + +#endif /* _LINUX_FPGA_BRIDGE_H */ -- 2.11.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox