From patchwork Fri Aug 7 14:43:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Anderson X-Patchwork-Id: 1342303 X-Patchwork-Delegate: jagannadh.teki@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=85.214.62.61; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20161025 header.b=q6AeHmQA; dkim-atps=neutral Received: from phobos.denx.de (phobos.denx.de [85.214.62.61]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BNSnv1Xndz9sTQ for ; Sat, 8 Aug 2020 00:45:23 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id F063A821DF; Fri, 7 Aug 2020 16:43:56 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="q6AeHmQA"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 633AE821EB; Fri, 7 Aug 2020 16:43:44 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FROM,SPF_HELO_NONE,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-qk1-x743.google.com (mail-qk1-x743.google.com [IPv6:2607:f8b0:4864:20::743]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 9DD93821D3 for ; Fri, 7 Aug 2020 16:43:40 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=seanga2@gmail.com Received: by mail-qk1-x743.google.com with SMTP id x69so1931815qkb.1 for ; Fri, 07 Aug 2020 07:43:40 -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=HROa6nWhsk41qItmP4XsraZI4j5kGcRYZqN/sp/7A88=; b=q6AeHmQA6qOi/x7NtVhR1kILdu+FpzqNIgTdcX+dUgkcP2yV7XxSUQKOeENYYlWlwK ejtdm75MuaUsamzkmd1HELLmeXYSD3ThEhtRJUZvVwKylglKEC3WQQsSVZ6dX0IWRCKW nyg9COyoCPLKuuKCC6HViFjIULeypXAYJsRR+c0VmCyoFWkBEwlOYAKFHE5oRQ0RpJHs syThBKL0tLZVAIp75mKQtUXx1xJsXoymhKVRlf0u1t5dEPeMowzddACmGLHHRr+FUJpS QgQuT9zQgbIRVH5RrD7sCaKCjEDikJu7KibZ9QNurX18kk7c8X5SjhgCmtqlQblf5HfJ 7WEA== 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=HROa6nWhsk41qItmP4XsraZI4j5kGcRYZqN/sp/7A88=; b=nIzAO3B4Up9LKtRgOmM/cqID86S9iT4492lQhczDSzZMfm1h2jAObsxVFZW+zA3cg2 azz8IVgsWUlvWP7oNr0Rs9HhhXldiPVY3rmCnBWz6Dn25I/j6DIkjwu1NcxeytDkxyPP U/6/WQkf0mHZK1DtSt63jRqsn0XC/zhuqu5C2l49y3brcVF1tpi15vlSqAaKuk9Zlixt UoreMa12/UhYOdZ5iWAhUbfi0iw8xqN8FJy80LwyDp/oXDf0NVdybpkjO/24lUPXuPj/ JicEtK1sZw+C2qlrqlazDVX9/cGN0J18Fc3HVwhVM7ANAyCBh/zNLEX8sw2PnoLmXSxy Qsvw== X-Gm-Message-State: AOAM530gdB5r90eVMCFKozmlYOLRqYESMDUPGFjt1YVnRbKNtHiK2WuQ +K6ETciHk19E9LVz6/xq1hyquYR1jfRmcA== X-Google-Smtp-Source: ABdhPJx4iXpG6FG9s92n0QUwtrmg3wcMLQfWFgVTOHxjXBJ8fqGqoUC1c4ZYZXLtGk1rH+dQ+XGWNQ== X-Received: by 2002:a37:b145:: with SMTP id a66mr13881649qkf.338.1596811419277; Fri, 07 Aug 2020 07:43:39 -0700 (PDT) Received: from godwin.fios-router.home (pool-108-51-35-162.washdc.fios.verizon.net. [108.51.35.162]) by smtp.gmail.com with ESMTPSA id k134sm6976538qke.60.2020.08.07.07.43.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Aug 2020 07:43:38 -0700 (PDT) From: Sean Anderson To: u-boot@lists.denx.de, uboot-snps-arc@synopsys.com Cc: Heinrich Schuchardt , Jagan Teki , Eugeniy Paltsev , Horatiu Vultur , Marek Vasut , Sean Anderson Subject: [PATCH v2 08/10] spi: dw: Add mem_ops Date: Fri, 7 Aug 2020 10:43:15 -0400 Message-Id: <20200807144317.282868-9-seanga2@gmail.com> X-Mailer: git-send-email 2.28.0 In-Reply-To: <20200807144317.282868-1-seanga2@gmail.com> References: <20200807144317.282868-1-seanga2@gmail.com> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean The designware ssi device has "broken" chip select behaviour [1], and needs specific manipulation to use the built-in chip select. The existing fix is to use an external GPIO for chip select, but typically the K210 has SPI3 directly connected to a flash chip with dedicated pins. This makes it impossible to use the spi_xfer function to use spi, since the CS is de-asserted in between calls. This patch adds an implementation of exec_op, which gives correct behaviour when reading/writing spi flash. [1] https://lkml.org/lkml/2015/12/23/132 Signed-off-by: Sean Anderson --- This patch was previously part of https://patchwork.ozlabs.org/project/uboot/list/?series=161576 Changes in v2: - Add external gpio cs support - Clean up exec_op - Convert debug to log_* - Limit data transfers to 64k drivers/spi/designware_spi.c | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index d9dc739d7d..62c0bda4cc 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -581,6 +582,108 @@ static int dw_spi_xfer(struct udevice *dev, unsigned int bitlen, return ret; } +/* + * This function is necessary for reading SPI flash with the native CS + * c.f. https://lkml.org/lkml/2015/12/23/132 + */ +static int dw_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op) +{ + bool read = op->data.dir == SPI_MEM_DATA_IN; + int pos, i, ret = 0; + struct udevice *bus = slave->dev->parent; + struct dw_spi_priv *priv = dev_get_priv(bus); + u8 op_len = sizeof(op->cmd.opcode) + op->addr.nbytes + op->dummy.nbytes; + u8 op_buf[op_len]; + u32 cr0; + + if (read) + priv->tmode = CTRLR0_TMOD_EPROMREAD; + else + priv->tmode = CTRLR0_TMOD_TO; + + log_debug("buf=%p len=%u [bytes]\n", op->data.buf.in, op->data.nbytes); + + cr0 = priv->update_cr0(priv); + log_debug("cr0=%08x\n", cr0); + + spi_enable_chip(priv, 0); + dw_write(priv, DW_SPI_CTRL0, cr0); + if (read) + dw_write(priv, DW_SPI_CTRL1, op->data.nbytes - 1); + spi_enable_chip(priv, 1); + + /* From spi_mem_exec_op */ + pos = 0; + op_buf[pos++] = op->cmd.opcode; + if (op->addr.nbytes) { + for (i = 0; i < op->addr.nbytes; i++) + op_buf[pos + i] = op->addr.val >> + (8 * (op->addr.nbytes - i - 1)); + + pos += op->addr.nbytes; + } + if (op->dummy.nbytes) + memset(op_buf + pos, 0xff, op->dummy.nbytes); + + external_cs_manage(slave->dev, false); + + priv->tx = &op_buf; + priv->tx_end = priv->tx + op_len; + priv->rx = NULL; + priv->rx_end = NULL; + while (priv->tx != priv->tx_end) + dw_writer(priv); + + /* + * XXX: The following are tight loops! Enabling debug messages may cause + * them to fail because we are not reading/writing the fifo fast enough. + */ + if (read) { + priv->rx = op->data.buf.in; + priv->rx_end = priv->rx + op->data.nbytes; + + dw_write(priv, DW_SPI_SER, 1 << spi_chip_select(slave->dev)); + while (priv->rx != priv->rx_end) + dw_reader(priv); + } else { + u32 val; + + priv->tx = op->data.buf.out; + priv->tx_end = priv->tx + op->data.nbytes; + + /* Fill up the write fifo before starting the transfer */ + dw_writer(priv); + dw_write(priv, DW_SPI_SER, 1 << spi_chip_select(slave->dev)); + while (priv->tx != priv->tx_end) + dw_writer(priv); + + if (readl_poll_timeout(priv->regs + DW_SPI_SR, val, + (val & SR_TF_EMPT) && !(val & SR_BUSY), + RX_TIMEOUT * 1000)) { + ret = -ETIMEDOUT; + } + } + + dw_write(priv, DW_SPI_SER, 0); + external_cs_manage(slave->dev, true); + + log_debug("%u bytes xfered\n", op->data.nbytes); + return ret; +} + +/* The size of ctrl1 limits data transfers to 64K */ +static int dw_spi_adjust_op_size(struct spi_slave *slave, struct spi_mem_op *op) +{ + op->data.nbytes = min(op->data.nbytes, (unsigned int)SZ_64K); + + return 0; +} + +static const struct spi_controller_mem_ops dw_spi_mem_ops = { + .exec_op = dw_spi_exec_op, + .adjust_op_size = dw_spi_adjust_op_size, +}; + static int dw_spi_set_speed(struct udevice *bus, uint speed) { struct dw_spi_platdata *plat = dev_get_platdata(bus); @@ -646,6 +749,7 @@ static int dw_spi_remove(struct udevice *bus) static const struct dm_spi_ops dw_spi_ops = { .xfer = dw_spi_xfer, + .mem_ops = &dw_spi_mem_ops, .set_speed = dw_spi_set_speed, .set_mode = dw_spi_set_mode, /*