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 #define FREEZE_CSR_OFFICIAL_VERSION 0xad000003 32 33 #define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0) 34 #define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1) 35 36 #define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0) 37 #define FREEZE_CSR_CTRL_RESET_REQ BIT(1) 38 #define FREEZE_CSR_CTRL_UNFREEZE_REQ BIT(2) 39 40 #define FREEZE_BRIDGE_NAME "freeze" 41 42 struct altera_freeze_br_data { 43 struct device *dev; 44 void __iomem *base_addr; 45 bool enable; 46 }; 47 48 /* 49 * Poll status until status bit is set or we have a timeout. 50 */ 51 static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv, 52 u32 timeout, u32 req_ack) 53 { 54 struct device *dev = priv->dev; 55 void __iomem *csr_illegal_req_addr = priv->base_addr + 56 FREEZE_CSR_ILLEGAL_REQ_OFFSET; 57 u32 status, illegal, ctrl; 58 int ret = -ETIMEDOUT; 59 60 do { 61 illegal = readl(csr_illegal_req_addr); 62 if (illegal) { 63 dev_err(dev, "illegal request detected 0x%x", illegal); 64 65 writel(1, csr_illegal_req_addr); 66 67 illegal = readl(csr_illegal_req_addr); 68 if (illegal) 69 dev_err(dev, "illegal request not cleared 0x%x", 70 illegal); 71 72 ret = -EINVAL; 73 break; 74 } 75 76 status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 77 dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack); 78 status &= req_ack; 79 if (status) { 80 ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET); 81 dev_dbg(dev, "%s request %x acknowledged %x %x\n", 82 __func__, req_ack, status, ctrl); 83 ret = 0; 84 break; 85 } 86 87 udelay(1); 88 } while (timeout--); 89 90 if (ret == -ETIMEDOUT) 91 dev_err(dev, "%s timeout waiting for 0x%x\n", 92 __func__, req_ack); 93 94 return ret; 95 } 96 97 static int altera_freeze_br_do_freeze(struct altera_freeze_br_data *priv, 98 u32 timeout) 99 { 100 struct device *dev = priv->dev; 101 void __iomem *csr_ctrl_addr = priv->base_addr + 102 FREEZE_CSR_CTRL_OFFSET; 103 u32 status; 104 int ret; 105 106 status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 107 108 dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 109 110 if (status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE) { 111 dev_dbg(dev, "%s bridge already disabled %d\n", 112 __func__, status); 113 return 0; 114 } else if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)) { 115 dev_err(dev, "%s bridge not enabled %d\n", __func__, status); 116 return -EINVAL; 117 } 118 119 writel(FREEZE_CSR_CTRL_FREEZE_REQ, csr_ctrl_addr); 120 121 ret = altera_freeze_br_req_ack(priv, timeout, 122 FREEZE_CSR_STATUS_FREEZE_REQ_DONE); 123 124 if (ret) 125 writel(0, csr_ctrl_addr); 126 else 127 writel(FREEZE_CSR_CTRL_RESET_REQ, csr_ctrl_addr); 128 129 return ret; 130 } 131 132 static int altera_freeze_br_do_unfreeze(struct altera_freeze_br_data *priv, 133 u32 timeout) 134 { 135 struct device *dev = priv->dev; 136 void __iomem *csr_ctrl_addr = priv->base_addr + 137 FREEZE_CSR_CTRL_OFFSET; 138 u32 status; 139 int ret; 140 141 writel(0, csr_ctrl_addr); 142 143 status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 144 145 dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 146 147 if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) { 148 dev_dbg(dev, "%s bridge already enabled %d\n", 149 __func__, status); 150 return 0; 151 } else if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE)) { 152 dev_err(dev, "%s bridge not frozen %d\n", __func__, status); 153 return -EINVAL; 154 } 155 156 writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, csr_ctrl_addr); 157 158 ret = altera_freeze_br_req_ack(priv, timeout, 159 FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE); 160 161 status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET); 162 163 dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr)); 164 165 writel(0, csr_ctrl_addr); 166 167 return ret; 168 } 169 170 /* 171 * enable = 1 : allow traffic through the bridge 172 * enable = 0 : disable traffic through the bridge 173 */ 174 static int altera_freeze_br_enable_set(struct fpga_bridge *bridge, 175 bool enable) 176 { 177 struct altera_freeze_br_data *priv = bridge->priv; 178 struct fpga_image_info *info = bridge->info; 179 u32 timeout = 0; 180 int ret; 181 182 if (enable) { 183 if (info) 184 timeout = info->enable_timeout_us; 185 186 ret = altera_freeze_br_do_unfreeze(bridge->priv, timeout); 187 } else { 188 if (info) 189 timeout = info->disable_timeout_us; 190 191 ret = altera_freeze_br_do_freeze(bridge->priv, timeout); 192 } 193 194 if (!ret) 195 priv->enable = enable; 196 197 return ret; 198 } 199 200 static int altera_freeze_br_enable_show(struct fpga_bridge *bridge) 201 { 202 struct altera_freeze_br_data *priv = bridge->priv; 203 204 return priv->enable; 205 } 206 207 static const struct fpga_bridge_ops altera_freeze_br_br_ops = { 208 .enable_set = altera_freeze_br_enable_set, 209 .enable_show = altera_freeze_br_enable_show, 210 }; 211 212 static const struct of_device_id altera_freeze_br_of_match[] = { 213 { .compatible = "altr,freeze-bridge-controller", }, 214 {}, 215 }; 216 MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match); 217 218 static int altera_freeze_br_probe(struct platform_device *pdev) 219 { 220 struct device *dev = &pdev->dev; 221 struct device_node *np = pdev->dev.of_node; 222 void __iomem *base_addr; 223 struct altera_freeze_br_data *priv; 224 struct resource *res; 225 u32 status, revision; 226 227 if (!np) 228 return -ENODEV; 229 230 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 231 base_addr = devm_ioremap_resource(dev, res); 232 if (IS_ERR(base_addr)) 233 return PTR_ERR(base_addr); 234 235 revision = readl(base_addr + FREEZE_CSR_REG_VERSION); 236 if ((revision != FREEZE_CSR_SUPPORTED_VERSION) && 237 (revision != FREEZE_CSR_OFFICIAL_VERSION)) { 238 dev_err(dev, 239 "%s unexpected revision 0x%x != 0x%x != 0x%x\n", 240 __func__, revision, FREEZE_CSR_SUPPORTED_VERSION, 241 FREEZE_CSR_OFFICIAL_VERSION); 242 return -EINVAL; 243 } 244 245 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 246 if (!priv) 247 return -ENOMEM; 248 249 priv->dev = dev; 250 251 status = readl(base_addr + FREEZE_CSR_STATUS_OFFSET); 252 if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) 253 priv->enable = 1; 254 255 priv->base_addr = base_addr; 256 257 return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME, 258 &altera_freeze_br_br_ops, priv); 259 } 260 261 static int altera_freeze_br_remove(struct platform_device *pdev) 262 { 263 fpga_bridge_unregister(&pdev->dev); 264 265 return 0; 266 } 267 268 static struct platform_driver altera_freeze_br_driver = { 269 .probe = altera_freeze_br_probe, 270 .remove = altera_freeze_br_remove, 271 .driver = { 272 .name = "altera_freeze_br", 273 .of_match_table = of_match_ptr(altera_freeze_br_of_match), 274 }, 275 }; 276 277 module_platform_driver(altera_freeze_br_driver); 278 279 MODULE_DESCRIPTION("Altera Freeze Bridge"); 280 MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>"); 281 MODULE_LICENSE("GPL v2"); 282