Skip to content

Commit 0f698d7

Browse files
KanjiMonsterbroonie
authored andcommitted
spi: bcm63xx-hsspi: add support for 1-2-2 read ops
Add support for 1-2-2 read ops by separately calculating the switch from single-bit to multi-bit, and then switching within the prepend data. This allows us to support single-bit write followed by multi-bit write followed by multi-bit read, and we do not need to reject 1-2-2 read operations anymore. Tested on BCM963268BU_P300 with custom fixup to allow 1-2-2 on the non-SDFP capable s25fl129p1 attached (which it actually supports): root@OpenWrt:~# cat /sys/kernel/debug/spi-nor/spi1.0/params name s25fl129p1 id 01 20 18 4d 01 01 size 16.0 MiB write size 1 page size 256 address nbytes 3 flags HAS_16BIT_SR | NO_READ_CR opcodes read 0xbb dummy cycles 4 erase 0xd8 program 0x02 8D extension none protocols read 1S-2S-2S write 1S-1S-1S register 1S-1S-1S Reading from flash is still working as expected: [ 1.070000] parser_imagetag: rootfs: CFE image tag found at 0x0 with version 6, board type 963168VX [ 1.080000] parser_imagetag: Partition 0 is rootfs offset 100 and length 665000 [ 1.090000] parser_imagetag: Partition 1 is kernel offset 665100 and length 136fa1 [ 1.100000] parser_imagetag: Spare partition is offset 7b0000 and length 30000 Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com> Acked-by: William Zhang <william.zhang@broadcom.com> Tested-by: David Regan <dregan@broadcom.com> Link: https://patch.msgid.link/20251217211026.173946-1-jonas.gorski@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 458800e commit 0f698d7

1 file changed

Lines changed: 41 additions & 23 deletions

File tree

drivers/spi/spi-bcm63xx-hsspi.c

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ struct bcm63xx_hsspi {
142142
u32 wait_mode;
143143
u32 xfer_mode;
144144
u32 prepend_cnt;
145+
u32 md_start;
145146
u8 *prepend_buf;
146147
};
147148

