Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mtd: spinand: Add octal DTR support

Create a new bus interface named ODTR for "octal DTR", which matches the
following pattern: 8D-8D-8D.

Add octal DTR support for all the existing core operations. Add a second
set of templates for this bus interface.

Give the possibility for drivers to register their read, write and
update cache variants as well as their vendor specific operations.

Check the SPI controller driver supports all the octal DTR commands that
we might need before switching to the ODTR bus interface.

Make the switch by calling ->configure_chip() with the ODTR
parameter. Fallback in case this step fails.

If someone ever attempts to suspend a chip in octal DTR mode, there are
changes that it will loose its configuration at resume. Prevent any
problem by explicitly switching back to SSDR while suspending. Note:
there is a limitation in the current approach, page I/Os are not
available as the dirmaps will be created for the ODTR bus interface if
that option is supported and not switched back to SSDR during
suspend. Switching them is possible but would be costly and would not
bring anything as right after resuming we will switch again to ODTR. In
case this capability is used for debug, developpers should mind to
destroy and recreate suitable direct mappings.

Finally, as a side effect, we increase the buffer for reading IDs to
6. No device at this point returns 6 bytes, but we support 5 bytes IDs,
which means in octal DTR mode we have no other choice than reading an
even number of bytes, hence 6.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

+216 -3
+139 -1
drivers/mtd/nand/spi/core.c
··· 57 57 { 58 58 struct spi_mem_op op = spinand->op_templates->set_feature; 59 59 60 + if (op.cmd.dtr && op.cmd.buswidth == 8) 61 + reg |= reg << 8; 62 + 60 63 op.addr.val = reg; 61 64 op.data.buf.out = valptr; 62 65 ··· 70 67 spinand_fill_get_feature_op(struct spinand_device *spinand, u64 reg, void *valptr) 71 68 { 72 69 struct spi_mem_op op = spinand->op_templates->get_feature; 70 + 71 + if (op.cmd.dtr && op.cmd.buswidth == 8) 72 + reg |= reg << 8; 73 73 74 74 op.addr.val = reg; 75 75 op.data.buf.in = valptr; ··· 1399 1393 return spinand->manufacturer->ops->cleanup(spinand); 1400 1394 } 1401 1395 1396 + static bool spinand_op_is_odtr(const struct spi_mem_op *op) 1397 + { 1398 + return op->cmd.dtr && op->cmd.buswidth == 8; 1399 + } 1400 + 1402 1401 static void spinand_init_ssdr_templates(struct spinand_device *spinand) 1403 1402 { 1404 1403 struct spinand_mem_ops *tmpl = &spinand->ssdr_op_templates; ··· 1436 1425 for (i = 0; i < info->vendor_ops->nops; i++) { 1437 1426 const struct spi_mem_op *op = &info->vendor_ops->ops[i]; 1438 1427 1428 + if ((iface == SSDR && spinand_op_is_odtr(op)) || 1429 + (iface == ODTR && !spinand_op_is_odtr(op))) 1430 + continue; 1431 + 1439 1432 if (!spi_mem_supports_op(spinand->spimem, op)) 1440 1433 return -EOPNOTSUPP; 1441 1434 } 1435 + 1436 + return 0; 1437 + } 1438 + 1439 + static int spinand_init_odtr_instruction_set(struct spinand_device *spinand) 1440 + { 1441 + struct spinand_mem_ops *tmpl = &spinand->odtr_op_templates; 1442 + 1443 + tmpl->reset = (struct spi_mem_op)SPINAND_RESET_8D_0_0_OP; 1444 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->reset)) 1445 + return -EOPNOTSUPP; 1446 + 1447 + tmpl->readid = (struct spi_mem_op)SPINAND_READID_8D_8D_8D_OP(0, 0, NULL, 0); 1448 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->readid)) 1449 + return -EOPNOTSUPP; 1450 + 1451 + tmpl->wr_en = (struct spi_mem_op)SPINAND_WR_EN_8D_0_0_OP; 1452 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_en)) 1453 + return -EOPNOTSUPP; 1454 + 1455 + tmpl->wr_dis = (struct spi_mem_op)SPINAND_WR_DIS_8D_0_0_OP; 1456 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->wr_dis)) 1457 + return -EOPNOTSUPP; 1458 + 1459 + tmpl->set_feature = (struct spi_mem_op)SPINAND_SET_FEATURE_8D_8D_8D_OP(0, NULL); 1460 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->set_feature)) 1461 + return -EOPNOTSUPP; 1462 + 1463 + tmpl->get_feature = (struct spi_mem_op)SPINAND_GET_FEATURE_8D_8D_8D_OP(0, NULL); 1464 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->get_feature)) 1465 + return -EOPNOTSUPP; 1466 + 1467 + tmpl->blk_erase = (struct spi_mem_op)SPINAND_BLK_ERASE_8D_8D_0_OP(0); 1468 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->blk_erase)) 1469 + return -EOPNOTSUPP; 1470 + 1471 + tmpl->page_read = (struct spi_mem_op)SPINAND_PAGE_READ_8D_8D_0_OP(0); 1472 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->page_read)) 1473 + return -EOPNOTSUPP; 1474 + 1475 + tmpl->prog_exec = (struct spi_mem_op)SPINAND_PROG_EXEC_8D_8D_0_OP(0); 1476 + if (!spi_mem_supports_op(spinand->spimem, &tmpl->prog_exec)) 1477 + return -EOPNOTSUPP; 1442 1478 1443 1479 return 0; 1444 1480 } ··· 1504 1446 u64 op_duration_ns = 0; 1505 1447 unsigned int nbytes; 1506 1448 int ret; 1449 + 1450 + if ((iface == SSDR && spinand_op_is_odtr(&op)) || 1451 + (iface == ODTR && !spinand_op_is_odtr(&op))) 1452 + continue; 1507 1453 1508 1454 nbytes = nanddev_per_page_oobsize(nand) + 1509 1455 nanddev_page_size(nand); ··· 1585 1523 spinand->read_retries = table[i].read_retries; 1586 1524 spinand->set_read_retry = table[i].set_read_retry; 1587 1525 1526 + /* I/O variants selection with single-spi SDR commands */ 1527 + 1588 1528 op = spinand_select_op_variant(spinand, SSDR, 1589 1529 info->op_variants.read_cache); 1590 1530 if (!op) ··· 1611 1547 ret = spinand_support_vendor_ops(spinand, info, SSDR); 1612 1548 if (ret) 1613 1549 return ret; 1550 + 1551 + /* I/O variants selection with octo-spi DDR commands (optional) */ 1552 + 1553 + ret = spinand_init_odtr_instruction_set(spinand); 1554 + if (ret) 1555 + return 0; 1556 + 1557 + ret = spinand_support_vendor_ops(spinand, info, ODTR); 1558 + if (ret) 1559 + return 0; 1560 + 1561 + op = spinand_select_op_variant(spinand, ODTR, 1562 + info->op_variants.read_cache); 1563 + spinand->odtr_op_templates.read_cache = op; 1564 + 1565 + op = spinand_select_op_variant(spinand, ODTR, 1566 + info->op_variants.write_cache); 1567 + spinand->odtr_op_templates.write_cache = op; 1568 + 1569 + op = spinand_select_op_variant(spinand, ODTR, 1570 + info->op_variants.update_cache); 1571 + spinand->odtr_op_templates.update_cache = op; 1614 1572 1615 1573 return 0; 1616 1574 } ··· 1675 1589 1676 1590 static int spinand_configure_chip(struct spinand_device *spinand) 1677 1591 { 1678 - bool quad_enable = false; 1592 + bool odtr = false, quad_enable = false; 1679 1593 int ret; 1680 1594 1595 + if (spinand->odtr_op_templates.read_cache && 1596 + spinand->odtr_op_templates.write_cache && 1597 + spinand->odtr_op_templates.update_cache) 1598 + odtr = true; 1599 + 1600 + if (odtr) { 1601 + if (!spinand->configure_chip) 1602 + goto try_ssdr; 1603 + 1604 + /* ODTR bus interface configuration happens here */ 1605 + ret = spinand->configure_chip(spinand, ODTR); 1606 + if (ret) { 1607 + spinand->odtr_op_templates.read_cache = NULL; 1608 + spinand->odtr_op_templates.write_cache = NULL; 1609 + spinand->odtr_op_templates.update_cache = NULL; 1610 + goto try_ssdr; 1611 + } 1612 + 1613 + spinand->op_templates = &spinand->odtr_op_templates; 1614 + spinand->bus_iface = ODTR; 1615 + 1616 + return 0; 1617 + } 1618 + 1619 + try_ssdr: 1681 1620 if (spinand->flags & SPINAND_HAS_QE_BIT) { 1682 1621 if (spinand->ssdr_op_templates.read_cache->data.buswidth == 4 || 1683 1622 spinand->ssdr_op_templates.write_cache->data.buswidth == 4 || ··· 1784 1673 spinand_ecc_enable(spinand, false); 1785 1674 } 1786 1675 1676 + static int spinand_mtd_suspend(struct mtd_info *mtd) 1677 + { 1678 + struct spinand_device *spinand = mtd_to_spinand(mtd); 1679 + int ret; 1680 + 1681 + /* 1682 + * Return to SSDR interface in the suspend path to make sure the 1683 + * reset operation is correctly processed upon resume. 1684 + * 1685 + * Note: Once back in SSDR mode, every operation but the page helpers 1686 + * (dirmap based I/O accessors) will work. Page accesses would require 1687 + * destroying and recreating the dirmaps twice to work, which would be 1688 + * impacting for no reason, as this is just a transitional state. 1689 + */ 1690 + if (spinand->bus_iface == ODTR) { 1691 + ret = spinand->configure_chip(spinand, SSDR); 1692 + if (ret) 1693 + return ret; 1694 + 1695 + spinand->op_templates = &spinand->ssdr_op_templates; 1696 + spinand->bus_iface = SSDR; 1697 + } 1698 + 1699 + return 0; 1700 + } 1701 + 1787 1702 static int spinand_init(struct spinand_device *spinand) 1788 1703 { 1789 1704 struct device *dev = &spinand->spimem->spi->dev; ··· 1879 1742 mtd->_block_isreserved = spinand_mtd_block_isreserved; 1880 1743 mtd->_erase = spinand_mtd_erase; 1881 1744 mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; 1745 + mtd->_suspend = spinand_mtd_suspend; 1882 1746 mtd->_resume = spinand_mtd_resume; 1883 1747 1884 1748 if (spinand_user_otp_size(spinand) || spinand_fact_otp_size(spinand)) {
+77 -2
include/linux/mtd/spinand.h
··· 238 238 SPI_MEM_OP_NO_DUMMY, \ 239 239 SPI_MEM_OP_DATA_OUT(len, buf, 8)) 240 240 241 + /** 242 + * Octal DDR SPI NAND flash operations 243 + */ 244 + 245 + #define SPINAND_RESET_8D_0_0_OP \ 246 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xff, 8), \ 247 + SPI_MEM_OP_NO_ADDR, \ 248 + SPI_MEM_OP_NO_DUMMY, \ 249 + SPI_MEM_OP_NO_DATA) 250 + 251 + #define SPINAND_READID_8D_8D_8D_OP(naddr, ndummy, buf, len) \ 252 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9f, 8), \ 253 + SPI_MEM_DTR_OP_ADDR(naddr, 0, 8), \ 254 + SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ 255 + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8)) 256 + 257 + #define SPINAND_WR_EN_8D_0_0_OP \ 258 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x06, 8), \ 259 + SPI_MEM_OP_NO_ADDR, \ 260 + SPI_MEM_OP_NO_DUMMY, \ 261 + SPI_MEM_OP_NO_DATA) 262 + 263 + #define SPINAND_WR_DIS_8D_0_0_OP \ 264 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x04, 8), \ 265 + SPI_MEM_OP_NO_ADDR, \ 266 + SPI_MEM_OP_NO_DUMMY, \ 267 + SPI_MEM_OP_NO_DATA) 268 + 269 + #define SPINAND_SET_FEATURE_8D_8D_8D_OP(reg, valptr) \ 270 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x1f, 8), \ 271 + SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ 272 + SPI_MEM_OP_NO_DUMMY, \ 273 + SPI_MEM_DTR_OP_DATA_OUT(2, valptr, 8)) 274 + 275 + #define SPINAND_GET_FEATURE_8D_8D_8D_OP(reg, valptr) \ 276 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x0f, 8), \ 277 + SPI_MEM_DTR_OP_RPT_ADDR(reg, 8), \ 278 + SPI_MEM_DTR_OP_DUMMY(14, 8), \ 279 + SPI_MEM_DTR_OP_DATA_IN(2, valptr, 8)) 280 + 281 + #define SPINAND_BLK_ERASE_8D_8D_0_OP(addr) \ 282 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0xd8, 8), \ 283 + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ 284 + SPI_MEM_OP_NO_DUMMY, \ 285 + SPI_MEM_OP_NO_DATA) 286 + 287 + #define SPINAND_PAGE_READ_8D_8D_0_OP(addr) \ 288 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x13, 8), \ 289 + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ 290 + SPI_MEM_OP_NO_DUMMY, \ 291 + SPI_MEM_OP_NO_DATA) 292 + 293 + #define SPINAND_PAGE_READ_FROM_CACHE_8D_8D_8D_OP(addr, ndummy, buf, len, freq) \ 294 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x9d, 8), \ 295 + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ 296 + SPI_MEM_DTR_OP_DUMMY(ndummy, 8), \ 297 + SPI_MEM_DTR_OP_DATA_IN(len, buf, 8), \ 298 + SPI_MEM_OP_MAX_FREQ(freq)) 299 + 300 + #define SPINAND_PROG_EXEC_8D_8D_0_OP(addr) \ 301 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD(0x10, 8), \ 302 + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ 303 + SPI_MEM_OP_NO_DUMMY, \ 304 + SPI_MEM_OP_NO_DATA) 305 + 306 + #define SPINAND_PROG_LOAD_8D_8D_8D_OP(reset, addr, buf, len) \ 307 + SPI_MEM_OP(SPI_MEM_DTR_OP_RPT_CMD((reset ? 0xc2 : 0xc4), 8), \ 308 + SPI_MEM_DTR_OP_ADDR(2, addr, 8), \ 309 + SPI_MEM_OP_NO_DUMMY, \ 310 + SPI_MEM_DTR_OP_DATA_OUT(len, buf, 8)) 311 + 241 312 /* feature register */ 242 313 #define REG_BLOCK_LOCK 0xa0 243 314 #define BL_ALL_UNLOCKED 0x00 ··· 332 261 struct spinand_op; 333 262 struct spinand_device; 334 263 335 - #define SPINAND_MAX_ID_LEN 5 264 + #define SPINAND_MAX_ID_LEN 6 336 265 /* 337 266 * For erase, write and read operation, we got the following timings : 338 267 * tBERS (erase) 1ms to 4ms ··· 358 287 359 288 /** 360 289 * struct spinand_id - SPI NAND id structure 361 - * @data: buffer containing the id bytes. Currently 5 bytes large, but can 290 + * @data: buffer containing the id bytes. Currently 6 bytes large, but can 362 291 * be extended if required 363 292 * @len: ID length 364 293 */ ··· 556 485 /** 557 486 * enum spinand_bus_interface - SPI NAND bus interface types 558 487 * @SSDR: Bus configuration supporting all 1S-XX-XX operations, including dual and quad 488 + * @ODTR: Bus configuration supporting only 8D-8D-8D operations 559 489 */ 560 490 enum spinand_bus_interface { 561 491 SSDR, 492 + ODTR, 562 493 }; 563 494 564 495 /** ··· 725 652 * @id: NAND ID as returned by READ_ID 726 653 * @flags: NAND flags 727 654 * @ssdr_op_templates: Templates for all single SDR SPI mem operations 655 + * @odtr_op_templates: Templates for all octal DTR SPI mem operations 728 656 * @op_templates: Templates for all SPI mem operations 729 657 * @bus_iface: Current bus interface 730 658 * @select_target: select a specific target/die. Usually called before sending ··· 762 688 u32 flags; 763 689 764 690 struct spinand_mem_ops ssdr_op_templates; 691 + struct spinand_mem_ops odtr_op_templates; 765 692 struct spinand_mem_ops *op_templates; 766 693 enum spinand_bus_interface bus_iface; 767 694