[openwrt/openwrt] bmips: bcm6348-enet: add PHY support

LEDE Commits lede-commits at lists.infradead.org
Wed Mar 29 07:29:40 PDT 2023


noltari pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/cd64353bd6724207994d80826f596c7f55528c6b

commit cd64353bd6724207994d80826f596c7f55528c6b
Author: Álvaro Fernández Rojas <noltari at gmail.com>
AuthorDate: Wed Mar 29 16:17:04 2023 +0200

    bmips: bcm6348-enet: add PHY support
    
    We should ensure that the PHY is properly configured.
    This is specially needed in devices using the internal PHY for ethernet0.
    
    Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
 target/linux/bmips/dts/bcm6358-huawei-hg556a-b.dts |   7 ++
 .../drivers/net/ethernet/broadcom/bcm6348-enet.c   | 112 +++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/target/linux/bmips/dts/bcm6358-huawei-hg556a-b.dts b/target/linux/bmips/dts/bcm6358-huawei-hg556a-b.dts
index 2ad9460a9c..273470b1bd 100644
--- a/target/linux/bmips/dts/bcm6358-huawei-hg556a-b.dts
+++ b/target/linux/bmips/dts/bcm6358-huawei-hg556a-b.dts
@@ -145,6 +145,13 @@
 
 	nvmem-cells = <&macaddr_cfe_6a0>;
 	nvmem-cell-names = "mac-address";
+
+	phy-mode = "mii";
+
+	fixed-link {
+		speed = <100>;
+		full-duplex;
+	};
 };
 
 &iudma {
diff --git a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6348-enet.c b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6348-enet.c
index 06a9df1c0a..75e85aa0f3 100644
--- a/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6348-enet.c
+++ b/target/linux/bmips/files/drivers/net/ethernet/broadcom/bcm6348-enet.c
@@ -489,6 +489,11 @@ struct bcm6348_emac {
 
 	/* external mii bus */
 	bool ext_mii;
+
+	/* phy */
+	int old_link;
+	int old_duplex;
+	int old_pause;
 };
 
 static inline void emac_writel(struct bcm6348_emac *emac, u32 val, u32 off)
@@ -968,6 +973,96 @@ static void bcm6348_emac_disable_mac(struct bcm6348_emac *emac)
 	} while (limit--);
 }
 
