Skip to content

Commit

Permalink
spi-nand/spi-mem DTR support
Browse files Browse the repository at this point in the history
Merge series from Miquel Raynal <miquel.raynal@bootlin.com>:

Here is a (big) series supposed to bring DTR support in SPI-NAND.
  • Loading branch information
Mark Brown committed Jan 10, 2025
2 parents 5e56618 + f000689 commit 89b37e4
Show file tree
Hide file tree
Showing 17 changed files with 204 additions and 40 deletions.
2 changes: 2 additions & 0 deletions drivers/mtd/nand/spi/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,8 @@ spinand_select_op_variant(struct spinand_device *spinand,
if (ret)
break;

spi_mem_adjust_op_freq(spinand->spimem, &op);

if (!spi_mem_supports_op(spinand->spimem, &op))
break;

Expand Down
21 changes: 11 additions & 10 deletions drivers/spi/spi-amd.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,19 +298,16 @@ static const struct amd_spi_freq amd_spi_freq[] = {
{ AMD_SPI_MIN_HZ, F_800KHz, 0},
};

static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
static void amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
{
unsigned int i, spd7_val, alt_spd;

if (speed_hz < AMD_SPI_MIN_HZ)
return -EINVAL;

for (i = 0; i < ARRAY_SIZE(amd_spi_freq); i++)
if (speed_hz >= amd_spi_freq[i].speed_hz)
break;

if (amd_spi->speed_hz == amd_spi_freq[i].speed_hz)
return 0;
return;

amd_spi->speed_hz = amd_spi_freq[i].speed_hz;

Expand All @@ -329,8 +326,6 @@ static int amd_set_spi_freq(struct amd_spi *amd_spi, u32 speed_hz)
amd_spi_setclear_reg32(amd_spi, AMD_SPI_SPEED_REG, spd7_val,
AMD_SPI_SPD7_MASK);
}

return 0;
}

static inline int amd_spi_fifo_xfer(struct amd_spi *amd_spi,
Expand Down Expand Up @@ -479,6 +474,9 @@ static bool amd_spi_supports_op(struct spi_mem *mem,
return false;
}

if (op->max_freq < mem->spi->controller->min_speed_hz)
return false;

return spi_mem_default_supports_op(mem, op);
}

