[Arm-dev] [PATCH 09/11] Add SMBus block read/write support for Designware I2C

Fri Nov 11 02:47:51 UTC 2016
Duc Dang <dhdang at apm.com>

The posted upstream patch (v4, https://lkml.org/lkml/2016/11/9/930)
already got an ack by Jarkko Nikula (https://lkml.org/lkml/2016/11/10/193)

Signed-off-by: Duc Dang <dhdang at apm.com>
---
 ...are-Implement-support-for-SMBus-block-rea.patch | 135 +++++++++++++++++++++
 SPECS/kernel-aarch64.spec                          |   3 +
 2 files changed, 138 insertions(+)
 create mode 100644 SOURCES/1019-i2c-designware-Implement-support-for-SMBus-block-rea.patch

diff --git a/SOURCES/1019-i2c-designware-Implement-support-for-SMBus-block-rea.patch b/SOURCES/1019-i2c-designware-Implement-support-for-SMBus-block-rea.patch
new file mode 100644
index 0000000..eb732e3
--- /dev/null
+++ b/SOURCES/1019-i2c-designware-Implement-support-for-SMBus-block-rea.patch
@@ -0,0 +1,135 @@
+From 4211222134d5758e53f667c6ebdf1e0c55d9137b Mon Sep 17 00:00:00 2001
+From: Tin Huynh <tnhuynh at apm.com>
+Date: Thu, 10 Nov 2016 17:33:00 -0600
+Subject: [PATCH] i2c: designware: Implement support for SMBus block read and
+ write
+
+Free and Open IPMI use SMBUS BLOCK Read/Write to support SSIF protocol.
+However, I2C Designware Core Driver doesn't handle the case at the moment.
+The below patch supports this feature.
+
+Signed-off-by: Tin Huynh <tnhuynh at apm.com>
+Acked-by: Jarkko Nikula <jarkko.nikula at linux.intel.com>
+
+[Apply from posted v4 patch (already acked-by Jarkko Nikula,
+https://lkml.org/lkml/2016/11/10/193) to CentOS 7.3 AltArch]
+Signed-off-by: Duc Dang <dhdang at apm.com>
+---
+ drivers/i2c/busses/i2c-designware-core.c    | 46 +++++++++++++++++++++++++++--
+ drivers/i2c/busses/i2c-designware-pcidrv.c  |  1 +
+ drivers/i2c/busses/i2c-designware-platdrv.c |  1 +
+ 3 files changed, 45 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
+index 10fbd6d..927849b 100644
+--- a/drivers/i2c/busses/i2c-designware-core.c
++++ b/drivers/i2c/busses/i2c-designware-core.c
+@@ -470,6 +470,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ 	intr_mask = DW_IC_INTR_DEFAULT_MASK;
+ 
+ 	for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
++		u32 flags = msgs[dev->msg_write_idx].flags;
++
+ 		/*
+ 		 * if target address has changed, we need to
+ 		 * reprogram the target address in the i2c
+@@ -515,8 +517,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ 			 * detected from the registers so we set it always
+ 			 * when writing/reading the last byte.
+ 			 */
++
++			/*
++			 * i2c-core.c always sets the buffer length of
++			 * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will
++			 * be adjusted when receiving the first byte.
++			 * Thus we can't stop the transaction here.
++			 */
+ 			if (dev->msg_write_idx == dev->msgs_num - 1 &&
+-			    buf_len == 1)
++			    buf_len == 1 && !(flags & I2C_M_RECV_LEN))
+ 				cmd |= BIT(9);
+ 
+ 			if (need_restart) {
+@@ -541,7 +550,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ 		dev->tx_buf = buf;
+ 		dev->tx_buf_len = buf_len;
+ 
+-		if (buf_len > 0) {
++		/*
++		 * Because we don't know the buffer length in the
++		 * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop
++		 * the transaction here.
++		 */
++		if (buf_len > 0 || flags & I2C_M_RECV_LEN) {
+ 			/* more bytes to be written */
+ 			dev->status |= STATUS_WRITE_IN_PROGRESS;
+ 			break;
+@@ -562,6 +576,24 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev)
+ 	dw_writel(dev, intr_mask,  DW_IC_INTR_MASK);
+ }
+ 
++static u8
++i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len)
++{
++	struct i2c_msg *msgs = dev->msgs;
++	u32 flags = msgs[dev->msg_read_idx].flags;
++
++	/*
++	 * Adjust the buffer length and mask the flag
++	 * after receiving the first byte.
++	 */
++	len += (flags & I2C_CLIENT_PEC) ? 2 : 1;
++	dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding);
++	msgs[dev->msg_read_idx].len = len;
++	msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN;
++
++	return len;
++}
++
+ static void
+ i2c_dw_read(struct dw_i2c_dev *dev)
+ {
+@@ -586,7 +618,15 @@ i2c_dw_read(struct dw_i2c_dev *dev)
+ 		rx_valid = dw_readl(dev, DW_IC_RXFLR);
+ 
+ 		for (; len > 0 && rx_valid > 0; len--, rx_valid--) {
+-			*buf++ = dw_readl(dev, DW_IC_DATA_CMD);
++			u32 flags = msgs[dev->msg_read_idx].flags;
++
++			*buf = dw_readl(dev, DW_IC_DATA_CMD);
++			/* Ensure length byte is a valid value */
++			if (flags & I2C_M_RECV_LEN &&
++				*buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) {
++				len = i2c_dw_recv_len(dev, *buf);
++			}
++			buf++;
+ 			dev->rx_outstanding--;
+ 		}
+ 
+diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
+index 7368be0..13578d9 100644
+--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
++++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
+@@ -78,6 +78,7 @@ struct dw_pci_controller {
+ 					I2C_FUNC_SMBUS_BYTE |		\
+ 					I2C_FUNC_SMBUS_BYTE_DATA |	\
+ 					I2C_FUNC_SMBUS_WORD_DATA |	\
++					I2C_FUNC_SMBUS_BLOCK_DATA |	\
+ 					I2C_FUNC_SMBUS_I2C_BLOCK)
+ 
+ /* BayTrail HCNT/LCNT/SDA hold time */
+diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
+index 438f1b4..f67aaed 100644
+--- a/drivers/i2c/busses/i2c-designware-platdrv.c
++++ b/drivers/i2c/busses/i2c-designware-platdrv.c
+@@ -210,6 +210,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
+ 		I2C_FUNC_SMBUS_BYTE |
+ 		I2C_FUNC_SMBUS_BYTE_DATA |
+ 		I2C_FUNC_SMBUS_WORD_DATA |
++		I2C_FUNC_SMBUS_BLOCK_DATA |
+ 		I2C_FUNC_SMBUS_I2C_BLOCK;
+ 	if (clk_freq == 100000)
+ 		dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE |
+-- 
+1.8.3.1
+
diff --git a/SPECS/kernel-aarch64.spec b/SPECS/kernel-aarch64.spec
index 4c20b21..de899ca 100644
--- a/SPECS/kernel-aarch64.spec
+++ b/SPECS/kernel-aarch64.spec
@@ -343,6 +343,7 @@ Patch1015: 1015-drivers-net-xgene-fix-Use-GPIO-to-get-link-status.patch
 Patch1016: 1016-drivers-net-xgene-fix-Disable-coalescing-on-v1-hardw.patch
 Patch1017: 1017-drivers-net-xgene-fix-Coalescing-values-for-v2-hardw.patch
 Patch1018: 1018-ACPI-PCI-fix-GIC-irq-model-default-PCI-IRQ-polarity.patch
+Patch1019: 1019-i2c-designware-Implement-support-for-SMBus-block-rea.patch
 
 # QDF2400 Patches
 Patch4000: 4000-arm64-Define-Qualcomm-Technologies-ARMv8-CPU.patch
@@ -696,6 +697,7 @@ git am %{PATCH1015}
 git am %{PATCH1016}
 git am %{PATCH1017}
 git am %{PATCH1018}
+git am %{PATCH1019}
 
 # Apply QDF2400 patches
 git am %{PATCH4000}
@@ -1475,6 +1477,7 @@ fi
 
 %changelog
 * Thu Nov 10 2016 Duc Dang <dhdang at apm.com> [4.5.0-17.el7]
+- Integrated posted patch to support SMBus block read/write for Designware I2C
 - Integrate upstream fix for GIC default PCI IRQ polarity
 - Integrate upstream updates for X-Gene Enet driver
 - Avoid dma_buffer overrun for SlimPRO I2C driver 
-- 
1.8.3.1