@@ -268,18 +269,20 @@ static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
268269
{
269270

270271
struct bcm63xx_hsspi *bs = spi_controller_get_devdata(host);
271-
bool tx_only = false;
272+
bool tx_only = false, multidata = false;
272273
struct spi_transfer *t;
273274

274275
/*
275276
* Multiple transfers within a message may be combined into one transfer
276277
* to the controller using its prepend feature. A SPI message is prependable
277278
* only if the following are all true:
278-
* 1. One or more half duplex write transfer in single bit mode
279-
* 2. Optional full duplex read/write at the end
280-
* 3. No delay and cs_change between transfers
279+
* 1. One or more half duplex write transfers at the start
280+
* 2. Optional switch from single to dual bit within the write transfers
281+
* 3. Optional full duplex read/write at the end if all single bit
282+
* 4. No delay and cs_change between transfers
281283
*/
282284
bs->prepend_cnt = 0;
285+
bs->md_start = 0;
283286
list_for_each_entry(t, &msg->transfers, transfer_list) {
284287
if ((spi_delay_to_ns(&t->delay, t) > 0) || t->cs_change) {
285288
bcm63xx_prepend_printk_on_checkfail(bs,
@@ -297,39 +300,52 @@ static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
297300
return false;
298301
}
299302

300-
if (t->tx_nbits > SPI_NBITS_SINGLE &&
301-
!list_is_last(&t->transfer_list, &msg->transfers)) {
303+
if (t->tx_nbits == SPI_NBITS_SINGLE &&
304+
!list_is_last(&t->transfer_list, &msg->transfers) &&
305+
multidata) {
302306
bcm63xx_prepend_printk_on_checkfail(bs,
303-
"multi-bit prepend buf not supported!\n");
307+
"single-bit after multi-bit not supported!\n");
304308
return false;
305309
}
306310

307-
if (t->tx_nbits == SPI_NBITS_SINGLE) {
308-
memcpy(bs->prepend_buf + bs->prepend_cnt, t->tx_buf, t->len);
309-
bs->prepend_cnt += t->len;
310-
}
311+
if (t->tx_nbits > SPI_NBITS_SINGLE)
312+
multidata = true;
313+
314+
memcpy(bs->prepend_buf + bs->prepend_cnt, t->tx_buf, t->len);
315+
bs->prepend_cnt += t->len;
316+
317+
if (t->tx_nbits == SPI_NBITS_SINGLE)
318+
bs->md_start += t->len;
319+
311320
} else {
312321
if (!list_is_last(&t->transfer_list, &msg->transfers)) {
313322
bcm63xx_prepend_printk_on_checkfail(bs,
314323
"rx/tx_rx transfer not supported when it is not last one!\n");
315324
return false;
316325
}
326+
327+
if (t->rx_buf && t->rx_nbits == SPI_NBITS_SINGLE &&
328+
multidata) {
329+
bcm63xx_prepend_printk_on_checkfail(bs,
330+
"single-bit after multi-bit not supported!\n");
331+
return false;
332+
}
317333
}
318334

319335
if (list_is_last(&t->transfer_list, &msg->transfers)) {
320336
memcpy(t_prepend, t, sizeof(struct spi_transfer));
321337

322-
if (tx_only && t->tx_nbits == SPI_NBITS_SINGLE) {
338+
if (tx_only) {
323339
/*
324-
* if the last one is also a single bit tx only transfer, merge
340+
* if the last one is also a tx only transfer, merge
325341
* all of them into one single tx transfer
326342
*/
327343
t_prepend->len = bs->prepend_cnt;
328344
t_prepend->tx_buf = bs->prepend_buf;
329345
bs->prepend_cnt = 0;
330346
} else {
331347
/*
332-
* if the last one is not a tx only transfer or dual tx xfer, all
348+
* if the last one is not a tx only transfer, all
333349
* the previous transfers are sent through prepend bytes and
334350
* make sure it does not exceed the max prepend len
335351
*/
@@ -339,6 +355,15 @@ static bool bcm63xx_prepare_prepend_transfer(struct spi_controller *host,
339355
return false;
340356
}
341357
}
358+
/*
359+
* If switching from single-bit to multi-bit, make sure
360+
* the start offset does not exceed the maximum
361+
*/
362+
if (multidata && bs->md_start > HSSPI_MAX_PREPEND_LEN) {
363+
bcm63xx_prepend_printk_on_checkfail(bs,
364+
"exceed max multi-bit offset, abort prepending transfers!\n");
365+
return false;
366+
}
342367
}
343368
}
344369

@@ -381,11 +406,11 @@ static int bcm63xx_hsspi_do_prepend_txrx(struct spi_device *spi,
381406

382407
if (t->rx_nbits == SPI_NBITS_DUAL) {
383408
reg |= 1 << MODE_CTRL_MULTIDATA_RD_SIZE_SHIFT;
384-
reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT;
409+
reg |= bs->md_start << MODE_CTRL_MULTIDATA_RD_STRT_SHIFT;
385410
}
386411
if (t->tx_nbits == SPI_NBITS_DUAL) {
387412
reg |= 1 << MODE_CTRL_MULTIDATA_WR_SIZE_SHIFT;
388-
reg |= bs->prepend_cnt << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT;
413+
reg |= bs->md_start << MODE_CTRL_MULTIDATA_WR_STRT_SHIFT;
389414
}
390415
}
391416

@@ -692,13 +717,6 @@ static bool bcm63xx_hsspi_mem_supports_op(struct spi_mem *mem,
692717
if (!spi_mem_default_supports_op(mem, op))
693718
return false;
694719

695-
/* Controller doesn't support spi mem dual io mode */
696-
if ((op->cmd.opcode == SPINOR_OP_READ_1_2_2) ||
697-
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_4B) ||
698-
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR) ||
699-
(op->cmd.opcode == SPINOR_OP_READ_1_2_2_DTR_4B))
700-
return false;
701-
702720
return true;
703721
}
704722

0 commit comments

Comments
 (0)