root/drivers/fpga/altera-freeze-bridge.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. altera_freeze_br_req_ack
  2. altera_freeze_br_do_freeze
  3. altera_freeze_br_do_unfreeze
  4. altera_freeze_br_enable_set
  5. altera_freeze_br_enable_show
  6. altera_freeze_br_probe
  7. altera_freeze_br_remove

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

/* [<][>][^][v][top][bottom][index][help] */