Expand Down Expand Up @@ -676,9 +674,7 @@ static int amd_spi_exec_mem_op(struct spi_mem *mem,

amd_spi = spi_controller_get_devdata(mem->spi->controller);

ret = amd_set_spi_freq(amd_spi, mem->spi->max_speed_hz);
if (ret)
return ret;
amd_set_spi_freq(amd_spi, op->max_freq);

if (amd_spi->version == AMD_SPI_V2)
amd_set_spi_addr_mode(amd_spi, op);
Expand All @@ -705,6 +701,10 @@ static const struct spi_controller_mem_ops amd_spi_mem_ops = {
.supports_op = amd_spi_supports_op,
};

static const struct spi_controller_mem_caps amd_spi_mem_caps = {
.per_op_freq = true,
};

static int amd_spi_host_transfer(struct spi_controller *host,
struct spi_message *msg)
{
Expand Down Expand Up @@ -782,6 +782,7 @@ static int amd_spi_probe(struct platform_device *pdev)
host->setup = amd_spi_host_setup;
host->transfer_one_message = amd_spi_host_transfer;
host->mem_ops = &amd_spi_mem_ops;
host->mem_caps = &amd_spi_mem_caps;
host->max_transfer_size = amd_spi_max_transfer_size;
host->max_message_size = amd_spi_max_transfer_size;

Expand Down
7 changes: 6 additions & 1 deletion drivers/spi/spi-amlogic-spifc-a1.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ static int amlogic_spifc_a1_exec_op(struct spi_mem *mem,
size_t data_size = op->data.nbytes;
int ret;

ret = amlogic_spifc_a1_set_freq(spifc, mem->spi->max_speed_hz);
ret = amlogic_spifc_a1_set_freq(spifc, op->max_freq);
if (ret)
return ret;

Expand Down Expand Up @@ -320,6 +320,10 @@ static const struct spi_controller_mem_ops amlogic_spifc_a1_mem_ops = {
.adjust_op_size = amlogic_spifc_a1_adjust_op_size,
};

static const struct spi_controller_mem_caps amlogic_spifc_a1_mem_caps = {
.per_op_freq = true,
};

static int amlogic_spifc_a1_probe(struct platform_device *pdev)
{
struct spi_controller *ctrl;
Expand Down Expand Up @@ -356,6 +360,7 @@ static int amlogic_spifc_a1_probe(struct platform_device *pdev)
ctrl->bits_per_word_mask = SPI_BPW_MASK(8);
ctrl->auto_runtime_pm = true;
ctrl->mem_ops = &amlogic_spifc_a1_mem_ops;
ctrl->mem_caps = &amlogic_spifc_a1_mem_caps;
ctrl->min_speed_hz = SPIFC_A1_MIN_HZ;
ctrl->max_speed_hz = SPIFC_A1_MAX_HZ;
ctrl->mode_bits = (SPI_RX_DUAL | SPI_TX_DUAL |
Expand Down
3 changes: 2 additions & 1 deletion drivers/spi/spi-cadence-quadspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1433,7 +1433,7 @@ static int cqspi_mem_process(struct spi_mem *mem, const struct spi_mem_op *op)
struct cqspi_flash_pdata *f_pdata;

f_pdata = &cqspi->f_pdata[spi_get_chipselect(mem->spi, 0)];
cqspi_configure(f_pdata, mem->spi->max_speed_hz);
cqspi_configure(f_pdata, op->max_freq);

if (op->data.dir == SPI_MEM_DATA_IN && op->data.buf.in) {
/*
Expand Down Expand Up @@ -1682,6 +1682,7 @@ static const struct spi_controller_mem_ops cqspi_mem_ops = {

static const struct spi_controller_mem_caps cqspi_mem_caps = {
.dtr = true,
.per_op_freq = true,
};

static int cqspi_setup_flash(struct cqspi_st *cqspi)
Expand Down
10 changes: 8 additions & 2 deletions drivers/spi/spi-dw-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,7 +677,7 @@ static int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
* operation. Transmit-only mode is suitable for the rest of them.
*/
cfg.dfs = 8;
cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
cfg.freq = clamp(op->max_freq, 0U, dws->max_mem_freq);
if (op->data.dir == SPI_MEM_DATA_IN) {
cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;
cfg.ndf = op->data.nbytes;
Expand Down Expand Up @@ -894,6 +894,10 @@ static void dw_spi_hw_init(struct device *dev, struct dw_spi *dws)
dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
}

static const struct spi_controller_mem_caps dw_spi_mem_caps = {
.per_op_freq = true,
};

int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
{
struct spi_controller *host;
Expand Down Expand Up @@ -941,8 +945,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
host->set_cs = dw_spi_set_cs;
host->transfer_one = dw_spi_transfer_one;
host->handle_err = dw_spi_handle_err;
if (dws->mem_ops.exec_op)
if (dws->mem_ops.exec_op) {
host->mem_ops = &dws->mem_ops;
host->mem_caps = &dw_spi_mem_caps;
}
host->max_speed_hz = dws->max_freq;
host->flags = SPI_CONTROLLER_GPIO_SS;
host->auto_runtime_pm = true;
Expand Down
12 changes: 9 additions & 3 deletions drivers/spi/spi-fsl-qspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,10 @@ static void fsl_qspi_invalidate(struct fsl_qspi *q)
qspi_writel(q, reg, q->iobase + QUADSPI_MCR);
}

static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi)
static void fsl_qspi_select_mem(struct fsl_qspi *q, struct spi_device *spi,
const struct spi_mem_op *op)
{
unsigned long rate = spi->max_speed_hz;
unsigned long rate = op->max_freq;
int ret;

if (q->selected == spi_get_chipselect(spi, 0))
Expand Down Expand Up @@ -652,7 +653,7 @@ static int fsl_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
fsl_qspi_readl_poll_tout(q, base + QUADSPI_SR, (QUADSPI_SR_IP_ACC_MASK |
QUADSPI_SR_AHB_ACC_MASK), 10, 1000);

fsl_qspi_select_mem(q, mem->spi);
fsl_qspi_select_mem(q, mem->spi, op);

if (needs_amba_base_offset(q))
addr_offset = q->memmap_phy;
Expand Down Expand Up @@ -839,6 +840,10 @@ static const struct spi_controller_mem_ops fsl_qspi_mem_ops = {
.get_name = fsl_qspi_get_name,
};

static const struct spi_controller_mem_caps fsl_qspi_mem_caps = {
.per_op_freq = true,
};

static int fsl_qspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
Expand Down Expand Up @@ -923,6 +928,7 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ctlr->bus_num = -1;
ctlr->num_chipselect = 4;
ctlr->mem_ops = &fsl_qspi_mem_ops;
ctlr->mem_caps = &fsl_qspi_mem_caps;

fsl_qspi_default_setup(q);

Expand Down
34 changes: 34 additions & 0 deletions drivers/spi/spi-mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
return false;
}

if (op->max_freq && mem->spi->controller->min_speed_hz &&
op->max_freq < mem->spi->controller->min_speed_hz)
return false;

if (op->max_freq &&
op->max_freq < mem->spi->max_speed_hz) {
if (!spi_mem_controller_is_capable(ctlr, per_op_freq))
return false;
}

return spi_mem_check_buswidth(mem, op);
}
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
Expand Down Expand Up @@ -364,6 +374,9 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
u8 *tmpbuf;
int ret;

/* Make sure the operation frequency is correct before going futher */
spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op);

ret = spi_mem_check_op(op);
if (ret)
return ret;
Expand Down Expand Up @@ -410,6 +423,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_buf = tmpbuf;
xfers[xferpos].len = op->cmd.nbytes;
xfers[xferpos].tx_nbits = op->cmd.buswidth;
xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen++;
Expand All @@ -424,6 +438,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].tx_buf = tmpbuf + 1;
xfers[xferpos].len = op->addr.nbytes;
xfers[xferpos].tx_nbits = op->addr.buswidth;
xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->addr.nbytes;
Expand All @@ -435,6 +450,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
xfers[xferpos].len = op->dummy.nbytes;
xfers[xferpos].tx_nbits = op->dummy.buswidth;
xfers[xferpos].dummy_data = 1;
xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->dummy.nbytes;
Expand All @@ -450,6 +466,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
}

xfers[xferpos].len = op->data.nbytes;
xfers[xferpos].speed_hz = op->max_freq;
spi_message_add_tail(&xfers[xferpos], &msg);
xferpos++;
totalxferlen += op->data.nbytes;
Expand Down Expand Up @@ -528,6 +545,23 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);

