2024-01-25 14:58:11

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 00/28] spi: s3c64xx: winter cleanup and gs101 support

Hi,

Special attention is needed for:
``asm-generic/io.h: add iowrite{8,16}_32 accessors``
as it's not under SPI's umbrella.

If the accessors are fine, I expect they'll be queued either to the
SPI tree or to the ASM header files tree, but by providing an immutable
tag, so that the other tree can merge them too.

The spi dt-bindings patches can be queued through the SPI tree, but
they'll need an immutable tag too. They'll be needed in the samsung tree
as I'll follow with patches for the samsung device trees to use the
"samsung,spi-fifosize" property.

The patch set cleans a bit the driver and adds support for gs101 SPI.
For the cleaning part, I removed the unfortunate dependency between the
SPI of_alias and the fifo_lvl_mask array from the driver. The SPI
of_alias was used as an index into the fifo_lvl_mask to determine the
FIFO depth of the SPI node. Changing the alias ID into the device tree
would make the driver choose a wrong FIFO size configuration, if not
accessing past the fifo_lvl_mask array boundaries. Not specifying an SPI
alias would make the driver fail to probe, which is wrong too.

Apart of the SPI patches, I added support for iowrite{8,16}_32 accessors
in asm-generic/io.h. This will allow devices that require 32 bits
register accesses to write data in chunks of 8 or 16 bits (a typical use
case is SPI, where clients can request transfers in words of 8 bits for
example). GS101 only allows 32bit register accesses otherwise it raisses
a Serror Interrupt and hangs the system, thus the accessors are needed
here.

The first 3 patches are fixes and they are intentionally put at the
beginning of the series so that they can be easily queued to the stable
kernels.

The SPI patches were tested with the spi-loopback-test on the gs101
controller.

Thanks!
ta

Changes in v2:
- move fixes at the beginning of the series so that they can be queued
easily to the stable kernels.
- break the dependency between the SPI of_alias, the fifo_lvl_mask and
the FIFO depth. Provide alternatives to either infer the FIFO size
from the compatible, where the SoC uses the same FIFO size for all the
instances of the IP, or by using the "samsung,spi-fifosize" dt
property, where the SoC uses different FIFO sizes for the instances of
the IP.
- split patches or other cosmetic changes, collect R-b tags.

Tudor Ambarus (28):
spi: s3c64xx: explicitly include <linux/io.h>
spi: s3c64xx: explicitly include <linux/bits.h>
spi: s3c64xx: avoid possible negative array index
spi: dt-bindings: samsung: add google,gs101-spi compatible
spi: dt-bindings: samsung: add samsung,spi-fifosize property
spi: s3c64xx: sort headers alphabetically
spi: s3c64xx: remove unneeded (void *) casts in of_match_table
spi: s3c64xx: remove else after return
spi: s3c64xx: use bitfield access macros
spi: s3c64xx: use full mask for {RX, TX}_FIFO_LVL
spi: s3c64xx: move common code outside if else
spi: s3c64xx: check return code of dmaengine_slave_config()
spi: s3c64xx: propagate the dma_submit_error() error code
spi: s3c64xx: rename prepare_dma() to s3c64xx_prepare_dma()
spi: s3c64xx: return ETIMEDOUT for wait_for_completion_timeout()
spi: s3c64xx: simplify s3c64xx_wait_for_pio()
spi: s3c64xx: drop blank line between declarations
spi: s3c64xx: fix typo, s/configuartion/configuration
spi: s3c64xx: downgrade dev_warn to dev_dbg for optional dt props
spi: s3c64xx: add support for inferring fifosize from the compatible
spi: s3c64xx: infer fifosize from the compatible
spi: s3c64xx: drop dependency on of_alias where possible
spi: s3c64xx: retrieve the FIFO size from the device tree
spi: s3c64xx: mark fifo_lvl_mask as deprecated
asm-generic/io.h: add iowrite{8,16}_32 accessors
spi: s3c64xx: add iowrite{8,16}_32_rep accessors
spi: s3c64xx: add support for google,gs101-spi
MAINTAINERS: add Tudor Ambarus as R for the samsung SPI driver

.../devicetree/bindings/spi/samsung,spi.yaml | 6 +
MAINTAINERS | 1 +
drivers/spi/spi-s3c64xx.c | 530 ++++++++++--------
include/asm-generic/io.h | 50 ++
include/asm-generic/iomap.h | 2 +
5 files changed, 345 insertions(+), 244 deletions(-)

--
2.43.0.429.g432eaa2c6b-goog



2024-01-25 14:58:15

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 27/28] spi: s3c64xx: add support for google,gs101-spi

Add support for GS101 SPI. All the SPI nodes on GS101 have 64 bytes
FIFOs, infer the FIFO size from the compatible. GS101 allows just 32bit
register accesses, otherwise a Serror Interrupt is raised. Do the write
reg accesses in 32 bits.

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 35a2d5554dfd..e887be6955a0 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1501,6 +1501,18 @@ static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
};

