2022-05-03 00:10:21

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 00/11] spi: spi-mem: Convert Aspeed SMC driver to spi-mem

Hi,

This series adds a new SPI driver using the spi-mem interface for the
Aspeed static memory controllers of the AST2600, AST2500 and AST2400
SoCs.

* AST2600 Firmware SPI Memory Controller (FMC)
* AST2600 SPI Flash Controller (SPI1 and SPI2)
* AST2500 Firmware SPI Memory Controller (FMC)
* AST2500 SPI Flash Controller (SPI1 and SPI2)
* AST2400 New Static Memory Controller (also referred as FMC)
* AST2400 SPI Flash Controller (SPI)

It is based on the current OpenBMC kernel driver [1], using directly
the MTD SPI-NOR interface and on a patchset [2] previously proposed
adding support for the AST2600 only. This driver takes a slightly
different approach to cover all 6 controllers.

It does not make use of the controller register disabling Address and
Data byte lanes because is not available on the AST2400 SoC. We could
introduce a specific handler for new features available on recent SoCs
if needed. As there is not much difference on performance, the driver
chooses the common denominator: "User mode" which has been heavily
tested in [1]. "User mode" is also used as a fall back method when
flash device mapping window is too small.

Problems to address with spi-mem were the configuration of the mapping
windows and the calibration of the read timings. The driver handles
them in the direct mapping handler when some knowledge on the size of
the flash device is know. It is not perfect but not incorrect either.
The algorithm is one from [1] because it doesn't require the DMA
registers which are not available on all controllers.

Direct mapping for writes is not supported (yet). I have seen some
corruption with writes and I preferred to use the safer and proven
method of the initial driver [1]. We can improve that later.

The driver supports Quad SPI RX transfers on the AST2600 SoC but it
didn't have the expected results. Therefore it is not activated yet.
There are some issues on the pinctrl to investigate first.

Tested on:

* OpenPOWER Palmetto (AST2400)
* Facebook Wedge 100 BMC (AST2400) by Tao Ren <[email protected]>
* Evaluation board (AST2500)
* Inspur FP5280G2 BMC (AST2500) by John Wang <[email protected]>
* Facebook Backpack CMM BMC (AST2500) by Tao Ren <[email protected]>
* OpenPOWER Witherspoon (AST2500)
* Evaluation board (AST2600 A0 and A3)
* Rainier board (AST2600)

[1] https://github.com/openbmc/linux/blob/dev-5.15/drivers/mtd/spi-nor/controllers/aspeed-smc.c
[2] https://patchwork.ozlabs.org/project/linux-aspeed/list/?series=212394

Thanks,

C.

Changes in v5:

- Rebased on 5.18-rc5
- More AST2600 tests from Jae Hyun Yoo
- Cleanups of aspeed,ast2600-fmc.yaml
- Modified aspeed_spi_send_cmd_addr() routine to return an error
- Simplified conditions in exec_op() handler when computing
the controller setting
- Dropped the use of memcpy_fromio for the SFDP address space

Changes in v4:

- Rebased on 5.18
- Removal of the SPI-NOR base driver (we had enough tests)
- Fix for small size flash devices on AST2600 (Potin)

Changes in v3:

- Fixed compile warning on aspeed_spi_dirmap_read() prototype reported
by kernel test robot
- Removed unnecessary entry in ast2600-fmc.yaml
- New patch from Tao to set spi-max-frequency on all FMC devices

Changes in v2:

- Fixed dt_binding_check warnings (Rob)
- New entry in MAINTAINERS
- Addressed Lukas comments regarding the SPI controller registration
and device removal. Checked with driver bind/unbind
- Introduced setup and cleanup handlers and removed routine looping
on the DT children properties (Pratyush)
- Clarified in commit log requirements for training.
- Removed defconfig changes of patch 1 since they were reverted in
the last patch (Joel)

