mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
i3c: master: svc: Use manual response for IBI events
[ Upstream commit a7869b0a2540fd122eccec00ae7d4243166b0a60 ]
Driver wants to nack the IBI request when the target is not in the
known address list. In below code, svc_i3c_master_nack_ibi() will
cause undefined behavior when using AUTOIBI with auto response rule,
because hw always auto ack the IBI request.
switch (ibitype) {
case SVC_I3C_MSTATUS_IBITYPE_IBI:
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
svc_i3c_master_nack_ibi(master);
...
break;
AutoIBI has another issue that the controller doesn't quit AutoIBI state
after IBIWON polling timeout when there is a SDA glitch(high->low->high).
1. SDA high->low: raising an interrupt to execute IBI ISR
2. SDA low->high
3. Driver writes an AutoIBI request
4. AutoIBI process does not start because SDA is not low
5. IBIWON polling times out
6. Controller reamins in AutoIBI state and doesn't accept EmitStop request
Emitting broadcast address with IBIRESP_MANUAL avoids both issues.
Fixes: dd3c52846d
("i3c: master: svc: Add Silvaco I3C master driver")
Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://lore.kernel.org/r/20250829012309.3562585-2-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
060ecc8124
commit
20ff7004c9
|
@ -430,9 +430,24 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
|||
*/
|
||||
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
|
||||
|
||||
/* Acknowledge the incoming interrupt with the AUTOIBI mechanism */
|
||||
writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI |
|
||||
SVC_I3C_MCTRL_IBIRESP_AUTO,
|
||||
/*
|
||||
* Write REQUEST_START_ADDR request to emit broadcast address for arbitration,
|
||||
* instend of using AUTO_IBI.
|
||||
*
|
||||
* Using AutoIBI request may cause controller to remain in AutoIBI state when
|
||||
* there is a glitch on SDA line (high->low->high).
|
||||
* 1. SDA high->low, raising an interrupt to execute IBI isr.
|
||||
* 2. SDA low->high.
|
||||
* 3. IBI isr writes an AutoIBI request.
|
||||
* 4. The controller will not start AutoIBI process because SDA is not low.
|
||||
* 5. IBIWON polling times out.
|
||||
* 6. Controller reamins in AutoIBI state and doesn't accept EmitStop request.
|
||||
*/
|
||||
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
|
||||
SVC_I3C_MCTRL_TYPE_I3C |
|
||||
SVC_I3C_MCTRL_IBIRESP_MANUAL |
|
||||
SVC_I3C_MCTRL_DIR(SVC_I3C_MCTRL_DIR_WRITE) |
|
||||
SVC_I3C_MCTRL_ADDR(I3C_BROADCAST_ADDR),
|
||||
master->regs + SVC_I3C_MCTRL);
|
||||
|
||||
/* Wait for IBIWON, should take approximately 100us */
|
||||
|
@ -452,10 +467,15 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
|
|||
switch (ibitype) {
|
||||
case SVC_I3C_MSTATUS_IBITYPE_IBI:
|
||||
dev = svc_i3c_master_dev_from_addr(master, ibiaddr);
|
||||
if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI))
|
||||
if (!dev || !is_events_enabled(master, SVC_I3C_EVENT_IBI)) {
|
||||
svc_i3c_master_nack_ibi(master);
|
||||
else
|
||||
} else {
|
||||
if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD)
|
||||
svc_i3c_master_ack_ibi(master, true);
|
||||
else
|
||||
svc_i3c_master_ack_ibi(master, false);
|
||||
svc_i3c_master_handle_ibi(master, dev);
|
||||
}
|
||||
break;
|
||||
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
|
||||
if (is_events_enabled(master, SVC_I3C_EVENT_HOTJOIN))
|
||||
|
|
Loading…
Reference in New Issue
Block a user