Merge tag 'spi-fix-v6.18-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi

Pull spi fixes from Mark Brown:
 "A moderately large collection of device specific changes here, mostly
  fixes but also including a few new quirks and device IDs. This is all
  fairly routine even for the affected devices"

* tag 'spi-fix-v6.18-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: dt-bindings: spi-rockchip: Add RK3506 compatible
  spi: intel-pci: Add support for Intel Wildcat Lake SPI serial flash
  spi: intel-pci: Add support for Arrow Lake-H SPI serial flash
  spi: intel: Add support for 128M component density
  spi: airoha: fix reading/writing of flashes with more than one plane per lun
  spi: airoha: switch back to non-dma mode in the case of error
  spi: airoha: add support of dual/quad wires spi modes to exec_op() handler
  spi: airoha: return an error for continuous mode dirmap creation cases
  spi: amlogic: fix spifc build error
  spi: cadence-quadspi: Fix pm_runtime unbalance on dma EPROBE_DEFER
  spi: spi-nxp-fspi: limit the clock rate for different sample clock source selection
  spi: spi-nxp-fspi: add extra delay after dll locked
  spi: spi-nxp-fspi: re-config the clock rate when operation require new clock rate
  spi: dw-mmio: add error handling for reset_control_deassert()
  spi: rockchip-sfc: Fix DMA-API usage
  spi: dt-bindings: cadence: add soc-specific compatible strings for zynqmp and versal-net
This commit is contained in:
Linus Torvalds
2025-10-24 11:01:40 -07:00
10 changed files with 160 additions and 45 deletions
@@ -14,9 +14,14 @@ allOf:
properties:
compatible:
enum:
- cdns,spi-r1p6
- xlnx,zynq-spi-r1p6
oneOf:
- enum:
- xlnx,zynq-spi-r1p6
- items:
- enum:
- xlnx,zynqmp-spi-r1p6
- xlnx,versal-net-spi-r1p6
- const: cdns,spi-r1p6
reg:
maxItems: 1
@@ -34,6 +34,7 @@ properties:
- rockchip,rk3328-spi
- rockchip,rk3368-spi
- rockchip,rk3399-spi
- rockchip,rk3506-spi
- rockchip,rk3528-spi
- rockchip,rk3562-spi
- rockchip,rk3568-spi
+97 -31
View File
@@ -192,6 +192,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
@@ -387,10 +395,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 +433,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;
@@ -618,6 +658,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;
@@ -654,13 +698,13 @@ static ssize_t airoha_snand_dirmap_read(struct spi_mem_dirmap_desc *desc,
err = airoha_snand_nfi_config(as_ctrl);
if (err)
return 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,
@@ -689,8 +733,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);
/* 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;
@@ -760,6 +805,8 @@ 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;
}
@@ -824,7 +871,9 @@ static ssize_t airoha_snand_dirmap_write(struct spi_mem_dirmap_desc *desc,
if (err)
goto error_dma_unmap;
err = regmap_write(as_ctrl->regmap_nfi, REG_SPI_NFI_PG_CTL2, 0x0);
/* 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;
@@ -892,18 +941,35 @@ 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);
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 +980,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;
}
+2 -2
View File
@@ -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;
+3 -2
View File
@@ -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);
+3 -1
View File
@@ -358,7 +358,9 @@ static int dw_spi_mmio_probe(struct platform_device *pdev)
if (IS_ERR(dwsmmio->rstc))
return PTR_ERR(dwsmmio->rstc);
reset_control_deassert(dwsmmio->rstc);
ret = reset_control_deassert(dwsmmio->rstc);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n");
dws->bus_num = pdev->id;
+2
View File
@@ -75,10 +75,12 @@ static const struct pci_device_id intel_spi_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x38a4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x43a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4b24), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x4d23), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info },
{ PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7723), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info },
{ PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info },
+6
View File
@@ -132,6 +132,7 @@
#define FLCOMP_C0DEN_16M 0x05
#define FLCOMP_C0DEN_32M 0x06
#define FLCOMP_C0DEN_64M 0x07
#define FLCOMP_C0DEN_128M 0x08
#define INTEL_SPI_TIMEOUT 5000 /* ms */
#define INTEL_SPI_FIFO_SZ 64
@@ -1347,7 +1348,12 @@ static int intel_spi_read_desc(struct intel_spi *ispi)
case FLCOMP_C0DEN_64M:
ispi->chip0_size = SZ_64M;
break;
case FLCOMP_C0DEN_128M:
ispi->chip0_size = SZ_128M;
break;
default:
dev_warn(ispi->dev, "unsupported C0DEN: %#lx\n",
flcomp & FLCOMP_C0DEN_MASK);
return -EINVAL;
}
+27 -5
View File
@@ -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);
}
+11 -1
View File
@@ -704,7 +704,12 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
ret = -ENOMEM;
goto err_dma;
}
sfc->dma_buffer = virt_to_phys(sfc->buffer);
sfc->dma_buffer = dma_map_single(dev, sfc->buffer,
sfc->max_iosize, DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev, sfc->dma_buffer)) {
ret = -ENOMEM;
goto err_dma_map;
}
}
ret = devm_spi_register_controller(dev, host);
@@ -715,6 +720,9 @@ static int rockchip_sfc_probe(struct platform_device *pdev)
return 0;
err_register:
dma_unmap_single(dev, sfc->dma_buffer, sfc->max_iosize,
DMA_BIDIRECTIONAL);
err_dma_map:
free_pages((unsigned long)sfc->buffer, get_order(sfc->max_iosize));
err_dma:
pm_runtime_get_sync(dev);
@@ -736,6 +744,8 @@ static void rockchip_sfc_remove(struct platform_device *pdev)
struct spi_controller *host = sfc->host;
spi_unregister_controller(host);
dma_unmap_single(&pdev->dev, sfc->dma_buffer, sfc->max_iosize,
DMA_BIDIRECTIONAL);
free_pages((unsigned long)sfc->buffer, get_order(sfc->max_iosize));
clk_disable_unprepare(sfc->clk);