Cédric Le Goater (9):
ARM: dts: aspeed: Adjust "reg" property of FMC/SPI controllers
dt-bindings: spi: Add Aspeed SMC controllers device tree binding
spi: spi-mem: Convert Aspeed SMC driver to spi-mem
spi: aspeed: Add support for direct mapping
spi: aspeed: Adjust direct mapping to device size
spi: aspeed: Workaround AST2500 limitations
spi: aspeed: Add support for the AST2400 SPI controller
spi: aspeed: Calibrate read timings
ARM: dts: aspeed: Enable Dual SPI RX transfers

Potin Lai (1):
mtd: spi-nor: aspeed: set the decoding size to at least 2MB for
AST2600

Tao Ren (1):
ARM: dts: aspeed-g4: Set spi-max-frequency for all flashes

drivers/mtd/spi-nor/controllers/aspeed-smc.c | 921 -------------
drivers/spi/spi-aspeed-smc.c | 1210 +++++++++++++++++
.../devicetree/bindings/mtd/aspeed-smc.txt | 51 -
.../bindings/spi/aspeed,ast2600-fmc.yaml | 82 ++
MAINTAINERS | 10 +
arch/arm/boot/dts/aspeed-g4.dtsi | 16 +-
arch/arm/boot/dts/aspeed-g5.dtsi | 16 +-
arch/arm/boot/dts/aspeed-g6.dtsi | 17 +-
drivers/mtd/spi-nor/controllers/Kconfig | 10 -
drivers/mtd/spi-nor/controllers/Makefile | 1 -
drivers/spi/Kconfig | 11 +
drivers/spi/Makefile | 1 +
12 files changed, 1347 insertions(+), 999 deletions(-)
delete mode 100644 drivers/mtd/spi-nor/controllers/aspeed-smc.c
create mode 100644 drivers/spi/spi-aspeed-smc.c
delete mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
create mode 100644 Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml

--
2.35.1


2022-05-03 00:23:37

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 06/11] spi: aspeed: Workaround AST2500 limitations

It is not possible to configure a full 128MB window for a chip of the
same size on the AST2500 SPI controller. For this case, the maximum
window size is restricted to 120MB for CE0.

Reviewed-by: Joel Stanley <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
drivers/spi/spi-aspeed-smc.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 0aff42e20b8d..d2b3342c133e 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -451,6 +451,8 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi,
* - ioremap each window, not strictly necessary since the overall window
* is correct.
*/
+static const struct aspeed_spi_data ast2500_spi_data;
+
static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
u32 local_offset, u32 size)
{
@@ -459,6 +461,16 @@ static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
struct aspeed_spi_window *win = &windows[chip->cs];
int ret;

+ /*
+ * Due to an HW issue on the AST2500 SPI controller, the CE0
+ * window size should be smaller than the maximum 128MB.
+ */
+ if (aspi->data == &ast2500_spi_data && chip->cs == 0 && size == SZ_128M) {
+ size = 120 << 20;
+ dev_info(aspi->dev, "CE%d window resized to %dMB (AST2500 HW quirk)",
+ chip->cs, size >> 20);
+ }
+
aspeed_spi_get_windows(aspi, windows);

/* Adjust this chip window */
--
2.35.1

2022-05-03 00:23:38

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 07/11] spi: aspeed: Add support for the AST2400 SPI controller

Extend the driver for the AST2400 SPI Flash Controller (SPI). This
controller has a slightly different interface which requires
adaptation of the 4B handling. Summary of features :

. host Firmware
. 1 chip select pin (CE0)
. slightly different register set, between AST2500 and the legacy
controller
. no segment registers
. single, dual mode.

