Merge branch 'gmac-next'
authorDavid S. Miller <davem@davemloft.net>
Thu, 1 Jan 2015 00:14:52 +0000 (19:14 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Jan 2015 00:14:52 +0000 (19:14 -0500)
Roger Chen says:

====================
support GMAC driver for RK3288

Roger Chen (6):
  patch1: add driver for Rockchip RK3288 SoCs integrated GMAC
  patch2: define clock ID used for GMAC
  patch3: modify CRU config for Rockchip RK3288 SoCs integrated GMAC
  patch4: dts: rockchip: add gmac info for rk3288
  patch5: dts: rockchip: enable gmac on RK3288 evb board
  patch6: add document for Rockchip RK3288 GMAC

Tested on rk3288 evb board:
Execute the following command to enable ethernet,
set local IP and ping a remote host.

busybox ifconfig eth0 up
busybox ifconfig eth0 192.168.1.111
ping 192.168.1.1
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/rockchip-dwmac.txt [new file with mode: 0644]
arch/arm/boot/dts/rk3288-evb-rk808.dts
arch/arm/boot/dts/rk3288-evb.dtsi
arch/arm/boot/dts/rk3288.dtsi
drivers/clk/rockchip/clk-rk3288.c
drivers/net/ethernet/stmicro/stmmac/Makefile
drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
include/dt-bindings/clock/rk3288-cru.h

diff --git a/Documentation/devicetree/bindings/net/rockchip-dwmac.txt b/Documentation/devicetree/bindings/net/rockchip-dwmac.txt
new file mode 100644 (file)
index 0000000..2362dcd
--- /dev/null
@@ -0,0 +1,67 @@
+Rockchip SoC RK3288 10/100/1000 Ethernet driver(GMAC)
+
+The device node has following properties.
+
+Required properties:
+ - compatible: Can be "rockchip,rk3288-gmac".
+ - reg: addresses and length of the register sets for the device.
+ - interrupts: Should contain the GMAC interrupts.
+ - interrupt-names: Should contain the interrupt names "macirq".
+ - rockchip,grf: phandle to the syscon grf used to control speed and mode.
+ - clocks: <&cru SCLK_MAC>: clock selector for main clock, from PLL or PHY.
+          <&cru SCLK_MAC_PLL>: PLL clock for SCLK_MAC
+          <&cru SCLK_MAC_RX>: clock gate for RX
+          <&cru SCLK_MAC_TX>: clock gate for TX
+          <&cru SCLK_MACREF>: clock gate for RMII referce clock
+          <&cru SCLK_MACREF_OUT> clock gate for RMII reference clock output
+          <&cru ACLK_GMAC>: AXI clock gate for GMAC
+          <&cru PCLK_GMAC>: APB clock gate for GMAC
+ - clock-names: One name for each entry in the clocks property.
+ - phy-mode: See ethernet.txt file in the same directory.
+ - pinctrl-names: Names corresponding to the numbered pinctrl states.
+ - pinctrl-0: pin-control mode. can be <&rgmii_pins> or <&rmii_pins>.
+ - clock_in_out: For RGMII, it must be "input", means main clock(125MHz)
+   is not sourced from SoC's PLL, but input from PHY; For RMII, "input" means
+   PHY provides the reference clock(50MHz), "output" means GMAC provides the
+   reference clock.
+ - snps,reset-gpio       gpio number for phy reset.
+ - snps,reset-active-low boolean flag to indicate if phy reset is active low.
+ - assigned-clocks: main clock, should be <&cru SCLK_MAC>;
+ - assigned-clock-parents = parent of main clock.
+   can be <&ext_gmac> or <&cru SCLK_MAC_PLL>.
+
+Optional properties:
+ - tx_delay: Delay value for TXD timing. Range value is 0~0x7F, 0x30 as default.
+ - rx_delay: Delay value for RXD timing. Range value is 0~0x7F, 0x10 as default.
+
+Example:
+
+gmac: ethernet@ff290000 {
+       compatible = "rockchip,rk3288-gmac";
+       reg = <0xff290000 0x10000>;
+       interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "macirq";
+       rockchip,grf = <&grf>;
+       clocks = <&cru SCLK_MAC>,
+               <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
+               <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
+               <&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
+       clock-names = "stmmaceth",
+               "mac_clk_rx", "mac_clk_tx",
+               "clk_mac_ref", "clk_mac_refout",
+               "aclk_mac", "pclk_mac";
+       phy-mode = "rgmii";
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins /*&rmii_pins*/>;
+
+       clock_in_out = "input";
+       snps,reset-gpio = <&gpio4 7 0>;
+       snps,reset-active-low;
+
+       assigned-clocks = <&cru SCLK_MAC>;
+       assigned-clock-parents = <&ext_gmac>;
+       tx_delay = <0x30>;
+       rx_delay = <0x10>;
+
+       status = "ok";
+};
index d8c775e..831a7aa 100644 (file)
 
 / {
        compatible = "rockchip,rk3288-evb-rk808", "rockchip,rk3288";
+
+       ext_gmac: external-gmac-clock {
+               compatible = "fixed-clock";
+               clock-frequency = <125000000>;
+               clock-output-names = "ext_gmac";
+               #clock-cells = <0>;
+       };
 };
 
 &cpu0 {
                };
        };
 };
