Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for Altera Partial Reconfiguration IP Core
0004  *
0005  * Copyright (C) 2016-2017 Intel Corporation
0006  *
0007  * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation
0008  *  by Alan Tull <atull@opensource.altera.com>
0009  */
0010 #include <linux/delay.h>
0011 #include <linux/fpga/altera-pr-ip-core.h>
0012 #include <linux/fpga/fpga-mgr.h>
0013 #include <linux/module.h>
0014 
0015 #define ALT_PR_DATA_OFST        0x00
0016 #define ALT_PR_CSR_OFST         0x04
0017 
0018 #define ALT_PR_CSR_PR_START     BIT(0)
0019 #define ALT_PR_CSR_STATUS_SFT       2
0020 #define ALT_PR_CSR_STATUS_MSK       (7 << ALT_PR_CSR_STATUS_SFT)
0021 #define ALT_PR_CSR_STATUS_NRESET    (0 << ALT_PR_CSR_STATUS_SFT)
0022 #define ALT_PR_CSR_STATUS_PR_ERR    (1 << ALT_PR_CSR_STATUS_SFT)
0023 #define ALT_PR_CSR_STATUS_CRC_ERR   (2 << ALT_PR_CSR_STATUS_SFT)
0024 #define ALT_PR_CSR_STATUS_BAD_BITS  (3 << ALT_PR_CSR_STATUS_SFT)
0025 #define ALT_PR_CSR_STATUS_PR_IN_PROG    (4 << ALT_PR_CSR_STATUS_SFT)
0026 #define ALT_PR_CSR_STATUS_PR_SUCCESS    (5 << ALT_PR_CSR_STATUS_SFT)
0027 
0028 struct alt_pr_priv {
0029     void __iomem *reg_base;
0030 };
0031 
0032 static enum fpga_mgr_states alt_pr_fpga_state(struct fpga_manager *mgr)
0033 {
0034     struct alt_pr_priv *priv = mgr->priv;
0035     const char *err = "unknown";
0036     enum fpga_mgr_states ret = FPGA_MGR_STATE_UNKNOWN;
0037     u32 val;
0038 
0039     val = readl(priv->reg_base + ALT_PR_CSR_OFST);
0040 
0041     val &= ALT_PR_CSR_STATUS_MSK;
0042 
0043     switch (val) {
0044     case ALT_PR_CSR_STATUS_NRESET:
0045         return FPGA_MGR_STATE_RESET;
0046 
0047     case ALT_PR_CSR_STATUS_PR_ERR:
0048         err = "pr error";
0049         ret = FPGA_MGR_STATE_WRITE_ERR;
0050         break;
0051 
0052     case ALT_PR_CSR_STATUS_CRC_ERR:
0053         err = "crc error";
0054         ret = FPGA_MGR_STATE_WRITE_ERR;
0055         break;
0056 
0057     case ALT_PR_CSR_STATUS_BAD_BITS:
0058         err = "bad bits";
0059         ret = FPGA_MGR_STATE_WRITE_ERR;
0060         break;
0061 
0062     case ALT_PR_CSR_STATUS_PR_IN_PROG:
0063         return FPGA_MGR_STATE_WRITE;
0064 
0065     case ALT_PR_CSR_STATUS_PR_SUCCESS:
0066         return FPGA_MGR_STATE_OPERATING;
0067 
0068     default:
0069         break;
0070     }
0071 
0072     dev_err(&mgr->dev, "encountered error code %d (%s) in %s()\n",
0073         val, err, __func__);
0074     return ret;
0075 }
0076 
0077 static int alt_pr_fpga_write_init(struct fpga_manager *mgr,
0078                   struct fpga_image_info *info,
0079                   const char *buf, size_t count)
0080 {
0081     struct alt_pr_priv *priv = mgr->priv;
0082     u32 val;
0083 
0084     if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
0085         dev_err(&mgr->dev, "%s Partial Reconfiguration flag not set\n",
0086             __func__);
0087         return -EINVAL;
0088     }
0089 
0090     val = readl(priv->reg_base + ALT_PR_CSR_OFST);
0091 
0092     if (val & ALT_PR_CSR_PR_START) {
0093         dev_err(&mgr->dev,
0094             "%s Partial Reconfiguration already started\n",
0095                __func__);
0096         return -EINVAL;
0097     }
0098 
0099     writel(val | ALT_PR_CSR_PR_START, priv->reg_base + ALT_PR_CSR_OFST);
0100 
0101     return 0;
0102 }
0103 
0104 static int alt_pr_fpga_write(struct fpga_manager *mgr, const char *buf,
0105                  size_t count)
0106 {
0107     struct alt_pr_priv *priv = mgr->priv;
0108     u32 *buffer_32 = (u32 *)buf;
0109     size_t i = 0;
0110 
0111     if (!count)
0112         return -EINVAL;
0113 
0114     /* Write out the complete 32-bit chunks */
0115     while (count >= sizeof(u32)) {
0116         writel(buffer_32[i++], priv->reg_base);
0117         count -= sizeof(u32);
0118     }
0119 
0120     /* Write out remaining non 32-bit chunks */
0121     switch (count) {
0122     case 3:
0123         writel(buffer_32[i++] & 0x00ffffff, priv->reg_base);
0124         break;
0125     case 2:
0126         writel(buffer_32[i++] & 0x0000ffff, priv->reg_base);
0127         break;
0128     case 1:
0129         writel(buffer_32[i++] & 0x000000ff, priv->reg_base);
0130         break;
0131     case 0:
0132         break;
0133     default:
0134         /* This will never happen */
0135         return -EFAULT;
0136     }
0137 
0138     if (alt_pr_fpga_state(mgr) == FPGA_MGR_STATE_WRITE_ERR)
0139         return -EIO;
0140 
0141     return 0;
0142 }
0143 
0144 static int alt_pr_fpga_write_complete(struct fpga_manager *mgr,
0145                       struct fpga_image_info *info)
0146 {
0147     u32 i = 0;
0148 
0149     do {
0150         switch (alt_pr_fpga_state(mgr)) {
0151         case FPGA_MGR_STATE_WRITE_ERR:
0152             return -EIO;
0153 
0154         case FPGA_MGR_STATE_OPERATING:
0155             dev_info(&mgr->dev,
0156                  "successful partial reconfiguration\n");
0157             return 0;
0158 
0159         default:
0160             break;
0161         }
0162         udelay(1);
0163     } while (info->config_complete_timeout_us > i++);
0164 
0165     dev_err(&mgr->dev, "timed out waiting for write to complete\n");
0166     return -ETIMEDOUT;
0167 }
0168 
0169 static const struct fpga_manager_ops alt_pr_ops = {
0170     .state = alt_pr_fpga_state,
0171     .write_init = alt_pr_fpga_write_init,
0172     .write = alt_pr_fpga_write,
0173     .write_complete = alt_pr_fpga_write_complete,
0174 };
0175 
0176 int alt_pr_register(struct device *dev, void __iomem *reg_base)
0177 {
0178     struct alt_pr_priv *priv;
0179     struct fpga_manager *mgr;
0180     u32 val;
0181 
0182     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0183     if (!priv)
0184         return -ENOMEM;
0185 
0186     priv->reg_base = reg_base;
0187 
0188     val = readl(priv->reg_base + ALT_PR_CSR_OFST);
0189 
0190     dev_dbg(dev, "%s status=%d start=%d\n", __func__,
0191         (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT,
0192         (int)(val & ALT_PR_CSR_PR_START));
0193 
0194     mgr = devm_fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv);
0195     return PTR_ERR_OR_ZERO(mgr);
0196 }
0197 EXPORT_SYMBOL_GPL(alt_pr_register);
0198 
0199 MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>");
0200 MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Core");
0201 MODULE_LICENSE("GPL v2");