424 lines
13 KiB
Diff
424 lines
13 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Paolo Sabatino <[email protected]>
|
|
Date: Thu, 25 Apr 2024 21:44:55 +0200
|
|
Subject: support gmac rmii phy for rk322x
|
|
|
|
---
|
|
arch/arm/dts/rk322x.dtsi | 8 +-
|
|
arch/arm/include/asm/arch-rockchip/cru_rk322x.h | 1 +
|
|
doc/device-tree-bindings/net/phy.txt | 13 +
|
|
drivers/clk/rockchip/clk_rk322x.c | 14 +-
|
|
drivers/net/gmac_rockchip.c | 186 +++++++++-
|
|
5 files changed, 205 insertions(+), 17 deletions(-)
|
|
|
|
diff --git a/arch/arm/dts/rk322x.dtsi b/arch/arm/dts/rk322x.dtsi
|
|
index 111111111111..222222222222 100644
|
|
--- a/arch/arm/dts/rk322x.dtsi
|
|
+++ b/arch/arm/dts/rk322x.dtsi
|
|
@@ -878,13 +878,13 @@
|
|
clocks = <&cru SCLK_MAC>, <&cru SCLK_MAC_RX>,
|
|
<&cru SCLK_MAC_TX>, <&cru SCLK_MAC_REF>,
|
|
<&cru SCLK_MAC_REFOUT>, <&cru ACLK_GMAC>,
|
|
- <&cru PCLK_GMAC>;
|
|
+ <&cru PCLK_GMAC>, <&cru SCLK_MAC_PHY>;
|
|
clock-names = "stmmaceth", "mac_clk_rx",
|
|
"mac_clk_tx", "clk_mac_ref",
|
|
"clk_mac_refout", "aclk_mac",
|
|
- "pclk_mac";
|
|
- resets = <&cru SRST_GMAC>;
|
|
- reset-names = "stmmaceth";
|
|
+ "pclk_mac", "clk_macphy";
|
|
+ resets = <&cru SRST_GMAC>, <&cru SRST_MACPHY>;
|
|
+ reset-names = "stmmaceth", "mac-phy";
|
|
rockchip,grf = <&grf>;
|
|
status = "disabled";
|
|
};
|
|
diff --git a/arch/arm/include/asm/arch-rockchip/cru_rk322x.h b/arch/arm/include/asm/arch-rockchip/cru_rk322x.h
|
|
index 111111111111..222222222222 100644
|
|
--- a/arch/arm/include/asm/arch-rockchip/cru_rk322x.h
|
|
+++ b/arch/arm/include/asm/arch-rockchip/cru_rk322x.h
|
|
@@ -10,6 +10,7 @@
|
|
|
|
#define APLL_HZ (600 * MHz)
|
|
#define GPLL_HZ (594 * MHz)
|
|
+#define CPLL_HZ (500 * MHz)
|
|
|
|
#define CORE_PERI_HZ 150000000
|
|
#define CORE_ACLK_HZ 300000000
|
|
diff --git a/doc/device-tree-bindings/net/phy.txt b/doc/device-tree-bindings/net/phy.txt
|
|
index 111111111111..222222222222 100644
|
|
--- a/doc/device-tree-bindings/net/phy.txt
|
|
+++ b/doc/device-tree-bindings/net/phy.txt
|
|
@@ -8,6 +8,19 @@ Required properties:
|
|
|
|
- reg : The ID number for the phy, usually a small integer
|
|
|
|
+Optional Properties:
|
|
+
|
|
+- compatible: Compatible list, may contain
|
|
+ "ethernet-phy-ieee802.3-c22" or "ethernet-phy-ieee802.3-c45" for
|
|
+ PHYs that implement IEEE802.3 clause 22 or IEEE802.3 clause 45
|
|
+ specifications. If neither of these are specified, the default is to
|
|
+ assume clause 22.
|
|
+
|
|
+- phy-is-integrated: If set, indicates that the PHY is integrated into the same
|
|
+ physical package as the Ethernet MAC. If needed, muxers should be configured
|
|
+ to ensure the integrated PHY is used. The absence of this property indicates
|
|
+ the muxers should be configured so that the external PHY is used.
|
|
+
|
|
Example:
|
|
|
|
ethernet-phy@0 {
|
|
diff --git a/drivers/clk/rockchip/clk_rk322x.c b/drivers/clk/rockchip/clk_rk322x.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/clk/rockchip/clk_rk322x.c
|
|
+++ b/drivers/clk/rockchip/clk_rk322x.c
|
|
@@ -42,6 +42,7 @@ enum {
|
|
/* use integer mode*/
|
|
static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
|
|
static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
|
|
+static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 3, 1);
|
|
|
|
static int rkclk_set_pll(struct rk322x_cru *cru, enum rk_clk_id clk_id,
|
|
const struct pll_div *div)
|
|
@@ -91,11 +92,13 @@ static void rkclk_init(struct rk322x_cru *cru)
|
|
rk_clrsetreg(&cru->cru_mode_con,
|
|
GPLL_MODE_MASK | APLL_MODE_MASK,
|
|
GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
|
|
- APLL_MODE_SLOW << APLL_MODE_SHIFT);
|
|
+ APLL_MODE_SLOW << APLL_MODE_SHIFT |
|
|
+ CPLL_MODE_SLOW << CPLL_MODE_SHIFT);
|
|
|
|
/* init pll */
|
|
rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
|
|
rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
|
|
+ rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg);
|
|
|
|
/*
|
|
* select apll as cpu/core clock pll source and
|
|
@@ -168,7 +171,8 @@ static void rkclk_init(struct rk322x_cru *cru)
|
|
rk_clrsetreg(&cru->cru_mode_con,
|
|
GPLL_MODE_MASK | APLL_MODE_MASK,
|
|
GPLL_MODE_NORM << GPLL_MODE_SHIFT |
|
|
- APLL_MODE_NORM << APLL_MODE_SHIFT);
|
|
+ APLL_MODE_NORM << APLL_MODE_SHIFT |
|
|
+ CPLL_MODE_NORM << CPLL_MODE_SHIFT);
|
|
}
|
|
|
|
/* Get pll rate by id */
|
|
@@ -258,11 +262,10 @@ static ulong rk322x_mac_set_clk(struct rk322x_cru *cru, uint freq)
|
|
ulong pll_rate;
|
|
u8 div;
|
|
|
|
- if ((con >> MAC_PLL_SEL_SHIFT) & MAC_PLL_SEL_MASK)
|
|
+ if (con & MAC_PLL_SEL_MASK)
|
|
pll_rate = GPLL_HZ;
|
|
else
|
|
- /* CPLL is not set */
|
|
- return -EPERM;
|
|
+ pll_rate = CPLL_HZ;
|
|
|
|
div = DIV_ROUND_UP(pll_rate, freq) - 1;
|
|
if (div <= 0x1f)
|
|
@@ -461,6 +464,7 @@ static ulong rk322x_clk_set_rate(struct clk *clk, ulong rate)
|
|
case CLK_DDR:
|
|
new_rate = rk322x_ddr_set_clk(priv->cru, rate);
|
|
break;
|
|
+ case SCLK_MAC_SRC:
|
|
case SCLK_MAC:
|
|
new_rate = rk322x_mac_set_clk(priv->cru, rate);
|
|
break;
|
|
diff --git a/drivers/net/gmac_rockchip.c b/drivers/net/gmac_rockchip.c
|
|
index 111111111111..222222222222 100644
|
|
--- a/drivers/net/gmac_rockchip.c
|
|
+++ b/drivers/net/gmac_rockchip.c
|
|
@@ -11,6 +11,7 @@
|
|
#include <log.h>
|
|
#include <net.h>
|
|
#include <phy.h>
|
|
+#include <reset.h>
|
|
#include <syscon.h>
|
|
#include <asm/global_data.h>
|
|
#include <asm/arch-rockchip/periph.h>
|
|
@@ -25,6 +26,8 @@
|
|
#include <asm/arch-rockchip/grf_rk3399.h>
|
|
#include <asm/arch-rockchip/grf_rv1108.h>
|
|
#include <dm/pinctrl.h>
|
|
+#include <dm/of_access.h>
|
|
+#include <linux/delay.h>
|
|
#include <dt-bindings/clock/rk3288-cru.h>
|
|
#include <linux/bitops.h>
|
|
#include "designware.h"
|
|
@@ -42,21 +45,30 @@ DECLARE_GLOBAL_DATA_PTR;
|
|
struct gmac_rockchip_plat {
|
|
struct dw_eth_pdata dw_eth_pdata;
|
|
bool clock_input;
|
|
+ bool integrated_phy;
|
|
+ struct reset_ctl phy_reset;
|
|
int tx_delay;
|
|
int rx_delay;
|
|
};
|
|
|
|
struct rk_gmac_ops {
|
|
int (*fix_mac_speed)(struct dw_eth_dev *priv);
|
|
+ int (*fix_rmii_speed)(struct gmac_rockchip_plat *pdata,
|
|
+ struct dw_eth_dev *priv);
|
|
+ int (*fix_rgmii_speed)(struct gmac_rockchip_plat *pdata,
|
|
+ struct dw_eth_dev *priv);
|
|
void (*set_to_rmii)(struct gmac_rockchip_plat *pdata);
|
|
void (*set_to_rgmii)(struct gmac_rockchip_plat *pdata);
|
|
+ void (*integrated_phy_powerup)(struct gmac_rockchip_plat *pdata);
|
|
};
|
|
|
|
|
|
static int gmac_rockchip_of_to_plat(struct udevice *dev)
|
|
{
|
|
struct gmac_rockchip_plat *pdata = dev_get_plat(dev);
|
|
+ struct ofnode_phandle_args args;
|
|
const char *string;
|
|
+ int ret;
|
|
|
|
string = dev_read_string(dev, "clock_in_out");
|
|
if (!strcmp(string, "input"))
|
|
@@ -64,6 +76,25 @@ static int gmac_rockchip_of_to_plat(struct udevice *dev)
|
|
else
|
|
pdata->clock_input = false;
|
|
|
|
+ /* If phy-handle property is passed from DT, use it as the PHY */
|
|
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0, &args);
|
|
+ if (ret) {
|
|
+ debug("Cannot get phy phandle: ret=%d\n", ret);
|
|
+ pdata->integrated_phy = dev_read_bool(dev, "phy-is-integrated");
|
|
+ } else {
|
|
+ debug("Found phy-handle subnode\n");
|
|
+ pdata->integrated_phy = ofnode_read_bool(args.node,
|
|
+ "phy-is-integrated");
|
|
+ }
|
|
+
|
|
+ if (pdata->integrated_phy) {
|
|
+ ret = reset_get_by_name(dev, "mac-phy", &pdata->phy_reset);
|
|
+ if (ret) {
|
|
+ debug("No PHY reset control found: ret=%d\n", ret);
|
|
+ return ret;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Check the new naming-style first... */
|
|
pdata->tx_delay = dev_read_u32_default(dev, "tx_delay", -ENOENT);
|
|
pdata->rx_delay = dev_read_u32_default(dev, "rx_delay", -ENOENT);
|
|
@@ -118,7 +149,43 @@ static int px30_gmac_fix_mac_speed(struct dw_eth_dev *priv)
|
|
return 0;
|
|
}
|
|
|
|
-static int rk3228_gmac_fix_mac_speed(struct dw_eth_dev *priv)
|
|
+static int rk3228_gmac_fix_rmii_speed(struct gmac_rockchip_plat *pdata,
|
|
+ struct dw_eth_dev *priv)
|
|
+{
|
|
+ struct rk322x_grf *grf;
|
|
+ int clk;
|
|
+ enum {
|
|
+ RK3228_GMAC_RMII_CLK_MASK = BIT(7),
|
|
+ RK3228_GMAC_RMII_CLK_2_5M = 0,
|
|
+ RK3228_GMAC_RMII_CLK_25M = BIT(7),
|
|
+
|
|
+ RK3228_GMAC_RMII_SPEED_MASK = BIT(2),
|
|
+ RK3228_GMAC_RMII_SPEED_10 = 0,
|
|
+ RK3228_GMAC_RMII_SPEED_100 = BIT(2),
|
|
+ };
|
|
+
|
|
+ switch (priv->phydev->speed) {
|
|
+ case 10:
|
|
+ clk = RK3228_GMAC_RMII_CLK_2_5M | RK3228_GMAC_RMII_SPEED_10;
|
|
+ break;
|
|
+ case 100:
|
|
+ clk = RK3228_GMAC_RMII_CLK_25M | RK3228_GMAC_RMII_SPEED_100;
|
|
+ break;
|
|
+ default:
|
|
+ debug("Unknown phy speed: %d\n", priv->phydev->speed);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
|
+ rk_clrsetreg(&grf->mac_con[1],
|
|
+ RK3228_GMAC_RMII_CLK_MASK | RK3228_GMAC_RMII_SPEED_MASK,
|
|
+ clk);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int rk3228_gmac_fix_rgmii_speed(struct gmac_rockchip_plat *pdata,
|
|
+ struct dw_eth_dev *priv)
|
|
{
|
|
struct rk322x_grf *grf;
|
|
int clk;
|
|
@@ -360,6 +427,28 @@ static void px30_gmac_set_to_rmii(struct gmac_rockchip_plat *pdata)
|
|
PX30_GMAC_PHY_INTF_SEL_RMII);
|
|
}
|
|
|
|
+static void rk3228_gmac_set_to_rmii(struct gmac_rockchip_plat *pdata)
|
|
+{
|
|
+ struct rk322x_grf *grf;
|
|
+ enum {
|
|
+ RK3228_GRF_CON_RMII_MODE_MASK = BIT(11),
|
|
+ RK3228_GRF_CON_RMII_MODE_SEL = BIT(11),
|
|
+ RK3228_RMII_MODE_MASK = BIT(10),
|
|
+ RK3228_RMII_MODE_SEL = BIT(10),
|
|
+ RK3228_GMAC_PHY_INTF_SEL_MASK = GENMASK(6, 4),
|
|
+ RK3228_GMAC_PHY_INTF_SEL_RMII = BIT(6),
|
|
+ };
|
|
+
|
|
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
|
+ rk_clrsetreg(&grf->mac_con[1],
|
|
+ RK3228_GRF_CON_RMII_MODE_MASK |
|
|
+ RK3228_RMII_MODE_MASK |
|
|
+ RK3228_GMAC_PHY_INTF_SEL_MASK,
|
|
+ RK3228_GRF_CON_RMII_MODE_SEL |
|
|
+ RK3228_RMII_MODE_SEL |
|
|
+ RK3228_GMAC_PHY_INTF_SEL_RMII);
|
|
+}
|
|
+
|
|
static void rk3228_gmac_set_to_rgmii(struct gmac_rockchip_plat *pdata)
|
|
{
|
|
struct rk322x_grf *grf;
|
|
@@ -553,6 +642,66 @@ static void rv1108_gmac_set_to_rmii(struct gmac_rockchip_plat *pdata)
|
|
RV1108_GMAC_PHY_INTF_SEL_RMII);
|
|
}
|
|
|
|
+static void rk3228_gmac_integrated_phy_powerup(struct gmac_rockchip_plat *pdata)
|
|
+{
|
|
+ struct rk322x_grf *grf;
|
|
+ enum {
|
|
+ RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY_MASK = BIT(15),
|
|
+ RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY = BIT(15),
|
|
+ };
|
|
+ enum {
|
|
+ RK3228_MACPHY_CFG_CLK_50M_MASK = BIT(14),
|
|
+ RK3228_MACPHY_CFG_CLK_50M = BIT(14),
|
|
+
|
|
+ RK3228_MACPHY_RMII_MODE_MASK = GENMASK(7, 6),
|
|
+ RK3228_MACPHY_RMII_MODE = BIT(6),
|
|
+
|
|
+ RK3228_MACPHY_ENABLE_MASK = BIT(0),
|
|
+ RK3228_MACPHY_DISENABLE = 0,
|
|
+ RK3228_MACPHY_ENABLE = BIT(0),
|
|
+ };
|
|
+ enum {
|
|
+ RK3228_RK_GRF_CON2_MACPHY_ID_MASK = GENMASK(6, 0),
|
|
+ RK3228_RK_GRF_CON2_MACPHY_ID = 0x1234,
|
|
+ };
|
|
+ enum {
|
|
+ RK3228_RK_GRF_CON3_MACPHY_ID_MASK = GENMASK(5, 0),
|
|
+ RK3228_RK_GRF_CON3_MACPHY_ID = 0x35,
|
|
+ };
|
|
+
|
|
+ grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
|
|
+ rk_clrsetreg(&grf->con_iomux,
|
|
+ RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY_MASK,
|
|
+ RK3228_GRF_CON_MUX_GMAC_INTEGRATED_PHY);
|
|
+
|
|
+ rk_clrsetreg(&grf->macphy_con[2],
|
|
+ RK3228_RK_GRF_CON2_MACPHY_ID_MASK,
|
|
+ RK3228_RK_GRF_CON2_MACPHY_ID);
|
|
+
|
|
+ rk_clrsetreg(&grf->macphy_con[3],
|
|
+ RK3228_RK_GRF_CON3_MACPHY_ID_MASK,
|
|
+ RK3228_RK_GRF_CON3_MACPHY_ID);
|
|
+
|
|
+ /* disabled before trying to reset it */
|
|
+ rk_clrsetreg(&grf->macphy_con[0],
|
|
+ RK3228_MACPHY_CFG_CLK_50M_MASK |
|
|
+ RK3228_MACPHY_RMII_MODE_MASK |
|
|
+ RK3228_MACPHY_ENABLE_MASK,
|
|
+ RK3228_MACPHY_CFG_CLK_50M |
|
|
+ RK3228_MACPHY_RMII_MODE |
|
|
+ RK3228_MACPHY_DISENABLE);
|
|
+
|
|
+ reset_assert(&pdata->phy_reset);
|
|
+ udelay(10);
|
|
+ reset_deassert(&pdata->phy_reset);
|
|
+ udelay(10);
|
|
+
|
|
+ rk_clrsetreg(&grf->macphy_con[0],
|
|
+ RK3228_MACPHY_ENABLE_MASK,
|
|
+ RK3228_MACPHY_ENABLE);
|
|
+ udelay(30 * 1000);
|
|
+}
|
|
+
|
|
static int gmac_rockchip_probe(struct udevice *dev)
|
|
{
|
|
struct gmac_rockchip_plat *pdata = dev_get_plat(dev);
|
|
@@ -572,6 +721,9 @@ static int gmac_rockchip_probe(struct udevice *dev)
|
|
if (ret)
|
|
return ret;
|
|
|
|
+ if (pdata->integrated_phy && ops->integrated_phy_powerup)
|
|
+ ops->integrated_phy_powerup(pdata);
|
|
+
|
|
switch (eth_pdata->phy_interface) {
|
|
case PHY_INTERFACE_MODE_RGMII:
|
|
/* Set to RGMII mode */
|
|
@@ -655,7 +807,7 @@ static int gmac_rockchip_probe(struct udevice *dev)
|
|
break;
|
|
|
|
default:
|
|
- debug("NO interface defined!\n");
|
|
+ debug("%s: no interface defined!\n", __func__);
|
|
return -ENXIO;
|
|
}
|
|
|
|
@@ -664,18 +816,33 @@ static int gmac_rockchip_probe(struct udevice *dev)
|
|
|
|
static int gmac_rockchip_eth_start(struct udevice *dev)
|
|
{
|
|
- struct eth_pdata *pdata = dev_get_plat(dev);
|
|
+ struct eth_pdata *eth_pdata = dev_get_plat(dev);
|
|
struct dw_eth_dev *priv = dev_get_priv(dev);
|
|
struct rk_gmac_ops *ops =
|
|
(struct rk_gmac_ops *)dev_get_driver_data(dev);
|
|
+ struct gmac_rockchip_plat *pdata = dev_get_plat(dev);
|
|
int ret;
|
|
|
|
- ret = designware_eth_init(priv, pdata->enetaddr);
|
|
- if (ret)
|
|
- return ret;
|
|
- ret = ops->fix_mac_speed(priv);
|
|
+ ret = designware_eth_init(priv, eth_pdata->enetaddr);
|
|
if (ret)
|
|
return ret;
|
|
+
|
|
+ switch (eth_pdata->phy_interface) {
|
|
+ case PHY_INTERFACE_MODE_RGMII:
|
|
+ ret = ops->fix_rgmii_speed(pdata, priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ break;
|
|
+ case PHY_INTERFACE_MODE_RMII:
|
|
+ ret = ops->fix_rmii_speed(pdata, priv);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ break;
|
|
+ default:
|
|
+ debug("%s: no interface defined!\n", __func__);
|
|
+ return -ENXIO;
|
|
+ }
|
|
+
|
|
ret = designware_eth_enable(priv);
|
|
if (ret)
|
|
return ret;
|
|
@@ -698,8 +865,11 @@ const struct rk_gmac_ops px30_gmac_ops = {
|
|
};
|
|
|
|
const struct rk_gmac_ops rk3228_gmac_ops = {
|
|
- .fix_mac_speed = rk3228_gmac_fix_mac_speed,
|
|
+ .fix_rmii_speed = rk3228_gmac_fix_rmii_speed,
|
|
+ .fix_rgmii_speed = rk3228_gmac_fix_rgmii_speed,
|
|
+ .set_to_rmii = rk3228_gmac_set_to_rmii,
|
|
.set_to_rgmii = rk3228_gmac_set_to_rgmii,
|
|
+ .integrated_phy_powerup = rk3228_gmac_integrated_phy_powerup,
|
|
};
|
|
|
|
const struct rk_gmac_ops rk3288_gmac_ops = {
|
|
--
|
|
Armbian
|
|
|