public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Jijie Shao <shaojijie@huawei.com>
To: <yisen.zhuang@huawei.com>, <salil.mehta@huawei.com>,
	<davem@davemloft.net>, <edumazet@google.com>, <kuba@kernel.org>,
	<pabeni@redhat.com>, <horms@kernel.org>
Cc: <shenjian15@huawei.com>, <wangpeiyang1@huawei.com>,
	<liuyonglong@huawei.com>, <shaojijie@huawei.com>,
	<sudongming1@huawei.com>, <xujunsheng@huawei.com>,
	<shiyongbang@huawei.com>, <netdev@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>
Subject: [RFC PATCH net-next 03/10] net: hibmcge: Add mdio and hardware configuration supported in this module
Date: Wed, 31 Jul 2024 17:42:38 +0800	[thread overview]
Message-ID: <20240731094245.1967834-4-shaojijie@huawei.com> (raw)
In-Reply-To: <20240731094245.1967834-1-shaojijie@huawei.com>

this driver using phy through genphy device. Implements the C22
read and write PHY registers interfaces.

Some hardware interfaces related to the PHY are also implemented
in this patch.

Signed-off-by: Jijie Shao <shaojijie@huawei.com>
---
 .../ethernet/hisilicon/hibmcge/hbg_common.h   |  34 +++
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.c   | 170 +++++++++++
 .../net/ethernet/hisilicon/hibmcge/hbg_hw.h   |   3 +
 .../net/ethernet/hisilicon/hibmcge/hbg_main.c |  26 +-
 .../net/ethernet/hisilicon/hibmcge/hbg_mdio.c | 276 ++++++++++++++++++
 .../net/ethernet/hisilicon/hibmcge/hbg_mdio.h |  13 +
 .../net/ethernet/hisilicon/hibmcge/hbg_reg.h  |  46 +++
 .../hisilicon/hibmcge/hbg_reg_union.h         | 112 +++++++
 8 files changed, 678 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
 create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
 create mode 100644 drivers/net/ethernet/hisilicon/hibmcge/hbg_reg_union.h

diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
index b56b5179f735..364aab4d61b9 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
@@ -5,7 +5,27 @@
 #define __HBG_COMMON_H
 
 #include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/linkmode.h>
 #include <linux/pci.h>
+#include "hbg_reg.h"
+
+#define HBG_STATUS_DISABLE		0x0
+#define HBG_STATUS_ENABLE		0x1
+#define HBG_DEFAULT_MTU_SIZE		1500
+#define HBG_RX_SKIP1			0x00
+#define HBG_RX_SKIP2			0x01
+#define HBG_LINK_DOWN	0
+#define HBG_LINK_UP	1
+
+enum hbg_dir {
+	HBG_DIR_TX = 1 << 0,
+	HBG_DIR_RX = 1 << 1,
+	HBG_DIR_TX_RX = HBG_DIR_TX | HBG_DIR_RX,
+};
+
+#define hbg_dir_has_tx(dir) ((dir) & HBG_DIR_TX)
+#define hbg_dir_has_rx(dir) ((dir) & HBG_DIR_RX)
 
 enum hbg_nic_state {
 	HBG_NIC_STATE_INITED = 0,
@@ -31,12 +51,26 @@ struct hbg_dev_specs {
 	u32 rx_buf_size;
 };
 
+struct hbg_mac {
+	struct mii_bus *mdio_bus;
+	struct phy_device *phydev;
+	u8 phy_addr;
+
+	u32 speed;
+	u32 duplex;
+	u32 autoneg;
+	u32 link_status;
+
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
+};
+
 struct hbg_priv {
 	struct net_device *netdev;
 	struct pci_dev *pdev;
 	u8 __iomem *io_base;
 	struct hbg_dev_specs dev_specs;
 	unsigned long state;
+	struct hbg_mac mac;
 };
 
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
index ca1cb09c90ff..b2465ba06cee 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
@@ -70,3 +70,173 @@ int hbg_hw_dev_specs_init(struct hbg_priv *priv)
 
 	return 0;
 }
