From patchwork Thu Sep 24 15:27:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chuanhong Guo X-Patchwork-Id: 11797731 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 6BA691668 for ; Thu, 24 Sep 2020 15:28:45 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2695E2311A for ; Thu, 24 Sep 2020 15:28:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="LlCVbrBx"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OEI3vPl+" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 2695E2311A Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.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=BSU3x6jCfCGp6BTwBvvGoablcil3W3AGxUCH4GrW360=; b=LlCVbrBxZO16sBZzQ986rcLmQ tCoz9QDwT7CPPW0rSlAUT3ZOotjmY2sbb+TBjN+iJ6zmcm1CQerNGH/aQXtDDeer57AZwNEgq4D7x muW+O+HP8nUiHHAa+1ur5Kx3f6HNHyLlBWA43yEwwAIezhjLHOG8MdklX8MNohbTVnbTo91NCI7cK odXE8AF/ehdnqdcH3mdvtwjng15hgUOid3MPc4EhPxius38RItjV3QSXvvwbwMFdtBL4TzWghbYBQ EE1mzdpJBTQj8yP1LFVH7ryI6R0VbBXfoULokoh7jDtLT9bS+p9acupJrDpSm3rgcdWu1KBAbHxTh p0zLKozOw==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLTAc-0003BJ-UC; Thu, 24 Sep 2020 15:28:30 +0000 Received: from mail-pj1-x1041.google.com ([2607:f8b0:4864:20::1041]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kLTAX-000394-19; Thu, 24 Sep 2020 15:28:26 +0000 Received: by mail-pj1-x1041.google.com with SMTP id q4so1880257pjh.5; Thu, 24 Sep 2020 08:28:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=vzz0659k4nwMVwakwm/RmtcC/L9vr67nkqocIx4yobo=; b=OEI3vPl+yd9QIKrq9/edbzxv4ksL18bROyX1URD2V/OelcE0t1iKUAP6iDZgDIC261 LKb8mf02MKWWNaQdnurAtYfmW9xYlXU+poqtaDanPW8I7bGg/R5caOTedxHIC3E/iIw4 Nh/WNn0BRTsriHXreeuhR0T1JFprH3Dh1AufH4ew5tch71spMA7p4z79FY+WoC5qkBB9 dmXPmdoRs9L5PiFnj88o6/m7IAz4I6my2tsFMvbdfHwMQr+X73NtV+/Gm9QXwJt2ETCu jZ4VaARxJ5X3DpFN4ACIZzyBxvvTicDqfO4Mum9tOJj3MjZ5fWt0EhKZxIp4aAt8q+Cm 5SSA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=vzz0659k4nwMVwakwm/RmtcC/L9vr67nkqocIx4yobo=; b=YmJDYPxxssV4uOLgCKnkiE/ZDIHrasx7EmEK5D0XclhVgqsuZ81MgKbDlzVw/3rG6c Ye7YED8mfwilaUZFty5eS3H/fiIdEmCy/Zc5G7YfaCscBsGJAFJe4j2NygIeLszfZXjg LuwMz4NerNq9HRNxRt2XT4ZzeSStXinYNblIRebUek8esuLCe7GSyM8EXZvzCQCTafZ0 3yISfRHJkKG3wf6zH2+mC121pLVGPOZ6FUtIy1M9Ma1uHlxFA02OJseG1Vd0j7aFUvXs 8xl/EePpLnw/KZPV8pwtYmVNapeAugyzEkkk+fYtR1mbsLSPm+2PfWf0GR3MgjupAR8e IIaw== X-Gm-Message-State: AOAM531H/JEPuxh3XMriLjZyAWbTYizq5uRhOnZYNbITx8rQcU8xtQHl cPFBuBgSRnWhu41CSARbHwI= X-Google-Smtp-Source: ABdhPJziJuVlIk0Pqjl8kKPAPvOSPiY8oac/jAD+WQLAQXWe0/6y7/sJek4nx6EQk8nCWigsCeI9/g== X-Received: by 2002:a17:902:bf08:b029:d1:bafb:ae2a with SMTP id bi8-20020a170902bf08b02900d1bafbae2amr4919264plb.39.1600961302878; Thu, 24 Sep 2020 08:28:22 -0700 (PDT) Received: from guoguo-omen.lan ([156.96.148.94]) by smtp.gmail.com with ESMTPSA id e62sm3233212pfh.76.2020.09.24.08.28.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 24 Sep 2020 08:28:22 -0700 (PDT) From: Chuanhong Guo To: linux-spi@vger.kernel.org Subject: [PATCH 1/3] spi: spi-mtk-nor: make use of full capability of prg mode Date: Thu, 24 Sep 2020 23:27:28 +0800 Message-Id: <20200924152730.733243-2-gch981213@gmail.com> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200924152730.733243-1-gch981213@gmail.com> References: <20200924152730.733243-1-gch981213@gmail.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200924_112825_130819_878F3D23 X-CRM114-Status: GOOD ( 21.19 ) X-Spam-Score: 2.6 (++) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (2.6 points) pts rule name description ---- ---------------------- -------------------------------------------------- 2.6 RCVD_IN_SBL RBL: Received via a relay in Spamhaus SBL [156.96.148.94 listed in zen.spamhaus.org] -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:1041 listed in] [list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider [gch981213[at]gmail.com] 0.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends in digit [gch981213[at]gmail.com] 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-kernel@vger.kernel.org, bayi.cheng@mediatek.com, Mark Brown , linux-mediatek@lists.infradead.org, Matthias Brugger , Chuanhong Guo , Ikjoon Jang , linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org "program" mode on this controller can trigger up to 56 bits of data shifting. During the operation, data in PRGDATA[0-5] will be shifted out from MOSI, and data from MISO will be continuously filling SHREG[0-9]. Currently this mode is used to implement transfer_one_message for 6-byte full-duplex transfer, but it can execute a transfer for up-to 7 bytes as long as the last byte is read only. transfer_one_message is expected to perform full-duplex transfer, instead of transfer with specific format. mtk_nor_spi_mem_prg is added here to use this extra byte. Newer version of this controller can trigger longer data shifting with shift bytes more than PRGDATA_MAX + SHREG_MAX. This patch is implemented with that in mind and it checks against both SHREG_MAX and PRG_CNT_MAX for future support of new controllers. Signed-off-by: Chuanhong Guo --- There are two calls of mtk_nor_spi_mem_prg in mtk_nor_exec_op, which doesn't look great. But I'd prefer keeping it this way to minimize change of mtk_nor_exec_op. I'll follow up with a cleanup patchset after this one gets merged. drivers/spi/spi-mtk-nor.c | 82 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-mtk-nor.c b/drivers/spi/spi-mtk-nor.c index 62f5ff2779884..a0087a5e869b9 100644 --- a/drivers/spi/spi-mtk-nor.c +++ b/drivers/spi/spi-mtk-nor.c @@ -27,6 +27,7 @@ #define MTK_NOR_CMD_MASK GENMASK(5, 0) #define MTK_NOR_REG_PRG_CNT 0x04 +#define MTK_NOR_PRG_CNT_MAX 56 #define MTK_NOR_REG_RDATA 0x0c #define MTK_NOR_REG_RADR0 0x10 @@ -404,6 +405,83 @@ static int mtk_nor_pp_unbuffered(struct mtk_nor *sp, return mtk_nor_cmd_exec(sp, MTK_NOR_CMD_WRITE, 6 * BITS_PER_BYTE); } +static int mtk_nor_spi_mem_prg(struct mtk_nor *sp, const struct spi_mem_op *op) +{ + int rx_len = 0; + int reg_offset = MTK_NOR_REG_PRGDATA_MAX; + int tx_len, prg_len; + int i, ret; + void __iomem *reg; + u8 bufbyte; + + tx_len = op->cmd.nbytes + op->addr.nbytes; + + // count dummy bytes only if we need to write data after it + if (op->data.dir == SPI_MEM_DATA_OUT) + tx_len += op->dummy.nbytes + op->data.nbytes; + else if (op->data.dir == SPI_MEM_DATA_IN) + rx_len = op->data.nbytes; + + prg_len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes + + op->data.nbytes; + + // an invalid op may reach here if the caller calls exec_op without + // adjust_op_size. return -EINVAL instead of -ENOTSUPP so that + // spi-mem won't try this op again with generic spi transfers. + if ((tx_len > MTK_NOR_REG_PRGDATA_MAX + 1) || + (rx_len > MTK_NOR_REG_SHIFT_MAX + 1) || + (prg_len > MTK_NOR_PRG_CNT_MAX / 8)) + return -EINVAL; + + // fill tx data + for (i = op->cmd.nbytes; i > 0; i--, reg_offset--) { + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); + bufbyte = (op->cmd.opcode >> ((i - 1) * BITS_PER_BYTE)) & 0xff; + writeb(bufbyte, reg); + } + + for (i = op->addr.nbytes; i > 0; i--, reg_offset--) { + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); + bufbyte = (op->addr.val >> ((i - 1) * BITS_PER_BYTE)) & 0xff; + writeb(bufbyte, reg); + } + + if (op->data.dir == SPI_MEM_DATA_OUT) { + for (i = 0; i < op->dummy.nbytes; i++, reg_offset--) { + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(0, reg); + } + + for (i = 0; i < op->data.nbytes; i++, reg_offset--) { + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(((const u8 *)(op->data.buf.out))[i], reg); + } + } + + for (; reg_offset >= 0; reg_offset--) { + reg = sp->base + MTK_NOR_REG_PRGDATA(reg_offset); + writeb(0, reg); + } + + // trigger op + writel(prg_len * BITS_PER_BYTE, sp->base + MTK_NOR_REG_PRG_CNT); + ret = mtk_nor_cmd_exec(sp, MTK_NOR_CMD_PROGRAM, + prg_len * BITS_PER_BYTE); + if (ret) + return ret; + + // fetch read data + reg_offset = 0; + if (op->data.dir == SPI_MEM_DATA_IN) { + for (i = op->data.nbytes - 1; i >= 0; i--, reg_offset++) { + reg = sp->base + MTK_NOR_REG_SHIFT(reg_offset); + ((u8 *)(op->data.buf.in))[i] = readb(reg); + } + } + + return 0; +} + static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) { struct mtk_nor *sp = spi_controller_get_devdata(mem->spi->master); @@ -411,7 +489,7 @@ static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) if ((op->data.nbytes == 0) || ((op->addr.nbytes != 3) && (op->addr.nbytes != 4))) - return -ENOTSUPP; + return mtk_nor_spi_mem_prg(sp, op); if (op->data.dir == SPI_MEM_DATA_OUT) { mtk_nor_set_addr(sp, op); @@ -441,7 +519,7 @@ static int mtk_nor_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) } } - return -ENOTSUPP; + return mtk_nor_spi_mem_prg(sp, op); } static int mtk_nor_setup(struct spi_device *spi)