+static const struct s3c64xx_spi_port_config gs101_spi_port_config = {
+ .fifosize = 64,
+ .rx_lvl_offset = 15,
+ .tx_st_done = 25,
+ .clk_div = 4,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .has_loopback = true,
+ .use_32bit_io = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static const struct s3c64xx_spi_port_config fsd_spi_port_config = {
.fifosize = 64,
.rx_lvl_offset = 15,
@@ -1556,6 +1568,10 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
.compatible = "samsung,exynosautov9-spi",
.data = &exynosautov9_spi_port_config,
},
+ {
+ .compatible = "google,gs101-spi",
+ .data = &gs101_spi_port_config,
+ },
{
.compatible = "tesla,fsd-spi",
.data = &fsd_spi_port_config,
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 14:58:17

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 26/28] spi: s3c64xx: add iowrite{8,16}_32_rep accessors

There are SoCs that allow just 32 bit register accesses otherwise they
throw a SError interrupt if accessing the bus with 8 or 16 bits widths.
Such an SoC is the google gs101. Allow such SoCs to use the
iowrite{8,16}_32_rep accessors.

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 46 +++++++++++++++++++++++++++------------
1 file changed, 32 insertions(+), 14 deletions(-)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index fa70c6aab7c2..35a2d5554dfd 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -139,6 +139,7 @@ struct s3c64xx_spi_dma_data {
* prescaler unit.
* @clk_ioclk: True if clock is present on this device
* @has_loopback: True if loopback mode can be supported
+ * @use_32bit_io: True if the SoC allows just 32-bit register accesses.
*
* The Samsung s3c64xx SPI controller are used on various Samsung SoC's but
* differ in some aspects such as the size of the fifo and spi bus clock
@@ -156,6 +157,7 @@ struct s3c64xx_spi_port_config {
bool clk_from_cmu;
bool clk_ioclk;
bool has_loopback;
+ bool use_32bit_io;
};

/**
@@ -412,6 +414,35 @@ static bool s3c64xx_spi_can_dma(struct spi_controller *host,
return false;
}

+static void s3c64xx_iowrite_rep(const struct s3c64xx_spi_driver_data *sdd,
+ struct spi_transfer *xfer)
+{
+ void __iomem *regs = sdd->regs;
+
+ switch (sdd->cur_bpw) {
+ case 32:
+ iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
+ xfer->tx_buf, xfer->len / 4);
+ break;
+ case 16:
+ if (sdd->port_conf->use_32bit_io)
+ iowrite16_32_rep(regs + S3C64XX_SPI_TX_DATA,
+ xfer->tx_buf, xfer->len / 2);
+ else
+ iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
+ xfer->tx_buf, xfer->len / 2);
+ break;
+ default:
+ if (sdd->port_conf->use_32bit_io)
+ iowrite8_32_rep(regs + S3C64XX_SPI_TX_DATA,
+ xfer->tx_buf, xfer->len);
+ else
+ iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
+ xfer->tx_buf, xfer->len);
+ break;
+ }
+}
+
static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
struct spi_transfer *xfer, int dma_mode)
{
@@ -445,20 +476,7 @@ static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
ret = s3c64xx_prepare_dma(&sdd->tx_dma, &xfer->tx_sg);
} else {
- switch (sdd->cur_bpw) {
- case 32:
- iowrite32_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len / 4);
- break;
- case 16:
- iowrite16_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len / 2);
- break;
- default:
- iowrite8_rep(regs + S3C64XX_SPI_TX_DATA,
- xfer->tx_buf, xfer->len);
- break;
- }
+ s3c64xx_iowrite_rep(sdd, xfer);
}
}

--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 14:58:49

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 22/28] spi: s3c64xx: drop dependency on of_alias where possible

Remove the dependency on the OF alias for SoCs that use the same FIFO
size for all the instances of the SPI IP. The driver failed to probe if
an SPI alias was not provided, which is obviously wrong.

We now let the SPI core determine the SPI alias, either by getting the
alias ID, or by allocating a dynamic bus number when the alias is
absent.

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 61 ++++++++++++++++++++++++---------------
1 file changed, 38 insertions(+), 23 deletions(-)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index b86eb0a77b60..7a99f6b02319 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -107,10 +107,9 @@

#define S3C64XX_SPI_FBCLK_MASK GENMASK(1, 0)

-#define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
(1 << (i)->port_conf->tx_st_done)) ? 1 : 0)
-#define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1)
+#define FIFO_DEPTH(x) (((x) >> 1) + 1)

#define S3C64XX_SPI_POLLING_SIZE 32

@@ -197,7 +196,6 @@ struct s3c64xx_spi_driver_data {
struct s3c64xx_spi_dma_data rx_dma;
struct s3c64xx_spi_dma_data tx_dma;
const struct s3c64xx_spi_port_config *port_conf;
- unsigned int port_id;
unsigned int fifosize;
};

@@ -1110,6 +1108,37 @@ static inline const struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config(
return (const struct s3c64xx_spi_port_config *)platform_get_device_id(pdev)->driver_data;
}

+static int s3c64xx_spi_get_fifosize(const struct platform_device *pdev,
+ struct s3c64xx_spi_driver_data *sdd)
+{
+ const struct s3c64xx_spi_port_config *port = sdd->port_conf;
+ const int *fifo_lvl_mask = port->fifo_lvl_mask;
+ struct device_node *np = pdev->dev.of_node;
+ int id;
+
+ if (!np) {
+ if (pdev->id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Negative platform ID is not allowed\n");
+ id = pdev->id;
+ sdd->fifosize = FIFO_DEPTH(fifo_lvl_mask[id]);
+ return 0;
+ }
+
+ if (port->fifosize) {
+ sdd->fifosize = port->fifosize;
+ return 0;
+ }
+
+ id = of_alias_get_id(np, "spi");
+ if (id < 0)
+ return dev_err_probe(&pdev->dev, id,
+ "Failed to get alias id\n");
+ sdd->fifosize = FIFO_DEPTH(fifo_lvl_mask[id]);
+
+ return 0;
+}
+
static int s3c64xx_spi_probe(struct platform_device *pdev)
{
struct resource *mem_res;
@@ -1142,34 +1171,20 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)

sdd = spi_controller_get_devdata(host);
sdd->port_conf = s3c64xx_spi_get_port_config(pdev);
+ ret = s3c64xx_spi_get_fifosize(pdev, sdd);
+ if (ret)
+ return ret;
+
sdd->host = host;
sdd->cntrlr_info = sci;
sdd->pdev = pdev;
- if (pdev->dev.of_node) {
- ret = of_alias_get_id(pdev->dev.of_node, "spi");
- if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
- "Failed to get alias id\n");
- sdd->port_id = ret;
- } else {
- if (pdev->id < 0)
- return dev_err_probe(&pdev->dev, -EINVAL,
- "Negative platform ID is not allowed\n");
- sdd->port_id = pdev->id;
- }
-
- if (sdd->port_conf->fifosize)
- sdd->fifosize = sdd->port_conf->fifosize;
- else
- sdd->fifosize = FIFO_DEPTH(sdd);
-
sdd->cur_bpw = 8;

sdd->tx_dma.direction = DMA_MEM_TO_DEV;
sdd->rx_dma.direction = DMA_DEV_TO_MEM;

host->dev.of_node = pdev->dev.of_node;
- host->bus_num = sdd->port_id;
+ host->bus_num = -1;
host->setup = s3c64xx_spi_setup;
host->cleanup = s3c64xx_spi_cleanup;
host->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer;
@@ -1250,7 +1265,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
}

dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Targets attached\n",
- sdd->port_id, host->num_chipselect);
+ host->bus_num, host->num_chipselect);
dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n",
mem_res, sdd->fifosize);

--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:00:18

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 04/28] spi: dt-bindings: samsung: add google,gs101-spi compatible

Add "google,gs101-spi" dedicated compatible for representing SPI of
Google GS101 SoC.

Reviewed-by: Sam Protsenko <[email protected]>
Reviewed-by: Krzysztof Kozlowski <[email protected]>
Acked-by: Andi Shyti <[email protected]>
Signed-off-by: Tudor Ambarus <[email protected]>
---
Documentation/devicetree/bindings/spi/samsung,spi.yaml | 1 +
1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/spi/samsung,spi.yaml b/Documentation/devicetree/bindings/spi/samsung,spi.yaml
index f71099852653..2f0a0835ecfb 100644
--- a/Documentation/devicetree/bindings/spi/samsung,spi.yaml
+++ b/Documentation/devicetree/bindings/spi/samsung,spi.yaml
@@ -17,6 +17,7 @@ properties:
compatible:
oneOf:
- enum:
+ - google,gs101-spi
- samsung,s3c2443-spi # for S3C2443, S3C2416 and S3C2450
- samsung,s3c6410-spi
- samsung,s5pv210-spi # for S5PV210 and S5PC110
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:00:57

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 03/28] spi: s3c64xx: avoid possible negative array index

The platform id is used as an index into the fifo_lvl_mask array.
Platforms can come with a negative device ID, PLATFORM_DEVID_NONE (-1),
thus we risked a negative array index. Catch such cases and fail to
probe.

Fixes: 2b90807549e5 ("spi: s3c64xx: add device tree support")
Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 2b5bb7604526..c3176a510643 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -1189,6 +1189,9 @@ static int s3c64xx_spi_probe(struct platform_device *pdev)
"Failed to get alias id\n");
sdd->port_id = ret;
} else {
+ if (pdev->id < 0)
+ return dev_err_probe(&pdev->dev, -EINVAL,
+ "Negative platform ID is not allowed\n");
sdd->port_id = pdev->id;
}

--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:01:58

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 09/28] spi: s3c64xx: use bitfield access macros

Use the bitfield access macros in order to clean and to make the driver
easier to read.

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 196 +++++++++++++++++++-------------------
1 file changed, 99 insertions(+), 97 deletions(-)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 1e44b24f6401..d046810da51f 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -4,6 +4,7 @@
// Jaswinder Singh <[email protected]>

#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -18,91 +19,91 @@
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>

-#define MAX_SPI_PORTS 12
-#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
-#define AUTOSUSPEND_TIMEOUT 2000
+#define MAX_SPI_PORTS 12
+#define S3C64XX_SPI_QUIRK_CS_AUTO BIT(1)
+#define AUTOSUSPEND_TIMEOUT 2000

/* Registers and bit-fields */

-#define S3C64XX_SPI_CH_CFG 0x00
-#define S3C64XX_SPI_CLK_CFG 0x04
-#define S3C64XX_SPI_MODE_CFG 0x08
-#define S3C64XX_SPI_CS_REG 0x0C
-#define S3C64XX_SPI_INT_EN 0x10
-#define S3C64XX_SPI_STATUS 0x14
-#define S3C64XX_SPI_TX_DATA 0x18
-#define S3C64XX_SPI_RX_DATA 0x1C
-#define S3C64XX_SPI_PACKET_CNT 0x20
-#define S3C64XX_SPI_PENDING_CLR 0x24
-#define S3C64XX_SPI_SWAP_CFG 0x28
-#define S3C64XX_SPI_FB_CLK 0x2C
-
-#define S3C64XX_SPI_CH_HS_EN (1<<6) /* High Speed Enable */
-#define S3C64XX_SPI_CH_SW_RST (1<<5)
-#define S3C64XX_SPI_CH_SLAVE (1<<4)
-#define S3C64XX_SPI_CPOL_L (1<<3)
-#define S3C64XX_SPI_CPHA_B (1<<2)
-#define S3C64XX_SPI_CH_RXCH_ON (1<<1)
-#define S3C64XX_SPI_CH_TXCH_ON (1<<0)
-
-#define S3C64XX_SPI_CLKSEL_SRCMSK (3<<9)
-#define S3C64XX_SPI_CLKSEL_SRCSHFT 9
-#define S3C64XX_SPI_ENCLK_ENABLE (1<<8)
-#define S3C64XX_SPI_PSR_MASK 0xff
-
-#define S3C64XX_SPI_MODE_CH_TSZ_BYTE (0<<29)
-#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD (1<<29)
-#define S3C64XX_SPI_MODE_CH_TSZ_WORD (2<<29)
-#define S3C64XX_SPI_MODE_CH_TSZ_MASK (3<<29)
-#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE (0<<17)
-#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17)
-#define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17)
-#define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17)
+#define S3C64XX_SPI_CH_CFG 0x00
+#define S3C64XX_SPI_CLK_CFG 0x04
+#define S3C64XX_SPI_MODE_CFG 0x08
+#define S3C64XX_SPI_CS_REG 0x0C
+#define S3C64XX_SPI_INT_EN 0x10
+#define S3C64XX_SPI_STATUS 0x14
+#define S3C64XX_SPI_TX_DATA 0x18
+#define S3C64XX_SPI_RX_DATA 0x1C
+#define S3C64XX_SPI_PACKET_CNT 0x20
+#define S3C64XX_SPI_PENDING_CLR 0x24
+#define S3C64XX_SPI_SWAP_CFG 0x28
+#define S3C64XX_SPI_FB_CLK 0x2C
+
+#define S3C64XX_SPI_CH_HS_EN BIT(6) /* High Speed Enable */
+#define S3C64XX_SPI_CH_SW_RST BIT(5)
+#define S3C64XX_SPI_CH_SLAVE BIT(4)
+#define S3C64XX_SPI_CPOL_L BIT(3)
+#define S3C64XX_SPI_CPHA_B BIT(2)
+#define S3C64XX_SPI_CH_RXCH_ON BIT(1)
+#define S3C64XX_SPI_CH_TXCH_ON BIT(0)
+
+#define S3C64XX_SPI_CLKSEL_SRCMSK GENMASK(10, 9)
+#define S3C64XX_SPI_ENCLK_ENABLE BIT(8)
+#define S3C64XX_SPI_PSR_MASK GENMASK(15, 0)
+
+#define S3C64XX_SPI_MODE_CH_TSZ_MASK GENMASK(30, 29)
+#define S3C64XX_SPI_MODE_CH_TSZ_BYTE 0
+#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD 1
+#define S3C64XX_SPI_MODE_CH_TSZ_WORD 2
+#define S3C64XX_SPI_MAX_TRAILCNT_MASK GENMASK(28, 19)
+#define S3C64XX_SPI_MODE_BUS_TSZ_MASK GENMASK(18, 17)
+#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE 0
+#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD 1
+#define S3C64XX_SPI_MODE_BUS_TSZ_WORD 2
#define S3C64XX_SPI_MODE_RX_RDY_LVL GENMASK(16, 11)
-#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT 11
-#define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3)
-#define S3C64XX_SPI_MODE_RXDMA_ON (1<<2)
-#define S3C64XX_SPI_MODE_TXDMA_ON (1<<1)
-#define S3C64XX_SPI_MODE_4BURST (1<<0)
-
-#define S3C64XX_SPI_CS_NSC_CNT_2 (2<<4)
-#define S3C64XX_SPI_CS_AUTO (1<<1)
-#define S3C64XX_SPI_CS_SIG_INACT (1<<0)
-
-#define S3C64XX_SPI_INT_TRAILING_EN (1<<6)
-#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
-#define S3C64XX_SPI_INT_RX_UNDERRUN_EN (1<<4)
-#define S3C64XX_SPI_INT_TX_OVERRUN_EN (1<<3)
-#define S3C64XX_SPI_INT_TX_UNDERRUN_EN (1<<2)
-#define S3C64XX_SPI_INT_RX_FIFORDY_EN (1<<1)
-#define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0)
-
-#define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5)
-#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4)
-#define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3)
-#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2)
-#define S3C64XX_SPI_ST_RX_FIFORDY (1<<1)
-#define S3C64XX_SPI_ST_TX_FIFORDY (1<<0)
-
-#define S3C64XX_SPI_PACKET_CNT_EN (1<<16)
+#define S3C64XX_SPI_MODE_SELF_LOOPBACK BIT(3)
+#define S3C64XX_SPI_MODE_RXDMA_ON BIT(2)
+#define S3C64XX_SPI_MODE_TXDMA_ON BIT(1)
+#define S3C64XX_SPI_MODE_4BURST BIT(0)
+
+#define S3C64XX_SPI_CS_NSC_CNT_MASK GENMASK(9, 4)
+#define S3C64XX_SPI_CS_NSC_CNT_2 2
+#define S3C64XX_SPI_CS_AUTO BIT(1)
+#define S3C64XX_SPI_CS_SIG_INACT BIT(0)
+
+#define S3C64XX_SPI_INT_TRAILING_EN BIT(6)
+#define S3C64XX_SPI_INT_RX_OVERRUN_EN BIT(5)
+#define S3C64XX_SPI_INT_RX_UNDERRUN_EN BIT(4)
+#define S3C64XX_SPI_INT_TX_OVERRUN_EN BIT(3)
+#define S3C64XX_SPI_INT_TX_UNDERRUN_EN BIT(2)
+#define S3C64XX_SPI_INT_RX_FIFORDY_EN BIT(1)
+#define S3C64XX_SPI_INT_TX_FIFORDY_EN BIT(0)
+
+#define S3C64XX_SPI_ST_RX_OVERRUN_ERR BIT(5)
+#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR BIT(4)
+#define S3C64XX_SPI_ST_TX_OVERRUN_ERR BIT(3)
+#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR BIT(2)
+#define S3C64XX_SPI_ST_RX_FIFORDY BIT(1)
+#define S3C64XX_SPI_ST_TX_FIFORDY BIT(0)
+
+#define S3C64XX_SPI_PACKET_CNT_EN BIT(16)
#define S3C64XX_SPI_PACKET_CNT_MASK GENMASK(15, 0)

-#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4)
-#define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3)
-#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR (1<<2)
-#define S3C64XX_SPI_PND_RX_OVERRUN_CLR (1<<1)
-#define S3C64XX_SPI_PND_TRAILING_CLR (1<<0)
+#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR BIT(4)
+#define S3C64XX_SPI_PND_TX_OVERRUN_CLR BIT(3)
+#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR BIT(2)
+#define S3C64XX_SPI_PND_RX_OVERRUN_CLR BIT(1)
+#define S3C64XX_SPI_PND_TRAILING_CLR BIT(0)

-#define S3C64XX_SPI_SWAP_RX_HALF_WORD (1<<7)
-#define S3C64XX_SPI_SWAP_RX_BYTE (1<<6)
-#define S3C64XX_SPI_SWAP_RX_BIT (1<<5)
-#define S3C64XX_SPI_SWAP_RX_EN (1<<4)
-#define S3C64XX_SPI_SWAP_TX_HALF_WORD (1<<3)
-#define S3C64XX_SPI_SWAP_TX_BYTE (1<<2)
-#define S3C64XX_SPI_SWAP_TX_BIT (1<<1)
-#define S3C64XX_SPI_SWAP_TX_EN (1<<0)
+#define S3C64XX_SPI_SWAP_RX_HALF_WORD BIT(7)
+#define S3C64XX_SPI_SWAP_RX_BYTE BIT(6)
+#define S3C64XX_SPI_SWAP_RX_BIT BIT(5)
+#define S3C64XX_SPI_SWAP_RX_EN BIT(4)
+#define S3C64XX_SPI_SWAP_TX_HALF_WORD BIT(3)
+#define S3C64XX_SPI_SWAP_TX_BYTE BIT(2)
+#define S3C64XX_SPI_SWAP_TX_BIT BIT(1)
+#define S3C64XX_SPI_SWAP_TX_EN BIT(0)

-#define S3C64XX_SPI_FBCLK_MSK (3<<0)
+#define S3C64XX_SPI_FBCLK_MASK GENMASK(1, 0)

#define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
@@ -112,18 +113,13 @@
FIFO_LVL_MASK(i))
#define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1)

-#define S3C64XX_SPI_MAX_TRAILCNT 0x3ff
-#define S3C64XX_SPI_TRAILCNT_OFF 19
-
-#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
-
#define S3C64XX_SPI_POLLING_SIZE 32

#define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
#define is_polling(x) (x->cntrlr_info->polling)

-#define RXBUSY (1<<2)
-#define TXBUSY (1<<3)
+#define RXBUSY BIT(2)
+#define TXBUSY BIT(3)

struct s3c64xx_spi_dma_data {
struct dma_chan *ch;
@@ -342,8 +338,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
} else {
u32 ssel = readl(sdd->regs + S3C64XX_SPI_CS_REG);

- ssel |= (S3C64XX_SPI_CS_AUTO |
- S3C64XX_SPI_CS_NSC_CNT_2);
+ ssel |= S3C64XX_SPI_CS_AUTO |
+ FIELD_PREP(S3C64XX_SPI_CS_NSC_CNT_MASK,
+ S3C64XX_SPI_CS_NSC_CNT_2);
writel(ssel, sdd->regs + S3C64XX_SPI_CS_REG);
}
} else {
@@ -666,16 +663,22 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)