Reviewed-by: Joel Stanley <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
drivers/spi/spi-aspeed-smc.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index d2b3342c133e..d2b63c8bb88f 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -30,6 +30,7 @@
#define CTRL_IO_DUAL_DATA BIT(29)
#define CTRL_IO_QUAD_DATA BIT(30)
#define CTRL_COMMAND_SHIFT 16
+#define CTRL_IO_ADDRESS_4B BIT(13) /* AST2400 SPI only */
#define CTRL_IO_DUMMY_SET(dummy) \
(((((dummy) >> 2) & 0x1) << 14) | (((dummy) & 0x3) << 6))
#define CTRL_CE_STOP_ACTIVE BIT(2)
@@ -280,6 +281,8 @@ static bool aspeed_spi_supports_op(struct spi_mem *mem, const struct spi_mem_op
return spi_mem_default_supports_op(mem, op);
}

+static const struct aspeed_spi_data ast2400_spi_data;
+
static int do_aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct aspeed_spi *aspi = spi_controller_get_devdata(mem->spi->master);
@@ -309,6 +312,9 @@ static int do_aspeed_spi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
addr_mode |= (0x11 << chip->cs);
else
addr_mode &= ~(0x11 << chip->cs);
+
+ if (op->addr.nbytes == 4 && chip->aspi->data == &ast2400_spi_data)
+ ctl_val |= CTRL_IO_ADDRESS_4B;
}

if (op->dummy.nbytes)
@@ -398,7 +404,13 @@ static int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip)
struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
struct aspeed_spi_window *win = &windows[chip->cs];

- aspeed_spi_get_windows(aspi, windows);
+ /* No segment registers for the AST2400 SPI controller */
+ if (aspi->data == &ast2400_spi_data) {
+ win->offset = 0;
+ win->size = aspi->ahb_window_size;
+ } else {
+ aspeed_spi_get_windows(aspi, windows);
+ }

chip->ahb_base = aspi->ahb_base + win->offset;
chip->ahb_window_size = win->size;
@@ -461,6 +473,10 @@ static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
struct aspeed_spi_window *win = &windows[chip->cs];
int ret;

+ /* No segment registers for the AST2400 SPI controller */
+ if (aspi->data == &ast2400_spi_data)
+ return 0;
+
/*
* Due to an HW issue on the AST2500 SPI controller, the CE0
* window size should be smaller than the maximum 128MB.
@@ -545,6 +561,12 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
else
addr_mode &= ~(0x11 << chip->cs);
writel(addr_mode, aspi->regs + CE_CTRL_REG);
+
+ /* AST2400 SPI controller sets 4BYTE address mode in
+ * CE0 Control Register
+ */
+ if (op->addr.nbytes == 4 && chip->aspi->data == &ast2400_spi_data)
+ ctl_val |= CTRL_IO_ADDRESS_4B;
}

/* READ mode is the controller default setting */
@@ -816,6 +838,14 @@ static const struct aspeed_spi_data ast2400_fmc_data = {
.segment_reg = aspeed_spi_segment_reg,
};