+
+&gmac {
+       phy_regulator = "vcc_phy";
+       phy-mode = "rgmii";
+       clock_in_out = "input";
+       snps,reset-gpio = <&gpio4 7 0>;
+       snps,reset-active-low;
+       snps,reset-delays-us = <0 10000 1000000>;
+       assigned-clocks = <&cru SCLK_MAC>;
+       assigned-clock-parents = <&ext_gmac>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&rgmii_pins>;
+       tx_delay = <0x30>;
+       rx_delay = <0x10>;
+       status = "ok";
+};
index 3e067dd..048cb17 100644 (file)
                regulator-always-on;
                regulator-boot-on;
        };
+
+       vcc_phy: vcc-phy-regulator {
+               compatible = "regulator-fixed";
+               enable-active-high;
+               gpio = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&eth_phy_pwr>;
+               regulator-name = "vcc_phy";
+               regulator-always-on;
+               regulator-boot-on;
+       };
 };
 
 &emmc {
                        rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
                };
        };
+
+       eth_phy {
+               eth_phy_pwr: eth-phy-pwr {
+                       rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_none>;
+               };
+       };
 };
 
 &usb_host0_ehci {
index fd19f00..910dcad 100644 (file)
                status = "disabled";
        };
 
+       gmac: ethernet@ff290000 {
+               compatible = "rockchip,rk3288-gmac";
+               reg = <0xff290000 0x10000>;
+               interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-names = "macirq";
+               rockchip,grf = <&grf>;
+               clocks = <&cru SCLK_MAC>,
+                       <&cru SCLK_MAC_RX>, <&cru SCLK_MAC_TX>,
+                       <&cru SCLK_MACREF>, <&cru SCLK_MACREF_OUT>,
+                       <&cru ACLK_GMAC>, <&cru PCLK_GMAC>;
+               clock-names = "stmmaceth",
+                       "mac_clk_rx", "mac_clk_tx",
+                       "clk_mac_ref", "clk_mac_refout",
+                       "aclk_mac", "pclk_mac";
+       };
+
        usb_host0_ehci: usb@ff500000 {
                compatible = "generic-ehci";
                reg = <0xff500000 0x100>;
                        bias-disable;
                };
 
+               pcfg_pull_none_12ma: pcfg-pull-none-12ma {
+                       bias-disable;
+                       drive-strength = <12>;
+               };
+
                i2c0 {
                        i2c0_xfer: i2c0-xfer {
                                rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>,
                                rockchip,pins = <7 23 3 &pcfg_pull_none>;
                        };
                };