switch (sdd->cur_bpw) {
case 32:
- val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
- val |= S3C64XX_SPI_MODE_CH_TSZ_WORD;
+ val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
+ S3C64XX_SPI_MODE_BUS_TSZ_WORD) |
+ FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
+ S3C64XX_SPI_MODE_CH_TSZ_WORD);
break;
case 16:
- val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
- val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD;
+ val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
+ S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD) |
+ FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
+ S3C64XX_SPI_MODE_CH_TSZ_HALFWORD);
break;
default:
- val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
- val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
+ val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
+ S3C64XX_SPI_MODE_BUS_TSZ_BYTE) |
+ FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
+ S3C64XX_SPI_MODE_CH_TSZ_BYTE);
break;
}

@@ -801,7 +804,7 @@ static int s3c64xx_spi_transfer_one(struct spi_controller *host,

val = readl(sdd->regs + S3C64XX_SPI_MODE_CFG);
val &= ~S3C64XX_SPI_MODE_RX_RDY_LVL;
- val |= (rdy_lv << S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT);
+ val |= FIELD_PREP(S3C64XX_SPI_MODE_RX_RDY_LVL, rdy_lv);
writel(val, sdd->regs + S3C64XX_SPI_MODE_CFG);

/* Enable FIFO_RDY_EN IRQ */
@@ -1074,8 +1077,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
writel(0, regs + S3C64XX_SPI_INT_EN);

if (!sdd->port_conf->clk_from_cmu)
- writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
- regs + S3C64XX_SPI_CLK_CFG);
+ writel(FIELD_PREP(S3C64XX_SPI_CLKSEL_SRCMSK, sci->src_clk_nr),
+ regs + S3C64XX_SPI_CLK_CFG);
writel(0, regs + S3C64XX_SPI_MODE_CFG);
writel(0, regs + S3C64XX_SPI_PACKET_CNT);

@@ -1091,8 +1094,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)

val = readl(regs + S3C64XX_SPI_MODE_CFG);
val &= ~S3C64XX_SPI_MODE_4BURST;
- val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
- val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
+ val |= S3C64XX_SPI_MAX_TRAILCNT_MASK;
writel(val, regs + S3C64XX_SPI_MODE_CFG);

s3c64xx_flush_fifo(sdd);
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:02:15

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 25/28] asm-generic/io.h: add iowrite{8,16}_32 accessors

This will allow devices that require 32 bits register accesses to write
data in chunks of 8 or 16 bits.

One SoC that requires 32 bit register accesses is the google gs101. A
typical use case is SPI, where the clients can request transfers in words
of 8 bits.

