From patchwork Thu Oct 6 20:34:17 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joshua Clayton X-Patchwork-Id: 9365281 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 131D3608A6 for ; Thu, 6 Oct 2016 20:36:39 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 01BA129236 for ; Thu, 6 Oct 2016 20:36:39 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E95B42923A; Thu, 6 Oct 2016 20:36:38 +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 818E329236 for ; Thu, 6 Oct 2016 20:36:38 +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 1bsFNT-00006L-7n; Thu, 06 Oct 2016 20:34:51 +0000 Received: from mail-pa0-x241.google.com ([2607:f8b0:400e:c03::241]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bsFNO-00005c-J0 for linux-arm-kernel@lists.infradead.org; Thu, 06 Oct 2016 20:34:47 +0000 Received: by mail-pa0-x241.google.com with SMTP id cd13so1566441pac.3 for ; Thu, 06 Oct 2016 13:34:25 -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; bh=Krd8VHizzEL4Pp+od513wxSlEQLJSVeWPYDri5lAqQ0=; b=h1ptfoStsZpVoSXKjJ8BQUfdvPJG1dHCBktoHVecxH+04ZOIyniXepql8wUACe9dqM zaoZ4esycpz86NJZ3yNmKeOxEpFWVZAjNdg4B8Ys32bWpMOGwqnVB2/h0RY3LDdoO1ND jBcvBVe5qUY1cL8HG6ecVFmpaERON+TfZdsO8Z585TTB9C1NiJqsr3LiKCdDdbVsP/vl tmjmtcCUtXafZ2xO8ZGLVRttY8j6YljckPa1ADbTIo3qPaHfPDfiJyMgJdmNdEnSLgkl ctBWu8VzWfAdRwdvieYyjAIFNkUeJU76/+U++l1+UFqrdbIlej0jMPLrfAzWGynwFeEB uxfw== 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; bh=Krd8VHizzEL4Pp+od513wxSlEQLJSVeWPYDri5lAqQ0=; b=a8cOj20nNhfaaDRnzg/N3tddHqeWo1x9sIUG52PSSYK7HBN8jyR5tAnemtMYRRD5wm Hqi7+eWPb/Ub0GzwAMQ44Ws0ZgUIFMfxmGhZZz3v7CLFKowrBDBA9z4A/wYY1rIRqKCA 4YZQGPGrwr8v+g6FlQW0QO0xJXLabTlBVMx+chzvDxZD1yKPorAVSVaeE2ALm0umyoiJ CYdfcxzJQ8BOPDPwEHINs7kIrlDdY5BhAA8aQC0tOa8H6z5RxoBf+VjS5K2RCXq2FG62 I6TvgqLAft8ZBLm1UzBpU4N+iCCCNb5/STFgAjyZuWFQbwp/yzsQWogi+sLgX3ShK5RA S3Yw== X-Gm-Message-State: AA6/9RkKg0djgsEbiY86NfcS62aGsvUDREichyqBszGsTdnJ4i5MWtSrrAZsXF70JwfBqg== X-Received: by 10.66.150.169 with SMTP id uj9mr24591703pab.23.1475786065387; Thu, 06 Oct 2016 13:34:25 -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 c9sm3095446pfc.79.2016.10.06.13.34.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 06 Oct 2016 13:34:23 -0700 (PDT) From: Joshua Clayton To: Alan Tull , Moritz Fischer Subject: [PATCH 1/3] fpga manager: Add cyclonespi driver for Altera fpgas Date: Thu, 6 Oct 2016 13:34:17 -0700 Message-Id: <4b4432c04b4ea92a2af814e3d7866c33f2eb12ea.1475783742.git.stillcompiling@gmail.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: References: X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20161006_133446_751233_97992763 X-CRM114-Status: GOOD ( 22.58 ) 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 cyclonespi loads fpga firmware over spi, using the "passive serial" interface on Altera Cyclone FPGAS. 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 | 6 ++ drivers/fpga/Makefile | 1 + drivers/fpga/cyclonespi.c | 173 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 180 insertions(+) create mode 100644 drivers/fpga/cyclonespi.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index cd84934..ccad5b1 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -13,6 +13,12 @@ config FPGA if FPGA +config FPGA_MGR_CYCLONE_SPI + tristate "Altera Cyclone V SPI" + depends on SPI + help + FPGA manager driver support for Altera Cyclone V 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..c03f40de 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_SPI) += cyclonespi.o obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o diff --git a/drivers/fpga/cyclonespi.c b/drivers/fpga/cyclonespi.c new file mode 100644 index 0000000..1ffa67c --- /dev/null +++ b/drivers/fpga/cyclonespi.c @@ -0,0 +1,173 @@ +/** + * 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 + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Joshua Clayton "); +MODULE_DESCRIPTION("Module to load Altera FPGA firmware over spi"); + +struct cyclonespi_conf { + struct gpio_desc *reset; + struct gpio_desc *status; + struct spi_device *spi; +}; + +static const struct of_device_id of_ef_match[] = { + { .compatible = "altr,cyclonespi-fpga-mgr", }, + {} +}; +MODULE_DEVICE_TABLE(of, of_ef_match); + +static enum fpga_mgr_states cyclonespi_state(struct fpga_manager *mgr) +{ + return mgr->state; +} + +static inline u32 revbit8x4(u32 n) +{ + n = ((n & 0xF0F0F0F0UL) >> 4) | ((n & 0x0F0F0F0FUL) << 4); + n = ((n & 0xCCCCCCCCUL) >> 2) | ((n & 0x33333333UL) << 2); + n = ((n & 0xAAAAAAAAUL) >> 1) | ((n & 0x55555555UL) << 1); + return n; +} + +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; + u32 *fw32 = (u32 *)buf; + const u32 *fw_end = (u32 *)(buf + count); + + if (flags & FPGA_MGR_PARTIAL_RECONFIG) { + dev_err(&mgr->dev, "Partial reconfiguration not supported.\n"); + return -EINVAL; + } + + gpiod_set_value(conf->reset, 0); + udelay(50); + if (gpiod_get_value(conf->status) == 1) { + dev_err(&mgr->dev, "Status pin should be low.\n"); + return -EIO; + } + + gpiod_set_value(conf->reset, 1); + msleep(1); + if (gpiod_get_value(conf->status) == 0) { + dev_err(&mgr->dev, "Status pin not ready.\n"); + return -EIO; + } + + /* set buffer to lsb first */ + while (fw32 < fw_end) { + *fw32 = revbit8x4(*fw32); + fw32++; + } + + return 0; +} + +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; + int stride = fw_data_end - fw_data; + + if (stride > SZ_4K) + stride = SZ_4K; + + 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->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(conf->reset)) { + dev_err(&spi->dev, "Failed to get reset gpio: %ld\n", + PTR_ERR(conf->reset)); + return PTR_ERR(conf->reset); + } + + 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 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 = "cyclonespi", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_ef_match), + }, + .probe = cyclonespi_probe, + .remove = cyclonespi_remove, +}; + +module_spi_driver(cyclonespi_driver)