Merge: i3c: master: v6.19 sync and ACPI support

MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-10/-/merge_requests/3302

JIRA: https://issues.redhat.com/browse/RHEL-143335

Update the i3c master driver with all features added up to upstream
v6.19 and most fixes up to v7.2-rc7.

ACPI support for i3c is taken from one patch series in linux-next.

---

This MR includes a partial backport for only the hunks affecting i3c
from a couple treewide patches upstream. All of these fixes are related
to excluded hunks.

Omitted-fix: fd1d6b9d13f3 (`xz: fix arm fdt compile error for kmalloc replacement`)

Omitted-fix: 96a7b71c4438 (`ubd: Use pointer-to-pointers for io_thread_req arrays`)

Omitted-fix: 795469820c63 (`kcsan: test: Adjust "expect" allocation type for kmalloc_obj`)

Omitted-fix: 5548dd7fa845 (`tools/testing: fix testing/vma and testing/radix-tree build`)

Omitted-fix: 405ca72dc589 (`landlock: Fix formatting`)

Omitted-fix: 4c0134639694 (`KVM: PPC: e500: Fix build error due to using kmalloc_obj() with wrong type`)

Omitted-fix: 2d2b5507e598 (`btrfs: replace kcalloc() calls to kzalloc_objs()`)

Omitted-fix: 9f4ab0787e7b (`btrfs: do more kmalloc_obj()/kmalloc_objs() conversions`)

Omitted-fix: 37f1f51fba1a (`btrfs: convert kmalloc_array to kmalloc_objs in btrfs_calc_avail_data_space()`)

Omitted-fix: 4c6d43db2a4d (`net: dst_metadata: fix false-positive memcpy overflow in tun_dst_unclone`)

Signed-off-by: Jennifer Berringer <jberring@redhat.com>

Approved-by: Mark Langsdorf <mlangsdo@redhat.com>
Approved-by: Mark Salter <msalter@redhat.com>
Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com>