+
+int hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex)
+{
+	if (speed != HBG_PORT_MODE_SGMII_10M &&
+	    speed != HBG_PORT_MODE_SGMII_100M &&
+	    speed != HBG_PORT_MODE_SGMII_1000M)
+		return -EOPNOTSUPP;
+
+	if (duplex != DUPLEX_FULL && duplex != DUPLEX_HALF)
+		return -EOPNOTSUPP;
+
+	if (speed == HBG_PORT_MODE_SGMII_1000M && duplex == DUPLEX_HALF)
+		return -EOPNOTSUPP;
+
+	hbg_reg_write_field(priv, HBG_REG_PORT_MODE_ADDR,
+			    HBG_REG_PORT_MODE_M, speed);
+	hbg_reg_write_bit(priv, HBG_REG_DUPLEX_TYPE_ADDR,
+			  HBG_REG_DUPLEX_B, duplex);
+
+	priv->mac.speed = speed;
+	priv->mac.duplex = duplex;
+
+	return 0;
+}
+
+/* sgmii autoneg always enable */
+int hbg_hw_sgmii_autoneg(struct hbg_priv *priv)
+{
+#define HBG_HW_DEFAULT_16_BIT_CNTR	0x3F
+#define HBG_HW_AUTONEG_TIMEOUT_MS	1000
+#define HBG_HW_AUTONEG_TIMEOUT_STEP	5
+
+	struct hbg_transmit_control control;
+	struct hbg_an_state an_state;
+	u32 wait_time, speed;
+
+	/* if already autoneg ok, return directly */
+	an_state.bits = hbg_reg_read(priv, HBG_REG_AN_NEG_STATE_ADDR);
+	if (an_state.an_done)
+		return 0;
+
+	hbg_reg_write(priv, HBG_REG_TX_LOCAL_PAGE_ADDR, HBG_STATUS_ENABLE);
+	hbg_reg_write(priv, HBG_REG_16_BIT_CNTR_ADDR, HBG_HW_DEFAULT_16_BIT_CNTR);
+	/* set BIT(1) */
+	hbg_reg_write(priv, HBG_REG_LD_LINK_COUNTER_ADDR, 0x2);
+
+	control.bits = hbg_reg_read(priv, HBG_REG_TRANSMIT_CONTROL_ADDR);
+	control.an_enable = HBG_STATUS_DISABLE;
+	hbg_reg_write(priv, HBG_REG_TRANSMIT_CONTROL_ADDR, control.bits);
+	control.an_enable = HBG_STATUS_ENABLE;
+	hbg_reg_write(priv, HBG_REG_TRANSMIT_CONTROL_ADDR, control.bits);
+
+	wait_time = 0;
+	do {
+		msleep(HBG_HW_AUTONEG_TIMEOUT_STEP);
+		wait_time += HBG_HW_AUTONEG_TIMEOUT_STEP;
+
+		an_state.bits = hbg_reg_read(priv, HBG_REG_AN_NEG_STATE_ADDR);
+		if (an_state.an_done)
+			break;
+	} while (wait_time < HBG_HW_AUTONEG_TIMEOUT_MS);
+
+	if (!an_state.an_done)
+		return -ETIMEDOUT;
+
+	switch (an_state.speed) {
+	case 0x0:
+		speed = HBG_PORT_MODE_SGMII_10M;
+		break;
+	case 0x1:
+		speed = HBG_PORT_MODE_SGMII_100M;
+		break;
+	case 0x2:
+		speed = HBG_PORT_MODE_SGMII_1000M;
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return hbg_hw_adjust_link(priv, speed, an_state.duplex);
+}
+
+static void hbg_hw_init_transmit_control(struct hbg_priv *priv)
+{
+	struct hbg_transmit_control control = {
+		.bits = 0,
+		.pad_enalbe = HBG_STATUS_ENABLE,
+		.crc_add = HBG_STATUS_ENABLE,
+		.an_enable = HBG_STATUS_ENABLE,
+	};
+
+	hbg_reg_write(priv, HBG_REG_TRANSMIT_CONTROL_ADDR, control.bits);
+}
+
+static void hbg_hw_init_rx_ctrl(struct hbg_priv *priv)
+{
+	struct hbg_rx_ctrl ctrl = {
+		.bits = 0,
+		.rx_get_addr_mode = HBG_STATUS_ENABLE,
+		.time_inf_en = HBG_STATUS_DISABLE,
+		.rx_align_num = NET_IP_ALIGN,
+		.rxbuf_1st_skip_size = HBG_RX_SKIP1,
+		.rxbuf_1st_skip_size2 = HBG_RX_SKIP2,
+		.port_num = priv->dev_specs.mac_id,
+	};
+
+	hbg_reg_write(priv, HBG_REG_RX_CTRL_ADDR, ctrl.bits);
+}
+
+static void hbg_hw_init_rx_pkt_mode(struct hbg_priv *priv)
+{
+/* 0x0: no parse, 0x1: parse from L2 layer, 0x10: parse from IP layer */
+#define HBG_RX_PKT_PARSE_MODE	0x1
+
+	struct hbg_rx_pkt_mode mode = {
+		.bits = 0,
+		.parse_mode = HBG_RX_PKT_PARSE_MODE,
+	};
+
+	hbg_reg_write(priv, HBG_REG_RX_PKT_MODE_ADDR, mode.bits);
+}
+
+static void hbg_hw_init_recv_ctrl(struct hbg_priv *priv)
+{
+	struct hbg_recv_control ctrl = {
+		.bits = 0,
+		.strip_pad_en = HBG_STATUS_ENABLE,
+	};
+
+	hbg_reg_write(priv, HBG_REG_RECV_CONTROL_ADDR, ctrl.bits);
+}
+
+static void hbg_hw_init_rx_control(struct hbg_priv *priv)
+{
+	hbg_reg_write_field(priv, HBG_REG_RX_BUF_SIZE_ADDR,
+			    HBG_REG_RX_BUF_SIZE_M, priv->dev_specs.rx_buf_size);
+	hbg_hw_init_rx_ctrl(priv);
+	hbg_hw_init_rx_pkt_mode(priv);
+	hbg_hw_init_recv_ctrl(priv);
+	hbg_reg_write_bit(priv, HBG_REG_CF_CRC_STRIP_ADDR,
+			  HBG_REG_CF_CRC_STRIP_B, HBG_STATUS_DISABLE);
+}
+
+int hbg_hw_init(struct hbg_priv *priv)
+{
+/* little endian or big endian.
+ * ctrl means packet description, data means skb packet data
+ */
+#define HBG_ENDIAN_CTRL_LE_DATA_BE	0x0
+
+	int ret;
+
+	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT);
+	if (ret)
+		return ret;
+
+	ret = hbg_hw_dev_specs_init(priv);
+	if (ret)
+		return ret;
+
+	hbg_reg_write_field(priv, HBG_REG_BUS_CTRL_ADDR,
+			    HBG_REG_BUS_CTRL_ENDIAN_M,
+			    HBG_ENDIAN_CTRL_LE_DATA_BE);
+	hbg_reg_write_bit(priv, HBG_REG_MODE_CHANGE_EN_ADDR,
+			  HBG_REG_MODE_CHANGE_EN_B, HBG_STATUS_ENABLE);
+
+	hbg_hw_init_rx_control(priv);
+	hbg_hw_init_transmit_control(priv);
+	return 0;
+}
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
index 61c6db948364..79a529d7212b 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
@@ -57,5 +57,8 @@ static inline void hbg_reg_write64(struct hbg_priv *priv, u32 reg_addr,
 
 int hbg_hw_event_notify(struct hbg_priv *priv, enum hbg_hw_event_type event_type);
 int hbg_hw_dev_specs_init(struct hbg_priv *priv);
+int hbg_hw_adjust_link(struct hbg_priv *priv, u32 speed, u32 duplex);
+int hbg_hw_sgmii_autoneg(struct hbg_priv *priv);
+int hbg_hw_init(struct hbg_priv *pri);
 
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
index df0fc6a1059b..940e1eef70a4 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
@@ -7,17 +7,39 @@
 #include "hbg_common.h"
 #include "hbg_hw.h"
 #include "hbg_main.h"
+#include "hbg_mdio.h"
+
+static const u32 hbg_mode_ability[] = {
+	ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
+	ETHTOOL_LINK_MODE_100baseT_Full_BIT,
+	ETHTOOL_LINK_MODE_100baseT_Half_BIT,
+	ETHTOOL_LINK_MODE_10baseT_Full_BIT,
+	ETHTOOL_LINK_MODE_10baseT_Half_BIT,
+	ETHTOOL_LINK_MODE_Autoneg_BIT,
+	ETHTOOL_LINK_MODE_TP_BIT,
+};
+
+static int hbg_mac_init(struct hbg_priv *priv)
+{
+	struct hbg_mac *mac = &priv->mac;
+	u32 i;
+
+	for (i = 0; i < ARRAY_SIZE(hbg_mode_ability); i++)
+		linkmode_set_bit(hbg_mode_ability[i], mac->supported);
+
+	return hbg_mdio_init(priv);
+}
 
 static int hbg_init(struct net_device *netdev)
 {
 	struct hbg_priv *priv = netdev_priv(netdev);
 	int ret;
 
-	ret = hbg_hw_event_notify(priv, HBG_HW_EVENT_INIT);
+	ret = hbg_hw_init(priv);
 	if (ret)
 		return ret;
 
-	return hbg_hw_dev_specs_init(priv);
+	return hbg_mac_init(priv);
 }
 
 static int hbg_pci_init(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
new file mode 100644
index 000000000000..2d6f3ad10087
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0+
+// Copyright (c) 2024 Hisilicon Limited.
+
+#include <linux/phy.h>
+#include "hbg_common.h"
+#include "hbg_hw.h"
+#include "hbg_mdio.h"
+#include "hbg_reg.h"
+
+#define HBG_MAC_GET_PRIV(mac) ((mac)->mdio_bus->priv)
+#define HBG_MII_BUS_GET_MAC(bus) (&((struct hbg_priv *)(bus)->priv)->mac)
+
+#define HBG_MDIO_FREQUENCE_2_5M		0x1
+#define HBG_MDIO_C22_MODE		0x1
+
+#define HBG_MDIO_C22_REG_WRITE		0x1
+#define HBG_MDIO_C22_REG_READ		0x2
+
+static void hbg_mdio_set_command(struct hbg_mac *mac,
+				 struct hbg_mdio_command *command)
+{
+	hbg_reg_write(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_COMMAND_REG_ADDR,
+		      command->bits);
+}
+
+static void hbg_mdio_get_command(struct hbg_mac *mac,
+				 struct hbg_mdio_command *command)
+{
+	command->bits = hbg_reg_read(HBG_MAC_GET_PRIV(mac),
+				     HBG_REG_MDIO_COMMAND_REG_ADDR);
+}
+
+static void hbg_mdio_set_wdata_reg(struct hbg_mac *mac, u16 wdata_value)
+{
+	hbg_reg_write_field(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_WDATA_REG_ADDR,
+			    HBG_REG_MDIO_WDATA_M, wdata_value);
+}
+
+static u32 hbg_mdio_get_rdata_reg(struct hbg_mac *mac)
+{
+	return hbg_reg_read_field(HBG_MAC_GET_PRIV(mac),
+				  HBG_REG_MDIO_RDATA_REG_ADDR,
+				  HBG_REG_MDIO_WDATA_M);
+}
+
+static int hbg_mdio_wait_ready(struct hbg_mac *mac)
+{
+#define HBG_MDIO_OP_TIMEOUT_MS		1000
+#define HBG_MDIO_OP_INTERVAL_MS		5
+
+	struct hbg_mdio_command command;
+	u32 timeout = 0;
+
+	do {
+		hbg_mdio_get_command(mac, &command);
+		if (command.mdio_start == 0)
+			/* the operation is complete */
+			return 0;
+
+		msleep(HBG_MDIO_OP_INTERVAL_MS);
+		timeout += HBG_MDIO_OP_INTERVAL_MS;
+	} while (timeout < HBG_MDIO_OP_TIMEOUT_MS);
+
+	return -ETIMEDOUT;
+}
+
+static int hbg_mdio_check_op_status(struct hbg_mac *mac)
+{
+	if (hbg_reg_read(HBG_MAC_GET_PRIV(mac), HBG_REG_MDIO_STA_REG_ADDR))
+		return -EBUSY;
+
+	return 0;
+}
+
+static int hbg_mdio_check_send_result(struct hbg_mac *mac)
+{
+	int ret;
+
+	ret = hbg_mdio_wait_ready(mac);
+	if (ret)
+		return ret;
+
+	return hbg_mdio_check_op_status(mac);
+}
+
+static int hbg_mdio_cmd_send(struct hbg_mac *mac, u32 prt_addr, u32 dev_addr,
+			     u32 type, u32 op_code)
+{
+	struct hbg_mdio_command mdio_cmd;
+
+	hbg_mdio_get_command(mac, &mdio_cmd);
+	mdio_cmd.mdio_st = type;
+	/* if auto scan enabled, this value need fix to 0 */
+	mdio_cmd.mdio_start = 0x1;
+	mdio_cmd.mdio_op = op_code;
+	mdio_cmd.mdio_prtad = prt_addr;
+	mdio_cmd.mdio_devad = dev_addr;
+	hbg_mdio_set_command(mac, &mdio_cmd);
+
+	/* wait operation complete and check the result */
+	return hbg_mdio_check_send_result(mac);
+}
+
+static int hbg_mdio_read22(struct mii_bus *bus, int phy_addr, int regnum)
+{
+	struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus);
+	int ret;
+
+	ret = hbg_mdio_check_op_status(mac);
+	if (ret)
+		return ret;
+
+	ret = hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE,
+				HBG_MDIO_C22_REG_READ);
+	if (ret)
+		return ret;
+
+	return hbg_mdio_get_rdata_reg(mac);
+}
+
+static int hbg_mdio_write22(struct mii_bus *bus, int phy_addr, int regnum,
+			    u16 val)
+{
+	struct hbg_mac *mac = HBG_MII_BUS_GET_MAC(bus);
+	int ret;
+
+	ret = hbg_mdio_check_op_status(mac);
+	if (ret)
+		return ret;
+
+	hbg_mdio_set_wdata_reg(mac, val);
+	return hbg_mdio_cmd_send(mac, phy_addr, regnum, HBG_MDIO_C22_MODE,
+				 HBG_MDIO_C22_REG_WRITE);
+}
+
+static int hbg_mdio_init_hw(struct hbg_mac *mac)
+{
+	u32 freq = HBG_MDIO_FREQUENCE_2_5M;
+	struct hbg_mdio_command cmd;
+
+	cmd.bits = 0;
+	cmd.mdio_auto_scan = HBG_STATUS_DISABLE;
+	cmd.mdio_st = HBG_MDIO_C22_MODE;
+
+	/* freq use two bits, which are stored in clk_sel and clk_sel_exp */
+	cmd.mdio_clk_sel = freq & 0x1;
+	cmd.mdio_clk_sel_exp = (((u32)freq) >> 1) & 0x1;
+
+	hbg_mdio_set_command(mac, &cmd);
+	return 0;
+}
+
+static void hbg_phy_adjust_link(struct net_device *netdev)
+{
+	struct hbg_priv *priv = netdev_priv(netdev);
+	struct phy_device *phydev = priv->mac.phydev;
+	u32 speed;
+
+	switch (phydev->speed) {
+	case SPEED_10:
+		speed = HBG_PORT_MODE_SGMII_10M;
+		break;
+	case SPEED_100:
+		speed = HBG_PORT_MODE_SGMII_100M;
+		break;
+	case SPEED_1000:
+		speed = HBG_PORT_MODE_SGMII_1000M;
+		break;
+	default:
+		return;
+	}
+
+	priv->mac.autoneg = phydev->autoneg;
+	hbg_hw_adjust_link(priv, speed, phydev->duplex);
+}
+
+static void hbg_phy_disconnect(void *data)
+{
+	phy_disconnect((struct phy_device *)data);
+}
+
+static int hbg_phy_connect(struct hbg_priv *priv)
+{
+	struct phy_device *phydev = priv->mac.phydev;
+	struct hbg_mac *mac = &priv->mac;
+	int ret;
+
+	linkmode_copy(phydev->supported, mac->supported);
+	linkmode_copy(phydev->advertising, mac->supported);
+
+	phy_connect_direct(priv->netdev, mac->phydev, hbg_phy_adjust_link,
+			   PHY_INTERFACE_MODE_SGMII);
+	ret = devm_add_action_or_reset(&priv->pdev->dev,
+				       hbg_phy_disconnect, mac->phydev);
+	if (ret)
+		return ret;
+
+	phy_attached_info(phydev);
+	return 0;
+}
+
+/* include phy link and mac link */
+u32 hbg_get_link_status(struct hbg_priv *priv)
+{
+	struct phy_device *phydev = priv->mac.phydev;
+	int ret;
+
+	if (!phydev)
+		return HBG_LINK_DOWN;
+
+	phy_read_status(phydev);
+	if ((phydev->state != PHY_UP && phydev->state != PHY_RUNNING) ||
+	    !phydev->link)
+		return HBG_LINK_DOWN;
+
+	ret = hbg_hw_sgmii_autoneg(priv);
+	if (ret)
+		return HBG_LINK_DOWN;
+
+	return HBG_LINK_UP;
+}
+
+void hbg_phy_start(struct hbg_priv *priv)
+{
+	if (!priv->mac.phydev)
+		return;
+
+	phy_start(priv->mac.phydev);
+}
+
+void hbg_phy_stop(struct hbg_priv *priv)
+{
+	if (!priv->mac.phydev)
+		return;
+
+	phy_stop(priv->mac.phydev);
+}
+
+int hbg_mdio_init(struct hbg_priv *priv)
+{
+	struct hbg_mac *mac = &priv->mac;
+	struct phy_device *phydev;
+	struct mii_bus *mdio_bus;
+	int ret;
+
+	mac->phy_addr = priv->dev_specs.phy_addr;
+	mdio_bus = devm_mdiobus_alloc(&priv->pdev->dev);
+	if (!mdio_bus)
+		return dev_err_probe(&priv->pdev->dev, -ENOMEM,
+				     "failed to alloc MDIO bus\n");
+
+	mdio_bus->parent = &priv->pdev->dev;
+	mdio_bus->priv = priv;
+	mdio_bus->phy_mask = ~(1 << mac->phy_addr);
+	mdio_bus->name = "hibmcge mii bus";
+	mac->mdio_bus = mdio_bus;
+
+	mdio_bus->read = hbg_mdio_read22;
+	mdio_bus->write = hbg_mdio_write22;
+	snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s-%s", "mii",
+		 dev_name(&priv->pdev->dev));
+
+	ret = devm_mdiobus_register(&priv->pdev->dev, mdio_bus);
+	if (ret)
+		return dev_err_probe(&priv->pdev->dev, ret,
+				     "failed to register MDIO bus\n");
+
+	phydev = mdiobus_get_phy(mdio_bus, mac->phy_addr);
+	if (!phydev)
+		return dev_err_probe(&priv->pdev->dev, -EIO,
+				     "failed to get phy device\n");
+
+	mac->phydev = phydev;
+	hbg_mdio_init_hw(mac);
+	return hbg_phy_connect(priv);
+}
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
new file mode 100644
index 000000000000..bca38c7fe14b
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2024 Hisilicon Limited. */
+
+#ifndef __HBG_MDIO_H
+#define __HBG_MDIO_H
+
+#include "hbg_common.h"
+
+int hbg_mdio_init(struct hbg_priv *priv);
+u32 hbg_get_link_status(struct hbg_priv *priv);
+void hbg_phy_start(struct hbg_priv *priv);
+void hbg_phy_stop(struct hbg_priv *priv);
+#endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
index 4c34516e0c89..f56893424da2 100644
--- a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h
@@ -4,6 +4,8 @@
 #ifndef __HBG_REG_H
 #define __HBG_REG_H
 
+#include "hbg_reg_union.h"
+
 /* DEV SPEC */
 #define HBG_REG_SPEC_VALID_ADDR			0x0000
 #define HBG_REG_EVENT_REQ_ADDR			0x0004
@@ -16,4 +18,48 @@
 #define HBG_REG_RX_FIFO_NUM_ADDR		0x0034
 #define HBG_REG_VLAN_LAYERS_ADDR		0x0038
 
+/* MDIO */
+#define HBG_REG_MDIO_BASE			0x8000
+#define HBG_REG_MDIO_COMMAND_REG_ADDR		(HBG_REG_MDIO_BASE + 0x0000)
+#define HBG_REG_MDIO_ADDR_REG_ADDR		(HBG_REG_MDIO_BASE + 0x0004)
+#define HBG_REG_MDIO_WDATA_REG_ADDR		(HBG_REG_MDIO_BASE + 0x0008)
+#define HBG_REG_MDIO_RDATA_REG_ADDR		(HBG_REG_MDIO_BASE + 0x000C)
+#define HBG_REG_MDIO_STA_REG_ADDR		(HBG_REG_MDIO_BASE + 0x0010)
+
+/* GMAC */
+#define HBG_REG_SGMII_BASE			0x10000
+#define HBG_REG_DUPLEX_TYPE_ADDR		(HBG_REG_SGMII_BASE + 0x0008)
+#define HBG_REG_PORT_MODE_ADDR			(HBG_REG_SGMII_BASE + 0x0040)
+#define HBG_REG_AN_NEG_STATE_ADDR		(HBG_REG_SGMII_BASE + 0x0058)
+#define HBG_REG_TX_LOCAL_PAGE_ADDR		(HBG_REG_SGMII_BASE + 0x005C)
+#define HBG_REG_TRANSMIT_CONTROL_ADDR		(HBG_REG_SGMII_BASE + 0x0060)
+#define HBG_REG_CF_CRC_STRIP_ADDR		(HBG_REG_SGMII_BASE + 0x01B0)
+#define HBG_REG_MODE_CHANGE_EN_ADDR		(HBG_REG_SGMII_BASE + 0x01B4)
+#define HBG_REG_16_BIT_CNTR_ADDR		(HBG_REG_SGMII_BASE + 0x01CC)
+#define HBG_REG_LD_LINK_COUNTER_ADDR		(HBG_REG_SGMII_BASE + 0x01D0)
+#define HBG_REG_RECV_CONTROL_ADDR		(HBG_REG_SGMII_BASE + 0x01E0)
+
+/* PCU */
+#define HBG_REG_RX_BUF_SIZE_ADDR		(HBG_REG_SGMII_BASE + 0x04E4)
+#define HBG_REG_BUS_CTRL_ADDR			(HBG_REG_SGMII_BASE + 0x04E8)
+#define HBG_REG_RX_CTRL_ADDR			(HBG_REG_SGMII_BASE + 0x04F0)
+#define HBG_REG_RX_PKT_MODE_ADDR		(HBG_REG_SGMII_BASE + 0x04F4)
+
+/* mask */
+#define HBG_REG_PORT_MODE_M			GENMASK(3, 0)
+#define HBG_REG_MODE_CHANGE_EN_B		BIT(0)
+#define HBG_REG_RX_BUF_SIZE_M			GENMASK(15, 0)
+#define HBG_REG_BUS_CTRL_ENDIAN_M		GENMASK(2, 1)
+#define HBG_REG_DUPLEX_B			BIT(0)
+#define HBG_REG_CF_CRC_STRIP_B			BIT(1)
+#define HBG_REG_MDIO_WDATA_M			GENMASK(15, 0)
+#define HBG_REG_IND_INTR_MASK_B			BIT(0)
+
+enum hbg_port_mode {
+	/* 0x0 ~ 0x5 are reserved */
+	HBG_PORT_MODE_SGMII_10M = 0x6,
+	HBG_PORT_MODE_SGMII_100M = 0x7,
+	HBG_PORT_MODE_SGMII_1000M = 0x8,
+};
+
 #endif
