I3C for 6.13

Core:
  - avoid possible deadlock on probe
  - ensured preferred address is used on hot-join
 
 Drivers:
  - dw: add AMD I3C controller support
  - mipi-i3c-hci: fix SETDASA, DMA interrupts fixes
  - svc: many fixes for IBI and hotjoin
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmdE9XkACgkQY6TcMGxw
 OjJemA//RXLJuJgTsOSnOIEOg/DrHMg1tY7QiuqWagp68i6IuV+a0m0Os0k3Ak0h
 EiZ5U8NkXAtAsf1dmA8CjZ5BnFswIJAm7rJI20vvFmaoNAQmqx1DQ5J2aSHm+pFK
 LZYyM/p3dbNsdDu4MNSiFHwoFi/ZubTQWaqhpdxE6cCKVhRvSUznL51M4dpXEbcE
 wgbAl+ivhqpiHbqBvfu2KDiZOi+Bb9Dn1voy4PZivuDI+C3SM3mB8K088GigFlkn
 Q1zMF4I7UdfAffF1Aj1e5YRn+hJcBEu1+UCf+Jj2W7Y2I9r8KQyBzxH0Xt9MVsua
 WoHT5np/Zc0pw4UykwMmg+qroOM6cXHgPnAq8EYmkY6Ab6XWEPLPY/VIPIn+tq7Y
 RQs90RKJUKQT8kV07taQ2KUgBSPsl/8iING12xNjfDQjjOY4ebhE3Ou9EIOec1dG
 rF3+5G8dTSyJfV+5PcgeGFGSIMAqKNRrRUNEfANE2uIh9VS7wcKUemto96uPOySR
 Ct5GhE21Xrdm+ZievHOTjLvlaSbDv5RU5qFezf15sD8ypF2RrEVE2mZj9bdynBth
 Qp6I5NDfjF0fW1dRGB44ZAWS82KWia+1D67I3Sy0R/VG5wax1OtQktmC6fA1iqKX
 wZD/d+zh5zs10wyTjmvEoN2UCoLlzXN/VvA+HQllOcDara9V9Jw=
 =B7J8
 -----END PGP SIGNATURE-----

Merge tag 'i3c/for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux

Pull i3c updates from Alexandre Belloni:
 "Core:
   - avoid possible deadlock on probe
   - ensured preferred address is used on hot-join

  Drivers:
   - dw: add AMD I3C controller support
   - mipi-i3c-hci: fix SETDASA, DMA interrupts fixes
   - svc: many fixes for IBI and hotjoin"

* tag 'i3c/for-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/i3c/linux:
  i3c: Use i3cdev->desc->info instead of calling i3c_device_get_info() to avoid deadlock
  i3c: mipi-i3c-hci: Support SETDASA CCC
  i3c: dw: Add quirk to address OD/PP timing issue on AMD platform
  i3c: dw: Add support for AMDI0015 ACPI ID
  i3c: master: svc: Modify enabled_events bit 7:0 to act as IBI enable counter
  i3c: Document I3C_ADDR_SLOT_EXT_STATUS_MASK
  i3c: master: svc: Fix pm_runtime_set_suspended() with runtime pm enabled
  i3c: mipi-i3c-hci: Handle interrupts according to current specifications
  i3c: mipi-i3c-hci: Mask ring interrupts before ring stop request
  i3c: master: Fix miss free init_dyn_addr at i3c_master_put_i3c_addrs()
  i3c: master: Remove i3c_dev_disable_ibi_locked(olddev) on device hotjoin
  i3c: master: svc: fix possible assignment of the same address to two devices
  i3c: master: svc: wait for Manual ACK/NACK Done before next step
  i3c: master: svc: use spin_lock_irqsave at svc_i3c_master_ibi_work()
  i3c: master: svc: need check IBIWON for dynamic address assignment
  i3c: master: svc: manually emit NACK/ACK for hotjoin
  i3c: master: svc: use repeat start when IBI WIN happens
  i3c: master: Fix dynamic address leak when 'assigned-address' is present
  i3c: master: Extend address status bit to 4 and add I3C_ADDR_SLOT_EXT_DESIRED
  i3c: master: Replace hard code 2 with macro I3C_ADDR_SLOT_STATUS_BITS
This commit is contained in:
Linus Torvalds 2024-11-26 18:23:31 -08:00
commit 750909d55a
9 changed files with 225 additions and 89 deletions

