Re: [PATCH v12 3/6] fpga: add simple-fpga-bus

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On Tue, Oct 27, 2015 at 05:09:12PM -0500, atull@xxxxxxxxxxxxxxxxxxxxx wrote:
> From: Alan Tull <atull@xxxxxxxxxxxxxxxxxxxxx>
> 
> The Simple FPGA bus uses the FPGA Manager Framework and the
> FPGA Bridge Framework to provide a manufactorer-agnostic
> interface for reprogramming FPGAs that is Device Tree
> Overlays-based.
> 
> When a Device Tree Overlay containing a Simple FPGA Bus is
> applied, the Simple FPGA Bus will be probed and will:
>  * Disable the FPGA bridges specified in the overlay
>  * Reprogram a specified FPGA with a specified image file
>  * Enable the specified FPGA bridges
>  * Populate the child devices
> 
> Removing the Device Tree Overlay is also supported.
> 
> This supports fpga use where hardware blocks on a fpga will
> need drivers.
> 
> Signed-off-by: Alan Tull <atull@xxxxxxxxxxxxxxxxxxxxx>
> ---
> v9:  initial version (this patch added during rest of patchset's v9)
> v10: request deferral if fpga mgr or bridges not available yet
>      cleanup as fpga manager core goes into the real kernel
>      Don't assume bridges are disabled before programming FPGA
>      Don't hang onto reference for fpga manager
>      Move to staging/simple-fpga-bus
> v11: No change in this patch for v11 of the patch set
> v12: Moved out of staging.
>      Use fpga bridges framework.
> ---
>  drivers/fpga/Kconfig           |    7 +
>  drivers/fpga/Makefile          |    3 +
>  drivers/fpga/simple-fpga-bus.c |  327 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 337 insertions(+)
>  create mode 100644 drivers/fpga/simple-fpga-bus.c
> 
> diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
> index 348e1dea..e8f5453 100644
> --- a/drivers/fpga/Kconfig
> +++ b/drivers/fpga/Kconfig
> @@ -13,6 +13,13 @@ config FPGA
>  
>  if FPGA
>  
> +config SIMPLE_FPGA_BUS
> +       bool "Simple FPGA Bus"
> +       depends on OF
> +       help
> +         Simple FPGA Bus allows loading FPGA images under control of
> +	 Device Tree.
> +
>  config FPGA_MGR_SOCFPGA
>  	tristate "Altera SOCFPGA FPGA Manager"
>  	depends on ARCH_SOCFPGA
> diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
> index bf0c0d2..0385622 100644
> --- a/drivers/fpga/Makefile
> +++ b/drivers/fpga/Makefile
> @@ -8,3 +8,6 @@ obj-$(CONFIG_FPGA)			+= fpga-mgr.o
>  # FPGA Manager Drivers
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA)		+= socfpga.o
>  obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10)	+= socfpga-a10.o
> +
> +# High Level Interfaces
> +obj-$(CONFIG_SIMPLE_FPGA_BUS)		+= simple-fpga-bus.o
> diff --git a/drivers/fpga/simple-fpga-bus.c b/drivers/fpga/simple-fpga-bus.c
> new file mode 100644
> index 0000000..6318cf1
> --- /dev/null
> +++ b/drivers/fpga/simple-fpga-bus.c
> @@ -0,0 +1,327 @@
> +/*
> + * Simple FPGA Bus
> + *
> + *  Copyright (C) 2013-2015 Altera Corporation
> + *
> + * 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/fpga/fpga-mgr.h>
> +#include <linux/fpga/fpga-bridge.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/reset.h>
> +#include <linux/slab.h>
> +
> +/**
> + * struct simple_fpga_bus - simple fpga bus private data
> + * @dev:	device from pdev
> + * @bridges:	FPGA bridges associated with this bus
> + * @num_bridges: size of the bridges array
> + */
> +struct simple_fpga_bus {
> +	struct device *dev;
> +	struct fpga_bridge **bridges;
> +	int num_bridges;
> +};
> +
> +/**
> + * simple_fpga_bus_get_mgr - get associated fpga manager
> + * @priv: simple fpga bus private data
> + * pointer to fpga manager in priv->mgr on success
> + *
> + * Given a simple fpga bus, get a reference to its the fpga manager specified
> + * by its "fpga-mgr" device tree property.
> + *
> + * Return: 0 if the fpga manager is not specified.
> + *         pointer to struct fpga_manager if successful.
> + *         Negative error code otherwise.
> + */
> +static struct fpga_manager *simple_fpga_bus_get_mgr(
> +					struct simple_fpga_bus *priv)
> +{
> +	struct device *dev = priv->dev;
> +	struct device_node *np = dev->of_node;
> +	struct device_node *mgr_node;
> +
> +	/*
> +	 * Return 0 (not an error) if fpga manager is not specified.
> +	 * This supports the case where fpga was already configured.
> +	 */
> +	mgr_node = of_parse_phandle(np, "fpga-mgr", 0);
> +	if (!mgr_node) {
> +		dev_dbg(dev, "could not find fpga-mgr DT property\n");
> +		return 0;
> +	}
> +
> +	return of_fpga_mgr_get(mgr_node);
> +}
> +
> +/**
> + * simple_fpga_bus_load_image - load an fpga image under device tree control
> + * @priv: simple fpga bus private data
> + *
> + * Given a simple fpga bus, load the fpga image specified in its device
> + * tree node.
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int simple_fpga_bus_load_image(struct simple_fpga_bus *priv,
> +				      struct fpga_manager *mgr)
> +{
> +	struct device *dev = priv->dev;
> +	struct device_node *np = dev->of_node;
> +	u32 flags = 0;
> +	const char *path;
> +
> +	if (of_property_read_bool(np, "partial-reconfig"))
> +		flags |= FPGA_MGR_PARTIAL_RECONFIG;
> +
> +	/* If firmware image is specified in the DT, load it */
> +	if (!of_property_read_string(np, "fpga-firmware", &path))
> +		return fpga_mgr_firmware_load(mgr, flags, path);
> +
> +	/*
> +	 * Here we can add other methods of getting ahold of a fpga image
> +	 * specified in the device tree and programming it.
> +	 */
> +
> +	dev_dbg(dev, "No FPGA image to load.\n");
> +
> +	/* Status is that we have a fpga manager but no image specified. */
> +	return -EINVAL;
> +}
> +
> +/**
> + * simple_fpga_bus_bridge_enable - enable the fpga bridges
> + * @priv: simple fpga bus private data
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int simple_fpga_bus_bridge_enable(struct simple_fpga_bus *priv)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < priv->num_bridges; i++) {
> +		ret = fpga_bridge_enable(priv->bridges[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * simple_fpga_bus_bridge_disable - disable the bridges
> + * @priv: simple fpga bus private data
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int simple_fpga_bus_bridge_disable(struct simple_fpga_bus *priv)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < priv->num_bridges; i++) {
> +		ret = fpga_bridge_disable(priv->bridges[i]);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * simple_fpga_bus_get_bridges - get references for fpga bridges
> + * @priv: simple fpga bus private data
> + *
> + * Given a simple fpga bus, get references for its associated fpga bridges.
> + * These are pointed to by "fpga-bridges" device tree property.
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int simple_fpga_bus_get_bridges(struct simple_fpga_bus *priv)
> +{
> +	struct device *dev = priv->dev;
> +	struct device_node *np = dev->of_node;
> +	struct of_phandle_args out_args;
> +	struct fpga_bridge *bridge, **bridges;
> +	int i, num_bridges, ret;
> +
> +	num_bridges = of_count_phandle_with_args(np, "fpga-bridges", NULL);
> +	if (!num_bridges) {
> +		dev_info(dev, "No fpga bridges found\n");
> +		return -EINVAL;
> +	}
> +
> +	bridges = kcalloc(num_bridges, sizeof(*bridge), GFP_KERNEL);
> +	if (!bridges)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < num_bridges; i++) {
> +		ret = of_parse_phandle_with_args(np, "fpga-bridges", NULL, i,
> +						 &out_args);
> +		if (ret)
> +			goto err_free_bridges;
> +
> +		bridge = of_fpga_bridge_get(out_args.np);
> +		if (!bridge) {
> +			dev_err(dev, "No fpga bridge found for phandle\n");
> +			goto err_free_bridges;
> +		}
> +
> +		dev_info(dev, "Found bridge: %s\n", dev_name(&bridge->dev));
> +
> +		bridges[i] = bridge;
> +	}
> +
> +	priv->bridges = bridges;
> +	priv->num_bridges = num_bridges;
> +
> +	return 0;
> +
> +err_free_bridges:
> +	while (i)
> +		fpga_bridge_put(bridges[--i]);
> +
> +	kfree(bridges);
> +	return -EINVAL;
> +}
> +
> +/**
> + * simple_fpga_bus_put_bridges - release references for the fpga bridges
> + * @priv: simple fpga bus private data
> + */
> +static void simple_fpga_bus_put_bridges(struct simple_fpga_bus *priv)
> +{
> +	int i;
> +
> +	for (i = 0; i < priv->num_bridges; i++)
> +		fpga_bridge_put(priv->bridges[i]);
> +
> +	kfree(priv->bridges);
> +	priv->num_bridges = 0;
> +}
> +
> +/**
> + * simple_fpga_bus_probe - Probe function for simple fpga bus.
> + * @pdev: platform device
> + *
> + * Do the necessary steps to program the FPGA and enable associated bridges.
> + * Then populate the device tree below this bus to get drivers probed for the
> + * hardware that is on the FPGA.
> + *
> + * Return: 0 on success, negative error code otherwise.
> + */
> +static int simple_fpga_bus_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *np = dev->of_node;
> +	struct simple_fpga_bus *priv;
> +	struct fpga_manager *mgr;
> +	int ret;
> +
> +	pr_err("%s line %d\n", __func__, __LINE__);

