lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230403064528.343866-3-jiawenwu@trustnetic.com>
Date:   Mon,  3 Apr 2023 14:45:24 +0800
From:   Jiawen Wu <jiawenwu@...stnetic.com>
To:     netdev@...r.kernel.org, linux@...linux.org.uk
Cc:     mengyuanlou@...-swift.com, Jiawen Wu <jiawenwu@...stnetic.com>
Subject: [PATCH net-next 2/6] net: txgbe: Implement I2C bus master driver

I2C bus is integrated in Wangxun 10Gb ethernet chip. Implement I2C bus
driver to receive I2C messages.

Signed-off-by: Jiawen Wu <jiawenwu@...stnetic.com>
---
 drivers/net/ethernet/wangxun/Kconfig          |   1 +
 .../net/ethernet/wangxun/txgbe/txgbe_phy.c    | 141 ++++++++++++++++++
 .../net/ethernet/wangxun/txgbe/txgbe_type.h   |  26 ++++
 3 files changed, 168 insertions(+)

diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig
index c9d88673d306..8cbf0dd48a2c 100644
--- a/drivers/net/ethernet/wangxun/Kconfig
+++ b/drivers/net/ethernet/wangxun/Kconfig
@@ -41,6 +41,7 @@ config TXGBE
 	tristate "Wangxun(R) 10GbE PCI Express adapters support"
 	depends on PCI
 	select LIBWX
+	select I2C
 	help
 	  This driver supports Wangxun(R) 10GbE PCI Express family of
 	  adapters.
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 163acb7e515e..f8a4b211f4e8 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -2,9 +2,12 @@
 /* Copyright (c) 2015 - 2023 Beijing WangXun Technology Co., Ltd. */
 
 #include <linux/gpio/property.h>
+#include <linux/iopoll.h>
+#include <linux/i2c.h>
 #include <linux/pci.h>
 
 #include "../libwx/wx_type.h"
+#include "../libwx/wx_hw.h"
 #include "txgbe_type.h"
 #include "txgbe_phy.h"
 
@@ -60,6 +63,130 @@ static int txgbe_swnodes_register(struct txgbe *txgbe)
 	return software_node_register_node_group(nodes->group);
 }
 
+static void txgbe_i2c_start(struct wx *wx, u16 dev_addr)
+{
+	wr32(wx, TXGBE_I2C_ENABLE, 0);
+
+	wr32(wx, TXGBE_I2C_CON,
+	     (TXGBE_I2C_CON_MASTER_MODE |
+	      TXGBE_I2C_CON_SPEED(1) |
+	      TXGBE_I2C_CON_RESTART_EN |
+	      TXGBE_I2C_CON_SLAVE_DISABLE));
+	/* Default addr is 0xA0 ,bit 0 is configure for read/write! */
+	wr32(wx, TXGBE_I2C_TAR, dev_addr);
+	wr32(wx, TXGBE_I2C_SS_SCL_HCNT, 600);
+	wr32(wx, TXGBE_I2C_SS_SCL_LCNT, 600);
+	wr32(wx, TXGBE_I2C_RX_TL, 0); /* 1byte for rx full signal */
+	wr32(wx, TXGBE_I2C_TX_TL, 4);
+	wr32(wx, TXGBE_I2C_SCL_STUCK_TIMEOUT, 0xFFFFFF);
+	wr32(wx, TXGBE_I2C_SDA_STUCK_TIMEOUT, 0xFFFFFF);
+
+	wr32(wx, TXGBE_I2C_INTR_MASK, 0);
+	wr32(wx, TXGBE_I2C_ENABLE, 1);
+}
+
+static int txgbe_read_i2c_bytes(struct wx *wx, u8 addr, u16 len, u8 *buf)
+{
+	int err, i;
+	u16 val;
+
+	for (i = 0; i < len; i++) {
+		/* wait tx empty */
+		err = read_poll_timeout(rd32, val,
+					(val & TXGBE_I2C_INTR_STAT_TEMP) ==
+					TXGBE_I2C_INTR_STAT_TEMP,
+					100, 1000, false, wx,
+					TXGBE_I2C_RAW_INTR_STAT);
+		if (err != 0)
+			return err;
+
+		/* read data */
+		wr32(wx, TXGBE_I2C_DATA_CMD, (addr + i) | TXGBE_I2C_DATA_CMD_STOP);
+		wr32(wx, TXGBE_I2C_DATA_CMD, TXGBE_I2C_DATA_CMD_READ);
+
+		/* wait for read complete */
+		err = read_poll_timeout(rd32, val,
+					(val & TXGBE_I2C_INTR_STAT_RFUL) ==
+					TXGBE_I2C_INTR_STAT_RFUL,
+					100, 1000, false, wx,
+					TXGBE_I2C_RAW_INTR_STAT);
+		if (err != 0)
+			return err;
+
+		buf[i] = 0xFF & rd32(wx, TXGBE_I2C_DATA_CMD);
+	}
+
+	return 0;
+}
+
+static int txgbe_i2c_xfer(struct i2c_adapter *i2c_adap,
+			  struct i2c_msg *msg, int num_msgs)
+{
+	struct wx *wx = i2c_get_adapdata(i2c_adap);
+	u8 *dev_addr = msg[0].buf;
+	bool read = false;
+	int i, ret;
+	u8 *buf;
+	u16 len;
+
+	txgbe_i2c_start(wx, msg[0].addr);
+
+	for (i = 0; i < num_msgs; i++) {
+		if (msg[i].flags & I2C_M_RD) {
+			read = true;
+			len = msg[i].len;
+			buf = msg[i].buf;
+		}
+	}
+
+	if (!read) {
+		wx_err(wx, "I2C write not supported\n");
+		return num_msgs;
+	}
+
+	ret = txgbe_read_i2c_bytes(wx, *dev_addr, len, buf);
+	if (!ret)
+		ret = num_msgs;
+
+	return ret;
+}
+
+static u32 txgbe_i2c_func(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm txgbe_i2c_algo = {
+	.master_xfer = txgbe_i2c_xfer,
+	.functionality = txgbe_i2c_func,
+};
+
+static int txgbe_i2c_adapter_add(struct txgbe *txgbe)
+{
+	struct pci_dev *pdev = txgbe->wx->pdev;
+	struct i2c_adapter *i2c_adap;
+	int ret;
+
+	i2c_adap = devm_kzalloc(&pdev->dev, sizeof(*i2c_adap), GFP_KERNEL);
+	if (!i2c_adap)
+		return -ENOMEM;
+
+	i2c_adap->owner = THIS_MODULE;
+	i2c_adap->algo = &txgbe_i2c_algo;
+	i2c_adap->dev.parent = &pdev->dev;
+	i2c_adap->dev.fwnode = software_node_fwnode(txgbe->nodes.group[SWNODE_I2C]);
+	strscpy(i2c_adap->name, "txgbe_i2c", sizeof(i2c_adap->name));
+
+	i2c_set_adapdata(i2c_adap, txgbe->wx);
+	ret = i2c_add_adapter(i2c_adap);
+	if (ret)
+		return ret;
+
+	txgbe->i2c_adap = i2c_adap;
+
+	return 0;
+}
+
 int txgbe_init_phy(struct txgbe *txgbe)
 {
 	int ret;
@@ -70,10 +197,24 @@ int txgbe_init_phy(struct txgbe *txgbe)
 		return ret;
 	}
 
+	ret = txgbe_i2c_adapter_add(txgbe);
+	if (ret) {
+		wx_err(txgbe->wx, "failed to init i2c interface: %d\n", ret);
+		goto err;
+	}
+
 	return 0;
+
+err:
+	txgbe_remove_phy(txgbe);
+
+	return ret;
 }
 
 void txgbe_remove_phy(struct txgbe *txgbe)
 {
+	if (txgbe->i2c_adap)
+		i2c_del_adapter(txgbe->i2c_adap);
+
 	software_node_unregister_node_group(txgbe->nodes.group);
 }
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index d30684378f4e..de488609f713 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -55,6 +55,31 @@
 #define TXGBE_TS_CTL                            0x10300
 #define TXGBE_TS_CTL_EVAL_MD                    BIT(31)
 
+/* I2C registers */
+#define TXGBE_I2C_CON                           0x14900 /* I2C Control */
+#define TXGBE_I2C_CON_SLAVE_DISABLE             BIT(6)
+#define TXGBE_I2C_CON_RESTART_EN                BIT(5)
+#define TXGBE_I2C_CON_SPEED(_v)                 FIELD_PREP(GENMASK(2, 1), _v)
+#define TXGBE_I2C_CON_MASTER_MODE               BIT(0)
+#define TXGBE_I2C_TAR                           0x14904 /* I2C Target Address */
+#define TXGBE_I2C_DATA_CMD                      0x14910 /* I2C Rx/Tx Data Buf and Cmd */
+#define TXGBE_I2C_DATA_CMD_STOP                 BIT(9)
+#define TXGBE_I2C_DATA_CMD_READ                 (BIT(8) | TXGBE_I2C_DATA_CMD_STOP)
+#define TXGBE_I2C_SS_SCL_HCNT                   0x14914
+#define TXGBE_I2C_SS_SCL_LCNT                   0x14918
+#define TXGBE_I2C_INTR_MASK                     0x14930 /* I2C Interrupt Mask */
+#define TXGBE_I2C_RAW_INTR_STAT                 0x14934 /* I2C Raw Interrupt Status */
+#define TXGBE_I2C_INTR_STAT_RFUL                BIT(2)
+#define TXGBE_I2C_INTR_STAT_TEMP                BIT(4)
+#define TXGBE_I2C_RX_TL                         0x14938 /* I2C Receive FIFO Threshold */
+#define TXGBE_I2C_TX_TL                         0x1493C /* I2C TX FIFO Threshold */
+#define TXGBE_I2C_ENABLE                        0x1496C /* I2C Enable */
+#define TXGBE_I2C_SCL_STUCK_TIMEOUT             0x149AC
+#define TXGBE_I2C_SDA_STUCK_TIMEOUT             0x149B0
+
+#define TXGBE_I2C_SLAVE_ADDR                    (0xA0 >> 1)
+#define TXGBE_I2C_EEPROM_DEV_ADDR               0xA0
+
 /* Part Number String Length */
 #define TXGBE_PBANUM_LENGTH                     32
 
@@ -139,6 +164,7 @@ struct txgbe_nodes {
 struct txgbe {
 	struct wx *wx;
 	struct txgbe_nodes nodes;
+	struct i2c_adapter *i2c_adap;
 };
 
 #endif /* _TXGBE_TYPE_H_ */
-- 
2.27.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