Skip to content

Commit 9bc7501

Browse files
nxpfranklialexandrebelloni
authored andcommitted
i3c: master: svc: resend target address when get NACK
According to I3C Spec 1.1.1, 11-Jun-2021, section: 5.1.2.2.3: If the Controller chooses to start an I3C Message with an I3C Dynamic Address, then special provisions shall be made because that same I3C Target may be initiating an IBI or a Controller Role Request. So, one of three things may happen: (skip 1, 2) 3. The Addresses match and the RnW bits also match, and so neither Controller nor Target will ACK since both are expecting the other side to provide ACK. As a result, each side might think it had "won" arbitration, but neither side would continue, as each would subsequently see that the other did not provide ACK. ... For either value of RnW: Due to the NACK, the Controller shall defer the Private Write or Private Read, and should typically transmit the Target ^^^^^^^^^^^^^^^^^^^ Address again after a Repeated START (i.e., the next one or any one prior ^^^^^^^^^^^^^ to a STOP in the Frame). Since the Address Header following a Repeated START is not arbitrated, the Controller will always win (see Section 5.1.2.2.4). Resend target address again if address is not 7E and controller get NACK. Reviewed-by: Miquel Raynal <[email protected]> Signed-off-by: Frank Li <[email protected]> Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 1613e60 commit 9bc7501

File tree

1 file changed

+44
-14
lines changed

1 file changed

+44
-14
lines changed

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

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1052,29 +1052,59 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
10521052
u8 *in, const u8 *out, unsigned int xfer_len,
10531053
unsigned int *actual_len, bool continued)
10541054
{
1055+
int retry = 2;
10551056
u32 reg;
10561057
int ret;
10571058

10581059
/* clean SVC_I3C_MINT_IBIWON w1c bits */
10591060
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
10601061

1061-
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
1062-
xfer_type |
1063-
SVC_I3C_MCTRL_IBIRESP_NACK |
1064-
SVC_I3C_MCTRL_DIR(rnw) |
1065-
SVC_I3C_MCTRL_ADDR(addr) |
1066-
SVC_I3C_MCTRL_RDTERM(*actual_len),
1067-
master->regs + SVC_I3C_MCTRL);
10681062

1069-
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
1063+
while (retry--) {
1064+
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
1065+
xfer_type |
1066+
SVC_I3C_MCTRL_IBIRESP_NACK |
1067+
SVC_I3C_MCTRL_DIR(rnw) |
1068+
SVC_I3C_MCTRL_ADDR(addr) |
1069+
SVC_I3C_MCTRL_RDTERM(*actual_len),
1070+
master->regs + SVC_I3C_MCTRL);
1071+
1072+
ret = readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
10701073
SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000);
1071-
if (ret)
1072-
goto emit_stop;
1074+
if (ret)
1075+
goto emit_stop;
10731076

1074-
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
1075-
ret = -ENXIO;
1076-
*actual_len = 0;
1077-
goto emit_stop;
1077+
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
1078+
/*
1079+
* According to I3C Spec 1.1.1, 11-Jun-2021, section: 5.1.2.2.3.
1080+
* If the Controller chooses to start an I3C Message with an I3C Dynamic
1081+
* Address, then special provisions shall be made because that same I3C
1082+
* Target may be initiating an IBI or a Controller Role Request. So, one of
1083+
* three things may happen: (skip 1, 2)
1084+
*
1085+
* 3. The Addresses match and the RnW bits also match, and so neither
1086+
* Controller nor Target will ACK since both are expecting the other side to
1087+
* provide ACK. As a result, each side might think it had "won" arbitration,
1088+
* but neither side would continue, as each would subsequently see that the
1089+
* other did not provide ACK.
1090+
* ...
1091+
* For either value of RnW: Due to the NACK, the Controller shall defer the
1092+
* Private Write or Private Read, and should typically transmit the Target
1093+
* Address again after a Repeated START (i.e., the next one or any one prior
1094+
* to a STOP in the Frame). Since the Address Header following a Repeated
1095+
* START is not arbitrated, the Controller will always win (see Section
1096+
* 5.1.2.2.4).
1097+
*/
1098+
if (retry && addr != 0x7e) {
1099+
writel(SVC_I3C_MERRWARN_NACK, master->regs + SVC_I3C_MERRWARN);
1100+
} else {
1101+
ret = -ENXIO;
1102+
*actual_len = 0;
1103+
goto emit_stop;
1104+
}
1105+
} else {
1106+
break;
1107+
}
10781108
}
10791109

10801110
/*

0 commit comments

Comments
 (0)