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

fpga: add altera freeze bridge support

Add a low level driver for Altera Freeze Bridges to the FPGA Bridge
framework. A freeze bridge is a bridge that exists in the FPGA
fabric to isolate one region of the FPGA from the busses while that
one region is being reprogrammed.

Signed-off-by: Alan Tull <atull@opensource.altera.com>
Signed-off-by: Matthew Gerlach <mgerlach@opensource.altera.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Alan Tull and committed by
Greg Kroah-Hartman
ca24a648 e5f8efa5

+283
+9
drivers/fpga/Kconfig
··· 47 47 Say Y to enable drivers for FPGA bridges for Altera SOCFPGA 48 48 devices. 49 49 50 + config ALTERA_FREEZE_BRIDGE 51 + tristate "Altera FPGA Freeze Bridge" 52 + depends on ARCH_SOCFPGA && FPGA_BRIDGE 53 + help 54 + Say Y to enable drivers for Altera FPGA Freeze bridges. A 55 + freeze bridge is a bridge that exists in the FPGA fabric to 56 + isolate one region of the FPGA from the busses while that 57 + region is being reprogrammed. 58 + 50 59 endif # FPGA 51 60 52 61 endmenu
+1
drivers/fpga/Makefile
··· 12 12 # FPGA Bridge Drivers 13 13 obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o 14 14 obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o 15 + obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o 15 16 16 17 # High Level Interfaces 17 18 obj-$(CONFIG_FPGA_REGION) += fpga-region.o
+273
drivers/fpga/altera-freeze-bridge.c
··· 1 + /* 2 + * FPGA Freeze Bridge Controller 3 + * 4 + * Copyright (C) 2016 Altera Corporation. All rights reserved. 5 + * 6 + * This program is free software; you can redistribute it and/or modify it 7 + * under the terms and conditions of the GNU General Public License, 8 + * version 2, as published by the Free Software Foundation. 9 + * 10 + * This program is distributed in the hope it will be useful, but WITHOUT 11 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 + * more details. 14 + * 15 + * You should have received a copy of the GNU General Public License along with 16 + * this program. If not, see <http://www.gnu.org/licenses/>. 17 + */ 18 + #include <linux/delay.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 FREEZE_CSR_STATUS_OFFSET 0 26 + #define FREEZE_CSR_CTRL_OFFSET 4 27 + #define FREEZE_CSR_ILLEGAL_REQ_OFFSET 8 28 + #define FREEZE_CSR_REG_VERSION 12 29 + 30 + #define FREEZE_CSR_SUPPORTED_VERSION 2 31 + 32 + #define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) 33 + #define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) 34 + 35 + #define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0) 36 + #define FREEZE_CSR_CTRL_RESET_REQ BIT(1) 37 + #define FREEZE_CSR_CTRL_UNFREEZE_REQ BIT(2) 38 + 39 + #define FREEZE_BRIDGE_NAME "freeze" 40 + 41 + struct altera_freeze_br_data { 42 + struct device *dev; 43 + void __iomem *base_addr; 44 + bool enable; 45 + }; 46 + 47 + /* 48 + * Poll status until status bit is set or we have a timeout. 49 + */ 50 + static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv, 51 + u32 timeout, u32 req_ack) 52 + { 53 + struct device *dev = priv->dev; 54 + void __iomem *csr_illegal_req_addr = priv->base_addr + 55 + FREEZE_CSR_ILLEGAL_REQ_OFFSET; 56 + u32 status, illegal, ctrl; 57 + int ret = -ETIMEDOUT; 58 + 59 + do { 60 + illegal = readl(csr_illegal_req_addr); 61 + if (illegal) { 62 + dev_err(dev, "illegal request detected 0x%x", illegal); 63 + 64 + writel(1, csr_illegal_req_addr); 65 + 66 + illegal = readl(csr_illegal_req_addr); 67 + if (illegal) 68 + dev_err(dev, "illegal request not cleared 0x%x", 69 + illegal); 70 + 71 + ret = -EINVAL; 72 + break; 73 + } 74 + 75 + status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 76 + dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack); 77 + status &= req_ack; 78 + if (status) { 79 + ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET); 80 + dev_dbg(dev, "%s request %x acknowledged %x %x\n", 81 + __func__, req_ack, status, ctrl); 82 + ret = 0; 83 + break; 84 + } 85 + 86 + udelay(1); 87 + } while (timeout--); 88 + 89 + if (ret == -ETIMEDOUT) 90 + dev_err(dev, "%s timeout waiting for 0x%x\n", 91 + __func__, req_ack); 92 + 93 + return ret; 94 + } 95 + 96 + static int altera_freeze_br_do_freeze(struct altera_freeze_br_data *priv, 97 + u32 timeout) 98 + { 99 + struct device *dev = priv->dev; 100 + void __iomem *csr_ctrl_addr = priv->base_addr + 101 + FREEZE_CSR_CTRL_OFFSET; 102 + u32 status; 103 + int ret; 104 + 105 + status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 106 + 107 + dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 108 + 109 + if (status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE) { 110 + dev_dbg(dev, "%s bridge already disabled %d\n", 111 + __func__, status); 112 + return 0; 113 + } else if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)) { 114 + dev_err(dev, "%s bridge not enabled %d\n", __func__, status); 115 + return -EINVAL; 116 + } 117 + 118 + writel(FREEZE_CSR_CTRL_FREEZE_REQ, csr_ctrl_addr); 119 + 120 + ret = altera_freeze_br_req_ack(priv, timeout, 121 + FREEZE_CSR_STATUS_FREEZE_REQ_DONE); 122 + 123 + if (ret) 124 + writel(0, csr_ctrl_addr); 125 + else 126 + writel(FREEZE_CSR_CTRL_RESET_REQ, csr_ctrl_addr); 127 + 128 + return ret; 129 + } 130 + 131 + static int altera_freeze_br_do_unfreeze(struct altera_freeze_br_data *priv, 132 + u32 timeout) 133 + { 134 + struct device *dev = priv->dev; 135 + void __iomem *csr_ctrl_addr = priv->base_addr + 136 + FREEZE_CSR_CTRL_OFFSET; 137 + u32 status; 138 + int ret; 139 + 140 + writel(0, csr_ctrl_addr); 141 + 142 + status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 143 + 144 + dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 145 + 146 + if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) { 147 + dev_dbg(dev, "%s bridge already enabled %d\n", 148 + __func__, status); 149 + return 0; 150 + } else if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE)) { 151 + dev_err(dev, "%s bridge not frozen %d\n", __func__, status); 152 + return -EINVAL; 153 + } 154 + 155 + writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, csr_ctrl_addr); 156 + 157 + ret = altera_freeze_br_req_ack(priv, timeout, 158 + FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE); 159 + 160 + status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 161 + 162 + dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 163 + 164 + writel(0, csr_ctrl_addr); 165 + 166 + return ret; 167 + } 168 + 169 + /* 170 + * enable = 1 : allow traffic through the bridge 171 + * enable = 0 : disable traffic through the bridge 172 + */ 173 + static int altera_freeze_br_enable_set(struct fpga_bridge *bridge, 174 + bool enable) 175 + { 176 + struct altera_freeze_br_data *priv = bridge->priv; 177 + struct fpga_image_info *info = bridge->info; 178 + u32 timeout = 0; 179 + int ret; 180 + 181 + if (enable) { 182 + if (info) 183 + timeout = info->enable_timeout_us; 184 + 185 + ret = altera_freeze_br_do_unfreeze(bridge->priv, timeout); 186 + } else { 187 + if (info) 188 + timeout = info->disable_timeout_us; 189 + 190 + ret = altera_freeze_br_do_freeze(bridge->priv, timeout); 191 + } 192 + 193 + if (!ret) 194 + priv->enable = enable; 195 + 196 + return ret; 197 + } 198 + 199 + static int altera_freeze_br_enable_show(struct fpga_bridge *bridge) 200 + { 201 + struct altera_freeze_br_data *priv = bridge->priv; 202 + 203 + return priv->enable; 204 + } 205 + 206 + static struct fpga_bridge_ops altera_freeze_br_br_ops = { 207 + .enable_set = altera_freeze_br_enable_set, 208 + .enable_show = altera_freeze_br_enable_show, 209 + }; 210 + 211 + static const struct of_device_id altera_freeze_br_of_match[] = { 212 + { .compatible = "altr,freeze-bridge-controller", }, 213 + {}, 214 + }; 215 + MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match); 216 + 217 + static int altera_freeze_br_probe(struct platform_device *pdev) 218 + { 219 + struct device *dev = &pdev->dev; 220 + struct device_node *np = pdev->dev.of_node; 221 + struct altera_freeze_br_data *priv; 222 + struct resource *res; 223 + u32 status, revision; 224 + 225 + if (!np) 226 + return -ENODEV; 227 + 228 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 229 + if (!priv) 230 + return -ENOMEM; 231 + 232 + priv->dev = dev; 233 + 234 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 235 + priv->base_addr = devm_ioremap_resource(dev, res); 236 + if (IS_ERR(priv->base_addr)) 237 + return PTR_ERR(priv->base_addr); 238 + 239 + status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 240 + if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) 241 + priv->enable = 1; 242 + 243 + revision = readl(priv->base_addr + FREEZE_CSR_REG_VERSION); 244 + if (revision != FREEZE_CSR_SUPPORTED_VERSION) 245 + dev_warn(dev, 246 + "%s Freeze Controller unexpected revision %d != %d\n", 247 + __func__, revision, FREEZE_CSR_SUPPORTED_VERSION); 248 + 249 + return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, 250 + &altera_freeze_br_br_ops, priv); 251 + } 252 + 253 + static int altera_freeze_br_remove(struct platform_device *pdev) 254 + { 255 + fpga_bridge_unregister(&pdev->dev); 256 + 257 + return 0; 258 + } 259 + 260 + static struct platform_driver altera_freeze_br_driver = { 261 + .probe = altera_freeze_br_probe, 262 + .remove = altera_freeze_br_remove, 263 + .driver = { 264 + .name = "altera_freeze_br", 265 + .of_match_table = of_match_ptr(altera_freeze_br_of_match), 266 + }, 267 + }; 268 + 269 + module_platform_driver(altera_freeze_br_driver); 270 + 271 + MODULE_DESCRIPTION("Altera Freeze Bridge"); 272 + MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); 273 + MODULE_LICENSE("GPL v2");