From patchwork Wed Sep 20 18:28:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: matthew.gerlach@linux.intel.com X-Patchwork-Id: 816391 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="a1Q9xkVP"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xy7ZK6wGqz9s7g for ; Thu, 21 Sep 2017 04:29:45 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=unIDCS3uV6sxUqtzMaPbgNQ2Ce+GESiMUUXO2XXEWGQ=; b=a1Q9xkVPx0qRv/pJiUfe6YGism hVn1BaCecav02saa4oxaI7XlILtgKnoo8muZMSpK0CAmdmpmMpGvZf95KJHZv2hNJjr8o4MrVrO9b 2Qy+TnGEFpbo/lyVcqPOclpT2eHH1qSLv+ntbuBW5FHzbTFIcBCybogdrJjqxIoA/Asu6fefddz99 hvBA70ZKRccZERGvmay+pbzGStgIAUAu98D6+dbpq1WpgrBvIScuVHkXf/mvcWJetHeYgxHjSH6DB PkxAGctysGAcr139CUj6NJhWz7poFB5Hvdd4Qrf583v9IHY0Gr4Cd28PVFjWorg5m6aOGi7TFwH2l oi601U2w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dujka-00027T-Cx; Wed, 20 Sep 2017 18:29:32 +0000 Received: from mga09.intel.com ([134.134.136.24]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dujkW-00024i-JT for linux-mtd@lists.infradead.org; Wed, 20 Sep 2017 18:29:30 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Sep 2017 11:29:06 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,422,1500966000"; d="scan'208";a="137603172" Received: from mgerlach-mobl.amr.corp.intel.com (HELO mgerlach-VirtualBox.amr.corp.intel.com) ([10.254.74.152]) by orsmga002.jf.intel.com with ESMTP; 20 Sep 2017 11:29:06 -0700 From: matthew.gerlach@linux.intel.com To: vndao@altera.com, dwmw2@infradead.org, computersforpeace@gmail.com, boris.brezillon@free-electrons.com, marek.vasut@gmail.com, richard@nod.at, cyrille.pitchen@wedev4u.fr, robh+dt@kernel.org, mark.rutland@arm.com, linux-mtd@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, davem@davemloft.net, mchehab@kernel.org, linux-fpga@vger.kernel.org, tien.hock.loh@intel.com, hean.loong.ong@intel.com Subject: [PATCH v2 1/3] dt-bindings: mtd: Altera ASMI Parallel II IP Core Date: Wed, 20 Sep 2017 11:28:57 -0700 Message-Id: <1505932139-2905-2-git-send-email-matthew.gerlach@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> References: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170920_112928_693842_F1E9F9F8 X-CRM114-Status: GOOD ( 10.36 ) X-Spam-Score: -6.9 (------) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-6.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [134.134.136.24 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [134.134.136.24 listed in wl.mailspike.net] -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthew Gerlach MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Matthew Gerlach Device Tree bindings for Altera ASMI Parallel II IP Core connected to a flash chip. Signed-off-by: Matthew Gerlach Acked-by: Rob Herring --- v2: Made substitutions suggested by Rob Herring. Emphasize driver expects controller is connected to spi-nor flash. --- Documentation/devicetree/bindings/mtd/altera-asmip2.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/altera-asmip2.txt diff --git a/Documentation/devicetree/bindings/mtd/altera-asmip2.txt b/Documentation/devicetree/bindings/mtd/altera-asmip2.txt new file mode 100644 index 0000000..2e58817 --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/altera-asmip2.txt @@ -0,0 +1,15 @@ +* Altera ASMI Parallel II IP Core + +Devicetree bindings for an Altera ASMI Parallel II IP core connected to a +spi-nor flash chip. + +Required properties: +- compatible : Should be "altr,asmi-parallel2-spi-nor". +- reg : A tuple consisting of a physical address and length. + +Example: + +qspi: spi@a0001000 { + compatible = "altr,asmi-parallel2-spi-nor"; + reg = <0xa0001000 0x10>; +}; From patchwork Wed Sep 20 18:28:58 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: matthew.gerlach@linux.intel.com X-Patchwork-Id: 816395 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="TRLyfbev"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xy7b02Rnkz9s7g for ; Thu, 21 Sep 2017 04:30:20 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-Id:Date:Subject:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=mREf1IcOiuBmsb/V2cffxK5qpXps/gQFCtuTjzCEvHc=; b=TRLyfbevlYYho9 v+1f93A1UH2xxNE/Nk8svoEWy0J8NqXghue0QcRmOx59nh1pg55DnBOHwIGSu1btLPAL4Aic96gJq vMzwCPXLmpzTVn1eprnyHcJRqN/x3LR/BnBvkREAgSv/DwbJegYQCQ1M4wmBLXuw/DelborNBulUB xCoqIpB7iaH6qwXDubXOHTKzI/58SwzaK/3e52tUJrQ+WCBsm3R2Mf6CODVJt02zQzGq2UhOFQhbn m11eMcP7LDlnWuv7Ao3UWwnLi2wlzzFNfpo1kqBWy5dnZqmZNbUzD1V1NPrSeTTpWO/LEL4KuOrjb 4BgPLUFUfiBEIwvPYtdw==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dujlD-00031H-78; Wed, 20 Sep 2017 18:30:11 +0000 Received: from mga09.intel.com ([134.134.136.24]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dujkY-00024i-Ij for linux-mtd@lists.infradead.org; Wed, 20 Sep 2017 18:29:33 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Sep 2017 11:29:07 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,422,1500966000"; d="scan'208";a="137603179" Received: from mgerlach-mobl.amr.corp.intel.com (HELO mgerlach-VirtualBox.amr.corp.intel.com) ([10.254.74.152]) by orsmga002.jf.intel.com with ESMTP; 20 Sep 2017 11:29:06 -0700 From: matthew.gerlach@linux.intel.com To: vndao@altera.com, dwmw2@infradead.org, computersforpeace@gmail.com, boris.brezillon@free-electrons.com, marek.vasut@gmail.com, richard@nod.at, cyrille.pitchen@wedev4u.fr, robh+dt@kernel.org, mark.rutland@arm.com, linux-mtd@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, davem@davemloft.net, mchehab@kernel.org, linux-fpga@vger.kernel.org, tien.hock.loh@intel.com, hean.loong.ong@intel.com Subject: [PATCH v2 2/3] mtd: spi-nor: Altera ASMI Parallel II IP Core Date: Wed, 20 Sep 2017 11:28:58 -0700 Message-Id: <1505932139-2905-3-git-send-email-matthew.gerlach@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> References: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170920_112930_779776_FEA9445A X-CRM114-Status: GOOD ( 24.28 ) X-Spam-Score: -6.9 (------) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-6.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [134.134.136.24 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [134.134.136.24 listed in wl.mailspike.net] -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthew Gerlach Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Matthew Gerlach This patch adds support for a spi-nor, platform driver for the Altera ASMI Parallel II IP Core. The intended use case is to be able to update the flash used to load a FPGA at power up with mtd-utils. Signed-off-by: Matthew Gerlach --- v2: minor checkpatch fixing by Wu Hao Use read_dummy value as suggested by Cyrille Pitchen. Don't assume 4 byte addressing (Cryille Pichecn and Marek Vasut). Fixed #define indenting as suggested by Marek Vasut. Added units to timer values as suggested by Marek Vasut. Use io(read|write)8_rep() as suggested by Marek Vasut. Renamed function prefixed with __ as suggested by Marek Vasut. --- MAINTAINERS | 7 + drivers/mtd/spi-nor/Kconfig | 6 + drivers/mtd/spi-nor/Makefile | 1 + drivers/mtd/spi-nor/altera-asmip2.c | 457 ++++++++++++++++++++++++++++++++++++ include/linux/mtd/altera-asmip2.h | 24 ++ 5 files changed, 495 insertions(+) create mode 100644 drivers/mtd/spi-nor/altera-asmip2.c create mode 100644 include/linux/mtd/altera-asmip2.h diff --git a/MAINTAINERS b/MAINTAINERS index b87c698..af48255 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -644,6 +644,13 @@ ALPS PS/2 TOUCHPAD DRIVER R: Pali Rohár F: drivers/input/mouse/alps.* +ALTERA ASMI Parallel II Driver +M: Matthew Gerlach +L: linux-mtd@lists.infradead.org +S: Maintained +F: drivers/mtd/spi-nor/altera-asmip2.c +F: inclulde/linux/mtd/altera-asmip2.h + ALTERA I2C CONTROLLER DRIVER M: Thor Thayer S: Maintained diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 69c638d..f81dbec 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -129,4 +129,10 @@ config SPI_STM32_QUADSPI This enables support for the STM32 Quad SPI controller. We only connect the NOR to this controller. +config SPI_ALTERA_ASMIP2 + tristate "Altera ASMI Parallel II IP" + depends on OF && HAS_IOMEM + help + Enable support for Altera ASMI Parallel II. + endif # MTD_SPI_NOR diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 7d84c51..1c79324 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o +obj-$(CONFIG_SPI_ALTERA_ASMIP2) += altera-asmip2.o obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o diff --git a/drivers/mtd/spi-nor/altera-asmip2.c b/drivers/mtd/spi-nor/altera-asmip2.c new file mode 100644 index 0000000..a977765 --- /dev/null +++ b/drivers/mtd/spi-nor/altera-asmip2.c @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#define QSPI_ACTION_REG 0 +#define QSPI_ACTION_RST BIT(0) +#define QSPI_ACTION_EN BIT(1) +#define QSPI_ACTION_SC BIT(2) +#define QSPI_ACTION_CHIP_SEL_SFT 4 +#define QSPI_ACTION_DUMMY_SFT 8 +#define QSPI_ACTION_READ_BACK_SFT 16 + +#define QSPI_FIFO_CNT_REG 4 +#define QSPI_FIFO_DEPTH 0x200 +#define QSPI_FIFO_CNT_MSK 0x3ff +#define QSPI_FIFO_CNT_RX_SFT 0 +#define QSPI_FIFO_CNT_TX_SFT 12 + +#define QSPI_DATA_REG 0x8 + +#define QSPI_POLL_TIMEOUT_US 10000000 +#define QSPI_POLL_INTERVAL_US 5 + +struct altera_asmip2 { + void __iomem *csr_base; + u32 num_flashes; + struct device *dev; + struct altera_asmip2_flash *flash[ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP]; + struct mutex bus_mutex; +}; + +struct altera_asmip2_flash { + struct spi_nor nor; + struct altera_asmip2 *q; +}; + +static int altera_asmip2_write_reg(struct spi_nor *nor, u8 opcode, u8 *val, + int len) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + u32 reg; + int ret; + + if ((len + 1) > QSPI_FIFO_DEPTH) { + dev_err(q->dev, "%s bad len %d > %d\n", + __func__, len + 1, QSPI_FIFO_DEPTH); + return -EINVAL; + } + + writeb(opcode, q->csr_base + QSPI_DATA_REG); + + iowrite8_rep(q->csr_base + QSPI_DATA_REG, val, len); + + reg = QSPI_ACTION_EN | QSPI_ACTION_SC; + + writel(reg, q->csr_base + QSPI_ACTION_REG); + + ret = readl_poll_timeout(q->csr_base + QSPI_FIFO_CNT_REG, reg, + (((reg >> QSPI_FIFO_CNT_TX_SFT) & + QSPI_FIFO_CNT_MSK) == 0), + QSPI_POLL_INTERVAL_US, QSPI_POLL_TIMEOUT_US); + if (ret) + dev_err(q->dev, "%s timed out\n", __func__); + + reg = QSPI_ACTION_EN; + + writel(reg, q->csr_base + QSPI_ACTION_REG); + + return ret; +} + +static int altera_asmip2_read_reg(struct spi_nor *nor, u8 opcode, u8 *val, + int len) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + u32 reg; + int ret; + + if (len > QSPI_FIFO_DEPTH) { + dev_err(q->dev, "%s bad len %d > %d\n", + __func__, len, QSPI_FIFO_DEPTH); + return -EINVAL; + } + + writeb(opcode, q->csr_base + QSPI_DATA_REG); + + reg = QSPI_ACTION_EN | QSPI_ACTION_SC | + (len << QSPI_ACTION_READ_BACK_SFT); + + writel(reg, q->csr_base + QSPI_ACTION_REG); + + ret = readl_poll_timeout(q->csr_base + QSPI_FIFO_CNT_REG, reg, + ((reg & QSPI_FIFO_CNT_MSK) == len), + QSPI_POLL_INTERVAL_US, QSPI_POLL_TIMEOUT_US); + + if (!ret) + ioread8_rep(q->csr_base + QSPI_DATA_REG, val, len); + else + dev_err(q->dev, "%s timeout\n", __func__); + + writel(QSPI_ACTION_EN, q->csr_base + QSPI_ACTION_REG); + + return ret; +} + +static inline void altera_asmip2_push_offset(struct altera_asmip2 *q, + struct spi_nor *nor, + loff_t offset) +{ + int i; + u32 val; + + for (i = (nor->addr_width - 1) * 8; i >= 0; i -= 8) { + val = (offset & (0xff << i)) >> i; + writeb(val, q->csr_base + QSPI_DATA_REG); + } +} + +static ssize_t altera_asmip2_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *buf) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + size_t bytes_to_read; + u32 reg; + int ret; + + bytes_to_read = min_t(size_t, len, QSPI_FIFO_DEPTH); + + writeb(nor->read_opcode, q->csr_base + QSPI_DATA_REG); + + altera_asmip2_push_offset(q, nor, from); + + reg = QSPI_ACTION_EN | QSPI_ACTION_SC | + (nor->read_dummy << QSPI_ACTION_DUMMY_SFT) | + (bytes_to_read << QSPI_ACTION_READ_BACK_SFT); + + writel(reg, q->csr_base + QSPI_ACTION_REG); + + ret = readl_poll_timeout(q->csr_base + QSPI_FIFO_CNT_REG, reg, + ((reg & QSPI_FIFO_CNT_MSK) == + bytes_to_read), QSPI_POLL_INTERVAL_US, + QSPI_POLL_TIMEOUT_US); + if (ret) { + dev_err(q->dev, "%s timed out\n", __func__); + bytes_to_read = 0; + } else + ioread8_rep(q->csr_base + QSPI_DATA_REG, buf, bytes_to_read); + + writel(QSPI_ACTION_EN, q->csr_base + QSPI_ACTION_REG); + + return bytes_to_read; +} + +static ssize_t altera_asmip2_write(struct spi_nor *nor, loff_t to, + size_t len, const u_char *buf) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + size_t bytes_to_write; + u32 reg; + int ret; + + bytes_to_write = min_t(size_t, len, + (QSPI_FIFO_DEPTH - (nor->addr_width + 1))); + + writeb(nor->program_opcode, q->csr_base + QSPI_DATA_REG); + + altera_asmip2_push_offset(q, nor, to); + + iowrite8_rep(q->csr_base + QSPI_DATA_REG, buf, bytes_to_write); + + reg = QSPI_ACTION_EN | QSPI_ACTION_SC; + + writel(reg, q->csr_base + QSPI_ACTION_REG); + + ret = readl_poll_timeout(q->csr_base + QSPI_FIFO_CNT_REG, reg, + (((reg >> QSPI_FIFO_CNT_TX_SFT) & + QSPI_FIFO_CNT_MSK) == 0), + QSPI_POLL_INTERVAL_US, QSPI_POLL_TIMEOUT_US); + + if (ret) { + dev_err(q->dev, + "%s timed out waiting for fifo to clear\n", + __func__); + bytes_to_write = 0; + } + + writel(QSPI_ACTION_EN, q->csr_base + QSPI_ACTION_REG); + + return bytes_to_write; +} + +static int altera_asmip2_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + + mutex_lock(&q->bus_mutex); + + return 0; +} + +static void altera_asmip2_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct altera_asmip2_flash *flash = nor->priv; + struct altera_asmip2 *q = flash->q; + + mutex_unlock(&q->bus_mutex); +} + +static int altera_asmip2_setup_banks(struct device *dev, + u32 bank, struct device_node *np) +{ + const struct spi_nor_hwcaps hwcaps = { + .mask = SNOR_HWCAPS_READ | + SNOR_HWCAPS_READ_FAST | + SNOR_HWCAPS_PP, + }; + struct altera_asmip2 *q = dev_get_drvdata(dev); + struct altera_asmip2_flash *flash; + struct spi_nor *nor; + int ret = 0; + + if (bank > q->num_flashes - 1) + return -EINVAL; + + flash = devm_kzalloc(q->dev, sizeof(*flash), GFP_KERNEL); + if (!flash) + return -ENOMEM; + + q->flash[bank] = flash; + flash->q = q; + + nor = &flash->nor; + nor->dev = dev; + nor->priv = flash; + nor->mtd.priv = nor; + spi_nor_set_flash_node(nor, np); + + /* spi nor framework*/ + nor->read_reg = altera_asmip2_read_reg; + nor->write_reg = altera_asmip2_write_reg; + nor->read = altera_asmip2_read; + nor->write = altera_asmip2_write; + nor->prepare = altera_asmip2_prep; + nor->unprepare = altera_asmip2_unprep; + + ret = spi_nor_scan(nor, NULL, &hwcaps); + if (ret) { + dev_err(nor->dev, "flash not found\n"); + return ret; + } + + ret = mtd_device_register(&nor->mtd, NULL, 0); + + return ret; +} + +static int altera_asmip2_create(struct device *dev, void __iomem *csr_base) +{ + struct altera_asmip2 *q; + u32 reg; + + q = devm_kzalloc(dev, sizeof(*q), GFP_KERNEL); + if (!q) + return -ENOMEM; + + q->dev = dev; + q->csr_base = csr_base; + + mutex_init(&q->bus_mutex); + + dev_set_drvdata(dev, q); + + reg = readl(q->csr_base + QSPI_ACTION_REG); + if (!(reg & QSPI_ACTION_RST)) { + writel((reg | QSPI_ACTION_RST), q->csr_base + QSPI_ACTION_REG); + dev_info(dev, "%s asserting reset\n", __func__); + udelay(10); + } + + writel((reg & ~QSPI_ACTION_RST), q->csr_base + QSPI_ACTION_REG); + udelay(10); + + return 0; +} + +static int altera_asmip2_add_bank(struct device *dev, + u32 bank, struct device_node *np) +{ + struct altera_asmip2 *q = dev_get_drvdata(dev); + + if (q->num_flashes >= ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP) + return -ENOMEM; + + q->num_flashes++; + + return altera_asmip2_setup_banks(dev, bank, np); +} + +static int altera_asmip2_remove_banks(struct device *dev) +{ + struct altera_asmip2 *q = dev_get_drvdata(dev); + struct altera_asmip2_flash *flash; + int i; + int ret = 0; + + if (!q) + return -EINVAL; + + /* clean up for all nor flash */ + for (i = 0; i < q->num_flashes; i++) { + flash = q->flash[i]; + if (!flash) + continue; + + /* clean up mtd stuff */ + ret = mtd_device_unregister(&flash->nor.mtd); + if (ret) { + dev_err(dev, "error removing mtd\n"); + return ret; + } + } + + return 0; +} + +static int altera_asmip2_probe_with_pdata(struct platform_device *pdev, + struct altera_asmip2_plat_data *qdata) +{ + struct device *dev = &pdev->dev; + int ret, i; + + ret = altera_asmip2_create(dev, qdata->csr_base); + + if (ret) { + dev_err(dev, "failed to create qspi device %d\n", ret); + return ret; + } + + for (i = 0; i < qdata->num_chip_sel; i++) { + ret = altera_asmip2_add_bank(dev, i, NULL); + if (ret) { + dev_err(dev, "failed to add qspi bank %d\n", ret); + break; + } + } + + return ret; +} + +static int altera_asmip2_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct altera_asmip2_plat_data *qdata; + struct resource *res; + void __iomem *csr_base; + u32 bank; + int ret; + struct device_node *pp; + + qdata = dev_get_platdata(dev); + + if (qdata) + return altera_asmip2_probe_with_pdata(pdev, qdata); + + if (!np) { + dev_err(dev, "no device tree found %p\n", pdev); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + csr_base = devm_ioremap_resource(dev, res); + if (IS_ERR(csr_base)) { + dev_err(dev, "%s: ERROR: failed to map csr base\n", __func__); + return PTR_ERR(csr_base); + } + + ret = altera_asmip2_create(dev, csr_base); + + if (ret) { + dev_err(dev, "failed to create qspi device\n"); + return ret; + } + + for_each_available_child_of_node(np, pp) { + of_property_read_u32(pp, "reg", &bank); + if (bank >= ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP) { + dev_err(dev, "bad reg value %u >= %u\n", bank, + ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP); + goto error; + } + + if (altera_asmip2_add_bank(dev, bank, pp)) { + dev_err(dev, "failed to add bank %u\n", bank); + goto error; + } + } + + return 0; +error: + altera_asmip2_remove_banks(dev); + return -EIO; +} + +static int altera_asmip2_remove(struct platform_device *pdev) +{ + struct altera_asmip2 *q = dev_get_drvdata(&pdev->dev); + + mutex_destroy(&q->bus_mutex); + + return altera_asmip2_remove_banks(&pdev->dev); +} + +static const struct of_device_id altera_asmip2_id_table[] = { + { .compatible = "altr,asmi-parallel2-spi-nor",}, + {} +}; +MODULE_DEVICE_TABLE(of, altera_asmip2_id_table); + +static struct platform_driver altera_asmip2_driver = { + .driver = { + .name = ALTERA_ASMIP2_DRV_NAME, + .of_match_table = altera_asmip2_id_table, + }, + .probe = altera_asmip2_probe, + .remove = altera_asmip2_remove, +}; +module_platform_driver(altera_asmip2_driver); + +MODULE_AUTHOR("Matthew Gerlach "); +MODULE_DESCRIPTION("Altera ASMI Parallel II"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" ALTERA_ASMIP2_DRV_NAME); diff --git a/include/linux/mtd/altera-asmip2.h b/include/linux/mtd/altera-asmip2.h new file mode 100644 index 0000000..580c43c --- /dev/null +++ b/include/linux/mtd/altera-asmip2.h @@ -0,0 +1,24 @@ +/* + * + * Copyright 2017 Intel Corporation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __ALTERA_QUADSPI_H +#define __ALTERA_QUADSPI_H + +#include + +#define ALTERA_ASMIP2_DRV_NAME "altr-asmip2" +#define ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP 3 +#define ALTERA_ASMIP2_RESOURCE_SIZE 0x10 + +struct altera_asmip2_plat_data { + void __iomem *csr_base; + u32 num_chip_sel; +}; + +#endif From patchwork Wed Sep 20 18:28:59 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: matthew.gerlach@linux.intel.com X-Patchwork-Id: 816396 X-Patchwork-Delegate: cyrille.pitchen@atmel.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=65.50.211.133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="LuvRP5lJ"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xy7bj0zz3z9sBd for ; Thu, 21 Sep 2017 04:30:54 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=aXwjx6MQPAvwib/PZQmt69RsUrdlW7RQofZ3TCjsMqc=; b=LuvRP5lJMRdz4tQ0z6lgUbWLr5 kRWzxAgc3iOv+wQemiUHzRpdgYrbvzPlFHtX23Y4vnuPzaUJHqdU2DJd1qO9VU9ku3t29vL9Nvb+Y /rCtsJtKwBII22jIK5Nb35Snk6I83xeWqBxpzfV2chKm3UJuQUi1WDrZFOnRH/xfOMxRr3N0+0g88 5y3vggJjWonXcra8NUMmDfCoeyRARcsuxdFeBGfRsp41RsRN+Rl7S2b0CZ8w6qo5eOo7J4DnvUhaO M/JFF6KIZFjUP156sM64azTa0utigPncahOECK71jF7t4kXvAkqtpTH4exbU8JxS4jlaf+KuqiFIf MwkxU6UA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dujlj-00047A-ES; Wed, 20 Sep 2017 18:30:43 +0000 Received: from mga09.intel.com ([134.134.136.24]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dujkt-000276-1b for linux-mtd@lists.infradead.org; Wed, 20 Sep 2017 18:30:00 +0000 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga102.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 20 Sep 2017 11:29:08 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.42,422,1500966000"; d="scan'208";a="137603185" Received: from mgerlach-mobl.amr.corp.intel.com (HELO mgerlach-VirtualBox.amr.corp.intel.com) ([10.254.74.152]) by orsmga002.jf.intel.com with ESMTP; 20 Sep 2017 11:29:07 -0700 From: matthew.gerlach@linux.intel.com To: vndao@altera.com, dwmw2@infradead.org, computersforpeace@gmail.com, boris.brezillon@free-electrons.com, marek.vasut@gmail.com, richard@nod.at, cyrille.pitchen@wedev4u.fr, robh+dt@kernel.org, mark.rutland@arm.com, linux-mtd@lists.infradead.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, gregkh@linuxfoundation.org, davem@davemloft.net, mchehab@kernel.org, linux-fpga@vger.kernel.org, tien.hock.loh@intel.com, hean.loong.ong@intel.com Subject: [PATCH v2 3/3] mtd: spi-nor: add flag for reading dummy cycles from nv cfg reg Date: Wed, 20 Sep 2017 11:28:59 -0700 Message-Id: <1505932139-2905-4-git-send-email-matthew.gerlach@linux.intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> References: <1505932139-2905-1-git-send-email-matthew.gerlach@linux.intel.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170920_112952_633196_4344F4ED X-CRM114-Status: GOOD ( 15.41 ) X-Spam-Score: -6.9 (------) X-Spam-Report: SpamAssassin version 3.4.1 on bombadil.infradead.org summary: Content analysis details: (-6.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -5.0 RCVD_IN_DNSWL_HI RBL: Sender listed at http://www.dnswl.org/, high trust [134.134.136.24 listed in list.dnswl.org] -0.0 RCVD_IN_MSPIKE_H3 RBL: Good reputation (+3) [134.134.136.24 listed in wl.mailspike.net] -0.0 RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.0 RCVD_IN_MSPIKE_WL Mailspike good senders X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthew Gerlach MIME-Version: 1.0 Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Matthew Gerlach This patch is a work around for some non-standard behavior of EPCQ flash parts: https://www.altera.com/documentation/wtw1396921531042.html#wtw1396921651224 These flash parts are generally used to configure Intel/Altera FPGAs on power up. These parts report a JEDEC id of the Micron part at the core, but have a different number of dummy cycles than specified in the Micron data sheet. The number of required dummy cycles can be read from the Non-Volatile Configuration register. Signed-off-by: Matthew Gerlach --- drivers/mtd/spi-nor/altera-asmip2.c | 31 ++++++++++++++++++++++++++----- include/linux/mtd/altera-asmip2.h | 3 +++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/spi-nor/altera-asmip2.c b/drivers/mtd/spi-nor/altera-asmip2.c index a977765..d9cd807 100644 --- a/drivers/mtd/spi-nor/altera-asmip2.c +++ b/drivers/mtd/spi-nor/altera-asmip2.c @@ -40,6 +40,10 @@ #define QSPI_POLL_TIMEOUT_US 10000000 #define QSPI_POLL_INTERVAL_US 5 +#define SPINOR_OP_RD_NVCFG 0xb5 +#define NVCFG_DUMMY_SFT 12 +#define NVCFG_DUMMY_MASK 0xf + struct altera_asmip2 { void __iomem *csr_base; u32 num_flashes; @@ -231,7 +235,8 @@ static void altera_asmip2_unprep(struct spi_nor *nor, enum spi_nor_ops ops) } static int altera_asmip2_setup_banks(struct device *dev, - u32 bank, struct device_node *np) + u32 bank, struct device_node *np, + u32 flags) { const struct spi_nor_hwcaps hwcaps = { .mask = SNOR_HWCAPS_READ | @@ -241,6 +246,7 @@ static int altera_asmip2_setup_banks(struct device *dev, struct altera_asmip2 *q = dev_get_drvdata(dev); struct altera_asmip2_flash *flash; struct spi_nor *nor; + u16 nvcfg; int ret = 0; if (bank > q->num_flashes - 1) @@ -273,6 +279,20 @@ static int altera_asmip2_setup_banks(struct device *dev, return ret; } + if (flags & ALTERA_ASMIP2_FLASH_FLG_RD_NVCFG) { + ret = altera_asmip2_read_reg(nor, SPINOR_OP_RD_NVCFG, + (u8*)&nvcfg, sizeof(nvcfg)); + + if (ret) { + dev_err(nor->dev, + "failed to read NV Configuration register\n"); + return ret; + } + + nor->read_dummy = (nvcfg >> NVCFG_DUMMY_SFT) & NVCFG_DUMMY_MASK; + dev_info(nor->dev, "%s dummy %d\n", __func__, nor->read_dummy); + } + ret = mtd_device_register(&nor->mtd, NULL, 0); return ret; @@ -308,7 +328,7 @@ static int altera_asmip2_create(struct device *dev, void __iomem *csr_base) } static int altera_asmip2_add_bank(struct device *dev, - u32 bank, struct device_node *np) + u32 bank, struct device_node *np, u32 flags) { struct altera_asmip2 *q = dev_get_drvdata(dev); @@ -317,7 +337,7 @@ static int altera_asmip2_add_bank(struct device *dev, q->num_flashes++; - return altera_asmip2_setup_banks(dev, bank, np); + return altera_asmip2_setup_banks(dev, bank, np, flags); } static int altera_asmip2_remove_banks(struct device *dev) @@ -361,7 +381,8 @@ static int altera_asmip2_probe_with_pdata(struct platform_device *pdev, } for (i = 0; i < qdata->num_chip_sel; i++) { - ret = altera_asmip2_add_bank(dev, i, NULL); + ret = altera_asmip2_add_bank(dev, i, NULL, + qdata->flash_flags[i]); if (ret) { dev_err(dev, "failed to add qspi bank %d\n", ret); break; @@ -414,7 +435,7 @@ static int altera_asmip2_probe(struct platform_device *pdev) goto error; } - if (altera_asmip2_add_bank(dev, bank, pp)) { + if (altera_asmip2_add_bank(dev, bank, pp, 0)) { dev_err(dev, "failed to add bank %u\n", bank); goto error; } diff --git a/include/linux/mtd/altera-asmip2.h b/include/linux/mtd/altera-asmip2.h index 580c43c..185a9b2 100644 --- a/include/linux/mtd/altera-asmip2.h +++ b/include/linux/mtd/altera-asmip2.h @@ -16,9 +16,12 @@ #define ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP 3 #define ALTERA_ASMIP2_RESOURCE_SIZE 0x10 +#define ALTERA_ASMIP2_FLASH_FLG_RD_NVCFG BIT(0) + struct altera_asmip2_plat_data { void __iomem *csr_base; u32 num_chip_sel; + u32 flash_flags[ALTERA_ASMIP2_MAX_NUM_FLASH_CHIP]; }; #endif