Signed-off-by: Tudor Ambarus <[email protected]>
---
include/asm-generic/io.h | 50 +++++++++++++++++++++++++++++++++++++
include/asm-generic/iomap.h | 2 ++
2 files changed, 52 insertions(+)

diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index bac63e874c7b..1e224d1ccc98 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -476,6 +476,21 @@ static inline void writesb(volatile void __iomem *addr, const void *buffer,
}
#endif

+#ifndef writesb_l
+#define writesb_l writesb_l
+static inline void writesb_l(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
+{
+ if (count) {
+ const u8 *buf = buffer;
+
+ do {
+ __raw_writel(*buf++, addr);
+ } while (--count);
+ }
+}
+#endif
+
#ifndef writesw
#define writesw writesw
static inline void writesw(volatile void __iomem *addr, const void *buffer,
@@ -491,6 +506,21 @@ static inline void writesw(volatile void __iomem *addr, const void *buffer,
}
#endif

+#ifndef writesw_l
+#define writesw_l writesw_l
+static inline void writesw_l(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
+{
+ if (count) {
+ const u16 *buf = buffer;
+
+ do {
+ __raw_writel(*buf++, addr);
+ } while (--count);
+ }
+}
+#endif
+
#ifndef writesl
#define writesl writesl
static inline void writesl(volatile void __iomem *addr, const void *buffer,
@@ -956,6 +986,16 @@ static inline void iowrite8_rep(volatile void __iomem *addr,
}
#endif

+#ifndef iowrite8_32_rep
+#define iowrite8_32_rep iowrite8_32_rep
+static inline void iowrite8_32_rep(volatile void __iomem *addr,
+ const void *buffer,
+ unsigned int count)
+{
+ writesb_l(addr, buffer, count);
+}
+#endif
+
#ifndef iowrite16_rep
#define iowrite16_rep iowrite16_rep
static inline void iowrite16_rep(volatile void __iomem *addr,
@@ -966,6 +1006,16 @@ static inline void iowrite16_rep(volatile void __iomem *addr,
}
#endif

+#ifndef iowrite16_32_rep
+#define iowrite16_32_rep iowrite16_32_rep
+static inline void iowrite16_32_rep(volatile void __iomem *addr,
+ const void *buffer,
+ unsigned int count)
+{
+ writesw_l(addr, buffer, count);
+}
+#endif
+
#ifndef iowrite32_rep
#define iowrite32_rep iowrite32_rep
static inline void iowrite32_rep(volatile void __iomem *addr,
diff --git a/include/asm-generic/iomap.h b/include/asm-generic/iomap.h
index 196087a8126e..9d63f9adf2db 100644
--- a/include/asm-generic/iomap.h
+++ b/include/asm-generic/iomap.h
@@ -84,7 +84,9 @@ extern void ioread16_rep(const void __iomem *port, void *buf, unsigned long coun
extern void ioread32_rep(const void __iomem *port, void *buf, unsigned long count);

extern void iowrite8_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void iowrite8_32_rep(void __iomem *port, const void *buf, unsigned long count);
extern void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
+extern void iowrite16_32_rep(void __iomem *port, const void *buf, unsigned long count);
extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);

#ifdef CONFIG_HAS_IOPORT_MAP
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:02:36

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 28/28] MAINTAINERS: add Tudor Ambarus as R for the samsung SPI driver

I'm working with the samsung SPI driver and I'd like to review further
patches on this driver. Add myself as reviewer.

Reviewed-by: Sam Protsenko <[email protected]>
Signed-off-by: Tudor Ambarus <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 8d1052fa6a69..b9cde7ed8489 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19404,6 +19404,7 @@ F: include/linux/clk/samsung.h

SAMSUNG SPI DRIVERS
M: Andi Shyti <[email protected]>
+R: Tudor Ambarus <[email protected]>
L: [email protected]
L: [email protected]
S: Maintained
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:03:00

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 01/28] spi: s3c64xx: explicitly include <linux/io.h>

The driver uses readl() but does not include <linux/io.h>.

It is good practice to directly include all headers used, it avoids
implicit dependencies and spurious breakage if someone rearranges
headers and causes the implicit include to vanish.

Include the missing header.

Fixes: 230d42d422e7 ("spi: Add s3c64xx SPI Controller driver")
Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 1 +
1 file changed, 1 insertion(+)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 7f7eb8f742e4..c1cbc4780a3b 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/spi/spi.h>
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:05:19

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 08/28] spi: s3c64xx: remove else after return

Else case is not needed after a return, remove it.

Reviewed-by: Andi Shyti <[email protected]>
Reviewed-by: Sam Protsenko <[email protected]>
Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 137faf9f2697..1e44b24f6401 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -407,12 +407,10 @@ static bool s3c64xx_spi_can_dma(struct spi_controller *host,
{
struct s3c64xx_spi_driver_data *sdd = spi_controller_get_devdata(host);

- if (sdd->rx_dma.ch && sdd->tx_dma.ch) {
+ if (sdd->rx_dma.ch && sdd->tx_dma.ch)
return xfer->len > FIFO_DEPTH(sdd);
- } else {
- return false;
- }

+ return false;
}

static int s3c64xx_enable_datapath(struct s3c64xx_spi_driver_data *sdd,
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 15:07:48

by Tudor Ambarus

[permalink] [raw]
Subject: [PATCH v2 10/28] spi: s3c64xx: use full mask for {RX, TX}_FIFO_LVL

SPI_STATUSn.{RX, TX}_FIFO_LVL fields show the data level in the RX and
TX FIFOs. The IP supports FIFOs from 8 to 256 bytes, but apart from the
MODE_CFG.{RX, TX}_RDY_LVL fields that configure the {RX, TX} FIFO
trigger level in the interrupt mode, there's nothing in the registers
that configure the FIFOs depth. Is the responsibility of the SoC that
integrates the IP to dictate the FIFO depth and of the SPI driver to
make sure it doesn't bypass the FIFO length.

{RX, TX}_FIFO_LVL was used to pass the FIFO length information based on
the IP configuration in the SoC. Its value was defined so that it
includes the entire FIFO length. For example, if one wanted to specify a
64 FIFO length (0x40), it wold configure the FIFO level to 127 (0x7f).
This is not only wrong, because it doesn't respect the IP's register
fields, it's also misleading. Use the full mask for the
SPI_STATUSn.{RX, TX}_FIFO_LVL fields. No change in functionality is
expected.

Signed-off-by: Tudor Ambarus <[email protected]>
---
drivers/spi/spi-s3c64xx.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index d046810da51f..b048e81e6207 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -78,6 +78,8 @@
#define S3C64XX_SPI_INT_RX_FIFORDY_EN BIT(1)
#define S3C64XX_SPI_INT_TX_FIFORDY_EN BIT(0)

+#define S3C64XX_SPI_ST_RX_FIFO_LVL GENMASK(23, 15)
+#define S3C64XX_SPI_ST_TX_FIFO_LVL GENMASK(14, 6)
#define S3C64XX_SPI_ST_RX_OVERRUN_ERR BIT(5)
#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR BIT(4)
#define S3C64XX_SPI_ST_TX_OVERRUN_ERR BIT(3)
@@ -108,9 +110,6 @@
#define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
#define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
(1 << (i)->port_conf->tx_st_done)) ? 1 : 0)
-#define TX_FIFO_LVL(v, i) (((v) >> 6) & FIFO_LVL_MASK(i))
-#define RX_FIFO_LVL(v, i) (((v) >> (i)->port_conf->rx_lvl_offset) & \
- FIFO_LVL_MASK(i))
#define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1)

#define S3C64XX_SPI_POLLING_SIZE 32
@@ -219,7 +218,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
loops = msecs_to_loops(1);
do {
val = readl(regs + S3C64XX_SPI_STATUS);
- } while (TX_FIFO_LVL(val, sdd) && loops--);
+ } while (FIELD_GET(S3C64XX_SPI_ST_TX_FIFO_LVL, val) && loops--);

if (loops == 0)
dev_warn(&sdd->pdev->dev, "Timed out flushing TX FIFO\n");
@@ -228,7 +227,7 @@ static void s3c64xx_flush_fifo(struct s3c64xx_spi_driver_data *sdd)
loops = msecs_to_loops(1);
do {
val = readl(regs + S3C64XX_SPI_STATUS);
- if (RX_FIFO_LVL(val, sdd))
+ if (FIELD_GET(S3C64XX_SPI_ST_RX_FIFO_LVL, val))
readl(regs + S3C64XX_SPI_RX_DATA);
else
break;
@@ -499,10 +498,11 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd,

do {
status = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(status, sdd) < max_fifo && --val);
+ } while (FIELD_GET(S3C64XX_SPI_ST_RX_FIFO_LVL, status) < max_fifo &&
+ --val);

/* return the actual received data length */
- return RX_FIFO_LVL(status, sdd);
+ return FIELD_GET(S3C64XX_SPI_ST_RX_FIFO_LVL, status);
}

