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@gmail.com>
This commit is contained in:
parent
7472476aef
commit
cd64353bd6
2 changed files with 119 additions and 0 deletions
|
@ -145,6 +145,13 @@
|
||||||
|
|
||||||
nvmem-cells = <&macaddr_cfe_6a0>;
|
nvmem-cells = <&macaddr_cfe_6a0>;
|
||||||
nvmem-cell-names = "mac-address";
|
nvmem-cell-names = "mac-address";
|
||||||
|
|
||||||
|
phy-mode = "mii";
|
||||||
|
|
||||||
|
fixed-link {
|
||||||
|
speed = <100>;
|
||||||
|
full-duplex;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
&iudma {
|
&iudma {
|
||||||
|
|
|
@ -489,6 +489,11 @@ struct bcm6348_emac {
|
||||||
|
|
||||||
/* external mii bus */
|
/* external mii bus */
|
||||||
bool ext_mii;
|
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)
|
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--);
|
} 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)
|
static int bcm6348_emac_open(struct net_device *ndev)
|
||||||
{
|
{
|
||||||
struct bcm6348_emac *emac = netdev_priv(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_writel(iudma, DMAC_IR_PKTDONE_MASK,
|
||||||
DMAC_IRMASK_REG, emac->tx_chan);
|
DMAC_IRMASK_REG, emac->tx_chan);
|
||||||
|
|
||||||
|
if (ndev->phydev)
|
||||||
|
phy_start(ndev->phydev);
|
||||||
|
|
||||||
netif_carrier_on(ndev);
|
netif_carrier_on(ndev);
|
||||||
netif_start_queue(ndev);
|
netif_start_queue(ndev);
|
||||||
|
|
||||||
|
@ -1171,6 +1269,9 @@ out_freeirq_rx:
|
||||||
free_irq(emac->irq_rx, ndev);
|
free_irq(emac->irq_rx, ndev);
|
||||||
|
|
||||||
out_freeirq:
|
out_freeirq:
|
||||||
|
if (ndev->phydev)
|
||||||
|
phy_disconnect(ndev->phydev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,6 +1284,8 @@ static int bcm6348_emac_stop(struct net_device *ndev)
|
||||||
|
|
||||||
netif_stop_queue(ndev);
|
netif_stop_queue(ndev);
|
||||||
napi_disable(&emac->napi);
|
napi_disable(&emac->napi);
|
||||||
|
if (ndev->phydev)
|
||||||
|
phy_stop(ndev->phydev);
|
||||||
del_timer_sync(&emac->rx_timeout);
|
del_timer_sync(&emac->rx_timeout);
|
||||||
|
|
||||||
/* mask all interrupts */
|
/* 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->tx_ring_size = ENET_DEF_TX_DESC;
|
||||||
emac->copybreak = ENET_DEF_CPY_BREAK;
|
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);
|
of_get_mac_address(node, ndev->dev_addr);
|
||||||
if (is_valid_ether_addr(ndev->dev_addr)) {
|
if (is_valid_ether_addr(ndev->dev_addr)) {
|
||||||
dev_info(dev, "mtd mac %pM\n", 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);
|
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,
|
dev_info(dev, "%s at 0x%px, IRQ %d\n", ndev->name, emac->base,
|
||||||
ndev->irq);
|
ndev->irq);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue