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

i3c: master: svc: Add basic HDR mode support

Add basic HDR mode support for the svs I3C master driver.

Only support for private transfers and does not support sending CCC
commands in HDR mode.

Key differences:
- HDR uses commands (0x00-0x7F for write, 0x80-0xFF for read) to
distinguish transfer direction.
- HDR read/write commands must be written to FIFO before issuing the I3C
address command. The hardware automatically sends the standard CCC command
to enter HDR mode.
- HDR exit pattern must be sent instead of send a stop after transfer
completion.
- Read/write data size must be an even number.

Co-developed-by: Carlos Song <carlos.song@nxp.com>
Signed-off-by: Carlos Song <carlos.song@nxp.com>
Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20251106-i3c_ddr-v11-4-33a6a66ed095@nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Frank Li and committed by
Alexandre Belloni
4e7263b8 108420fe

+83 -13
+83 -13
drivers/i3c/master/svc-i3c-master.c
··· 40 40 #define SVC_I3C_MCTRL_REQUEST_NONE 0 41 41 #define SVC_I3C_MCTRL_REQUEST_START_ADDR 1 42 42 #define SVC_I3C_MCTRL_REQUEST_STOP 2 43 + #define SVC_I3C_MCTRL_REQUEST_FORCE_EXIT 6 43 44 #define SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK 3 44 45 #define SVC_I3C_MCTRL_REQUEST_PROC_DAA 4 45 46 #define SVC_I3C_MCTRL_REQUEST_AUTO_IBI 7 46 47 #define SVC_I3C_MCTRL_TYPE_I3C 0 47 48 #define SVC_I3C_MCTRL_TYPE_I2C BIT(4) 49 + #define SVC_I3C_MCTRL_TYPE_DDR BIT(5) 48 50 #define SVC_I3C_MCTRL_IBIRESP_AUTO 0 49 51 #define SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE 0 50 52 #define SVC_I3C_MCTRL_IBIRESP_ACK_WITH_BYTE BIT(7) ··· 97 95 #define SVC_I3C_MINTMASKED 0x098 98 96 #define SVC_I3C_MERRWARN 0x09C 99 97 #define SVC_I3C_MERRWARN_NACK BIT(2) 98 + #define SVC_I3C_MERRWARN_CRC BIT(10) 100 99 #define SVC_I3C_MERRWARN_TIMEOUT BIT(20) 101 100 #define SVC_I3C_MDMACTRL 0x0A0 102 101 #define SVC_I3C_MDATACTRL 0x0AC ··· 177 174 const void *out; 178 175 unsigned int len; 179 176 unsigned int actual_len; 180 - struct i3c_priv_xfer *xfer; 177 + struct i3c_xfer *xfer; 181 178 bool continued; 182 179 }; 183 180 ··· 392 389 393 390 static bool svc_cmd_is_read(u32 rnw_cmd, u32 type) 394 391 { 395 - return rnw_cmd; 392 + return (type == SVC_I3C_MCTRL_TYPE_DDR) ? (rnw_cmd & 0x80) : rnw_cmd; 393 + } 394 + 395 + static void svc_i3c_master_emit_force_exit(struct svc_i3c_master *master) 396 + { 397 + u32 reg; 398 + 399 + writel(SVC_I3C_MCTRL_REQUEST_FORCE_EXIT, master->regs + SVC_I3C_MCTRL); 400 + 401 + /* 402 + * Not need check error here because it is never happen at hardware. 403 + * IP just wait for few fclk cycle to complete DDR exit pattern. Even 404 + * though fclk stop, timeout happen here, the whole data actually 405 + * already finish transfer. The next command will be timeout because 406 + * wrong hardware state. 407 + */ 408 + readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg, 409 + SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000); 410 + 411 + /* 412 + * This delay is necessary after the emission of a stop, otherwise eg. 413 + * repeating IBIs do not get detected. There is a note in the manual 414 + * about it, stating that the stop condition might not be settled 415 + * correctly if a start condition follows too rapidly. 416 + */ 417 + udelay(1); 396 418 } 397 419 398 420 static void svc_i3c_master_emit_stop(struct svc_i3c_master *master) ··· 555 527 * cycle, leading to missed client IBI handlers. 556 528 * 557 529 * A typical scenario is when IBIWON occurs and bus arbitration is lost 558 - * at svc_i3c_master_priv_xfers(). 530 + * at svc_i3c_master_i3c_xfers(). 559 531 * 560 532 * Clear SVC_I3C_MINT_IBIWON before sending SVC_I3C_MCTRL_REQUEST_AUTO_IBI. 561 533 */ ··· 834 806 goto rpm_out; 835 807 836 808 info.dyn_addr = ret; 809 + 810 + info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR); 837 811 838 812 writel(SVC_MDYNADDR_VALID | SVC_MDYNADDR_ADDR(info.dyn_addr), 839 813 master->regs + SVC_I3C_MDYNADDR); ··· 1350 1320 /* clean SVC_I3C_MINT_IBIWON w1c bits */ 1351 1321 writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS); 1352 1322 1323 + if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR) { 1324 + /* DDR command need prefill into FIFO */ 1325 + writel(rnw_cmd, master->regs + SVC_I3C_MWDATAB); 1326 + if (!rnw) { 1327 + /* write data also need prefill into FIFO */ 1328 + ret = svc_i3c_master_write(master, out, xfer_len); 1329 + if (ret) 1330 + goto emit_stop; 1331 + } 1332 + } 1353 1333 1354 1334 while (retry--) { 1355 1335 writel(SVC_I3C_MCTRL_REQUEST_START_ADDR | ··· 1453 1413 1454 1414 if (rnw) 1455 1415 ret = svc_i3c_master_read(master, in, xfer_len); 1456 - else 1416 + else if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR) 1457 1417 ret = svc_i3c_master_write(master, out, xfer_len); 1458 1418 if (ret < 0) 1459 1419 goto emit_stop; ··· 1466 1426 if (ret) 1467 1427 goto emit_stop; 1468 1428 1429 + if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR && 1430 + (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_CRC)) { 1431 + ret = -ENXIO; 1432 + goto emit_stop; 1433 + } 1434 + 1469 1435 writel(SVC_I3C_MINT_COMPLETE, master->regs + SVC_I3C_MSTATUS); 1470 1436 1471 1437 if (!continued) { 1472 - svc_i3c_master_emit_stop(master); 1438 + if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR) 1439 + svc_i3c_master_emit_stop(master); 1440 + else 1441 + svc_i3c_master_emit_force_exit(master); 1473 1442 1474 1443 /* Wait idle if stop is sent. */ 1475 1444 readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg, ··· 1488 1439 return 0; 1489 1440 1490 1441 emit_stop: 1491 - svc_i3c_master_emit_stop(master); 1442 + if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR) 1443 + svc_i3c_master_emit_stop(master); 1444 + else 1445 + svc_i3c_master_emit_force_exit(master); 1446 + 1492 1447 svc_i3c_master_clear_merrwarn(master); 1493 1448 svc_i3c_master_flush_fifo(master); 1494 1449 ··· 1537 1484 spin_lock_irqsave(&master->xferqueue.lock, flags); 1538 1485 svc_i3c_master_dequeue_xfer_locked(master, xfer); 1539 1486 spin_unlock_irqrestore(&master->xferqueue.lock, flags); 1487 + } 1488 + 1489 + static int i3c_mode_to_svc_type(enum i3c_xfer_mode mode) 1490 + { 1491 + return (mode == I3C_SDR) ? SVC_I3C_MCTRL_TYPE_I3C : SVC_I3C_MCTRL_TYPE_DDR; 1540 1492 } 1541 1493 1542 1494 static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master) ··· 1733 1675 return ret; 1734 1676 } 1735 1677 1736 - static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev, 1737 - struct i3c_priv_xfer *xfers, 1738 - int nxfers) 1678 + static int svc_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *xfers, 1679 + int nxfers, enum i3c_xfer_mode mode) 1739 1680 { 1740 1681 struct i3c_master_controller *m = i3c_dev_get_master(dev); 1741 1682 struct svc_i3c_master *master = to_svc_i3c_master(m); ··· 1742 1685 struct svc_i3c_xfer *xfer; 1743 1686 int ret, i; 1744 1687 1688 + if (mode != I3C_SDR) { 1689 + /* 1690 + * Only support data size less than FIFO SIZE when using DDR 1691 + * mode. First entry is cmd in FIFO, so actual available FIFO 1692 + * for data is SVC_I3C_FIFO_SIZE - 2 since DDR only supports 1693 + * even length. 1694 + */ 1695 + for (i = 0; i < nxfers; i++) 1696 + if (xfers[i].len > SVC_I3C_FIFO_SIZE - 2) 1697 + return -EINVAL; 1698 + } 1699 + 1745 1700 xfer = svc_i3c_master_alloc_xfer(master, nxfers); 1746 1701 if (!xfer) 1747 1702 return -ENOMEM; 1748 1703 1749 - xfer->type = SVC_I3C_MCTRL_TYPE_I3C; 1704 + xfer->type = i3c_mode_to_svc_type(mode); 1750 1705 1751 1706 for (i = 0; i < nxfers; i++) { 1707 + u32 rnw_cmd = (mode == I3C_SDR) ? xfers[i].rnw : xfers[i].cmd; 1708 + bool rnw = svc_cmd_is_read(rnw_cmd, xfer->type); 1752 1709 struct svc_i3c_cmd *cmd = &xfer->cmds[i]; 1753 - bool rnw = xfers[i].rnw; 1754 1710 1755 1711 cmd->xfer = &xfers[i]; 1756 1712 cmd->addr = master->addrs[data->index]; 1757 - cmd->rnw = rnw; 1713 + cmd->rnw_cmd = rnw_cmd; 1758 1714 cmd->in = rnw ? xfers[i].data.in : NULL; 1759 1715 cmd->out = rnw ? NULL : xfers[i].data.out; 1760 1716 cmd->len = xfers[i].len; ··· 1966 1896 .do_daa = svc_i3c_master_do_daa, 1967 1897 .supports_ccc_cmd = svc_i3c_master_supports_ccc_cmd, 1968 1898 .send_ccc_cmd = svc_i3c_master_send_ccc_cmd, 1969 - .priv_xfers = svc_i3c_master_priv_xfers, 1899 + .i3c_xfers = svc_i3c_master_i3c_xfers, 1970 1900 .i2c_xfers = svc_i3c_master_i2c_xfers, 1971 1901 .request_ibi = svc_i3c_master_request_ibi, 1972 1902 .free_ibi = svc_i3c_master_free_ibi,