Commit 71a55a23 authored by Biao Huang's avatar Biao Huang Committed by David S. Miller
Browse files

net-next: stmmac: mediatek: add more support for RMII



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: default avatarBiao Huang <biao.huang@mediatek.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e133f76
Loading
Loading
Loading
Loading
+60 −29
Original line number Diff line number Diff line
@@ -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;
};

@@ -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:
@@ -173,7 +187,21 @@ 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,
		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
@@ -202,6 +230,7 @@ static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
			 */
			if (mac_delay->tx_inv)
				fine_val = ETH_RMII_DLY_TX_INV;
		}
		break;
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_TXID:
@@ -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;
}
@@ -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);
}

@@ -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;
@@ -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);