Debugging residue, I guess, please remove.

> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +
> +	/*
> +	 * If simple_fpga_bus_get_mgr returns a negative error, the fpga
> +	 * manager may not have probed yet.
> +	 */
> +	mgr = simple_fpga_bus_get_mgr(priv);
> +	if (IS_ERR(mgr))
> +		return -EPROBE_DEFER;
> +
> +	if (mgr) {
> +		ret = simple_fpga_bus_get_bridges(priv);
> +		if (ret) {
> +			ret = -EPROBE_DEFER;
> +			goto err_release_mgr;
> +		}
> +
> +		ret = simple_fpga_bus_bridge_disable(priv);
> +		if (ret)
> +			goto err_release_br;
> +
> +		ret = simple_fpga_bus_load_image(priv, mgr);
> +		if (ret)
> +			goto err_release_br;
> +
> +		ret = simple_fpga_bus_bridge_enable(priv);
> +		if (ret)
> +			goto err_release_br;
> +
> +		fpga_mgr_put(mgr);
> +	}
> +
> +	of_platform_populate(np, of_default_bus_match_table, NULL, dev);
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	return 0;
> +
> +err_release_br:
> +	simple_fpga_bus_put_bridges(priv);
> +err_release_mgr:
> +	fpga_mgr_put(mgr);
> +
> +	return ret;
> +}
> +
> +static int simple_fpga_bus_remove(struct platform_device *pdev)
> +{
> +	struct simple_fpga_bus *priv = platform_get_drvdata(pdev);
> +
> +	simple_fpga_bus_bridge_disable(priv);
> +	simple_fpga_bus_put_bridges(priv);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id simple_fpga_bus_of_match[] = {
> +	{ .compatible = "simple-fpga-bus", },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, simple_fpga_bus_of_match);
> +
> +static struct platform_driver simple_fpga_bus_driver = {
> +	.probe = simple_fpga_bus_probe,
> +	.remove = simple_fpga_bus_remove,
> +	.driver = {
> +		.name	= "simple-fpga-bus",
> +		.owner	= THIS_MODULE,
> +		.of_match_table = of_match_ptr(simple_fpga_bus_of_match),
> +	},
> +};
> +
> +static int __init simple_fpga_bus_init(void)
> +{
> +	return platform_driver_register(&simple_fpga_bus_driver);
> +}
> +
> +static void __exit simple_fpga_bus_exit(void)
> +{
> +	platform_driver_unregister(&simple_fpga_bus_driver);
> +}
> +
> +module_init(simple_fpga_bus_init);
> +module_exit(simple_fpga_bus_exit);
> +
> +MODULE_DESCRIPTION("Simple FPGA Bus");
> +MODULE_AUTHOR("Alan Tull <atull@xxxxxxxxxxxxxxxxxxxxx>");
> +MODULE_LICENSE("GPL v2");

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux