ethernet: support GMAC driver for RK3128

This commit is contained in:
roger
2014-08-08 20:57:19 +08:00
parent 65f991dd31
commit 686e3a9bc8
7 changed files with 480 additions and 208 deletions

View File

@@ -133,4 +133,9 @@
status = "disabled";
};
&gmac {
//pmu_regulator = "act_ldo5";
//pmu_enable_level = <1>; //1->HIGH, 0->LOW
//power-gpio = <&gpio0 GPIO_A6 GPIO_ACTIVE_HIGH>;
reset-gpio = <&gpio2 GPIO_D0 GPIO_ACTIVE_LOW>;
};

View File

@@ -39,10 +39,10 @@
#clock-cells = <0>;
};
gmac_clkin: rmii_clkin {
gmac_clkin: gmac_clkin {
compatible = "rockchip,rk-fixed-clock";
clock-output-names = "gmac_clkin";
clock-frequency = <0>;
clock-frequency = <125000000>;
#clock-cells = <0>;
};

View File

@@ -788,7 +788,12 @@
rockchip,pins = <GMAC_COL>;
rockchip,pull = <VALUE_PULL_DEFAULT>;
};
gmac_col_gpio:gmac-col-gpio {
rockchip,pins = <GPIO2_D0>;
rockchip,pull = <VALUE_PULL_DEFAULT>;
};
gmac_mdc:gmac-mdc {
rockchip,pins = <GMAC_MDC>;
rockchip,pull = <VALUE_PULL_DEFAULT>;

View File

@@ -187,6 +187,25 @@
status = "disabled";
};
gmac: eth@2008c000 {
compatible = "rockchip,gmac";
reg = <0x2008c000 0x4000>;
interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>; /*irq=88*/
interrupt-names = "macirq";
clocks = <&clk_mac_ref>, <&clk_gates2 6>,
<&clk_gates2 7>, <&clk_gates2 4>,
<&clk_gates2 5>,
<&clk_gates10 11>;
clock-names = "clk_mac", "mac_clk_rx",
"mac_clk_tx", "clk_mac_ref",
"clk_mac_refout",
"pclk_mac";
//phy-mode = "rmii";
phy-mode = "rgmii";
pinctrl-names = "default";
pinctrl-0 = <&gmac_rxdv &gmac_txclk &gmac_crs &gmac_rxclk &gmac_mdio &gmac_txen &gmac_clk &gmac_rxer &gmac_rxd1 &gmac_rxd0 &gmac_txd1 &gmac_txd0 &gmac_rxd3 &gmac_rxd2 &gmac_txd2 &gmac_txd3 &gmac_col_gpio &gmac_mdc>;
};
fiq-debugger {
compatible = "rockchip,fiq-debugger";
rockchip,serial-id = <2>;
@@ -220,7 +239,7 @@
<&aclk_vio0_pre 300000000>, <&hclk_vio_pre 150000000>,
<&aclk_vio1_pre 300000000>, <&clk_vepu 300000000>,
<&clk_vdpu 300000000>, <&clk_hevc_core 200000000>,
<&clk_mac_ref 50000000>;
<&clk_mac_ref 125000000>;
/* rockchip,clocks-uboot-has-init =
<&aclk_vio1>;*/
};

View File

@@ -91,17 +91,7 @@ struct stmmac_priv {
u32 msg_enable;
int wolopts;
int wol_irq;
struct clk *clk_mac;
struct clk *stmmac_clk;
struct clk *clk_mac_pll;
struct clk *gmac_clkin;
struct clk *mac_clk_rx;
struct clk *mac_clk_tx;
struct clk *clk_mac_ref;
struct clk *clk_mac_refout;
struct clk *aclk_mac;
struct clk *pclk_mac;
bool clk_enable;
int clk_csr;
struct timer_list eee_ctrl_timer;
int lpi_irq;
@@ -129,7 +119,20 @@ struct bsp_priv {
int reset_io;
int reset_io_level;
int phy_iface;
int (*phy_power_on)(struct plat_stmmacenet_data *plat, int enable);
struct clk *clk_mac;
struct clk *clk_mac_pll;
struct clk *gmac_clkin;
struct clk *mac_clk_rx;
struct clk *mac_clk_tx;
struct clk *clk_mac_ref;
struct clk *clk_mac_refout;
struct clk *aclk_mac;
struct clk *pclk_mac;
bool clk_enable;
int (*phy_power_on)(bool enable);
int (*gmac_clk_enable)(bool enable);
};
extern int phyaddr;

View File

@@ -148,61 +148,6 @@ static void stmmac_exit_fs(void);
#define STMMAC_COAL_TIMER(x) (jiffies + usecs_to_jiffies(x))
static int gmac_clk_enable(struct stmmac_priv *priv) {
int phy_iface = -1;
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
phy_iface = bsp_priv->phy_iface;
} else {
pr_err("%s:get PHY interface type failed!", __func__);
}
if (!priv->clk_enable) {
if (phy_iface == PHY_INTERFACE_MODE_RMII) {
clk_set_rate(priv->stmmac_clk, 50000000);
clk_prepare_enable(priv->mac_clk_rx);
clk_prepare_enable(priv->clk_mac_ref);
clk_prepare_enable(priv->clk_mac_refout);
}
clk_prepare_enable(priv->aclk_mac);
clk_prepare_enable(priv->pclk_mac);
clk_prepare_enable(priv->mac_clk_tx);
priv->clk_enable = true;
}
return 0;
}
static int gmac_clk_disable(struct stmmac_priv *priv) {
int phy_iface = -1;
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
phy_iface = bsp_priv->phy_iface;
} else {
pr_err("%s:get PHY interface type failed!", __func__);
}
if (priv->clk_enable) {
if (phy_iface == PHY_INTERFACE_MODE_RMII) {
clk_disable_unprepare(priv->mac_clk_rx);
clk_disable_unprepare(priv->clk_mac_ref);
clk_disable_unprepare(priv->clk_mac_refout);
}
clk_disable_unprepare(priv->aclk_mac);
clk_disable_unprepare(priv->pclk_mac);
clk_disable_unprepare(priv->mac_clk_tx);
priv->clk_enable = false;
}
return 0;
}
/**
* stmmac_verify_args - verify the driver parameters.
* Description: it verifies if some wrong parameter is passed to the driver.
@@ -858,6 +803,79 @@ static void stmmac_check_pcs_mode(struct stmmac_priv *priv)
}
}
static int gPhyReg;
static ssize_t show_phy_reg(struct device *dev,
struct device_attribute *attr, char *buf) {
int ret = snprintf(buf, PAGE_SIZE, "current phy reg = 0x%x\n", gPhyReg);
return ret;
}
static ssize_t set_phy_reg(struct device *dev,struct device_attribute *attr,
const char *buf, size_t count) {
int ovl;
int r = kstrtoint(buf, 0, &ovl);
if (r) printk("kstrtoint failed\n");
gPhyReg = ovl;
printk("%s----ovl=0x%x\n", __FUNCTION__, ovl);
return count;
}
static ssize_t show_phy_regValue(struct device *dev,
struct device_attribute *attr, char *buf) {
struct phy_device *phy_dev = dev_get_drvdata(dev);
int ret = 0;
int val;
#if 0
val = phy_read(phy_dev, gPhyReg);
ret = snprintf(buf, PAGE_SIZE, "phy reg 0x%x = 0x%x\n", gPhyReg, val);
#else
int i=0;
for (i=0; i<32; i++) {
printk("%d: 0x%x\n", i, phy_read(phy_dev, i));
}
val = phy_read(phy_dev, gPhyReg);
ret = snprintf(buf, PAGE_SIZE, "phy reg 0x%x = 0x%x\n", gPhyReg, val);
#endif
return ret;
}
static ssize_t set_phy_regValue(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count) {
int ovl;
int ret;
struct phy_device *phy_dev = dev_get_drvdata(dev);
ret = kstrtoint(buf, 0, &ovl);
printk("%s----reg 0x%x: ovl=0x%x\n", __FUNCTION__, gPhyReg, ovl);
phy_write(phy_dev, gPhyReg, ovl);
return count;
}
static struct device_attribute phy_reg_attrs[] = {
__ATTR(phy_reg, S_IRUGO | S_IWUSR, show_phy_reg, set_phy_reg),
__ATTR(phy_regValue, S_IRUGO | S_IWUSR, show_phy_regValue, set_phy_regValue)
};
int gmac_create_sysfs(struct phy_device * phy_dev) {
int r;
int t;
dev_set_drvdata(&phy_dev->dev, phy_dev);
for (t = 0; t < ARRAY_SIZE(phy_reg_attrs); t++) {
r = device_create_file(&phy_dev->dev,&phy_reg_attrs[t]);
if (r) {
dev_err(&phy_dev->dev, "failed to create sysfs file\n");
return r;
}
}
return 0;
}
/**
* stmmac_init_phy - PHY initialization
* @dev: net device structure
@@ -917,6 +935,8 @@ static int stmmac_init_phy(struct net_device *dev)
priv->phydev = phydev;
gmac_create_sysfs(phydev);
return 0;
}
@@ -1625,32 +1645,33 @@ static int stmmac_open(struct net_device *dev)
struct stmmac_priv *priv = netdev_priv(dev);
int ret;
clk_prepare_enable(priv->stmmac_clk);
gmac_clk_enable(priv);
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
if ((bsp_priv) && (bsp_priv->phy_power_on)) {
bsp_priv->phy_power_on(priv->plat, 1);
if (bsp_priv) {
if (bsp_priv->phy_power_on) {
bsp_priv->phy_power_on(true);
}
if (bsp_priv->gmac_clk_enable) {
bsp_priv->gmac_clk_enable(true);
}
}
}
stmmac_check_ether_addr(priv);
if (priv->pcs != STMMAC_PCS_SGMII && priv->pcs != STMMAC_PCS_TBI &&
priv->pcs != STMMAC_PCS_RTBI && !priv->mdio_registered) {
/* MDIO bus Registration */
ret = stmmac_mdio_register(priv->dev);
if (ret < 0) {
pr_debug("%s: MDIO bus (id: %d) registration failed",
__func__, priv->plat->bus_id);
goto open_error;
}
priv->mdio_registered = true;
}
if (priv->pcs != STMMAC_PCS_SGMII && priv->pcs != STMMAC_PCS_TBI &&
priv->pcs != STMMAC_PCS_RTBI) {
if(!priv->mdio_registered) {
/* MDIO bus Registration */
ret = stmmac_mdio_register(priv->dev);
if (ret < 0) {
pr_debug("%s: MDIO bus (id: %d) registration failed",
__func__, priv->plat->bus_id);
goto open_error;
}
priv->mdio_registered = true;
}
ret = stmmac_init_phy(dev);
if (ret) {
pr_err("%s: Cannot attach to PHY (error: %d)\n",
@@ -1778,8 +1799,12 @@ open_error:
if (priv->phydev)
phy_disconnect(priv->phydev);
clk_disable_unprepare(priv->stmmac_clk);
gmac_clk_disable(priv);
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
if ((bsp_priv) && (bsp_priv->gmac_clk_enable)) {
bsp_priv->gmac_clk_enable(false);
}
}
return ret;
}
@@ -1832,15 +1857,18 @@ static int stmmac_release(struct net_device *dev)
#ifdef CONFIG_GMAC_DEBUG_FS
stmmac_exit_fs();
#endif
clk_disable_unprepare(priv->stmmac_clk);
gmac_clk_disable(priv);
stmmac_release_ptp(priv);
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
if ((bsp_priv) && (bsp_priv->phy_power_on)) {
bsp_priv->phy_power_on(priv->plat, 0);
if (bsp_priv) {
if (bsp_priv->phy_power_on) {
bsp_priv->phy_power_on(false);
}
if (bsp_priv->gmac_clk_enable) {
bsp_priv->gmac_clk_enable(false);
}
}
}
@@ -2789,69 +2817,13 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
}
priv->mdio_registered = false;
priv->clk_enable = false;
priv->mac_clk_rx = clk_get(priv->device,"mac_clk_rx");
if (IS_ERR(priv->mac_clk_rx)) {
pr_warn("%s: warning: cannot get mac_clk_rx clock\n", __func__);
goto error_clk_get;
}
priv->mac_clk_tx = clk_get(priv->device,"mac_clk_tx");
if (IS_ERR(priv->mac_clk_tx)) {
pr_warn("%s: warning: cannot get mac_clk_tx clock\n", __func__);
goto error_clk_get;
}
priv->clk_mac_ref = clk_get(priv->device,"clk_mac_ref");
if (IS_ERR(priv->clk_mac_ref)) {
pr_warn("%s: warning: cannot get clk_mac_ref clock\n", __func__);
goto error_clk_get;
}
priv->clk_mac_refout = clk_get(priv->device,"clk_mac_refout");
if (IS_ERR(priv->clk_mac_refout)) {
pr_warn("%s: warning: cannot get clk_mac_refout clock\n", __func__);
goto error_clk_get;
}
priv->aclk_mac = clk_get(priv->device,"aclk_mac");
if (IS_ERR(priv->aclk_mac)) {
pr_warn("%s: warning: cannot get aclk_mac clock\n", __func__);
goto error_clk_get;
}
priv->pclk_mac = clk_get(priv->device,"pclk_mac");
if (IS_ERR(priv->pclk_mac)) {
pr_warn("%s: warning: cannot get pclk_mac clock\n", __func__);
goto error_clk_get;
}
priv->clk_mac_pll = clk_get(priv->device,"clk_mac_pll");
if (IS_ERR(priv->clk_mac_pll)) {
pr_warn("%s: warning: cannot get clk_mac_pll clock\n", __func__);
goto error_clk_get;
}
priv->gmac_clkin = clk_get(priv->device,"gmac_clkin");
if (IS_ERR(priv->gmac_clkin)) {
pr_warn("%s: warning: cannot get gmac_clkin clock\n", __func__);
goto error_clk_get;
}
priv->stmmac_clk = clk_get(priv->device, "clk_mac");
priv->stmmac_clk = ((struct bsp_priv *)(priv->plat->bsp_priv))->clk_mac;
if (IS_ERR(priv->stmmac_clk)) {
pr_warn("%s: warning: cannot get CSR clock\n", __func__);
goto error_clk_get;
}
#ifdef CONFIG_GMAC_CLK_IN
clk_set_parent(priv->stmmac_clk, priv->gmac_clkin);
#else
clk_set_parent(priv->stmmac_clk, priv->clk_mac_pll);
#endif
/* If a specific clk_csr value is passed from the platform
* this means that the CSR Clock Range selection cannot be
* changed at run-time and it is fixed. Viceversa the driver'll try to
@@ -2864,18 +2836,23 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
priv->clk_csr = priv->plat->clk_csr;
stmmac_check_pcs_mode(priv);
#if 0
if (priv->pcs != STMMAC_PCS_RGMII && priv->pcs != STMMAC_PCS_TBI &&
priv->pcs != STMMAC_PCS_RTBI) {
/* MDIO bus Registration */
ret = stmmac_mdio_register(ndev);
if (ret < 0) {
pr_debug("%s: MDIO bus (id: %d) registration failed",
__func__, priv->plat->bus_id);
goto error_mdio_register;
}
}
#endif
return priv;
/*error_mdio_register:
#if 0
error_mdio_register:
clk_put(priv->stmmac_clk);
clk_put(priv->clk_mac);
clk_put(priv->mac_clk_rx);
clk_put(priv->mac_clk_tx);
clk_put(priv->clk_mac_ref);
clk_put(priv->clk_mac_refout);
clk_put(priv->aclk_mac);
clk_put(priv->pclk_mac);*/
#endif
error_clk_get:
unregister_netdev(ndev);
error_netdev_register:
@@ -2943,8 +2920,13 @@ int stmmac_suspend(struct net_device *ndev)
else {
stmmac_set_mac(priv->ioaddr, false);
/* Disable clock in case of PWM is off */
clk_disable_unprepare(priv->stmmac_clk);
gmac_clk_disable(priv);
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
if ((bsp_priv) && (bsp_priv->gmac_clk_enable)) {
bsp_priv->gmac_clk_enable(false);
}
}
}
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
@@ -2970,8 +2952,12 @@ int stmmac_resume(struct net_device *ndev)
priv->hw->mac->pmt(priv->ioaddr, 0);
else {
/* enable the clk prevously disabled */
clk_prepare_enable(priv->stmmac_clk);
gmac_clk_enable(priv);
if ((priv->plat) && (priv->plat->bsp_priv)) {
struct bsp_priv * bsp_priv = priv->plat->bsp_priv;
if ((bsp_priv) && (bsp_priv->gmac_clk_enable)) {
bsp_priv->gmac_clk_enable(true);
}
}
}
netif_device_attach(ndev);