+static const struct aspeed_spi_data ast2400_spi_data = {
+ .max_cs = 1,
+ .hastype = false,
+ .we0 = 0,
+ .ctl0 = 0x04,
+ /* No segment registers */
+};
+
static const struct aspeed_spi_data ast2500_fmc_data = {
.max_cs = 3,
.hastype = true,
@@ -860,6 +890,7 @@ static const struct aspeed_spi_data ast2600_spi_data = {

static const struct of_device_id aspeed_spi_matches[] = {
{ .compatible = "aspeed,ast2400-fmc", .data = &ast2400_fmc_data },
+ { .compatible = "aspeed,ast2400-spi", .data = &ast2400_spi_data },
{ .compatible = "aspeed,ast2500-fmc", .data = &ast2500_fmc_data },
{ .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data },
{ .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data },
--
2.35.1

2022-05-03 00:27:50

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 02/11] dt-bindings: spi: Add Aspeed SMC controllers device tree binding

The "interrupt" property is optional because it is only necessary for
controllers supporting DMAs (Not implemented yet in the new driver).

Cc: Chin-Ting Kuo <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Reviewed-by: Joel Stanley <[email protected]>
Reviewed-by: Rob Herring <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
.../bindings/spi/aspeed,ast2600-fmc.yaml | 82 +++++++++++++++++++
MAINTAINERS | 9 ++
2 files changed, 91 insertions(+)
create mode 100644 Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml

diff --git a/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml b/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml
new file mode 100644
index 000000000000..42a56f3c337c
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml
@@ -0,0 +1,82 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spi/aspeed,ast2600-fmc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Aspeed SMC controllers bindings
+
+maintainers:
+ - Chin-Ting Kuo <[email protected]>
+ - Cédric Le Goater <[email protected]>
+
+description: |
+ This binding describes the Aspeed Static Memory Controllers (FMC and
+ SPI) of the AST2400, AST2500 and AST2600 SOCs.
+
+allOf:
+ - $ref: "spi-controller.yaml#"
+
+properties:
+ compatible:
+ enum:
+ - aspeed,ast2600-fmc
+ - aspeed,ast2600-spi
+ - aspeed,ast2500-fmc
+ - aspeed,ast2500-spi
+ - aspeed,ast2400-fmc
+ - aspeed,ast2400-spi
+
+ reg:
+ items:
+ - description: registers
+ - description: memory mapping
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
+ #include <dt-bindings/clock/ast2600-clock.h>
+
+ spi@1e620000 {
+ reg = <0x1e620000 0xc4>, <0x20000000 0x10000000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "aspeed,ast2600-fmc";
+ clocks = <&syscon ASPEED_CLK_AHB>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+
+ flash@0 {
+ reg = < 0 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ spi-rx-bus-width = <2>;
+ };
+
+ flash@1 {
+ reg = < 1 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ spi-rx-bus-width = <2>;
+ };
+
+ flash@2 {
+ reg = < 2 >;
+ compatible = "jedec,spi-nor";
+ spi-max-frequency = <50000000>;
+ spi-rx-bus-width = <2>;
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 5e8c2f611766..3d74b5010cbb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3100,6 +3100,15 @@ S: Maintained
F: Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
F: drivers/mmc/host/sdhci-of-aspeed*

+ASPEED SMC SPI DRIVER
+M: Chin-Ting Kuo <[email protected]>
+M: Cédric Le Goater <[email protected]>
+L: [email protected] (moderated for non-subscribers)
+L: [email protected] (moderated for non-subscribers)
+L: [email protected]
+S: Maintained
+F: Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml
+
ASPEED VIDEO ENGINE DRIVER
M: Eddie James <[email protected]>
L: [email protected]
--
2.35.1

2022-05-03 00:34:20

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 11/11] mtd: spi-nor: aspeed: set the decoding size to at least 2MB for AST2600

From: Potin Lai <[email protected]>

In AST2600, the unit of SPI CEx decoding range register is 1MB, and end
address offset is set to the acctual offset - 1MB. If the flash only has
1MB, the end address will has same value as start address, which will
causing unexpected errors.

This patch set the decoding size to at least 2MB to avoid decoding errors.

Tested:
root@bletchley:~# dmesg | grep "aspeed-smc 1e631000.spi: CE0 window"
[ 59.328134] aspeed-smc 1e631000.spi: CE0 window resized to 2MB (AST2600 Decoding)
[ 59.343001] aspeed-smc 1e631000.spi: CE0 window [ 0x50000000 - 0x50200000 ] 2MB
root@bletchley:~# devmem 0x1e631030
0x00100000

Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Potin Lai <[email protected]>
[ clg : Ported on new spi-mem driver ]
Signed-off-by: Cédric Le Goater <[email protected]>
---
drivers/spi/spi-aspeed-smc.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 35f6934847b7..496f3e1e9079 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -474,6 +474,8 @@ static int aspeed_spi_set_window(struct aspeed_spi *aspi,
* is correct.
*/
static const struct aspeed_spi_data ast2500_spi_data;
+static const struct aspeed_spi_data ast2600_spi_data;
+static const struct aspeed_spi_data ast2600_fmc_data;

static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
u32 local_offset, u32 size)
@@ -497,6 +499,17 @@ static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
chip->cs, size >> 20);
}

+ /*
+ * The decoding size of AST2600 SPI controller should set at
+ * least 2MB.
+ */
+ if ((aspi->data == &ast2600_spi_data || aspi->data == &ast2600_fmc_data) &&
+ size < SZ_2M) {
+ size = SZ_2M;
+ dev_info(aspi->dev, "CE%d window resized to %dMB (AST2600 Decoding)",
+ chip->cs, size >> 20);
+ }
+
aspeed_spi_get_windows(aspi, windows);

/* Adjust this chip window */
--
2.35.1

2022-05-03 00:36:21

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 10/11] ARM: dts: aspeed-g4: Set spi-max-frequency for all flashes

From: Tao Ren <[email protected]>

Set "spi-max-frequency" to 50 MHz for all the flashes under the FMC
controller to ensure the clock frequency is calculated correctly.

Suggested-by: Cédric Le Goater <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Tao Ren <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
arch/arm/boot/dts/aspeed-g4.dtsi | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index 1c6354cec9f2..530491ae5eb2 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -72,24 +72,28 @@ flash@1 {
reg = < 1 >;
compatible = "jedec,spi-nor";
spi-rx-bus-width = <2>;
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@2 {
reg = < 2 >;
compatible = "jedec,spi-nor";
spi-rx-bus-width = <2>;
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@3 {
reg = < 3 >;
compatible = "jedec,spi-nor";
spi-rx-bus-width = <2>;
+ spi-max-frequency = <50000000>;
status = "disabled";
};
flash@4 {
reg = < 4 >;
compatible = "jedec,spi-nor";
spi-rx-bus-width = <2>;
+ spi-max-frequency = <50000000>;
status = "disabled";
};
};
--
2.35.1

2022-05-03 00:41:52

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 04/11] spi: aspeed: Add support for direct mapping

Use direct mapping to read the flash device contents. This operation
mode is called "Command mode" on Aspeed SoC SMC controllers. It uses a
Control Register for the settings to apply when a memory operation is
performed on the flash device mapping window.

If the window is not big enough, fall back to the "User mode" to
perform the read.

Direct mapping for writes will come later when validated.

Reviewed-by: Joel Stanley <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
drivers/spi/spi-aspeed-smc.c | 68 ++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index cb5a0652e5a4..50cc7bd7ba3e 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -411,10 +411,78 @@ static int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip)
return chip->ahb_window_size ? 0 : -1;
}

+static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
+{
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi_chip *chip = &aspi->chips[desc->mem->spi->chip_select];
+ struct spi_mem_op *op = &desc->info.op_tmpl;
+ u32 ctl_val;
+ int ret = 0;
+
+ chip->clk_freq = desc->mem->spi->max_speed_hz;
+
+ /* Only for reads */
+ if (op->data.dir != SPI_MEM_DATA_IN)
+ return -EOPNOTSUPP;
+
+ if (desc->info.length > chip->ahb_window_size)
+ dev_warn(aspi->dev, "CE%d window (%dMB) too small for mapping",
+ chip->cs, chip->ahb_window_size >> 20);
+
+ /* Define the default IO read settings */
+ ctl_val = readl(chip->ctl) & ~CTRL_IO_CMD_MASK;
+ ctl_val |= aspeed_spi_get_io_mode(op) |
+ op->cmd.opcode << CTRL_COMMAND_SHIFT |
+ CTRL_IO_DUMMY_SET(op->dummy.nbytes / op->dummy.buswidth) |
+ CTRL_IO_MODE_READ;
+
+ /* Tune 4BYTE address mode */
+ if (op->addr.nbytes) {
+ u32 addr_mode = readl(aspi->regs + CE_CTRL_REG);
+
+ if (op->addr.nbytes == 4)
+ addr_mode |= (0x11 << chip->cs);
+ else
+ addr_mode &= ~(0x11 << chip->cs);
+ writel(addr_mode, aspi->regs + CE_CTRL_REG);
+ }
+
+ /* READ mode is the controller default setting */
+ chip->ctl_val[ASPEED_SPI_READ] = ctl_val;
+ writel(chip->ctl_val[ASPEED_SPI_READ], chip->ctl);
+
+ dev_info(aspi->dev, "CE%d read buswidth:%d [0x%08x]\n",
+ chip->cs, op->data.buswidth, chip->ctl_val[ASPEED_SPI_READ]);
+
+ return ret;
+}
+
+static ssize_t aspeed_spi_dirmap_read(struct spi_mem_dirmap_desc *desc,
+ u64 offset, size_t len, void *buf)
+{
+ struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
+ struct aspeed_spi_chip *chip = &aspi->chips[desc->mem->spi->chip_select];
+
+ /* Switch to USER command mode if mapping window is too small */
+ if (chip->ahb_window_size < offset + len) {
+ int ret;
+
+ ret = aspeed_spi_read_user(chip, &desc->info.op_tmpl, offset, len, buf);
+ if (ret < 0)
+ return ret;
+ } else {
+ memcpy_fromio(buf, chip->ahb_base + offset, len);
+ }
+
+ return len;
+}
+
static const struct spi_controller_mem_ops aspeed_spi_mem_ops = {
.supports_op = aspeed_spi_supports_op,
.exec_op = aspeed_spi_exec_op,
.get_name = aspeed_spi_get_name,
+ .dirmap_create = aspeed_spi_dirmap_create,
+ .dirmap_read = aspeed_spi_dirmap_read,
};

static void aspeed_spi_chip_set_type(struct aspeed_spi *aspi, unsigned int cs, int type)
--
2.35.1

2022-05-03 00:45:37

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 01/11] ARM: dts: aspeed: Adjust "reg" property of FMC/SPI controllers

This is compatible with the current driver and addresses issues when
running 'make dt_binding_check'.

Cc: Chin-Ting Kuo <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
arch/arm/boot/dts/aspeed-g4.dtsi | 6 ++----
arch/arm/boot/dts/aspeed-g5.dtsi | 9 +++------
arch/arm/boot/dts/aspeed-g6.dtsi | 9 +++------
3 files changed, 8 insertions(+), 16 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed-g4.dtsi b/arch/arm/boot/dts/aspeed-g4.dtsi
index fa8b581c3d6c..3b7b98e787e7 100644
--- a/arch/arm/boot/dts/aspeed-g4.dtsi
+++ b/arch/arm/boot/dts/aspeed-g4.dtsi
@@ -54,8 +54,7 @@ ahb {
ranges;

fmc: spi@1e620000 {
- reg = < 0x1e620000 0x94
- 0x20000000 0x10000000 >;
+ reg = <0x1e620000 0x94>, <0x20000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2400-fmc";
@@ -91,8 +90,7 @@ flash@4 {
};

spi: spi@1e630000 {
- reg = < 0x1e630000 0x18
- 0x30000000 0x10000000 >;
+ reg = <0x1e630000 0x18>, <0x30000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2400-spi";
diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi
index 4147b397c883..1e727cbaab14 100644
--- a/arch/arm/boot/dts/aspeed-g5.dtsi
+++ b/arch/arm/boot/dts/aspeed-g5.dtsi
@@ -55,8 +55,7 @@ ahb {
ranges;

fmc: spi@1e620000 {
- reg = < 0x1e620000 0xc4
- 0x20000000 0x10000000 >;
+ reg = <0x1e620000 0xc4>, <0x20000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2500-fmc";
@@ -84,8 +83,7 @@ flash@2 {
};

spi1: spi@1e630000 {
- reg = < 0x1e630000 0xc4
- 0x30000000 0x08000000 >;
+ reg = <0x1e630000 0xc4>, <0x30000000 0x08000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2500-spi";
@@ -106,8 +104,7 @@ flash@1 {
};

spi2: spi@1e631000 {
- reg = < 0x1e631000 0xc4
- 0x38000000 0x08000000 >;
+ reg = <0x1e631000 0xc4>, <0x38000000 0x08000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2500-spi";
diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index 3d5ce9da42c3..6ae5dfecbdf1 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -95,8 +95,7 @@ gic: interrupt-controller@40461000 {
};

fmc: spi@1e620000 {
- reg = < 0x1e620000 0xc4
- 0x20000000 0x10000000 >;
+ reg = <0x1e620000 0xc4>, <0x20000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2600-fmc";
@@ -124,8 +123,7 @@ flash@2 {
};

spi1: spi@1e630000 {
- reg = < 0x1e630000 0xc4
- 0x30000000 0x10000000 >;
+ reg = <0x1e630000 0xc4>, <0x30000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2600-spi";
@@ -146,8 +144,7 @@ flash@1 {
};

spi2: spi@1e631000 {
- reg = < 0x1e631000 0xc4
- 0x50000000 0x10000000 >;
+ reg = <0x1e631000 0xc4>, <0x50000000 0x10000000>;
#address-cells = <1>;
#size-cells = <0>;
compatible = "aspeed,ast2600-spi";
--
2.35.1

2022-05-03 00:52:20

by Cédric Le Goater

[permalink] [raw]
Subject: [PATCH v5 05/11] spi: aspeed: Adjust direct mapping to device size

The segment registers of the FMC/SPI controllers provide a way to
configure the mapping window of the flash device contents on the AHB
bus. Adjust this window to the size of the spi-mem mapping.

Things get more complex with multiple devices. The driver needs to
also adjust the window of the next device to make sure that there is
no overlap, even if there is no available device. The proposal below
is not perfect but it is covering all the cases we have seen on
different boards with one and two devices on the same bus.

Reviewed-by: Joel Stanley <[email protected]>
Tested-by: Joel Stanley <[email protected]>
Tested-by: Tao Ren <[email protected]>
Tested-by: Jae Hyun Yoo <[email protected]>
Signed-off-by: Cédric Le Goater <[email protected]>
---
drivers/spi/spi-aspeed-smc.c | 88 ++++++++++++++++++++++++++++++++++++
1 file changed, 88 insertions(+)

diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c
index 50cc7bd7ba3e..0aff42e20b8d 100644
--- a/drivers/spi/spi-aspeed-smc.c
+++ b/drivers/spi/spi-aspeed-smc.c
@@ -411,6 +411,92 @@ static int aspeed_spi_chip_set_default_window(struct aspeed_spi_chip *chip)
return chip->ahb_window_size ? 0 : -1;
}

+static int aspeed_spi_set_window(struct aspeed_spi *aspi,
+ const struct aspeed_spi_window *win)
+{
+ u32 start = aspi->ahb_base_phy + win->offset;
+ u32 end = start + win->size;
+ void __iomem *seg_reg = aspi->regs + CE0_SEGMENT_ADDR_REG + win->cs * 4;
+ u32 seg_val_backup = readl(seg_reg);
+ u32 seg_val = aspi->data->segment_reg(aspi, start, end);
+
+ if (seg_val == seg_val_backup)
+ return 0;
+
+ writel(seg_val, seg_reg);
+
+ /*
+ * Restore initial value if something goes wrong else we could
+ * loose access to the chip.
+ */
+ if (seg_val != readl(seg_reg)) {
+ dev_err(aspi->dev, "CE%d invalid window [ 0x%.8x - 0x%.8x ] %dMB",
+ win->cs, start, end - 1, win->size >> 20);
+ writel(seg_val_backup, seg_reg);
+ return -EIO;
+ }
+
+ if (win->size)
+ dev_dbg(aspi->dev, "CE%d new window [ 0x%.8x - 0x%.8x ] %dMB",
+ win->cs, start, end - 1, win->size >> 20);
+ else
+ dev_dbg(aspi->dev, "CE%d window closed", win->cs);
+
+ return 0;
+}
+
+/*
+ * Yet to be done when possible :
+ * - Align mappings on flash size (we don't have the info)
+ * - ioremap each window, not strictly necessary since the overall window
+ * is correct.
+ */
+static int aspeed_spi_chip_adjust_window(struct aspeed_spi_chip *chip,
+ u32 local_offset, u32 size)
+{
+ struct aspeed_spi *aspi = chip->aspi;
+ struct aspeed_spi_window windows[ASPEED_SPI_MAX_NUM_CS] = { 0 };
+ struct aspeed_spi_window *win = &windows[chip->cs];
+ int ret;
+
+ aspeed_spi_get_windows(aspi, windows);
+
+ /* Adjust this chip window */
+ win->offset += local_offset;
+ win->size = size;
+
+ if (win->offset + win->size > aspi->ahb_window_size) {
+ win->size = aspi->ahb_window_size - win->offset;
+ dev_warn(aspi->dev, "CE%d window resized to %dMB", chip->cs, win->size >> 20);
+ }
+
+ ret = aspeed_spi_set_window(aspi, win);
+ if (ret)
+ return ret;
+
+ /* Update chip mapping info */
+ chip->ahb_base = aspi->ahb_base + win->offset;
+ chip->ahb_window_size = win->size;
+
+ /*
+ * Also adjust next chip window to make sure that it does not
+ * overlap with the current window.
+ */
+ if (chip->cs < aspi->data->max_cs - 1) {
+ struct aspeed_spi_window *next = &windows[chip->cs + 1];
+
+ /* Change offset and size to keep the same end address */
+ if ((next->offset + next->size) > (win->offset + win->size))
+ next->size = (next->offset + next->size) - (win->offset + win->size);
+ else
+ next->size = 0;
+ next->offset = win->offset + win->size;
+
+ aspeed_spi_set_window(aspi, next);
+ }
+ return 0;
+}
+
static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
{
struct aspeed_spi *aspi = spi_controller_get_devdata(desc->mem->spi->master);
@@ -425,6 +511,8 @@ static int aspeed_spi_dirmap_create(struct spi_mem_dirmap_desc *desc)
if (op->data.dir != SPI_MEM_DATA_IN)
return -EOPNOTSUPP;

+ aspeed_spi_chip_adjust_window(chip, desc->info.offset, desc->info.length);
+
if (desc->info.length > chip->ahb_window_size)
dev_warn(aspi->dev, "CE%d window (%dMB) too small for mapping",
chip->cs, chip->ahb_window_size >> 20);
--
2.35.1

2022-05-03 05:38:55

by Joel Stanley

[permalink] [raw]
Subject: Re: [PATCH v5 00/11] spi: spi-mem: Convert Aspeed SMC driver to spi-mem

On Mon, 2 May 2022 at 08:13, Cédric Le Goater <[email protected]> wrote:
> This series adds a new SPI driver using the spi-mem interface for the
> Aspeed static memory controllers of the AST2600, AST2500 and AST2400
> SoCs.

I put this into the OpenBMC yocto tree, which pushes it through CI and
does a qemu boot on Romulus. I also tested on Palmetto in qemu and the
AST2600A3 EVB.

https://gerrit.openbmc-project.xyz/c/openbmc/openbmc/+/51551

It looks good.

Tested-by: Joel Stanley <[email protected]>

Cheers,

Joel