Skip to content

Commit 4e7263b

Browse files
nxpfranklialexandrebelloni
authored andcommitted
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>
1 parent 108420f commit 4e7263b

1 file changed

Lines changed: 83 additions & 13 deletions

File tree

drivers/i3c/master/svc-i3c-master.c

Lines changed: 83 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,13 @@
4040
#define SVC_I3C_MCTRL_REQUEST_NONE 0
4141
#define SVC_I3C_MCTRL_REQUEST_START_ADDR 1
4242
#define SVC_I3C_MCTRL_REQUEST_STOP 2
43+
#define SVC_I3C_MCTRL_REQUEST_FORCE_EXIT 6
4344
#define SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK 3
4445
#define SVC_I3C_MCTRL_REQUEST_PROC_DAA 4
4546
#define SVC_I3C_MCTRL_REQUEST_AUTO_IBI 7
4647
#define SVC_I3C_MCTRL_TYPE_I3C 0
4748
#define SVC_I3C_MCTRL_TYPE_I2C BIT(4)
49+
#define SVC_I3C_MCTRL_TYPE_DDR BIT(5)
4850
#define SVC_I3C_MCTRL_IBIRESP_AUTO 0
4951
#define SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE 0
5052
#define SVC_I3C_MCTRL_IBIRESP_ACK_WITH_BYTE BIT(7)
@@ -95,6 +97,7 @@
9597
#define SVC_I3C_MINTMASKED 0x098
9698
#define SVC_I3C_MERRWARN 0x09C
9799
#define SVC_I3C_MERRWARN_NACK BIT(2)
100+
#define SVC_I3C_MERRWARN_CRC BIT(10)
98101
#define SVC_I3C_MERRWARN_TIMEOUT BIT(20)
99102
#define SVC_I3C_MDMACTRL 0x0A0
100103
#define SVC_I3C_MDATACTRL 0x0AC
@@ -174,7 +177,7 @@ struct svc_i3c_cmd {
174177
const void *out;
175178
unsigned int len;
176179
unsigned int actual_len;
177-
struct i3c_priv_xfer *xfer;
180+
struct i3c_xfer *xfer;
178181
bool continued;
179182
};
180183

@@ -389,7 +392,32 @@ svc_i3c_master_dev_from_addr(struct svc_i3c_master *master,
389392

390393
static bool svc_cmd_is_read(u32 rnw_cmd, u32 type)
391394
{
392-
return rnw_cmd;
395+
return (type == SVC_I3C_MCTRL_TYPE_DDR) ? (rnw_cmd & 0x80) : rnw_cmd;
396+
}
397+
398+
static void svc_i3c_master_emit_force_exit(struct svc_i3c_master *master)
399+
{
400+
u32 reg;
401+
402+
writel(SVC_I3C_MCTRL_REQUEST_FORCE_EXIT, master->regs + SVC_I3C_MCTRL);
403+
404+
/*
405+
* Not need check error here because it is never happen at hardware.
406+
* IP just wait for few fclk cycle to complete DDR exit pattern. Even
407+
* though fclk stop, timeout happen here, the whole data actually
408+
* already finish transfer. The next command will be timeout because
409+
* wrong hardware state.
410+
*/
411+
readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg,
412+
SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000);
413+
414+
/*
415+
* This delay is necessary after the emission of a stop, otherwise eg.
416+
* repeating IBIs do not get detected. There is a note in the manual
417+
* about it, stating that the stop condition might not be settled
418+
* correctly if a start condition follows too rapidly.
419+
*/
420+
udelay(1);
393421
}
394422

395423
static void svc_i3c_master_emit_stop(struct svc_i3c_master *master)
@@ -527,7 +555,7 @@ static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master)
527555
* cycle, leading to missed client IBI handlers.
528556
*
529557
* A typical scenario is when IBIWON occurs and bus arbitration is lost
530-
* at svc_i3c_master_priv_xfers().
558+
* at svc_i3c_master_i3c_xfers().
531559
*
532560
* Clear SVC_I3C_MINT_IBIWON before sending SVC_I3C_MCTRL_REQUEST_AUTO_IBI.
533561
*/
@@ -807,6 +835,8 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
807835

808836
info.dyn_addr = ret;
809837

838+
info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
839+
810840
writel(SVC_MDYNADDR_VALID | SVC_MDYNADDR_ADDR(info.dyn_addr),
811841
master->regs + SVC_I3C_MDYNADDR);
812842

@@ -1320,6 +1350,16 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
13201350
/* clean SVC_I3C_MINT_IBIWON w1c bits */
13211351
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
13221352

1353+
if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR) {
1354+
/* DDR command need prefill into FIFO */
1355+
writel(rnw_cmd, master->regs + SVC_I3C_MWDATAB);
1356+
if (!rnw) {
1357+
/* write data also need prefill into FIFO */
1358+
ret = svc_i3c_master_write(master, out, xfer_len);
1359+
if (ret)
1360+
goto emit_stop;
1361+
}
1362+
}
13231363

13241364
while (retry--) {
13251365
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
@@ -1413,7 +1453,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
14131453

14141454
if (rnw)
14151455
ret = svc_i3c_master_read(master, in, xfer_len);
1416-
else
1456+
else if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
14171457
ret = svc_i3c_master_write(master, out, xfer_len);
14181458
if (ret < 0)
14191459
goto emit_stop;
@@ -1426,10 +1466,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
14261466
if (ret)
14271467
goto emit_stop;
14281468

1469+
if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR &&
1470+
(readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_CRC)) {
1471+
ret = -ENXIO;
1472+
goto emit_stop;
1473+
}
1474+
14291475
writel(SVC_I3C_MINT_COMPLETE, master->regs + SVC_I3C_MSTATUS);
14301476

14311477
if (!continued) {
1432-
svc_i3c_master_emit_stop(master);
1478+
if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
1479+
svc_i3c_master_emit_stop(master);
1480+
else
1481+
svc_i3c_master_emit_force_exit(master);
14331482

14341483
/* Wait idle if stop is sent. */
14351484
readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -1439,7 +1488,11 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
14391488
return 0;
14401489

14411490
emit_stop:
1442-
svc_i3c_master_emit_stop(master);
1491+
if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
1492+
svc_i3c_master_emit_stop(master);
1493+
else
1494+
svc_i3c_master_emit_force_exit(master);
1495+
14431496
svc_i3c_master_clear_merrwarn(master);
14441497
svc_i3c_master_flush_fifo(master);
14451498

@@ -1486,6 +1539,11 @@ static void svc_i3c_master_dequeue_xfer(struct svc_i3c_master *master,
14861539
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
14871540
}
14881541

1542+
static int i3c_mode_to_svc_type(enum i3c_xfer_mode mode)
1543+
{
1544+
return (mode == I3C_SDR) ? SVC_I3C_MCTRL_TYPE_I3C : SVC_I3C_MCTRL_TYPE_DDR;
1545+
}
1546+
14891547
static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
14901548
{
14911549
struct svc_i3c_xfer *xfer = master->xferqueue.cur;
@@ -1675,29 +1733,41 @@ static int svc_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
16751733
return ret;
16761734
}
16771735

1678-
static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
1679-
struct i3c_priv_xfer *xfers,
1680-
int nxfers)
1736+
static int svc_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
1737+
int nxfers, enum i3c_xfer_mode mode)
16811738
{
16821739
struct i3c_master_controller *m = i3c_dev_get_master(dev);
16831740
struct svc_i3c_master *master = to_svc_i3c_master(m);
16841741
struct svc_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
16851742
struct svc_i3c_xfer *xfer;
16861743
int ret, i;
16871744

1745+
if (mode != I3C_SDR) {
1746+
/*
1747+
* Only support data size less than FIFO SIZE when using DDR
1748+
* mode. First entry is cmd in FIFO, so actual available FIFO
1749+
* for data is SVC_I3C_FIFO_SIZE - 2 since DDR only supports
1750+
* even length.
1751+
*/
1752+
for (i = 0; i < nxfers; i++)
1753+
if (xfers[i].len > SVC_I3C_FIFO_SIZE - 2)
1754+
return -EINVAL;
1755+
}
1756+
16881757
xfer = svc_i3c_master_alloc_xfer(master, nxfers);
16891758
if (!xfer)
16901759
return -ENOMEM;
16911760

1692-
xfer->type = SVC_I3C_MCTRL_TYPE_I3C;
1761+
xfer->type = i3c_mode_to_svc_type(mode);
16931762

16941763
for (i = 0; i < nxfers; i++) {
1764+
u32 rnw_cmd = (mode == I3C_SDR) ? xfers[i].rnw : xfers[i].cmd;
1765+
bool rnw = svc_cmd_is_read(rnw_cmd, xfer->type);
16951766
struct svc_i3c_cmd *cmd = &xfer->cmds[i];
1696-
bool rnw = xfers[i].rnw;
16971767

16981768
cmd->xfer = &xfers[i];
16991769
cmd->addr = master->addrs[data->index];
1700-
cmd->rnw = rnw;
1770+
cmd->rnw_cmd = rnw_cmd;
17011771
cmd->in = rnw ? xfers[i].data.in : NULL;
17021772
cmd->out = rnw ? NULL : xfers[i].data.out;
17031773
cmd->len = xfers[i].len;
@@ -1896,7 +1966,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
18961966
.do_daa = svc_i3c_master_do_daa,
18971967
.supports_ccc_cmd = svc_i3c_master_supports_ccc_cmd,
18981968
.send_ccc_cmd = svc_i3c_master_send_ccc_cmd,
1899-
.priv_xfers = svc_i3c_master_priv_xfers,
1969+
.i3c_xfers = svc_i3c_master_i3c_xfers,
19001970
.i2c_xfers = svc_i3c_master_i2c_xfers,
19011971
.request_ibi = svc_i3c_master_request_ibi,
19021972
.free_ibi = svc_i3c_master_free_ibi,

0 commit comments

Comments
 (0)