View File

@@ -38,7 +38,8 @@
#define grf_readl(offset) readl_relaxed(RK_GRF_VIRT + offset)
#define grf_writel(v, offset) do { writel_relaxed(v, RK_GRF_VIRT + offset); dsb(); } while (0)
// RK3288_GRF_SOC_CON1
//RK3288_GRF_SOC_CON1
//RK3128_GRF_MAC_CON1
#define GMAC_PHY_INTF_SEL_RGMII ((0x01C0 << 16) | (0x0040))
#define GMAC_PHY_INTF_SEL_RMII ((0x01C0 << 16) | (0x0100))
#define GMAC_FLOW_CTRL ((0x0200 << 16) | (0x0200))
@@ -53,47 +54,297 @@
#define GMAC_RMII_MODE ((0x4000 << 16) | (0x4000))
#define GMAC_RMII_MODE_CLR ((0x4000 << 16) | (0x0000))
// RK3288_GRF_SOC_CON3
//RK3288_GRF_SOC_CON3
//RK3128_GRF_MAC_CON0
#define GMAC_TXCLK_DLY_ENABLE ((0x4000 << 16) | (0x4000))
#define GMAC_TXCLK_DLY_DISABLE ((0x4000 << 16) | (0x0000))
#define GMAC_RXCLK_DLY_ENABLE ((0x8000 << 16) | (0x8000))
#define GMAC_RXCLK_DLY_DISABLE ((0x8000 << 16) | (0x0000))
#if 0
#define GMAC_CLK_RX_DL_CFG ((0x3F80 << 16) | (0x0800))
#define GMAC_CLK_TX_DL_CFG ((0x007F << 16) | (0x0040))
#else
#define GMAC_CLK_RX_DL_CFG(val) ((0x3F80 << 16) | (val<<7)) // 7bit
#define GMAC_CLK_TX_DL_CFG(val) ((0x007F << 16) | (val)) // 7bit
#if 0 //3288
#define SET_RGMII { \
grf_writel(GMAC_PHY_INTF_SEL_RGMII, RK3288_GRF_SOC_CON1); \
grf_writel(GMAC_RMII_MODE_CLR, RK3288_GRF_SOC_CON1); \
grf_writel(GMAC_RXCLK_DLY_ENABLE, RK3288_GRF_SOC_CON3); \
grf_writel(GMAC_TXCLK_DLY_ENABLE, RK3288_GRF_SOC_CON3); \
grf_writel(GMAC_CLK_RX_DL_CFG(0x10), RK3288_GRF_SOC_CON3); \
grf_writel(GMAC_CLK_TX_DL_CFG(0x30), RK3288_GRF_SOC_CON3); \
grf_writel(0xffffffff,RK3288_GRF_GPIO3D_E); \
grf_writel(grf_readl(RK3288_GRF_GPIO4B_E) | 0x3<<2<<16 | 0x3<<2, RK3288_GRF_GPIO4B_E); \
grf_writel(0xffffffff,RK3288_GRF_GPIO4A_E); \
}
#define SET_RMII { \
grf_writel(GMAC_PHY_INTF_SEL_RMII, RK3288_GRF_SOC_CON1); \
grf_writel(GMAC_RMII_MODE, RK3288_GRF_SOC_CON1); \
}
#define SET_RGMII_10M { \
grf_writel(GMAC_CLK_2_5M, RK3288_GRF_SOC_CON1); \
}
#define SET_RGMII_100M { \
grf_writel(GMAC_CLK_25M, RK3288_GRF_SOC_CON1); \
}
#define SET_RGMII_1000M { \
grf_writel(GMAC_CLK_125M, RK3288_GRF_SOC_CON1); \
}
#define SET_RMII_10M { \
grf_writel(GMAC_RMII_CLK_2_5M, RK3288_GRF_SOC_CON1); \
grf_writel(GMAC_SPEED_10M, RK3288_GRF_SOC_CON1); \
}
#define SET_RMII_100M { \
grf_writel(GMAC_RMII_CLK_25M, RK3288_GRF_SOC_CON1); \
grf_writel(GMAC_SPEED_100M, RK3288_GRF_SOC_CON1); \
}
#else //3128
#define SET_RGMII { \
grf_writel(GMAC_PHY_INTF_SEL_RGMII, RK312X_GRF_MAC_CON1); \
grf_writel(GMAC_RMII_MODE_CLR, RK312X_GRF_MAC_CON1); \
grf_writel(GMAC_RXCLK_DLY_ENABLE, RK312X_GRF_MAC_CON0); \
grf_writel(GMAC_TXCLK_DLY_ENABLE, RK312X_GRF_MAC_CON0); \
grf_writel(GMAC_CLK_RX_DL_CFG(0x10), RK312X_GRF_MAC_CON0); \
grf_writel(GMAC_CLK_TX_DL_CFG(0x30), RK312X_GRF_MAC_CON0); \
}
#define SET_RMII { \
grf_writel(GMAC_PHY_INTF_SEL_RMII, RK312X_GRF_MAC_CON1); \
grf_writel(GMAC_RMII_MODE, RK312X_GRF_MAC_CON1); \
}
#define SET_RGMII_10M { \
grf_writel(GMAC_CLK_2_5M, RK312X_GRF_MAC_CON1); \
}
#define SET_RGMII_100M { \
grf_writel(GMAC_CLK_25M, RK312X_GRF_MAC_CON1); \
}
#define SET_RGMII_1000M { \
grf_writel(GMAC_CLK_125M, RK312X_GRF_MAC_CON1); \
}
#define SET_RMII_10M { \
grf_writel(GMAC_RMII_CLK_2_5M, RK312X_GRF_MAC_CON1); \
grf_writel(GMAC_SPEED_10M, RK312X_GRF_MAC_CON1); \
}
#define SET_RMII_100M { \
grf_writel(GMAC_RMII_CLK_25M, RK312X_GRF_MAC_CON1); \
grf_writel(GMAC_SPEED_100M, RK312X_GRF_MAC_CON1); \
}
#endif
struct bsp_priv g_bsp_priv;
static int phy_power_on(struct plat_stmmacenet_data *plat, int enable)
int gmac_clk_init(struct device *device)
{
struct bsp_priv * bsp_priv;
//int ret;
struct bsp_priv * bsp_priv = &g_bsp_priv;
printk("%s: enable = %d \n", __func__, enable);
bsp_priv->clk_enable = false;
if ((plat) && (plat->bsp_priv)) {
bsp_priv = plat->bsp_priv;
bsp_priv->mac_clk_rx = clk_get(device,"mac_clk_rx");
if (IS_ERR(bsp_priv->mac_clk_rx)) {
pr_warn("%s: warning: cannot get mac_clk_rx clock\n", __func__);
}
bsp_priv->mac_clk_tx = clk_get(device,"mac_clk_tx");
if (IS_ERR(bsp_priv->mac_clk_tx)) {
pr_warn("%s: warning: cannot get mac_clk_tx clock\n", __func__);
}
bsp_priv->clk_mac_ref = clk_get(device,"clk_mac_ref");
if (IS_ERR(bsp_priv->clk_mac_ref)) {
pr_warn("%s: warning: cannot get clk_mac_ref clock\n", __func__);
}
bsp_priv->clk_mac_refout = clk_get(device,"clk_mac_refout");
if (IS_ERR(bsp_priv->clk_mac_refout)) {
pr_warn("%s: warning: cannot get clk_mac_refout clock\n", __func__);
}
bsp_priv->aclk_mac = clk_get(device,"aclk_mac");
if (IS_ERR(bsp_priv->aclk_mac)) {
pr_warn("%s: warning: cannot get aclk_mac clock\n", __func__);
}
bsp_priv->pclk_mac = clk_get(device,"pclk_mac");
if (IS_ERR(bsp_priv->pclk_mac)) {
pr_warn("%s: warning: cannot get pclk_mac clock\n", __func__);
}
bsp_priv->clk_mac_pll = clk_get(device,"clk_mac_pll");
if (IS_ERR(bsp_priv->clk_mac_pll)) {
pr_warn("%s: warning: cannot get clk_mac_pll clock\n", __func__);
}
bsp_priv->gmac_clkin = clk_get(device,"gmac_clkin");
if (IS_ERR(bsp_priv->gmac_clkin)) {
pr_warn("%s: warning: cannot get gmac_clkin clock\n", __func__);
}
bsp_priv->clk_mac = clk_get(device, "clk_mac");
if (IS_ERR(bsp_priv->clk_mac)) {
pr_warn("%s: warning: cannot get clk_mac clock\n", __func__);
}
#ifdef CONFIG_GMAC_CLK_IN
clk_set_parent(bsp_priv->clk_mac, bsp_priv->gmac_clkin);
#else
clk_set_parent(bsp_priv->clk_mac, bsp_priv->clk_mac_pll);
#endif
return 0;
}
static int gmac_clk_enable(bool enable) {
int phy_iface = -1;
struct bsp_priv * bsp_priv = &g_bsp_priv;
phy_iface = bsp_priv->phy_iface;
if (enable) {
if (!bsp_priv->clk_enable) {
if (phy_iface == PHY_INTERFACE_MODE_RMII) {
if (!IS_ERR(bsp_priv->clk_mac))
clk_set_rate(bsp_priv->clk_mac, 50000000);
if (!IS_ERR(bsp_priv->mac_clk_rx))
clk_prepare_enable(bsp_priv->mac_clk_rx);
if (!IS_ERR(bsp_priv->clk_mac_ref))
clk_prepare_enable(bsp_priv->clk_mac_ref);
if (!IS_ERR(bsp_priv->clk_mac_refout))
clk_prepare_enable(bsp_priv->clk_mac_refout);
}
if (!IS_ERR(bsp_priv->aclk_mac))
clk_prepare_enable(bsp_priv->aclk_mac);
if (!IS_ERR(bsp_priv->pclk_mac))
clk_prepare_enable(bsp_priv->pclk_mac);
if (!IS_ERR(bsp_priv->mac_clk_tx))
clk_prepare_enable(bsp_priv->mac_clk_tx);
if (!IS_ERR(bsp_priv->clk_mac))
clk_prepare_enable(bsp_priv->clk_mac);
bsp_priv->clk_enable = true;
}
} else {
pr_err("%s: ERROR: platform data or private data is NULL.\n", __FUNCTION__);
if (bsp_priv->clk_enable) {
if (phy_iface == PHY_INTERFACE_MODE_RMII) {
if (!IS_ERR(bsp_priv->mac_clk_rx))
clk_disable_unprepare(bsp_priv->mac_clk_rx);
if (!IS_ERR(bsp_priv->clk_mac_ref))
clk_disable_unprepare(bsp_priv->clk_mac_ref);
if (!IS_ERR(bsp_priv->clk_mac_refout))
clk_disable_unprepare(bsp_priv->clk_mac_refout);
}
if (!IS_ERR(bsp_priv->aclk_mac))
clk_disable_unprepare(bsp_priv->aclk_mac);
if (!IS_ERR(bsp_priv->pclk_mac))
clk_disable_unprepare(bsp_priv->pclk_mac);
if (!IS_ERR(bsp_priv->mac_clk_tx))
clk_disable_unprepare(bsp_priv->mac_clk_tx);
if (!IS_ERR(bsp_priv->clk_mac))
clk_disable_unprepare(bsp_priv->clk_mac);
bsp_priv->clk_enable = false;
}
}
return 0;
}
static int power_on_by_pmu(bool enable) {
struct bsp_priv * bsp_priv = &g_bsp_priv;
struct regulator * ldo;
char * ldostr = bsp_priv->pmu_regulator;
int ret;
if (ldostr == NULL) {
pr_err("%s: no ldo found\n", __func__);
return -1;
}
ldo = regulator_get(NULL, ldostr);
if (ldo == NULL) {
pr_err("\n%s get ldo %s failed\n", __func__, ldostr);
} else {
if (enable) {
if(!regulator_is_enabled(ldo)) {
regulator_set_voltage(ldo, 3300000, 3300000);
ret = regulator_enable(ldo);
if(ret != 0){
pr_err("%s: faild to enable %s\n", __func__, ldostr);
} else {
pr_info("turn on ldo done.\n");
}
} else {
pr_warn("%s is enabled before enable", ldostr);
}
} else {
if(regulator_is_enabled(ldo)) {
ret = regulator_disable(ldo);
if(ret != 0){
pr_err("%s: faild to disable %s\n", __func__, ldostr);
} else {
pr_info("turn off ldo done.\n");
}
} else {
pr_warn("%s is disabled before disable", ldostr);
}
}
regulator_put(ldo);
msleep(100);
if (enable) {
//reset
if (gpio_is_valid(bsp_priv->reset_io)) {
gpio_direction_output(bsp_priv->reset_io, bsp_priv->reset_io_level);
msleep(10);
gpio_direction_output(bsp_priv->reset_io, !bsp_priv->reset_io_level);
}
msleep(100);
} else {
//pull up reset
if (gpio_is_valid(bsp_priv->reset_io)) {
gpio_direction_output(bsp_priv->reset_io, !bsp_priv->reset_io_level);
}
}
}
return 0;
}
static int power_on_by_gpio(bool enable) {
struct bsp_priv * bsp_priv = &g_bsp_priv;
if (enable) {
//power on
if (gpio_is_valid(bsp_priv->power_io)) {
gpio_direction_output(bsp_priv->power_io, !bsp_priv->power_io_level);
msleep(10);
gpio_direction_output(bsp_priv->power_io, bsp_priv->power_io_level);
//gpio_set_value(bsp_priv->power_io, 1);
}
//reset
if (gpio_is_valid(bsp_priv->reset_io)) {
gpio_direction_output(bsp_priv->reset_io, bsp_priv->reset_io_level);
//gpio_set_value(bsp_priv->reset_io, 0);
msleep(10);
gpio_direction_output(bsp_priv->reset_io, !bsp_priv->reset_io_level);
}
@@ -102,13 +353,28 @@ static int phy_power_on(struct plat_stmmacenet_data *plat, int enable)
//power off
if (gpio_is_valid(bsp_priv->power_io)) {
gpio_direction_output(bsp_priv->power_io, !bsp_priv->power_io_level);
//gpio_set_value(bsp_priv->power_io, 0);
}
//pull down reset
if (gpio_is_valid(bsp_priv->reset_io)) {
gpio_direction_output(bsp_priv->reset_io, !bsp_priv->reset_io_level);
}
}
return 0;
}
static int phy_power_on(bool enable)
{
struct bsp_priv *bsp_priv = &g_bsp_priv;
printk("%s: enable = %d \n", __func__, enable);
if (bsp_priv->power_ctrl_by_pmu) {
return power_on_by_pmu(enable);
} else {
return power_on_by_gpio(enable);
}
}
int stmmc_pltfr_init(struct platform_device *pdev) {
int phy_iface;
int err;
@@ -134,42 +400,28 @@ int stmmc_pltfr_init(struct platform_device *pdev) {
//power
if (!gpio_is_valid(bsp_priv->power_io)) {
pr_err("%s: ERROR: Get power-gpio failed.\n", __func__);
//return -EINVAL;
} else {
err = gpio_request(bsp_priv->power_io, "gmac_phy_power");
if (err) {
pr_err("%s: ERROR: Request gmac phy power pin failed.\n", __func__);
//return -EINVAL;
}
}
if (!gpio_is_valid(bsp_priv->reset_io)) {
pr_err("%s: ERROR: Get reset-gpio failed.\n", __func__);
//return -EINVAL;
} else {
err = gpio_request(bsp_priv->reset_io, "gmac_phy_reset");
if (err) {
pr_err("%s: ERROR: Request gmac phy reset pin failed.\n", __func__);
//return -EINVAL;
}
}
//rmii or rgmii
if (phy_iface == PHY_INTERFACE_MODE_RGMII) {
pr_info("%s: init for RGMII\n", __func__);
grf_writel(GMAC_PHY_INTF_SEL_RGMII, RK3288_GRF_SOC_CON1);
grf_writel(GMAC_RMII_MODE_CLR, RK3288_GRF_SOC_CON1);
grf_writel(GMAC_RXCLK_DLY_ENABLE, RK3288_GRF_SOC_CON3);
grf_writel(GMAC_TXCLK_DLY_ENABLE, RK3288_GRF_SOC_CON3);
grf_writel(GMAC_CLK_RX_DL_CFG(0x10), RK3288_GRF_SOC_CON3);
grf_writel(GMAC_CLK_TX_DL_CFG(0x30), RK3288_GRF_SOC_CON3);
grf_writel(0xffffffff,RK3288_GRF_GPIO3D_E);
grf_writel(grf_readl(RK3288_GRF_GPIO4B_E) | 0x3<<2<<16 | 0x3<<2, RK3288_GRF_GPIO4B_E);
grf_writel(0xffffffff,RK3288_GRF_GPIO4A_E);
SET_RGMII
} else if (phy_iface == PHY_INTERFACE_MODE_RMII) {
pr_info("%s: init for RMII\n", __func__);
grf_writel(GMAC_PHY_INTF_SEL_RMII, RK3288_GRF_SOC_CON1);
grf_writel(GMAC_RMII_MODE, RK3288_GRF_SOC_CON1);
SET_RMII
} else {
pr_err("%s: ERROR: NO interface defined!\n", __func__);
}
@@ -192,15 +444,15 @@ void stmmc_pltfr_fix_mac_speed(void *priv, unsigned int speed){
switch (speed) {
case 10: {
grf_writel(GMAC_CLK_2_5M, RK3288_GRF_SOC_CON1);
SET_RGMII_10M
break;
}
case 100: {
grf_writel(GMAC_CLK_25M, RK3288_GRF_SOC_CON1);
SET_RGMII_100M
break;
}
case 1000: {
grf_writel(GMAC_CLK_125M, RK3288_GRF_SOC_CON1);
SET_RGMII_1000M
break;
}
default: {
@@ -212,13 +464,11 @@ void stmmc_pltfr_fix_mac_speed(void *priv, unsigned int speed){
pr_info("%s: fix speed for RMII\n", __func__);
switch (speed) {
case 10: {
grf_writel(GMAC_RMII_CLK_2_5M, RK3288_GRF_SOC_CON1);
grf_writel(GMAC_SPEED_10M, RK3288_GRF_SOC_CON1);
SET_RMII_10M
break;
}
case 100: {
grf_writel(GMAC_RMII_CLK_25M, RK3288_GRF_SOC_CON1);
grf_writel(GMAC_SPEED_100M, RK3288_GRF_SOC_CON1);
SET_RMII_100M
break;
}
default: {
@@ -247,7 +497,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
*mac = of_get_mac_address(np);
plat->interface = of_get_phy_mode(np);
//don't care about the return value of of_get_phy_mode(np)
//don't care about the return value of of_get_phy_mode(np)
#ifdef CONFIG_GMAC_PHY_RMII
plat->interface = PHY_INTERFACE_MODE_RMII;
#else
@@ -289,6 +539,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
g_bsp_priv.phy_iface = plat->interface;
g_bsp_priv.phy_power_on = phy_power_on;
g_bsp_priv.gmac_clk_enable = gmac_clk_enable;
plat->bsp_priv = &g_bsp_priv;
@@ -349,7 +600,7 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
if (ret) {
pr_err("%s: ERROR: main dt probe failed", __func__);
pr_err("%s: main dt probe failed", __func__);
return ret;
}
} else {
@@ -363,12 +614,15 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
return ret;
}
gmac_clk_init(&(pdev->dev));
priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
if (!priv) {
pr_err("%s: ERROR: main driver probe failed", __func__);
pr_err("%s: main driver probe failed", __func__);
return -ENODEV;
}
/* Get MAC address if available (DT) */
if (mac)
memcpy(priv->dev->dev_addr, mac, ETH_ALEN);