From: Keiji Hayashibara <hayashibara.keiji@socionext.com> To: broonie@kernel.org, yamada.masahiro@socionext.com, linux-spi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: masami.hiramatsu@linaro.org, jaswinder.singh@linaro.org, linux-kernel@vger.kernel.org, hayashibara.keiji@socionext.com Subject: [PATCH 3/3] spi: uniphier: introduce polling mode Date: Tue, 3 Sep 2019 14:31:01 +0900 [thread overview] Message-ID: <1567488661-11428-4-git-send-email-hayashibara.keiji@socionext.com> (raw) In-Reply-To: <1567488661-11428-1-git-send-email-hayashibara.keiji@socionext.com> Introduce new polling mode for short size transfer. Either the estimated transfer time is estimated to exceed 200us, or polling loop actually exceeds 200us, it switches to irq mode. Signed-off-by: Keiji Hayashibara <hayashibara.keiji@socionext.com> --- drivers/spi/spi-uniphier.c | 81 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index d40ad93..6b83b25 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -7,6 +7,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -16,6 +17,7 @@ #include <asm/unaligned.h> #define SSI_TIMEOUT_MS 2000 +#define SSI_POLL_TIMEOUT_US 200 #define SSI_MAX_CLK_DIVIDER 254 #define SSI_MIN_CLK_DIVIDER 4 @@ -290,21 +292,23 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv) static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) { - unsigned int tx_count; + unsigned int fifo_threshold, fill_bytes; u32 val; - tx_count = DIV_ROUND_UP(priv->tx_bytes, + fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bytes_per_word(priv->bits_per_word)); - tx_count = min(tx_count, SSI_FIFO_DEPTH); + fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); + + fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes); /* set fifo threshold */ val = readl(priv->base + SSI_FC); val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); - val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count); - val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count); + val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold); + val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold); writel(val, priv->base + SSI_FC); - while (tx_count--) + while (fill_bytes--) uniphier_spi_send(priv); } @@ -323,20 +327,14 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) writel(val, priv->base + SSI_FPS); } -static int uniphier_spi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *t) +static int uniphier_spi_transfer_one_irq(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); struct device *dev = master->dev.parent; unsigned long time_left; - /* Terminate and return success for 0 byte length transfer */ - if (!t->len) - return 0; - - uniphier_spi_setup_transfer(spi, t); - reinit_completion(&priv->xfer_done); uniphier_spi_fill_tx_fifo(priv); @@ -356,6 +354,59 @@ static int uniphier_spi_transfer_one(struct spi_master *master, return priv->error; } +static int uniphier_spi_transfer_one_poll(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int loop = SSI_POLL_TIMEOUT_US * 10; + + while (priv->tx_bytes) { + uniphier_spi_fill_tx_fifo(priv); + + while ((priv->rx_bytes - priv->tx_bytes) > 0) { + while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE) + && loop--) + ndelay(100); + + if (loop == -1) + goto irq_transfer; + + uniphier_spi_recv(priv); + } + } + + return 0; + +irq_transfer: + return uniphier_spi_transfer_one_irq(master, spi, t); +} + +static int uniphier_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + unsigned long threshold; + + /* Terminate and return success for 0 byte length transfer */ + if (!t->len) + return 0; + + uniphier_spi_setup_transfer(spi, t); + + /* + * If the transfer operation will take longer than + * SSI_POLL_TIMEOUT_US, it should use irq. + */ + threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, + USEC_PER_SEC * BITS_PER_BYTE); + if (t->len > threshold) + return uniphier_spi_transfer_one_irq(master, spi, t); + else + return uniphier_spi_transfer_one_poll(master, spi, t); +} + static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); -- 2.7.4
WARNING: multiple messages have this Message-ID (diff)
From: Keiji Hayashibara <hayashibara.keiji@socionext.com> To: broonie@kernel.org, yamada.masahiro@socionext.com, linux-spi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: jaswinder.singh@linaro.org, linux-kernel@vger.kernel.org, masami.hiramatsu@linaro.org, hayashibara.keiji@socionext.com Subject: [PATCH 3/3] spi: uniphier: introduce polling mode Date: Tue, 3 Sep 2019 14:31:01 +0900 [thread overview] Message-ID: <1567488661-11428-4-git-send-email-hayashibara.keiji@socionext.com> (raw) In-Reply-To: <1567488661-11428-1-git-send-email-hayashibara.keiji@socionext.com> Introduce new polling mode for short size transfer. Either the estimated transfer time is estimated to exceed 200us, or polling loop actually exceeds 200us, it switches to irq mode. Signed-off-by: Keiji Hayashibara <hayashibara.keiji@socionext.com> --- drivers/spi/spi-uniphier.c | 81 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-uniphier.c b/drivers/spi/spi-uniphier.c index d40ad93..6b83b25 100644 --- a/drivers/spi/spi-uniphier.c +++ b/drivers/spi/spi-uniphier.c @@ -7,6 +7,7 @@ #include <linux/bitfield.h> #include <linux/bitops.h> #include <linux/clk.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> @@ -16,6 +17,7 @@ #include <asm/unaligned.h> #define SSI_TIMEOUT_MS 2000 +#define SSI_POLL_TIMEOUT_US 200 #define SSI_MAX_CLK_DIVIDER 254 #define SSI_MIN_CLK_DIVIDER 4 @@ -290,21 +292,23 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv) static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv) { - unsigned int tx_count; + unsigned int fifo_threshold, fill_bytes; u32 val; - tx_count = DIV_ROUND_UP(priv->tx_bytes, + fifo_threshold = DIV_ROUND_UP(priv->rx_bytes, bytes_per_word(priv->bits_per_word)); - tx_count = min(tx_count, SSI_FIFO_DEPTH); + fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH); + + fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes); /* set fifo threshold */ val = readl(priv->base + SSI_FC); val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK); - val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count); - val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count); + val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold); + val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold); writel(val, priv->base + SSI_FC); - while (tx_count--) + while (fill_bytes--) uniphier_spi_send(priv); } @@ -323,20 +327,14 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable) writel(val, priv->base + SSI_FPS); } -static int uniphier_spi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *t) +static int uniphier_spi_transfer_one_irq(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); struct device *dev = master->dev.parent; unsigned long time_left; - /* Terminate and return success for 0 byte length transfer */ - if (!t->len) - return 0; - - uniphier_spi_setup_transfer(spi, t); - reinit_completion(&priv->xfer_done); uniphier_spi_fill_tx_fifo(priv); @@ -356,6 +354,59 @@ static int uniphier_spi_transfer_one(struct spi_master *master, return priv->error; } +static int uniphier_spi_transfer_one_poll(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + int loop = SSI_POLL_TIMEOUT_US * 10; + + while (priv->tx_bytes) { + uniphier_spi_fill_tx_fifo(priv); + + while ((priv->rx_bytes - priv->tx_bytes) > 0) { + while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE) + && loop--) + ndelay(100); + + if (loop == -1) + goto irq_transfer; + + uniphier_spi_recv(priv); + } + } + + return 0; + +irq_transfer: + return uniphier_spi_transfer_one_irq(master, spi, t); +} + +static int uniphier_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) +{ + struct uniphier_spi_priv *priv = spi_master_get_devdata(master); + unsigned long threshold; + + /* Terminate and return success for 0 byte length transfer */ + if (!t->len) + return 0; + + uniphier_spi_setup_transfer(spi, t); + + /* + * If the transfer operation will take longer than + * SSI_POLL_TIMEOUT_US, it should use irq. + */ + threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz, + USEC_PER_SEC * BITS_PER_BYTE); + if (t->len > threshold) + return uniphier_spi_transfer_one_irq(master, spi, t); + else + return uniphier_spi_transfer_one_poll(master, spi, t); +} + static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master) { struct uniphier_spi_priv *priv = spi_master_get_devdata(master); -- 2.7.4 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
next prev parent reply other threads:[~2019-09-03 5:31 UTC|newest] Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-09-03 5:30 [PATCH 0/3] spi: uniphier: introduce polling mode and fix bug Keiji Hayashibara 2019-09-03 5:30 ` Keiji Hayashibara 2019-09-03 5:30 ` [PATCH 1/3] spi: uniphier: fix wrong register overwrite Keiji Hayashibara 2019-09-03 5:30 ` Keiji Hayashibara 2019-09-03 11:57 ` Applied "spi: uniphier: fix wrong register overwrite" to the spi tree Mark Brown 2019-09-03 11:57 ` Mark Brown 2019-09-03 11:57 ` Mark Brown 2019-09-03 5:31 ` [PATCH 2/3] spi: uniphier: remove unnecessary code Keiji Hayashibara 2019-09-03 5:31 ` Keiji Hayashibara 2019-09-03 11:57 ` Applied "spi: uniphier: remove unnecessary code" to the spi tree Mark Brown 2019-09-03 11:57 ` Mark Brown 2019-09-03 11:57 ` Mark Brown 2019-09-03 5:31 ` Keiji Hayashibara [this message] 2019-09-03 5:31 ` [PATCH 3/3] spi: uniphier: introduce polling mode Keiji Hayashibara 2019-09-03 11:57 ` Applied "spi: uniphier: introduce polling mode" to the spi tree Mark Brown 2019-09-03 11:57 ` Mark Brown 2019-09-03 11:57 ` Mark Brown
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1567488661-11428-4-git-send-email-hayashibara.keiji@socionext.com \ --to=hayashibara.keiji@socionext.com \ --cc=broonie@kernel.org \ --cc=jaswinder.singh@linaro.org \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=linux-spi@vger.kernel.org \ --cc=masami.hiramatsu@linaro.org \ --cc=yamada.masahiro@socionext.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.