View File

@ -282,7 +282,8 @@ static int i3c_device_uevent(const struct device *dev, struct kobj_uevent_env *e
struct i3c_device_info devinfo;
u16 manuf, part, ext;
i3c_device_get_info(i3cdev, &devinfo);
if (i3cdev->desc)
devinfo = i3cdev->desc->info;
manuf = I3C_PID_MANUF_ID(devinfo.pid);
part = I3C_PID_PART_ID(devinfo.pid);
ext = I3C_PID_EXTRA_INFO(devinfo.pid);
@ -345,10 +346,10 @@ const struct bus_type i3c_bus_type = {
EXPORT_SYMBOL_GPL(i3c_bus_type);
static enum i3c_addr_slot_status
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
i3c_bus_get_addr_slot_status_mask(struct i3c_bus *bus, u16 addr, u32 mask)
{
unsigned long status;
int bitpos = addr * 2;
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
if (addr > I2C_MAX_ADDR)
return I3C_ADDR_SLOT_RSVD;
@ -356,22 +357,33 @@ i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
status = bus->addrslots[bitpos / BITS_PER_LONG];
status >>= bitpos % BITS_PER_LONG;
return status & I3C_ADDR_SLOT_STATUS_MASK;
return status & mask;
}
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
enum i3c_addr_slot_status status)
static enum i3c_addr_slot_status
i3c_bus_get_addr_slot_status(struct i3c_bus *bus, u16 addr)
{
int bitpos = addr * 2;
return i3c_bus_get_addr_slot_status_mask(bus, addr, I3C_ADDR_SLOT_STATUS_MASK);
}
static void i3c_bus_set_addr_slot_status_mask(struct i3c_bus *bus, u16 addr,
enum i3c_addr_slot_status status, u32 mask)
{
int bitpos = addr * I3C_ADDR_SLOT_STATUS_BITS;
unsigned long *ptr;
if (addr > I2C_MAX_ADDR)
return;
ptr = bus->addrslots + (bitpos / BITS_PER_LONG);
*ptr &= ~((unsigned long)I3C_ADDR_SLOT_STATUS_MASK <<
(bitpos % BITS_PER_LONG));
*ptr |= (unsigned long)status << (bitpos % BITS_PER_LONG);
*ptr &= ~((unsigned long)mask << (bitpos % BITS_PER_LONG));
*ptr |= ((unsigned long)status & mask) << (bitpos % BITS_PER_LONG);
}
static void i3c_bus_set_addr_slot_status(struct i3c_bus *bus, u16 addr,
enum i3c_addr_slot_status status)
{
i3c_bus_set_addr_slot_status_mask(bus, addr, status, I3C_ADDR_SLOT_STATUS_MASK);
}
static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
@ -383,13 +395,44 @@ static bool i3c_bus_dev_addr_is_avail(struct i3c_bus *bus, u8 addr)
return status == I3C_ADDR_SLOT_FREE;
}
/*
*
* S/Sr 7'h7E RnW=0 ACK ENTDAA T
*
*
*
* Sr7'h7E RnW=1 ACK48bit UID BCR DCRAssign 7bit AddrPAR ACK/NACK
*
* Some master controllers (such as HCI) need to prepare the entire above transaction before
* sending it out to the I3C bus. This means that a 7-bit dynamic address needs to be allocated
* before knowing the target device's UID information.
*
* However, some I3C targets may request specific addresses (called as "init_dyn_addr"), which is
* typically specified by the DT-'s assigned-address property. Lower addresses having higher IBI
* priority. If it is available, i3c_bus_get_free_addr() preferably return a free address that is
* not in the list of desired addresses (called as "init_dyn_addr"). This allows the device with
* the "init_dyn_addr" to switch to its "init_dyn_addr" when it hot-joins the I3C bus. Otherwise,
* if the "init_dyn_addr" is already in use by another I3C device, the target device will not be
* able to switch to its desired address.
*
* If the previous step fails, fallback returning one of the remaining unassigned address,
* regardless of its state in the desired list.
*/
static int i3c_bus_get_free_addr(struct i3c_bus *bus, u8 start_addr)
{
enum i3c_addr_slot_status status;
u8 addr;
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
status = i3c_bus_get_addr_slot_status(bus, addr);
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
I3C_ADDR_SLOT_EXT_STATUS_MASK);
if (status == I3C_ADDR_SLOT_FREE)
return addr;
}
for (addr = start_addr; addr < I3C_MAX_ADDR; addr++) {
status = i3c_bus_get_addr_slot_status_mask(bus, addr,
I3C_ADDR_SLOT_STATUS_MASK);
if (status == I3C_ADDR_SLOT_FREE)
return addr;
}
@ -1417,7 +1460,7 @@ static void i3c_master_put_i3c_addrs(struct i3c_dev_desc *dev)
I3C_ADDR_SLOT_FREE);
if (dev->boardinfo && dev->boardinfo->init_dyn_addr)
i3c_bus_set_addr_slot_status(&master->bus, dev->info.dyn_addr,
i3c_bus_set_addr_slot_status(&master->bus, dev->boardinfo->init_dyn_addr,
I3C_ADDR_SLOT_FREE);
}
@ -1506,16 +1549,9 @@ static int i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
u8 old_dyn_addr)
{
struct i3c_master_controller *master = i3c_dev_get_master(dev);
enum i3c_addr_slot_status status;
int ret;
if (dev->info.dyn_addr != old_dyn_addr &&
(!dev->boardinfo ||
dev->info.dyn_addr != dev->boardinfo->init_dyn_addr)) {
status = i3c_bus_get_addr_slot_status(&master->bus,
dev->info.dyn_addr);
if (status != I3C_ADDR_SLOT_FREE)
return -EBUSY;
if (dev->info.dyn_addr != old_dyn_addr) {
i3c_bus_set_addr_slot_status(&master->bus,
dev->info.dyn_addr,
I3C_ADDR_SLOT_I3C_DEV);
@ -1918,9 +1954,11 @@ static int i3c_master_bus_init(struct i3c_master_controller *master)
goto err_rstdaa;
}
i3c_bus_set_addr_slot_status(&master->bus,
i3cboardinfo->init_dyn_addr,
I3C_ADDR_SLOT_I3C_DEV);
/* Do not mark as occupied until real device exist in bus */
i3c_bus_set_addr_slot_status_mask(&master->bus,
i3cboardinfo->init_dyn_addr,
I3C_ADDR_SLOT_EXT_DESIRED,
I3C_ADDR_SLOT_EXT_STATUS_MASK);
/*
* Only try to create/attach devices that have a static
@ -2051,11 +2089,16 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
ibireq.max_payload_len = olddev->ibi->max_payload_len;
ibireq.num_slots = olddev->ibi->num_slots;
if (olddev->ibi->enabled) {
if (olddev->ibi->enabled)
enable_ibi = true;
i3c_dev_disable_ibi_locked(olddev);
}
/*
* The olddev should not receive any commands on the
* i3c bus as it does not exist and has been assigned
* a new address. This will result in NACK or timeout.
* So, update the olddev->ibi->enabled flag to false
* to avoid DISEC with OldAddr.
*/
olddev->ibi->enabled = false;
i3c_dev_free_ibi_locked(olddev);
}
mutex_unlock(&olddev->ibi_lock);
@ -2083,7 +2126,8 @@ int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
else
expected_dyn_addr = newdev->info.dyn_addr;
if (newdev->info.dyn_addr != expected_dyn_addr) {
if (newdev->info.dyn_addr != expected_dyn_addr &&
i3c_bus_get_addr_slot_status(&master->bus, expected_dyn_addr) == I3C_ADDR_SLOT_FREE) {
/*
* Try to apply the expected dynamic address. If it fails, keep
* the address assigned by the master.

View File

@ -220,6 +220,14 @@
#define XFER_TIMEOUT (msecs_to_jiffies(1000))
#define RPM_AUTOSUSPEND_TIMEOUT 1000 /* ms */
/* Timing values to configure 12.5MHz frequency */
#define AMD_I3C_OD_TIMING 0x4C007C
#define AMD_I3C_PP_TIMING 0x8001A
/* List of quirks */
#define AMD_I3C_OD_PP_TIMING BIT(1)
struct dw_i3c_cmd {
u32 cmd_lo;
u32 cmd_hi;
@ -794,6 +802,12 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
return ret;
}
static void amd_configure_od_pp_quirk(struct dw_i3c_master *master)
{
master->i3c_od_timing = AMD_I3C_OD_TIMING;
master->i3c_pp_timing = AMD_I3C_PP_TIMING;
}
static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
struct i3c_ccc_cmd *ccc)
{
@ -803,6 +817,13 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
if (ccc->id == I3C_CCC_ENTDAA)
return -EINVAL;
/* AMD platform specific OD and PP timings */
if (master->quirks & AMD_I3C_OD_PP_TIMING) {
amd_configure_od_pp_quirk(master);
writel(master->i3c_pp_timing, master->regs + SCL_I3C_PP_TIMING);
writel(master->i3c_od_timing, master->regs + SCL_I3C_OD_TIMING);
}
ret = pm_runtime_resume_and_get(master->dev);
if (ret < 0) {
dev_err(master->dev,
@ -1602,6 +1623,8 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
master->maxdevs = ret >> 16;
master->free_pos = GENMASK(master->maxdevs - 1, 0);
master->quirks = (unsigned long)device_get_match_data(&pdev->dev);
INIT_WORK(&master->hj_work, dw_i3c_hj_work);
ret = i3c_master_register(&master->base, &pdev->dev,
&dw_mipi_i3c_ops, false);
@ -1675,6 +1698,10 @@ static void dw_i3c_master_restore_addrs(struct dw_i3c_master *master)
static void dw_i3c_master_restore_timing_regs(struct dw_i3c_master *master)
{
/* AMD platform specific OD and PP timings */
if (master->quirks & AMD_I3C_OD_PP_TIMING)
amd_configure_od_pp_quirk(master);
writel(master->i3c_pp_timing, master->regs + SCL_I3C_PP_TIMING);
writel(master->bus_free_timing, master->regs + BUS_FREE_TIMING);
writel(master->i3c_od_timing, master->regs + SCL_I3C_OD_TIMING);
@ -1748,12 +1775,19 @@ static const struct of_device_id dw_i3c_master_of_match[] = {
};
MODULE_DEVICE_TABLE(of, dw_i3c_master_of_match);
static const struct acpi_device_id amd_i3c_device_match[] = {
{ "AMDI0015", AMD_I3C_OD_PP_TIMING },
{ }
};
MODULE_DEVICE_TABLE(acpi, amd_i3c_device_match);
static struct platform_driver dw_i3c_driver = {
.probe = dw_i3c_probe,
.remove_new = dw_i3c_remove,
.driver = {
.name = "dw-i3c-master",
.of_match_table = dw_i3c_master_of_match,
.acpi_match_table = amd_i3c_device_match,
.pm = &dw_i3c_pm_ops,
},
};

View File

@ -50,6 +50,7 @@ struct dw_i3c_master {
u32 bus_free_timing;
u32 i2c_fm_timing;
u32 i2c_fmp_timing;
u32 quirks;
/*
* Per-device hardware data, used to manage the device address table
* (DAT)

View File

@ -80,8 +80,6 @@
#define INTR_HC_CMD_SEQ_UFLOW_STAT BIT(12) /* Cmd Sequence Underflow */
#define INTR_HC_RESET_CANCEL BIT(11) /* HC Cancelled Reset */
#define INTR_HC_INTERNAL_ERR BIT(10) /* HC Internal Error */
#define INTR_HC_PIO BIT(8) /* cascaded PIO interrupt */
#define INTR_HC_RINGS GENMASK(7, 0)
#define DAT_SECTION 0x30 /* Device Address Table */
#define DAT_ENTRY_SIZE GENMASK(31, 28)
@ -438,7 +436,8 @@ static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev)
kfree(dev_data);
return ret;
}
mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret, dev->info.dyn_addr);
mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret,
dev->info.dyn_addr ?: dev->info.static_addr);
dev_data->dat_idx = ret;
}
i3c_dev_set_master_data(dev, dev_data);
@ -597,9 +596,6 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
if (val) {
reg_write(INTR_STATUS, val);
} else {
/* v1.0 does not have PIO cascaded notification bits */
val |= INTR_HC_PIO;
}
if (val & INTR_HC_RESET_CANCEL) {
@ -610,14 +606,9 @@ static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
dev_err(&hci->master.dev, "Host Controller Internal Error\n");
val &= ~INTR_HC_INTERNAL_ERR;
}
if (val & INTR_HC_PIO) {
hci->io->irq_handler(hci, 0);
val &= ~INTR_HC_PIO;
}
if (val & INTR_HC_RINGS) {
hci->io->irq_handler(hci, val & INTR_HC_RINGS);
val &= ~INTR_HC_RINGS;
}
hci->io->irq_handler(hci);
if (val)
dev_err(&hci->master.dev, "unexpected INTR_STATUS %#x\n", val);
else

View File

@ -159,10 +159,10 @@ static void hci_dma_cleanup(struct i3c_hci *hci)
for (i = 0; i < rings->total; i++) {
rh = &rings->headers[i];
rh_reg_write(INTR_SIGNAL_ENABLE, 0);
rh_reg_write(RING_CONTROL, 0);
rh_reg_write(CR_SETUP, 0);
rh_reg_write(IBI_SETUP, 0);
rh_reg_write(INTR_SIGNAL_ENABLE, 0);
if (rh->xfer)
dma_free_coherent(&hci->master.dev,
@ -733,20 +733,16 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
rh_reg_write(CHUNK_CONTROL, rh_reg_read(CHUNK_CONTROL) + ibi_chunks);
}
static bool hci_dma_irq_handler(struct i3c_hci *hci, unsigned int mask)
static bool hci_dma_irq_handler(struct i3c_hci *hci)
{
struct hci_rings_data *rings = hci->io_data;
unsigned int i;
bool handled = false;
for (i = 0; mask && i < rings->total; i++) {
for (i = 0; i < rings->total; i++) {
struct hci_rh_data *rh;
u32 status;
if (!(mask & BIT(i)))
continue;
mask &= ~BIT(i);
rh = &rings->headers[i];
status = rh_reg_read(INTR_STATUS);
DBG("rh%d status: %#x", i, status);

View File

@ -115,7 +115,7 @@ static inline void hci_free_xfer(struct hci_xfer *xfer, unsigned int n)
/* This abstracts PIO vs DMA operations */
struct hci_io_ops {
bool (*irq_handler)(struct i3c_hci *hci, unsigned int mask);
bool (*irq_handler)(struct i3c_hci *hci);
int (*queue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
bool (*dequeue_xfer)(struct i3c_hci *hci, struct hci_xfer *xfer, int n);
int (*request_ibi)(struct i3c_hci *hci, struct i3c_dev_desc *dev,

View File

@ -979,7 +979,7 @@ static void hci_pio_recycle_ibi_slot(struct i3c_hci *hci,
i3c_generic_ibi_recycle_slot(dev_ibi->pool, slot);
}
static bool hci_pio_irq_handler(struct i3c_hci *hci, unsigned int unused)
static bool hci_pio_irq_handler(struct i3c_hci *hci)
{
struct hci_pio_data *pio = hci->io_data;
u32 status;

View File

@ -130,8 +130,8 @@
#define SVC_I3C_PPBAUD_MAX 15
#define SVC_I3C_QUICK_I2C_CLK 4170000
#define SVC_I3C_EVENT_IBI BIT(0)
#define SVC_I3C_EVENT_HOTJOIN BIT(1)
#define SVC_I3C_EVENT_IBI GENMASK(7, 0)
#define SVC_I3C_EVENT_HOTJOIN BIT(31)
struct svc_i3c_cmd {
u8 addr;
@ -214,7 +214,7 @@ struct svc_i3c_master {
spinlock_t lock;
} ibi;
struct mutex lock;
int enabled_events;
u32 enabled_events;
u32 mctrl_config;
};
@ -388,10 +388,11 @@ static int svc_i3c_master_handle_ibi(struct svc_i3c_master *master,
return 0;
}
static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master,
static int svc_i3c_master_ack_ibi(struct svc_i3c_master *master,
bool mandatory_byte)
{
unsigned int ibi_ack_nack;
u32 reg;
ibi_ack_nack = SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK;
if (mandatory_byte)
@ -400,13 +401,43 @@ static void svc_i3c_master_ack_ibi(struct svc_i3c_master *master,
ibi_ack_nack |= SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE;
writel(ibi_ack_nack, master->regs + SVC_I3C_MCTRL);
return readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg,
SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000);
}
static void svc_i3c_master_nack_ibi(struct svc_i3c_master *master)
static int svc_i3c_master_nack_ibi(struct svc_i3c_master *master)
{
int ret;
u32 reg;
writel(SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK |
SVC_I3C_MCTRL_IBIRESP_NACK,
master->regs + SVC_I3C_MCTRL);
ret = readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg,
SVC_I3C_MSTATUS_MCTRLDONE(reg), 1, 1000);
return ret;
}
static int svc_i3c_master_handle_ibi_won(struct svc_i3c_master *master, u32 mstatus)
{
u32 ibitype;
int ret = 0;
ibitype = SVC_I3C_MSTATUS_IBITYPE(mstatus);
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
/* Hardware can't auto emit NACK for hot join and master request */
switch (ibitype) {
case SVC_I3C_MSTATUS_IBITYPE_HOT_JOIN:
case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
ret = svc_i3c_master_nack_ibi(master);
}
return ret;
}
static void svc_i3c_master_ibi_work(struct work_struct *work)
@ -418,7 +449,16 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
u32 status, val;
int ret;
mutex_lock(&master->lock);
/*
* According to I3C spec ver 1.1, 09-Jun-2021, section 5.1.2.5:
*
* The I3C Controller shall hold SCL low while the Bus is in ACK/NACK Phase of I3C/I2C
* transfer. But maximum stall time is 100us. The IRQs have to be disabled to prevent
* schedule during the whole I3C transaction, otherwise, the I3C bus timeout may happen if
* any irq or schedule happen during transaction.
*/
guard(spinlock_irqsave)(&master->xferqueue.lock);
/*
* IBIWON may be set before SVC_I3C_MCTRL_REQUEST_AUTO_IBI, causing
* readl_relaxed_poll_timeout() to return immediately. Consequently,
@ -438,8 +478,8 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
master->regs + SVC_I3C_MCTRL);
/* Wait for IBIWON, should take approximately 100us */
ret = readl_relaxed_poll_timeout(master->regs + SVC_I3C_MSTATUS, val,
SVC_I3C_MSTATUS_IBIWON(val), 0, 1000);
ret = readl_relaxed_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, val,
SVC_I3C_MSTATUS_IBIWON(val), 0, 100);
if (ret) {
dev_err(master->dev, "Timeout when polling for IBIWON\n");
svc_i3c_master_emit_stop(master);
@ -511,7 +551,6 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
reenable_ibis:
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
mutex_unlock(&master->lock);
}
static irqreturn_t svc_i3c_master_irq_handler(int irq, void *dev_id)
@ -854,6 +893,9 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
int ret, i;
while (true) {
/* clean SVC_I3C_MINT_IBIWON w1c bits */
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
/* SVC_I3C_MCTRL_REQUEST_PROC_DAA have two mode, ENTER DAA or PROCESS DAA.
*
* ENTER DAA:
@ -905,6 +947,11 @@ static int svc_i3c_master_do_daa_locked(struct svc_i3c_master *master,
ret = svc_i3c_master_readb(master, data, 2);
if (ret)
break;
} else if (SVC_I3C_MSTATUS_IBIWON(reg)) {
ret = svc_i3c_master_handle_ibi_won(master, reg);
if (ret)
break;
continue;
} else if (SVC_I3C_MSTATUS_MCTRLDONE(reg)) {
if (SVC_I3C_MSTATUS_STATE_IDLE(reg) &&
SVC_I3C_MSTATUS_COMPLETE(reg)) {
@ -1056,12 +1103,27 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
if (ret)
goto rpm_out;
/* Register all devices who participated to the core */
for (i = 0; i < dev_nb; i++) {
ret = i3c_master_add_i3c_dev_locked(m, addrs[i]);
if (ret)
goto rpm_out;
}
/*
* Register all devices who participated to the core
*
* If two devices (A and B) are detected in DAA and address 0xa is assigned to
* device A and 0xb to device B, a failure in i3c_master_add_i3c_dev_locked()
* for device A (addr: 0xa) could prevent device B (addr: 0xb) from being
* registered on the bus. The I3C stack might still consider 0xb a free
* address. If a subsequent Hotjoin occurs, 0xb might be assigned to Device A,
* causing both devices A and B to use the same address 0xb, violating the I3C
* specification.
*
* The return value for i3c_master_add_i3c_dev_locked() should not be checked
* because subsequent steps will scan the entire I3C bus, independent of
* whether i3c_master_add_i3c_dev_locked() returns success.
*
* If device A registration fails, there is still a chance to register device
* B. i3c_master_add_i3c_dev_locked() can reset DAA if a failure occurs while
* retrieving device information.
*/
for (i = 0; i < dev_nb; i++)
i3c_master_add_i3c_dev_locked(m, addrs[i]);
/* Configure IBI auto-rules */
ret = svc_i3c_update_ibirules(master);
@ -1163,6 +1225,26 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
if (ret)
goto emit_stop;
/*
* According to I3C spec ver 1.1.1, 5.1.2.2.3 Consequence of Controller Starting a
* Frame with I3C Target Address.
*
* The I3C Controller normally should start a Frame, the Address may be arbitrated,
* and so the Controller shall monitor to see whether an In-Band Interrupt request,
* a Controller Role Request (i.e., Secondary Controller requests to become the
* Active Controller), or a Hot-Join Request has been made.
*
* If missed IBIWON check, the wrong data will be return. When IBIWON happen, issue
* repeat start. Address arbitrate only happen at START, never happen at REPEAT
* start.
*/
if (SVC_I3C_MSTATUS_IBIWON(reg)) {
ret = svc_i3c_master_handle_ibi_won(master, reg);
if (ret)
goto emit_stop;
continue;
}
if (readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_NACK) {
/*
* According to I3C Spec 1.1.1, 11-Jun-2021, section: 5.1.2.2.3.
@ -1196,24 +1278,6 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
}
}
/*
* According to I3C spec ver 1.1.1, 5.1.2.2.3 Consequence of Controller Starting a Frame
* with I3C Target Address.
*
* The I3C Controller normally should start a Frame, the Address may be arbitrated, and so
* the Controller shall monitor to see whether an In-Band Interrupt request, a Controller
* Role Request (i.e., Secondary Controller requests to become the Active Controller), or
* a Hot-Join Request has been made.
*
* If missed IBIWON check, the wrong data will be return. When IBIWON happen, return failure
* and yield the above events handler.
*/
if (SVC_I3C_MSTATUS_IBIWON(reg)) {
ret = -EAGAIN;
*actual_len = 0;
goto emit_stop;
}
if (rnw)
ret = svc_i3c_master_read(master, in, xfer_len);
else
@ -1624,7 +1688,7 @@ static int svc_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
return ret;
}
master->enabled_events |= SVC_I3C_EVENT_IBI;
master->enabled_events++;
svc_i3c_master_enable_interrupts(master, SVC_I3C_MINT_SLVSTART);
return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
@ -1636,7 +1700,7 @@ static int svc_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
struct svc_i3c_master *master = to_svc_i3c_master(m);
int ret;
master->enabled_events &= ~SVC_I3C_EVENT_IBI;
master->enabled_events--;
if (!master->enabled_events)
svc_i3c_master_disable_interrupts(master);
@ -1827,8 +1891,8 @@ static int svc_i3c_master_probe(struct platform_device *pdev)
rpm_disable:
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
err_disable_clks:
svc_i3c_master_unprepare_clks(master);

View File

@ -298,7 +298,9 @@ enum i3c_open_drain_speed {
* @I3C_ADDR_SLOT_I2C_DEV: address is assigned to an I2C device
* @I3C_ADDR_SLOT_I3C_DEV: address is assigned to an I3C device
* @I3C_ADDR_SLOT_STATUS_MASK: address slot mask
*
* @I3C_ADDR_SLOT_EXT_STATUS_MASK: address slot mask with extended information
* @I3C_ADDR_SLOT_EXT_DESIRED: the bitmask represents addresses that are preferred by some devices,
* such as the "assigned-address" property in a device tree source.
* On an I3C bus, addresses are assigned dynamically, and we need to know which
* addresses are free to use and which ones are already assigned.
*
@ -311,8 +313,12 @@ enum i3c_addr_slot_status {
I3C_ADDR_SLOT_I2C_DEV,
I3C_ADDR_SLOT_I3C_DEV,
I3C_ADDR_SLOT_STATUS_MASK = 3,
I3C_ADDR_SLOT_EXT_STATUS_MASK = 7,
I3C_ADDR_SLOT_EXT_DESIRED = BIT(2),
};
#define I3C_ADDR_SLOT_STATUS_BITS 4
/**
* struct i3c_bus - I3C bus object
* @cur_master: I3C master currently driving the bus. Since I3C is multi-master
@ -354,7 +360,7 @@ enum i3c_addr_slot_status {
struct i3c_bus {
struct i3c_dev_desc *cur_master;
int id;
unsigned long addrslots[((I2C_MAX_ADDR + 1) * 2) / BITS_PER_LONG];
unsigned long addrslots[((I2C_MAX_ADDR + 1) * I3C_ADDR_SLOT_STATUS_BITS) / BITS_PER_LONG];
enum i3c_bus_mode mode;
struct {
unsigned long i3c;