cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ts73xx-fpga.c (3510B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Technologic Systems TS-73xx SBC FPGA loader
      4 *
      5 * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com>
      6 *
      7 * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on
      8 * TS-7300, heavily based on load_fpga.c in their vendor tree.
      9 */
     10
     11#include <linux/delay.h>
     12#include <linux/io.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15#include <linux/string.h>
     16#include <linux/iopoll.h>
     17#include <linux/fpga/fpga-mgr.h>
     18
     19#define TS73XX_FPGA_DATA_REG		0
     20#define TS73XX_FPGA_CONFIG_REG		1
     21
     22#define TS73XX_FPGA_WRITE_DONE		0x1
     23#define TS73XX_FPGA_WRITE_DONE_TIMEOUT	1000	/* us */
     24#define TS73XX_FPGA_RESET		0x2
     25#define TS73XX_FPGA_RESET_LOW_DELAY	30	/* us */
     26#define TS73XX_FPGA_RESET_HIGH_DELAY	80	/* us */
     27#define TS73XX_FPGA_LOAD_OK		0x4
     28#define TS73XX_FPGA_CONFIG_LOAD		0x8
     29
     30struct ts73xx_fpga_priv {
     31	void __iomem	*io_base;
     32	struct device	*dev;
     33};
     34
     35static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
     36				  struct fpga_image_info *info,
     37				  const char *buf, size_t count)
     38{
     39	struct ts73xx_fpga_priv *priv = mgr->priv;
     40
     41	/* Reset the FPGA */
     42	writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG);
     43	udelay(TS73XX_FPGA_RESET_LOW_DELAY);
     44	writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG);
     45	udelay(TS73XX_FPGA_RESET_HIGH_DELAY);
     46
     47	return 0;
     48}
     49
     50static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf,
     51			     size_t count)
     52{
     53	struct ts73xx_fpga_priv *priv = mgr->priv;
     54	size_t i = 0;
     55	int ret;
     56	u8 reg;
     57
     58	while (count--) {
     59		ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG,
     60					 reg, !(reg & TS73XX_FPGA_WRITE_DONE),
     61					 1, TS73XX_FPGA_WRITE_DONE_TIMEOUT);
     62		if (ret < 0)
     63			return ret;
     64
     65		writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG);
     66		i++;
     67	}
     68
     69	return 0;
     70}
     71
     72static int ts73xx_fpga_write_complete(struct fpga_manager *mgr,
     73				      struct fpga_image_info *info)
     74{
     75	struct ts73xx_fpga_priv *priv = mgr->priv;
     76	u8 reg;
     77
     78	usleep_range(1000, 2000);
     79	reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
     80	reg |= TS73XX_FPGA_CONFIG_LOAD;
     81	writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
     82
     83	usleep_range(1000, 2000);
     84	reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
     85	reg &= ~TS73XX_FPGA_CONFIG_LOAD;
     86	writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
     87
     88	reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
     89	if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK)
     90		return -ETIMEDOUT;
     91
     92	return 0;
     93}
     94
     95static const struct fpga_manager_ops ts73xx_fpga_ops = {
     96	.write_init	= ts73xx_fpga_write_init,
     97	.write		= ts73xx_fpga_write,
     98	.write_complete	= ts73xx_fpga_write_complete,
     99};
    100
    101static int ts73xx_fpga_probe(struct platform_device *pdev)
    102{
    103	struct device *kdev = &pdev->dev;
    104	struct ts73xx_fpga_priv *priv;
    105	struct fpga_manager *mgr;
    106	struct resource *res;
    107
    108	priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
    109	if (!priv)
    110		return -ENOMEM;
    111
    112	priv->dev = kdev;
    113
    114	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    115	priv->io_base = devm_ioremap_resource(kdev, res);
    116	if (IS_ERR(priv->io_base))
    117		return PTR_ERR(priv->io_base);
    118
    119	mgr = devm_fpga_mgr_register(kdev, "TS-73xx FPGA Manager",
    120				     &ts73xx_fpga_ops, priv);
    121	return PTR_ERR_OR_ZERO(mgr);
    122}
    123
    124static struct platform_driver ts73xx_fpga_driver = {
    125	.driver	= {
    126		.name	= "ts73xx-fpga-mgr",
    127	},
    128	.probe	= ts73xx_fpga_probe,
    129};
    130module_platform_driver(ts73xx_fpga_driver);
    131
    132MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
    133MODULE_DESCRIPTION("TS-73xx FPGA Manager driver");
    134MODULE_LICENSE("GPL v2");