armbian-build/patch/kernel/archive/meson-6.10/0023-net-stmmac-dwmac-meson...

118 lines
3.5 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Date: Sat, 25 Dec 2021 04:22:53 +0100
Subject: net: stmmac: dwmac-meson: Manage the "ethernet" clock
Meson6 and Meson8 (both use the same glue registers on top of the DWMAC
IP) have a dedicated Ethernet clock. For RMII mode the SoC has an input
for an external RMII reference clock signal (which can be provided by
either the PHY or an external oscillator). This clock needs to run at
50MHz because the additional glue registers can divide by 2 - to achieve
25MHz for 100Mbit/s line speed, or 20 - to achieve 2.5MHz for 10Mbit/s
line speed.
Set the correct frequency for this clock and enable it during init. Also
enable the ETHMAC_DIV_EN bit which enables the divider in the glue
registers, based on the Ethernet clock input.
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c | 51 +++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
index 111111111111..222222222222 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
@@ -5,6 +5,7 @@
* Copyright (C) 2014 Beniamino Galvani <b.galvani@gmail.com>
*/
+#include <linux/clk.h>
#include <linux/device.h>
#include <linux/ethtool.h>
#include <linux/io.h>
@@ -15,12 +16,15 @@
#include "stmmac_platform.h"
+#define PREG_ETHERNET_ADDR0_DIV_EN BIT(0)
+
/* divides the input clock by 20 (= 0x0) or 2 (= 0x1) */
#define PREG_ETHERNET_ADDR0_SPEED_100 BIT(1)
struct meson_dwmac {
struct device *dev;
void __iomem *reg;
+ struct clk *ethernet_clk;
};
static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned int mode)
@@ -42,6 +46,33 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed, unsigned
writel(val, dwmac->reg);
}
+static int meson6_dwmac_init(struct platform_device *pdev, void *priv)
+{
+ struct meson_dwmac *dwmac = priv;
+ int ret;
+
+ ret = clk_set_rate(dwmac->ethernet_clk, 50 * 1000 * 1000);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(dwmac->ethernet_clk);
+ if (ret)
+ return ret;
+
+ writel(readl(dwmac->reg) | PREG_ETHERNET_ADDR0_DIV_EN, dwmac->reg);
+
+ return 0;
+}
+
+static void meson6_dwmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct meson_dwmac *dwmac = priv;
+
+ writel(readl(dwmac->reg) & ~PREG_ETHERNET_ADDR0_DIV_EN, dwmac->reg);
+
+ clk_disable_unprepare(dwmac->ethernet_clk);
+}
+
static int meson6_dwmac_probe(struct platform_device *pdev)
{
struct plat_stmmacenet_data *plat_dat;
@@ -65,10 +96,28 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
if (IS_ERR(dwmac->reg))
return PTR_ERR(dwmac->reg);
+ dwmac->ethernet_clk = devm_clk_get_optional(&pdev->dev, "ethernet");
+ if (IS_ERR(dwmac->ethernet_clk))
+ return PTR_ERR(dwmac->ethernet_clk);
+
plat_dat->bsp_priv = dwmac;
+ plat_dat->init = meson6_dwmac_init;
+ plat_dat->exit = meson6_dwmac_exit;
plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
- return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ ret = meson6_dwmac_init(pdev, dwmac);
+ if (ret)
+ return ret;
+
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ goto err_exit_dwmac;
+
+ return 0;
+
+err_exit_dwmac:
+ meson6_dwmac_exit(pdev, dwmac);
+ return ret;
}
static const struct of_device_id meson6_dwmac_match[] = {
--
Armbian