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