Merged-by: CKI GitLab Kmaint Pipeline Bot <26919896-cki-kmaint-pipeline-bot@users.noreply.gitlab.com>
This commit is contained in:
CKI KWF Bot
2026-09-01 07:27:23 +00:00
20 changed files with 1515 additions and 525 deletions
+31
View File
@@ -161,3 +161,34 @@ Contact: linux-i3c@vger.kernel.org
Description:
These directories are just symbolic links to
/sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>.
What: /sys/bus/i3c/devices/i3c-<bus-id>/<bus-id>-<device-pid>/dev_nack_retry_count
KernelVersion: 6.18
Contact: linux-i3c@vger.kernel.org
Description:
Expose the dev_nak_retry_count which controls the number of
automatic retries that will be performed by the controller when
the target device returns a NACK response. A value of 0 disables
the automatic retries. Exist only when I3C constroller supports
this retry on nack feature.
What: /sys/bus/i3c/devices/i3c-<bus-id>/do_daa
KernelVersion: 7.0
Contact: linux-i3c@vger.kernel.org
Description:
Write-only attribute that triggers a Dynamic Address Assignment
(DAA) procedure which discovers new I3C devices on the bus.
Writing a boolean true value (1, y, yes, true, on) to this
attribute causes the master controller to perform DAA, which
includes broadcasting an ENTDAA (Enter Dynamic Address Assignment)
Common Command Code (CCC) on the bus. Writing a false value
returns -EINVAL.
This is useful for discovering I3C devices that were not present
during initial bus initialization and are unable to issue
Hot-Join. Only devices without a currently assigned dynamic address
will respond to the ENTDAA broadcast and be assigned addresses.
Note that this mechanism is distinct from Hot-Join, since this is
controller-initiated discovery, while Hot-Join is device-initiated
method to provoke controller discovery procedure.
+31 -5
View File
@@ -31,10 +31,12 @@ properties:
described in the device tree, which in turn means we have to describe
I3C devices.
Another use case for describing an I3C device in the device tree is when
this I3C device has a static I2C address and we want to assign it a
specific I3C dynamic address before the DAA takes place (so that other
devices on the bus can't take this dynamic address).
Other use-cases for describing an I3C device in the device tree are:
- When the I3C device has a static I2C address and we want to assign
it a specific I3C dynamic address before the DAA takes place (so
that other devices on the bus can't take this dynamic address).
- When the I3C device requires SETAASA for its discovery and uses a
pre-defined static address.
"#size-cells":
const: 0
@@ -145,7 +147,31 @@ patternProperties:
Dynamic address to be assigned to this device. In case static address is
present (first cell of the reg property != 0), this address is assigned
through SETDASA. If static address is not present, this address is assigned
through SETNEWDA after assigning a temporary address via ENTDAA.
through SETNEWDA after assigning a temporary address via ENTDAA. If
SETAASA is used, this property is not used, and the static address itself
becomes the dynamic address.
mipi-i3c-static-method:
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 0x1
maximum: 0x7
default: 1
description: |
Bitmap describing which methods of Dynamic Address Assignment from a
static address are supported by this I3C Target. For each defined bit
position, a set bit indicates support for that method and a cleared
bit indicates lack of support.
Bit 0: SETDASA CCC (Direct)
Bit 1: SETAASA CCC (Broadcast)
Bit 2: Other CCC (vendor / standards extension)
All other bits are reserved.
This property follows the MIPI I3C specification. The primary use
of this property is to indicate support for SETAASA, i.e Bit 1, but
will allow other values mentioned in the specification so that it
mirrors the specification. SETDASA will remain as the default method
even if this property is not present.
required:
- reg
+6 -1
View File
@@ -315,7 +315,7 @@ struct acpi_rsconvert_info acpi_rs_convert_csi2_serial_bus[14] = {
*
******************************************************************************/
struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[17] = {
struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[18] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS,
ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus),
ACPI_RSC_TABLE_SIZE(acpi_rs_convert_i2c_serial_bus)},
@@ -391,6 +391,11 @@ struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[17] = {
AML_OFFSET(i2c_serial_bus.type_specific_flags),
0},
/* Read LVR from Type Specific Flags, bits[15:8] */
{ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.i2c_serial_bus.lvr),
AML_OFFSET(i2c_serial_bus.type_specific_flags) + 1,
1},
{ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.i2c_serial_bus.connection_speed),
AML_OFFSET(i2c_serial_bus.connection_speed),
1},
+6 -3
View File
@@ -2201,12 +2201,15 @@ config SENSORS_INA3221
config SENSORS_SPD5118
tristate "SPD5118 Compliant Temperature Sensors"
depends on I2C
depends on I3C_OR_I2C
select REGMAP_I2C
select REGMAP_I3C if I3C
help
If you say yes here you get support for SPD5118 (JEDEC JESD300)
compliant temperature sensors. Such sensors are found on DDR5 memory
modules.
compliant temperature sensors using I2C or I3C bus interface.
Such sensors are found on DDR5 memory modules.
This driver supports both I2C and I3C interfaces.
This driver can also be built as a module. If so, the module
will be called spd5118.
+52 -67
View File
@@ -18,6 +18,7 @@
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/i3c/device.h>
#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -66,9 +67,6 @@ static const unsigned short normal_i2c[] = {
#define SPD5118_EEPROM_BASE 0x80
#define SPD5118_EEPROM_SIZE (SPD5118_PAGE_SIZE * SPD5118_NUM_PAGES)
#define PAGE_ADDR0(page) (((page) & BIT(0)) << 6)
#define PAGE_ADDR1_4(page) (((page) & GENMASK(4, 1)) >> 1)
/* Temperature unit in millicelsius */
#define SPD5118_TEMP_UNIT (MILLIDEGREE_PER_DEGREE / 4)
/* Representable temperature range in millicelsius */
@@ -78,7 +76,6 @@ static const unsigned short normal_i2c[] = {
struct spd5118_data {
struct regmap *regmap;
struct mutex nvmem_lock;
bool is_16bit;
};
/* hwmon */
@@ -354,12 +351,7 @@ static ssize_t spd5118_nvmem_read_page(struct spd5118_data *data, char *buf,
if (offset + count > SPD5118_PAGE_SIZE)
count = SPD5118_PAGE_SIZE - offset;
if (data->is_16bit) {
addr = SPD5118_EEPROM_BASE | PAGE_ADDR0(page) |
(PAGE_ADDR1_4(page) << 8);
} else {
addr = page * 0x100 + SPD5118_EEPROM_BASE;
}
addr = page * 0x100 + SPD5118_EEPROM_BASE;
err = regmap_bulk_read(regmap, addr + offset, buf, count);
if (err)
return err;
@@ -479,10 +471,22 @@ static const struct regmap_config spd5118_regmap8_config = {
.num_ranges = ARRAY_SIZE(spd5118_i2c_regmap_range_cfg),
};
static const struct regmap_config spd5118_regmap16_config = {
/*
* SPD5118 2-byte register address format (JESD300-5, Tables 7 & 20):
* Byte 1 (on wire first): MemReg | BlkAddr[0] | Address[5:0]
* Byte 2 (on wire second): 0000 | BlkAddr[4:1]
*
* The address byte (with MemReg and lower address bits) must be sent first,
* followed by the upper block address byte. With regmap 16-bit register
* format, this maps to little-endian: the low byte of the 16-bit value is
* transmitted first. No range config is needed since I3C does not use MR11
* page switching.
*/
static const struct regmap_config spd5118_regmap_i3c_config = {
.reg_bits = 16,
.val_bits = 8,
.max_register = 0x7ff,
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
.writeable_reg = spd5118_writeable_reg,
.volatile_reg = spd5118_volatile_reg,
.cache_type = REGCACHE_MAPLE,
@@ -525,8 +529,7 @@ static int spd5118_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(spd5118_pm_ops, spd5118_suspend, spd5118_resume);
static int spd5118_common_probe(struct device *dev, struct regmap *regmap,
bool is_16bit)
static int spd5118_common_probe(struct device *dev, struct regmap *regmap)
{
unsigned int capability, revision, vendor, bank;
struct spd5118_data *data;
@@ -543,8 +546,6 @@ static int spd5118_common_probe(struct device *dev, struct regmap *regmap,
if (!(capability & SPD5118_CAP_TS_SUPPORT))
return -ENODEV;
data->is_16bit = is_16bit;
err = regmap_read(regmap, SPD5118_REG_REVISION, &revision);
if (err)
return err;
@@ -686,69 +687,21 @@ static int spd5118_i2c_init(struct i2c_client *client)
return 0;
}
/*
* 16-bit addressing note:
*
* If I2C_FUNC_I2C is not supported by an I2C adapter driver, regmap uses
* SMBus operations as alternative. To simulate a read operation with a 16-bit
* address, it writes the address using i2c_smbus_write_byte_data(), followed
* by one or more calls to i2c_smbus_read_byte() to read the data.
* Per spd5118 standard, a read operation after writing the address must start
* with <Sr> (Repeat Start). However, a SMBus read byte operation starts with
* <S> (Start). This resets the register address in the spd5118 chip. As result,
* i2c_smbus_read_byte() always returns data from register address 0x00.
*
* A working alternative to access chips with 16-bit register addresses in the
* absence of I2C_FUNC_I2C support is not known.
*
* For this reason, 16-bit addressing can only be supported with I2C if the
* adapter supports I2C_FUNC_I2C.
*
* For I2C, the addressing mode selected by the BIOS must not be changed.
* Experiments show that at least some PC BIOS versions will not change the
* addressing mode on a soft reboot and end up in setup, claiming that some
* configuration change happened. This will happen again after a power cycle,
* which does reset the addressing mode. To prevent this from happening,
* detect if 16-bit addressing is enabled and always use the currently
* configured addressing mode.
*/
static int spd5118_i2c_probe(struct i2c_client *client)
{
const struct regmap_config *config;
struct device *dev = &client->dev;
struct regmap *regmap;
int err, mode;
bool is_16bit;
int err;
err = spd5118_i2c_init(client);
if (err)
return err;
mode = i2c_smbus_read_byte_data(client, SPD5118_REG_I2C_LEGACY_MODE);
if (mode < 0)
return mode;
is_16bit = mode & SPD5118_LEGACY_MODE_ADDR;
if (is_16bit) {
/*
* See 16-bit addressing note above explaining why it is
* necessary to check for I2C_FUNC_I2C support here.
*/
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(dev, "Adapter does not support 16-bit register addresses\n");
return -ENODEV;
}
config = &spd5118_regmap16_config;
} else {
config = &spd5118_regmap8_config;
}
regmap = devm_regmap_init_i2c(client, config);
regmap = devm_regmap_init_i2c(client, &spd5118_regmap8_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n");
return spd5118_common_probe(dev, regmap, is_16bit);
return spd5118_common_probe(dev, regmap);
}
static const struct i2c_device_id spd5118_i2c_id[] = {
@@ -776,7 +729,39 @@ static struct i2c_driver spd5118_i2c_driver = {
.address_list = IS_ENABLED(CONFIG_SENSORS_SPD5118_DETECT) ? normal_i2c : NULL,
};
module_i2c_driver(spd5118_i2c_driver);
/* I3C */
static int spd5118_i3c_probe(struct i3c_device *i3cdev)
{
struct device *dev = i3cdev_to_dev(i3cdev);
struct regmap *regmap;
u8 regval[2];
int err;
regmap = devm_regmap_init_i3c(i3cdev, &spd5118_regmap_i3c_config);
if (IS_ERR(regmap))
return dev_err_probe(dev, PTR_ERR(regmap), "regmap init failed\n");
err = regmap_bulk_read(regmap, SPD5118_REG_TYPE, regval, 2);
if (err)
return dev_err_probe(dev, err, "failed to read device type\n");
if (regval[0] != 0x51 || regval[1] != 0x18)
return -ENODEV;
return spd5118_common_probe(dev, regmap);
}
static struct i3c_driver spd5118_i3c_driver = {
.driver = {
.name = "spd5118_i3c",
.of_match_table = spd5118_of_ids,
.pm = pm_sleep_ptr(&spd5118_pm_ops),
},
.probe = spd5118_i3c_probe,
};
module_i3c_i2c_driver(spd5118_i3c_driver, &spd5118_i2c_driver);
MODULE_AUTHOR("René Rebe <rene@exactcode.de>");
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+63 -10
View File
@@ -15,12 +15,12 @@
#include "internals.h"
/**
* i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a
* specific device
* i3c_device_do_xfers() - do I3C transfers directed to a specific device
*
* @dev: device with which the transfers should be done
* @xfers: array of transfers
* @nxfers: number of transfers
* @mode: transfer mode
*
* Initiate one or several private SDR transfers with @dev.
*
@@ -32,9 +32,8 @@
* driver needs to resend the 'xfers' some time later.
* See I3C spec ver 1.1.1 09-Jun-2021. Section: 5.1.2.2.3.
*/
int i3c_device_do_priv_xfers(struct i3c_device *dev,
struct i3c_priv_xfer *xfers,
int nxfers)
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode)
{
int ret, i;
@@ -46,13 +45,19 @@ int i3c_device_do_priv_xfers(struct i3c_device *dev,
return -EINVAL;
}
ret = i3c_bus_rpm_get(dev->bus);
if (ret)
return ret;
i3c_bus_normaluse_lock(dev->bus);
ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers);
ret = i3c_dev_do_xfers_locked(dev->desc, xfers, nxfers, mode);
i3c_bus_normaluse_unlock(dev->bus);
i3c_bus_rpm_put(dev->bus);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers);
EXPORT_SYMBOL_GPL(i3c_device_do_xfers);
/**
* i3c_device_do_setdasa() - do I3C dynamic address assignement with
@@ -66,10 +71,16 @@ int i3c_device_do_setdasa(struct i3c_device *dev)
{
int ret;
ret = i3c_bus_rpm_get(dev->bus);
if (ret)
return ret;
i3c_bus_normaluse_lock(dev->bus);
ret = i3c_dev_setdasa_locked(dev->desc);
i3c_bus_normaluse_unlock(dev->bus);
i3c_bus_rpm_put(dev->bus);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_device_do_setdasa);
@@ -106,16 +117,27 @@ EXPORT_SYMBOL_GPL(i3c_device_get_info);
*/
int i3c_device_disable_ibi(struct i3c_device *dev)
{
int ret = -ENOENT;
int ret;
if (i3c_bus_rpm_ibi_allowed(dev->bus)) {
ret = i3c_bus_rpm_get(dev->bus);
if (ret)
return ret;
}
i3c_bus_normaluse_lock(dev->bus);
if (dev->desc) {
mutex_lock(&dev->desc->ibi_lock);
ret = i3c_dev_disable_ibi_locked(dev->desc);
mutex_unlock(&dev->desc->ibi_lock);
} else {
ret = -ENOENT;
}
i3c_bus_normaluse_unlock(dev->bus);
if (!ret || i3c_bus_rpm_ibi_allowed(dev->bus))
i3c_bus_rpm_put(dev->bus);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
@@ -135,16 +157,25 @@ EXPORT_SYMBOL_GPL(i3c_device_disable_ibi);
*/
int i3c_device_enable_ibi(struct i3c_device *dev)
{
int ret = -ENOENT;
int ret;
ret = i3c_bus_rpm_get(dev->bus);
if (ret)
return ret;
i3c_bus_normaluse_lock(dev->bus);
if (dev->desc) {
mutex_lock(&dev->desc->ibi_lock);
ret = i3c_dev_enable_ibi_locked(dev->desc);
mutex_unlock(&dev->desc->ibi_lock);
} else {
ret = -ENOENT;
}
i3c_bus_normaluse_unlock(dev->bus);
if (ret || i3c_bus_rpm_ibi_allowed(dev->bus))
i3c_bus_rpm_put(dev->bus);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
@@ -163,19 +194,27 @@ EXPORT_SYMBOL_GPL(i3c_device_enable_ibi);
int i3c_device_request_ibi(struct i3c_device *dev,
const struct i3c_ibi_setup *req)
{
int ret = -ENOENT;
int ret;
if (!req->handler || !req->num_slots)
return -EINVAL;
ret = i3c_bus_rpm_get(dev->bus);
if (ret)
return ret;
i3c_bus_normaluse_lock(dev->bus);
if (dev->desc) {
mutex_lock(&dev->desc->ibi_lock);
ret = i3c_dev_request_ibi_locked(dev->desc, req);
mutex_unlock(&dev->desc->ibi_lock);
} else {
ret = -ENOENT;
}
i3c_bus_normaluse_unlock(dev->bus);
i3c_bus_rpm_put(dev->bus);
return ret;
}
EXPORT_SYMBOL_GPL(i3c_device_request_ibi);
@@ -259,6 +298,20 @@ i3c_device_match_id(struct i3c_device *i3cdev,
}
EXPORT_SYMBOL_GPL(i3c_device_match_id);
/**
* i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
* connected master controller.
* @dev: I3C device
*
* Return: a bit mask, which supported transfer mode, bit position is defined at
* enum i3c_hdr_mode
*/
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
{
return i3c_dev_get_master(dev->desc)->this->info.hdr_cap | BIT(I3C_SDR);
}
EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
/**
* i3c_driver_register_with_owner() - register an I3C device driver
*
+53 -3
View File
@@ -9,17 +9,67 @@
#define I3C_INTERNALS_H
#include <linux/i3c/master.h>
#include <linux/io.h>
int __must_check i3c_bus_rpm_get(struct i3c_bus *bus);
void i3c_bus_rpm_put(struct i3c_bus *bus);
bool i3c_bus_rpm_ibi_allowed(struct i3c_bus *bus);
void i3c_bus_normaluse_lock(struct i3c_bus *bus);
void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev);
int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *xfers,
int nxfers);
int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev,
struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode);
int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev);
int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev);
int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void i3c_dev_free_ibi_locked(struct i3c_dev_desc *dev);
/**
* i3c_writel_fifo - Write data buffer to 32bit FIFO
* @addr: FIFO Address to write to
* @buf: Pointer to the data bytes to write
* @nbytes: Number of bytes to write
*/
static inline void i3c_writel_fifo(void __iomem *addr, const void *buf,
int nbytes)
{
writesl(addr, buf, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, buf + (nbytes & ~3), nbytes & 3);
/*
* writesl() instead of writel() to keep FIFO
* byteorder on big-endian targets
*/
writesl(addr, &tmp, 1);
}
}
/**
* i3c_readl_fifo - Read data buffer from 32bit FIFO
* @addr: FIFO Address to read from
* @buf: Pointer to the buffer to store read bytes
* @nbytes: Number of bytes to read
*/
static inline void i3c_readl_fifo(const void __iomem *addr, void *buf,
int nbytes)
{
readsl(addr, buf, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
/*
* readsl() instead of readl() to keep FIFO
* byteorder on big-endian targets
*/
readsl(addr, &tmp, 1);
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
}
}
#endif /* I3C_INTERNAL_H */
+837 -163
View File
File diff suppressed because it is too large Load Diff
+179 -131
View File
@@ -5,7 +5,9 @@
* Author: Vitor Soares <vitor.soares@synopsys.com>
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/err.h>
@@ -23,6 +25,7 @@
#include <linux/reset.h>
#include <linux/slab.h>
#include "../internals.h"
#include "dw-i3c-master.h"
#define DEVICE_CTRL 0x0
@@ -203,12 +206,23 @@
#define EXTENDED_CAPABILITY 0xe8
#define SLAVE_CONFIG 0xec
#define DYN_ADDR_LO_MASK GENMASK(4, 0)
#define DYN_ADDR_HI_MASK GENMASK(6, 5)
#define IBI_SIR_BIT_MOD 32 /* 32-bit vector */
#define DW_I3C_DEV_NACK_RETRY_CNT_MAX 0x3
#define DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK GENMASK(30, 29)
#define DEV_ADDR_TABLE_DYNAMIC_MASK GENMASK(23, 16)
#define DEV_ADDR_TABLE_STATIC_MASK GENMASK(6, 0)
#define DEV_ADDR_TABLE_IBI_MDB BIT(12)
#define DEV_ADDR_TABLE_SIR_REJECT BIT(13)
#define DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(x) \
FIELD_PREP(DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK, (x))
#define DEV_ADDR_TABLE_LEGACY_I2C_DEV BIT(31)
#define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) (((x) << 16) & GENMASK(23, 16))
#define DEV_ADDR_TABLE_STATIC_ADDR(x) ((x) & GENMASK(6, 0))
#define DEV_ADDR_TABLE_DYNAMIC_ADDR(x) FIELD_PREP(DEV_ADDR_TABLE_DYNAMIC_MASK, x)
#define DEV_ADDR_TABLE_STATIC_ADDR(x) FIELD_PREP(DEV_ADDR_TABLE_STATIC_MASK, x)
#define DEV_ADDR_TABLE_LOC(start, idx) ((start) + ((idx) << 2))
#define DEV_ADDR_TABLE_GET_DYNAMIC_ADDR(x) FIELD_GET(DEV_ADDR_TABLE_DYNAMIC_MASK, x)
#define I3C_BUS_SDR1_SCL_RATE 8000000
#define I3C_BUS_SDR2_SCL_RATE 6000000
@@ -228,6 +242,7 @@
/* List of quirks */
#define AMD_I3C_OD_PP_TIMING BIT(1)
#define DW_I3C_DISABLE_RUNTIME_PM_QUIRK BIT(2)
#define DW_I3C_ACPI_SKIP_CLK_RST BIT(3)
struct dw_i3c_cmd {
u32 cmd_lo;
@@ -264,6 +279,14 @@ static u8 even_parity(u8 p)
return (0x9669 >> p) & 1;
}
static inline u32 get_ibi_sir_bit_index(u8 addr)
{
u32 lo = FIELD_GET(DYN_ADDR_LO_MASK, addr);
u32 hi = FIELD_GET(DYN_ADDR_HI_MASK, addr);
return (lo + hi) % IBI_SIR_BIT_MOD;
}
static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
const struct i3c_ccc_cmd *cmd)
{
@@ -295,6 +318,8 @@ static bool dw_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
case I3C_CCC_GETSTATUS:
case I3C_CCC_GETMXDS:
case I3C_CCC_GETHDRCAP:
case I3C_CCC_SETAASA:
case I3C_CCC_VENDOR(0, true): /* SETHID */
return true;
default:
return false;
@@ -349,37 +374,19 @@ static int dw_i3c_master_get_free_pos(struct dw_i3c_master *master)
static void dw_i3c_master_wr_tx_fifo(struct dw_i3c_master *master,
const u8 *bytes, int nbytes)
{
writesl(master->regs + RX_TX_DATA_PORT, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
writesl(master->regs + RX_TX_DATA_PORT, &tmp, 1);
}
}
static void dw_i3c_master_read_fifo(struct dw_i3c_master *master,
int reg, u8 *bytes, int nbytes)
{
readsl(master->regs + reg, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
readsl(master->regs + reg, &tmp, 1);
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_writel_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_rx_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
return dw_i3c_master_read_fifo(master, RX_TX_DATA_PORT, bytes, nbytes);
i3c_readl_fifo(master->regs + RX_TX_DATA_PORT, bytes, nbytes);
}
static void dw_i3c_master_read_ibi_fifo(struct dw_i3c_master *master,
u8 *bytes, int nbytes)
{
return dw_i3c_master_read_fifo(master, IBI_QUEUE_STATUS, bytes, nbytes);
i3c_readl_fifo(master->regs + IBI_QUEUE_STATUS, bytes, nbytes);
}
static struct dw_i3c_xfer *
@@ -387,7 +394,7 @@ dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds)
{
struct dw_i3c_xfer *xfer;
xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
xfer = kzalloc_flex(*xfer, cmds, ncmds, GFP_KERNEL);
if (!xfer)
return NULL;
@@ -398,11 +405,6 @@ dw_i3c_master_alloc_xfer(struct dw_i3c_master *master, unsigned int ncmds)
return xfer;
}
static void dw_i3c_master_free_xfer(struct dw_i3c_xfer *xfer)
{
kfree(xfer);
}
static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
{
struct dw_i3c_xfer *xfer = master->xferqueue.cur;
@@ -434,17 +436,14 @@ static void dw_i3c_master_start_xfer_locked(struct dw_i3c_master *master)
static void dw_i3c_master_enqueue_xfer(struct dw_i3c_master *master,
struct dw_i3c_xfer *xfer)
{
unsigned long flags;
init_completion(&xfer->comp);
spin_lock_irqsave(&master->xferqueue.lock, flags);
guard(spinlock_irqsave)(&master->xferqueue.lock);
if (master->xferqueue.cur) {
list_add_tail(&xfer->node, &master->xferqueue.list);
} else {
master->xferqueue.cur = xfer;
dw_i3c_master_start_xfer_locked(master);
}
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
}
static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master,
@@ -469,11 +468,8 @@ static void dw_i3c_master_dequeue_xfer_locked(struct dw_i3c_master *master,
static void dw_i3c_master_dequeue_xfer(struct dw_i3c_master *master,
struct dw_i3c_xfer *xfer)
{
unsigned long flags;
spin_lock_irqsave(&master->xferqueue.lock, flags);
guard(spinlock_irqsave)(&master->xferqueue.lock);
dw_i3c_master_dequeue_xfer_locked(master, xfer);
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
}
static void dw_i3c_master_end_xfer_locked(struct dw_i3c_master *master, u32 isr)
@@ -569,13 +565,28 @@ static void dw_i3c_master_set_intr_regs(struct dw_i3c_master *master)
writel(IBI_REQ_REJECT_ALL, master->regs + IBI_MR_REQ_REJECT);
}
static unsigned long dw_i3c_master_get_core_rate(struct dw_i3c_master *master)
{
unsigned int core_rate_prop;
if (master->core_clk)
return clk_get_rate(master->core_clk);
if (device_property_read_u32(master->dev, "clock-frequency", &core_rate_prop)) {
dev_err(master->dev, "missing clock-frequency property\n");
return 0;
}
return core_rate_prop;
}
static int dw_i3c_clk_cfg(struct dw_i3c_master *master)
{
unsigned long core_rate, core_period;
u32 scl_timing;
u8 hcnt, lcnt;
core_rate = clk_get_rate(master->core_clk);
core_rate = dw_i3c_master_get_core_rate(master);
if (!core_rate)
return -EINVAL;
@@ -628,21 +639,21 @@ static int dw_i2c_clk_cfg(struct dw_i3c_master *master)
u16 hcnt, lcnt;
u32 scl_timing;
core_rate = clk_get_rate(master->core_clk);
core_rate = dw_i3c_master_get_core_rate(master);
if (!core_rate)
return -EINVAL;
core_period = DIV_ROUND_UP(1000000000, core_rate);
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FMP_TLOW_MIN_NS, core_period);
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_RATE) - lcnt;
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FMP_TIMING_HCNT(hcnt) |
SCL_I2C_FMP_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FMP_TIMING);
master->i2c_fmp_timing = scl_timing;
lcnt = DIV_ROUND_UP(I3C_BUS_I2C_FM_TLOW_MIN_NS, core_period);
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_RATE) - lcnt;
hcnt = DIV_ROUND_UP(core_rate, I3C_BUS_I2C_FM_SCL_MAX_RATE) - lcnt;
scl_timing = SCL_I2C_FM_TIMING_HCNT(hcnt) |
SCL_I2C_FM_TIMING_LCNT(lcnt);
writel(scl_timing, master->regs + SCL_I2C_FM_TIMING);
@@ -712,7 +723,6 @@ static int dw_i3c_master_bus_init(struct i3c_master_controller *m)
dw_i3c_master_enable(master);
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -727,7 +737,6 @@ static void dw_i3c_master_bus_cleanup(struct i3c_master_controller *m)
static int dw_i3c_ccc_set(struct dw_i3c_master *master,
struct i3c_ccc_cmd *ccc)
{
struct dw_i3c_xfer *xfer;
struct dw_i3c_cmd *cmd;
int ret, pos = 0;
@@ -737,7 +746,7 @@ static int dw_i3c_ccc_set(struct dw_i3c_master *master,
return pos;
}
xfer = dw_i3c_master_alloc_xfer(master, 1);
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
if (!xfer)
return -ENOMEM;
@@ -762,14 +771,11 @@ static int dw_i3c_ccc_set(struct dw_i3c_master *master,
if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
ccc->err = I3C_ERROR_M2;
dw_i3c_master_free_xfer(xfer);
return ret;
}
static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
{
struct dw_i3c_xfer *xfer;
struct dw_i3c_cmd *cmd;
int ret, pos;
@@ -777,7 +783,7 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
if (pos < 0)
return pos;
xfer = dw_i3c_master_alloc_xfer(master, 1);
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
if (!xfer)
return -ENOMEM;
@@ -802,7 +808,6 @@ static int dw_i3c_ccc_get(struct dw_i3c_master *master, struct i3c_ccc_cmd *ccc)
ret = xfer->ret;
if (xfer->cmds[0].error == RESPONSE_ERROR_IBA_NACK)
ccc->err = I3C_ERROR_M2;
dw_i3c_master_free_xfer(xfer);
return ret;
}
@@ -842,7 +847,6 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
else
ret = dw_i3c_ccc_set(master, ccc);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -850,12 +854,15 @@ static int dw_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
static int dw_i3c_master_daa(struct i3c_master_controller *m)
{
struct dw_i3c_master *master = to_dw_i3c_master(m);
struct dw_i3c_xfer *xfer;
struct dw_i3c_cmd *cmd;
u32 olddevs, newdevs;
u8 p, last_addr = 0;
int ret, pos;
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, 1);
if (!xfer)
return -ENOMEM;
ret = pm_runtime_resume_and_get(master->dev);
if (ret < 0) {
dev_err(master->dev,
@@ -889,15 +896,8 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
ret = 0;
}
xfer = dw_i3c_master_alloc_xfer(master, 1);
if (!xfer) {
ret = -ENOMEM;
goto rpm_out;
}
pos = dw_i3c_master_get_free_pos(master);
if (pos < 0) {
dw_i3c_master_free_xfer(xfer);
ret = pos;
goto rpm_out;
}
@@ -922,30 +922,26 @@ static int dw_i3c_master_daa(struct i3c_master_controller *m)
i3c_master_add_i3c_dev_locked(m, master->devs[pos].addr);
}
dw_i3c_master_free_xfer(xfer);
rpm_out:
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *i3c_xfers,
int i3c_nxfers)
static int dw_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
struct i3c_xfer *i3c_xfers,
int i3c_nxfers, enum i3c_xfer_mode mode)
{
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned int nrxwords = 0, ntxwords = 0;
struct dw_i3c_xfer *xfer;
int i, ret = 0;
if (!i3c_nxfers)
return 0;
if (i3c_nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
for (i = 0; i < i3c_nxfers; i++) {
if (i3c_xfers[i].rnw)
@@ -956,9 +952,9 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i3c_nxfers);
if (!xfer)
return -ENOMEM;
@@ -1009,9 +1005,7 @@ static int dw_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
}
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -1039,7 +1033,7 @@ static int dw_i3c_master_reattach_i3c_dev(struct i3c_dev_desc *dev,
master->free_pos &= ~BIT(pos);
}
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr),
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(dev->info.dyn_addr) | DEV_ADDR_TABLE_SIR_REJECT,
master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
@@ -1059,7 +1053,7 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
if (pos < 0)
return pos;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
@@ -1068,7 +1062,7 @@ static int dw_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
master->free_pos &= ~BIT(pos);
i3c_dev_set_master_data(dev, data);
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr),
writel(DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr) | DEV_ADDR_TABLE_SIR_REJECT,
master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, data->index));
@@ -1092,21 +1086,20 @@ static void dw_i3c_master_detach_i3c_dev(struct i3c_dev_desc *dev)
}
static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
const struct i2c_msg *i2c_xfers,
struct i2c_msg *i2c_xfers,
int i2c_nxfers)
{
struct dw_i3c_i2c_dev_data *data = i2c_dev_get_master_data(dev);
struct i3c_master_controller *m = i2c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned int nrxwords = 0, ntxwords = 0;
struct dw_i3c_xfer *xfer;
int i, ret = 0;
if (!i2c_nxfers)
return 0;
if (i2c_nxfers > master->caps.cmdfifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
for (i = 0; i < i2c_nxfers; i++) {
if (i2c_xfers[i].flags & I2C_M_RD)
@@ -1117,9 +1110,9 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
if (ntxwords > master->caps.datafifodepth ||
nrxwords > master->caps.datafifodepth)
return -ENOTSUPP;
return -EOPNOTSUPP;
xfer = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
struct dw_i3c_xfer *xfer __free(kfree) = dw_i3c_master_alloc_xfer(master, i2c_nxfers);
if (!xfer)
return -ENOMEM;
@@ -1155,13 +1148,11 @@ static int dw_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
}
dw_i3c_master_enqueue_xfer(master, xfer);
if (!wait_for_completion_timeout(&xfer->comp, XFER_TIMEOUT))
if (!wait_for_completion_timeout(&xfer->comp, m->i2c.timeout))
dw_i3c_master_dequeue_xfer(master, xfer);
ret = xfer->ret;
dw_i3c_master_free_xfer(xfer);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return ret;
}
@@ -1177,7 +1168,7 @@ static int dw_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
if (pos < 0)
return pos;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
@@ -1217,15 +1208,13 @@ static int dw_i3c_master_request_ibi(struct i3c_dev_desc *dev,
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned long flags;
data->ibi_pool = i3c_generic_ibi_alloc_pool(dev, req);
if (IS_ERR(data->ibi_pool))
return PTR_ERR(data->ibi_pool);
spin_lock_irqsave(&master->devs_lock, flags);
guard(spinlock_irqsave)(&master->devs_lock);
master->devs[data->index].ibi_dev = dev;
spin_unlock_irqrestore(&master->devs_lock, flags);
return 0;
}
@@ -1235,11 +1224,10 @@ static void dw_i3c_master_free_ibi(struct i3c_dev_desc *dev)
struct dw_i3c_i2c_dev_data *data = i3c_dev_get_master_data(dev);
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct dw_i3c_master *master = to_dw_i3c_master(m);
unsigned long flags;
spin_lock_irqsave(&master->devs_lock, flags);
master->devs[data->index].ibi_dev = NULL;
spin_unlock_irqrestore(&master->devs_lock, flags);
scoped_guard(spinlock_irqsave, &master->devs_lock) {
master->devs[data->index].ibi_dev = NULL;
}
i3c_generic_ibi_free_pool(data->ibi_pool);
data->ibi_pool = NULL;
@@ -1266,14 +1254,21 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
struct i3c_dev_desc *dev,
u8 idx, bool enable)
{
unsigned long flags;
u32 dat_entry, reg;
bool global;
u8 dynamic_addr;
dat_entry = DEV_ADDR_TABLE_LOC(master->datstartaddr, idx);
spin_lock_irqsave(&master->devs_lock, flags);
guard(spinlock_irqsave)(&master->devs_lock);
reg = readl(master->regs + dat_entry);
dynamic_addr = DEV_ADDR_TABLE_GET_DYNAMIC_ADDR(reg);
if (!dynamic_addr)
dev_warn(master->dev,
"<%s> unassigned slave device, dynamic addr:%x\n",
__func__, dynamic_addr);
if (enable) {
reg &= ~DEV_ADDR_TABLE_SIR_REJECT;
if (dev->info.bcr & I3C_BCR_IBI_PAYLOAD)
@@ -1286,20 +1281,17 @@ static void dw_i3c_master_set_sir_enabled(struct dw_i3c_master *master,
if (enable) {
global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL);
master->sir_rej_mask &= ~BIT(idx);
master->sir_rej_mask &= ~BIT(get_ibi_sir_bit_index(dynamic_addr));
} else {
bool hj_rejected = !!(readl(master->regs + DEVICE_CTRL) & DEV_CTRL_HOT_JOIN_NACK);
master->sir_rej_mask |= BIT(idx);
master->sir_rej_mask |= BIT(get_ibi_sir_bit_index(dynamic_addr));
global = (master->sir_rej_mask == IBI_REQ_REJECT_ALL) && hj_rejected;
}
writel(master->sir_rej_mask, master->regs + IBI_SIR_REQ_REJECT);
if (global)
dw_i3c_master_enable_sir_signal(master, enable);
spin_unlock_irqrestore(&master->devs_lock, flags);
}
static int dw_i3c_master_enable_hotjoin(struct i3c_master_controller *m)
@@ -1329,7 +1321,6 @@ static int dw_i3c_master_disable_hotjoin(struct i3c_master_controller *m)
writel(readl(master->regs + DEVICE_CTRL) | DEV_CTRL_HOT_JOIN_NACK,
master->regs + DEVICE_CTRL);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
@@ -1355,7 +1346,6 @@ static int dw_i3c_master_enable_ibi(struct i3c_dev_desc *dev)
if (rc) {
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
}
@@ -1375,7 +1365,6 @@ static int dw_i3c_master_disable_ibi(struct i3c_dev_desc *dev)
dw_i3c_master_set_sir_enabled(master, dev, data->index, false);
pm_runtime_mark_last_busy(master->dev);
pm_runtime_put_autosuspend(master->dev);
return 0;
}
@@ -1403,7 +1392,6 @@ static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master,
struct dw_i3c_i2c_dev_data *data;
struct i3c_ibi_slot *slot;
struct i3c_dev_desc *dev;
unsigned long flags;
u8 addr, len;
int idx;
@@ -1421,7 +1409,7 @@ static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master,
* a new platform op to validate it.
*/
spin_lock_irqsave(&master->devs_lock, flags);
guard(spinlock_irqsave)(&master->devs_lock);
idx = dw_i3c_master_get_addr_pos(master, addr);
if (idx < 0) {
dev_dbg_ratelimited(&master->base.dev,
@@ -1457,14 +1445,10 @@ static void dw_i3c_master_handle_ibi_sir(struct dw_i3c_master *master,
}
i3c_master_queue_ibi(dev, slot);
spin_unlock_irqrestore(&master->devs_lock, flags);
return;
err_drain:
dw_i3c_master_drain_ibi_queue(master, len);
spin_unlock_irqrestore(&master->devs_lock, flags);
}
/* "ibis": referring to In-Band Interrupts, and not
@@ -1477,7 +1461,11 @@ static void dw_i3c_master_irq_handle_ibis(struct dw_i3c_master *master)
u32 reg;
reg = readl(master->regs + QUEUE_STATUS_LEVEL);
n_ibis = QUEUE_STATUS_IBI_STATUS_CNT(reg);
if (master->has_ibi_data)
n_ibis = QUEUE_STATUS_IBI_STATUS_CNT(reg);
else
n_ibis = QUEUE_STATUS_IBI_BUF_BLR(reg);
if (!n_ibis)
return;
@@ -1522,6 +1510,40 @@ static irqreturn_t dw_i3c_master_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int dw_i3c_master_set_dev_nack_retry(struct i3c_master_controller *m,
unsigned int dev_nack_retry_cnt)
{
struct dw_i3c_master *master = to_dw_i3c_master(m);
u32 reg;
int i;
if (dev_nack_retry_cnt > DW_I3C_DEV_NACK_RETRY_CNT_MAX) {
dev_err(&master->base.dev,
"Value %u exceeds maximum %d\n",
dev_nack_retry_cnt, DW_I3C_DEV_NACK_RETRY_CNT_MAX);
return -ERANGE;
}
/*
* Update DAT entries for all currently attached devices.
* We directly iterate through the master's device array.
*/
for (i = 0; i < master->maxdevs; i++) {
/* Skip free/empty slots */
if (master->free_pos & BIT(i))
continue;
reg = readl(master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, i));
reg &= ~DEV_ADDR_TABLE_DEV_NACK_RETRY_MASK;
reg |= DEV_ADDR_TABLE_DEV_NACK_RETRY_CNT(dev_nack_retry_cnt);
writel(reg, master->regs +
DEV_ADDR_TABLE_LOC(master->datstartaddr, i));
}
return 0;
}
static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
.bus_init = dw_i3c_master_bus_init,
.bus_cleanup = dw_i3c_master_bus_cleanup,
@@ -1531,7 +1553,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
.do_daa = dw_i3c_master_daa,
.supports_ccc_cmd = dw_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = dw_i3c_master_send_ccc_cmd,
.priv_xfers = dw_i3c_master_priv_xfers,
.i3c_xfers = dw_i3c_master_i3c_xfers,
.attach_i2c_dev = dw_i3c_master_attach_i2c_dev,
.detach_i2c_dev = dw_i3c_master_detach_i2c_dev,
.i2c_xfers = dw_i3c_master_i2c_xfers,
@@ -1542,6 +1564,7 @@ static const struct i3c_master_controller_ops dw_mipi_i3c_ops = {
.recycle_ibi_slot = dw_i3c_master_recycle_ibi_slot,
.enable_hotjoin = dw_i3c_master_enable_hotjoin,
.disable_hotjoin = dw_i3c_master_disable_hotjoin,
.set_dev_nack_retry = dw_i3c_master_set_dev_nack_retry,
};
/* default platform ops implementations */
@@ -1573,6 +1596,7 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
struct platform_device *pdev)
{
int ret, irq;
u32 thld_ctrl;
const struct dw_i3c_drvdata *drvdata;
unsigned long quirks = 0;
@@ -1581,35 +1605,49 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
master->dev = &pdev->dev;
if (has_acpi_companion(&pdev->dev)) {
quirks = (unsigned long)device_get_match_data(&pdev->dev);
} else if (pdev->dev.of_node) {
drvdata = device_get_match_data(&pdev->dev);
if (drvdata)
quirks = drvdata->flags;
}
master->quirks = quirks;
master->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(master->regs))
return PTR_ERR(master->regs);
master->core_clk = devm_clk_get_enabled(&pdev->dev, NULL);
master->core_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(master->core_clk))
return PTR_ERR(master->core_clk);
if (!master->core_clk && !(master->quirks & DW_I3C_ACPI_SKIP_CLK_RST)) {
dev_err(&pdev->dev, "missing core clock\n");
return -EINVAL;
}
master->pclk = devm_clk_get_optional_enabled(&pdev->dev, "pclk");
if (IS_ERR(master->pclk))
return PTR_ERR(master->pclk);
master->core_rst = devm_reset_control_get_optional_exclusive(&pdev->dev,
"core_rst");
master->core_rst = devm_reset_control_get_optional_exclusive_deasserted(&pdev->dev,
"core_rst");
if (IS_ERR(master->core_rst))
return PTR_ERR(master->core_rst);
reset_control_deassert(master->core_rst);
spin_lock_init(&master->xferqueue.lock);
INIT_LIST_HEAD(&master->xferqueue.list);
spin_lock_init(&master->devs_lock);
writel(INTR_ALL, master->regs + INTR_STATUS);
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, irq,
dw_i3c_master_irq_handler, 0,
dev_name(&pdev->dev), master);
if (ret)
goto err_assert_rst;
return ret;
platform_set_drvdata(pdev, master);
@@ -1630,20 +1668,27 @@ int dw_i3c_common_probe(struct dw_i3c_master *master,
master->maxdevs = ret >> 16;
master->free_pos = GENMASK(master->maxdevs - 1, 0);
if (has_acpi_companion(&pdev->dev)) {
quirks = (unsigned long)device_get_match_data(&pdev->dev);
} else if (pdev->dev.of_node) {
drvdata = device_get_match_data(&pdev->dev);
if (drvdata)
quirks = drvdata->flags;
}
master->quirks = quirks;
/*
* Detect IBI data capability (IC_HAS_IBI_DATA): write a non-zero value
* to IBI_DATA_THLD and read back. On controllers like Versalnet
* the field is hardwired to 0 and the write is ignored. Restore the
* original register value after detection.
*/
thld_ctrl = readl(master->regs + QUEUE_THLD_CTRL);
ret = thld_ctrl | QUEUE_THLD_CTRL_IBI_DATA(2);
writel(ret, master->regs + QUEUE_THLD_CTRL);
ret = readl(master->regs + QUEUE_THLD_CTRL);
if (ret & QUEUE_THLD_CTRL_IBI_DATA_MASK)
master->has_ibi_data = true;
writel(thld_ctrl, master->regs + QUEUE_THLD_CTRL);
/* Keep controller enabled by preventing runtime suspend */
if (master->quirks & DW_I3C_DISABLE_RUNTIME_PM_QUIRK)
pm_runtime_get_noresume(&pdev->dev);
INIT_WORK(&master->hj_work, dw_i3c_hj_work);
device_set_of_node_from_dev(&master->base.i2c.dev, &pdev->dev);
ret = i3c_master_register(&master->base, &pdev->dev,
&dw_mipi_i3c_ops, false);
if (ret)
@@ -1658,9 +1703,6 @@ err_disable_pm:
pm_runtime_set_suspended(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
err_assert_rst:
reset_control_assert(master->core_rst);
return ret;
}
EXPORT_SYMBOL_GPL(dw_i3c_common_probe);
@@ -1711,11 +1753,16 @@ static void dw_i3c_master_restore_addrs(struct dw_i3c_master *master)
if (master->free_pos & BIT(pos))
continue;
if (master->devs[pos].is_i2c_addr)
reg_val = DEV_ADDR_TABLE_LEGACY_I2C_DEV |
reg_val = readl(master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, pos));
if (master->devs[pos].is_i2c_addr) {
reg_val &= ~DEV_ADDR_TABLE_STATIC_MASK;
reg_val |= DEV_ADDR_TABLE_LEGACY_I2C_DEV |
DEV_ADDR_TABLE_STATIC_ADDR(master->devs[pos].addr);
else
reg_val = DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr);
} else {
reg_val &= ~DEV_ADDR_TABLE_DYNAMIC_MASK;
reg_val |= DEV_ADDR_TABLE_DYNAMIC_ADDR(master->devs[pos].addr);
}
writel(reg_val, master->regs + DEV_ADDR_TABLE_LOC(master->datstartaddr, pos));
}
@@ -1829,11 +1876,12 @@ 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[] = {
static const struct acpi_device_id dw_i3c_master_acpi_match[] = {
{ "AMDI0015", AMD_I3C_OD_PP_TIMING },
{ "NVDA2018", DW_I3C_ACPI_SKIP_CLK_RST },
{ }
};
MODULE_DEVICE_TABLE(acpi, amd_i3c_device_match);
MODULE_DEVICE_TABLE(acpi, dw_i3c_master_acpi_match);
static struct platform_driver dw_i3c_driver = {
.probe = dw_i3c_probe,
@@ -1842,7 +1890,7 @@ static struct platform_driver dw_i3c_driver = {
.driver = {
.name = "dw-i3c-master",
.of_match_table = dw_i3c_master_of_match,
.acpi_match_table = amd_i3c_device_match,
.acpi_match_table = dw_i3c_master_acpi_match,
.pm = &dw_i3c_pm_ops,
},
};
+1
View File
@@ -51,6 +51,7 @@ struct dw_i3c_master {
u32 i2c_fm_timing;
u32 i2c_fmp_timing;
u32 quirks;
bool has_ibi_data;
/*
* Per-device hardware data, used to manage the device address table
* (DAT)
+13 -28
View File
@@ -23,6 +23,8 @@
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include "../internals.h"
#define DEV_ID 0x0
#define DEV_ID_I3C_MASTER 0x5034
@@ -427,25 +429,13 @@ to_cdns_i3c_master(struct i3c_master_controller *master)
static void cdns_i3c_master_wr_to_tx_fifo(struct cdns_i3c_master *master,
const u8 *bytes, int nbytes)
{
writesl(master->regs + TX_FIFO, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp = 0;
memcpy(&tmp, bytes + (nbytes & ~3), nbytes & 3);
writesl(master->regs + TX_FIFO, &tmp, 1);
}
i3c_writel_fifo(master->regs + TX_FIFO, bytes, nbytes);
}
static void cdns_i3c_master_rd_from_rx_fifo(struct cdns_i3c_master *master,
u8 *bytes, int nbytes)
{
readsl(master->regs + RX_FIFO, bytes, nbytes / 4);
if (nbytes & 3) {
u32 tmp;
readsl(master->regs + RX_FIFO, &tmp, 1);
memcpy(bytes + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_readl_fifo(master->regs + RX_FIFO, bytes, nbytes);
}
static bool cdns_i3c_master_supports_ccc_cmd(struct i3c_master_controller *m,
@@ -509,7 +499,7 @@ cdns_i3c_master_alloc_xfer(struct cdns_i3c_master *master, unsigned int ncmds)
{
struct cdns_i3c_xfer *xfer;
xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
xfer = kzalloc_flex(*xfer, cmds, ncmds, GFP_KERNEL);
if (!xfer)
return NULL;
@@ -731,9 +721,9 @@ static int cdns_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
return ret;
}
static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *xfers,
int nxfers)
static int cdns_i3c_master_i3c_xfers(struct i3c_dev_desc *dev,
struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct cdns_i3c_master *master = to_cdns_i3c_master(m);
@@ -813,7 +803,7 @@ static int cdns_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
}
static int cdns_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
const struct i2c_msg *xfers, int nxfers)
struct i2c_msg *xfers, int nxfers)
{
struct i3c_master_controller *m = i2c_dev_get_master(dev);
struct cdns_i3c_master *master = to_cdns_i3c_master(m);
@@ -952,7 +942,7 @@ static int cdns_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
struct cdns_i3c_i2c_dev_data *data;
int slot;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
@@ -1003,7 +993,7 @@ static int cdns_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
if (slot < 0)
return slot;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data)
return -ENOMEM;
@@ -1331,12 +1321,7 @@ static void cdns_i3c_master_handle_ibi(struct cdns_i3c_master *master,
buf = slot->data;
nbytes = IBIR_XFER_BYTES(ibir);
readsl(master->regs + IBI_DATA_FIFO, buf, nbytes / 4);
if (nbytes % 3) {
u32 tmp = __raw_readl(master->regs + IBI_DATA_FIFO);
memcpy(buf + (nbytes & ~3), &tmp, nbytes & 3);
}
i3c_readl_fifo(master->regs + IBI_DATA_FIFO, buf, nbytes);
slot->len = min_t(unsigned int, IBIR_XFER_BYTES(ibir),
dev->ibi->max_payload_len);
@@ -1536,7 +1521,7 @@ static const struct i3c_master_controller_ops cdns_i3c_master_ops = {
.detach_i2c_dev = cdns_i3c_master_detach_i2c_dev,
.supports_ccc_cmd = cdns_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = cdns_i3c_master_send_ccc_cmd,
.priv_xfers = cdns_i3c_master_priv_xfers,
.i3c_xfers = cdns_i3c_master_i3c_xfers,
.i2c_xfers = cdns_i3c_master_i2c_xfers,
.enable_ibi = cdns_i3c_master_enable_ibi,
.disable_ibi = cdns_i3c_master_disable_ibi,
+8 -44
View File
@@ -274,37 +274,9 @@ static int i3c_hci_daa(struct i3c_master_controller *m)
return hci->cmd->perform_daa(hci);
}
static int i3c_hci_alloc_safe_xfer_buf(struct i3c_hci *hci,
struct hci_xfer *xfer)
{
if (hci->io != &mipi_i3c_hci_dma ||
xfer->data == NULL || !is_vmalloc_addr(xfer->data))
return 0;
if (xfer->rnw)
xfer->bounce_buf = kzalloc(xfer->data_len, GFP_KERNEL);
else
xfer->bounce_buf = kmemdup(xfer->data,
xfer->data_len, GFP_KERNEL);
return xfer->bounce_buf == NULL ? -ENOMEM : 0;
}
static void i3c_hci_free_safe_xfer_buf(struct i3c_hci *hci,
struct hci_xfer *xfer)
{
if (hci->io != &mipi_i3c_hci_dma || xfer->bounce_buf == NULL)
return;
if (xfer->rnw)
memcpy(xfer->data, xfer->bounce_buf, xfer->data_len);
kfree(xfer->bounce_buf);
}
static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *i3c_xfers,
int nxfers)
static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
struct i3c_xfer *i3c_xfers, int nxfers,
enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct i3c_hci *hci = to_i3c_hci(m);
@@ -335,9 +307,6 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
}
hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i]);
xfer[i].cmd_desc[0] |= CMD_0_ROC;
ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
if (ret)
goto out;
}
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -361,15 +330,12 @@ static int i3c_hci_priv_xfers(struct i3c_dev_desc *dev,
}
out:
for (i = 0; i < nxfers; i++)
i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
hci_free_xfer(xfer, nxfers);
return ret;
}
static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
const struct i2c_msg *i2c_xfers, int nxfers)
struct i2c_msg *i2c_xfers, int nxfers)
{
struct i3c_master_controller *m = i2c_dev_get_master(dev);
struct i3c_hci *hci = to_i3c_hci(m);
@@ -384,14 +350,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
return -ENOMEM;
for (i = 0; i < nxfers; i++) {
xfer[i].data = i2c_xfers[i].buf;
xfer[i].data = i2c_get_dma_safe_msg_buf(&i2c_xfers[i], 1);
xfer[i].data_len = i2c_xfers[i].len;
xfer[i].rnw = i2c_xfers[i].flags & I2C_M_RD;
hci->cmd->prep_i2c_xfer(hci, dev, &xfer[i]);
xfer[i].cmd_desc[0] |= CMD_0_ROC;
ret = i3c_hci_alloc_safe_xfer_buf(hci, &xfer[i]);
if (ret)
goto out;
}
last = i - 1;
xfer[last].cmd_desc[0] |= CMD_0_TOC;
@@ -414,7 +377,8 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
out:
for (i = 0; i < nxfers; i++)
i3c_hci_free_safe_xfer_buf(hci, &xfer[i]);
i2c_put_dma_safe_msg_buf(xfer[i].data, &i2c_xfers[i],
ret ? false : true);
hci_free_xfer(xfer, nxfers);
return ret;
@@ -572,7 +536,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = {
.bus_cleanup = i3c_hci_bus_cleanup,
.do_daa = i3c_hci_daa,
.send_ccc_cmd = i3c_hci_send_ccc_cmd,
.priv_xfers = i3c_hci_priv_xfers,
.i3c_xfers = i3c_hci_i3c_xfers,
.i2c_xfers = i3c_hci_i2c_xfers,
.attach_i3c_dev = i3c_hci_attach_i3c_dev,
.reattach_i3c_dev = i3c_hci_reattach_i3c_dev,
+11 -16
View File
@@ -349,9 +349,7 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
xfer = xfer_list + i;
if (!xfer->data)
continue;
dma_unmap_single(&hci->master.dev,
xfer->data_dma, xfer->data_len,
xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
i3c_master_dma_unmap_single(xfer->dma);
}
}
@@ -362,7 +360,6 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
struct hci_rh_data *rh;
unsigned int i, ring, enqueue_ptr;
u32 op1_val, op2_val;
void *buf;
/* For now we only use ring 0 */
ring = 0;
@@ -373,6 +370,8 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
for (i = 0; i < n; i++) {
struct hci_xfer *xfer = xfer_list + i;
u32 *ring_data = rh->xfer + rh->xfer_struct_sz * enqueue_ptr;
enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE :
DMA_TO_DEVICE;
/* store cmd descriptor */
*ring_data++ = xfer->cmd_desc[0];
@@ -391,21 +390,17 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
/* 2nd and 3rd words of Data Buffer Descriptor Structure */
if (xfer->data) {
buf = xfer->bounce_buf ? xfer->bounce_buf : xfer->data;
xfer->data_dma =
dma_map_single(&hci->master.dev,
buf,
xfer->data_len,
xfer->rnw ?
DMA_FROM_DEVICE :
DMA_TO_DEVICE);
if (dma_mapping_error(&hci->master.dev,
xfer->data_dma)) {
xfer->dma = i3c_master_dma_map_single(&hci->master.dev,
xfer->data,
xfer->data_len,
false,
dir);
if (!xfer->dma) {
hci_dma_unmap_xfer(hci, xfer_list, i);
return -ENOMEM;
}
*ring_data++ = lower_32_bits(xfer->data_dma);
*ring_data++ = upper_32_bits(xfer->data_dma);
*ring_data++ = lower_32_bits(xfer->dma->addr);
*ring_data++ = upper_32_bits(xfer->dma->addr);
} else {
*ring_data++ = 0;
*ring_data++ = 0;
+1 -2
View File
@@ -94,8 +94,7 @@ struct hci_xfer {
};
struct {
/* DMA specific */
dma_addr_t data_dma;
void *bounce_buf;
struct i3c_dma *dma;
int ring_number;
int ring_entry;
};
+106 -25
View File
@@ -39,11 +39,13 @@
#define SVC_I3C_MCTRL_REQUEST_NONE 0
#define SVC_I3C_MCTRL_REQUEST_START_ADDR 1
#define SVC_I3C_MCTRL_REQUEST_STOP 2
#define SVC_I3C_MCTRL_REQUEST_FORCE_EXIT 6
#define SVC_I3C_MCTRL_REQUEST_IBI_ACKNACK 3
#define SVC_I3C_MCTRL_REQUEST_PROC_DAA 4
#define SVC_I3C_MCTRL_REQUEST_AUTO_IBI 7
#define SVC_I3C_MCTRL_TYPE_I3C 0
#define SVC_I3C_MCTRL_TYPE_I2C BIT(4)
#define SVC_I3C_MCTRL_TYPE_DDR BIT(5)
#define SVC_I3C_MCTRL_IBIRESP_AUTO 0
#define SVC_I3C_MCTRL_IBIRESP_ACK_WITHOUT_BYTE 0
#define SVC_I3C_MCTRL_IBIRESP_ACK_WITH_BYTE BIT(7)
@@ -93,6 +95,7 @@
#define SVC_I3C_MINTMASKED 0x098
#define SVC_I3C_MERRWARN 0x09C
#define SVC_I3C_MERRWARN_NACK BIT(2)
#define SVC_I3C_MERRWARN_CRC BIT(10)
#define SVC_I3C_MERRWARN_TIMEOUT BIT(20)
#define SVC_I3C_MDMACTRL 0x0A0
#define SVC_I3C_MDATACTRL 0x0AC
@@ -135,12 +138,16 @@
struct svc_i3c_cmd {
u8 addr;
bool rnw;
union {
bool rnw;
u8 cmd;
u32 rnw_cmd;
};
u8 *in;
const void *out;
unsigned int len;
unsigned int actual_len;
struct i3c_priv_xfer *xfer;
struct i3c_xfer *xfer;
bool continued;
};
@@ -337,6 +344,36 @@ svc_i3c_master_dev_from_addr(struct svc_i3c_master *master,
return master->descs[i];
}
static bool svc_cmd_is_read(u32 rnw_cmd, u32 type)
{
return (type == SVC_I3C_MCTRL_TYPE_DDR) ? (rnw_cmd & 0x80) : rnw_cmd;
}
static void svc_i3c_master_emit_force_exit(struct svc_i3c_master *master)
{
u32 reg;
writel(SVC_I3C_MCTRL_REQUEST_FORCE_EXIT, master->regs + SVC_I3C_MCTRL);
/*
* Not need check error here because it is never happen at hardware.
* IP just wait for few fclk cycle to complete DDR exit pattern. Even
* though fclk stop, timeout happen here, the whole data actually
* already finish transfer. The next command will be timeout because
* wrong hardware state.
*/
readl_poll_timeout_atomic(master->regs + SVC_I3C_MSTATUS, reg,
SVC_I3C_MSTATUS_MCTRLDONE(reg), 0, 1000);
/*
* This delay is necessary after the emission of a stop, otherwise eg.
* repeating IBIs do not get detected. There is a note in the manual
* about it, stating that the stop condition might not be settled
* correctly if a start condition follows too rapidly.
*/
udelay(1);
}
static void svc_i3c_master_emit_stop(struct svc_i3c_master *master)
{
writel(SVC_I3C_MCTRL_REQUEST_STOP, master->regs + SVC_I3C_MCTRL);
@@ -426,7 +463,7 @@ static void svc_i3c_master_ibi_work(struct work_struct *work)
* cycle, leading to missed client IBI handlers.
*
* A typical scenario is when IBIWON occurs and bus arbitration is lost
* at svc_i3c_master_priv_xfers().
* at svc_i3c_master_i3c_xfers().
*
* Clear SVC_I3C_MINT_IBIWON before sending SVC_I3C_MCTRL_REQUEST_AUTO_IBI.
*/
@@ -682,6 +719,8 @@ static int svc_i3c_master_bus_init(struct i3c_master_controller *m)
info.dyn_addr = ret;
info.hdr_cap = I3C_CCC_HDR_MODE(I3C_HDR_DDR);
writel(SVC_MDYNADDR_VALID | SVC_MDYNADDR_ADDR(info.dyn_addr),
master->regs + SVC_I3C_MDYNADDR);
@@ -747,7 +786,7 @@ static int svc_i3c_master_attach_i3c_dev(struct i3c_dev_desc *dev)
if (slot < 0)
return slot;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data) {
svc_i3c_master_release_slot(master, slot);
return -ENOMEM;
@@ -800,7 +839,7 @@ static int svc_i3c_master_attach_i2c_dev(struct i2c_dev_desc *dev)
if (slot < 0)
return slot;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = kzalloc_obj(*data);
if (!data) {
svc_i3c_master_release_slot(master, slot);
return -ENOMEM;
@@ -1066,7 +1105,7 @@ static int svc_i3c_master_do_daa(struct i3c_master_controller *m)
/* Configure IBI auto-rules */
ret = svc_i3c_update_ibirules(master);
if (ret)
dev_err(master->dev, "Cannot handle such a list of devices");
dev_err(master->dev, "Cannot handle such a list of devices\n");
rpm_out:
pm_runtime_mark_last_busy(master->dev);
@@ -1137,17 +1176,28 @@ static int svc_i3c_master_write(struct svc_i3c_master *master,
}
static int svc_i3c_master_xfer(struct svc_i3c_master *master,
bool rnw, unsigned int xfer_type, u8 addr,
u32 rnw_cmd, unsigned int xfer_type, u8 addr,
u8 *in, const u8 *out, unsigned int xfer_len,
unsigned int *actual_len, bool continued)
unsigned int *actual_len, bool continued, bool repeat_start)
{
int retry = 2;
bool rnw = svc_cmd_is_read(rnw_cmd, xfer_type);
int retry = repeat_start ? 1 : 2;
u32 reg;
int ret;
/* clean SVC_I3C_MINT_IBIWON w1c bits */
writel(SVC_I3C_MINT_IBIWON, master->regs + SVC_I3C_MSTATUS);
if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR) {
/* DDR command need prefill into FIFO */
writel(rnw_cmd, master->regs + SVC_I3C_MWDATAB);
if (!rnw) {
/* write data also need prefill into FIFO */
ret = svc_i3c_master_write(master, out, xfer_len);
if (ret)
goto emit_stop;
}
}
while (retry--) {
writel(SVC_I3C_MCTRL_REQUEST_START_ADDR |
@@ -1216,7 +1266,7 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
if (rnw)
ret = svc_i3c_master_read(master, in, xfer_len);
else
else if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
ret = svc_i3c_master_write(master, out, xfer_len);
if (ret < 0)
goto emit_stop;
@@ -1229,10 +1279,19 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
if (ret)
goto emit_stop;
if (xfer_type == SVC_I3C_MCTRL_TYPE_DDR &&
(readl(master->regs + SVC_I3C_MERRWARN) & SVC_I3C_MERRWARN_CRC)) {
ret = -ENXIO;
goto emit_stop;
}
writel(SVC_I3C_MINT_COMPLETE, master->regs + SVC_I3C_MSTATUS);
if (!continued) {
svc_i3c_master_emit_stop(master);
if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
svc_i3c_master_emit_stop(master);
else
svc_i3c_master_emit_force_exit(master);
/* Wait idle if stop is sent. */
readl_poll_timeout(master->regs + SVC_I3C_MSTATUS, reg,
@@ -1242,7 +1301,11 @@ static int svc_i3c_master_xfer(struct svc_i3c_master *master,
return 0;
emit_stop:
svc_i3c_master_emit_stop(master);
if (xfer_type != SVC_I3C_MCTRL_TYPE_DDR)
svc_i3c_master_emit_stop(master);
else
svc_i3c_master_emit_force_exit(master);
svc_i3c_master_clear_merrwarn(master);
return ret;
@@ -1253,7 +1316,7 @@ svc_i3c_master_alloc_xfer(struct svc_i3c_master *master, unsigned int ncmds)
{
struct svc_i3c_xfer *xfer;
xfer = kzalloc(struct_size(xfer, cmds, ncmds), GFP_KERNEL);
xfer = kzalloc_flex(*xfer, cmds, ncmds, GFP_KERNEL);
if (!xfer)
return NULL;
@@ -1288,6 +1351,11 @@ static void svc_i3c_master_dequeue_xfer(struct svc_i3c_master *master,
spin_unlock_irqrestore(&master->xferqueue.lock, flags);
}
static int i3c_mode_to_svc_type(enum i3c_xfer_mode mode)
{
return (mode == I3C_SDR) ? SVC_I3C_MCTRL_TYPE_I3C : SVC_I3C_MCTRL_TYPE_DDR;
}
static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
{
struct svc_i3c_xfer *xfer = master->xferqueue.cur;
@@ -1302,10 +1370,10 @@ static void svc_i3c_master_start_xfer_locked(struct svc_i3c_master *master)
for (i = 0; i < xfer->ncmds; i++) {
struct svc_i3c_cmd *cmd = &xfer->cmds[i];
ret = svc_i3c_master_xfer(master, cmd->rnw, xfer->type,
ret = svc_i3c_master_xfer(master, cmd->rnw_cmd, xfer->type,
cmd->addr, cmd->in, cmd->out,
cmd->len, &cmd->actual_len,
cmd->continued);
cmd->continued, i > 0);
/* cmd->xfer is NULL if I2C or CCC transfer */
if (cmd->xfer)
cmd->xfer->actual_len = cmd->actual_len;
@@ -1478,9 +1546,8 @@ static int svc_i3c_master_send_ccc_cmd(struct i3c_master_controller *m,
return ret;
}
static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *xfers,
int nxfers)
static int svc_i3c_master_i3c_xfers(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode)
{
struct i3c_master_controller *m = i3c_dev_get_master(dev);
struct svc_i3c_master *master = to_svc_i3c_master(m);
@@ -1488,22 +1555,36 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
struct svc_i3c_xfer *xfer;
int ret, i;
if (mode != I3C_SDR) {
/*
* Only support data size less than FIFO SIZE when using DDR
* mode. First entry is cmd in FIFO, so actual available FIFO
* for data is SVC_I3C_FIFO_SIZE - 2 since DDR only supports
* even length.
*/
for (i = 0; i < nxfers; i++)
if (xfers[i].len > SVC_I3C_FIFO_SIZE - 2)
return -EINVAL;
}
xfer = svc_i3c_master_alloc_xfer(master, nxfers);
if (!xfer)
return -ENOMEM;
xfer->type = SVC_I3C_MCTRL_TYPE_I3C;
xfer->type = i3c_mode_to_svc_type(mode);
for (i = 0; i < nxfers; i++) {
u32 rnw_cmd = (mode == I3C_SDR) ? xfers[i].rnw : xfers[i].cmd;
bool rnw = svc_cmd_is_read(rnw_cmd, xfer->type);
struct svc_i3c_cmd *cmd = &xfer->cmds[i];
cmd->xfer = &xfers[i];
cmd->addr = master->addrs[data->index];
cmd->rnw = xfers[i].rnw;
cmd->in = xfers[i].rnw ? xfers[i].data.in : NULL;
cmd->out = xfers[i].rnw ? NULL : xfers[i].data.out;
cmd->rnw_cmd = rnw_cmd;
cmd->in = rnw ? xfers[i].data.in : NULL;
cmd->out = rnw ? NULL : xfers[i].data.out;
cmd->len = xfers[i].len;
cmd->actual_len = xfers[i].rnw ? xfers[i].len : 0;
cmd->actual_len = rnw ? xfers[i].len : 0;
cmd->continued = (i + 1) < nxfers;
}
@@ -1520,7 +1601,7 @@ static int svc_i3c_master_priv_xfers(struct i3c_dev_desc *dev,
}
static int svc_i3c_master_i2c_xfers(struct i2c_dev_desc *dev,
const struct i2c_msg *xfers,
struct i2c_msg *xfers,
int nxfers)
{
struct i3c_master_controller *m = i2c_dev_get_master(dev);
@@ -1700,7 +1781,7 @@ static const struct i3c_master_controller_ops svc_i3c_master_ops = {
.do_daa = svc_i3c_master_do_daa,
.supports_ccc_cmd = svc_i3c_master_supports_ccc_cmd,
.send_ccc_cmd = svc_i3c_master_send_ccc_cmd,
.priv_xfers = svc_i3c_master_priv_xfers,
.i3c_xfers = svc_i3c_master_i3c_xfers,
.i2c_xfers = svc_i3c_master_i2c_xfers,
.request_ibi = svc_i3c_master_request_ibi,
.free_ibi = svc_i3c_master_free_ibi,
+1
View File
@@ -423,6 +423,7 @@ struct acpi_resource_i2c_serialbus {
ACPI_RESOURCE_SERIAL_COMMON u8 access_mode;
u16 slave_address;
u32 connection_speed;
u8 lvr;
};
/* Values for access_mode field above */
+4
View File
@@ -13,4 +13,8 @@
#define I2C_NO_FILTER_HIGH_FREQUENCY (1 << 5)
#define I2C_NO_FILTER_LOW_FREQUENCY (2 << 5)
#define I3C_ADDR_METHOD_SETDASA (1 << 0)
#define I3C_ADDR_METHOD_SETAASA (1 << 1)
#define I3C_ADDR_METHOD_VENDOR (1 << 2)
#endif
+1
View File
@@ -32,6 +32,7 @@
#define I3C_CCC_DEFSLVS I3C_CCC_ID(0x8, true)
#define I3C_CCC_ENTTM I3C_CCC_ID(0xb, true)
#define I3C_CCC_ENTHDR(x) I3C_CCC_ID(0x20 + (x), true)
#define I3C_CCC_SETAASA I3C_CCC_ID(0x29, true)
/* Unicast-only commands */
#define I3C_CCC_SETDASA I3C_CCC_ID(0x7, false)
+30 -12
View File
@@ -27,7 +27,7 @@
* These are the standard error codes as defined by the I3C specification.
* When -EIO is returned by the i3c_device_do_priv_xfers() or
* i3c_device_send_hdr_cmds() one can check the error code in
* &struct_i3c_priv_xfer.err or &struct i3c_hdr_cmd.err to get a better idea of
* &struct_i3c_xfer.err or &struct i3c_hdr_cmd.err to get a better idea of
* what went wrong.
*
*/
@@ -39,20 +39,25 @@ enum i3c_error_code {
};
/**
* enum i3c_hdr_mode - HDR mode ids
* enum i3c_xfer_mode - I3C xfer mode ids
* @I3C_HDR_DDR: DDR mode
* @I3C_HDR_TSP: TSP mode
* @I3C_HDR_TSL: TSL mode
* @I3C_SDR: SDR mode (NOT HDR mode)
*/
enum i3c_hdr_mode {
I3C_HDR_DDR,
I3C_HDR_TSP,
I3C_HDR_TSL,
enum i3c_xfer_mode {
/* The below 3 value (I3C_HDR*) must match GETCAP1 Byte bit position */
I3C_HDR_DDR = 0,
I3C_HDR_TSP = 1,
I3C_HDR_TSL = 2,
/* Use for default SDR transfer mode */
I3C_SDR = 0x31,
};
/**
* struct i3c_priv_xfer - I3C SDR private transfer
* struct i3c_xfer - I3C data transfer
* @rnw: encodes the transfer direction. true for a read, false for a write
* @cmd: Read/Write command in HDR mode, read: 0x80 - 0xff, write: 0x00 - 0x7f
* @len: transfer length in bytes of the transfer
* @actual_len: actual length in bytes are transferred by the controller
* @data: input/output buffer
@@ -60,8 +65,11 @@ enum i3c_hdr_mode {
* @data.out: output buffer. Must point to a DMA-able buffer
* @err: I3C error code
*/
struct i3c_priv_xfer {
u8 rnw;
struct i3c_xfer {
union {
u8 rnw;
u8 cmd;
};
u16 len;
u16 actual_len;
union {
@@ -71,6 +79,9 @@ struct i3c_priv_xfer {
enum i3c_error_code err;
};
/* keep back compatible */
#define i3c_priv_xfer i3c_xfer
/**
* enum i3c_dcr - I3C DCR values
* @I3C_DCR_GENERIC_DEVICE: generic I3C device
@@ -297,9 +308,15 @@ static inline void i3c_i2c_driver_unregister(struct i3c_driver *i3cdrv,
i3c_i2c_driver_unregister, \
__i2cdrv)
int i3c_device_do_priv_xfers(struct i3c_device *dev,
struct i3c_priv_xfer *xfers,
int nxfers);
int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode);
static inline int i3c_device_do_priv_xfers(struct i3c_device *dev,
struct i3c_xfer *xfers,
int nxfers)
{
return i3c_device_do_xfers(dev, xfers, nxfers, I3C_SDR);
}
int i3c_device_do_setdasa(struct i3c_device *dev);
@@ -341,5 +358,6 @@ int i3c_device_request_ibi(struct i3c_device *dev,
void i3c_device_free_ibi(struct i3c_device *dev);
int i3c_device_enable_ibi(struct i3c_device *dev);
int i3c_device_disable_ibi(struct i3c_device *dev);
u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev);
#endif /* I3C_DEV_H */
+81 -15
View File
@@ -174,10 +174,19 @@ struct i3c_device_ibi_info {
* assigned a dynamic address by the master. Will be used during
* bus initialization to assign it a specific dynamic address
* before starting DAA (Dynamic Address Assignment)
* @static_addr_method: Bitmap describing which methods of Dynamic Address
* Assignment from a Static Address are supported by this I3C Target.
* A value of 1 in a bit position indicates that the I3C target
* supports that method, and a value of 0 indicates that the I3C
* target does not support that method.
* Bit 0: SETDASA
* Bit 1: SETAASA
* All other bits are reserved.
* @pid: I3C Provisioned ID exposed by the device. This is a unique identifier
* that may be used to attach boardinfo to i3c_dev_desc when the device
* does not have a static address
* @of_node: optional DT node in case the device has been described in the DT
* @fwnode: Firmware node (DT or ACPI) in case the device has been
* described in firmware
*
* This structure is used to attach board-level information to an I3C device.
* Not all I3C devices connected on the bus will have a boardinfo. It's only
@@ -188,8 +197,9 @@ struct i3c_dev_boardinfo {
struct list_head node;
u8 init_dyn_addr;
u8 static_addr;
u8 static_addr_method;
u64 pid;
struct device_node *of_node;
struct fwnode_handle *fwnode;
};
/**
@@ -249,10 +259,15 @@ struct i3c_device {
*/
#define I3C_BUS_MAX_DEVS 11
#define I3C_BUS_MAX_I3C_SCL_RATE 12900000
#define I3C_BUS_TYP_I3C_SCL_RATE 12500000
#define I3C_BUS_I2C_FM_PLUS_SCL_RATE 1000000
#define I3C_BUS_I2C_FM_SCL_RATE 400000
/* Taken from the I3C Spec V1.1.1, chapter 6.2. "Timing specification" */
#define I3C_BUS_I2C_FM_PLUS_SCL_MAX_RATE 1000000
#define I3C_BUS_I2C_FM_SCL_MAX_RATE 400000
#define I3C_BUS_I3C_SCL_MAX_RATE 12900000
#define I3C_BUS_I3C_SCL_TYP_RATE 12500000
#define I3C_BUS_TAVAL_MIN_NS 1000
#define I3C_BUS_TBUF_MIXED_FM_MIN_NS 1300
#define I3C_BUS_THIGH_MIXED_MAX_NS 41
#define I3C_BUS_TIDLE_MIN_NS 200000
#define I3C_BUS_TLOW_OD_MIN_NS 200
/**
@@ -298,7 +313,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 +328,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 +375,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;
@@ -406,8 +427,8 @@ struct i3c_bus {
* all CCC commands are supported.
* @send_ccc_cmd: send a CCC command
* This method is mandatory.
* @priv_xfers: do one or several private I3C SDR transfers
* This method is mandatory.
* @i3c_xfers: do one or several I3C SDR or HDR transfers.
* This method is mandatory.
* @attach_i2c_dev: called every time an I2C device is attached to the bus.
* This is a good place to attach master controller specific
* data to I2C devices.
@@ -451,6 +472,8 @@ struct i3c_bus {
* @enable_hotjoin: enable hot join event detect.
* @disable_hotjoin: disable hot join event detect.
* @set_speed: adjust I3C open drain mode timing.
* @set_dev_nack_retry: configure device NACK retry count for the master
* controller.
*/
struct i3c_master_controller_ops {
int (*bus_init)(struct i3c_master_controller *master);
@@ -463,13 +486,13 @@ struct i3c_master_controller_ops {
const struct i3c_ccc_cmd *cmd);
int (*send_ccc_cmd)(struct i3c_master_controller *master,
struct i3c_ccc_cmd *cmd);
int (*priv_xfers)(struct i3c_dev_desc *dev,
struct i3c_priv_xfer *xfers,
int nxfers);
int (*i3c_xfers)(struct i3c_dev_desc *dev,
struct i3c_xfer *xfers,
int nxfers, enum i3c_xfer_mode mode);
int (*attach_i2c_dev)(struct i2c_dev_desc *dev);
void (*detach_i2c_dev)(struct i2c_dev_desc *dev);
int (*i2c_xfers)(struct i2c_dev_desc *dev,
const struct i2c_msg *xfers, int nxfers);
struct i2c_msg *xfers, int nxfers);
int (*request_ibi)(struct i3c_dev_desc *dev,
const struct i3c_ibi_setup *req);
void (*free_ibi)(struct i3c_dev_desc *dev);
@@ -480,6 +503,8 @@ struct i3c_master_controller_ops {
int (*enable_hotjoin)(struct i3c_master_controller *master);
int (*disable_hotjoin)(struct i3c_master_controller *master);
int (*set_speed)(struct i3c_master_controller *master, enum i3c_open_drain_speed speed);
int (*set_dev_nack_retry)(struct i3c_master_controller *master,
unsigned int dev_nack_retry_cnt);
};
/**
@@ -494,15 +519,23 @@ struct i3c_master_controller_ops {
* @secondary: true if the master is a secondary master
* @init_done: true when the bus initialization is done
* @hotjoin: true if the master support hotjoin
* @rpm_allowed: true if Runtime PM allowed
* @rpm_ibi_allowed: true if IBI and Hot-Join allowed while runtime suspended
* @boardinfo.i3c: list of I3C boardinfo objects
* @boardinfo.i2c: list of I2C boardinfo objects
* @boardinfo: board-level information attached to devices connected on the bus
* @bus: I3C bus exposed by this master
* @wq: workqueue which can be used by master
* @addr_method: Bitmap describing which methods of Address Assignment required
* to be run for discovering all the devices on the bus.
* Bit 0: SETDASA
* Bit 1: SETAASA
* All other bits are reserved.
* @wq: freezable workqueue which can be used by master
* drivers if they need to postpone operations that need to take place
* in a thread context. Typical examples are Hot Join processing which
* requires taking the bus lock in maintenance, which in turn, can only
* be done from a sleep-able context
* @dev_nack_retry_count: retry count when slave device nack
*
* A &struct i3c_master_controller has to be registered to the I3C subsystem
* through i3c_master_register(). None of &struct i3c_master_controller fields
@@ -517,12 +550,16 @@ struct i3c_master_controller {
unsigned int secondary : 1;
unsigned int init_done : 1;
unsigned int hotjoin: 1;
unsigned int rpm_allowed: 1;
unsigned int rpm_ibi_allowed: 1;
struct {
struct list_head i3c;
struct list_head i2c;
} boardinfo;
struct i3c_bus bus;
u8 addr_method;
struct workqueue_struct *wq;
unsigned int dev_nack_retry_count;
};
/**
@@ -547,6 +584,26 @@ struct i3c_master_controller {
#define i3c_bus_for_each_i3cdev(bus, dev) \
list_for_each_entry(dev, &(bus)->devs.i3c, common.node)
/**
* struct i3c_dma - DMA transfer and mapping descriptor
* @dev: device object of a device doing DMA
* @buf: destination/source buffer for DMA
* @len: length of transfer
* @map_len: length of DMA mapping
* @addr: mapped DMA address for a Host Controller Driver
* @dir: DMA direction
* @bounce_buf: an allocated bounce buffer if transfer needs it or NULL
*/
struct i3c_dma {
struct device *dev;
void *buf;
size_t len;
size_t map_len;
dma_addr_t addr;
enum dma_data_direction dir;
void *bounce_buf;
};
int i3c_master_do_i2c_xfers(struct i3c_master_controller *master,
const struct i2c_msg *xfers,
int nxfers);
@@ -564,7 +621,16 @@ int i3c_master_get_free_addr(struct i3c_master_controller *master,
int i3c_master_add_i3c_dev_locked(struct i3c_master_controller *master,
u8 addr);
int i3c_master_do_daa(struct i3c_master_controller *master);
int i3c_master_do_daa_ext(struct i3c_master_controller *master, bool rstdaa);
struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *ptr,
size_t len, bool force_bounce,
enum dma_data_direction dir);
void i3c_master_dma_unmap_single(struct i3c_dma *dma_xfer);
DEFINE_FREE(i3c_master_dma_unmap_single, void *,
if (_T) i3c_master_dma_unmap_single(_T))
int i3c_master_reattach_i3c_dev_locked(struct i3c_dev_desc *dev,
u8 old_dyn_addr);
int i3c_master_set_info(struct i3c_master_controller *master,
const struct i3c_device_info *info);