Skip to content

Commit 0fefead

Browse files
miquelraynalbroonie
authored andcommitted
spi: spi-mem: Extend spi-mem operations with a per-operation maximum frequency
In the spi subsystem, the bus frequency is derived as follows: - the controller may expose a minimum and maximum operating frequency - the hardware description, through the spi peripheral properties, advise what is the maximum acceptable frequency from a device/wiring point of view. Transfers must be observed at a frequency which fits both (so in practice, the lowest maximum). Actually, this second point mixes two information and already takes the lowest frequency among: - what the spi device is capable of (what is written in the component datasheet) - what the wiring allows (electromagnetic sensibility, crossovers, terminations, antenna effect, etc). This logic works until spi devices are no longer capable of sustaining their highest frequency regardless of the operation. Spi memories are typically subject to such variation. Some devices are capable of spitting their internally stored data (essentially in read mode) at a very fast rate, typically up to 166MHz on Winbond SPI-NAND chips, using "fast" commands. However, some of the low-end operations, such as regular page read-from-cache commands, are more limited and can only be executed at 54MHz at most. This is currently a problem in the SPI-NAND subsystem. Another situation, even if not yet supported, will be with DTR commands, when the data is latched on both edges of the clock. The same chips as mentioned previously are in this case limited to 80MHz. Yet another example might be continuous reads, which, under certain circumstances, can also run at most at 104 or 120MHz. As a matter of fact, the "one frequency per chip" policy is outdated and more fine grain configuration is needed: we need to allow per-operation frequency limitations. So far, all datasheets I encountered advertise a maximum default frequency, which need to be lowered for certain specific operations. So based on the current infrastructure, we can still expect firmware (device trees in general) to continued advertising the same maximum speed which is a mix between the PCB limitations and the chip maximum capability, and expect per-operation lower frequencies when this is relevant. Add a `struct spi_mem_op` member to carry this information. Not providing this field explicitly from upper layers means that there is no further constraint and the default spi device maximum speed will be carried instead. The SPI_MEM_OP() macro is also expanded with an optional frequency argument, because virtually all operations can be subject to such a limitation, and this will allow for a smooth and discrete transition. For controller drivers which do not implement the spi-mem interface, the per-transfer speed is also set acordingly to a lower (than the maximum default) speed when relevant. Acked-by: Pratyush Yadav <[email protected]> Signed-off-by: Miquel Raynal <[email protected]> Link: https://patch.msgid.link/20241224-winbond-6-11-rc1-quad-support-v2-1-ad218dbc406f@bootlin.com Signed-off-by: Mark Brown <[email protected]>
1 parent 9d89551 commit 0fefead

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

drivers/mtd/nand/spi/core.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,8 @@ spinand_select_op_variant(struct spinand_device *spinand,
12141214
if (ret)
12151215
break;
12161216

1217+
spi_mem_adjust_op_freq(spinand->spimem, &op);
1218+
12171219
if (!spi_mem_supports_op(spinand->spimem, &op))
12181220
break;
12191221

drivers/spi/spi-mem.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
187187
return false;
188188
}
189189

190+
if (op->max_freq && mem->spi->controller->min_speed_hz &&
191+
op->max_freq < mem->spi->controller->min_speed_hz)
192+
return false;
193+
190194
return spi_mem_check_buswidth(mem, op);
191195
}
192196
EXPORT_SYMBOL_GPL(spi_mem_default_supports_op);
@@ -364,6 +368,9 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
364368
u8 *tmpbuf;
365369
int ret;
366370

