spi: Add spi_mem_calc_op_duration() helper

Merge series from Miquel Raynal <miquel.raynal@bootlin.com>:

Add a spi_mem_calc_op_duration() helper
This commit is contained in:
Mark Brown 2025-01-10 17:09:28 +00:00
commit fd85b6b7bc
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 31 additions and 0 deletions

View File

@ -562,6 +562,36 @@ void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
} }
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq); EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
/**
* spi_mem_calc_op_duration() - Derives the theoretical length (in ns) of an
* operation. This helps finding the best variant
* among a list of possible choices.
* @op: the operation to benchmark
*
* Some chips have per-op frequency limitations, PCBs usually have their own
* limitations as well, and controllers can support dual, quad or even octal
* modes, sometimes in DTR. All these combinations make it impossible to
* statically list the best combination for all situations. If we want something
* accurate, all these combinations should be rated (eg. with a time estimate)
* and the best pick should be taken based on these calculations.
*
* Returns a ns estimate for the time this op would take.
*/
u64 spi_mem_calc_op_duration(struct spi_mem_op *op)
{
u64 ncycles = 0;
u32 ns_per_cycles;
ns_per_cycles = 1000000000 / op->max_freq;
ncycles += ((op->cmd.nbytes * 8) / op->cmd.buswidth) / (op->cmd.dtr ? 2 : 1);
ncycles += ((op->addr.nbytes * 8) / op->addr.buswidth) / (op->addr.dtr ? 2 : 1);
ncycles += ((op->dummy.nbytes * 8) / op->dummy.buswidth) / (op->dummy.dtr ? 2 : 1);
ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1);
return ncycles * ns_per_cycles;
}
EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc, static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
u64 offs, size_t len, void *buf) u64 offs, size_t len, void *buf)
{ {

View File

@ -424,6 +424,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op); int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op); void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op);
u64 spi_mem_calc_op_duration(struct spi_mem_op *op);
bool spi_mem_supports_op(struct spi_mem *mem, bool spi_mem_supports_op(struct spi_mem *mem,
const struct spi_mem_op *op); const struct spi_mem_op *op);