diff options
| -rw-r--r-- | drivers/spi/spi-airoha-snfi.c | 513 | ||||
| -rw-r--r-- | drivers/spi/spi-amlogic-spifc-a4.c | 4 | ||||
| -rw-r--r-- | drivers/spi/spi-cadence-quadspi.c | 5 | ||||
| -rw-r--r-- | drivers/spi/spi-nxp-fspi.c | 32 |
4 files changed, 298 insertions, 256 deletions
diff --git a/drivers/spi/spi-airoha-snfi.c b/drivers/spi/spi-airoha-snfi.c index dbe640986825..8408aee9c06e 100644 --- a/drivers/spi/spi-airoha-snfi.c +++ b/drivers/spi/spi-airoha-snfi.c @@ -147,6 +147,8 @@ #define SPI_NFI_CUS_SEC_SIZE_EN BIT(16) #define REG_SPI_NFI_RD_CTL2 0x0510 +#define SPI_NFI_DATA_READ_CMD GENMASK(7, 0) + #define REG_SPI_NFI_RD_CTL3 0x0514 #define REG_SPI_NFI_PG_CTL1 0x0524 @@ -179,7 +181,9 @@ #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE 0x03 #define SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST 0x0b #define SPI_NAND_OP_READ_FROM_CACHE_DUAL 0x3b +#define SPI_NAND_OP_READ_FROM_CACHE_DUALIO 0xbb #define SPI_NAND_OP_READ_FROM_CACHE_QUAD 0x6b +#define SPI_NAND_OP_READ_FROM_CACHE_QUADIO 0xeb #define SPI_NAND_OP_WRITE_ENABLE 0x06 #define SPI_NAND_OP_WRITE_DISABLE 0x04 #define SPI_NAND_OP_PROGRAM_LOAD_SINGLE 0x02 @@ -192,6 +196,14 @@ #define SPI_NAND_OP_RESET 0xff #define SPI_NAND_OP_DIE_SELECT 0xc2 +/* SNAND FIFO commands */ +#define SNAND_FIFO_TX_BUSWIDTH_SINGLE 0x08 +#define SNAND_FIFO_TX_BUSWIDTH_DUAL 0x09 +#define SNAND_FIFO_TX_BUSWIDTH_QUAD 0x0a +#define SNAND_FIFO_RX_BUSWIDTH_SINGLE 0x0c +#define SNAND_FIFO_RX_BUSWIDTH_DUAL 0x0e +#define SNAND_FIFO_RX_BUSWIDTH_QUAD 0x0f + #define SPI_NAND_CACHE_SIZE (SZ_4K + SZ_256) #define SPI_MAX_TRANSFER_SIZE 511 @@ -211,13 +223,6 @@ struct airoha_snand_ctrl { struct regmap *regmap_ctrl; struct regmap *regmap_nfi; struct clk *spi_clk; - - struct { - size_t page_size; - size_t sec_size; - u8 sec_num; - u8 spare_size; - } nfi_cfg; }; static int airoha_snand_set_fifo_op(struct airoha_snand_ctrl *as_ctrl, @@ -387,10 +392,26 @@ static int airoha_snand_set_mode(struct airoha_snand_ctrl *as_ctrl, return regmap_write(as_ctrl->regmap_ctrl, REG_SPI_CTRL_DUMMY, 0); } -static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd, - const u8 *data, int len) +static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, + const u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_TX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_TX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_TX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; @@ -409,16 +430,32 @@ static int airoha_snand_write_data(struct airoha_snand_ctrl *as_ctrl, u8 cmd, return 0; } -static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, u8 *data, - int len) +static int airoha_snand_read_data(struct airoha_snand_ctrl *as_ctrl, + u8 *data, int len, int buswidth) { int i, data_len; + u8 cmd; + + switch (buswidth) { + case 0: + case 1: + cmd = SNAND_FIFO_RX_BUSWIDTH_SINGLE; + break; + case 2: + cmd = SNAND_FIFO_RX_BUSWIDTH_DUAL; + break; + case 4: + cmd = SNAND_FIFO_RX_BUSWIDTH_QUAD; + break; + default: + return -EINVAL; + } for (i = 0; i < len; i += data_len) { int err; data_len = min(len - i, SPI_MAX_TRANSFER_SIZE); - err = airoha_snand_set_fifo_op(as_ctrl, 0xc, data_len); + err = airoha_snand_set_fifo_op(as_ctrl, cmd, data_len); if (err) return err; @@ -446,92 +483,6 @@ static int airoha_snand_nfi_init(struct airoha_snand_ctrl *as_ctrl) SPI_NFI_ALL_IRQ_EN, SPI_NFI_AHB_DONE_EN); } -static int airoha_snand_nfi_config(struct airoha_snand_ctrl *as_ctrl) -{ - int err; - u32 val; - - err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, - SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); - if (err) - return err; - - /* auto FDM */ - err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_AUTO_FDM_EN); - if (err) - return err; - - /* HW ECC */ - err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_HW_ECC_EN); - if (err) - return err; - - /* DMA Burst */ - err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_DMA_BURST_EN); - if (err) - return err; - - /* page format */ - switch (as_ctrl->nfi_cfg.spare_size) { - case 26: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x1); - break; - case 27: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x2); - break; - case 28: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x3); - break; - default: - val = FIELD_PREP(SPI_NFI_SPARE_SIZE, 0x0); - break; - } - - err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_SPARE_SIZE, val); - if (err) - return err; - - switch (as_ctrl->nfi_cfg.page_size) { - case 2048: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x1); - break; - case 4096: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x2); - break; - default: - val = FIELD_PREP(SPI_NFI_PAGE_SIZE, 0x0); - break; - } - - err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_PAGEFMT, - SPI_NFI_PAGE_SIZE, val); - if (err) - return err; - - /* sec num */ - val = FIELD_PREP(SPI_NFI_SEC_NUM, as_ctrl->nfi_cfg.sec_num); - err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, - SPI_NFI_SEC_NUM, val); - if (err) - return err; - - /* enable cust sec size */ - err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE_EN); - if (err) - return err; - - /* set cust sec size */ - val = FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, as_ctrl->nfi_cfg.sec_size); - return regmap_update_bits(as_ctrl->regmap_nfi, - REG_SPI_NFI_SECCUS_SIZE, - SPI_NFI_CUS_SEC_SIZE, val); -} - static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) { if (op->addr.nbytes != 2) @@ -564,33 +515,6 @@ static bool airoha_snand_is_page_ops(const struct spi_mem_op *op) } } -static int airoha_snand_adjust_op_size(struct spi_mem *mem, - struct spi_mem_op *op) -{ - size_t max_len; - - if (airoha_snand_is_page_ops(op)) { - struct airoha_snand_ctrl *as_ctrl; - - as_ctrl = spi_controller_get_devdata(mem->spi->controller); - max_len = as_ctrl->nfi_cfg.sec_size; - max_len += as_ctrl->nfi_cfg.spare_size; - max_len *= as_ctrl->nfi_cfg.sec_num; - - if (op->data.nbytes > max_len) - op->data.nbytes = max_len; - } else { - max_len = 1 + op->addr.nbytes + op->dummy.nbytes; - if (max_len >= 160) - return -EOPNOTSUPP; - - if (op->data.nbytes > 160 - max_len) - op->data.nbytes = 160 - max_len; - } - - return 0; -} - static bool airoha_snand_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { @@ -618,6 +542,10 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) if (desc->info.offset + desc->info.length > U32_MAX) return -EINVAL; + /* continuous reading is not supported */ + if (desc->info.length > SPI_NAND_CACHE_SIZE) + return -E2BIG; + if (!airoha_snand_supports_op(desc->mem, &desc->info.op_tmpl)) return -EOPNOTSUPP; @@ -627,40 +555,97 @@ static int airoha_snand_dirmap_create(struct spi_mem_dirmap_desc *desc) static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, void *buf) { - struct spi_mem_op *op = &desc->info.op_tmpl; struct spi_device *spi = desc->mem->spi; struct airoha_snand_ctrl *as_ctrl; u8 *txrx_buf = spi_get_ctldata(spi); dma_addr_t dma_addr; - u32 val, rd_mode; + u32 val, rd_mode, opcode; + size_t bytes; int err; - switch (op->cmd.opcode) { + as_ctrl = spi_controller_get_devdata(spi->controller); + + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + /* + * DUALIO and QUADIO opcodes are not supported by the spi controller, + * replace them with supported opcodes. + */ + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE: + case SPI_NAND_OP_READ_FROM_CACHE_SINGLE_FAST: + rd_mode = 0; + break; case SPI_NAND_OP_READ_FROM_CACHE_DUAL: + case SPI_NAND_OP_READ_FROM_CACHE_DUALIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_DUAL; rd_mode = 1; break; case SPI_NAND_OP_READ_FROM_CACHE_QUAD: + case SPI_NAND_OP_READ_FROM_CACHE_QUADIO: + opcode = SPI_NAND_OP_READ_FROM_CACHE_QUAD; rd_mode = 2; break; default: - rd_mode = 0; - break; + /* unknown opcode */ + return -EOPNOTSUPP; } - as_ctrl = spi_controller_get_devdata(spi->controller); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); if (err < 0) return err; - err = airoha_snand_nfi_config(as_ctrl); + /* NFI reset */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); if (err) - return err; + goto error_dma_mode_off; + + /* NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for reading (SPI_NFI_READ_MODE) + * - Setup reading command: FIELD_PREP(SPI_NFI_OPMODE, 6) + * - Use DMA instead of PIO for data reading + */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 6)); + if (err) + goto error_dma_mode_off; + + /* Set number of sector will be read */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); err = dma_mapping_error(as_ctrl->dev, dma_addr); if (err) - return err; + goto error_dma_mode_off; /* set dma addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, @@ -668,18 +653,24 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, if (err) goto error_dma_unmap; - /* set cust sec size */ - val = as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num; - val = FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, val); + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.read_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL2, - SPI_NFI_READ_DATA_BYTE_NUM, val); + SPI_NFI_READ_DATA_BYTE_NUM, + FIELD_PREP(SPI_NFI_READ_DATA_BYTE_NUM, bytes)); if (err) goto error_dma_unmap; /* set read command */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL2, - op->cmd.opcode); + FIELD_PREP(SPI_NFI_DATA_READ_CMD, opcode)); if (err) goto error_dma_unmap; @@ -689,20 +680,9 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, if (err) goto error_dma_unmap; - /* set read addr */ - err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, 0x0); - if (err) - goto error_dma_unmap; - - /* set nfi read */ - err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_OPMODE, - FIELD_PREP(SPI_NFI_OPMODE, 6)); - if (err) - goto error_dma_unmap; - - err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_READ_MODE | SPI_NFI_DMA_MODE); + /* set read addr: zero page offset + descriptor read offset */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_RD_CTL3, + desc->info.offset); if (err) goto error_dma_unmap; @@ -710,7 +690,7 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, if (err) goto error_dma_unmap; - /* trigger dma start read */ + /* trigger dma reading */ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_RD_TRIG); if (err) @@ -760,87 +740,138 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc, error_dma_unmap: dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, DMA_FROM_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); return err; } static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, u64 offs, size_t len, const void *buf) { - struct spi_mem_op *op = &desc->info.op_tmpl; struct spi_device *spi = desc->mem->spi; u8 *txrx_buf = spi_get_ctldata(spi); struct airoha_snand_ctrl *as_ctrl; dma_addr_t dma_addr; - u32 wr_mode, val; + u32 wr_mode, val, opcode; + size_t bytes; int err; as_ctrl = spi_controller_get_devdata(spi->controller); - err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); - if (err < 0) - return err; + /* minimum oob size is 64 */ + bytes = round_up(offs + len, 64); + + opcode = desc->info.op_tmpl.cmd.opcode; + switch (opcode) { + case SPI_NAND_OP_PROGRAM_LOAD_SINGLE: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDOM_SINGLE: + wr_mode = 0; + break; + case SPI_NAND_OP_PROGRAM_LOAD_QUAD: + case SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD: + wr_mode = 2; + break; + default: + /* unknown opcode */ + return -EOPNOTSUPP; + } + + if (offs > 0) + memset(txrx_buf, 0xff, offs); memcpy(txrx_buf + offs, buf, len); - dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, - DMA_TO_DEVICE); - err = dma_mapping_error(as_ctrl->dev, dma_addr); - if (err) - return err; + if (bytes > offs + len) + memset(txrx_buf + offs + len, 0xff, bytes - offs - len); err = airoha_snand_set_mode(as_ctrl, SPI_MODE_DMA); if (err < 0) - goto error_dma_unmap; + return err; - err = airoha_snand_nfi_config(as_ctrl); + /* NFI reset */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_FIFO_FLUSH | SPI_NFI_RST); if (err) - goto error_dma_unmap; + goto error_dma_mode_off; - if (op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_QUAD || - op->cmd.opcode == SPI_NAND_OP_PROGRAM_LOAD_RAMDON_QUAD) - wr_mode = BIT(1); - else - wr_mode = 0; + /* + * NFI configure: + * - No AutoFDM (custom sector size (SECCUS) register will be used) + * - No SoC's hardware ECC (flash internal ECC will be used) + * - Use burst mode (faster, but requires 16 byte alignment for addresses) + * - Setup for writing (SPI_NFI_READ_MODE bit is cleared) + * - Setup writing command: FIELD_PREP(SPI_NFI_OPMODE, 3) + * - Use DMA instead of PIO for data writing + */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, + SPI_NFI_DMA_MODE | + SPI_NFI_READ_MODE | + SPI_NFI_DMA_BURST_EN | + SPI_NFI_HW_ECC_EN | + SPI_NFI_AUTO_FDM_EN | + SPI_NFI_OPMODE, + SPI_NFI_DMA_MODE | + SPI_NFI_DMA_BURST_EN | + FIELD_PREP(SPI_NFI_OPMODE, 3)); + if (err) + goto error_dma_mode_off; + /* Set number of sector will be written */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, + SPI_NFI_SEC_NUM, + FIELD_PREP(SPI_NFI_SEC_NUM, 1)); + if (err) + goto error_dma_mode_off; + + /* Set custom sector size */ + err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, + SPI_NFI_CUS_SEC_SIZE | + SPI_NFI_CUS_SEC_SIZE_EN, + FIELD_PREP(SPI_NFI_CUS_SEC_SIZE, bytes) | + SPI_NFI_CUS_SEC_SIZE_EN); + if (err) + goto error_dma_mode_off; + + dma_addr = dma_map_single(as_ctrl->dev, txrx_buf, SPI_NAND_CACHE_SIZE, + DMA_TO_DEVICE); + err = dma_mapping_error(as_ctrl->dev, dma_addr); + if (err) + goto error_dma_mode_off; + + /* set dma addr */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_STRADDR, dma_addr); if (err) goto error_dma_unmap; - val = FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, - as_ctrl->nfi_cfg.sec_size * as_ctrl->nfi_cfg.sec_num); + /* + * Setup transfer length + * --------------------- + * The following rule MUST be met: + * transfer_length = + * = NFI_SNF_MISC_CTL2.write_data_byte_number = + * = NFI_CON.sector_number * NFI_SECCUS.custom_sector_size + */ err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL2, - SPI_NFI_PROG_LOAD_BYTE_NUM, val); + SPI_NFI_PROG_LOAD_BYTE_NUM, + FIELD_PREP(SPI_NFI_PROG_LOAD_BYTE_NUM, bytes)); if (err) goto error_dma_unmap; + /* set write command */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL1, - FIELD_PREP(SPI_NFI_PG_LOAD_CMD, - op->cmd.opcode)); + FIELD_PREP(SPI_NFI_PG_LOAD_CMD, opcode)); if (err) goto error_dma_unmap; + /* set write mode */ err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_SNF_MISC_CTL, FIELD_PREP(SPI_NFI_DATA_READ_WR_MODE, wr_mode)); if (err) goto error_dma_unmap; - err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0); - if (err) - goto error_dma_unmap; - - err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_READ_MODE); - if (err) - goto error_dma_unmap; - - err = regmap_update_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_OPMODE, - FIELD_PREP(SPI_NFI_OPMODE, 3)); - if (err) - goto error_dma_unmap; - - err = regmap_set_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CNFG, - SPI_NFI_DMA_MODE); + /* set write addr: zero page offset + descriptor write offset */ + err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, + desc->info.offset); if (err) goto error_dma_unmap; @@ -848,6 +879,7 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, if (err) goto error_dma_unmap; + /* trigger dma writing */ err = regmap_clear_bits(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, SPI_NFI_WR_TRIG); if (err) @@ -892,18 +924,36 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc, error_dma_unmap: dma_unmap_single(as_ctrl->dev, dma_addr, SPI_NAND_CACHE_SIZE, DMA_TO_DEVICE); +error_dma_mode_off: + airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); return err; } static int airoha_snand_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) { - u8 data[8], cmd, opcode = op->cmd.opcode; struct airoha_snand_ctrl *as_ctrl; + int op_len, addr_len, dummy_len; + u8 buf[20], *data; int i, err; as_ctrl = spi_controller_get_devdata(mem->spi->controller); + op_len = op->cmd.nbytes; + addr_len = op->addr.nbytes; + dummy_len = op->dummy.nbytes; + + if (op_len + dummy_len + addr_len > sizeof(buf)) + return -EIO; + + data = buf; + for (i = 0; i < op_len; i++) + *data++ = op->cmd.opcode >> (8 * (op_len - i - 1)); + for (i = 0; i < addr_len; i++) + *data++ = op->addr.val >> (8 * (addr_len - i - 1)); + for (i = 0; i < dummy_len; i++) + *data++ = 0xff; + /* switch to manual mode */ err = airoha_snand_set_mode(as_ctrl, SPI_MODE_MANUAL); if (err < 0) @@ -914,40 +964,40 @@ static int airoha_snand_exec_op(struct spi_mem *mem, return err; /* opcode */ - err = airoha_snand_write_data(as_ctrl, 0x8, &opcode, sizeof(opcode)); + data = buf; + err = airoha_snand_write_data(as_ctrl, data, op_len, + op->cmd.buswidth); if (err) return err; /* addr part */ - cmd = opcode == SPI_NAND_OP_GET_FEATURE ? 0x11 : 0x8; - put_unaligned_be64(op->addr.val, data); - - for (i = ARRAY_SIZE(data) - op->addr.nbytes; - i < ARRAY_SIZE(data); i++) { - err = airoha_snand_write_data(as_ctrl, cmd, &data[i], - sizeof(data[0])); + data += op_len; + if (addr_len) { + err = airoha_snand_write_data(as_ctrl, data, addr_len, + op->addr.buswidth); if (err) return err; } /* dummy */ - data[0] = 0xff; - for (i = 0; i < op->dummy.nbytes; i++) { - err = airoha_snand_write_data(as_ctrl, 0x8, &data[0], - sizeof(data[0])); + data += addr_len; + if (dummy_len) { + err = airoha_snand_write_data(as_ctrl, data, dummy_len, + op->dummy.buswidth); if (err) return err; } /* data */ - if (op->data.dir == SPI_MEM_DATA_IN) { - err = airoha_snand_read_data(as_ctrl, op->data.buf.in, - op->data.nbytes); - if (err) - return err; - } else { - err = airoha_snand_write_data(as_ctrl, 0x8, op->data.buf.out, - op->data.nbytes); + if (op->data.nbytes) { + if (op->data.dir == SPI_MEM_DATA_IN) + err = airoha_snand_read_data(as_ctrl, op->data.buf.in, + op->data.nbytes, + op->data.buswidth); + else + err = airoha_snand_write_data(as_ctrl, op->data.buf.out, + op->data.nbytes, + op->data.buswidth); if (err) return err; } @@ -956,7 +1006,6 @@ static int airoha_snand_exec_op(struct spi_mem *mem, } static const struct spi_controller_mem_ops airoha_snand_mem_ops = { - .adjust_op_size = airoha_snand_adjust_op_size, .supports_op = airoha_snand_supports_op, .exec_op = airoha_snand_exec_op, .dirmap_create = airoha_snand_dirmap_create, @@ -981,36 +1030,6 @@ static int airoha_snand_setup(struct spi_device *spi) return 0; } -static int airoha_snand_nfi_setup(struct airoha_snand_ctrl *as_ctrl) -{ - u32 val, sec_size, sec_num; - int err; - - err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_CON, &val); - if (err) - return err; - - sec_num = FIELD_GET(SPI_NFI_SEC_NUM, val); - - err = regmap_read(as_ctrl->regmap_nfi, REG_SPI_NFI_SECCUS_SIZE, &val); - if (err) - return err; - - sec_size = FIELD_GET(SPI_NFI_CUS_SEC_SIZE, val); - - /* init default value */ - as_ctrl->nfi_cfg.sec_size = sec_size; - as_ctrl->nfi_cfg.sec_num = sec_num; - as_ctrl->nfi_cfg.page_size = round_down(sec_size * sec_num, 1024); - as_ctrl->nfi_cfg.spare_size = 16; - - err = airoha_snand_nfi_init(as_ctrl); - if (err) - return err; - - return airoha_snand_nfi_config(as_ctrl); -} - static const struct regmap_config spi_ctrl_regmap_config = { .name = "ctrl", .reg_bits = 32, @@ -1084,7 +1103,7 @@ static int airoha_snand_probe(struct platform_device *pdev) ctrl->setup = airoha_snand_setup; device_set_node(&ctrl->dev, dev_fwnode(dev)); - err = airoha_snand_nfi_setup(as_ctrl); + err = airoha_snand_nfi_init(as_ctrl); if (err) return err; diff --git a/drivers/spi/spi-amlogic-spifc-a4.c b/drivers/spi/spi-amlogic-spifc-a4.c index 4338d00e56a6..35a7c4965e11 100644 --- a/drivers/spi/spi-amlogic-spifc-a4.c +++ b/drivers/spi/spi-amlogic-spifc-a4.c @@ -286,7 +286,7 @@ static int aml_sfc_set_bus_width(struct aml_sfc *sfc, u8 buswidth, u32 mask) for (i = 0; i <= LANE_MAX; i++) { if (buswidth == 1 << i) { - conf = i << __bf_shf(mask); + conf = i << __ffs(mask); return regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG, mask, conf); } @@ -566,7 +566,7 @@ static int aml_sfc_raw_io_op(struct aml_sfc *sfc, const struct spi_mem_op *op) if (!op->data.nbytes) goto end_xfer; - conf = (op->data.nbytes >> RAW_SIZE_BW) << __bf_shf(RAW_EXT_SIZE); + conf = (op->data.nbytes >> RAW_SIZE_BW) << __ffs(RAW_EXT_SIZE); ret = regmap_update_bits(sfc->regmap_base, SFC_SPI_CFG, RAW_EXT_SIZE, conf); if (ret) goto err_out; diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 8fb13df8ff87..81017402bc56 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1995,7 +1995,7 @@ static int cqspi_probe(struct platform_device *pdev) if (cqspi->use_direct_mode) { ret = cqspi_request_mmap_dma(cqspi); if (ret == -EPROBE_DEFER) - goto probe_setup_failed; + goto probe_dma_failed; } if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { @@ -2019,9 +2019,10 @@ static int cqspi_probe(struct platform_device *pdev) return 0; probe_setup_failed: - cqspi_controller_enable(cqspi, 0); if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) pm_runtime_disable(dev); +probe_dma_failed: + cqspi_controller_enable(cqspi, 0); probe_reset_failed: if (cqspi->is_jh7110) cqspi_jh7110_disable_clk(pdev, cqspi); diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index f9371f98a65b..b6c79e50d842 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -404,6 +404,10 @@ struct nxp_fspi { #define FSPI_NEED_INIT BIT(0) #define FSPI_DTR_MODE BIT(1) int flags; + /* save the previous operation clock rate */ + unsigned long pre_op_rate; + /* the max clock rate fspi output to device */ + unsigned long max_rate; }; static inline int needs_ip_only(struct nxp_fspi *f) @@ -685,10 +689,13 @@ static void nxp_fspi_select_rx_sample_clk_source(struct nxp_fspi *f, * change the mode back to mode 0. */ reg = fspi_readl(f, f->iobase + FSPI_MCR0); - if (op_is_dtr) + if (op_is_dtr) { reg |= FSPI_MCR0_RXCLKSRC(3); - else /*select mode 0 */ + f->max_rate = 166000000; + } else { /*select mode 0 */ reg &= ~FSPI_MCR0_RXCLKSRC(3); + f->max_rate = 66000000; + } fspi_writel(f, reg, f->iobase + FSPI_MCR0); } @@ -719,6 +726,12 @@ static void nxp_fspi_dll_calibration(struct nxp_fspi *f) 0, POLL_TOUT, true); if (ret) dev_warn(f->dev, "DLL lock failed, please fix it!\n"); + + /* + * For ERR050272, DLL lock status bit is not accurate, + * wait for 4us more as a workaround. + */ + udelay(4); } /* @@ -780,11 +793,17 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, uint64_t size_kb; /* - * Return, if previously selected target device is same as current - * requested target device. Also the DTR or STR mode do not change. + * Return when following condition all meet, + * 1, if previously selected target device is same as current + * requested target device. + * 2, the DTR or STR mode do not change. + * 3, previous operation max rate equals current one. + * + * For other case, need to re-config. */ if ((f->selected == spi_get_chipselect(spi, 0)) && - (!!(f->flags & FSPI_DTR_MODE) == op_is_dtr)) + (!!(f->flags & FSPI_DTR_MODE) == op_is_dtr) && + (f->pre_op_rate == op->max_freq)) return; /* Reset FLSHxxCR0 registers */ @@ -802,6 +821,7 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, dev_dbg(f->dev, "Target device [CS:%x] selected\n", spi_get_chipselect(spi, 0)); nxp_fspi_select_rx_sample_clk_source(f, op_is_dtr); + rate = min(f->max_rate, op->max_freq); if (op_is_dtr) { f->flags |= FSPI_DTR_MODE; @@ -832,6 +852,8 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi, else nxp_fspi_dll_override(f); + f->pre_op_rate = op->max_freq; + f->selected = spi_get_chipselect(spi, 0); } |