static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
@@ -533,7 +533,7 @@ static int s3c64xx_wait_for_dma(struct s3c64xx_spi_driver_data *sdd,
if (val && !xfer->rx_buf) {
val = msecs_to_loops(10);
status = readl(regs + S3C64XX_SPI_STATUS);
- while ((TX_FIFO_LVL(status, sdd)
+ while ((FIELD_GET(S3C64XX_SPI_ST_TX_FIFO_LVL, status)
|| !S3C64XX_SPI_ST_TX_DONE(status, sdd))
&& --val) {
cpu_relax();
@@ -568,7 +568,7 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,

/* sleep during signal transfer time */
status = readl(regs + S3C64XX_SPI_STATUS);
- if (RX_FIFO_LVL(status, sdd) < xfer->len)
+ if (FIELD_GET(S3C64XX_SPI_ST_RX_FIFO_LVL, status) < xfer->len)
usleep_range(time_us / 2, time_us);

if (use_irq) {
@@ -580,7 +580,8 @@ static int s3c64xx_wait_for_pio(struct s3c64xx_spi_driver_data *sdd,
val = msecs_to_loops(ms);
do {
status = readl(regs + S3C64XX_SPI_STATUS);
- } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val);
+ } while (FIELD_GET(S3C64XX_SPI_ST_RX_FIFO_LVL, status) < xfer->len &&
+ --val);

if (!val)
return -EIO;
--
2.43.0.429.g432eaa2c6b-goog


2024-01-25 17:41:29

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v2 25/28] asm-generic/io.h: add iowrite{8,16}_32 accessors

On Thu, Jan 25, 2024 at 02:50:03PM +0000, Tudor Ambarus wrote:
> This will allow devices that require 32 bits register accesses to write
> data in chunks of 8 or 16 bits.
>
> One SoC that requires 32 bit register accesses is the google gs101. A
> typical use case is SPI, where the clients can request transfers in words
> of 8 bits.

Might be good to CC this one to linux-arch if reposting.


Attachments:
(No filename) (402.00 B)
signature.asc (499.00 B)
Download all attachments

2024-01-25 19:50:45

by Sam Protsenko

[permalink] [raw]
Subject: Re: [PATCH v2 09/28] spi: s3c64xx: use bitfield access macros

On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <tudor.ambarus@linaroorg> wrote:
>
> Use the bitfield access macros in order to clean and to make the driver
> easier to read.
>
> Signed-off-by: Tudor Ambarus <[email protected]>
> ---
> drivers/spi/spi-s3c64xx.c | 196 +++++++++++++++++++-------------------
> 1 file changed, 99 insertions(+), 97 deletions(-)
>
> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
> index 1e44b24f6401..d046810da51f 100644
> --- a/drivers/spi/spi-s3c64xx.c
> +++ b/drivers/spi/spi-s3c64xx.c
> @@ -4,6 +4,7 @@
> // Jaswinder Singh <[email protected]>
>
> #include <linux/bits.h>
> +#include <linux/bitfield.h>
> #include <linux/clk.h>
> #include <linux/delay.h>
> #include <linux/dma-mapping.h>
> @@ -18,91 +19,91 @@
> #include <linux/pm_runtime.h>
> #include <linux/spi/spi.h>
>
> -#define MAX_SPI_PORTS 12
> -#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
> -#define AUTOSUSPEND_TIMEOUT 2000
> +#define MAX_SPI_PORTS 12
> +#define S3C64XX_SPI_QUIRK_CS_AUTO BIT(1)
> +#define AUTOSUSPEND_TIMEOUT 2000
>
> /* Registers and bit-fields */
>
> -#define S3C64XX_SPI_CH_CFG 0x00
> -#define S3C64XX_SPI_CLK_CFG 0x04
> -#define S3C64XX_SPI_MODE_CFG 0x08
> -#define S3C64XX_SPI_CS_REG 0x0C
> -#define S3C64XX_SPI_INT_EN 0x10
> -#define S3C64XX_SPI_STATUS 0x14
> -#define S3C64XX_SPI_TX_DATA 0x18
> -#define S3C64XX_SPI_RX_DATA 0x1C
> -#define S3C64XX_SPI_PACKET_CNT 0x20
> -#define S3C64XX_SPI_PENDING_CLR 0x24
> -#define S3C64XX_SPI_SWAP_CFG 0x28
> -#define S3C64XX_SPI_FB_CLK 0x2C
> -
> -#define S3C64XX_SPI_CH_HS_EN (1<<6) /* High Speed Enable */
> -#define S3C64XX_SPI_CH_SW_RST (1<<5)
> -#define S3C64XX_SPI_CH_SLAVE (1<<4)
> -#define S3C64XX_SPI_CPOL_L (1<<3)
> -#define S3C64XX_SPI_CPHA_B (1<<2)
> -#define S3C64XX_SPI_CH_RXCH_ON (1<<1)
> -#define S3C64XX_SPI_CH_TXCH_ON (1<<0)
> -
> -#define S3C64XX_SPI_CLKSEL_SRCMSK (3<<9)
> -#define S3C64XX_SPI_CLKSEL_SRCSHFT 9
> -#define S3C64XX_SPI_ENCLK_ENABLE (1<<8)
> -#define S3C64XX_SPI_PSR_MASK 0xff
> -
> -#define S3C64XX_SPI_MODE_CH_TSZ_BYTE (0<<29)
> -#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD (1<<29)
> -#define S3C64XX_SPI_MODE_CH_TSZ_WORD (2<<29)
> -#define S3C64XX_SPI_MODE_CH_TSZ_MASK (3<<29)
> -#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE (0<<17)
> -#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD (1<<17)
> -#define S3C64XX_SPI_MODE_BUS_TSZ_WORD (2<<17)
> -#define S3C64XX_SPI_MODE_BUS_TSZ_MASK (3<<17)
> +#define S3C64XX_SPI_CH_CFG 0x00
> +#define S3C64XX_SPI_CLK_CFG 0x04
> +#define S3C64XX_SPI_MODE_CFG 0x08
> +#define S3C64XX_SPI_CS_REG 0x0C
> +#define S3C64XX_SPI_INT_EN 0x10
> +#define S3C64XX_SPI_STATUS 0x14
> +#define S3C64XX_SPI_TX_DATA 0x18
> +#define S3C64XX_SPI_RX_DATA 0x1C
> +#define S3C64XX_SPI_PACKET_CNT 0x20
> +#define S3C64XX_SPI_PENDING_CLR 0x24
> +#define S3C64XX_SPI_SWAP_CFG 0x28
> +#define S3C64XX_SPI_FB_CLK 0x2C
> +
> +#define S3C64XX_SPI_CH_HS_EN BIT(6) /* High Speed Enable */
> +#define S3C64XX_SPI_CH_SW_RST BIT(5)
> +#define S3C64XX_SPI_CH_SLAVE BIT(4)
> +#define S3C64XX_SPI_CPOL_L BIT(3)
> +#define S3C64XX_SPI_CPHA_B BIT(2)
> +#define S3C64XX_SPI_CH_RXCH_ON BIT(1)
> +#define S3C64XX_SPI_CH_TXCH_ON BIT(0)
> +
> +#define S3C64XX_SPI_CLKSEL_SRCMSK GENMASK(10, 9)
> +#define S3C64XX_SPI_ENCLK_ENABLE BIT(8)
> +#define S3C64XX_SPI_PSR_MASK GENMASK(15, 0)

But it was 0xff (7:0) originally, and here you extend it up to 15:0.
Was it intentional? If so, I'd advice to keep non-functional changes
as a separate patch, and pull all functional changes like these into
another one, probably with an explanation why it's needed.

> +
> +#define S3C64XX_SPI_MODE_CH_TSZ_MASK GENMASK(30, 29)
> +#define S3C64XX_SPI_MODE_CH_TSZ_BYTE 0
> +#define S3C64XX_SPI_MODE_CH_TSZ_HALFWORD 1
> +#define S3C64XX_SPI_MODE_CH_TSZ_WORD 2
> +#define S3C64XX_SPI_MAX_TRAILCNT_MASK GENMASK(28, 19)
> +#define S3C64XX_SPI_MODE_BUS_TSZ_MASK GENMASK(18, 17)
> +#define S3C64XX_SPI_MODE_BUS_TSZ_BYTE 0
> +#define S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD 1
> +#define S3C64XX_SPI_MODE_BUS_TSZ_WORD 2
> #define S3C64XX_SPI_MODE_RX_RDY_LVL GENMASK(16, 11)
> -#define S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT 11
> -#define S3C64XX_SPI_MODE_SELF_LOOPBACK (1<<3)
> -#define S3C64XX_SPI_MODE_RXDMA_ON (1<<2)
> -#define S3C64XX_SPI_MODE_TXDMA_ON (1<<1)
> -#define S3C64XX_SPI_MODE_4BURST (1<<0)
> -
> -#define S3C64XX_SPI_CS_NSC_CNT_2 (2<<4)
> -#define S3C64XX_SPI_CS_AUTO (1<<1)
> -#define S3C64XX_SPI_CS_SIG_INACT (1<<0)
> -
> -#define S3C64XX_SPI_INT_TRAILING_EN (1<<6)
> -#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
> -#define S3C64XX_SPI_INT_RX_UNDERRUN_EN (1<<4)
> -#define S3C64XX_SPI_INT_TX_OVERRUN_EN (1<<3)
> -#define S3C64XX_SPI_INT_TX_UNDERRUN_EN (1<<2)
> -#define S3C64XX_SPI_INT_RX_FIFORDY_EN (1<<1)
> -#define S3C64XX_SPI_INT_TX_FIFORDY_EN (1<<0)
> -
> -#define S3C64XX_SPI_ST_RX_OVERRUN_ERR (1<<5)
> -#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR (1<<4)
> -#define S3C64XX_SPI_ST_TX_OVERRUN_ERR (1<<3)
> -#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR (1<<2)
> -#define S3C64XX_SPI_ST_RX_FIFORDY (1<<1)
> -#define S3C64XX_SPI_ST_TX_FIFORDY (1<<0)
> -
> -#define S3C64XX_SPI_PACKET_CNT_EN (1<<16)
> +#define S3C64XX_SPI_MODE_SELF_LOOPBACK BIT(3)
> +#define S3C64XX_SPI_MODE_RXDMA_ON BIT(2)
> +#define S3C64XX_SPI_MODE_TXDMA_ON BIT(1)
> +#define S3C64XX_SPI_MODE_4BURST BIT(0)
> +
> +#define S3C64XX_SPI_CS_NSC_CNT_MASK GENMASK(9, 4)
> +#define S3C64XX_SPI_CS_NSC_CNT_2 2
> +#define S3C64XX_SPI_CS_AUTO BIT(1)
> +#define S3C64XX_SPI_CS_SIG_INACT BIT(0)
> +
> +#define S3C64XX_SPI_INT_TRAILING_EN BIT(6)
> +#define S3C64XX_SPI_INT_RX_OVERRUN_EN BIT(5)
> +#define S3C64XX_SPI_INT_RX_UNDERRUN_EN BIT(4)
> +#define S3C64XX_SPI_INT_TX_OVERRUN_EN BIT(3)
> +#define S3C64XX_SPI_INT_TX_UNDERRUN_EN BIT(2)
> +#define S3C64XX_SPI_INT_RX_FIFORDY_EN BIT(1)
> +#define S3C64XX_SPI_INT_TX_FIFORDY_EN BIT(0)
> +
> +#define S3C64XX_SPI_ST_RX_OVERRUN_ERR BIT(5)
> +#define S3C64XX_SPI_ST_RX_UNDERRUN_ERR BIT(4)
> +#define S3C64XX_SPI_ST_TX_OVERRUN_ERR BIT(3)
> +#define S3C64XX_SPI_ST_TX_UNDERRUN_ERR BIT(2)
> +#define S3C64XX_SPI_ST_RX_FIFORDY BIT(1)
> +#define S3C64XX_SPI_ST_TX_FIFORDY BIT(0)
> +
> +#define S3C64XX_SPI_PACKET_CNT_EN BIT(16)
> #define S3C64XX_SPI_PACKET_CNT_MASK GENMASK(15, 0)
>
> -#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR (1<<4)
> -#define S3C64XX_SPI_PND_TX_OVERRUN_CLR (1<<3)
> -#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR (1<<2)
> -#define S3C64XX_SPI_PND_RX_OVERRUN_CLR (1<<1)
> -#define S3C64XX_SPI_PND_TRAILING_CLR (1<<0)
> +#define S3C64XX_SPI_PND_TX_UNDERRUN_CLR BIT(4)
> +#define S3C64XX_SPI_PND_TX_OVERRUN_CLR BIT(3)
> +#define S3C64XX_SPI_PND_RX_UNDERRUN_CLR BIT(2)
> +#define S3C64XX_SPI_PND_RX_OVERRUN_CLR BIT(1)
> +#define S3C64XX_SPI_PND_TRAILING_CLR BIT(0)
>
> -#define S3C64XX_SPI_SWAP_RX_HALF_WORD (1<<7)
> -#define S3C64XX_SPI_SWAP_RX_BYTE (1<<6)
> -#define S3C64XX_SPI_SWAP_RX_BIT (1<<5)
> -#define S3C64XX_SPI_SWAP_RX_EN (1<<4)
> -#define S3C64XX_SPI_SWAP_TX_HALF_WORD (1<<3)
> -#define S3C64XX_SPI_SWAP_TX_BYTE (1<<2)
> -#define S3C64XX_SPI_SWAP_TX_BIT (1<<1)
> -#define S3C64XX_SPI_SWAP_TX_EN (1<<0)
> +#define S3C64XX_SPI_SWAP_RX_HALF_WORD BIT(7)
> +#define S3C64XX_SPI_SWAP_RX_BYTE BIT(6)
> +#define S3C64XX_SPI_SWAP_RX_BIT BIT(5)
> +#define S3C64XX_SPI_SWAP_RX_EN BIT(4)
> +#define S3C64XX_SPI_SWAP_TX_HALF_WORD BIT(3)
> +#define S3C64XX_SPI_SWAP_TX_BYTE BIT(2)
> +#define S3C64XX_SPI_SWAP_TX_BIT BIT(1)
> +#define S3C64XX_SPI_SWAP_TX_EN BIT(0)
>
> -#define S3C64XX_SPI_FBCLK_MSK (3<<0)
> +#define S3C64XX_SPI_FBCLK_MASK GENMASK(1, 0)
>
> #define FIFO_LVL_MASK(i) ((i)->port_conf->fifo_lvl_mask[i->port_id])
> #define S3C64XX_SPI_ST_TX_DONE(v, i) (((v) & \
> @@ -112,18 +113,13 @@
> FIFO_LVL_MASK(i))
> #define FIFO_DEPTH(i) ((FIFO_LVL_MASK(i) >> 1) + 1)
>
> -#define S3C64XX_SPI_MAX_TRAILCNT 0x3ff
> -#define S3C64XX_SPI_TRAILCNT_OFF 19
> -
> -#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
> -
> #define S3C64XX_SPI_POLLING_SIZE 32
>
> #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t)
> #define is_polling(x) (x->cntrlr_info->polling)
>
> -#define RXBUSY (1<<2)
> -#define TXBUSY (1<<3)
> +#define RXBUSY BIT(2)
> +#define TXBUSY BIT(3)
>
> struct s3c64xx_spi_dma_data {
> struct dma_chan *ch;
> @@ -342,8 +338,9 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable)
> } else {
> u32 ssel = readl(sdd->regs + S3C64XX_SPI_CS_REG);
>
> - ssel |= (S3C64XX_SPI_CS_AUTO |
> - S3C64XX_SPI_CS_NSC_CNT_2);
> + ssel |= S3C64XX_SPI_CS_AUTO |
> + FIELD_PREP(S3C64XX_SPI_CS_NSC_CNT_MASK,
> + S3C64XX_SPI_CS_NSC_CNT_2);
> writel(ssel, sdd->regs + S3C64XX_SPI_CS_REG);
> }
> } else {
> @@ -666,16 +663,22 @@ static int s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
>
> switch (sdd->cur_bpw) {
> case 32:
> - val |= S3C64XX_SPI_MODE_BUS_TSZ_WORD;
> - val |= S3C64XX_SPI_MODE_CH_TSZ_WORD;
> + val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
> + S3C64XX_SPI_MODE_BUS_TSZ_WORD) |
> + FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
> + S3C64XX_SPI_MODE_CH_TSZ_WORD);
> break;
> case 16:
> - val |= S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD;
> - val |= S3C64XX_SPI_MODE_CH_TSZ_HALFWORD;
> + val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
> + S3C64XX_SPI_MODE_BUS_TSZ_HALFWORD) |
> + FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
> + S3C64XX_SPI_MODE_CH_TSZ_HALFWORD);
> break;
> default:
> - val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
> - val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
> + val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
> + S3C64XX_SPI_MODE_BUS_TSZ_BYTE) |
> + FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
> + S3C64XX_SPI_MODE_CH_TSZ_BYTE);

