drivers: i3c: add v1.0 support flag

This adds a v1.0 support dts flag for devices. This also makes it so it
doesn't try to send a GETCAPS (GETHDRCAP) ccc if this flag is set and it
doesn't support any HDR modes.

Signed-off-by: Ryan McClelland <ryanmcclelland@meta.com>
This commit is contained in:
Ryan McClelland 2025-03-20 23:09:39 -07:00 committed by Benjamin Cabé
commit 2e8c911fa3
5 changed files with 52 additions and 31 deletions

View file

@ -777,28 +777,28 @@ int i3c_device_adv_info_get(struct i3c_device_desc *target)
/* GETMRL */ /* GETMRL */
if (i3c_ccc_do_getmrl(target, &mrl) != 0) { if (i3c_ccc_do_getmrl(target, &mrl) != 0) {
/* GETMRL may be optionally supported if no settable limit */ /* GETMRL may be optionally supported if no settable limit */
LOG_DBG("No settable limit for GETMRL"); LOG_DBG("%s: No settable limit for GETMRL", target->dev->name);
} }
/* GETMWL */ /* GETMWL */
if (i3c_ccc_do_getmwl(target, &mwl) != 0) { if (i3c_ccc_do_getmwl(target, &mwl) != 0) {
/* GETMWL may be optionally supported if no settable limit */ /* GETMWL may be optionally supported if no settable limit */
LOG_DBG("No settable limit for GETMWL"); LOG_DBG("%s: No settable limit for GETMWL", target->dev->name);
} }
/* GETCAPS */ /* GETCAPS */
ret = i3c_ccc_do_getcaps_fmt1(target, &caps); if (((target->flags & I3C_V1P0_SUPPORT) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) ||
/* (!(target->flags & I3C_V1P0_SUPPORT))) {
* GETCAPS (GETHDRCAP) is required to be supported for I3C v1.0 targets that support HDR /*
* modes and required if the Target's I3C version is v1.1 or later, but which the version it * GETCAPS (GETHDRCAP) is required to be supported for I3C v1.0 targets that support
* supports it can't be known ahead of time. So if the BCR bit for Advanced capabilities is * HDR modes and required if the Target's I3C version is v1.1 or later.
* set, then it is expected for GETCAPS to always be supported. Otherwise, then it's a I3C * It is also possible for this function to be called on an 'unknown' device such as
* v1.0 device without any HDR modes so do not treat as an error if no valid response. * from a secondary controller gathering info about a target it found about through
*/ * DEFTGTS, and it can't be known ahead of time if it is a v1.0 or v1.1 device.
if ((ret != 0) && (target->bcr & I3C_BCR_ADV_CAPABILITIES)) { */
return ret; if (i3c_ccc_do_getcaps_fmt1(target, &caps) != 0) {
} else { LOG_DBG("%s: GETCAPS not received", target->dev->name);
ret = 0; }
} }
/* CRCAPS */ /* CRCAPS */
@ -873,8 +873,9 @@ static int i3c_bus_setdasa(const struct device *dev, const struct i3c_dev_list *
* address as its static address if a different dynamic address * address as its static address if a different dynamic address
* is not requested * is not requested
*/ */
if ((desc->supports_setaasa) && ((desc->init_dynamic_addr == 0) || if ((desc->flags & I3C_SUPPORTS_SETAASA) &&
desc->init_dynamic_addr == desc->static_addr)) { ((desc->init_dynamic_addr == 0) ||
desc->init_dynamic_addr == desc->static_addr)) {
*need_aasa = true; *need_aasa = true;
continue; continue;
} }
@ -1079,7 +1080,8 @@ int i3c_bus_init(const struct device *dev, const struct i3c_dev_list *dev_list)
* Only set for devices that support SETAASA and do not * Only set for devices that support SETAASA and do not
* request a different dynamic address than its SA * request a different dynamic address than its SA
*/ */
if ((desc->supports_setaasa) && (desc->static_addr != 0) && if ((desc->flags & I3C_SUPPORTS_SETAASA) &&
(desc->static_addr != 0) &&
((desc->init_dynamic_addr == 0) || ((desc->init_dynamic_addr == 0) ||
desc->init_dynamic_addr == desc->static_addr)) { desc->init_dynamic_addr == desc->static_addr)) {
desc->dynamic_addr = desc->static_addr; desc->dynamic_addr = desc->static_addr;

View file

@ -629,7 +629,7 @@ static int cmd_i3c_ccc_setaasa(const struct shell *sh, size_t argc, char **argv)
/* set all devices DA to SA */ /* set all devices DA to SA */
I3C_BUS_FOR_EACH_I3CDEV(dev, desc) { I3C_BUS_FOR_EACH_I3CDEV(dev, desc) {
if ((desc->supports_setaasa) && (desc->dynamic_addr == 0) && if (((desc->flags) & I3C_SUPPORTS_SETAASA) && (desc->dynamic_addr == 0) &&
(desc->static_addr != 0)) { (desc->static_addr != 0)) {
desc->dynamic_addr = desc->static_addr; desc->dynamic_addr = desc->static_addr;
} }

View file

@ -67,3 +67,8 @@ properties:
description: | description: |
Indicates if the device supports the CCC SETAASA. If true, it will Indicates if the device supports the CCC SETAASA. If true, it will
be used as an optimization for bus initialization. be used as an optimization for bus initialization.
v1p0-support:
type: boolean
description: |
Indicates if the device compiles to I3C v1.0.

View file

@ -929,12 +929,13 @@ struct i3c_device_desc {
const uint8_t init_dynamic_addr; const uint8_t init_dynamic_addr;
/** /**
* Device support for SETAASA * Device Flags
* *
* This will be used as an optimization for bus initializtion if the * BIT[0]: This shall be used as an optimization for bus initializtion if the
* device supports SETAASA. * device supports SETAASA.
* BIT[1]: This shall be used to indicate if the device is a I3C v1.0 device
*/ */
const bool supports_setaasa; const uint8_t flags;
/** /**
* Dynamic Address for this target device used for communication. * Dynamic Address for this target device used for communication.

View file

@ -52,6 +52,19 @@ extern "C" {
#define I3C_DEVICE_ID_DT_INST(inst) \ #define I3C_DEVICE_ID_DT_INST(inst) \
I3C_DEVICE_ID_DT(DT_DRV_INST(inst)) I3C_DEVICE_ID_DT(DT_DRV_INST(inst))
/**
* @name I3C device flags.
* @anchor I3C_DEVICE_FLAGS
* @{
*/
/** Device supports SETAASA CCC */
#define I3C_SUPPORTS_SETAASA BIT(0)
/** Device supports I3C v1.0 */
#define I3C_V1P0_SUPPORT BIT(1)
/** @} */
/** /**
* @brief Structure initializer for i3c_device_desc from devicetree * @brief Structure initializer for i3c_device_desc from devicetree
* *
@ -62,16 +75,16 @@ extern "C" {
* @param node_id Devicetree node identifier for the I3C device whose * @param node_id Devicetree node identifier for the I3C device whose
* struct i3c_device_desc to create an initializer for * struct i3c_device_desc to create an initializer for
*/ */
#define I3C_DEVICE_DESC_DT(node_id) \ #define I3C_DEVICE_DESC_DT(node_id) \
{ \ { \
.bus = DEVICE_DT_GET(DT_BUS(node_id)), \ .bus = DEVICE_DT_GET(DT_BUS(node_id)), \
.dev = DEVICE_DT_GET(node_id), \ .dev = DEVICE_DT_GET(node_id), \
.static_addr = DT_PROP_BY_IDX(node_id, reg, 0), \ .static_addr = DT_PROP_BY_IDX(node_id, reg, 0), \
.pid = ((uint64_t)DT_PROP_BY_IDX(node_id, reg, 1) << 32)\ .pid = ((uint64_t)DT_PROP_BY_IDX(node_id, reg, 1) << 32) | \
| DT_PROP_BY_IDX(node_id, reg, 2), \ DT_PROP_BY_IDX(node_id, reg, 2), \
.init_dynamic_addr = \ .init_dynamic_addr = DT_PROP_OR(node_id, assigned_address, 0), \
DT_PROP_OR(node_id, assigned_address, 0), \ .flags = FIELD_PREP(I3C_SUPPORTS_SETAASA, DT_PROP(node_id, supports_setaasa)) | \
.supports_setaasa = DT_PROP(node_id, supports_setaasa), \ FIELD_PREP(I3C_V1P0_SUPPORT, DT_PROP(node_id, v1p0_support)), \
}, },
/** /**