From patchwork Fri Oct 28 16:56:40 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Clayton X-Patchwork-Id: 9402385 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DBCE460588 for ; Fri, 28 Oct 2016 16:59:41 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id CDA192A77E for ; Fri, 28 Oct 2016 16:59:41 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id C0AEA2A8AF; Fri, 28 Oct 2016 16:59:41 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,FREEMAIL_FROM,RCVD_IN_DNSWL_MED,T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 58D022A77E for ; Fri, 28 Oct 2016 16:59:41 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1c0ATx-00031p-Sy; Fri, 28 Oct 2016 16:58:17 +0000 Received: from mail-pf0-x241.google.com ([2607:f8b0:400e:c00::241]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1c0ASu-0002Yz-MK for linux-arm-kernel@lists.infradead.org; Fri, 28 Oct 2016 16:57:16 +0000 Received: by mail-pf0-x241.google.com with SMTP id u84so1723899pfj.1 for ; Fri, 28 Oct 2016 09:56:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=Jxtt8dU2c6XSnJVmv+afRNEunG/Y8s7MmbYjEfMkUeo=; b=G8ACAGpwFb+h8c1qbpQT6kfbij7QQYNAn9WMHiMOzZqqsQB71D2Zs9elp+XHAm3eDk 7U/eIsHORf9Kj1Bd8OqtA4+SHSL7jM7cGpoDCQdRd79f1gRYzqz3wtTj4XQshWtL3c67 alsMO2587uRefiiZ+HsWzY27KGL4KxsiSJkMNpvWipzvgTKAHe9/lihXcMMnbL743sxX RyHjHPqW/C5Xy86E5LXhZQV/Ybup97kiz0JUCEzl1Cyyk06+EB1S8yh2gq60TcU9z8hX iz9LNSRVZBPXHkpEvs2cQ2l+JJKOxFm6AAXW8cbzeVWMS1eHcfTWEOKztlweGpRcJrX9 aJaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=Jxtt8dU2c6XSnJVmv+afRNEunG/Y8s7MmbYjEfMkUeo=; b=FecMJgepp8BksiSZXUp6UDg1pqN6OyVKpNbXDfWf/4hxuPv3dxVERwcz3EsV1XF/BM dg6IqDCBEvo/9dlaPgjHyeqonxCiTFjluqR72k0s8uBkj9SqIQVmktnzA9bSP77VCFZa 2WvrdxVzWN4huGUV4KJFi1XPECyU75oAHV3H4PdbST10buiEaQg3JVOj8AvOPK7bfsvb dC25R+UCquIY1Onc/Io9xmgSSKVBOBP3p+nGezBpCmtjR9OK4g2w0Fo5HfHCsWpON+du jAEyjgsW7M+9FyfKu3YRZ734lYBZv1O81de4XBcgSCR38mou3hHVE0r+KOmT8IRAVsbK 5+cA== X-Gm-Message-State: ABUngveNN1Hs9a8lqeI/4CIpu/qJgEAT3DmaOMj5N7xMHhsZ/azQT9GOXDe0HrZ8QfGteA== X-Received: by 10.99.226.83 with SMTP id y19mr22116943pgj.147.1477673813266; Fri, 28 Oct 2016 09:56:53 -0700 (PDT) Received: from jclayton-pc.columbia.uniwest.com (68-185-59-186.static.knwc.wa.charter.com. [68.185.59.186]) by smtp.gmail.com with ESMTPSA id h85sm20106124pfj.89.2016.10.28.09.56.51 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 28 Oct 2016 09:56:52 -0700 (PDT) From: Joshua Clayton To: Alan Tull , Moritz Fischer Subject: [PATCH v2 3/5] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs Date: Fri, 28 Oct 2016 09:56:40 -0700 Message-Id: <202cdeff42a2de149c471630110a8b2657ccf5ca.1477669745.git.stillcompiling@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: In-Reply-To: References: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161028_095712_933184_0C51E37C X-CRM114-Status: GOOD ( 21.85 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Mark Rutland , devicetree@vger.kernel.org, Joshua Clayton , Russell King , linux-kernel@vger.kernel.org, Rob Herring , Sascha Hauer , Fabio Estevam , Shawn Guo , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP cyclone-ps-spi loads FPGA firmware over spi, using the "passive serial" interface on Altera Cyclone FPGAS. This is one of the simpler ways to set up an FPGA at runtime. The signal interface is close to unidirectional spi with lsb first. Signed-off-by: Joshua Clayton --- drivers/fpga/Kconfig | 7 ++ drivers/fpga/Makefile | 1 + drivers/fpga/cyclone-ps-spi.c | 172 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 drivers/fpga/cyclone-ps-spi.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index cd84934..2462707 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -13,6 +13,13 @@ config FPGA if FPGA +config FPGA_MGR_CYCLONE_PS_SPI + tristate "Altera Cyclone FPGA Passive Serial over SPI" + depends on SPI + help + FPGA manager driver support for Altera Cyclone using the + passive serial interface over SPI + config FPGA_MGR_SOCFPGA tristate "Altera SOCFPGA FPGA Manager" depends on ARCH_SOCFPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index 8d83fc6..8f93930 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -6,5 +6,6 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o # FPGA Manager Drivers +obj-$(CONFIG_FPGA_MGR_CYCLONE_PS_SPI) += cyclone-ps-spi.o obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o diff --git a/drivers/fpga/cyclone-ps-spi.c b/drivers/fpga/cyclone-ps-spi.c new file mode 100644 index 0000000..4b70d5c --- /dev/null +++ b/drivers/fpga/cyclone-ps-spi.c @@ -0,0 +1,172 @@ +/** + * Copyright (c) 2015 United Western Technologies, Corporation + * + * Joshua Clayton + * + * Manage Altera fpga firmware that is loaded over spi. + * Firmware must be in binary "rbf" format. + * Works on Cyclone V. Should work on cyclone series. + * May work on other Altera fpgas. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define FPGA_RESET_TIME 50 /* time in usecs to trigger FPGA config */ +#define FPGA_MIN_DELAY 250 /* min usecs to wait for config status */ + +struct cyclonespi_conf { + struct gpio_desc *config; + struct gpio_desc *status; + struct spi_device *spi; +}; + +static const struct of_device_id of_ef_match[] = { + { .compatible = "altr,cyclone-ps-spi-fpga-mgr", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_ef_match); + +static enum fpga_mgr_states cyclonespi_state(struct fpga_manager *mgr) +{ + return mgr->state; +} + +static int cyclonespi_write_init(struct fpga_manager *mgr, u32 flags, + const char *buf, size_t count) +{ + struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv; + + if (flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); + return -EINVAL; + } + + gpiod_set_value(conf->config, 0); + usleep_range(FPGA_RESET_TIME, FPGA_RESET_TIME + 20); + if (gpiod_get_value(conf->status) == 1) { + dev_err(&mgr->dev, "Status pin should be low.\n"); + return -EIO; + } + + gpiod_set_value(conf->config, 1); + usleep_range(FPGA_MIN_DELAY, FPGA_MIN_DELAY + 20); + if (gpiod_get_value(conf->status) == 0) { + dev_err(&mgr->dev, "Status pin not ready.\n"); + return -EIO; + } + + return 0; +} + +static void rev_buf(void *buf, size_t len) +{ + u32 *fw32 = (u32 *)buf; + const u32 *fw_end = (u32 *)(buf + len); + + /* set buffer to lsb first */ + while (fw32 < fw_end) { + *fw32 = bitrev8x4(*fw32); + fw32++; + } +} + +static int cyclonespi_write(struct fpga_manager *mgr, const char *buf, + size_t count) +{ + struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv; + const char *fw_data = buf; + const char *fw_data_end = fw_data + count; + + while (fw_data < fw_data_end) { + int ret; + size_t stride = min(fw_data_end - fw_data, SZ_4K); + + rev_buf((void *)fw_data, stride); + ret = spi_write(conf->spi, fw_data, stride); + if (ret) { + dev_err(&mgr->dev, "spi error in firmware write: %d\n", + ret); + return ret; + } + fw_data += stride; + } + + return 0; +} + +static int cyclonespi_write_complete(struct fpga_manager *mgr, u32 flags) +{ + struct cyclonespi_conf *conf = (struct cyclonespi_conf *)mgr->priv; + + if (gpiod_get_value(conf->status) == 0) { + dev_err(&mgr->dev, "Error during configuration.\n"); + return -EIO; + } + + return 0; +} + +static const struct fpga_manager_ops cyclonespi_ops = { + .state = cyclonespi_state, + .write_init = cyclonespi_write_init, + .write = cyclonespi_write, + .write_complete = cyclonespi_write_complete, +}; + +static int cyclonespi_probe(struct spi_device *spi) +{ + struct cyclonespi_conf *conf = devm_kzalloc(&spi->dev, sizeof(*conf), + GFP_KERNEL); + + if (!conf) + return -ENOMEM; + + conf->spi = spi; + conf->config = devm_gpiod_get(&spi->dev, "config", GPIOD_OUT_LOW); + if (IS_ERR(conf->config)) { + dev_err(&spi->dev, "Failed to get config gpio: %ld\n", + PTR_ERR(conf->config)); + return PTR_ERR(conf->config); + } + + conf->status = devm_gpiod_get(&spi->dev, "status", GPIOD_IN); + if (IS_ERR(conf->status)) { + dev_err(&spi->dev, "Failed to get status gpio: %ld\n", + PTR_ERR(conf->status)); + return PTR_ERR(conf->status); + } + + return fpga_mgr_register(&spi->dev, + "Altera Cyclone PS SPI FPGA Manager", + &cyclonespi_ops, conf); +} + +static int cyclonespi_remove(struct spi_device *spi) +{ + fpga_mgr_unregister(&spi->dev); + + return 0; +} + +static struct spi_driver cyclonespi_driver = { + .driver = { + .name = "cyclone-ps-spi", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_ef_match), + }, + .probe = cyclonespi_probe, + .remove = cyclonespi_remove, +}; + +module_spi_driver(cyclonespi_driver) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joshua Clayton "); +MODULE_DESCRIPTION("Module to load Altera FPGA firmware over spi");