I don't know. Maybe it's me, but using this FIELD_PREP() macro seems
to only making the code harder to read. At least in cases like this. I
would vote against its usage, to keep the code compact and easy to
read.

> break;
> }
>
> @@ -801,7 +804,7 @@ static int s3c64xx_spi_transfer_one(struct spi_controller *host,
>
> val = readl(sdd->regs + S3C64XX_SPI_MODE_CFG);
> val &= ~S3C64XX_SPI_MODE_RX_RDY_LVL;
> - val |= (rdy_lv << S3C64XX_SPI_MODE_RX_RDY_LVL_SHIFT);
> + val |= FIELD_PREP(S3C64XX_SPI_MODE_RX_RDY_LVL, rdy_lv);
> writel(val, sdd->regs + S3C64XX_SPI_MODE_CFG);
>
> /* Enable FIFO_RDY_EN IRQ */
> @@ -1074,8 +1077,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
> writel(0, regs + S3C64XX_SPI_INT_EN);
>
> if (!sdd->port_conf->clk_from_cmu)
> - writel(sci->src_clk_nr << S3C64XX_SPI_CLKSEL_SRCSHFT,
> - regs + S3C64XX_SPI_CLK_CFG);
> + writel(FIELD_PREP(S3C64XX_SPI_CLKSEL_SRCMSK, sci->src_clk_nr),
> + regs + S3C64XX_SPI_CLK_CFG);
> writel(0, regs + S3C64XX_SPI_MODE_CFG);
> writel(0, regs + S3C64XX_SPI_PACKET_CNT);
>
> @@ -1091,8 +1094,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
>
> val = readl(regs + S3C64XX_SPI_MODE_CFG);
> val &= ~S3C64XX_SPI_MODE_4BURST;
> - val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);

Doesn't it change the behavior?

> - val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
> + val |= S3C64XX_SPI_MAX_TRAILCNT_MASK;
> writel(val, regs + S3C64XX_SPI_MODE_CFG);
>
> s3c64xx_flush_fifo(sdd);
> --
> 2.43.0.429.g432eaa2c6b-goog
>

2024-01-25 20:45:47

by Sam Protsenko

[permalink] [raw]
Subject: Re: [PATCH v2 27/28] spi: s3c64xx: add support for google,gs101-spi

