Skip to content

Commit

Permalink
net-next: stmmac: mediatek: add more support for RMII
Browse files Browse the repository at this point in the history
MT2712 SoC can provide the rmii reference clock, and the clock
will output from TXC pin only, which means ref_clk pin of external
PHY should connect to TXC pin in this case.
Add corresponding clock and timing settings.

Signed-off-by: Biao Huang <biao.huang@mediatek.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Biao Huang authored and David S. Miller committed Dec 17, 2019
1 parent 4e133f7 commit 71a55a2
Showing 1 changed file with 60 additions and 29 deletions.
89 changes: 60 additions & 29 deletions drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ struct mediatek_dwmac_plat_data {
struct regmap *peri_regmap;
struct device *dev;
phy_interface_t phy_mode;
int num_clks_to_config;
bool rmii_clk_from_mac;
bool rmii_rxc;
};

Expand All @@ -73,21 +75,33 @@ struct mediatek_dwmac_variant {

/* list of clocks required for mac */
static const char * const mt2712_dwmac_clk_l[] = {
"axi", "apb", "mac_main", "ptp_ref"
"axi", "apb", "mac_main", "ptp_ref", "rmii_internal"
};

static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat)
{
int rmii_clk_from_mac = plat->rmii_clk_from_mac ? RMII_CLK_SRC_INTERNAL : 0;
int rmii_rxc = plat->rmii_rxc ? RMII_CLK_SRC_RXC : 0;
u32 intf_val = 0;

/* The clock labeled as "rmii_internal" in mt2712_dwmac_clk_l is needed
* only in RMII(when MAC provides the reference clock), and useless for
* RGMII/MII/RMII(when PHY provides the reference clock).
* num_clks_to_config indicates the real number of clocks should be
* configured, equals to (plat->variant->num_clks - 1) in default for all the case,
* then +1 for rmii_clk_from_mac case.
*/
plat->num_clks_to_config = plat->variant->num_clks - 1;

/* select phy interface in top control domain */
switch (plat->phy_mode) {
case PHY_INTERFACE_MODE_MII:
intf_val |= PHY_INTF_MII;
break;
case PHY_INTERFACE_MODE_RMII:
intf_val |= (PHY_INTF_RMII | rmii_rxc);
if (plat->rmii_clk_from_mac)
plat->num_clks_to_config++;
intf_val |= (PHY_INTF_RMII | rmii_rxc | rmii_clk_from_mac);
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_TXID:
Expand Down Expand Up @@ -173,35 +187,50 @@ static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
break;
case PHY_INTERFACE_MODE_RMII:
/* the rmii reference clock is from external phy,
* and the property "rmii_rxc" indicates which pin(TXC/RXC)
* the reference clk is connected to. The reference clock is a
* received signal, so rx_delay/rx_inv are used to indicate
* the reference clock timing adjustment
*/
if (plat->rmii_rxc) {
/* the rmii reference clock from outside is connected
* to RXC pin, the reference clock will be adjusted
* by RXC delay macro circuit.
*/
delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
} else {
/* the rmii reference clock from outside is connected
* to TXC pin, the reference clock will be adjusted
* by TXC delay macro circuit.
if (plat->rmii_clk_from_mac) {
/* case 1: mac provides the rmii reference clock,
* and the clock output to TXC pin.
* The egress timing can be adjusted by GTXC delay macro circuit.
* The ingress timing can be adjusted by TXC delay macro circuit.
*/
delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);

delay_val |= FIELD_PREP(ETH_DLY_GTXC_ENABLE, !!mac_delay->tx_delay);
delay_val |= FIELD_PREP(ETH_DLY_GTXC_STAGES, mac_delay->tx_delay);
delay_val |= FIELD_PREP(ETH_DLY_GTXC_INV, mac_delay->tx_inv);
} else {
/* case 2: the rmii reference clock is from external phy,
* and the property "rmii_rxc" indicates which pin(TXC/RXC)
* the reference clk is connected to. The reference clock is a
* received signal, so rx_delay/rx_inv are used to indicate
* the reference clock timing adjustment
*/
if (plat->rmii_rxc) {
/* the rmii reference clock from outside is connected
* to RXC pin, the reference clock will be adjusted
* by RXC delay macro circuit.
*/
delay_val |= FIELD_PREP(ETH_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_RXC_STAGES, mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_RXC_INV, mac_delay->rx_inv);
} else {
/* the rmii reference clock from outside is connected
* to TXC pin, the reference clock will be adjusted
* by TXC delay macro circuit.
*/
delay_val |= FIELD_PREP(ETH_DLY_TXC_ENABLE, !!mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_TXC_STAGES, mac_delay->rx_delay);
delay_val |= FIELD_PREP(ETH_DLY_TXC_INV, mac_delay->rx_inv);
}
/* tx_inv will inverse the tx clock inside mac relateive to
* reference clock from external phy,
* and this bit is located in the same register with fine-tune
*/
if (mac_delay->tx_inv)
fine_val = ETH_RMII_DLY_TX_INV;
}
/* tx_inv will inverse the tx clock inside mac relateive to
* reference clock from external phy,
* and this bit is located in the same register with fine-tune
*/
if (mac_delay->tx_inv)
fine_val = ETH_RMII_DLY_TX_INV;
break;
case PHY_INTERFACE_MODE_RGMII:
case PHY_INTERFACE_MODE_RGMII_TXID:
Expand Down Expand Up @@ -278,6 +307,7 @@ static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat)
mac_delay->tx_inv = of_property_read_bool(plat->np, "mediatek,txc-inverse");
mac_delay->rx_inv = of_property_read_bool(plat->np, "mediatek,rxc-inverse");
plat->rmii_rxc = of_property_read_bool(plat->np, "mediatek,rmii-rxc");
plat->rmii_clk_from_mac = of_property_read_bool(plat->np, "mediatek,rmii-clk-from-mac");

return 0;
}
Expand All @@ -294,6 +324,8 @@ static int mediatek_dwmac_clk_init(struct mediatek_dwmac_plat_data *plat)
for (i = 0; i < num; i++)
plat->clks[i].id = variant->clk_list[i];

plat->num_clks_to_config = variant->num_clks;

return devm_clk_bulk_get(plat->dev, num, plat->clks);
}

Expand Down Expand Up @@ -321,7 +353,7 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
return ret;
}

ret = clk_bulk_prepare_enable(variant->num_clks, plat->clks);
ret = clk_bulk_prepare_enable(plat->num_clks_to_config, plat->clks);
if (ret) {
dev_err(plat->dev, "failed to enable clks, err = %d\n", ret);
return ret;
Expand All @@ -336,9 +368,8 @@ static int mediatek_dwmac_init(struct platform_device *pdev, void *priv)
static void mediatek_dwmac_exit(struct platform_device *pdev, void *priv)
{
struct mediatek_dwmac_plat_data *plat = priv;
const struct mediatek_dwmac_variant *variant = plat->variant;

clk_bulk_disable_unprepare(variant->num_clks, plat->clks);
clk_bulk_disable_unprepare(plat->num_clks_to_config, plat->clks);

pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
Expand Down

0 comments on commit 71a55a2

Please sign in to comment.