Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i3c: Add HDR API support

Rename struct i3c_priv_xfer to struct i3c_xfer, since private xfer in the
I3C spec refers only to SDR transfers. Ref: i3c spec ver1.2, section 3,
Technical Overview.

i3c_xfer will be used for both SDR and HDR.

Rename enum i3c_hdr_mode to i3c_xfer_mode. Previous definition need match
CCC GET_CAP1 bit position. Use 31 as SDR transfer mode.

Add i3c_device_do_xfers() with an xfer mode argument, while keeping
i3c_device_do_priv_xfers() as a wrapper that calls i3c_device_do_xfers()
with I3C_SDR for backward compatibility.

Introduce a 'cmd' field in struct i3c_xfer as an anonymous union with
'rnw', since HDR mode uses read/write commands instead of the SDR address
bit.

Add .i3c_xfers() callback for master controllers. If not implemented, fall
back to SDR with .priv_xfers(). The .priv_xfers() API can be removed once
all controllers switch to .i3c_xfers().

Add 'mode_mask' bitmask to advertise controller capability.

Signed-off-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20251106-i3c_ddr-v11-1-33a6a66ed095@nxp.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

authored by

Frank Li and committed by
Alexandre Belloni
256a2174 de53ad6c

+70 -26
+20 -7
drivers/i3c/device.c
··· 15 15 #include "internals.h" 16 16 17 17 /** 18 - * i3c_device_do_priv_xfers() - do I3C SDR private transfers directed to a 19 - * specific device 18 + * i3c_device_do_xfers() - do I3C transfers directed to a specific device 20 19 * 21 20 * @dev: device with which the transfers should be done 22 21 * @xfers: array of transfers 23 22 * @nxfers: number of transfers 23 + * @mode: transfer mode 24 24 * 25 25 * Initiate one or several private SDR transfers with @dev. 26 26 * ··· 33 33 * 'xfers' some time later. See I3C spec ver 1.1.1 09-Jun-2021. Section: 34 34 * 5.1.2.2.3. 35 35 */ 36 - int i3c_device_do_priv_xfers(struct i3c_device *dev, 37 - struct i3c_priv_xfer *xfers, 38 - int nxfers) 36 + int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers, 37 + int nxfers, enum i3c_xfer_mode mode) 39 38 { 40 39 int ret, i; 41 40 ··· 47 48 } 48 49 49 50 i3c_bus_normaluse_lock(dev->bus); 50 - ret = i3c_dev_do_priv_xfers_locked(dev->desc, xfers, nxfers); 51 + ret = i3c_dev_do_xfers_locked(dev->desc, xfers, nxfers, mode); 51 52 i3c_bus_normaluse_unlock(dev->bus); 52 53 53 54 return ret; 54 55 } 55 - EXPORT_SYMBOL_GPL(i3c_device_do_priv_xfers); 56 + EXPORT_SYMBOL_GPL(i3c_device_do_xfers); 56 57 57 58 /** 58 59 * i3c_device_do_setdasa() - do I3C dynamic address assignement with ··· 258 259 return NULL; 259 260 } 260 261 EXPORT_SYMBOL_GPL(i3c_device_match_id); 262 + 263 + /** 264 + * i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by 265 + * connected master controller. 266 + * @dev: I3C device 267 + * 268 + * Return: a bit mask, which supported transfer mode, bit position is defined at 269 + * enum i3c_hdr_mode 270 + */ 271 + u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev) 272 + { 273 + return i3c_dev_get_master(dev->desc)->this->info.hdr_cap | BIT(I3C_SDR); 274 + } 275 + EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode); 261 276 262 277 /** 263 278 * i3c_driver_register_with_owner() - register an I3C device driver
+3 -3
drivers/i3c/internals.h
··· 15 15 void i3c_bus_normaluse_unlock(struct i3c_bus *bus); 16 16 17 17 int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev); 18 - int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev, 19 - struct i3c_priv_xfer *xfers, 20 - int nxfers); 18 + int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, 19 + struct i3c_xfer *xfers, 20 + int nxfers, enum i3c_xfer_mode mode); 21 21 int i3c_dev_disable_ibi_locked(struct i3c_dev_desc *dev); 22 22 int i3c_dev_enable_ibi_locked(struct i3c_dev_desc *dev); 23 23 int i3c_dev_request_ibi_locked(struct i3c_dev_desc *dev,
+14 -5
drivers/i3c/master.c
··· 2819 2819 2820 2820 static int i3c_master_check_ops(const struct i3c_master_controller_ops *ops) 2821 2821 { 2822 - if (!ops || !ops->bus_init || !ops->priv_xfers || 2822 + if (!ops || !ops->bus_init || 2823 2823 !ops->send_ccc_cmd || !ops->do_daa || !ops->i2c_xfers) 2824 + return -EINVAL; 2825 + 2826 + /* Must provide one of priv_xfers (SDR only) or i3c_xfers (all modes) */ 2827 + if (!ops->priv_xfers && !ops->i3c_xfers) 2824 2828 return -EINVAL; 2825 2829 2826 2830 if (ops->request_ibi && ··· 3016 3012 dev->boardinfo->init_dyn_addr); 3017 3013 } 3018 3014 3019 - int i3c_dev_do_priv_xfers_locked(struct i3c_dev_desc *dev, 3020 - struct i3c_priv_xfer *xfers, 3021 - int nxfers) 3015 + int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers, 3016 + int nxfers, enum i3c_xfer_mode mode) 3022 3017 { 3023 3018 struct i3c_master_controller *master; 3024 3019 ··· 3028 3025 if (!master || !xfers) 3029 3026 return -EINVAL; 3030 3027 3031 - if (!master->ops->priv_xfers) 3028 + if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode))) 3032 3029 return -EOPNOTSUPP; 3030 + 3031 + if (master->ops->i3c_xfers) 3032 + return master->ops->i3c_xfers(dev, xfers, nxfers, mode); 3033 + 3034 + if (mode != I3C_SDR) 3035 + return -EINVAL; 3033 3036 3034 3037 return master->ops->priv_xfers(dev, xfers, nxfers); 3035 3038 }
+29 -11
include/linux/i3c/device.h
··· 39 39 }; 40 40 41 41 /** 42 - * enum i3c_hdr_mode - HDR mode ids 42 + * enum i3c_xfer_mode - I3C xfer mode ids 43 43 * @I3C_HDR_DDR: DDR mode 44 44 * @I3C_HDR_TSP: TSP mode 45 45 * @I3C_HDR_TSL: TSL mode 46 + * @I3C_SDR: SDR mode (NOT HDR mode) 46 47 */ 47 - enum i3c_hdr_mode { 48 - I3C_HDR_DDR, 49 - I3C_HDR_TSP, 50 - I3C_HDR_TSL, 48 + enum i3c_xfer_mode { 49 + /* The below 3 value (I3C_HDR*) must match GETCAP1 Byte bit position */ 50 + I3C_HDR_DDR = 0, 51 + I3C_HDR_TSP = 1, 52 + I3C_HDR_TSL = 2, 53 + /* Use for default SDR transfer mode */ 54 + I3C_SDR = 0x31, 51 55 }; 52 56 53 57 /** 54 - * struct i3c_priv_xfer - I3C SDR private transfer 58 + * struct i3c_xfer - I3C data transfer 55 59 * @rnw: encodes the transfer direction. true for a read, false for a write 60 + * @cmd: Read/Write command in HDR mode, read: 0x80 - 0xff, write: 0x00 - 0x7f 56 61 * @len: transfer length in bytes of the transfer 57 62 * @actual_len: actual length in bytes are transferred by the controller 58 63 * @data: input/output buffer ··· 65 60 * @data.out: output buffer. Must point to a DMA-able buffer 66 61 * @err: I3C error code 67 62 */ 68 - struct i3c_priv_xfer { 69 - u8 rnw; 63 + struct i3c_xfer { 64 + union { 65 + u8 rnw; 66 + u8 cmd; 67 + }; 70 68 u16 len; 71 69 u16 actual_len; 72 70 union { ··· 78 70 } data; 79 71 enum i3c_error_code err; 80 72 }; 73 + 74 + /* keep back compatible */ 75 + #define i3c_priv_xfer i3c_xfer 81 76 82 77 /** 83 78 * enum i3c_dcr - I3C DCR values ··· 308 297 i3c_i2c_driver_unregister, \ 309 298 __i2cdrv) 310 299 311 - int i3c_device_do_priv_xfers(struct i3c_device *dev, 312 - struct i3c_priv_xfer *xfers, 313 - int nxfers); 300 + int i3c_device_do_xfers(struct i3c_device *dev, struct i3c_xfer *xfers, 301 + int nxfers, enum i3c_xfer_mode mode); 302 + 303 + static inline int i3c_device_do_priv_xfers(struct i3c_device *dev, 304 + struct i3c_priv_xfer *xfers, 305 + int nxfers) 306 + { 307 + return i3c_device_do_xfers(dev, xfers, nxfers, I3C_SDR); 308 + } 314 309 315 310 int i3c_device_do_setdasa(struct i3c_device *dev); 316 311 ··· 358 341 void i3c_device_free_ibi(struct i3c_device *dev); 359 342 int i3c_device_enable_ibi(struct i3c_device *dev); 360 343 int i3c_device_disable_ibi(struct i3c_device *dev); 344 + u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev); 361 345 362 346 #endif /* I3C_DEV_H */
+4
include/linux/i3c/master.h
··· 474 474 const struct i3c_ccc_cmd *cmd); 475 475 int (*send_ccc_cmd)(struct i3c_master_controller *master, 476 476 struct i3c_ccc_cmd *cmd); 477 + /* Deprecated, please use i3c_xfers() */ 477 478 int (*priv_xfers)(struct i3c_dev_desc *dev, 478 479 struct i3c_priv_xfer *xfers, 479 480 int nxfers); 481 + int (*i3c_xfers)(struct i3c_dev_desc *dev, 482 + struct i3c_xfer *xfers, 483 + int nxfers, enum i3c_xfer_mode mode); 480 484 int (*attach_i2c_dev)(struct i2c_dev_desc *dev); 481 485 void (*detach_i2c_dev)(struct i2c_dev_desc *dev); 482 486 int (*i2c_xfers)(struct i2c_dev_desc *dev,