From: Miquel Raynal Date: Wed, 18 Jun 2025 12:14:18 +0000 (+0200) Subject: spi: spi-mem: Use picoseconds for calculating the op durations X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=62df72a0ab22b3377aeba3b2159ab35274a4106f;p=thirdparty%2Flinux.git spi: spi-mem: Use picoseconds for calculating the op durations spi_mem_calc_op_duration() is deriving the duration of a specific op, by multiplying the number of cycles with the time a cycle will last. This time was measured in nanoseconds, which means at high frequencies the delta between two frequencies might not be properly catch due to roundings. For instance, the Winbond driver has a changing number of dummy cycles depending on the speed, adding +8 dummy cycles when running at 166MHz compared to 162MHz. Both frequencies would lead to using a 6ns delay per cycle for the op duration computation, whereas in practice there is a small difference which actually offsets the number of extra dummy cycles on a normal page read. Augmenting the precision of the calculation by using picoseconds prevents selecting a lower frequency if we can do slightly better with another frequency involving more cycles. As a result, the above situation leads to comparing cycles of 6024 and 6172 picoseconds which leads to picking the most efficient variant. Reviewed-by: Mark Brown Signed-off-by: Miquel Raynal --- diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c index 5db0639d3b015..c42c227eb2a29 100644 --- a/drivers/spi/spi-mem.c +++ b/drivers/spi/spi-mem.c @@ -591,9 +591,11 @@ EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq); u64 spi_mem_calc_op_duration(struct spi_mem_op *op) { u64 ncycles = 0; - u32 ns_per_cycles; + u64 ps_per_cycles, duration; + + ps_per_cycles = 1000000000000ULL; + do_div(ps_per_cycles, op->max_freq); - 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); @@ -603,7 +605,12 @@ u64 spi_mem_calc_op_duration(struct spi_mem_op *op) ncycles += ((op->data.nbytes * 8) / op->data.buswidth) / (op->data.dtr ? 2 : 1); - return ncycles * ns_per_cycles; + /* Derive the duration in ps */ + duration = ncycles * ps_per_cycles; + /* Convert into ns */ + do_div(duration, 1000); + + return duration; } EXPORT_SYMBOL_GPL(spi_mem_calc_op_duration);