/**
* spi_mem_adjust_op_freq() - Adjust the frequency of a SPI mem operation to
* match controller, PCB and chip limitations
* @mem: the SPI memory
* @op: the operation to adjust
*
* Some chips have per-op frequency limitations and must adapt the maximum
* speed. This function allows SPI mem drivers to set @op->max_freq to the
* maximum supported value.
*/
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
{
if (!op->max_freq || op->max_freq > mem->spi->max_speed_hz)
op->max_freq = mem->spi->max_speed_hz;
}
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);

static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf)
{
Expand Down
26 changes: 22 additions & 4 deletions drivers/spi/spi-microchip-core-qspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,8 @@ static irqreturn_t mchp_coreqspi_isr(int irq, void *dev_id)
return ret;
}

static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi)
static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_device *spi,
const struct spi_mem_op *op)
{
unsigned long clk_hz;
u32 control, baud_rate_val = 0;
Expand All @@ -274,11 +275,11 @@ static int mchp_coreqspi_setup_clock(struct mchp_coreqspi *qspi, struct spi_devi
if (!clk_hz)
return -EINVAL;

baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * spi->max_speed_hz);
baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER) {
dev_err(&spi->dev,
"could not configure the clock for spi clock %d Hz & system clock %ld Hz\n",
spi->max_speed_hz, clk_hz);
op->max_freq, clk_hz);
return -EINVAL;
}