371+
/* Make sure the operation frequency is correct before going futher */
372+
spi_mem_adjust_op_freq(mem, (struct spi_mem_op *)op);
373+
367374
ret = spi_mem_check_op(op);
368375
if (ret)
369376
return ret;
@@ -410,6 +417,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
410417
xfers[xferpos].tx_buf = tmpbuf;
411418
xfers[xferpos].len = op->cmd.nbytes;
412419
xfers[xferpos].tx_nbits = op->cmd.buswidth;
420+
xfers[xferpos].speed_hz = op->max_freq;
413421
spi_message_add_tail(&xfers[xferpos], &msg);
414422
xferpos++;
415423
totalxferlen++;
@@ -424,6 +432,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
424432
xfers[xferpos].tx_buf = tmpbuf + 1;
425433
xfers[xferpos].len = op->addr.nbytes;
426434
xfers[xferpos].tx_nbits = op->addr.buswidth;
435+
xfers[xferpos].speed_hz = op->max_freq;
427436
spi_message_add_tail(&xfers[xferpos], &msg);
428437
xferpos++;
429438
totalxferlen += op->addr.nbytes;
@@ -435,6 +444,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
435444
xfers[xferpos].len = op->dummy.nbytes;
436445
xfers[xferpos].tx_nbits = op->dummy.buswidth;
437446
xfers[xferpos].dummy_data = 1;
447+
xfers[xferpos].speed_hz = op->max_freq;
438448
spi_message_add_tail(&xfers[xferpos], &msg);
439449
xferpos++;
440450
totalxferlen += op->dummy.nbytes;
@@ -450,6 +460,7 @@ int spi_mem_exec_op(struct spi_mem *mem, const struct spi_mem_op *op)
450460
}
451461

452462
xfers[xferpos].len = op->data.nbytes;
463+
xfers[xferpos].speed_hz = op->max_freq;
453464
spi_message_add_tail(&xfers[xferpos], &msg);
454465
xferpos++;
455466
totalxferlen += op->data.nbytes;
@@ -528,6 +539,23 @@ int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
528539
}
529540
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_size);
530541

542+
/**
543+
* spi_mem_adjust_op_freq() - Adjust the frequency of a SPI mem operation to
544+
* match controller, PCB and chip limitations
545+
* @mem: the SPI memory
546+
* @op: the operation to adjust
547+
*
548+
* Some chips have per-op frequency limitations and must adapt the maximum
549+
* speed. This function allows SPI mem drivers to set @op->max_freq to the
550+
* maximum supported value.
551+
*/
552+
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op)
553+
{
554+
if (!op->max_freq || op->max_freq > mem->spi->max_speed_hz)
555+
op->max_freq = mem->spi->max_speed_hz;
556+
}
557+
EXPORT_SYMBOL_GPL(spi_mem_adjust_op_freq);
558+
531559
static ssize_t spi_mem_no_dirmap_read(struct spi_mem_dirmap_desc *desc,
532560
u64 offs, size_t len, void *buf)
533561
{

include/linux/spi/spi-mem.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ enum spi_mem_data_dir {
6868
SPI_MEM_DATA_OUT,
6969
};
7070

71+
#define SPI_MEM_OP_MAX_FREQ(__freq) \
72+
.max_freq = __freq
73+
7174
/**
7275
* struct spi_mem_op - describes a SPI memory operation
7376
* @cmd.nbytes: number of opcode bytes (only 1 or 2 are valid). The opcode is
@@ -97,6 +100,9 @@ enum spi_mem_data_dir {
97100
* operation does not involve transferring data
98101
* @data.buf.in: input buffer (must be DMA-able)
99102
* @data.buf.out: output buffer (must be DMA-able)
103+
* @max_freq: frequency limitation wrt this operation. 0 means there is no
104+
* specific constraint and the highest achievable frequency can be
105+
* attempted.
100106
*/
101107
struct spi_mem_op {
102108
struct {
@@ -135,14 +141,17 @@ struct spi_mem_op {
135141
const void *out;
136142
} buf;
137143
} data;
144+
145+
unsigned int max_freq;
138146
};
139147

140-
#define SPI_MEM_OP(__cmd, __addr, __dummy, __data) \
148+
#define SPI_MEM_OP(__cmd, __addr, __dummy, __data, ...) \
141149
{ \
142150
.cmd = __cmd, \
143151
.addr = __addr, \
144152
.dummy = __dummy, \
145153
.data = __data, \
154+
__VA_ARGS__ \
146155
}
147156

148157
/**
@@ -371,6 +380,7 @@ bool spi_mem_default_supports_op(struct spi_mem *mem,
371380
#endif /* CONFIG_SPI_MEM */
372381

373382
int spi_mem_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op);
383+
void spi_mem_adjust_op_freq(struct spi_mem *mem, struct spi_mem_op *op);
374384

375385
bool spi_mem_supports_op(struct spi_mem *mem,
376386
const struct spi_mem_op *op);

0 commit comments

Comments
 (0)