diff --git a/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg_union.h b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg_union.h
new file mode 100644
index 000000000000..fc6cad15438d
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hibmcge/hbg_reg_union.h
@@ -0,0 +1,112 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/* Copyright (c) 2024 Hisilicon Limited. */
+
+#ifndef __HBG_REG_UNION_H
+#define __HBG_REG_UNION_H
+
+struct hbg_rx_ctrl {
+	union {
+		struct {
+			u32 rxbuf_1st_skip_size2 : 4;
+			u32 cache_line_l : 3;
+			u32 rx_cfg_req_en : 1;
+			u32 cache_line_h : 2;
+			u32 addr_mode : 2;
+			u32 rx_get_addr_mode : 1;
+			u32 port_num : 4;
+			u32 rx_align_num : 2;
+			u32 pool_num : 4;
+			u32 time_inf_en : 1;
+			u32 rxbuf_no_1st_skip_size : 4;
+			u32 rxbuf_1st_skip_size : 4;
+		};
+		u32 bits;
+	};
+};
+
+struct hbg_rx_pkt_mode {
+	union {
+		struct {
+			u32 gen_id : 8;
+			u32 rsv_0 : 4;
+			u32 match_offset : 9;
+			u32 parse_mode : 2;
+			u32 skip_len : 7;
+			u32 rsv_1 : 1;
+			u32 instr_head_mode : 1;
+		};
+		u32 bits;
+	};
+};
+
+struct hbg_transmit_control {
+	union {
+		struct {
+			u32 rsv_0 : 5;
+			u32 an_enable : 1;
+			u32 crc_add : 1;
+			u32 pad_enalbe : 1;
+			u32 rsv_1 : 24;
+		};
+		u32 bits;
+	};
+};
+
+struct hbg_mdio_command {
+	union {
+		struct {
+			u32 mdio_devad : 5;
+			u32 mdio_prtad :5;
+			u32 mdio_op : 2;
+			u32 mdio_st : 2;
+			u32 mdio_start : 1;
+			u32 mdio_clk_sel : 1;
+			u32 mdio_auto_scan : 1;
+			u32 mdio_clk_sel_exp : 1;
+			u32 rev : 14;
+		};
+		u32 bits;
+	};
+};
+
+struct hbg_an_state {
+	union {
+		struct {
+			u32 reserved_0 : 5;
+			/* SerDes autoneg */
+			u32 half_duplex : 1;
+			/* SerDes autoneg */
+			u32 full_duplex : 1;
+			/* SerDes autoneg */
+			u32 support_pause_frame : 2;
+			u32 reserved_1 : 1;
+			/* SerDes autoneg, b10: 1000M; b01: 100M; b00: 10M */
+			u32 speed : 2;
+			/* SGMII autoneg, 0: half duplex; 1: full duplex */
+			u32 duplex : 1;
+			u32 rf2 : 1;
+			u32 reserved_2 : 1;
+			u32 link_ok : 1;
+			u32 reserved_3 : 4;
+			u32 rx_sync_ok : 1;
+			u32 an_done : 1;
+			u32 reserved_4 : 10;
+		};
+		u32 bits;
+	};
+};
+
+struct hbg_recv_control {
+	union {
+		struct {
+			u32 reserved_0 : 3;
+			u32 strip_pad_en : 1;
+			/* short frame transparent transmission enable */
+			u32 runt_pkt_en : 1;
+			u32 reserved_1 : 27;
+		};
+		u32 bits;
+	};
+};
+
+#endif
-- 
2.33.0


  parent reply	other threads:[~2024-07-31  9:48 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-31  9:42 [RFC PATCH net-next 00/10] Add support of HIBMCGE Ethernet Driver Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 01/10] net: hibmcge: Add pci table supported in this module Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 02/10] net: hibmcge: Add read/write registers supported through the bar space Jijie Shao
