Commit 01aa2997 authored by David S. Miller's avatar David S. Miller

Merge branch 'gmac-next'

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 9aacfb20 53a83930
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";
};
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
/ { / {
compatible = "rockchip,rk3288-evb-rk808", "rockchip,rk3288"; 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 { &cpu0 {
...@@ -152,3 +159,19 @@ vcc_lcd: SWITCH_REG2 { ...@@ -152,3 +159,19 @@ vcc_lcd: SWITCH_REG2 {
}; };
}; };
}; };
&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";
};
...@@ -90,6 +90,17 @@ vcc_host: vcc-host-regulator { ...@@ -90,6 +90,17 @@ vcc_host: vcc-host-regulator {
regulator-always-on; regulator-always-on;
regulator-boot-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 { &emmc {
...@@ -178,6 +189,12 @@ host_vbus_drv: host-vbus-drv { ...@@ -178,6 +189,12 @@ host_vbus_drv: host-vbus-drv {
rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>; 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 { &usb_host0_ehci {
......
...@@ -380,6 +380,22 @@ tsadc: tsadc@ff280000 { ...@@ -380,6 +380,22 @@ tsadc: tsadc@ff280000 {
status = "disabled"; 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 { usb_host0_ehci: usb@ff500000 {
compatible = "generic-ehci"; compatible = "generic-ehci";
reg = <0xff500000 0x100>; reg = <0xff500000 0x100>;
...@@ -725,6 +741,11 @@ pcfg_pull_none: pcfg-pull-none { ...@@ -725,6 +741,11 @@ pcfg_pull_none: pcfg-pull-none {
bias-disable; bias-disable;
}; };
pcfg_pull_none_12ma: pcfg-pull-none-12ma {
bias-disable;
drive-strength = <12>;
};
i2c0 { i2c0 {
i2c0_xfer: i2c0-xfer { i2c0_xfer: i2c0-xfer {
rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>, rockchip,pins = <0 15 RK_FUNC_1 &pcfg_pull_none>,
...@@ -1068,5 +1089,38 @@ pwm3_pin: pwm3-pin { ...@@ -1068,5 +1089,38 @@ pwm3_pin: pwm3-pin {
rockchip,pins = <7 23 3 &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>;
};
};
}; };
}; };
...@@ -190,7 +190,7 @@ PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" }; ...@@ -190,7 +190,7 @@ PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" }; PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" };
PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" }; PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" };
PNAME(mux_cif_out_p) = { "cif_src", "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_hsadcout_p) = { "hsadc_src", "ext_hsadc" };
PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" }; PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" };
PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" }; PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" };
...@@ -575,18 +575,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = { ...@@ -575,18 +575,18 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0, MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS), 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_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
RK3288_CLKGATE_CON(2), 5, GFLAGS), 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), 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), 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), 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), 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), RK3288_CLKGATE_CON(5), 1, GFLAGS),
COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0, COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
......
...@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ ...@@ -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 obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.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 obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
stmmac-pci-objs:= stmmac_pci.o stmmac-pci-objs:= stmmac_pci.o
/**
* 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,
};
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
static const struct of_device_id stmmac_dt_ids[] = { static const struct of_device_id stmmac_dt_ids[] = {
/* SoC specific glue layers should come before generic bindings */ /* 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 = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data}, { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
......
...@@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data; ...@@ -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 stih4xx_dwmac_data;
extern const struct stmmac_of_data stid127_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 socfpga_gmac_data;
extern const struct stmmac_of_data rk3288_gmac_data;
#endif /* __STMMAC_PLATFORM_H__ */ #endif /* __STMMAC_PLATFORM_H__ */
...@@ -81,6 +81,9 @@ ...@@ -81,6 +81,9 @@
#define SCLK_SDIO1_SAMPLE 120 #define SCLK_SDIO1_SAMPLE 120
#define SCLK_EMMC_SAMPLE 121 #define SCLK_EMMC_SAMPLE 121
#define SCLK_MAC 151
#define SCLK_MACREF_OUT 152
#define DCLK_VOP0 190 #define DCLK_VOP0 190
#define DCLK_VOP1 191 #define DCLK_VOP1 191
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment