* [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth
2023-03-17 14:54 [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Lars-Peter Clausen
@ 2023-03-17 14:54 ` Lars-Peter Clausen
2023-03-20 10:11 ` Michal Simek
2023-03-29 19:19 ` Wolfram Sang
2023-03-17 14:54 ` [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size Lars-Peter Clausen
` (3 subsequent siblings)
4 siblings, 2 replies; 10+ messages in thread
From: Lars-Peter Clausen @ 2023-03-17 14:54 UTC (permalink / raw)
To: Wolfram Sang
Cc: Michal Simek, Shubhrajyoti Datta, Rob Herring,
Krzysztof Kozlowski, linux-i2c, devicetree, Lars-Peter Clausen
The FIFO depth is a synthesis configuration parameters of the Cadence I2C
IP. Different SoCs might use different values for these parameters.
Currently the driver has the FIFO depth hardcoded to 16. Trying to use the
driver with an IP instance that uses smaller values for these will work for
short transfers. But longer transfers will fail.
Introduce a new devicetree property that allows to describe the FIFO depth
of the I2C controller.
These changes have been tested with
1) The Xilinx MPSoC for which this driver was originally written which has
the previous hardcoded settings of 16 and 255.
2) Another instance of the Cadence I2C IP with FIFO depth of 8 and maximum
transfer length of 16.
Without these changes the latter would fail for I2C transfers longer than
8. With the updated driver both work fine even for longer transfers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
Changes since v1:
* Split dynamic FIFO depth and transaction size support into two patches
* Add kernel-doc for new struct members
* Make `fifo_depth` struct field u32 so it can be directly used with
`of_property_read_u32()` API
---
drivers/i2c/busses/i2c-cadence.c | 29 +++++++++++++++++------------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 93c6d0822468..0834e1ac9d03 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -114,7 +114,7 @@
/* timeout for pm runtime autosuspend */
#define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
-#define CDNS_I2C_FIFO_DEPTH 16
+#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
@@ -184,6 +184,7 @@ enum cdns_i2c_slave_state {
* @slave: Registered slave instance.
* @dev_mode: I2C operating role(master/slave).
* @slave_state: I2C Slave state(idle/read/write).
+ * @fifo_depth: The depth of the transfer FIFO
*/
struct cdns_i2c {
struct device *dev;
@@ -211,6 +212,7 @@ struct cdns_i2c {
enum cdns_i2c_mode dev_mode;
enum cdns_i2c_slave_state slave_state;
#endif
+ u32 fifo_depth;
};
struct cdns_platform_data {
@@ -236,7 +238,7 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
{
return (hold_wrkaround &&
- (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
+ (id->curr_recv_count == id->fifo_depth + 1));
}
#if IS_ENABLED(CONFIG_I2C_SLAVE)
@@ -431,7 +433,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
* if RX data left is less than or equal to
* FIFO DEPTH unless repeated start is selected
*/
- if (id->recv_count <= CDNS_I2C_FIFO_DEPTH &&
+ if (id->recv_count <= id->fifo_depth &&
!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
@@ -456,22 +458,22 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
if (cdns_is_holdquirk(id, updatetx)) {
/* wait while fifo is full */
while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
- (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+ (id->curr_recv_count - id->fifo_depth))
;
/*
* Check number of bytes to be received against maximum
* transfer size and update register accordingly.
*/
- if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
+ if (((int)(id->recv_count) - id->fifo_depth) >
CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
- CDNS_I2C_FIFO_DEPTH;
+ id->fifo_depth;
} else {
cdns_i2c_writereg(id->recv_count -
- CDNS_I2C_FIFO_DEPTH,
+ id->fifo_depth,
CDNS_I2C_XFER_SIZE_OFFSET);
id->curr_recv_count = id->recv_count;
}
@@ -494,7 +496,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
* space available in FIFO and fill with that many bytes.
*/
if (id->send_count) {
- avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ avail_bytes = id->fifo_depth -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
bytes_to_send = avail_bytes;
@@ -588,7 +590,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
- if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
+ if (id->recv_count > id->fifo_depth)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
@@ -612,7 +614,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
}
/* Determine hold_clear based on number of bytes to receive and hold flag */
- if (!id->bus_hold_flag && id->recv_count <= CDNS_I2C_FIFO_DEPTH) {
+ if (!id->bus_hold_flag && id->recv_count <= id->fifo_depth) {
if (ctrl_reg & CDNS_I2C_CR_HOLD) {
hold_clear = true;
if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
@@ -673,7 +675,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
*/
- if (id->send_count > CDNS_I2C_FIFO_DEPTH)
+ if (id->send_count > id->fifo_depth)
ctrl_reg |= CDNS_I2C_CR_HOLD;
cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
@@ -686,7 +688,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
* against the space available, and fill the FIFO accordingly.
* Enable the interrupts.
*/
- avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ avail_bytes = id->fifo_depth -
cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
if (id->send_count > avail_bytes)
@@ -1316,6 +1318,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
#endif
id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
+ id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
+ of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
+
ret = cdns_i2c_setclk(id->input_clk, id);
if (ret) {
dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth
2023-03-17 14:54 ` [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth Lars-Peter Clausen
@ 2023-03-20 10:11 ` Michal Simek
2023-03-29 19:19 ` Wolfram Sang
1 sibling, 0 replies; 10+ messages in thread
From: Michal Simek @ 2023-03-20 10:11 UTC (permalink / raw)
To: Lars-Peter Clausen, Wolfram Sang
Cc: Shubhrajyoti Datta, Rob Herring, Krzysztof Kozlowski, linux-i2c,
devicetree
On 3/17/23 15:54, Lars-Peter Clausen wrote:
> The FIFO depth is a synthesis configuration parameters of the Cadence I2C
> IP. Different SoCs might use different values for these parameters.
>
> Currently the driver has the FIFO depth hardcoded to 16. Trying to use the
> driver with an IP instance that uses smaller values for these will work for
> short transfers. But longer transfers will fail.
>
> Introduce a new devicetree property that allows to describe the FIFO depth
> of the I2C controller.
>
> These changes have been tested with
> 1) The Xilinx MPSoC for which this driver was originally written which has
> the previous hardcoded settings of 16 and 255.
> 2) Another instance of the Cadence I2C IP with FIFO depth of 8 and maximum
> transfer length of 16.
>
> Without these changes the latter would fail for I2C transfers longer than
> 8. With the updated driver both work fine even for longer transfers.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
> Changes since v1:
> * Split dynamic FIFO depth and transaction size support into two patches
> * Add kernel-doc for new struct members
> * Make `fifo_depth` struct field u32 so it can be directly used with
> `of_property_read_u32()` API
> ---
> drivers/i2c/busses/i2c-cadence.c | 29 +++++++++++++++++------------
> 1 file changed, 17 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
> index 93c6d0822468..0834e1ac9d03 100644
> --- a/drivers/i2c/busses/i2c-cadence.c
> +++ b/drivers/i2c/busses/i2c-cadence.c
> @@ -114,7 +114,7 @@
> /* timeout for pm runtime autosuspend */
> #define CNDS_I2C_PM_TIMEOUT 1000 /* ms */
>
> -#define CDNS_I2C_FIFO_DEPTH 16
> +#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
> #define CDNS_I2C_MAX_TRANSFER_SIZE 255
> /* Transfer size in multiples of data interrupt depth */
> #define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
> @@ -184,6 +184,7 @@ enum cdns_i2c_slave_state {
> * @slave: Registered slave instance.
> * @dev_mode: I2C operating role(master/slave).
> * @slave_state: I2C Slave state(idle/read/write).
> + * @fifo_depth: The depth of the transfer FIFO
> */
> struct cdns_i2c {
> struct device *dev;
> @@ -211,6 +212,7 @@ struct cdns_i2c {
> enum cdns_i2c_mode dev_mode;
> enum cdns_i2c_slave_state slave_state;
> #endif
> + u32 fifo_depth;
> };
>
> struct cdns_platform_data {
> @@ -236,7 +238,7 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
> static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround)
> {
> return (hold_wrkaround &&
> - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1));
> + (id->curr_recv_count == id->fifo_depth + 1));
> }
>
> #if IS_ENABLED(CONFIG_I2C_SLAVE)
> @@ -431,7 +433,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
> * if RX data left is less than or equal to
> * FIFO DEPTH unless repeated start is selected
> */
> - if (id->recv_count <= CDNS_I2C_FIFO_DEPTH &&
> + if (id->recv_count <= id->fifo_depth &&
> !id->bus_hold_flag)
> cdns_i2c_clear_bus_hold(id);
>
> @@ -456,22 +458,22 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
> if (cdns_is_holdquirk(id, updatetx)) {
> /* wait while fifo is full */
> while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
> - (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
> + (id->curr_recv_count - id->fifo_depth))
> ;
>
> /*
> * Check number of bytes to be received against maximum
> * transfer size and update register accordingly.
> */
> - if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
> + if (((int)(id->recv_count) - id->fifo_depth) >
> CDNS_I2C_TRANSFER_SIZE) {
> cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
> CDNS_I2C_XFER_SIZE_OFFSET);
> id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
> - CDNS_I2C_FIFO_DEPTH;
> + id->fifo_depth;
> } else {
> cdns_i2c_writereg(id->recv_count -
> - CDNS_I2C_FIFO_DEPTH,
> + id->fifo_depth,
> CDNS_I2C_XFER_SIZE_OFFSET);
> id->curr_recv_count = id->recv_count;
> }
> @@ -494,7 +496,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
> * space available in FIFO and fill with that many bytes.
> */
> if (id->send_count) {
> - avail_bytes = CDNS_I2C_FIFO_DEPTH -
> + avail_bytes = id->fifo_depth -
> cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
> if (id->send_count > avail_bytes)
> bytes_to_send = avail_bytes;
> @@ -588,7 +590,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> * Check for the message size against FIFO depth and set the
> * 'hold bus' bit if it is greater than FIFO depth.
> */
> - if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
> + if (id->recv_count > id->fifo_depth)
> ctrl_reg |= CDNS_I2C_CR_HOLD;
>
> cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
> @@ -612,7 +614,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> }
>
> /* Determine hold_clear based on number of bytes to receive and hold flag */
> - if (!id->bus_hold_flag && id->recv_count <= CDNS_I2C_FIFO_DEPTH) {
> + if (!id->bus_hold_flag && id->recv_count <= id->fifo_depth) {
> if (ctrl_reg & CDNS_I2C_CR_HOLD) {
> hold_clear = true;
> if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT)
> @@ -673,7 +675,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
> * Check for the message size against FIFO depth and set the
> * 'hold bus' bit if it is greater than FIFO depth.
> */
> - if (id->send_count > CDNS_I2C_FIFO_DEPTH)
> + if (id->send_count > id->fifo_depth)
> ctrl_reg |= CDNS_I2C_CR_HOLD;
> cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
>
> @@ -686,7 +688,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id)
> * against the space available, and fill the FIFO accordingly.
> * Enable the interrupts.
> */
> - avail_bytes = CDNS_I2C_FIFO_DEPTH -
> + avail_bytes = id->fifo_depth -
> cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
>
> if (id->send_count > avail_bytes)
> @@ -1316,6 +1318,9 @@ static int cdns_i2c_probe(struct platform_device *pdev)
> #endif
> id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS;
>
> + id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
> + of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
> +
> ret = cdns_i2c_setclk(id->input_clk, id);
> if (ret) {
> dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
Acked-by: Michal Simek <michal.simek@amd.com>
Thanks,
Michal
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth
2023-03-17 14:54 ` [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth Lars-Peter Clausen
2023-03-20 10:11 ` Michal Simek
@ 2023-03-29 19:19 ` Wolfram Sang
1 sibling, 0 replies; 10+ messages in thread
From: Wolfram Sang @ 2023-03-29 19:19 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Michal Simek, Shubhrajyoti Datta, Rob Herring,
Krzysztof Kozlowski, linux-i2c, devicetree
[-- Attachment #1: Type: text/plain, Size: 1065 bytes --]
On Fri, Mar 17, 2023 at 07:54:40AM -0700, Lars-Peter Clausen wrote:
> The FIFO depth is a synthesis configuration parameters of the Cadence I2C
> IP. Different SoCs might use different values for these parameters.
>
> Currently the driver has the FIFO depth hardcoded to 16. Trying to use the
> driver with an IP instance that uses smaller values for these will work for
> short transfers. But longer transfers will fail.
>
> Introduce a new devicetree property that allows to describe the FIFO depth
> of the I2C controller.
>
> These changes have been tested with
> 1) The Xilinx MPSoC for which this driver was originally written which has
> the previous hardcoded settings of 16 and 255.
> 2) Another instance of the Cadence I2C IP with FIFO depth of 8 and maximum
> transfer length of 16.
>
> Without these changes the latter would fail for I2C transfers longer than
> 8. With the updated driver both work fine even for longer transfers.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size
2023-03-17 14:54 [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Lars-Peter Clausen
2023-03-17 14:54 ` [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth Lars-Peter Clausen
@ 2023-03-17 14:54 ` Lars-Peter Clausen
2023-03-20 10:13 ` Michal Simek
2023-03-29 19:19 ` Wolfram Sang
2023-03-20 10:13 ` [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Michal Simek
` (2 subsequent siblings)
4 siblings, 2 replies; 10+ messages in thread
From: Lars-Peter Clausen @ 2023-03-17 14:54 UTC (permalink / raw)
To: Wolfram Sang
Cc: Michal Simek, Shubhrajyoti Datta, Rob Herring,
Krzysztof Kozlowski, linux-i2c, devicetree, Lars-Peter Clausen
The maximum transfer length is a synthesis configuration parameters of the
Cadence I2C IP. Different SoCs might use different values for these
parameters.
Currently the driver has the maximum transfer length hardcoded to 255.
Trying to use the driver with an IP instance that uses smaller values for
these will work for short transfers. But longer transfers will fail.
The maximum transfer length can easily be detected at runtime since the
unused MSBs of the transfer length register are hardwired to 0. Writing
0xff and then reading back the value will give the maximum transfer length.
These changes have been tested with
1) The Xilinx MPSoC for which this driver was originally written which
has the previous hardcoded settings of 16 and 255.
2) Another instance of the Cadence I2C IP with FIFO depth of 8 and
maximum transfer length of 16.
Without these changes the latter would fail for I2C transfers longer than
16. With the updated driver both work fine even for longer transfers.
Note that the IP core and driver support chaining multiple transfers into a
single longer transfer using the HOLD bit. So the maximum transfer size is
not the limit for the length of the I2C transfer, but the limit for how
much data can be transferred without having to reprogram the control
registers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
---
Changes since v1:
* Split dynamic FIFO depth and transaction size support into two patches
* Add kernel-doc for new struct members
---
drivers/i2c/busses/i2c-cadence.c | 49 +++++++++++++++++++++++++++-----
1 file changed, 42 insertions(+), 7 deletions(-)
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 0834e1ac9d03..8f61a633c42c 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -117,7 +117,7 @@
#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
/* Transfer size in multiples of data interrupt depth */
-#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
+#define CDNS_I2C_TRANSFER_SIZE(max) ((max) - 3)
#define DRIVER_NAME "cdns-i2c"
@@ -185,6 +185,7 @@ enum cdns_i2c_slave_state {
* @dev_mode: I2C operating role(master/slave).
* @slave_state: I2C Slave state(idle/read/write).
* @fifo_depth: The depth of the transfer FIFO
+ * @transfer_size: The maximum number of bytes in one transfer
*/
struct cdns_i2c {
struct device *dev;
@@ -213,6 +214,7 @@ struct cdns_i2c {
enum cdns_i2c_slave_state slave_state;
#endif
u32 fifo_depth;
+ unsigned int transfer_size;
};
struct cdns_platform_data {
@@ -466,10 +468,10 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
* transfer size and update register accordingly.
*/
if (((int)(id->recv_count) - id->fifo_depth) >
- CDNS_I2C_TRANSFER_SIZE) {
- cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ id->transfer_size) {
+ cdns_i2c_writereg(id->transfer_size,
CDNS_I2C_XFER_SIZE_OFFSET);
- id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+ id->curr_recv_count = id->transfer_size +
id->fifo_depth;
} else {
cdns_i2c_writereg(id->recv_count -
@@ -605,10 +607,10 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
* receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts.
*/
- if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
- cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ if (id->recv_count > id->transfer_size) {
+ cdns_i2c_writereg(id->transfer_size,
CDNS_I2C_XFER_SIZE_OFFSET);
- id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ id->curr_recv_count = id->transfer_size;
} else {
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
}
@@ -1227,6 +1229,37 @@ static const struct of_device_id cdns_i2c_of_match[] = {
};
MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
+/**
+ * cdns_i2c_detect_transfer_size - Detect the maximum transfer size supported
+ * @id: Device private data structure
+ *
+ * Detect the maximum transfer size that is supported by this instance of the
+ * Cadence I2C controller.
+ */
+static void cdns_i2c_detect_transfer_size(struct cdns_i2c *id)
+{
+ u32 val;
+
+ /*
+ * Writing to the transfer size register is only possible if these two bits
+ * are set in the control register.
+ */
+ cdns_i2c_writereg(CDNS_I2C_CR_MS | CDNS_I2C_CR_RW, CDNS_I2C_CR_OFFSET);
+
+ /*
+ * The number of writable bits of the transfer size register can be between
+ * 4 and 8. This is a controlled through a synthesis parameter of the IP
+ * core and can vary from instance to instance. The unused MSBs always read
+ * back as 0. Writing 0xff and then reading the value back will report the
+ * maximum supported transfer size.
+ */
+ cdns_i2c_writereg(CDNS_I2C_MAX_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET);
+ val = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ id->transfer_size = CDNS_I2C_TRANSFER_SIZE(val);
+ cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
+ cdns_i2c_writereg(0, CDNS_I2C_CR_OFFSET);
+}
+
/**
* cdns_i2c_probe - Platform registration call
* @pdev: Handle to the platform device structure
@@ -1321,6 +1354,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
+ cdns_i2c_detect_transfer_size(id);
+
ret = cdns_i2c_setclk(id->input_clk, id);
if (ret) {
dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size
2023-03-17 14:54 ` [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size Lars-Peter Clausen
@ 2023-03-20 10:13 ` Michal Simek
2023-03-29 19:19 ` Wolfram Sang
1 sibling, 0 replies; 10+ messages in thread
From: Michal Simek @ 2023-03-20 10:13 UTC (permalink / raw)
To: Lars-Peter Clausen, Wolfram Sang
Cc: Shubhrajyoti Datta, Rob Herring, Krzysztof Kozlowski, linux-i2c,
devicetree
On 3/17/23 15:54, Lars-Peter Clausen wrote:
> The maximum transfer length is a synthesis configuration parameters of the
> Cadence I2C IP. Different SoCs might use different values for these
> parameters.
>
> Currently the driver has the maximum transfer length hardcoded to 255.
> Trying to use the driver with an IP instance that uses smaller values for
> these will work for short transfers. But longer transfers will fail.
>
> The maximum transfer length can easily be detected at runtime since the
> unused MSBs of the transfer length register are hardwired to 0. Writing
> 0xff and then reading back the value will give the maximum transfer length.
>
> These changes have been tested with
> 1) The Xilinx MPSoC for which this driver was originally written which
> has the previous hardcoded settings of 16 and 255.
> 2) Another instance of the Cadence I2C IP with FIFO depth of 8 and
> maximum transfer length of 16.
>
> Without these changes the latter would fail for I2C transfers longer than
> 16. With the updated driver both work fine even for longer transfers.
>
> Note that the IP core and driver support chaining multiple transfers into a
> single longer transfer using the HOLD bit. So the maximum transfer size is
> not the limit for the length of the I2C transfer, but the limit for how
> much data can be transferred without having to reprogram the control
> registers.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
> Changes since v1:
> * Split dynamic FIFO depth and transaction size support into two patches
> * Add kernel-doc for new struct members
> ---
> drivers/i2c/busses/i2c-cadence.c | 49 +++++++++++++++++++++++++++-----
> 1 file changed, 42 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
> index 0834e1ac9d03..8f61a633c42c 100644
> --- a/drivers/i2c/busses/i2c-cadence.c
> +++ b/drivers/i2c/busses/i2c-cadence.c
> @@ -117,7 +117,7 @@
> #define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
> #define CDNS_I2C_MAX_TRANSFER_SIZE 255
> /* Transfer size in multiples of data interrupt depth */
> -#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
> +#define CDNS_I2C_TRANSFER_SIZE(max) ((max) - 3)
>
> #define DRIVER_NAME "cdns-i2c"
>
> @@ -185,6 +185,7 @@ enum cdns_i2c_slave_state {
> * @dev_mode: I2C operating role(master/slave).
> * @slave_state: I2C Slave state(idle/read/write).
> * @fifo_depth: The depth of the transfer FIFO
> + * @transfer_size: The maximum number of bytes in one transfer
> */
> struct cdns_i2c {
> struct device *dev;
> @@ -213,6 +214,7 @@ struct cdns_i2c {
> enum cdns_i2c_slave_state slave_state;
> #endif
> u32 fifo_depth;
> + unsigned int transfer_size;
> };
>
> struct cdns_platform_data {
> @@ -466,10 +468,10 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
> * transfer size and update register accordingly.
> */
> if (((int)(id->recv_count) - id->fifo_depth) >
> - CDNS_I2C_TRANSFER_SIZE) {
> - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
> + id->transfer_size) {
> + cdns_i2c_writereg(id->transfer_size,
> CDNS_I2C_XFER_SIZE_OFFSET);
> - id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
> + id->curr_recv_count = id->transfer_size +
> id->fifo_depth;
> } else {
> cdns_i2c_writereg(id->recv_count -
> @@ -605,10 +607,10 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
> * receive if it is less than transfer size and transfer size if
> * it is more. Enable the interrupts.
> */
> - if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
> - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
> + if (id->recv_count > id->transfer_size) {
> + cdns_i2c_writereg(id->transfer_size,
> CDNS_I2C_XFER_SIZE_OFFSET);
> - id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
> + id->curr_recv_count = id->transfer_size;
> } else {
> cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
> }
> @@ -1227,6 +1229,37 @@ static const struct of_device_id cdns_i2c_of_match[] = {
> };
> MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
>
> +/**
> + * cdns_i2c_detect_transfer_size - Detect the maximum transfer size supported
> + * @id: Device private data structure
> + *
> + * Detect the maximum transfer size that is supported by this instance of the
> + * Cadence I2C controller.
> + */
> +static void cdns_i2c_detect_transfer_size(struct cdns_i2c *id)
> +{
> + u32 val;
> +
> + /*
> + * Writing to the transfer size register is only possible if these two bits
> + * are set in the control register.
> + */
> + cdns_i2c_writereg(CDNS_I2C_CR_MS | CDNS_I2C_CR_RW, CDNS_I2C_CR_OFFSET);
> +
> + /*
> + * The number of writable bits of the transfer size register can be between
> + * 4 and 8. This is a controlled through a synthesis parameter of the IP
> + * core and can vary from instance to instance. The unused MSBs always read
> + * back as 0. Writing 0xff and then reading the value back will report the
> + * maximum supported transfer size.
> + */
> + cdns_i2c_writereg(CDNS_I2C_MAX_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET);
> + val = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
> + id->transfer_size = CDNS_I2C_TRANSFER_SIZE(val);
> + cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
> + cdns_i2c_writereg(0, CDNS_I2C_CR_OFFSET);
> +}
> +
> /**
> * cdns_i2c_probe - Platform registration call
> * @pdev: Handle to the platform device structure
> @@ -1321,6 +1354,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
> id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
> of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
>
> + cdns_i2c_detect_transfer_size(id);
> +
> ret = cdns_i2c_setclk(id->input_clk, id);
> if (ret) {
> dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
Acked-by: Michal Simek <michal.simek@amd.com>
Thanks,
Michal
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size
2023-03-17 14:54 ` [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size Lars-Peter Clausen
2023-03-20 10:13 ` Michal Simek
@ 2023-03-29 19:19 ` Wolfram Sang
1 sibling, 0 replies; 10+ messages in thread
From: Wolfram Sang @ 2023-03-29 19:19 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Michal Simek, Shubhrajyoti Datta, Rob Herring,
Krzysztof Kozlowski, linux-i2c, devicetree
[-- Attachment #1: Type: text/plain, Size: 1552 bytes --]
On Fri, Mar 17, 2023 at 07:54:41AM -0700, Lars-Peter Clausen wrote:
> The maximum transfer length is a synthesis configuration parameters of the
> Cadence I2C IP. Different SoCs might use different values for these
> parameters.
>
> Currently the driver has the maximum transfer length hardcoded to 255.
> Trying to use the driver with an IP instance that uses smaller values for
> these will work for short transfers. But longer transfers will fail.
>
> The maximum transfer length can easily be detected at runtime since the
> unused MSBs of the transfer length register are hardwired to 0. Writing
> 0xff and then reading back the value will give the maximum transfer length.
>
> These changes have been tested with
> 1) The Xilinx MPSoC for which this driver was originally written which
> has the previous hardcoded settings of 16 and 255.
> 2) Another instance of the Cadence I2C IP with FIFO depth of 8 and
> maximum transfer length of 16.
>
> Without these changes the latter would fail for I2C transfers longer than
> 16. With the updated driver both work fine even for longer transfers.
>
> Note that the IP core and driver support chaining multiple transfers into a
> single longer transfer using the HOLD bit. So the maximum transfer size is
> not the limit for the length of the I2C transfer, but the limit for how
> much data can be transferred without having to reprogram the control
> registers.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property
2023-03-17 14:54 [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Lars-Peter Clausen
2023-03-17 14:54 ` [PATCH v2 2/3] i2c: cadence: Allow to specify the FIFO depth Lars-Peter Clausen
2023-03-17 14:54 ` [PATCH v2 3/3] i2c: cadence: Detect maximum transfer size Lars-Peter Clausen
@ 2023-03-20 10:13 ` Michal Simek
2023-03-21 20:20 ` Rob Herring
2023-03-29 19:19 ` Wolfram Sang
4 siblings, 0 replies; 10+ messages in thread
From: Michal Simek @ 2023-03-20 10:13 UTC (permalink / raw)
To: Lars-Peter Clausen, Wolfram Sang
Cc: Shubhrajyoti Datta, Rob Herring, Krzysztof Kozlowski, linux-i2c,
devicetree
On 3/17/23 15:54, Lars-Peter Clausen wrote:
> The depth of the FIFO of the Cadence I2C controller IP is a synthesis
> configuration parameter. Different instances of the IP can have different
> values. For correct operation software needs to be aware of the size of the
> FIFO.
>
> Add the documentation for the devicetree property that describes the FIFO
> depth of the IP core.
>
> The default value of 16 is for backwards compatibility reasons with
> existing hardware descriptions where this property is not specified and
> software has assumed that the FIFO depth is 16.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
> Changes since v1:
> * Remove quotes around "/schemas/types.yaml#/definitions/uint32"
> * Add `enum` describing valid values
> * Use `fifo-depth` instead of `cdns,fifo-depth`
> * Use `bytes` instead of `words` for the property unit
> ---
> Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml
> index 2e95cda7262a..2401d1e19916 100644
> --- a/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml
> +++ b/Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml
> @@ -38,6 +38,13 @@ properties:
> description: |
> Input clock name.
>
> + fifo-depth:
> + description:
> + Size of the data FIFO in bytes.
> + $ref: /schemas/types.yaml#/definitions/uint32
> + default: 16
> + enum: [2, 4, 8, 16, 32, 64, 128, 256]
> +
> required:
> - compatible
> - reg
> @@ -57,4 +64,5 @@ examples:
> clock-frequency = <400000>;
> #address-cells = <1>;
> #size-cells = <0>;
> + fifo-depth = <8>;
> };
Acked-by: Michal Simek <michal.simek@amd.com>
Thanks,
Michal
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property
2023-03-17 14:54 [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Lars-Peter Clausen
` (2 preceding siblings ...)
2023-03-20 10:13 ` [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Michal Simek
@ 2023-03-21 20:20 ` Rob Herring
2023-03-29 19:19 ` Wolfram Sang
4 siblings, 0 replies; 10+ messages in thread
From: Rob Herring @ 2023-03-21 20:20 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: devicetree, Wolfram Sang, Shubhrajyoti Datta, Rob Herring,
Michal Simek, Krzysztof Kozlowski, linux-i2c
On Fri, 17 Mar 2023 07:54:39 -0700, Lars-Peter Clausen wrote:
> The depth of the FIFO of the Cadence I2C controller IP is a synthesis
> configuration parameter. Different instances of the IP can have different
> values. For correct operation software needs to be aware of the size of the
> FIFO.
>
> Add the documentation for the devicetree property that describes the FIFO
> depth of the IP core.
>
> The default value of 16 is for backwards compatibility reasons with
> existing hardware descriptions where this property is not specified and
> software has assumed that the FIFO depth is 16.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> ---
> Changes since v1:
> * Remove quotes around "/schemas/types.yaml#/definitions/uint32"
> * Add `enum` describing valid values
> * Use `fifo-depth` instead of `cdns,fifo-depth`
> * Use `bytes` instead of `words` for the property unit
> ---
> Documentation/devicetree/bindings/i2c/cdns,i2c-r1p10.yaml | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
Reviewed-by: Rob Herring <robh@kernel.org>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property
2023-03-17 14:54 [PATCH v2 1/3] dt-bindings: i2c: cadence: Document `fifo-depth` property Lars-Peter Clausen
` (3 preceding siblings ...)
2023-03-21 20:20 ` Rob Herring
@ 2023-03-29 19:19 ` Wolfram Sang
4 siblings, 0 replies; 10+ messages in thread
From: Wolfram Sang @ 2023-03-29 19:19 UTC (permalink / raw)
To: Lars-Peter Clausen
Cc: Michal Simek, Shubhrajyoti Datta, Rob Herring,
Krzysztof Kozlowski, linux-i2c, devicetree
[-- Attachment #1: Type: text/plain, Size: 707 bytes --]
On Fri, Mar 17, 2023 at 07:54:39AM -0700, Lars-Peter Clausen wrote:
> The depth of the FIFO of the Cadence I2C controller IP is a synthesis
> configuration parameter. Different instances of the IP can have different
> values. For correct operation software needs to be aware of the size of the
> FIFO.
>
> Add the documentation for the devicetree property that describes the FIFO
> depth of the IP core.
>
> The default value of 16 is for backwards compatibility reasons with
> existing hardware descriptions where this property is not specified and
> software has assumed that the FIFO depth is 16.
>
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Applied to for-next, thanks!
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread