Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

spi: aspeed: Add AST2700 SoC support and Quad SPI

Merge series from Chin-Ting Kuo <chin-ting_kuo@aspeedtech.com>:

This series adds AST2700 support to the ASPEED FMC/SPI driver and
bindings, introduces 64-bit address compatibility, and improves
Quad SPI page programming behavior. It also implements AST2700-specific
segment logic, where range adjustment is not required because the
AST2700 SPI hardware controller already fixes decoding issues on
the existing platforms and adopts an updated scheme.

+95 -16
+3 -1
Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml
··· 12 12 13 13 description: | 14 14 This binding describes the Aspeed Static Memory Controllers (FMC and 15 - SPI) of the AST2400, AST2500 and AST2600 SOCs. 15 + SPI) of the AST2400, AST2500, AST2600 and AST2700 SOCs. 16 16 17 17 allOf: 18 18 - $ref: spi-controller.yaml# ··· 20 20 properties: 21 21 compatible: 22 22 enum: 23 + - aspeed,ast2700-fmc 24 + - aspeed,ast2700-spi 23 25 - aspeed,ast2600-fmc 24 26 - aspeed,ast2600-spi 25 27 - aspeed,ast2500-fmc
+92 -15
drivers/spi/spi-aspeed-smc.c
··· 82 82 u32 hdiv_max; 83 83 u32 min_window_size; 84 84 85 - u32 (*segment_start)(struct aspeed_spi *aspi, u32 reg); 86 - u32 (*segment_end)(struct aspeed_spi *aspi, u32 reg); 87 - u32 (*segment_reg)(struct aspeed_spi *aspi, u32 start, u32 end); 85 + phys_addr_t (*segment_start)(struct aspeed_spi *aspi, u32 reg); 86 + phys_addr_t (*segment_end)(struct aspeed_spi *aspi, u32 reg); 87 + u32 (*segment_reg)(struct aspeed_spi *aspi, phys_addr_t start, 88 + phys_addr_t end); 88 89 int (*adjust_window)(struct aspeed_spi *aspi); 89 90 u32 (*get_clk_div)(struct aspeed_spi_chip *chip, u32 hz); 90 91 int (*calibrate)(struct aspeed_spi_chip *chip, u32 hdiv, ··· 98 97 const struct aspeed_spi_data *data; 99 98 100 99 void __iomem *regs; 101 - u32 ahb_base_phy; 100 + phys_addr_t ahb_base_phy; 102 101 u32 ahb_window_size; 103 102 u32 num_cs; 104 103 struct device *dev; ··· 264 263 const struct spi_mem_op *op) 265 264 { 266 265 int ret; 266 + int io_mode = aspeed_spi_get_io_mode(op); 267 267 268 268 aspeed_spi_start_user(chip); 269 269 ret = aspeed_spi_send_cmd_addr(chip, op->addr.nbytes, op->addr.val, op->cmd.opcode); 270 270 if (ret < 0) 271 271 goto stop_user; 272 + 273 + aspeed_spi_set_io_mode(chip, io_mode); 274 + 272 275 aspeed_spi_write_to_ahb(chip->ahb_base, op->data.buf.out, op->data.nbytes); 273 276 stop_user: 274 277 aspeed_spi_stop_user(chip); ··· 485 480 /* Assign the minimum window size to each CS */ 486 481 for (cs = 0; cs < aspi->num_cs; cs++) { 487 482 aspi->chips[cs].ahb_window_size = aspi->data->min_window_size; 488 - dev_dbg(aspi->dev, "CE%d default window [ 0x%.8x - 0x%.8x ]", 489 - cs, aspi->ahb_base_phy + aspi->data->min_window_size * cs, 490 - aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1); 483 + dev_dbg(aspi->dev, "CE%d default window [ 0x%.9llx - 0x%.9llx ]", 484 + cs, (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs), 485 + (u64)(aspi->ahb_base_phy + aspi->data->min_window_size * cs - 1)); 491 486 } 492 487 493 488 /* Close unused CS */ ··· 931 926 * The address range is encoded with absolute addresses in the overall 932 927 * mapping window. 933 928 */ 934 - static u32 aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg) 929 + static phys_addr_t aspeed_spi_segment_start(struct aspeed_spi *aspi, u32 reg) 935 930 { 936 931 return ((reg >> 16) & 0xFF) << 23; 937 932 } 938 933 939 - static u32 aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg) 934 + static phys_addr_t aspeed_spi_segment_end(struct aspeed_spi *aspi, u32 reg) 940 935 { 941 936 return ((reg >> 24) & 0xFF) << 23; 942 937 } 943 938 944 - static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, u32 start, u32 end) 939 + static u32 aspeed_spi_segment_reg(struct aspeed_spi *aspi, 940 + phys_addr_t start, phys_addr_t end) 945 941 { 946 942 return (((start >> 23) & 0xFF) << 16) | (((end >> 23) & 0xFF) << 24); 947 943 } ··· 954 948 955 949 #define AST2600_SEG_ADDR_MASK 0x0ff00000 956 950 957 - static u32 aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi, 958 - u32 reg) 951 + static phys_addr_t aspeed_spi_segment_ast2600_start(struct aspeed_spi *aspi, 952 + u32 reg) 959 953 { 960 954 u32 start_offset = (reg << 16) & AST2600_SEG_ADDR_MASK; 961 955 962 956 return aspi->ahb_base_phy + start_offset; 963 957 } 964 958 965 - static u32 aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi, 966 - u32 reg) 959 + static phys_addr_t aspeed_spi_segment_ast2600_end(struct aspeed_spi *aspi, 960 + u32 reg) 967 961 { 968 962 u32 end_offset = reg & AST2600_SEG_ADDR_MASK; 969 963 ··· 975 969 } 976 970 977 971 static u32 aspeed_spi_segment_ast2600_reg(struct aspeed_spi *aspi, 978 - u32 start, u32 end) 972 + phys_addr_t start, phys_addr_t end) 979 973 { 980 974 /* disable zero size segments */ 981 975 if (start == end) ··· 983 977 984 978 return ((start & AST2600_SEG_ADDR_MASK) >> 16) | 985 979 ((end - 1) & AST2600_SEG_ADDR_MASK); 980 + } 981 + 982 + /* The Segment Registers of the AST2700 use a 64KB unit. */ 983 + #define AST2700_SEG_ADDR_MASK 0x7fff0000 984 + 985 + static phys_addr_t aspeed_spi_segment_ast2700_start(struct aspeed_spi *aspi, 986 + u32 reg) 987 + { 988 + u64 start_offset = (reg << 16) & AST2700_SEG_ADDR_MASK; 989 + 990 + if (!start_offset) 991 + return aspi->ahb_base_phy; 992 + 993 + return aspi->ahb_base_phy + start_offset; 994 + } 995 + 996 + static phys_addr_t aspeed_spi_segment_ast2700_end(struct aspeed_spi *aspi, 997 + u32 reg) 998 + { 999 + u64 end_offset = reg & AST2700_SEG_ADDR_MASK; 1000 + 1001 + if (!end_offset) 1002 + return aspi->ahb_base_phy; 1003 + 1004 + return aspi->ahb_base_phy + end_offset; 1005 + } 1006 + 1007 + static u32 aspeed_spi_segment_ast2700_reg(struct aspeed_spi *aspi, 1008 + phys_addr_t start, phys_addr_t end) 1009 + { 1010 + if (start == end) 1011 + return 0; 1012 + 1013 + return (u32)(((start & AST2700_SEG_ADDR_MASK) >> 16) | 1014 + (end & AST2700_SEG_ADDR_MASK)); 986 1015 } 987 1016 988 1017 /* ··· 1546 1505 .adjust_window = aspeed_adjust_window_ast2600, 1547 1506 }; 1548 1507 1508 + static const struct aspeed_spi_data ast2700_fmc_data = { 1509 + .max_cs = 3, 1510 + .hastype = false, 1511 + .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, 1512 + .we0 = 16, 1513 + .ctl0 = CE0_CTRL_REG, 1514 + .timing = CE0_TIMING_COMPENSATION_REG, 1515 + .hclk_mask = 0xf0fff0ff, 1516 + .hdiv_max = 2, 1517 + .min_window_size = 0x10000, 1518 + .get_clk_div = aspeed_get_clk_div_ast2600, 1519 + .calibrate = aspeed_spi_ast2600_calibrate, 1520 + .segment_start = aspeed_spi_segment_ast2700_start, 1521 + .segment_end = aspeed_spi_segment_ast2700_end, 1522 + .segment_reg = aspeed_spi_segment_ast2700_reg, 1523 + }; 1524 + 1525 + static const struct aspeed_spi_data ast2700_spi_data = { 1526 + .max_cs = 2, 1527 + .hastype = false, 1528 + .mode_bits = SPI_RX_QUAD | SPI_TX_QUAD, 1529 + .we0 = 16, 1530 + .ctl0 = CE0_CTRL_REG, 1531 + .timing = CE0_TIMING_COMPENSATION_REG, 1532 + .hclk_mask = 0xf0fff0ff, 1533 + .hdiv_max = 2, 1534 + .min_window_size = 0x10000, 1535 + .get_clk_div = aspeed_get_clk_div_ast2600, 1536 + .calibrate = aspeed_spi_ast2600_calibrate, 1537 + .segment_start = aspeed_spi_segment_ast2700_start, 1538 + .segment_end = aspeed_spi_segment_ast2700_end, 1539 + .segment_reg = aspeed_spi_segment_ast2700_reg, 1540 + }; 1541 + 1549 1542 static const struct of_device_id aspeed_spi_matches[] = { 1550 1543 { .compatible = "aspeed,ast2400-fmc", .data = &ast2400_fmc_data }, 1551 1544 { .compatible = "aspeed,ast2400-spi", .data = &ast2400_spi_data }, ··· 1587 1512 { .compatible = "aspeed,ast2500-spi", .data = &ast2500_spi_data }, 1588 1513 { .compatible = "aspeed,ast2600-fmc", .data = &ast2600_fmc_data }, 1589 1514 { .compatible = "aspeed,ast2600-spi", .data = &ast2600_spi_data }, 1515 + { .compatible = "aspeed,ast2700-fmc", .data = &ast2700_fmc_data }, 1516 + { .compatible = "aspeed,ast2700-spi", .data = &ast2700_spi_data }, 1590 1517 { } 1591 1518 }; 1592 1519 MODULE_DEVICE_TABLE(of, aspeed_spi_matches);