+
+               gmac {
+                       rgmii_pins: rgmii-pins {
+                               rockchip,pins = <3 30 3 &pcfg_pull_none>,
+                                               <3 31 3 &pcfg_pull_none>,
+                                               <3 26 3 &pcfg_pull_none>,
+                                               <3 27 3 &pcfg_pull_none>,
+                                               <3 28 3 &pcfg_pull_none_12ma>,
+                                               <3 29 3 &pcfg_pull_none_12ma>,
+                                               <3 24 3 &pcfg_pull_none_12ma>,
+                                               <3 25 3 &pcfg_pull_none_12ma>,
+                                               <4 0 3 &pcfg_pull_none>,
+                                               <4 5 3 &pcfg_pull_none>,
+                                               <4 6 3 &pcfg_pull_none>,
+                                               <4 9 3 &pcfg_pull_none_12ma>,
+                                               <4 4 3 &pcfg_pull_none_12ma>,
+                                               <4 1 3 &pcfg_pull_none>,
+                                               <4 3 3 &pcfg_pull_none>;
+                       };
+
+                       rmii_pins: rmii-pins {
+                               rockchip,pins = <3 30 3 &pcfg_pull_none>,
+                                               <3 31 3 &pcfg_pull_none>,
+                                               <3 28 3 &pcfg_pull_none>,
+                                               <3 29 3 &pcfg_pull_none>,
+                                               <4 0 3 &pcfg_pull_none>,
+                                               <4 5 3 &pcfg_pull_none>,
+                                               <4 4 3 &pcfg_pull_none>,
+                                               <4 1 3 &pcfg_pull_none>,
+                                               <4 2 3 &pcfg_pull_none>,
+                                               <4 3 3 &pcfg_pull_none>;
+                       };
+               };
        };
 };
index ac6be7c..40d267f 100644 (file)
@@ -190,7 +190,7 @@ PNAME(mux_uart2_p)  = { "uart2_src", "uart2_frac", "xin24m" };
 PNAME(mux_uart3_p)     = { "uart3_src", "uart3_frac", "xin24m" };
 PNAME(mux_uart4_p)     = { "uart4_src", "uart4_frac", "xin24m" };
 PNAME(mux_cif_out_p)   = { "cif_src", "xin24m" };
-PNAME(mux_macref_p)    = { "mac_src", "ext_gmac" };
+PNAME(mux_mac_p)       = { "mac_pll_src", "ext_gmac" };
 PNAME(mux_hsadcout_p)  = { "hsadc_src", "ext_hsadc" };
 PNAME(mux_edp_24m_p)   = { "ext_edp_24m", "xin24m" };
 PNAME(mux_tspout_p)    = { "cpll", "gpll", "npll", "xin27m" };
@@ -575,18 +575,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
        MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
                        RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
 
-       COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
+       COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
                        RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
                        RK3288_CLKGATE_CON(2), 5, GFLAGS),
-       MUX(0, "macref", mux_macref_p, 0,
+       MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
                        RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
-       GATE(0, "sclk_macref_out", "macref", 0,
+       GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
                        RK3288_CLKGATE_CON(5), 3, GFLAGS),
-       GATE(SCLK_MACREF, "sclk_macref", "macref", 0,
+       GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
                        RK3288_CLKGATE_CON(5), 2, GFLAGS),
-       GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0,
+       GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
                        RK3288_CLKGATE_CON(5), 0, GFLAGS),
-       GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0,
+       GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
                        RK3288_CLKGATE_CON(5), 1, GFLAGS),
 
        COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
index ac4d562..73c2715 100644 (file)
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o  \
 
 obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
 stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o   \
-                      dwmac-sti.o dwmac-socfpga.o
+                      dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
 
 obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
 stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