On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <tudor.ambarus@linaroorg> wrote:
>
> Add support for GS101 SPI. All the SPI nodes on GS101 have 64 bytes
> FIFOs, infer the FIFO size from the compatible. GS101 allows just 32bit
> register accesses, otherwise a Serror Interrupt is raised. Do the write
> reg accesses in 32 bits.
>
> Signed-off-by: Tudor Ambarus <[email protected]>
> ---
> drivers/spi/spi-s3c64xx.c | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
> index 35a2d5554dfd..e887be6955a0 100644
> --- a/drivers/spi/spi-s3c64xx.c
> +++ b/drivers/spi/spi-s3c64xx.c
> @@ -1501,6 +1501,18 @@ static const struct s3c64xx_spi_port_config exynosautov9_spi_port_config = {
> .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
> };
>
> +static const struct s3c64xx_spi_port_config gs101_spi_port_config = {
> + .fifosize = 64,
> + .rx_lvl_offset = 15,
> + .tx_st_done = 25,
> + .clk_div = 4,
> + .high_speed = true,
> + .clk_from_cmu = true,
> + .has_loopback = true,
> + .use_32bit_io = true,
> + .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
> +};
> +
> static const struct s3c64xx_spi_port_config fsd_spi_port_config = {
> .fifosize = 64,
> .rx_lvl_offset = 15,
> @@ -1556,6 +1568,10 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
> .compatible = "samsung,exynosautov9-spi",
> .data = &exynosautov9_spi_port_config,
> },
> + {

As I mentioned before, this braces style looks too bloated to me.
Other than that:

Reviewed-by: Sam Protsenko <[email protected]>

> + .compatible = "google,gs101-spi",
> + .data = &gs101_spi_port_config,
> + },
> {
> .compatible = "tesla,fsd-spi",
> .data = &fsd_spi_port_config,
> --
> 2.43.0.429.g432eaa2c6b-goog
>

2024-01-25 21:56:33

by Mark Brown

[permalink] [raw]
Subject: Re: [PATCH v2 10/28] spi: s3c64xx: use full mask for {RX, TX}_FIFO_LVL

On Thu, Jan 25, 2024 at 02:03:15PM -0600, Sam Protsenko wrote:
> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:

> > +#define S3C64XX_SPI_ST_RX_FIFO_LVL GENMASK(23, 15)

> What about s3c* architectures, where RX_LVL starts with bit #13, as
> can be seen from .rx_lvl_offset values in corresponding port_configs?
> Wouldn't this change break those?

I should point out that I have a s3c6410 board I care about.


Attachments:
(No filename) (467.00 B)
signature.asc (499.00 B)
Download all attachments

2024-01-26 08:57:42

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 25/28] asm-generic/io.h: add iowrite{8,16}_32 accessors



On 1/25/24 21:23, Arnd Bergmann wrote:
> My feeling is that this operation is rare enough that I'd prefer
> it to be open-coded in the driver than made generic here. Making
> it work for all corner cases is possible but probably not worth
> it.

Thanks for all the explanations, Arnd. I'll open-code the op in the SPI
driver for now.

Cheers,
ta

2024-01-26 09:14:06

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 10/28] spi: s3c64xx: use full mask for {RX, TX}_FIFO_LVL



On 1/25/24 20:03, Sam Protsenko wrote:
> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
>>
>> SPI_STATUSn.{RX, TX}_FIFO_LVL fields show the data level in the RX and
>> TX FIFOs. The IP supports FIFOs from 8 to 256 bytes, but apart from the
>> MODE_CFG.{RX, TX}_RDY_LVL fields that configure the {RX, TX} FIFO
>> trigger level in the interrupt mode, there's nothing in the registers
>> that configure the FIFOs depth. Is the responsibility of the SoC that
>> integrates the IP to dictate the FIFO depth and of the SPI driver to
>> make sure it doesn't bypass the FIFO length.
>>
>> {RX, TX}_FIFO_LVL was used to pass the FIFO length information based on
>> the IP configuration in the SoC. Its value was defined so that it
>> includes the entire FIFO length. For example, if one wanted to specify a
>> 64 FIFO length (0x40), it wold configure the FIFO level to 127 (0x7f).
>
> s/wodl/would/

oh, yes, thanks
>
>> This is not only wrong, because it doesn't respect the IP's register
>> fields, it's also misleading. Use the full mask for the
>> SPI_STATUSn.{RX, TX}_FIFO_LVL fields. No change in functionality is
>> expected.
>>
>> Signed-off-by: Tudor Ambarus <[email protected]>
>> ---
>> drivers/spi/spi-s3c64xx.c | 21 +++++++++++----------
>> 1 file changed, 11 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
>> index d046810da51f..b048e81e6207 100644
>> --- a/drivers/spi/spi-s3c64xx.c
>> +++ b/drivers/spi/spi-s3c64xx.c
>> @@ -78,6 +78,8 @@
>> #define S3C64XX_SPI_INT_RX_FIFORDY_EN BIT(1)
>> #define S3C64XX_SPI_INT_TX_FIFORDY_EN BIT(0)
>>
>> +#define S3C64XX_SPI_ST_RX_FIFO_LVL GENMASK(23, 15)
>
> What about s3c* architectures, where RX_LVL starts with bit #13, as
> can be seen from .rx_lvl_offset values in corresponding port_configs?
> Wouldn't this change break those?

ah, wonderful catch, Sam. I break those indeed.
>
> More generally, I don't understand why this patch is needed. Looks

I said in the commit message and subject that I'd like to use the full
FIFO level mask rather than just a partial mask. On gs101 at least, that
register field is on 9 bits, but as the code is now, we consider that
register on 7 bits. For gs101 the FIFO size is always 64 bytes, thus
indirectly the fifo_lvl_mask is always 0x7f.

Unfortunately I'll drop this patch because I don't have access to all
the SoC datasheets, thus I can't tell for sure if that register is
always 9 bits wide. s3c2443 and s3c6410, which have the rx-lvl-offset
set to 13, use just 0x7f masks. That's a pitty.

2024-01-26 09:25:01

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 10/28] spi: s3c64xx: use full mask for {RX, TX}_FIFO_LVL



On 1/25/24 21:48, Mark Brown wrote:
> On Thu, Jan 25, 2024 at 02:03:15PM -0600, Sam Protsenko wrote:
>> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
>
>>> +#define S3C64XX_SPI_ST_RX_FIFO_LVL GENMASK(23, 15)
>
>> What about s3c* architectures, where RX_LVL starts with bit #13, as
>> can be seen from .rx_lvl_offset values in corresponding port_configs?
>> Wouldn't this change break those?
>
> I should point out that I have a s3c6410 board I care about.

Obviously, I don't want to break things, but it may happen as Sam
pointed out. I'll be around to fix whatever I break. It's good that you
have a s3c6410 board, maybe you can run a test on it after I send v3?

Thanks!

2024-01-26 09:25:44

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 09/28] spi: s3c64xx: use bitfield access macros



On 1/25/24 19:50, Sam Protsenko wrote:
> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
>>
>> Use the bitfield access macros in order to clean and to make the driver
>> easier to read.
>>
>> Signed-off-by: Tudor Ambarus <[email protected]>
>> ---
>> drivers/spi/spi-s3c64xx.c | 196 +++++++++++++++++++-------------------
>> 1 file changed, 99 insertions(+), 97 deletions(-)
>>
>> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
>> index 1e44b24f6401..d046810da51f 100644
>> --- a/drivers/spi/spi-s3c64xx.c
>> +++ b/drivers/spi/spi-s3c64xx.c
>> @@ -4,6 +4,7 @@

cut

>> +#define S3C64XX_SPI_PSR_MASK GENMASK(15, 0)
>
> But it was 0xff (7:0) originally, and here you extend it up to 15:0.

this is a bug from my side, I'll fix it, thanks!

cut

>> default:
>> - val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
>> - val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
>> + val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
>> + S3C64XX_SPI_MODE_BUS_TSZ_BYTE) |
>> + FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
>> + S3C64XX_SPI_MODE_CH_TSZ_BYTE);
>
> I don't know. Maybe it's me, but using this FIELD_PREP() macro seems
> to only making the code harder to read. At least in cases like this. I
> would vote against its usage, to keep the code compact and easy to
> read.

I saw Andi complained about this too, maybe Mark can chime in.

To me this is not a matter of taste, it's how it should be done. In this
particular case you have more lines when using FIELD_PREP because the
mask starts from bit 0. If the mask ever changes for new IPs then you'd
have to hack the code, whereas if using FIELD_PREP you just have to
update the mask field, something like:

FIELD_PREP(drv_prv_data->whatever_reg.field_mask,
S3C64XX_SPI_MODE_CH_TSZ_BYTE);

Thus it makes the code generic and more friendly for new IP additions.
And I have to admit I like it better too. I know from the start that
we're dealing with register fields and not some internal driver mask.

2024-01-26 14:21:18

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [PATCH v2 25/28] asm-generic/io.h: add iowrite{8,16}_32 accessors

On Thu, Jan 25, 2024, at 15:50, Tudor Ambarus wrote:
> This will allow devices that require 32 bits register accesses to write
> data in chunks of 8 or 16 bits.
>
> One SoC that requires 32 bit register accesses is the google gs101. A
> typical use case is SPI, where the clients can request transfers in words
> of 8 bits.
>
> Signed-off-by: Tudor Ambarus <[email protected]>

My feeling is that this operation is rare enough that I'd prefer
it to be open-coded in the driver than made generic here. Making
it work for all corner cases is possible but probably not worth
it.

> +#ifndef writesb_l
> +#define writesb_l writesb_l
> +static inline void writesb_l(volatile void __iomem *addr, const void
> *buffer,
> + unsigned int count)
> +{
> + if (count) {
> + const u8 *buf = buffer;
> +
> + do {
> + __raw_writel(*buf++, addr);
> + } while (--count);
> + }
> +}
> +#endif

There are architectures where writesb() requires an extra
barrier before and/or after the loop. I think there are
others that get the endianess wrong in the generic version
you have here.

> +#ifndef iowrite8_32_rep
> +#define iowrite8_32_rep iowrite8_32_rep
> +static inline void iowrite8_32_rep(volatile void __iomem *addr,
> + const void *buffer,
> + unsigned int count)
> +{
> + writesb_l(addr, buffer, count);
> +}
> +#endif

This one is wrong for architectures that have a custom inl()
helper and need to multiplex between inl() and writel() in
iowrite32(), notably x86.

For completeness you would need to add the out-of-line version
in lib/iomap.c for those, plus the corresponding insb_32()
and possibly the respective big-endian versions of those.

If you keep the helper in a driver that is only used on
regular architectures like arm64, it will work reliably.

Arnd

2024-01-26 14:43:16

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 01/28] spi: s3c64xx: explicitly include <linux/io.h>



On 1/25/24 18:58, Sam Protsenko wrote:
> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
>>
>> The driver uses readl() but does not include <linux/io.h>.
>>
>> It is good practice to directly include all headers used, it avoids
>> implicit dependencies and spurious breakage if someone rearranges
>> headers and causes the implicit include to vanish.
>>
>> Include the missing header.
>>
>> Fixes: 230d42d422e7 ("spi: Add s3c64xx SPI Controller driver")
>
> Not sure the "Fixes" tag is needed here. AFAIU, this patch doesn't fix

fixes tag indicates which commit failed to include the necessary header

> any actual bugs, seems more like a style fix to me. In other words,

not yet, but we can't estimate what header get rearranged and whether it
will cause the implicit include to vanish.

> I'm not convinced it has to be necessarily backported to stable
> kernels. The same goes for another similar patch from this series.

It would be good to have this in the stable kernels for the reasons
described in the commit message.

>
>> Signed-off-by: Tudor Ambarus <[email protected]>
>> ---
>> drivers/spi/spi-s3c64xx.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
>> index 7f7eb8f742e4..c1cbc4780a3b 100644
>> --- a/drivers/spi/spi-s3c64xx.c
>> +++ b/drivers/spi/spi-s3c64xx.c
>> @@ -10,6 +10,7 @@
>> #include <linux/clk.h>
>> #include <linux/dma-mapping.h>
>> #include <linux/dmaengine.h>
>> +#include <linux/io.h>
>> #include <linux/platform_device.h>
>> #include <linux/pm_runtime.h>
>> #include <linux/spi/spi.h>
>> --
>> 2.43.0.429.g432eaa2c6b-goog
>>

2024-01-26 16:02:06

by Tudor Ambarus

[permalink] [raw]
Subject: Re: [PATCH v2 09/28] spi: s3c64xx: use bitfield access macros

Hi, Sam,

I just noticed that I haven't responded to a question you had.

On 1/25/24 19:50, Sam Protsenko wrote:
> On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
>>
>> Use the bitfield access macros in order to clean and to make the driver
>> easier to read.
>>
>> Signed-off-by: Tudor Ambarus <[email protected]>
>> ---
>> drivers/spi/spi-s3c64xx.c | 196 +++++++++++++++++++-------------------
>> 1 file changed, 99 insertions(+), 97 deletions(-)
>>
>> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
>> index 1e44b24f6401..d046810da51f 100644
>> --- a/drivers/spi/spi-s3c64xx.c
>> +++ b/drivers/spi/spi-s3c64xx.c
>> @@ -4,6 +4,7 @@

cut


>> +#define S3C64XX_SPI_MAX_TRAILCNT_MASK GENMASK(28, 19)

cut

>> +#define S3C64XX_SPI_CS_NSC_CNT_MASK GENMASK(9, 4)

I was wrong introducing this mask because I can't tell if it applies to
all the versions of the IP. Thus I'll keep S3C64XX_SPI_CS_NSC_CNT_2
defined as (2 << 4) and add the following comment on top of it:

/*

* S3C64XX_SPI_CS_NSC_CNT_2 is a value into the NCS_TIME_COUNT field. In
newer
* datasheets this field is defined as GENMASK(9, 4). We don't know if
this mask
* applies to all the versions of the IP, thus we can't yet define

* S3C64XX_SPI_CS_NSC_CNT_2 as a value and the register field as a mask.

*/

#define S3C64XX_SPI_CS_NSC_CNT_2 (2 << 4)


cut

>> -#define S3C64XX_SPI_MAX_TRAILCNT 0x3ff
>> -#define S3C64XX_SPI_TRAILCNT_OFF 19
>> -
>> -#define S3C64XX_SPI_TRAILCNT S3C64XX_SPI_MAX_TRAILCNT
>> -

cut

>> @@ -1091,8 +1094,7 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd)
>>
>> val = readl(regs + S3C64XX_SPI_MODE_CFG);
>> val &= ~S3C64XX_SPI_MODE_4BURST;
>> - val &= ~(S3C64XX_SPI_MAX_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
>
> Doesn't it change the behavior?

No, I don't think it does.

so above we wipe the mask, it's equivalent to:
val &= ~(GENMASK(28, 19))
>
>> - val |= (S3C64XX_SPI_TRAILCNT << S3C64XX_SPI_TRAILCNT_OFF);
and above we set the entire mask:
val |= GENMASK(28, 19)

the wipe is not necessary. This can be done in a separate patch of
course, but I considered that if I removed the shift, the value and
replaced them with the mask, I get the liberty of using the mask
directly. I'll split this op in a separate patch (it starts to feel tiring).

I verified the entire patch again, apart of the problem with the wrong
mask for S3C64XX_SPI_PSR_MASK and the problem that I specified with
S3C64XX_SPI_CS_NSC_CNT_MASK everything shall be fine. All the bits
handling shall be equivalent.

2024-01-26 19:55:40

by Sam Protsenko

[permalink] [raw]
Subject: Re: [PATCH v2 09/28] spi: s3c64xx: use bitfield access macros

On Fri, Jan 26, 2024 at 2:49 AM Tudor Ambarus <tudor.ambarus@linaroorg> wrote:
>
>
>
> On 1/25/24 19:50, Sam Protsenko wrote:
> > On Thu, Jan 25, 2024 at 8:50 AM Tudor Ambarus <[email protected]> wrote:
> >>
> >> Use the bitfield access macros in order to clean and to make the driver
> >> easier to read.
> >>
> >> Signed-off-by: Tudor Ambarus <[email protected]>
> >> ---
> >> drivers/spi/spi-s3c64xx.c | 196 +++++++++++++++++++-------------------
> >> 1 file changed, 99 insertions(+), 97 deletions(-)
> >>
> >> diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
> >> index 1e44b24f6401..d046810da51f 100644
> >> --- a/drivers/spi/spi-s3c64xx.c
> >> +++ b/drivers/spi/spi-s3c64xx.c
> >> @@ -4,6 +4,7 @@
>
> cut
>
> >> +#define S3C64XX_SPI_PSR_MASK GENMASK(15, 0)
> >
> > But it was 0xff (7:0) originally, and here you extend it up to 15:0.
>
> this is a bug from my side, I'll fix it, thanks!
>
> cut
>
> >> default:
> >> - val |= S3C64XX_SPI_MODE_BUS_TSZ_BYTE;
> >> - val |= S3C64XX_SPI_MODE_CH_TSZ_BYTE;
> >> + val |= FIELD_PREP(S3C64XX_SPI_MODE_BUS_TSZ_MASK,
> >> + S3C64XX_SPI_MODE_BUS_TSZ_BYTE) |
> >> + FIELD_PREP(S3C64XX_SPI_MODE_CH_TSZ_MASK,
> >> + S3C64XX_SPI_MODE_CH_TSZ_BYTE);
> >
> > I don't know. Maybe it's me, but using this FIELD_PREP() macro seems
> > to only making the code harder to read. At least in cases like this. I
> > would vote against its usage, to keep the code compact and easy to
> > read.
>
> I saw Andi complained about this too, maybe Mark can chime in.
>
> To me this is not a matter of taste, it's how it should be done. In this

Sure. But if you think it has to be done, I suggest it's done taking
next things into the account:
1. It shouldn't make code harder to read
2. Preferably stick to canonical ways of doing things
3. IMHO patches like this *must* be tested thoroughly on different
boards with different test-cases, to make sure there are no
regressions. Because the benefits of cleanups are not that great, as I
see it, but we are risking to break some hardware/software combination
unintentionally while doing those cleanups. It's a good idea to
describe how it was tested in commit message or PATCH #0. Just my
$.02.

For (1) and (2): I noticed a lot of drivers are carrying additional
helper functions for read/write operations, to keep things tidy and
functional at the same time. Another mechanism that comes into mind is
regmap, though I'm not sure if it's needed for such low-level entities
as bus drivers. Also I think Andi has a point about FIELD_PREP and how
that can be handled.

> particular case you have more lines when using FIELD_PREP because the
> mask starts from bit 0. If the mask ever changes for new IPs then you'd
> have to hack the code, whereas if using FIELD_PREP you just have to
> update the mask field, something like:
>
> FIELD_PREP(drv_prv_data->whatever_reg.field_mask,
> S3C64XX_SPI_MODE_CH_TSZ_BYTE);
>
> Thus it makes the code generic and more friendly for new IP additions.
> And I have to admit I like it better too. I know from the start that
> we're dealing with register fields and not some internal driver mask.