eth: meson-g12a: add Ethernet driver support

PD#156734: eth: meson-g12a: add Ethernet driver support

Enable the ethernet driver on G12A board, which tested
with RTL8211F 1000M PHY && Internal PHY.

And here we enable Internal PHY for g12a_skt board.

Change-Id: I839639ac92790c27117b9745275b346cd4ce40d7
Signed-off-by: Yixun Lan <yixun.lan@amlogic.com>
This commit is contained in:
Yixun Lan
2018-02-01 19:58:02 +08:00
parent 21245374ef
commit c1ee19ab52
3 changed files with 269 additions and 10 deletions

View File

@@ -139,7 +139,45 @@
dev_name = "vout";
status = "okay";
};
/*external_phy please use this
ethmac: ethernet@ff3f0000 {
compatible = "amlogic, g12a-eth-dwmac", "snps,dwmac";
reg = <0x0 0xff3f0000 0x0 0x10000
0x0 0xff634540 0x0 0x8
0x0 0xff64c000 0x0 0xa0>;
reg-names = "eth_base", "eth_cfg", "eth_pll";
interrupts = <0 8 1>;
interrupt-names = "macirq";
status = "okay";
clocks = <&clkc CLKID_ETH_CORE>;
clock-names = "ethclk81";
pinctrl-names = "external_eth_pins";
pinctrl-0 = <&external_eth_pins>;
mc_val = <0x1621>;
internal_phy=<0>;
};
*/
ethmac: ethernet@ff3f0000 {
compatible = "amlogic, g12a-eth-dwmac","snps,dwmac";
reg = <0x0 0xff3f0000 0x0 0x10000
0x0 0xff634540 0x0 0x8
0x0 0xff64c000 0x0 0xa0>;
reg-names = "eth_base", "eth_cfg", "eth_pll";
interrupts = <0 8 1>;
interrupt-names = "macirq";
status = "okay";
clocks = <&clkc CLKID_ETH_CORE>;
clock-names = "ethclk81";
pinctrl-names = "internal_eth_pins";
pinctrl-0 = <&internal_eth_pins>;
mc_val = <0x4be04>;
internal_phy=<1>;
};
amhdmitx: amhdmitx{
compatible = "amlogic, amhdmitx";
dev_name = "amhdmitx";

View File

@@ -1128,6 +1128,34 @@
function = "cec_ao_ee";
};
};
internal_eth_pins: internal_eth_pins {
mux {
groups = "eth_link_led",
"eth_act_led";
function = "eth";
};
};
external_eth_pins: external_eth_pins {
mux {
groups = "eth_mdio",
"eth_mdc",
"eth_rgmii_rx_clk",
"eth_rx_dv",
"eth_rxd0",
"eth_rxd1",
"eth_rxd2_rgmii",
"eth_rxd3_rgmii",
"eth_rgmii_tx_clk",
"eth_txen",
"eth_txd0",
"eth_txd1",
"eth_txd2_rgmii",
"eth_txd3_rgmii";
function = "eth";
};
};
};
&pinctrl_aobus {

View File

@@ -19,17 +19,45 @@
#include <linux/platform_device.h>
#include <linux/stmmac.h>
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
#include <linux/bitops.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include "dwmac1000.h"
#include "dwmac_dma.h"
#endif
#include "stmmac_platform.h"
#define ETHMAC_SPEED_100 BIT(1)
#define ETHMAC_SPEED_10 BIT(1)
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
/* Ethernet register for G12A PHY */
#define ETH_PLL_CTL0 0x44
#define ETH_PLL_CTL1 0x48
#define ETH_PLL_CTL2 0x4C
#define ETH_PLL_CTL3 0x50
#define ETH_PLL_CTL4 0x54
#define ETH_PLL_CTL5 0x58
#define ETH_PLL_CTL6 0x5C
#define ETH_PLL_CTL7 0x60
#define ETH_PHY_CNTL0 0x80
#define ETH_PHY_CNTL1 0x84
#define ETH_PHY_CNTL2 0x88
#define ETH_USE_EPHY BIT(5)
#define ETH_EPHY_FROM_MAC BIT(6)
struct meson_dwmac_data {
bool g12a_phy;
};
#endif
struct meson_dwmac {
struct device *dev;
void __iomem *reg;
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
const struct meson_dwmac_data *data;
#endif
};
static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed)
@@ -81,24 +109,39 @@ static void __iomem *network_interface_setup(struct platform_device *pdev)
struct resource *res;
u32 mc_val, cali_val, internal_phy;
void __iomem *addr = NULL;
void __iomem *PREG_ETH_REG0;
void __iomem *PREG_ETH_REG1;
void __iomem *PREG_ETH_REG2;
void __iomem *PREG_ETH_REG3;
void __iomem *PREG_ETH_REG4;
void __iomem *PREG_ETH_REG0 = NULL;
void __iomem *PREG_ETH_REG1 = NULL;
void __iomem *PREG_ETH_REG2 = NULL;
void __iomem *PREG_ETH_REG3 = NULL;
void __iomem *PREG_ETH_REG4 = NULL;
/*map reg0 and reg 1 addr.*/
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "Unable to get resource(%d)\n", __LINE__);
return NULL;
}
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
dev_err(&pdev->dev, "Unable to map base (%d)\n", __LINE__);
return NULL;
}
PREG_ETH_REG0 = addr;
PREG_ETH_REG1 = addr + 4;
pr_debug("REG0:REG1 = %p :%p\n", PREG_ETH_REG0, PREG_ETH_REG1);
if (!of_property_read_u32(np, "internal_phy", &internal_phy)) {
res = NULL;
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (res) {
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
dev_err(&pdev->dev, "Unable to map %d\n", __LINE__);
return NULL;
}
PREG_ETH_REG2 = addr;
PREG_ETH_REG3 = addr + 4;
PREG_ETH_REG4 = addr + 8;
@@ -165,6 +208,128 @@ static void __iomem *network_interface_setup(struct platform_device *pdev)
pr_debug("Ethernet: pinmux setup ok\n");
return PREG_ETH_REG0;
}
static int dwmac_meson_cfg_pll(void __iomem *base_addr)
{
void __iomem *ETH_PHY_config_addr = base_addr;
writel(0x19C0040A, ETH_PHY_config_addr + ETH_PLL_CTL0);
writel(0x927E0000, ETH_PHY_config_addr + ETH_PLL_CTL1);
writel(0x705B49e5, ETH_PHY_config_addr + ETH_PLL_CTL2);
writel(0x00000000, ETH_PHY_config_addr + ETH_PLL_CTL3);
usleep_range(100, 200);
writel(0x19C0040A, ETH_PHY_config_addr + ETH_PLL_CTL0);
return 0;
}
static int dwmac_meson_cfg_analog(void __iomem *base_addr)
{
void __iomem *ETH_PHY_config_addr = base_addr;
/*Analog*/
writel(0x20200000, ETH_PHY_config_addr + ETH_PLL_CTL5);
writel(0x0000c002, ETH_PHY_config_addr + ETH_PLL_CTL6);
writel(0x00000023, ETH_PHY_config_addr + ETH_PLL_CTL7);
return 0;
}
static int dwmac_meson_cfg_ctrl(void __iomem *base_addr)
{
void __iomem *ETH_PHY_config_addr = base_addr;
/*config phyid should between a 0~0xffffffff*/
/*please don't use 44000181, this has been used by internal phy*/
writel(0x33000180, ETH_PHY_config_addr + ETH_PHY_CNTL0);
/*use_phy_smi | use_phy_ip | co_clkin from eth_phy_top*/
writel(0x260, ETH_PHY_config_addr + ETH_PHY_CNTL2);
writel(0x74043, ETH_PHY_config_addr + ETH_PHY_CNTL1);
writel(0x34043, ETH_PHY_config_addr + ETH_PHY_CNTL1);
writel(0x74043, ETH_PHY_config_addr + ETH_PHY_CNTL1);
return 0;
}
/*for newer then g12a use this dts architecture for dts*/
static void __iomem *g12a_network_interface_setup(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
struct pinctrl *pin_ctl;
struct resource *res = NULL;
u32 mc_val;
void __iomem *addr = NULL;
void __iomem *REG_ETH_reg0_addr = NULL;
void __iomem *ETH_PHY_config_addr = NULL;
u32 internal_phy = 0;
pr_debug("g12a_network_interface_setup\n");
/*map PRG_ETH_REG */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth_cfg");
if (!res) {
dev_err(&pdev->dev, "Unable to get resource(%d)\n", __LINE__);
return NULL;
}
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
dev_err(&pdev->dev, "Unable to map base (%d)\n", __LINE__);
return NULL;
}
REG_ETH_reg0_addr = addr;
pr_info(" REG0:Addr = %p\n", REG_ETH_reg0_addr);
/*map ETH_PLL address*/
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "eth_pll");
if (!res) {
dev_err(&pdev->dev, "Unable to get resource(%d)\n", __LINE__);
return NULL;
}
addr = devm_ioremap_resource(dev, res);
if (IS_ERR(addr)) {
dev_err(&pdev->dev, "Unable to map clk base (%d)\n", __LINE__);
return NULL;
}
ETH_PHY_config_addr = addr;
/*PRG_ETH_REG0*/
if (of_property_read_u32(np, "mc_val", &mc_val))
pr_info("Miss mc_val for REG0\n");
else
writel(mc_val, REG_ETH_reg0_addr);
/*read phy option*/
if (of_property_read_u32(np, "internal_phy", &internal_phy) != 0) {
pr_info("Dts miss internal_phy item\n");
return REG_ETH_reg0_addr;
}
/* Config G12A internal PHY */
if (internal_phy) {
/*PLL*/
dwmac_meson_cfg_pll(ETH_PHY_config_addr);
dwmac_meson_cfg_analog(ETH_PHY_config_addr);
dwmac_meson_cfg_ctrl(ETH_PHY_config_addr);
pin_ctl = devm_pinctrl_get_select
(&pdev->dev, "internal_eth_pins");
return REG_ETH_reg0_addr;
}
/*config extern phy*/
if (internal_phy == 0) {
/*TODO*/
pin_ctl = devm_pinctrl_get_select
(&pdev->dev, "external_eth_pins");
return REG_ETH_reg0_addr;
}
pr_info("should not happen\n");
return REG_ETH_reg0_addr;
}
#endif
static int meson6_dwmac_probe(struct platform_device *pdev)
{
@@ -188,7 +353,13 @@ static int meson6_dwmac_probe(struct platform_device *pdev)
}
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
dwmac->reg = network_interface_setup(pdev);
dwmac->data = (const struct meson_dwmac_data *)
of_device_get_match_data(&pdev->dev);
if (dwmac->data->g12a_phy)
dwmac->reg = g12a_network_interface_setup(pdev);
else
dwmac->reg = network_interface_setup(pdev);
/* Custom initialisation (if needed) */
if (plat_dat->init) {
ret = plat_dat->init(pdev, plat_dat->bsp_priv);
@@ -219,9 +390,31 @@ err_remove_config_dt:
return ret;
}
static const struct of_device_id meson6_dwmac_match[] = {
{ .compatible = "amlogic,meson6-dwmac" },
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
static const struct meson_dwmac_data gxbb_dwmac_data = {
.g12a_phy = false,
};
static const struct meson_dwmac_data g12a_dwmac_data = {
.g12a_phy = true,
};
#endif
static const struct of_device_id meson6_dwmac_match[] = {
#ifdef CONFIG_AMLOGIC_ETH_PRIVE
{
.compatible = "amlogic, meson6-dwmac",
.data = &gxbb_dwmac_data,
},
{
.compatible = "amlogic, gxbb-eth-dwmac",
.data = &gxbb_dwmac_data,
},
{
.compatible = "amlogic, g12a-eth-dwmac",
.data = &g12a_dwmac_data,
},
#else
{ .compatible = "amlogic,meson6-dwmac" },
{ .compatible = "amlogic, gxbb-eth-dwmac" },
#endif
{ }