2024-08-05 12:55   ` Simon Horman
2024-08-05 13:08     ` Jijie Shao
2024-07-31  9:42 ` Jijie Shao [this message]
2024-08-01  0:42   ` [RFC PATCH net-next 03/10] net: hibmcge: Add mdio and hardware configuration supported in this module Andrew Lunn
2024-08-01  9:04     ` Jijie Shao
2024-08-01 12:07       ` Andrew Lunn
2024-07-31  9:42 ` [RFC PATCH net-next 04/10] net: hibmcge: Add interrupt " Jijie Shao
2024-07-31 13:14   ` Joe Damato
2024-08-01 11:31     ` Jijie Shao
2024-08-05 12:57   ` Simon Horman
2024-08-05 13:29     ` Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 05/10] net: hibmcge: Implement some .ndo functions Jijie Shao
2024-08-01  0:51   ` Andrew Lunn
2024-08-01  9:13     ` Jijie Shao
2024-08-01 12:18       ` Andrew Lunn
2024-08-01 12:33         ` Jijie Shao
2024-08-01 12:36           ` Andrew Lunn
2024-08-01 13:08             ` Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 06/10] net: hibmcge: Implement .ndo_start_xmit function Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 07/10] net: hibmcge: Implement rx_poll function to receive packets Jijie Shao
2024-07-31 13:23   ` Joe Damato
2024-08-01 11:58     ` Jijie Shao
2024-07-31  9:42 ` [RFC PATCH net-next 08/10] net: hibmcge: Implement workqueue and some ethtool_ops functions Jijie Shao
2024-08-01  1:10   ` Andrew Lunn
2024-08-01 11:10     ` Jijie Shao
2024-08-01 12:26       ` Andrew Lunn
2024-08-01 13:06         ` Jijie Shao
2024-08-01 20:16           ` Andrew Lunn
2024-07-31  9:42 ` [RFC PATCH net-next 09/10] net: hibmcge: Add a Makefile and update Kconfig for hibmcge Jijie Shao
2024-08-01  1:13   ` Andrew Lunn
2024-08-01 12:15     ` Jijie Shao
2024-08-01 12:33       ` Andrew Lunn
2024-07-31  9:42 ` [RFC PATCH net-next 10/10] net: hibmcge: Add maintainer " Jijie Shao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240731094245.1967834-4-shaojijie@huawei.com \
    --to=shaojijie@huawei.com \
    --cc=davem@davemloft.net \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=liuyonglong@huawei.com \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=salil.mehta@huawei.com \
    --cc=shenjian15@huawei.com \
    --cc=shiyongbang@huawei.com \
    --cc=sudongming1@huawei.com \
    --cc=wangpeiyang1@huawei.com \
    --cc=xujunsheng@huawei.com \
    --cc=yisen.zhuang@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox