Skip to content

Commit 4286e1f

Browse files
committed
Merge tag 'i3c/for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux
Pull i3c updates from Alexandre Belloni: "Runtime PM (power management) is improved and hot-join support has been added to the dw controller driver. Core: - Allow device driver to trigger controller runtime PM Drivers: - dw: hot-join support - svc: better IBI handling" * tag 'i3c/for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux: i3c: dw: Add hot-join support. i3c: master: Enable runtime PM for master controller i3c: master: svc: fix invalidate IBI type and miss call client IBI handler i3c: master: svc: change ENXIO to EAGAIN when IBI occurs during start frame i3c: Add comment for -EAGAIN in i3c_device_do_priv_xfers()
2 parents 6951abe + 1d08326 commit 4286e1f

File tree

5 files changed

+80
-17
lines changed

5 files changed

+80
-17
lines changed

drivers/i3c/device.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
* This function can sleep and thus cannot be called in atomic context.
2828
*
2929
* Return: 0 in case of success, a negative error core otherwise.
30+
* -EAGAIN: controller lost address arbitration. Target
31+
* (IBI, HJ or controller role request) win the bus. Client
32+
* driver needs to resend the 'xfers' some time later.
33+
* See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3.
3034
*/
3135
int i3c_device_do_priv_xfers(struct i3c_device *dev,
3236
struct i3c_priv_xfer *xfers,

drivers/i3c/master.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/kernel.h>
1414
#include <linux/list.h>
1515
#include <linux/of.h>
16+
#include <linux/pm_runtime.h>
1617
#include <linux/slab.h>
1718
#include <linux/spinlock.h>
1819
#include <linux/workqueue.h>
@@ -2812,6 +2813,10 @@ int i3c_master_register(struct i3c_master_controller *master,
28122813

28132814
i3c_bus_notify(i3cbus, I3C_NOTIFY_BUS_ADD);
28142815

2816+
pm_runtime_no_callbacks(&master->dev);
2817+
pm_suspend_ignore_children(&master->dev, true);
2818+
pm_runtime_enable(&master->dev);
2819+
28152820
/*
28162821
* We're done initializing the bus and the controller, we can now
28172822
* register I3C devices discovered during the initial DAA.
@@ -2849,6 +2854,7 @@ void i3c_master_unregister(struct i3c_master_controller *master)
28492854
i3c_master_i2c_adapter_cleanup(master);
28502855
i3c_master_unregister_i3c_devs(master);
28512856
i3c_master_bus_cleanup(master);
2857+
pm_runtime_disable(&master->dev);
28522858
device_unregister(&master->dev);
28532859
}
28542860
EXPORT_SYMBOL_GPL(i3c_master_unregister);

drivers/i3c/master/dw-i3c-master.c

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,23 @@ static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev)
11361136
data->ibi_pool = NULL;
11371137
}
11381138

1139+
static void dw_i3c_master_enable_sir_signal(struct dw_i3c_master *master, bool enable)
1140+
{
1141+
u32 reg;
1142+
1143+
reg = readl(master->regs + INTR_STATUS_EN);
1144+
reg &= ~INTR_IBI_THLD_STAT;
1145+
if (enable)
1146+
reg |= INTR_IBI_THLD_STAT;
1147+
writel(reg, master->regs + INTR_STATUS_EN);
1148+
1149+
reg = readl(master->regs + INTR_SIGNAL_EN);
1150+
reg &= ~INTR_IBI_THLD_STAT;
1151+
if (enable)
1152+
reg |= INTR_IBI_THLD_STAT;
1153+
writel(reg, master->regs + INTR_SIGNAL_EN);
1154+
}
1155+
11391156
static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
11401157
struct i3c_dev_desc *dev,
11411158
u8 idx, bool enable)
@@ -1170,23 +1187,34 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
11701187
}
11711188
writel(reg, master->regs + IBI_SIR_REQ_REJECT);
11721189

1173-
if (global) {
1174-
reg = readl(master->regs + INTR_STATUS_EN);
1175-
reg &= ~INTR_IBI_THLD_STAT;
1176-
if (enable)
1177-
reg |= INTR_IBI_THLD_STAT;
1178-
writel(reg, master->regs + INTR_STATUS_EN);
1179-
1180-
reg = readl(master->regs + INTR_SIGNAL_EN);
1181-
reg &= ~INTR_IBI_THLD_STAT;
1182-
if (enable)
1183-
reg |= INTR_IBI_THLD_STAT;
1184-
writel(reg, master->regs + INTR_SIGNAL_EN);
1185-
}
1190+
if (global)
1191+
dw_i3c_master_enable_sir_signal(master, enable);
1192+
11861193

11871194
spin_unlock_irqrestore(&master->devs_lock, flags);
11881195
}
11891196

1197+
static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
1198+
{
1199+
struct dw_i3c_master *master = to_dw_i3c_master(m);
1200+
1201+
dw_i3c_master_enable_sir_signal(master, true);
1202+
writel(readl(master->regs + DEVICE_CTRL) & ~DEV_CTRL_HOT_JOIN_NACK,
1203+
master->regs + DEVICE_CTRL);
1204+
1205+
return 0;
1206+
}
1207+
1208+
static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
1209+
{
1210+
struct dw_i3c_master *master = to_dw_i3c_master(m);
1211+
1212+
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
1213+
master->regs + DEVICE_CTRL);
1214+
1215+
return 0;
1216+
}
1217+
11901218
static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
11911219
{
11921220
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
@@ -1326,6 +1354,8 @@ static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master)
13261354

13271355
if (IBI_TYPE_SIRQ(reg)) {
13281356
dw_i3c_master_handle_ibi_sir(master, reg);
1357+
} else if (IBI_TYPE_HJ(reg)) {
1358+
queue_work(master->base.wq, &master->hj_work);
13291359
} else {
13301360
len = IBI_QUEUE_STATUS_DATA_LEN(reg);
13311361
dev_info(&master->base.dev,
@@ -1393,6 +1423,8 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ibi_ops = {
13931423
.enable_ibi = dw_i3c_master_enable_ibi,
13941424
.disable_ibi = dw_i3c_master_disable_ibi,
13951425
.recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot,
1426+
.enable_hotjoin = dw_i3c_master_enable_hotjoin,
1427+
.disable_hotjoin = dw_i3c_master_disable_hotjoin,
13961428
};
13971429

13981430
/* default platform ops implementations */
@@ -1412,6 +1444,14 @@ static const struct dw_i3c_platform_ops dw_i3c_platform_ops_default = {
14121444
.set_dat_ibi = dw_i3c_platform_set_dat_ibi_nop,
14131445
};
14141446

1447+
static void dw_i3c_hj_work(struct work_struct *work)
1448+
{
1449+
struct dw_i3c_master *master =
1450+
container_of(work, typeof(*master), hj_work);
1451+
1452+
i3c_master_do_daa(&master->base);
1453+
}
1454+
14151455
int dw_i3c_common_probe(struct dw_i3c_master *master,
14161456
struct platform_device *pdev)
14171457
{
@@ -1469,6 +1509,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
14691509
if (master->ibi_capable)
14701510
ops = &dw_mipi_i3c_ibi_ops;
14711511

1512+
INIT_WORK(&master->hj_work, dw_i3c_hj_work);
14721513
ret = i3c_master_register(&master->base, &pdev->dev, ops, false);
14731514
if (ret)
14741515
goto err_assert_rst;

drivers/i3c/master/dw-i3c-master.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ struct dw_i3c_master {
5757

5858
/* platform-specific data */
5959
const struct dw_i3c_platform_ops *platform_ops;
60+
61+
struct work_struct hj_work;
6062
};
6163

6264
struct dw_i3c_platform_ops {

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,19 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
415415
int ret;
416416

417417
mutex_lock(&master->lock);
418+
/*
419+
* IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing
420+
* readl_relaxed_poll_timeout() to return immediately. Consequently,
421+
* ibitype will be 0 since it was last updated only after the 8th SCL
422+
* cycle, leading to missed client IBI handlers.
423+
*
424+
* A typical scenario is when IBIWON occurs and bus arbitration is lost
425+
* at svc_i3c_master_priv_xfers().
426+
*
427+
* Clear SVC_I3C_MINT_IBIWON before sending SVC_I3C_MCTRL_REQUEST_AUTO_IBI.
428+
*/
429+
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
430+
418431
/* Acknowledge the incoming interrupt with the AUTOIBI mechanism */
419432
writel(SVC_I3C_MCTRL_REQUEST_AUTO_IBI |
420433
SVC_I3C_MCTRL_IBIRESP_AUTO,
@@ -429,9 +442,6 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
429442
goto reenable_ibis;
430443
}
431444

432-
/* Clear the interrupt status */
433-
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
434-
435445
status = readl(master->regs + SVC_I3C_MSTATUS);
436446
ibitype = SVC_I3C_MSTATUS_IBITYPE(status);
437447
ibiaddr = SVC_I3C_MSTATUS_IBIADDR(status);
@@ -1080,7 +1090,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
10801090
* and yield the above events handler.
10811091
*/
10821092
if (SVC_I3C_MSTATUS_IBIWON(reg)) {
1083-
ret = -ENXIO;
1093+
ret = -EAGAIN;
10841094
*actual_len = 0;
10851095
goto emit_stop;
10861096
}

0 commit comments

Comments
 (0)