linux/drivers/fpga/altera-pr-ip-core.c
<<
>>
Prefs
   1/*
   2 * Driver for Altera Partial Reconfiguration IP Core
   3 *
   4 * Copyright (C) 2016-2017 Intel Corporation
   5 *
   6 * Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation
   7 *  by Alan Tull <atull@opensource.altera.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms and conditions of the GNU General Public License,
  11 * version 2, as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope it will be useful, but WITHOUT
  14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  16 * more details.
  17 *
  18 * You should have received a copy of the GNU General Public License along with
  19 * this program.  If not, see <http://www.gnu.org/licenses/>.
  20 */
  21#include <linux/delay.h>
  22#include <linux/fpga/altera-pr-ip-core.h>
  23#include <linux/fpga/fpga-mgr.h>
  24#include <linux/module.h>
  25
  26#define ALT_PR_DATA_OFST                0x00
  27#define ALT_PR_CSR_OFST                 0x04
  28
  29#define ALT_PR_CSR_PR_START             BIT(0)
  30#define ALT_PR_CSR_STATUS_SFT           2
  31#define ALT_PR_CSR_STATUS_MSK           (7 << ALT_PR_CSR_STATUS_SFT)
  32#define ALT_PR_CSR_STATUS_NRESET        (0 << ALT_PR_CSR_STATUS_SFT)
  33#define ALT_PR_CSR_STATUS_PR_ERR        (1 << ALT_PR_CSR_STATUS_SFT)
  34#define ALT_PR_CSR_STATUS_CRC_ERR       (2 << ALT_PR_CSR_STATUS_SFT)
  35#define ALT_PR_CSR_STATUS_BAD_BITS      (3 << ALT_PR_CSR_STATUS_SFT)
  36#define ALT_PR_CSR_STATUS_PR_IN_PROG    (4 << ALT_PR_CSR_STATUS_SFT)
  37#define ALT_PR_CSR_STATUS_PR_SUCCESS    (5 << ALT_PR_CSR_STATUS_SFT)
  38
  39struct alt_pr_priv {
  40        void __iomem *reg_base;
  41};
  42
  43static enum fpga_mgr_states alt_pr_fpga_state(struct fpga_manager *mgr)
  44{
  45        struct alt_pr_priv *priv = mgr->priv;
  46        const char *err = "unknown";
  47        enum fpga_mgr_states ret = FPGA_MGR_STATE_UNKNOWN;
  48        u32 val;
  49
  50        val = readl(priv->reg_base + ALT_PR_CSR_OFST);
  51
  52        val &= ALT_PR_CSR_STATUS_MSK;
  53
  54        switch (val) {
  55        case ALT_PR_CSR_STATUS_NRESET:
  56                return FPGA_MGR_STATE_RESET;
  57
  58        case ALT_PR_CSR_STATUS_PR_ERR:
  59                err = "pr error";
  60                ret = FPGA_MGR_STATE_WRITE_ERR;
  61                break;
  62
  63        case ALT_PR_CSR_STATUS_CRC_ERR:
  64                err = "crc error";
  65                ret = FPGA_MGR_STATE_WRITE_ERR;
  66                break;
  67
  68        case ALT_PR_CSR_STATUS_BAD_BITS:
  69                err = "bad bits";
  70                ret = FPGA_MGR_STATE_WRITE_ERR;
  71                break;
  72
  73        case ALT_PR_CSR_STATUS_PR_IN_PROG:
  74                return FPGA_MGR_STATE_WRITE;
  75
  76        case ALT_PR_CSR_STATUS_PR_SUCCESS:
  77                return FPGA_MGR_STATE_OPERATING;
  78
  79        default:
  80                break;
  81        }
  82
  83        dev_err(&mgr->dev, "encountered error code %d (%s) in %s()\n",
  84                val, err, __func__);
  85        return ret;
  86}
  87
  88static int alt_pr_fpga_write_init(struct fpga_manager *mgr,
  89                                  struct fpga_image_info *info,
  90                                  const char *buf, size_t count)
  91{
  92        struct alt_pr_priv *priv = mgr->priv;
  93        u32 val;
  94
  95        if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
  96                dev_err(&mgr->dev, "%s Partial Reconfiguration flag not set\n",
  97                        __func__);
  98                return -EINVAL;
  99        }
 100
 101        val = readl(priv->reg_base + ALT_PR_CSR_OFST);
 102
 103        if (val & ALT_PR_CSR_PR_START) {
 104                dev_err(&mgr->dev,
 105                        "%s Partial Reconfiguration already started\n",
 106                       __func__);
 107                return -EINVAL;
 108        }
 109
 110        writel(val | ALT_PR_CSR_PR_START, priv->reg_base + ALT_PR_CSR_OFST);
 111
 112        return 0;
 113}
 114
 115static int alt_pr_fpga_write(struct fpga_manager *mgr, const char *buf,
 116                             size_t count)
 117{
 118        struct alt_pr_priv *priv = mgr->priv;
 119        u32 *buffer_32 = (u32 *)buf;
 120        size_t i = 0;
 121
 122        if (count <= 0)
 123                return -EINVAL;
 124
 125        /* Write out the complete 32-bit chunks */
 126        while (count >= sizeof(u32)) {
 127                writel(buffer_32[i++], priv->reg_base);
 128                count -= sizeof(u32);
 129        }
 130
 131        /* Write out remaining non 32-bit chunks */
 132        switch (count) {
 133        case 3:
 134                writel(buffer_32[i++] & 0x00ffffff, priv->reg_base);
 135                break;
 136        case 2:
 137                writel(buffer_32[i++] & 0x0000ffff, priv->reg_base);
 138                break;
 139        case 1:
 140                writel(buffer_32[i++] & 0x000000ff, priv->reg_base);
 141                break;
 142        case 0:
 143                break;
 144        default:
 145                /* This will never happen */
 146                return -EFAULT;
 147        }
 148
 149        if (alt_pr_fpga_state(mgr) == FPGA_MGR_STATE_WRITE_ERR)
 150                return -EIO;
 151
 152        return 0;
 153}
 154
 155static int alt_pr_fpga_write_complete(struct fpga_manager *mgr,
 156                                      struct fpga_image_info *info)
 157{
 158        u32 i = 0;
 159
 160        do {
 161                switch (alt_pr_fpga_state(mgr)) {
 162                case FPGA_MGR_STATE_WRITE_ERR:
 163                        return -EIO;
 164
 165                case FPGA_MGR_STATE_OPERATING:
 166                        dev_info(&mgr->dev,
 167                                 "successful partial reconfiguration\n");
 168                        return 0;
 169
 170                default:
 171                        break;
 172                }
 173                udelay(1);
 174        } while (info->config_complete_timeout_us > i++);
 175
 176        dev_err(&mgr->dev, "timed out waiting for write to complete\n");
 177        return -ETIMEDOUT;
 178}
 179
 180static const struct fpga_manager_ops alt_pr_ops = {
 181        .state = alt_pr_fpga_state,
 182        .write_init = alt_pr_fpga_write_init,
 183        .write = alt_pr_fpga_write,
 184        .write_complete = alt_pr_fpga_write_complete,
 185};
 186
 187int alt_pr_register(struct device *dev, void __iomem *reg_base)
 188{
 189        struct alt_pr_priv *priv;
 190        u32 val;
 191
 192        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 193        if (!priv)
 194                return -ENOMEM;
 195
 196        priv->reg_base = reg_base;
 197
 198        val = readl(priv->reg_base + ALT_PR_CSR_OFST);
 199
 200        dev_dbg(dev, "%s status=%d start=%d\n", __func__,
 201                (val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT,
 202                (int)(val & ALT_PR_CSR_PR_START));
 203
 204        return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv);
 205}
 206EXPORT_SYMBOL_GPL(alt_pr_register);
 207
 208int alt_pr_unregister(struct device *dev)
 209{
 210        dev_dbg(dev, "%s\n", __func__);
 211
 212        fpga_mgr_unregister(dev);
 213
 214        return 0;
 215}
 216EXPORT_SYMBOL_GPL(alt_pr_unregister);
 217
 218MODULE_AUTHOR("Matthew Gerlach <matthew.gerlach@linux.intel.com>");
 219MODULE_DESCRIPTION("Altera Partial Reconfiguration IP Core");
 220MODULE_LICENSE("GPL v2");
 221