From: 郭毅 Date: Mon, 21 Jul 2014 07:54:38 +0000 (+0800) Subject: rk32: gmac: better support 1000M X-Git-Tag: firefly_0821_release~4959 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=a874c3009d5eb34b1d1958fdb83b93a4bae94402;p=firefly-linux-kernel-4.4.55.git rk32: gmac: better support 1000M --- diff --git a/arch/arm/boot/dts/rk3288-clocks.dtsi b/arch/arm/boot/dts/rk3288-clocks.dtsi index 93612c6bdf2b..2eaf3f54177d 100755 --- a/arch/arm/boot/dts/rk3288-clocks.dtsi +++ b/arch/arm/boot/dts/rk3288-clocks.dtsi @@ -84,7 +84,7 @@ compatible = "rockchip,rk-fixed-clock"; #clock-cells = <0>; clock-output-names = "gmac_clkin"; - clock-frequency = <0>; + clock-frequency = <125000000>; }; clk_hsadc_ext: clk_hsadc_ext { diff --git a/drivers/net/ethernet/rockchip/gmac/Kconfig b/drivers/net/ethernet/rockchip/gmac/Kconfig index 957a46bdbc18..93f4a86b8dce 100755 --- a/drivers/net/ethernet/rockchip/gmac/Kconfig +++ b/drivers/net/ethernet/rockchip/gmac/Kconfig @@ -10,6 +10,13 @@ config RK_GMAC_ETH Rockchip 10/100/1000 Ethernet driver. if RK_GMAC_ETH +config GMAC_CLK_IN + bool "Clock input from PHY" + default y + +config GMAC_PHY_RMII + bool "GMAC interface set to RMII" + default n config GMAC_DEBUG_FS bool "Enable monitoring via sysFS " diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac.h b/drivers/net/ethernet/rockchip/gmac/stmmac.h index 0f965cecce85..d736777358ca 100755 --- a/drivers/net/ethernet/rockchip/gmac/stmmac.h +++ b/drivers/net/ethernet/rockchip/gmac/stmmac.h @@ -91,8 +91,10 @@ struct stmmac_priv { u32 msg_enable; int wolopts; int wol_irq; - struct clk *stmmac_clk; 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; @@ -119,7 +121,9 @@ struct stmmac_priv { }; struct bsp_priv { - char pwr_ctl_by[8]; + bool power_ctrl_by_pmu; + char pmu_regulator[32]; + int pmu_enable_level; int power_io; int power_io_level; int reset_io; diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_main.c b/drivers/net/ethernet/rockchip/gmac/stmmac_main.c index 775379ba3b53..04e71c29ce06 100755 --- a/drivers/net/ethernet/rockchip/gmac/stmmac_main.c +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_main.c @@ -148,32 +148,55 @@ 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) -{ +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) { - clk_prepare_enable(priv->clk_mac); - clk_prepare_enable(priv->mac_clk_rx); - clk_prepare_enable(priv->mac_clk_tx); - clk_prepare_enable(priv->clk_mac_ref); - clk_prepare_enable(priv->clk_mac_refout); + 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) -{ +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) { - clk_disable_unprepare(priv->clk_mac); - clk_disable_unprepare(priv->mac_clk_rx); - clk_disable_unprepare(priv->mac_clk_tx); - clk_disable_unprepare(priv->clk_mac_ref); - clk_disable_unprepare(priv->clk_mac_refout); + 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; } @@ -683,6 +706,7 @@ static int stmmac_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) * This is done by looking at the HW cap. register. * Also it registers the ptp driver. */ +/* static int stmmac_init_ptp(struct stmmac_priv *priv) { if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) @@ -706,7 +730,7 @@ static int stmmac_init_ptp(struct stmmac_priv *priv) return stmmac_ptp_register(priv); } - +*/ static void stmmac_release_ptp(struct stmmac_priv *priv) { stmmac_ptp_unregister(priv); @@ -1700,11 +1724,11 @@ static int stmmac_open(struct net_device *dev) priv->xstats.threshold = tc; stmmac_mmc_setup(priv); - +/* ret = stmmac_init_ptp(priv); if (ret) pr_warn("%s: failed PTP initialisation\n", __func__); - +*/ #ifdef CONFIG_GMAC_DEBUG_FS ret = stmmac_init_fs(dev); if (ret < 0) @@ -2766,12 +2790,6 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, priv->mdio_registered = false; priv->clk_enable = false; - - priv->clk_mac = clk_get(priv->device,"clk_mac"); - if (IS_ERR(priv->clk_mac)) { - pr_warn("%s: warning: cannot get clk_mac clock\n", __func__); - goto error_clk_get; - } priv->mac_clk_rx = clk_get(priv->device,"mac_clk_rx"); if (IS_ERR(priv->mac_clk_rx)) { @@ -2809,12 +2827,31 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device, goto error_clk_get; } - priv->stmmac_clk = clk_get(priv->device, "clk_mac"/*STMMAC_RESOURCE_NAME*/); + 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"); + 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 diff --git a/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c b/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c index c1085196c2f9..471bfe71b70e 100755 --- a/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c +++ b/drivers/net/ethernet/rockchip/gmac/stmmac_platform.c @@ -33,6 +33,7 @@ #include "stmmac.h" #include #include +#include #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) @@ -42,8 +43,8 @@ #define GMAC_PHY_INTF_SEL_RMII ((0x01C0 << 16) | (0x0100)) #define GMAC_FLOW_CTRL ((0x0200 << 16) | (0x0200)) #define GMAC_FLOW_CTRL_CLR ((0x0200 << 16) | (0x0000)) -#define GMAC_SPEED_10M ((0x0400 << 16) | (0x0400)) -#define GMAC_SPEED_100M ((0x0400 << 16) | (0x0000)) +#define GMAC_SPEED_10M ((0x0400 << 16) | (0x0000)) +#define GMAC_SPEED_100M ((0x0400 << 16) | (0x0400)) #define GMAC_RMII_CLK_25M ((0x0800 << 16) | (0x0800)) #define GMAC_RMII_CLK_2_5M ((0x0800 << 16) | (0x0000)) #define GMAC_CLK_125M ((0x3000 << 16) | (0x0000)) @@ -69,8 +70,9 @@ struct bsp_priv g_bsp_priv; static int phy_power_on(struct plat_stmmacenet_data *plat, int enable) { struct bsp_priv * bsp_priv; + //int ret; - pr_info("%s: enable = %d \n", __func__, enable); + printk("%s: enable = %d \n", __func__, enable); if ((plat) && (plat->bsp_priv)) { bsp_priv = plat->bsp_priv; @@ -108,7 +110,6 @@ static int phy_power_on(struct plat_stmmacenet_data *plat, int enable) } int stmmc_pltfr_init(struct platform_device *pdev) { - //struct pinctrl_state *gmac_state; int phy_iface; int err; struct bsp_priv *bsp_priv; @@ -134,35 +135,38 @@ int stmmc_pltfr_init(struct platform_device *pdev) { if (!gpio_is_valid(bsp_priv->power_io)) { pr_err("%s: ERROR: Get power-gpio failed.\n", __func__); //return -EINVAL; - } - - 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; + } 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; + } } - - 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) { + 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(0x40), RK3288_GRF_SOC_CON3); - } else if (phy_iface & PHY_INTERFACE_MODE_RMII) { + 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); + + } 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); @@ -183,7 +187,7 @@ void stmmc_pltfr_fix_mac_speed(void *priv, unsigned int speed){ interface = bsp_priv->phy_iface; } - if (interface & PHY_INTERFACE_MODE_RGMII) { + if (interface == PHY_INTERFACE_MODE_RGMII) { pr_info("%s: fix speed for RGMII\n", __func__); switch (speed) { @@ -204,15 +208,17 @@ void stmmc_pltfr_fix_mac_speed(void *priv, unsigned int speed){ } } - } else if (interface & PHY_INTERFACE_MODE_RMII) { + } else if (interface == PHY_INTERFACE_MODE_RMII) { 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); break; } case 100: { grf_writel(GMAC_RMII_CLK_25M, RK3288_GRF_SOC_CON1); + grf_writel(GMAC_SPEED_100M, RK3288_GRF_SOC_CON1); break; } default: { @@ -232,12 +238,22 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; enum of_gpio_flags flags; + int ret; + const char * strings = NULL; + int value; if (!np) return -ENODEV; *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) +#ifdef CONFIG_GMAC_PHY_RMII + plat->interface = PHY_INTERFACE_MODE_RMII; +#else + plat->interface = PHY_INTERFACE_MODE_RGMII; +#endif + plat->mdio_bus_data = devm_kzalloc(&pdev->dev, sizeof(struct stmmac_mdio_bus_data), GFP_KERNEL); @@ -245,6 +261,25 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, plat->init = stmmc_pltfr_init; plat->fix_mac_speed = stmmc_pltfr_fix_mac_speed; + ret = of_property_read_string(np, "pmu_regulator", &strings); + if (ret) { + pr_err("%s: Can not read property: pmu_regulator.\n", __func__); + g_bsp_priv.power_ctrl_by_pmu = false; + } else { + pr_info("%s: ethernet phy power controled by pmu(%s).\n", __func__, strings); + g_bsp_priv.power_ctrl_by_pmu = true; + strcpy(g_bsp_priv.pmu_regulator, strings); + } + ret = of_property_read_u32(np, "pmu_enable_level", &value); + if (ret) { + pr_err("%s: Can not read property: pmu_enable_level.\n", __func__); + g_bsp_priv.power_ctrl_by_pmu = false; + } else { + pr_info("%s: ethernet phy power controled by pmu(level = %s).\n", __func__, (value == 1)?"HIGH":"LOW"); + g_bsp_priv.power_ctrl_by_pmu = true; + g_bsp_priv.pmu_enable_level = value; + } + g_bsp_priv.reset_io = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); g_bsp_priv.reset_io_level = (flags == GPIO_ACTIVE_HIGH) ? 1 : 0;