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