Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Technologic Systems TS-73xx SBC FPGA loader
0004  *
0005  * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com>
0006  *
0007  * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on
0008  * TS-7300, heavily based on load_fpga.c in their vendor tree.
0009  */
0010 
0011 #include <linux/delay.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/string.h>
0016 #include <linux/iopoll.h>
0017 #include <linux/fpga/fpga-mgr.h>
0018 
0019 #define TS73XX_FPGA_DATA_REG        0
0020 #define TS73XX_FPGA_CONFIG_REG      1
0021 
0022 #define TS73XX_FPGA_WRITE_DONE      0x1
0023 #define TS73XX_FPGA_WRITE_DONE_TIMEOUT  1000    /* us */
0024 #define TS73XX_FPGA_RESET       0x2
0025 #define TS73XX_FPGA_RESET_LOW_DELAY 30  /* us */
0026 #define TS73XX_FPGA_RESET_HIGH_DELAY    80  /* us */
0027 #define TS73XX_FPGA_LOAD_OK     0x4
0028 #define TS73XX_FPGA_CONFIG_LOAD     0x8
0029 
0030 struct ts73xx_fpga_priv {
0031     void __iomem    *io_base;
0032     struct device   *dev;
0033 };
0034 
0035 static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
0036                   struct fpga_image_info *info,
0037                   const char *buf, size_t count)
0038 {
0039     struct ts73xx_fpga_priv *priv = mgr->priv;
0040 
0041     /* Reset the FPGA */
0042     writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0043     udelay(TS73XX_FPGA_RESET_LOW_DELAY);
0044     writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0045     udelay(TS73XX_FPGA_RESET_HIGH_DELAY);
0046 
0047     return 0;
0048 }
0049 
0050 static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf,
0051                  size_t count)
0052 {
0053     struct ts73xx_fpga_priv *priv = mgr->priv;
0054     size_t i = 0;
0055     int ret;
0056     u8 reg;
0057 
0058     while (count--) {
0059         ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG,
0060                      reg, !(reg & TS73XX_FPGA_WRITE_DONE),
0061                      1, TS73XX_FPGA_WRITE_DONE_TIMEOUT);
0062         if (ret < 0)
0063             return ret;
0064 
0065         writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG);
0066         i++;
0067     }
0068 
0069     return 0;
0070 }
0071 
0072 static int ts73xx_fpga_write_complete(struct fpga_manager *mgr,
0073                       struct fpga_image_info *info)
0074 {
0075     struct ts73xx_fpga_priv *priv = mgr->priv;
0076     u8 reg;
0077 
0078     usleep_range(1000, 2000);
0079     reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0080     reg |= TS73XX_FPGA_CONFIG_LOAD;
0081     writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0082 
0083     usleep_range(1000, 2000);
0084     reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0085     reg &= ~TS73XX_FPGA_CONFIG_LOAD;
0086     writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0087 
0088     reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0089     if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK)
0090         return -ETIMEDOUT;
0091 
0092     return 0;
0093 }
0094 
0095 static const struct fpga_manager_ops ts73xx_fpga_ops = {
0096     .write_init = ts73xx_fpga_write_init,
0097     .write      = ts73xx_fpga_write,
0098     .write_complete = ts73xx_fpga_write_complete,
0099 };
0100 
0101 static int ts73xx_fpga_probe(struct platform_device *pdev)
0102 {
0103     struct device *kdev = &pdev->dev;
0104     struct ts73xx_fpga_priv *priv;
0105     struct fpga_manager *mgr;
0106     struct resource *res;
0107 
0108     priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
0109     if (!priv)
0110         return -ENOMEM;
0111 
0112     priv->dev = kdev;
0113 
0114     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0115     priv->io_base = devm_ioremap_resource(kdev, res);
0116     if (IS_ERR(priv->io_base))
0117         return PTR_ERR(priv->io_base);
0118 
0119     mgr = devm_fpga_mgr_register(kdev, "TS-73xx FPGA Manager",
0120                      &ts73xx_fpga_ops, priv);
0121     return PTR_ERR_OR_ZERO(mgr);
0122 }
0123 
0124 static struct platform_driver ts73xx_fpga_driver = {
0125     .driver = {
0126         .name   = "ts73xx-fpga-mgr",
0127     },
0128     .probe  = ts73xx_fpga_probe,
0129 };
0130 module_platform_driver(ts73xx_fpga_driver);
0131 
0132 MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
0133 MODULE_DESCRIPTION("TS-73xx FPGA Manager driver");
0134 MODULE_LICENSE("GPL v2");