new file mode 100644 (file)
index 0000000..35f9b86
--- /dev/null
@@ -0,0 +1,459 @@
+/**
+ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
+ *
+ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
+ *
+ * Chen-Zhi (Roger Chen)  <roger.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/stmmac.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+struct rk_priv_data {
+       struct platform_device *pdev;
+       int phy_iface;
+       char regulator[32];
+
+       bool clk_enabled;
+       bool clock_input;
+
+       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;
+
+       int tx_delay;
+       int rx_delay;
+
+       struct regmap *grf;
+};
+
+#define HIWORD_UPDATE(val, mask, shift) \
+               ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define GRF_BIT(nr)    (BIT(nr) | BIT(nr+16))
+#define GRF_CLR_BIT(nr)        (BIT(nr+16))
+
+#define RK3288_GRF_SOC_CON1    0x0248
+#define RK3288_GRF_SOC_CON3    0x0250
+#define RK3288_GRF_GPIO3D_E    0x01ec
+#define RK3288_GRF_GPIO4A_E    0x01f0
+#define RK3288_GRF_GPIO4B_E    0x01f4
+
+/*RK3288_GRF_SOC_CON1*/
+#define GMAC_PHY_INTF_SEL_RGMII        (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
+#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
+#define GMAC_FLOW_CTRL         GRF_BIT(9)
+#define GMAC_FLOW_CTRL_CLR     GRF_CLR_BIT(9)
+#define GMAC_SPEED_10M         GRF_CLR_BIT(10)
+#define GMAC_SPEED_100M                GRF_BIT(10)
+#define GMAC_RMII_CLK_25M      GRF_BIT(11)
+#define GMAC_RMII_CLK_2_5M     GRF_CLR_BIT(11)
+#define GMAC_CLK_125M          (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+#define GMAC_CLK_25M           (GRF_BIT(12) | GRF_BIT(13))
+#define GMAC_CLK_2_5M          (GRF_CLR_BIT(12) | GRF_BIT(13))
+#define GMAC_RMII_MODE         GRF_BIT(14)
+#define GMAC_RMII_MODE_CLR     GRF_CLR_BIT(14)
+
+/*RK3288_GRF_SOC_CON3*/
+#define GMAC_TXCLK_DLY_ENABLE  GRF_BIT(14)
+#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+#define GMAC_RXCLK_DLY_ENABLE  GRF_BIT(15)
+#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define GMAC_CLK_RX_DL_CFG(val)        HIWORD_UPDATE(val, 0x7F, 7)
+#define GMAC_CLK_TX_DL_CFG(val)        HIWORD_UPDATE(val, 0x7F, 0)
+
+static void set_to_rgmii(struct rk_priv_data *bsp_priv,
+                        int tx_delay, int rx_delay)
+{
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (IS_ERR(bsp_priv->grf)) {
+               dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+               return;
+       }
+
+       regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+                    GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR);
+       regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+                    GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE |
+                    GMAC_CLK_RX_DL_CFG(rx_delay) |
+                    GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (IS_ERR(bsp_priv->grf)) {
+               dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+               return;
+       }
+
+       regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+                    GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE);
+}
+
+static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (IS_ERR(bsp_priv->grf)) {
+               dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+               return;
+       }
+
+       if (speed == 10)
+               regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
+       else if (speed == 100)
+               regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
+       else if (speed == 1000)
+               regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
+       else
+               dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (IS_ERR(bsp_priv->grf)) {
+               dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+               return;
+       }
+
+       if (speed == 10) {
+               regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+                            GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M);
+       } else if (speed == 100) {
+               regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+                            GMAC_RMII_CLK_25M | GMAC_SPEED_100M);
+       } else {
+               dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+       }
+}
+
+static int gmac_clk_init(struct rk_priv_data *bsp_priv)
+{
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       bsp_priv->clk_enabled = false;
+
+       bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
+       if (IS_ERR(bsp_priv->mac_clk_rx))
+               dev_err(dev, "%s: cannot get clock %s\n",
+                       __func__, "mac_clk_rx");
+
+       bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
+       if (IS_ERR(bsp_priv->mac_clk_tx))
+               dev_err(dev, "%s: cannot get clock %s\n",
+                       __func__, "mac_clk_tx");
+
+       bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
+       if (IS_ERR(bsp_priv->aclk_mac))
+               dev_err(dev, "%s: cannot get clock %s\n",
+                       __func__, "aclk_mac");
+
+       bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
+       if (IS_ERR(bsp_priv->pclk_mac))
+               dev_err(dev, "%s: cannot get clock %s\n",
+                       __func__, "pclk_mac");
+
+       bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
+       if (IS_ERR(bsp_priv->clk_mac))
+               dev_err(dev, "%s: cannot get clock %s\n",
+                       __func__, "stmmaceth");
+
+       if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+               bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
+               if (IS_ERR(bsp_priv->clk_mac_ref))
+                       dev_err(dev, "%s: cannot get clock %s\n",
+                               __func__, "clk_mac_ref");
+
+               if (!bsp_priv->clock_input) {
+                       bsp_priv->clk_mac_refout =
+                               devm_clk_get(dev, "clk_mac_refout");
+                       if (IS_ERR(bsp_priv->clk_mac_refout))
+                               dev_err(dev, "%s: cannot get clock %s\n",
+                                       __func__, "clk_mac_refout");
+               }
+       }
+
+       if (bsp_priv->clock_input) {
+               dev_info(dev, "%s: clock input from PHY\n", __func__);
+       } else {
+               if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+                       clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
+       }
+
+       return 0;
+}
+
+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
+{
+       int phy_iface = phy_iface = bsp_priv->phy_iface;
+
+       if (enable) {
+               if (!bsp_priv->clk_enabled) {
+                       if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+                               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);
+                        */
+                       mdelay(5);
+                       bsp_priv->clk_enabled = true;
+               }
+       } else {
+               if (bsp_priv->clk_enabled) {
+                       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_enabled = false;
+               }
+       }
+
+       return 0;
+}
+
+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+{
+       struct regulator *ldo;
+       char *ldostr = bsp_priv->regulator;
+       int ret;
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (!ldostr) {
+               dev_err(dev, "%s: no ldo found\n", __func__);
+               return -1;
+       }
+
+       ldo = regulator_get(NULL, ldostr);
+       if (!ldo) {
+               dev_err(dev, "\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)
+                                       dev_err(dev, "%s: fail to enable %s\n",
+                                               __func__, ldostr);
+                               else
+                                       dev_info(dev, "turn on ldo done.\n");
+                       } else {
+                               dev_warn(dev, "%s is enabled before enable",
+                                        ldostr);
+                       }
+               } else {
+                       if (regulator_is_enabled(ldo)) {
+                               ret = regulator_disable(ldo);
+                               if (ret != 0)
+                                       dev_err(dev, "%s: fail to disable %s\n",
+                                               __func__, ldostr);
+                               else
+                                       dev_info(dev, "turn off ldo done.\n");
+                       } else {
+                               dev_warn(dev, "%s is disabled before disable",
+                                        ldostr);
+                       }
+               }
+               regulator_put(ldo);
+       }
+
+       return 0;
+}
+
+static void *rk_gmac_setup(struct platform_device *pdev)
+{
+       struct rk_priv_data *bsp_priv;
+       struct device *dev = &pdev->dev;
+       int ret;
+       const char *strings = NULL;
+       int value;
+
+       bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
+       if (!bsp_priv)
+               return ERR_PTR(-ENOMEM);
+
+       bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
+
+       ret = of_property_read_string(dev->of_node, "phy_regulator", &strings);
+       if (ret) {
+               dev_warn(dev, "%s: Can not read property: phy_regulator.\n",
+                        __func__);
+       } else {
+               dev_info(dev, "%s: PHY power controlled by regulator(%s).\n",
+                        __func__, strings);
+               strcpy(bsp_priv->regulator, strings);
+       }
+
+       ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+       if (ret) {
+               dev_err(dev, "%s: Can not read property: clock_in_out.\n",
+                       __func__);
+               bsp_priv->clock_input = true;
+       } else {
+               dev_info(dev, "%s: clock input or output? (%s).\n",
+                        __func__, strings);
+               if (!strcmp(strings, "input"))
+                       bsp_priv->clock_input = true;
+               else
+                       bsp_priv->clock_input = false;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+       if (ret) {
+               bsp_priv->tx_delay = 0x30;
+               dev_err(dev, "%s: Can not read property: tx_delay.", __func__);
+               dev_err(dev, "%s: set tx_delay to 0x%x\n",
+                       __func__, bsp_priv->tx_delay);
+       } else {
+               dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value);
+               bsp_priv->tx_delay = value;
+       }
+
+       ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+       if (ret) {
+               bsp_priv->rx_delay = 0x10;
+               dev_err(dev, "%s: Can not read property: rx_delay.", __func__);
+               dev_err(dev, "%s: set rx_delay to 0x%x\n",
+                       __func__, bsp_priv->rx_delay);
+       } else {
+               dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value);
+               bsp_priv->rx_delay = value;
+       }
+
+       bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                                       "rockchip,grf");
+       bsp_priv->pdev = pdev;
+
+       /*rmii or rgmii*/
+       if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+               dev_info(dev, "%s: init for RGMII\n", __func__);
+               set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
+       } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+               dev_info(dev, "%s: init for RMII\n", __func__);
+               set_to_rmii(bsp_priv);
+       } else {
+               dev_err(dev, "%s: NO interface defined!\n", __func__);
+       }
+
+       gmac_clk_init(bsp_priv);
+
+       return bsp_priv;
+}
+
+static int rk_gmac_init(struct platform_device *pdev, void *priv)
+{
+       struct rk_priv_data *bsp_priv = priv;
+       int ret;
+
+       ret = phy_power_on(bsp_priv, true);
+       if (ret)
+               return ret;
+
+       ret = gmac_clk_enable(bsp_priv, true);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static void rk_gmac_exit(struct platform_device *pdev, void *priv)
+{
+       struct rk_priv_data *gmac = priv;
+
+       phy_power_on(gmac, false);
+       gmac_clk_enable(gmac, false);
+}
+
+static void rk_fix_speed(void *priv, unsigned int speed)
+{
+       struct rk_priv_data *bsp_priv = priv;
+       struct device *dev = &bsp_priv->pdev->dev;
+
+       if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
+               set_rgmii_speed(bsp_priv, speed);
+       else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+               set_rmii_speed(bsp_priv, speed);
+       else
+               dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
+}
+
+const struct stmmac_of_data rk3288_gmac_data = {
+       .has_gmac = 1,
+       .fix_mac_speed = rk_fix_speed,
+       .setup = rk_gmac_setup,
+       .init = rk_gmac_init,
+       .exit = rk_gmac_exit,
+};
index 3039de2..879e29f 100644 (file)
@@ -33,6 +33,7 @@
 
 static const struct of_device_id stmmac_dt_ids[] = {
        /* SoC specific glue layers should come before generic bindings */
+       { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
        { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
        { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
        { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
index 25dd1f7..093eb99 100644 (file)
@@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data;
 extern const struct stmmac_of_data stih4xx_dwmac_data;
 extern const struct stmmac_of_data stid127_dwmac_data;
 extern const struct stmmac_of_data socfpga_gmac_data;
+extern const struct stmmac_of_data rk3288_gmac_data;
 
 #endif /* __STMMAC_PLATFORM_H__ */
index f60ce72..1c34c24 100644 (file)
@@ -81,6 +81,9 @@
 #define SCLK_SDIO1_SAMPLE      120
 #define SCLK_EMMC_SAMPLE       121
 
+#define SCLK_MAC               151
+#define SCLK_MACREF_OUT                152
+
 #define DCLK_VOP0              190
 #define DCLK_VOP1              191