Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fpga: Add support for Xilinx LogiCORE PR Decoupler

This adds support for the Xilinx LogiCORE PR Decoupler
soft-ip that does decoupling of PR regions in the FPGA
fabric during partial reconfiguration.

Signed-off-by: Moritz Fischer <mdf@kernel.org>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Cc: Sören Brinkmann <soren.brinkmann@xilinx.com>
Cc: linux-kernel@vger.kernel.org
Cc: devicetree@vger.kernel.org
Acked-by: Alan Tull <atull@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Moritz Fischer and committed by
Greg Kroah-Hartman
7e961c12 00846a44

+172
+10
drivers/fpga/Kconfig
··· 95 95 Platform driver support for Altera Partial Reconfiguration IP 96 96 component 97 97 98 + config XILINX_PR_DECOUPLER 99 + tristate "Xilinx LogiCORE PR Decoupler" 100 + depends on FPGA_BRIDGE 101 + depends on HAS_IOMEM 102 + help 103 + Say Y to enable drivers for Xilinx LogiCORE PR Decoupler. 104 + The PR Decoupler exists in the FPGA fabric to isolate one 105 + region of the FPGA from the busses while that region is 106 + being reprogrammed during partial reconfig. 107 + 98 108 endif # FPGA 99 109 100 110 endmenu
+1
drivers/fpga/Makefile
··· 19 19 obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o 20 20 obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o 21 21 obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o 22 + obj-$(CONFIG_XILINX_PR_DECOUPLER) += xilinx-pr-decoupler.o 22 23 23 24 # High Level Interfaces 24 25 obj-$(CONFIG_FPGA_REGION) += fpga-region.o
+161
drivers/fpga/xilinx-pr-decoupler.c
··· 1 + /* 2 + * Copyright (c) 2017, National Instruments Corp. 3 + * Copyright (c) 2017, Xilix Inc 4 + * 5 + * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration 6 + * Decoupler IP Core. 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; version 2 of the License. 11 + * 12 + * This program is distributed in the hope that it will be useful, 13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 + * GNU General Public License for more details. 16 + */ 17 + 18 + #include <linux/clk.h> 19 + #include <linux/io.h> 20 + #include <linux/kernel.h> 21 + #include <linux/of_device.h> 22 + #include <linux/module.h> 23 + #include <linux/fpga/fpga-bridge.h> 24 + 25 + #define CTRL_CMD_DECOUPLE BIT(0) 26 + #define CTRL_CMD_COUPLE 0 27 + #define CTRL_OFFSET 0 28 + 29 + struct xlnx_pr_decoupler_data { 30 + void __iomem *io_base; 31 + struct clk *clk; 32 + }; 33 + 34 + static inline void xlnx_pr_decoupler_write(struct xlnx_pr_decoupler_data *d, 35 + u32 offset, u32 val) 36 + { 37 + writel(val, d->io_base + offset); 38 + } 39 + 40 + static inline u32 xlnx_pr_decouple_read(const struct xlnx_pr_decoupler_data *d, 41 + u32 offset) 42 + { 43 + return readl(d->io_base + offset); 44 + } 45 + 46 + static int xlnx_pr_decoupler_enable_set(struct fpga_bridge *bridge, bool enable) 47 + { 48 + int err; 49 + struct xlnx_pr_decoupler_data *priv = bridge->priv; 50 + 51 + err = clk_enable(priv->clk); 52 + if (err) 53 + return err; 54 + 55 + if (enable) 56 + xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_COUPLE); 57 + else 58 + xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_DECOUPLE); 59 + 60 + clk_disable(priv->clk); 61 + 62 + return 0; 63 + } 64 + 65 + static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge) 66 + { 67 + const struct xlnx_pr_decoupler_data *priv = bridge->priv; 68 + u32 status; 69 + int err; 70 + 71 + err = clk_enable(priv->clk); 72 + if (err) 73 + return err; 74 + 75 + status = readl(priv->io_base); 76 + 77 + clk_disable(priv->clk); 78 + 79 + return !status; 80 + } 81 + 82 + static struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = { 83 + .enable_set = xlnx_pr_decoupler_enable_set, 84 + .enable_show = xlnx_pr_decoupler_enable_show, 85 + }; 86 + 87 + static const struct of_device_id xlnx_pr_decoupler_of_match[] = { 88 + { .compatible = "xlnx,pr-decoupler-1.00", }, 89 + { .compatible = "xlnx,pr-decoupler", }, 90 + {}, 91 + }; 92 + MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match); 93 + 94 + static int xlnx_pr_decoupler_probe(struct platform_device *pdev) 95 + { 96 + struct xlnx_pr_decoupler_data *priv; 97 + int err; 98 + struct resource *res; 99 + 100 + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 101 + if (!priv) 102 + return -ENOMEM; 103 + 104 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 105 + priv->io_base = devm_ioremap_resource(&pdev->dev, res); 106 + if (IS_ERR(priv->io_base)) 107 + return PTR_ERR(priv->io_base); 108 + 109 + priv->clk = devm_clk_get(&pdev->dev, "aclk"); 110 + if (IS_ERR(priv->clk)) { 111 + dev_err(&pdev->dev, "input clock not found\n"); 112 + return PTR_ERR(priv->clk); 113 + } 114 + 115 + err = clk_prepare_enable(priv->clk); 116 + if (err) { 117 + dev_err(&pdev->dev, "unable to enable clock\n"); 118 + return err; 119 + } 120 + 121 + clk_disable(priv->clk); 122 + 123 + err = fpga_bridge_register(&pdev->dev, "Xilinx PR Decoupler", 124 + &xlnx_pr_decoupler_br_ops, priv); 125 + 126 + if (err) { 127 + dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler"); 128 + clk_unprepare(priv->clk); 129 + return err; 130 + } 131 + 132 + return 0; 133 + } 134 + 135 + static int xlnx_pr_decoupler_remove(struct platform_device *pdev) 136 + { 137 + struct fpga_bridge *bridge = platform_get_drvdata(pdev); 138 + struct xlnx_pr_decoupler_data *p = bridge->priv; 139 + 140 + fpga_bridge_unregister(&pdev->dev); 141 + 142 + clk_unprepare(p->clk); 143 + 144 + return 0; 145 + } 146 + 147 + static struct platform_driver xlnx_pr_decoupler_driver = { 148 + .probe = xlnx_pr_decoupler_probe, 149 + .remove = xlnx_pr_decoupler_remove, 150 + .driver = { 151 + .name = "xlnx_pr_decoupler", 152 + .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match), 153 + }, 154 + }; 155 + 156 + module_platform_driver(xlnx_pr_decoupler_driver); 157 + 158 + MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler"); 159 + MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>"); 160 + MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>"); 161 + MODULE_LICENSE("GPL v2");