Message ID | 20230124221218.341511-9-william.zhang@broadcom.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:eb09:0:0:0:0:0 with SMTP id s9csp2405572wrn; Tue, 24 Jan 2023 14:36:08 -0800 (PST) X-Google-Smtp-Source: AMrXdXsVNkjEIgmUOAuL8ZHkM3Qg18rq12n3wJnKS3c/w0hxO8AdDQ4FsEqt1sl0d/NmvwbJhui9 X-Received: by 2002:a17:906:3a97:b0:86e:bbdf:95c5 with SMTP id y23-20020a1709063a9700b0086ebbdf95c5mr32801474ejd.26.1674599768653; Tue, 24 Jan 2023 14:36:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1674599768; cv=none; d=google.com; s=arc-20160816; b=hlP5qRkkRUyysnyxnNH9GjcRf+omVu86Lcvbo/wNNhzR2PtmJROGwr9vJNIuttAvUO KH+NrIkHtk+MxxmFiT3E3WanWL8sxoURTJaUPWNCJemA6lmsii4gAS6bRvm9ilvtoOza 8YpFU51kmynxko2t0MfL8Fd8sYcD+RGOPD/i/DnkrzY/dsSpp+tpxQTd5NFjyqixsS5E gEn0lNAJ6gnQUg5t1W+BnT/9ZFexs2CUDfdSvmBQcXyeJsxglEmV98Pm6KwZEx+cgytQ UHf3GCTXg5wfDiI2zFyDJCdf0vzwXSJLIP+L+CF9TCQe6vyPBgI7+cPfcC4HyBDhfiOL 0eVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:dkim-filter; bh=PRoSEq2QC4qm0MmM5NEoeNJKpHQMh3aNqQO7SRwDIRs=; b=dFP7RDv/JBN/NJG8YMT90rZUig67zuZj5TspcIdcsfL9oR1ZF4nL0ujEPa4//Ml/Oz HJWUPwFnaIPasVhyOuABJfFh22yF5YsAzAW/sjl2kB8zlo3bqGaLIwhxjDdidREHU1hB 5FFOZlbP+YniwjELMUgQICIdIZTHf2nYSq5IfXPgWq7PidrwYqvF+a4OOC1+z470/Itt 3hx2Zb6WJwfS5dNOaVHvVzVoX6gYGCwx85R4e7qjBvOO5XjoQ2VzARxyUoj7QGznu5m8 qwJ4C/iEXyC2Negaei5kUYLyTKkUPxibzNvnuE/agAAzPZStsXW0CjQSRUEoxXRNtXOH VWIA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@broadcom.com header.s=dkimrelay header.b=ETTpjJFx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=broadcom.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id mx14-20020a1709065a0e00b0084d3d86a628si3712812ejc.410.2023.01.24.14.35.44; Tue, 24 Jan 2023 14:36:08 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@broadcom.com header.s=dkimrelay header.b=ETTpjJFx; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=broadcom.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234764AbjAXWdn (ORCPT <rfc822;rust.linux@gmail.com> + 99 others); Tue, 24 Jan 2023 17:33:43 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32886 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235075AbjAXWdV (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Tue, 24 Jan 2023 17:33:21 -0500 Received: from relay.smtp-ext.broadcom.com (lpdvacalvio01.broadcom.com [192.19.166.228]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 785EE530E8; Tue, 24 Jan 2023 14:33:07 -0800 (PST) Received: from mail-lvn-it-01.lvn.broadcom.net (mail-lvn-it-01.lvn.broadcom.net [10.75.146.107]) by relay.smtp-ext.broadcom.com (Postfix) with ESMTP id 1B79DC0000E8; Tue, 24 Jan 2023 14:33:07 -0800 (PST) DKIM-Filter: OpenDKIM Filter v2.11.0 relay.smtp-ext.broadcom.com 1B79DC0000E8 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=broadcom.com; s=dkimrelay; t=1674599587; bh=J1uqvs80rFu4ZJ4yuFFt4i7aXR50M8kpaFeq7uY4yfE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ETTpjJFxHsLLLvrL2EDCEKfYaye/YncGW6BVONuFREHze7Ps9oSP2ssnobUwfl+TE kPGM2JyZ8g18SQ2FS4aY8zpouS3LwVFfMSczymkK9EFCn5nCF4VnBbSfNC2UkFSTb1 JgiFUckzc8/5cT0AkzTq8H5tsFtiBOlKNJp78t4I= Received: from bcacpedev-irv-3.lvn.broadcom.net (bcacpedev-irv-3.lvn.broadcom.net [10.75.138.105]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail-lvn-it-01.lvn.broadcom.net (Postfix) with ESMTPS id 19FA618041CAC6; Tue, 24 Jan 2023 14:33:07 -0800 (PST) Received: by bcacpedev-irv-3.lvn.broadcom.net (Postfix, from userid 28376) id 5ED65101B55; Tue, 24 Jan 2023 14:33:00 -0800 (PST) From: William Zhang <william.zhang@broadcom.com> To: Linux SPI List <linux-spi@vger.kernel.org>, Broadcom Kernel List <bcm-kernel-feedback-list@broadcom.com> Cc: tomer.yacoby@broadcom.com, kursad.oney@broadcom.com, dregan@mail.com, f.fainelli@gmail.com, anand.gore@broadcom.com, jonas.gorski@gmail.com, dan.beygelman@broadcom.com, joel.peshkin@broadcom.com, William Zhang <william.zhang@broadcom.com>, Mark Brown <broonie@kernel.org>, linux-kernel@vger.kernel.org Subject: [PATCH v2 08/14] spi: bcm63xx-hsspi: Handle cs_change correctly Date: Tue, 24 Jan 2023 14:12:11 -0800 Message-Id: <20230124221218.341511-9-william.zhang@broadcom.com> X-Mailer: git-send-email 2.37.3 In-Reply-To: <20230124221218.341511-1-william.zhang@broadcom.com> References: <20230124221218.341511-1-william.zhang@broadcom.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE, SPF_NONE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1755945127465544299?= X-GMAIL-MSGID: =?utf-8?q?1755945127465544299?= |
Series |
spi: bcm63xx-hsspi: driver and doc updates
|
|
Commit Message
William Zhang
Jan. 24, 2023, 10:12 p.m. UTC
The kernel SPI interface includes the cs_change flag that alters how the CS behaves. If we're in the middle of transfers, it tells us to unselect the CS momentarily since the target device requires that. If we're at the end of a transfer, it tells us to keep the CS selected, perhaps because the next transfer is likely targeted to the same device. We implement this scheme in the HSSPI driver in this change. Prior to this change, the CS would toggle momentarily if cs_change was set for the last transfer. This can be ignored by some or most devices, but the Microchip TPM2 device does not ignore it. With the change, the behavior is corrected and the 'glitch' is eliminated. Signed-off-by: Kursad Oney <kursad.oney@broadcom.com> Signed-off-by: William Zhang <william.zhang@broadcom.com> --- Changes in v2: - Fix unused variable ‘reg’ compile warning drivers/spi/spi-bcm63xx-hsspi.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-)
Comments
On Tue, 24 Jan 2023 at 23:33, William Zhang <william.zhang@broadcom.com> wrote: > > The kernel SPI interface includes the cs_change flag that alters how > the CS behaves. > > If we're in the middle of transfers, it tells us to unselect the > CS momentarily since the target device requires that. > > If we're at the end of a transfer, it tells us to keep the CS > selected, perhaps because the next transfer is likely targeted > to the same device. > > We implement this scheme in the HSSPI driver in this change. > > Prior to this change, the CS would toggle momentarily if cs_change > was set for the last transfer. This can be ignored by some or > most devices, but the Microchip TPM2 device does not ignore it. > > With the change, the behavior is corrected and the 'glitch' is > eliminated. > > Signed-off-by: Kursad Oney <kursad.oney@broadcom.com> > Signed-off-by: William Zhang <william.zhang@broadcom.com> > > --- > > Changes in v2: > - Fix unused variable ‘reg’ compile warning > > drivers/spi/spi-bcm63xx-hsspi.c | 29 +++++++++++++++++++++-------- > 1 file changed, 21 insertions(+), 8 deletions(-) > > diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c > index 55cbe7deba08..696e14abba2d 100644 > --- a/drivers/spi/spi-bcm63xx-hsspi.c > +++ b/drivers/spi/spi-bcm63xx-hsspi.c > @@ -338,7 +338,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, > struct spi_device *spi = msg->spi; > int status = -EINVAL; > int dummy_cs; > - u32 reg; > + bool restore_polarity = true; While restore polarity is how this is implemented, I think using a more semantic name like keep_cs would be better. > > mutex_lock(&bs->msg_mutex); > /* This controller does not support keeping CS active during idle. > @@ -367,16 +367,29 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, > > spi_transfer_delay_exec(t); > > - if (t->cs_change) > + /* > + * cs_change rules: > + * (1) cs_change = 0 && last_xfer = 0: > + * Do not touch the CS. On to the next xfer. > + * (2) cs_change = 1 && last_xfer = 0: > + * Set cs = false before the next xfer. > + * (3) cs_change = 0 && last_xfer = 1: > + * We want CS to be deactivated. So do NOT set cs = false, > + * instead just restore the original polarity. This has the > + * same effect of deactivating the CS. > + * (4) cs_change = 1 && last_xfer = 1: > + * We want to keep CS active. So do NOT set cs = false, and > + * make sure we do NOT reverse polarity. > + */ > + if (t->cs_change && !list_is_last(&t->transfer_list, &msg->transfers)) > bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); > + > + restore_polarity = !t->cs_change; > } I still find setting restore_polarity on each loop iteration when only its last set value matters confusing and hard to read, so I still propose keeping close to the generic implementation ( https://elixir.bootlin.com/linux/v6.1.8/source/drivers/spi/spi.c#L1560 ) and do if (t->cs_change) { if (list_is_last()) restore_polarity = false; else bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); } While there, you might also want to check the cs_off value(s) as well. > > - mutex_lock(&bs->bus_mutex); > - reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); > - reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK; > - reg |= bs->cs_polarity; > - __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG); > - mutex_unlock(&bs->bus_mutex); > + bcm63xx_hsspi_set_cs(bs, dummy_cs, false); > + if (restore_polarity) > + bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); > > mutex_unlock(&bs->msg_mutex); > msg->status = status; > -- > 2.37.3 >
Hi Jonas, William, On Thu, Jan 26, 2023 at 10:13 AM Jonas Gorski <jonas.gorski@gmail.com> wrote: > > On Tue, 24 Jan 2023 at 23:33, William Zhang <william.zhang@broadcom.com> wrote: > > > > The kernel SPI interface includes the cs_change flag that alters how > > the CS behaves. > > > > If we're in the middle of transfers, it tells us to unselect the > > CS momentarily since the target device requires that. > > > > If we're at the end of a transfer, it tells us to keep the CS > > selected, perhaps because the next transfer is likely targeted > > to the same device. > > > > We implement this scheme in the HSSPI driver in this change. > > > > Prior to this change, the CS would toggle momentarily if cs_change > > was set for the last transfer. This can be ignored by some or > > most devices, but the Microchip TPM2 device does not ignore it. > > > > With the change, the behavior is corrected and the 'glitch' is > > eliminated. > > > > Signed-off-by: Kursad Oney <kursad.oney@broadcom.com> > > Signed-off-by: William Zhang <william.zhang@broadcom.com> > > > > --- > > > > Changes in v2: > > - Fix unused variable ‘reg’ compile warning > > > > drivers/spi/spi-bcm63xx-hsspi.c | 29 +++++++++++++++++++++-------- > > 1 file changed, 21 insertions(+), 8 deletions(-) > > > > diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c > > index 55cbe7deba08..696e14abba2d 100644 > > --- a/drivers/spi/spi-bcm63xx-hsspi.c > > +++ b/drivers/spi/spi-bcm63xx-hsspi.c > > @@ -338,7 +338,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, > > struct spi_device *spi = msg->spi; > > int status = -EINVAL; > > int dummy_cs; > > - u32 reg; > > + bool restore_polarity = true; > > While restore polarity is how this is implemented, I think using a > more semantic name like keep_cs would be better. This sounds reasonable to me. > > > > > mutex_lock(&bs->msg_mutex); > > /* This controller does not support keeping CS active during idle. > > @@ -367,16 +367,29 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, > > > > spi_transfer_delay_exec(t); > > > > - if (t->cs_change) > > + /* > > + * cs_change rules: > > + * (1) cs_change = 0 && last_xfer = 0: > > + * Do not touch the CS. On to the next xfer. > > + * (2) cs_change = 1 && last_xfer = 0: > > + * Set cs = false before the next xfer. > > + * (3) cs_change = 0 && last_xfer = 1: > > + * We want CS to be deactivated. So do NOT set cs = false, > > + * instead just restore the original polarity. This has the > > + * same effect of deactivating the CS. > > + * (4) cs_change = 1 && last_xfer = 1: > > + * We want to keep CS active. So do NOT set cs = false, and > > + * make sure we do NOT reverse polarity. > > + */ > > + if (t->cs_change && !list_is_last(&t->transfer_list, &msg->transfers)) > > bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); > > + > > + restore_polarity = !t->cs_change; > > } > > I still find setting restore_polarity on each loop iteration when only > its last set value matters confusing and hard to read, so I still > propose keeping close to the generic implementation ( > https://elixir.bootlin.com/linux/v6.1.8/source/drivers/spi/spi.c#L1560 > ) and do > > if (t->cs_change) { > if (list_is_last()) > restore_polarity = false; > else > bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); > } OK I think this makes sense too but it might be a bit clearer to do: if (list_is_last()) { if (cs_change) keep_cs = false; else bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); } The gating condition here is when we reach the final transfer. But list_is_last() is more expensive, so that's another consideration. > > While there, you might also want to check the cs_off value(s) as well. Can you explain this please? > > > > > > > - mutex_lock(&bs->bus_mutex); > > - reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); > > - reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK; > > - reg |= bs->cs_polarity; > > - __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG); > > - mutex_unlock(&bs->bus_mutex); > > + bcm63xx_hsspi_set_cs(bs, dummy_cs, false); > > + if (restore_polarity) > > + bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); > > > > mutex_unlock(&bs->msg_mutex); > > msg->status = status; > > -- > > 2.37.3 > >
Hi Kursad, On Thu, 26 Jan 2023 at 17:22, Kursad Oney <kursad.oney@broadcom.com> wrote: > > > > While there, you might also want to check the cs_off value(s) as well. > > Can you explain this please? I'm talking about the transfer property cs_off: " @cs_off: performs the transfer with chipselect off." See how it is handled in the generic spi_transfer_one_message(): spi_set_cs(msg->spi, !xfer->cs_off, false); ... list_for_each_entry(xfer, &msg->transfers, transfer_list) { ... if (xfer->cs_change) { if (list_is_last(&xfer->transfer_list, &msg->transfers)) { keep_cs = true; } else { if (!xfer->cs_off) spi_set_cs(msg->spi, false, false); _spi_transfer_cs_change_delay(msg, xfer); if (!list_next_entry(xfer, transfer_list)->cs_off) spi_set_cs(msg->spi, true, false); } } else if (!list_is_last(&xfer->transfer_list, &msg->transfers) && xfer->cs_off != list_next_entry(xfer, transfer_list)->cs_off) { spi_set_cs(msg->spi, xfer->cs_off, false); } ... } if we fix the cs_change handling, we might as well bring it up to state. In theory I would suggest to switch to implementing the set_cs() / transfer_one() so you could let the core take care of all of that, but that wouldn't work with dynamically switching to prepend mode. Might be something for v1.1 though. Regards Jonas
On 01/26/2023 09:33 AM, Jonas Gorski wrote: > Hi Kursad, > > On Thu, 26 Jan 2023 at 17:22, Kursad Oney <kursad.oney@broadcom.com> wrote: >>> >>> While there, you might also want to check the cs_off value(s) as well. >> >> Can you explain this please? > > I'm talking about the transfer property cs_off: > > " @cs_off: performs the transfer with chipselect off." > > See how it is handled in the generic spi_transfer_one_message(): > > spi_set_cs(msg->spi, !xfer->cs_off, false); > ... > list_for_each_entry(xfer, &msg->transfers, transfer_list) { > ... > if (xfer->cs_change) { > if (list_is_last(&xfer->transfer_list, > &msg->transfers)) { > keep_cs = true; > } else { > if (!xfer->cs_off) > spi_set_cs(msg->spi, false, false); > _spi_transfer_cs_change_delay(msg, xfer); > if (!list_next_entry(xfer, > transfer_list)->cs_off) > spi_set_cs(msg->spi, true, false); > } > } else if (!list_is_last(&xfer->transfer_list, > &msg->transfers) && > xfer->cs_off != list_next_entry(xfer, > transfer_list)->cs_off) { > spi_set_cs(msg->spi, xfer->cs_off, false); > } > ... > } > > if we fix the cs_change handling, we might as well bring it up to state. > We can blindly port this logic over but this cs_off stuff (from the spi.h comment @cs_off: performs the transfer with chipselect off) sounds weird. What kind of device do transfer when cs is off? I don't have any device like this to test. > In theory I would suggest to switch to implementing the set_cs() / > transfer_one() so you could let the core take care of all of that, but > that wouldn't work with dynamically switching to prepend mode. Might > be something for v1.1 though. > That is good idea and I can certainly try that. > > Regards > Jonas >
diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index 55cbe7deba08..696e14abba2d 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -338,7 +338,7 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, struct spi_device *spi = msg->spi; int status = -EINVAL; int dummy_cs; - u32 reg; + bool restore_polarity = true; mutex_lock(&bs->msg_mutex); /* This controller does not support keeping CS active during idle. @@ -367,16 +367,29 @@ static int bcm63xx_hsspi_transfer_one(struct spi_master *master, spi_transfer_delay_exec(t); - if (t->cs_change) + /* + * cs_change rules: + * (1) cs_change = 0 && last_xfer = 0: + * Do not touch the CS. On to the next xfer. + * (2) cs_change = 1 && last_xfer = 0: + * Set cs = false before the next xfer. + * (3) cs_change = 0 && last_xfer = 1: + * We want CS to be deactivated. So do NOT set cs = false, + * instead just restore the original polarity. This has the + * same effect of deactivating the CS. + * (4) cs_change = 1 && last_xfer = 1: + * We want to keep CS active. So do NOT set cs = false, and + * make sure we do NOT reverse polarity. + */ + if (t->cs_change && !list_is_last(&t->transfer_list, &msg->transfers)) bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); + + restore_polarity = !t->cs_change; } - mutex_lock(&bs->bus_mutex); - reg = __raw_readl(bs->regs + HSSPI_GLOBAL_CTRL_REG); - reg &= ~GLOBAL_CTRL_CS_POLARITY_MASK; - reg |= bs->cs_polarity; - __raw_writel(reg, bs->regs + HSSPI_GLOBAL_CTRL_REG); - mutex_unlock(&bs->bus_mutex); + bcm63xx_hsspi_set_cs(bs, dummy_cs, false); + if (restore_polarity) + bcm63xx_hsspi_set_cs(bs, spi->chip_select, false); mutex_unlock(&bs->msg_mutex); msg->status = status;