Expand Down Expand Up @@ -399,7 +400,7 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o
if (err)
goto error;

err = mchp_coreqspi_setup_clock(qspi, mem->spi);
err = mchp_coreqspi_setup_clock(qspi, mem->spi, op);
if (err)
goto error;

Expand Down Expand Up @@ -457,6 +458,10 @@ static int mchp_coreqspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *o

static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_op *op)
{
struct mchp_coreqspi *qspi = spi_controller_get_devdata(mem->spi->controller);
unsigned long clk_hz;
u32 baud_rate_val;

if (!spi_mem_default_supports_op(mem, op))
return false;

Expand All @@ -479,6 +484,14 @@ static bool mchp_coreqspi_supports_op(struct spi_mem *mem, const struct spi_mem_
return false;
}

clk_hz = clk_get_rate(qspi->clk);
if (!clk_hz)
return false;

baud_rate_val = DIV_ROUND_UP(clk_hz, 2 * op->max_freq);
if (baud_rate_val > MAX_DIVIDER || baud_rate_val < MIN_DIVIDER)
return false;

return true;
}

Expand All @@ -498,6 +511,10 @@ static const struct spi_controller_mem_ops mchp_coreqspi_mem_ops = {
.exec_op = mchp_coreqspi_exec_op,
};

static const struct spi_controller_mem_caps mchp_coreqspi_mem_caps = {
.per_op_freq = true,
};

static int mchp_coreqspi_probe(struct platform_device *pdev)
{
struct spi_controller *ctlr;
Expand Down Expand Up @@ -540,6 +557,7 @@ static int mchp_coreqspi_probe(struct platform_device *pdev)

ctlr->bits_per_word_mask = SPI_BPW_MASK(8);
ctlr->mem_ops = &mchp_coreqspi_mem_ops;
ctlr->mem_caps = &mchp_coreqspi_mem_caps;
ctlr->setup = mchp_coreqspi_setup_op;
ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD |
SPI_TX_DUAL | SPI_TX_QUAD;
Expand Down
7 changes: 6 additions & 1 deletion drivers/spi/spi-mt65xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,7 @@ static int mtk_spi_mem_exec_op(struct spi_mem *mem,

mtk_spi_reset(mdata);
mtk_spi_hw_init(mem->spi->controller, mem->spi);
mtk_spi_prepare_transfer(mem->spi->controller, mem->spi->max_speed_hz);
mtk_spi_prepare_transfer(mem->spi->controller, op->max_freq);

reg_val = readl(mdata->base + SPI_CFG3_IPM_REG);
/* opcode byte len */
Expand Down Expand Up @@ -1122,6 +1122,10 @@ static const struct spi_controller_mem_ops mtk_spi_mem_ops = {
.exec_op = mtk_spi_mem_exec_op,
};

static const struct spi_controller_mem_caps mtk_spi_mem_caps = {
.per_op_freq = true,
};

static int mtk_spi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand Down Expand Up @@ -1160,6 +1164,7 @@ static int mtk_spi_probe(struct platform_device *pdev)
if (mdata->dev_comp->ipm_design) {
mdata->dev = dev;
host->mem_ops = &mtk_spi_mem_ops;
host->mem_caps = &mtk_spi_mem_caps;
init_completion(&mdata->spimem_done);
}

Expand Down
Loading

0 comments on commit 89b37e4

Please sign in to comment.