+/*
+ * set emac duplex parameters
+ */
+static void bcm6348_emac_set_duplex(struct bcm6348_emac *emac, int fullduplex)
+{
+	u32 val;
+
+	val = emac_readl(emac, ENET_TXCTL_REG);
+	if (fullduplex)
+		val |= ENET_TXCTL_FD_MASK;
+	else
+		val &= ~ENET_TXCTL_FD_MASK;
+	emac_writel(emac, val, ENET_TXCTL_REG);
+}
+
+/*
+ * set emac flow control parameters
+ */
+static void bcm6348_emac_set_flow(struct bcm6348_emac *emac, bool rx_en, bool tx_en)
+{
+	struct bcm6348_iudma *iudma = emac->iudma;
+	u32 val;
+
+	val = emac_readl(emac, ENET_RXCFG_REG);
+	if (rx_en)
+		val |= ENET_RXCFG_ENFLOW_MASK;
+	else
+		val &= ~ENET_RXCFG_ENFLOW_MASK;
+	emac_writel(emac, val, ENET_RXCFG_REG);
+
+	dmas_writel(iudma, emac->rx_desc_dma, DMAS_RSTART_REG, emac->rx_chan);
+	dmas_writel(iudma, emac->tx_desc_dma, DMAS_RSTART_REG, emac->tx_chan);
+
+	val = dma_readl(iudma, DMA_CFG_REG);
+	if (tx_en)
+		val |= DMA_CFG_FLOWCH_MASK(emac->rx_chan);
+	else
+		val &= ~DMA_CFG_FLOWCH_MASK(emac->rx_chan);
+	dma_writel(iudma, val, DMA_CFG_REG);
+}
+
+/*
+ * adjust emac phy
+ */
+static void bcm6348_emac_adjust_phy(struct net_device *ndev)
+{
+	struct phy_device *phydev = ndev->phydev;
+	struct bcm6348_emac *emac = netdev_priv(ndev);
+	struct platform_device *pdev = emac->pdev;
+	struct device *dev = &pdev->dev;
+	bool status_changed = false;
+
+	if (emac->old_link != phydev->link) {
+		status_changed = true;
+		emac->old_link = phydev->link;
+	}
+
+	if (phydev->link && phydev->duplex != emac->old_duplex) {
+		bcm6348_emac_set_duplex(emac, phydev->duplex == DUPLEX_FULL);
+		status_changed = true;
+		emac->old_duplex = phydev->duplex;
+	}
+
+	if (phydev->link && phydev->pause != emac->old_pause) {
+		bool rx_pause_en, tx_pause_en;
+
+		if (phydev->pause) {
+			rx_pause_en = true;
+			tx_pause_en = true;
+		} else {
+			rx_pause_en = false;
+			tx_pause_en = false;
+		}
+
+		bcm6348_emac_set_flow(emac, rx_pause_en, tx_pause_en);
+		status_changed = true;
+		emac->old_pause = phydev->pause;
+	}
+
+	if (status_changed)
+		dev_info(dev, "%s: phy link %s %s/%s/%s/%s\n",
+			 ndev->name,
+			 phydev->link ? "UP" : "DOWN",
+			 phy_modes(phydev->interface),
+			 phy_speed_to_str(phydev->speed),
+			 phy_duplex_to_str(phydev->duplex),
+			 phydev->pause ? "rx/tx" : "off");
+}
+
+
 static int bcm6348_emac_open(struct net_device *ndev)
 {
 	struct bcm6348_emac *emac = netdev_priv(ndev);
@@ -1133,6 +1228,9 @@ static int bcm6348_emac_open(struct net_device *ndev)
 	dmac_writel(iudma, DMAC_IR_PKTDONE_MASK,
 		    DMAC_IRMASK_REG, emac->tx_chan);
 
+	if (ndev->phydev)
+		phy_start(ndev->phydev);
+
 	netif_carrier_on(ndev);
 	netif_start_queue(ndev);
 
@@ -1171,6 +1269,9 @@ out_freeirq_rx:
 	free_irq(emac->irq_rx, ndev);
 
 out_freeirq:
+	if (ndev->phydev)
+		phy_disconnect(ndev->phydev);
+
 	return ret;
 }
 
@@ -1183,6 +1284,8 @@ static int bcm6348_emac_stop(struct net_device *ndev)
 
 	netif_stop_queue(ndev);
 	napi_disable(&emac->napi);
+	if (ndev->phydev)
+		phy_stop(ndev->phydev);
 	del_timer_sync(&emac->rx_timeout);
 
 	/* mask all interrupts */
@@ -1454,6 +1557,10 @@ static int bcm6348_emac_probe(struct platform_device *pdev)
 	emac->tx_ring_size = ENET_DEF_TX_DESC;
 	emac->copybreak = ENET_DEF_CPY_BREAK;
 
+	emac->old_link = 0;
+	emac->old_duplex = -1;
+	emac->old_pause = -1;
+
 	of_get_mac_address(node, ndev->dev_addr);
 	if (is_valid_ether_addr(ndev->dev_addr)) {
 		dev_info(dev, "mtd mac %pM\n", ndev->dev_addr);
@@ -1543,6 +1650,11 @@ static int bcm6348_emac_probe(struct platform_device *pdev)
 
 	netif_carrier_off(ndev);
 
+	ndev->phydev = of_phy_get_and_connect(ndev, node,
+					      bcm6348_emac_adjust_phy);
+	if (IS_ERR_OR_NULL(ndev->phydev))
+		dev_warn(dev, "PHY not found!\n");
+
 	dev_info(dev, "%s at 0x%px, IRQ %d\n", ndev->name, emac->base,
 		 ndev->irq);
 




More information about the lede-commits mailing list