From 716d0a0a2ab00c601120c19bb357f4373f4722d1 Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 14 Nov 2025 18:10:40 +0800 Subject: spi: aspeed: Enable Quad SPI mode for page program Ensure the controller switches to quad I/O mode when spi-tx-bus-width dts property is 4 and the Quad SPI program opcode (32h or 34h) is used. Without this change, high-bit data will be lost during page programming. Signed-off-by: Chin-Ting Kuo Link: https://patch.msgid.link/20251114101042.1520997-3-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- drivers/spi/spi-aspeed-smc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 179c47ffbfeb..4163632fed8b 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -263,11 +263,15 @@ static ssize_t aspeed_spi_write_user(struct aspeed_spi_chip *chip, const struct spi_mem_op *op) { int ret; + int io_mode = aspeed_spi_get_io_mode(op); aspeed_spi_start_user(chip); ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode); if (ret < 0) goto stop_user; + + aspeed_spi_set_io_mode(chip, io_mode); + aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes); stop_user: aspeed_spi_stop_user(chip); -- cgit v1.2.3 From be6671d3908e97a2128f5327610a1dcb4d420cfa Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 14 Nov 2025 18:10:39 +0800 Subject: spi: dt-bindings: aspeed,ast2600-fmc: Add AST2700 SoC support Add AST2700 to the list of supported SoCs in the ASPEED FMC/SPI bindings. AST2700 FMC/SPI controllers are not compatible with AST2600 due to the following hardware differences: - Address decoding unit uses 64KB granularity (AST2600 uses 1MB). - Segment register semantics are changed. AST2600: start <= range <= end AST2700: start <= range < end - Hardware limitations in AST2600 address decoding registers have been resolved in AST2700, so extra callback function used for bug fixup is no longer required. These differences require distinct compatible strings for AST2700. Signed-off-by: Chin-Ting Kuo Acked-by: Conor Dooley Link: https://patch.msgid.link/20251114101042.1520997-2-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml b/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml index 57d932af4506..80e542624cc6 100644 --- a/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml +++ b/Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml @@ -12,7 +12,7 @@ maintainers: description: | This binding describes the Aspeed Static Memory Controllers (FMC and - SPI) of the AST2400, AST2500 and AST2600 SOCs. + SPI) of the AST2400, AST2500, AST2600 and AST2700 SOCs. allOf: - $ref: spi-controller.yaml# @@ -20,6 +20,8 @@ allOf: properties: compatible: enum: + - aspeed,ast2700-fmc + - aspeed,ast2700-spi - aspeed,ast2600-fmc - aspeed,ast2600-spi - aspeed,ast2500-fmc -- cgit v1.2.3 From 508f3d3b688e1650ed383fe208b323aa6c164420 Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 14 Nov 2025 18:10:41 +0800 Subject: spi: aspeed: Use phys_addr_t for bus addresses to support 64-bit platforms Update bus address types from u32 to phys_addr_t to support systems with 64-bit memory address space. This change ensures compatibility with upcoming SoCs that extend the system bus beyond 32-bit, while maintaining support for existing platforms. Signed-off-by: Chin-Ting Kuo Link: https://patch.msgid.link/20251114101042.1520997-4-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- drivers/spi/spi-aspeed-smc.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index 4163632fed8b..d1a8bdf6d540 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -82,9 +82,10 @@ struct aspeed_spi_data { u32 hdiv_max; u32 min_window_size; - u32 (*segment_start)(struct aspeed_spi *aspi, u32 reg); - u32 (*segment_end)(struct aspeed_spi *aspi, u32 reg); - u32 (*segment_reg)(struct aspeed_spi *aspi, u32 start, u32 end); + phys_addr_t (*segment_start)(struct aspeed_spi *aspi, u32 reg); + phys_addr_t (*segment_end)(struct aspeed_spi *aspi, u32 reg); + u32 (*segment_reg)(struct aspeed_spi *aspi, phys_addr_t start, + phys_addr_t end); int (*adjust_window)(struct aspeed_spi *aspi); u32 (*get_clk_div)(struct aspeed_spi_chip *chip, u32 hz); int (*calibrate)(struct aspeed_spi_chip *chip, u32 hdiv, @@ -97,7 +98,7 @@ struct aspeed_spi { const struct aspeed_spi_data *data; void __iomem *regs; - u32 ahb_base_phy; + phys_addr_t ahb_base_phy; u32 ahb_window_size; u32 num_cs; struct device *dev; @@ -484,9 +485,9 @@ static int aspeed_spi_chip_set_default_window(struct aspeed_spi *aspi) /* Assign the minimum window size to each CS */ for (cs = 0; cs < aspi->num_cs; cs++) { aspi->chips[cs].ahb_window_size = aspi->data->min_window_size; - dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ]", - cs, aspi->ahb_base_phy + aspi->data->min_window_size * cs, - aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1); + dev_dbg(aspi->dev, "CE%d default window [ 0x%.9llx - 0x%.9llx ]", + cs, (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs), + (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1)); } /* Close unused CS */ @@ -930,17 +931,18 @@ static void aspeed_spi_remove(struct platform_device *pdev) * The address range is encoded with absolute addresses in the overall * mapping window. */ -static u32 aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg) +static phys_addr_t aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg) { return ((reg >> 16) & 0xFF) << 23; } -static u32 aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg) +static phys_addr_t aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg) { return ((reg >> 24) & 0xFF) << 23; } -static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end) +static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, + phys_addr_t start, phys_addr_t end) { return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24); } @@ -952,16 +954,16 @@ static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end) #define AST2600_SEG_ADDR_MASK 0x0ff00000 -static u32 aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi, - u32 reg) +static phys_addr_t aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi, + u32 reg) { u32 start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; return aspi->ahb_base_phy + start_offset; } -static u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi, - u32 reg) +static phys_addr_t aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi, + u32 reg) { u32 end_offset = reg & AST2600_SEG_ADDR_MASK; @@ -973,7 +975,7 @@ static u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi, } static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi, - u32 start, u32 end) + phys_addr_t start, phys_addr_t end) { /* disable zero size segments */ if (start == end) -- cgit v1.2.3 From 9e510e677090bb794b46348b10e1c8038286e00a Mon Sep 17 00:00:00 2001 From: Chin-Ting Kuo Date: Fri, 14 Nov 2025 18:10:42 +0800 Subject: spi: aspeed: Add support for the AST2700 SPI controller Extend the driver to support the AST2700 SPI controller. Compared to AST2600, AST2700 has the following characteristics: - A 64-bit memory address space. - A 64KB address decoding unit. - Segment registers now use (start <= range < end) semantics, which differs slightly from (start <= range <= end) in AST2600. - Known issues related to address decoding range registers have been resolved, and the decoding range is now 1GB, which is sufficient. Therefore, the adjust_window callback is no longer required on AST2700 for range adjustment and bug fixes. - The SPI clock divider method and timing calibration logic remain unchanged from AST2600. Signed-off-by: Chin-Ting Kuo Link: https://patch.msgid.link/20251114101042.1520997-5-chin-ting_kuo@aspeedtech.com Signed-off-by: Mark Brown --- drivers/spi/spi-aspeed-smc.c | 71 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/drivers/spi/spi-aspeed-smc.c b/drivers/spi/spi-aspeed-smc.c index d1a8bdf6d540..db3e096f2eb0 100644 --- a/drivers/spi/spi-aspeed-smc.c +++ b/drivers/spi/spi-aspeed-smc.c @@ -985,6 +985,41 @@ static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi, ((end - 1) & AST2600_SEG_ADDR_MASK); } +/* The Segment Registers of the AST2700 use a 64KB unit. */ +#define AST2700_SEG_ADDR_MASK 0x7fff0000 + +static phys_addr_t aspeed_spi_segment_ast2700_start(struct aspeed_spi *aspi, + u32 reg) +{ + u64 start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK; + + if (!start_offset) + return aspi->ahb_base_phy; + + return aspi->ahb_base_phy + start_offset; +} + +static phys_addr_t aspeed_spi_segment_ast2700_end(struct aspeed_spi *aspi, + u32 reg) +{ + u64 end_offset = reg & AST2700_SEG_ADDR_MASK; + + if (!end_offset) + return aspi->ahb_base_phy; + + return aspi->ahb_base_phy + end_offset; +} + +static u32 aspeed_spi_segment_ast2700_reg(struct aspeed_spi *aspi, + phys_addr_t start, phys_addr_t end) +{ + if (start == end) + return 0; + + return (u32)(((start & AST2700_SEG_ADDR_MASK) >> 16) | + (end & AST2700_SEG_ADDR_MASK)); +} + /* * Read timing compensation sequences */ @@ -1511,6 +1546,40 @@ static const struct aspeed_spi_data ast2600_spi_data = { .adjust_window = aspeed_adjust_window_ast2600, }; +static const struct aspeed_spi_data ast2700_fmc_data = { + .max_cs = 3, + .hastype = false, + .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, + .we0 = 16, + .ctl0 = CE0_CTRL_REG, + .timing = CE0_TIMING_COMPENSATION_REG, + .hclk_mask = 0xf0fff0ff, + .hdiv_max = 2, + .min_window_size = 0x10000, + .get_clk_div = aspeed_get_clk_div_ast2600, + .calibrate = aspeed_spi_ast2600_calibrate, + .segment_start = aspeed_spi_segment_ast2700_start, + .segment_end = aspeed_spi_segment_ast2700_end, + .segment_reg = aspeed_spi_segment_ast2700_reg, +}; + +static const struct aspeed_spi_data ast2700_spi_data = { + .max_cs = 2, + .hastype = false, + .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, + .we0 = 16, + .ctl0 = CE0_CTRL_REG, + .timing = CE0_TIMING_COMPENSATION_REG, + .hclk_mask = 0xf0fff0ff, + .hdiv_max = 2, + .min_window_size = 0x10000, + .get_clk_div = aspeed_get_clk_div_ast2600, + .calibrate = aspeed_spi_ast2600_calibrate, + .segment_start = aspeed_spi_segment_ast2700_start, + .segment_end = aspeed_spi_segment_ast2700_end, + .segment_reg = aspeed_spi_segment_ast2700_reg, +}; + 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 }, @@ -1518,6 +1587,8 @@ static const struct of_device_id aspeed_spi_matches[] = { { .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data }, { .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data }, { .compatible = "aspeed,ast2600-spi", .data = &ast2600_spi_data }, + { .compatible = "aspeed,ast2700-fmc", .data = &ast2700_fmc_data }, + { .compatible = "aspeed,ast2700-spi", .data = &ast2700_spi_data }, { } }; MODULE_DEVICE_TABLE(of, aspeed_spi_matches); -- cgit v1.2.3