Commit 5befa5e8 authored by David S. Miller's avatar David S. Miller

Merge branch 'stmmac-IPQ806x'

Mathieu Olivari says:

====================
Add support for QCA IPQ806x Ethernet GMAC controller

This patch set adds support for the integrated Ethernet GMAC controller
on QCA IPQ806x SoC. This controller is based on a Gigabit Synopsys
DesignWare IP, already supported in the stmmac driver located in
drivers/net/ethernet/stmicro/stmmac.

This change is done as a follow-up to the following thread:
*http://www.spinics.net/lists/netdev/msg311265.html
While previous attempt was creating a new driver to drive this controller,
this new post leverages the existing stmmac driver by implementing the
SoC specific glue to it.

Aside from the pure stmmac glue layer, we have a couple of related
patches:
*IPQ806x NSS clock addition is cherry-picked and refreshed from the
 following thread: https://lkml.org/lkml/2014/8/6/390
*phy-handle and fixed-link support are also added in this change set so the
 driver can be fully functional on platforms using device-trees as well as
 ethernet switches.

V2:
 *Fix MODULE_LICENSE to "Dual BSD/GPL" as the dwmac-ipq806x.c is using
  ISC license.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a74eab63 95e130af
* IPQ806x DWMAC Ethernet controller
The device inherits all the properties of the dwmac/stmmac devices
described in the file net/stmmac.txt with the following changes.
Required properties:
- compatible: should be "qcom,ipq806x-gmac" along with "snps,dwmac"
and any applicable more detailed version number
described in net/stmmac.txt
- qcom,nss-common: should contain a phandle to a syscon device mapping the
nss-common registers.
- qcom,qsgmii-csr: should contain a phandle to a syscon device mapping the
qsgmii-csr registers.
Example:
gmac: ethernet@37000000 {
device_type = "network";
compatible = "qcom,ipq806x-gmac";
reg = <0x37000000 0x200000>;
interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "macirq";
qcom,nss-common = <&nss_common>;
qcom,qsgmii-csr = <&qsgmii_csr>;
clocks = <&gcc GMAC_CORE1_CLK>;
clock-names = "stmmaceth";
resets = <&gcc GMAC_CORE1_RESET>;
reset-names = "stmmaceth";
};
...@@ -140,12 +140,47 @@ static struct clk_regmap pll14_vote = { ...@@ -140,12 +140,47 @@ static struct clk_regmap pll14_vote = {
}, },
}; };
#define NSS_PLL_RATE(f, _l, _m, _n, i) \
{ \
.freq = f, \
.l = _l, \
.m = _m, \
.n = _n, \
.ibits = i, \
}
static struct pll_freq_tbl pll18_freq_tbl[] = {
NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625),
NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625),
};
static struct clk_pll pll18 = {
.l_reg = 0x31a4,
.m_reg = 0x31a8,
.n_reg = 0x31ac,
.config_reg = 0x31b4,
.mode_reg = 0x31a0,
.status_reg = 0x31b8,
.status_bit = 16,
.post_div_shift = 16,
.post_div_width = 1,
.freq_tbl = pll18_freq_tbl,
.clkr.hw.init = &(struct clk_init_data){
.name = "pll18",
.parent_names = (const char *[]){ "pxo" },
.num_parents = 1,
.ops = &clk_pll_ops,
},
};
enum { enum {
P_PXO, P_PXO,
P_PLL8, P_PLL8,
P_PLL3, P_PLL3,
P_PLL0, P_PLL0,
P_CXO, P_CXO,
P_PLL14,
P_PLL18,
}; };
static const struct parent_map gcc_pxo_pll8_map[] = { static const struct parent_map gcc_pxo_pll8_map[] = {
...@@ -197,6 +232,22 @@ static const char *gcc_pxo_pll8_pll0_map[] = { ...@@ -197,6 +232,22 @@ static const char *gcc_pxo_pll8_pll0_map[] = {
"pll0_vote", "pll0_vote",
}; };
static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
{ P_PXO, 0 },
{ P_PLL8, 4 },
{ P_PLL0, 2 },
{ P_PLL14, 5 },
{ P_PLL18, 1 }
};
static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
"pxo",
"pll8_vote",
"pll0_vote",
"pll14",
"pll18",
};
static struct freq_tbl clk_tbl_gsbi_uart[] = { static struct freq_tbl clk_tbl_gsbi_uart[] = {
{ 1843200, P_PLL8, 2, 6, 625 }, { 1843200, P_PLL8, 2, 6, 625 },
{ 3686400, P_PLL8, 2, 12, 625 }, { 3686400, P_PLL8, 2, 12, 625 },
...@@ -2202,6 +2253,472 @@ static struct clk_branch ebi2_aon_clk = { ...@@ -2202,6 +2253,472 @@ static struct clk_branch ebi2_aon_clk = {
}, },
}; };
static const struct freq_tbl clk_tbl_gmac[] = {
{ 133000000, P_PLL0, 1, 50, 301 },
{ 266000000, P_PLL0, 1, 127, 382 },
{ }
};
static struct clk_dyn_rcg gmac_core1_src = {
.ns_reg[0] = 0x3cac,
.ns_reg[1] = 0x3cb0,
.md_reg[0] = 0x3ca4,
.md_reg[1] = 0x3ca8,
.bank_reg = 0x3ca0,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_gmac,
.clkr = {
.enable_reg = 0x3ca0,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gmac_core1_src",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
},
},
};
static struct clk_branch gmac_core1_clk = {
.halt_reg = 0x3c20,
.halt_bit = 4,
.hwcg_reg = 0x3cb4,
.hwcg_bit = 6,
.clkr = {
.enable_reg = 0x3cb4,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gmac_core1_clk",
.parent_names = (const char *[]){
"gmac_core1_src",
},
.num_parents = 1,
.ops = &clk_branch_ops,
.flags = CLK_SET_RATE_PARENT,
},
},
};
static struct clk_dyn_rcg gmac_core2_src = {
.ns_reg[0] = 0x3ccc,
.ns_reg[1] = 0x3cd0,
.md_reg[0] = 0x3cc4,
.md_reg[1] = 0x3cc8,
.bank_reg = 0x3ca0,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_gmac,
.clkr = {
.enable_reg = 0x3cc0,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gmac_core2_src",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
},
},
};
static struct clk_branch gmac_core2_clk = {
.halt_reg = 0x3c20,
.halt_bit = 5,
.hwcg_reg = 0x3cd4,
.hwcg_bit = 6,
.clkr = {
.enable_reg = 0x3cd4,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gmac_core2_clk",
.parent_names = (const char *[]){
"gmac_core2_src",
},
.num_parents = 1,
.ops = &clk_branch_ops,
.flags = CLK_SET_RATE_PARENT,
},
},
};
static struct clk_dyn_rcg gmac_core3_src = {
.ns_reg[0] = 0x3cec,
.ns_reg[1] = 0x3cf0,
.md_reg[0] = 0x3ce4,
.md_reg[1] = 0x3ce8,
.bank_reg = 0x3ce0,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_gmac,
.clkr = {
.enable_reg = 0x3ce0,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gmac_core3_src",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
},
},
};
static struct clk_branch gmac_core3_clk = {
.halt_reg = 0x3c20,
.halt_bit = 6,
.hwcg_reg = 0x3cf4,
.hwcg_bit = 6,
.clkr = {
.enable_reg = 0x3cf4,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gmac_core3_clk",
.parent_names = (const char *[]){
"gmac_core3_src",
},
.num_parents = 1,
.ops = &clk_branch_ops,
.flags = CLK_SET_RATE_PARENT,
},
},
};
static struct clk_dyn_rcg gmac_core4_src = {
.ns_reg[0] = 0x3d0c,
.ns_reg[1] = 0x3d10,
.md_reg[0] = 0x3d04,
.md_reg[1] = 0x3d08,
.bank_reg = 0x3d00,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_gmac,
.clkr = {
.enable_reg = 0x3d00,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "gmac_core4_src",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
},
},
};
static struct clk_branch gmac_core4_clk = {
.halt_reg = 0x3c20,
.halt_bit = 7,
.hwcg_reg = 0x3d14,
.hwcg_bit = 6,
.clkr = {
.enable_reg = 0x3d14,
.enable_mask = BIT(4),
.hw.init = &(struct clk_init_data){
.name = "gmac_core4_clk",
.parent_names = (const char *[]){
"gmac_core4_src",
},
.num_parents = 1,
.ops = &clk_branch_ops,
.flags = CLK_SET_RATE_PARENT,
},
},
};
static const struct freq_tbl clk_tbl_nss_tcm[] = {
{ 266000000, P_PLL0, 3, 0, 0 },
{ 400000000, P_PLL0, 2, 0, 0 },
{ }
};
static struct clk_dyn_rcg nss_tcm_src = {
.ns_reg[0] = 0x3dc4,
.ns_reg[1] = 0x3dc8,
.bank_reg = 0x3dc0,
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 4,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 4,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_nss_tcm,
.clkr = {
.enable_reg = 0x3dc0,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "nss_tcm_src",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
},
},
};
static struct clk_branch nss_tcm_clk = {
.halt_reg = 0x3c20,
.halt_bit = 14,
.clkr = {
.enable_reg = 0x3dd0,
.enable_mask = BIT(6) | BIT(4),
.hw.init = &(struct clk_init_data){
.name = "nss_tcm_clk",
.parent_names = (const char *[]){
"nss_tcm_src",
},
.num_parents = 1,
.ops = &clk_branch_ops,
.flags = CLK_SET_RATE_PARENT,
},
},
};
static const struct freq_tbl clk_tbl_nss[] = {
{ 110000000, P_PLL18, 1, 1, 5 },
{ 275000000, P_PLL18, 2, 0, 0 },
{ 550000000, P_PLL18, 1, 0, 0 },
{ 733000000, P_PLL18, 1, 0, 0 },
{ }
};
static struct clk_dyn_rcg ubi32_core1_src_clk = {
.ns_reg[0] = 0x3d2c,
.ns_reg[1] = 0x3d30,
.md_reg[0] = 0x3d24,
.md_reg[1] = 0x3d28,
.bank_reg = 0x3d20,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_nss,
.clkr = {
.enable_reg = 0x3d20,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "ubi32_core1_src_clk",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
},
};
static struct clk_dyn_rcg ubi32_core2_src_clk = {
.ns_reg[0] = 0x3d4c,
.ns_reg[1] = 0x3d50,
.md_reg[0] = 0x3d44,
.md_reg[1] = 0x3d48,
.bank_reg = 0x3d40,
.mn[0] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.mn[1] = {
.mnctr_en_bit = 8,
.mnctr_reset_bit = 7,
.mnctr_mode_shift = 5,
.n_val_shift = 16,
.m_val_shift = 16,
.width = 8,
},
.s[0] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.s[1] = {
.src_sel_shift = 0,
.parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
},
.p[0] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.p[1] = {
.pre_div_shift = 3,
.pre_div_width = 2,
},
.mux_sel_bit = 0,
.freq_tbl = clk_tbl_nss,
.clkr = {
.enable_reg = 0x3d40,
.enable_mask = BIT(1),
.hw.init = &(struct clk_init_data){
.name = "ubi32_core2_src_clk",
.parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
.num_parents = 5,
.ops = &clk_dyn_rcg_ops,
.flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
},
},
};
static struct clk_regmap *gcc_ipq806x_clks[] = { static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr, [PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote, [PLL0_VOTE] = &pll0_vote,
...@@ -2211,6 +2728,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { ...@@ -2211,6 +2728,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL8_VOTE] = &pll8_vote, [PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr, [PLL14] = &pll14.clkr,
[PLL14_VOTE] = &pll14_vote, [PLL14_VOTE] = &pll14_vote,
[PLL18] = &pll18.clkr,
[GSBI1_UART_SRC] = &gsbi1_uart_src.clkr, [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr,
[GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr, [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr,
[GSBI2_UART_SRC] = &gsbi2_uart_src.clkr, [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr,
...@@ -2307,6 +2825,18 @@ static struct clk_regmap *gcc_ipq806x_clks[] = { ...@@ -2307,6 +2825,18 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr, [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr,
[EBI2_CLK] = &ebi2_clk.clkr, [EBI2_CLK] = &ebi2_clk.clkr,
[EBI2_AON_CLK] = &ebi2_aon_clk.clkr, [EBI2_AON_CLK] = &ebi2_aon_clk.clkr,
[GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr,
[GMAC_CORE1_CLK] = &gmac_core1_clk.clkr,
[GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr,
[GMAC_CORE2_CLK] = &gmac_core2_clk.clkr,
[GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr,
[GMAC_CORE3_CLK] = &gmac_core3_clk.clkr,
[GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr,
[GMAC_CORE4_CLK] = &gmac_core4_clk.clkr,
[UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr,
[UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
[NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
[NSSTCM_CLK] = &nss_tcm_clk.clkr,
}; };
static const struct qcom_reset_map gcc_ipq806x_resets[] = { static const struct qcom_reset_map gcc_ipq806x_resets[] = {
...@@ -2425,6 +2955,48 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = { ...@@ -2425,6 +2955,48 @@ static const struct qcom_reset_map gcc_ipq806x_resets[] = {
[USB30_1_PHY_RESET] = { 0x3b58, 0 }, [USB30_1_PHY_RESET] = { 0x3b58, 0 },
[NSSFB0_RESET] = { 0x3b60, 6 }, [NSSFB0_RESET] = { 0x3b60, 6 },
[NSSFB1_RESET] = { 0x3b60, 7 }, [NSSFB1_RESET] = { 0x3b60, 7 },
[UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3},
[UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 },
[UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 },
[UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 },
[UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 },
[UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 },
[UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 },
[UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 },
[GMAC_CORE1_RESET] = { 0x3cbc, 0 },
[GMAC_CORE2_RESET] = { 0x3cdc, 0 },
[GMAC_CORE3_RESET] = { 0x3cfc, 0 },
[GMAC_CORE4_RESET] = { 0x3d1c, 0 },
[GMAC_AHB_RESET] = { 0x3e24, 0 },
[NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 },
[NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 },
[NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 },
[NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 },
[NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 },
[NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 },
[NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 },
[NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 },
[NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 },
[NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 },
[NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 },
[NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 },
[NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 },
[NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 },
[NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 },
[NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 },
[NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 },
[NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 },
[NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 },
[NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 },
[NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 },
[NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 },
[NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 },
[NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 },
[NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 },
[NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 },
[NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 },
[NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 },
[NSS_SRDS_N_RESET] = { 0x3b60, 28 },
}; };
static const struct regmap_config gcc_ipq806x_regmap_config = { static const struct regmap_config gcc_ipq806x_regmap_config = {
...@@ -2453,6 +3025,8 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) ...@@ -2453,6 +3025,8 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
{ {
struct clk *clk; struct clk *clk;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct regmap *regmap;
int ret;
/* Temporary until RPM clocks supported */ /* Temporary until RPM clocks supported */
clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000); clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
...@@ -2463,7 +3037,25 @@ static int gcc_ipq806x_probe(struct platform_device *pdev) ...@@ -2463,7 +3037,25 @@ static int gcc_ipq806x_probe(struct platform_device *pdev)
if (IS_ERR(clk)) if (IS_ERR(clk))
return PTR_ERR(clk); return PTR_ERR(clk);
return qcom_cc_probe(pdev, &gcc_ipq806x_desc); ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
if (ret)
return ret;
regmap = dev_get_regmap(dev, NULL);
if (!regmap)
return -ENODEV;
/* Setup PLL18 static bits */
regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400);
regmap_write(regmap, 0x31b0, 0x3080);
/* Set GMAC footswitch sleep/wakeup values */
regmap_write(regmap, 0x3cb8, 8);
regmap_write(regmap, 0x3cd8, 8);
regmap_write(regmap, 0x3cf8, 8);
regmap_write(regmap, 0x3d18, 8);
return 0;
} }
static int gcc_ipq806x_remove(struct platform_device *pdev) static int gcc_ipq806x_remove(struct platform_device *pdev)
......
...@@ -16,6 +16,7 @@ if STMMAC_ETH ...@@ -16,6 +16,7 @@ if STMMAC_ETH
config STMMAC_PLATFORM config STMMAC_PLATFORM
tristate "STMMAC Platform bus support" tristate "STMMAC Platform bus support"
depends on STMMAC_ETH depends on STMMAC_ETH
select MFD_SYSCON
default y default y
---help--- ---help---
This selects the platform specific bus support for the stmmac driver. This selects the platform specific bus support for the stmmac driver.
...@@ -36,6 +37,19 @@ config DWMAC_GENERIC ...@@ -36,6 +37,19 @@ config DWMAC_GENERIC
platform specific code to function or is using platform platform specific code to function or is using platform
data for setup. data for setup.
config DWMAC_IPQ806X
tristate "QCA IPQ806x DWMAC support"
default ARCH_QCOM
depends on OF
select MFD_SYSCON
help
Support for QCA IPQ806X DWMAC Ethernet.
This selects the IPQ806x SoC glue layer support for the stmmac
device driver. This driver does not use any of the hardware
acceleration features available on this SoC. Network devices
will behave like standard non-accelerated ethernet interfaces.
config DWMAC_LPC18XX config DWMAC_LPC18XX
tristate "NXP LPC18xx/43xx DWMAC support" tristate "NXP LPC18xx/43xx DWMAC support"
default ARCH_LPC18XX default ARCH_LPC18XX
......
...@@ -6,6 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ ...@@ -6,6 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
# Ordering matters. Generic driver must be last. # Ordering matters. Generic driver must be last.
obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
......
/*
* Qualcomm Atheros IPQ806x GMAC glue layer
*
* Copyright (C) 2015 The Linux Foundation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/of_net.h>
#include <linux/mfd/syscon.h>
#include <linux/stmmac.h>
#include <linux/of_mdio.h>
#include <linux/module.h>
#include "stmmac_platform.h"
#define NSS_COMMON_CLK_GATE 0x8
#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x)
#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2))
#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2))
#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x)
#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x)
#define NSS_COMMON_CLK_DIV0 0xC
#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8)
#define NSS_COMMON_CLK_DIV_MASK 0x7f
#define NSS_COMMON_CLK_SRC_CTRL 0x14
#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (1 << x)
/* Mode is coded on 1 bit but is different depending on the MAC ID:
* MAC0: QSGMII=0 RGMII=1
* MAC1: QSGMII=0 SGMII=0 RGMII=1
* MAC2 & MAC3: QSGMII=0 SGMII=1
*/
#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
#define NSS_COMMON_MACSEC_CTL 0x28
#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
#define NSS_COMMON_CLK_DIV_RGMII_1000 1
#define NSS_COMMON_CLK_DIV_RGMII_100 9
#define NSS_COMMON_CLK_DIV_RGMII_10 99
#define NSS_COMMON_CLK_DIV_SGMII_1000 0
#define NSS_COMMON_CLK_DIV_SGMII_100 4
#define NSS_COMMON_CLK_DIV_SGMII_10 49
#define QSGMII_PCS_MODE_CTL 0x68
#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \
(0x13c + (4 * (x - 2))))
#define QSGMII_PHY_CDR_EN BIT(0)
#define QSGMII_PHY_RX_FRONT_EN BIT(1)
#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2)
#define QSGMII_PHY_TX_DRIVER_EN BIT(3)
#define QSGMII_PHY_QSGMII_EN BIT(7)
#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
struct ipq806x_gmac {
struct platform_device *pdev;
struct regmap *nss_common;
struct regmap *qsgmii_csr;
uint32_t id;
struct clk *core_clk;
phy_interface_t phy_mode;
};
static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
{
struct device *dev = &gmac->pdev->dev;
int div;
switch (speed) {
case SPEED_1000:
div = NSS_COMMON_CLK_DIV_SGMII_1000;
break;
case SPEED_100:
div = NSS_COMMON_CLK_DIV_SGMII_100;
break;
case SPEED_10:
div = NSS_COMMON_CLK_DIV_SGMII_10;
break;
default:
dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
return -EINVAL;
}
return div;
}
static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
{
struct device *dev = &gmac->pdev->dev;
int div;
switch (speed) {
case SPEED_1000:
div = NSS_COMMON_CLK_DIV_RGMII_1000;
break;
case SPEED_100:
div = NSS_COMMON_CLK_DIV_RGMII_100;
break;
case SPEED_10:
div = NSS_COMMON_CLK_DIV_RGMII_10;
break;
default:
dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
return -EINVAL;
}
return div;
}
static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
{
uint32_t clk_bits, val;
int div;
switch (gmac->phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
div = get_clk_div_rgmii(gmac, speed);
clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
break;
case PHY_INTERFACE_MODE_SGMII:
div = get_clk_div_sgmii(gmac, speed);
clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
break;
default:
dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
phy_modes(gmac->phy_mode));
return -EINVAL;
}
/* Disable the clocks */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
val &= ~clk_bits;
regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
/* Set the divider */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
val &= ~(NSS_COMMON_CLK_DIV_MASK
<< NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
/* Enable the clock back */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
val |= clk_bits;
regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
return 0;
}
static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
{
struct device *dev = &gmac->pdev->dev;
gmac->phy_mode = of_get_phy_mode(dev->of_node);
if (gmac->phy_mode < 0) {
dev_err(dev, "missing phy mode property\n");
return ERR_PTR(-EINVAL);
}
if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
dev_err(dev, "missing qcom id property\n");
return ERR_PTR(-EINVAL);
}
/* The GMACs are called 1 to 4 in the documentation, but to simplify the
* code and keep it consistent with the Linux convention, we'll number
* them from 0 to 3 here.
*/
if (gmac->id < 0 || gmac->id > 3) {
dev_err(dev, "invalid gmac id\n");
return ERR_PTR(-EINVAL);
}
gmac->core_clk = devm_clk_get(dev, "stmmaceth");
if (IS_ERR(gmac->core_clk)) {
dev_err(dev, "missing stmmaceth clk property\n");
return gmac->core_clk;
}
clk_set_rate(gmac->core_clk, 266000000);
/* Setup the register map for the nss common registers */
gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
"qcom,nss-common");
if (IS_ERR(gmac->nss_common)) {
dev_err(dev, "missing nss-common node\n");
return gmac->nss_common;
}
/* Setup the register map for the qsgmii csr registers */
gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
"qcom,qsgmii-csr");
if (IS_ERR(gmac->qsgmii_csr)) {
dev_err(dev, "missing qsgmii-csr node\n");
return gmac->qsgmii_csr;
}
return NULL;
}
static void *ipq806x_gmac_setup(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ipq806x_gmac *gmac;
int val;
void *err;
gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
if (!gmac)
return ERR_PTR(-ENOMEM);
gmac->pdev = pdev;
err = ipq806x_gmac_of_parse(gmac);
if (err) {
dev_err(dev, "device tree parsing error\n");
return err;
}
regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
QSGMII_PCS_CAL_LCKDT_CTL_RST);
/* Inter frame gap is set to 12 */
val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
/* We also initiate an AXI low power exit request */
val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
switch (gmac->phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
break;
case PHY_INTERFACE_MODE_SGMII:
val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
break;
default:
dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
phy_modes(gmac->phy_mode));
return NULL;
}
regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
/* Configure the clock src according to the mode */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
val &= ~NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
switch (gmac->phy_mode) {
case PHY_INTERFACE_MODE_RGMII:
val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
break;
case PHY_INTERFACE_MODE_SGMII:
val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
break;
default:
dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
phy_modes(gmac->phy_mode));
return NULL;
}
regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
/* Enable PTP clock */
regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
QSGMII_PHY_CDR_EN |
QSGMII_PHY_RX_FRONT_EN |
QSGMII_PHY_RX_SIGNAL_DETECT_EN |
QSGMII_PHY_TX_DRIVER_EN |
QSGMII_PHY_QSGMII_EN |
0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
}
return gmac;
}
static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
{
struct ipq806x_gmac *gmac = priv;
ipq806x_gmac_set_speed(gmac, speed);
}
static const struct stmmac_of_data ipq806x_gmac_data = {
.has_gmac = 1,
.setup = ipq806x_gmac_setup,
.fix_mac_speed = ipq806x_gmac_fix_mac_speed,
};
static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
{ .compatible = "qcom,ipq806x-gmac", .data = &ipq806x_gmac_data },
{ }
};
MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match);
static struct platform_driver ipq806x_gmac_dwmac_driver = {
.probe = stmmac_pltfr_probe,
.remove = stmmac_pltfr_remove,
.driver = {
.name = "ipq806x-gmac-dwmac",
.pm = &stmmac_pltfr_pm_ops,
.of_match_table = ipq806x_gmac_dwmac_match,
},
};
module_platform_driver(ipq806x_gmac_dwmac_driver);
MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
MODULE_LICENSE("Dual BSD/GPL");
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include "stmmac_ptp.h" #include "stmmac_ptp.h"
#include "stmmac.h" #include "stmmac.h"
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/of_mdio.h>
#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x) #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
...@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_device *dev) ...@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_device *dev)
priv->speed = 0; priv->speed = 0;
priv->oldduplex = -1; priv->oldduplex = -1;
if (priv->plat->phy_bus_name) if (priv->plat->phy_node) {
snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x", phydev = of_phy_connect(dev, priv->plat->phy_node,
priv->plat->phy_bus_name, priv->plat->bus_id); &stmmac_adjust_link, 0, interface);
else } else {
snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", if (priv->plat->phy_bus_name)
priv->plat->bus_id); snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
priv->plat->phy_bus_name, priv->plat->bus_id);
else
snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
priv->plat->bus_id);
snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
priv->plat->phy_addr); priv->plat->phy_addr);
pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt); pr_debug("stmmac_init_phy: trying to attach to %s\n",
phy_id_fmt);
phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface); phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
interface);
}
if (IS_ERR(phydev)) { if (IS_ERR(phydev)) {
pr_err("%s: Could not attach to PHY\n", dev->name); pr_err("%s: Could not attach to PHY\n", dev->name);
...@@ -848,7 +856,7 @@ static int stmmac_init_phy(struct net_device *dev) ...@@ -848,7 +856,7 @@ static int stmmac_init_phy(struct net_device *dev)
* device as well. * device as well.
* Note: phydev->phy_id is the result of reading the UID PHY registers. * Note: phydev->phy_id is the result of reading the UID PHY registers.
*/ */
if (phydev->phy_id == 0) { if (!priv->plat->phy_node && phydev->phy_id == 0) {
phy_disconnect(phydev); phy_disconnect(phydev);
return -ENODEV; return -ENODEV;
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_net.h> #include <linux/of_net.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_mdio.h>
#include "stmmac.h" #include "stmmac.h"
#include "stmmac_platform.h" #include "stmmac_platform.h"
...@@ -144,13 +145,24 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, ...@@ -144,13 +145,24 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
/* Default to phy auto-detection */ /* Default to phy auto-detection */
plat->phy_addr = -1; plat->phy_addr = -1;
/* If we find a phy-handle property, use it as the PHY */
plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
/* If phy-handle is not specified, check if we have a fixed-phy */
if (!plat->phy_node && of_phy_is_fixed_link(np)) {
if ((of_phy_register_fixed_link(np) < 0))
return -ENODEV;
plat->phy_node = of_node_get(np);
}
/* "snps,phy-addr" is not a standard property. Mark it as deprecated /* "snps,phy-addr" is not a standard property. Mark it as deprecated
* and warn of its use. Remove this when phy node support is added. * and warn of its use. Remove this when phy node support is added.
*/ */
if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0) if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n"); dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
if (plat->phy_bus_name) if (plat->phy_node || plat->phy_bus_name)
plat->mdio_bus_data = NULL; plat->mdio_bus_data = NULL;
else else
plat->mdio_bus_data = plat->mdio_bus_data =
...@@ -208,8 +220,10 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, ...@@ -208,8 +220,10 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
if (of_find_property(np, "snps,pbl", NULL)) { if (of_find_property(np, "snps,pbl", NULL)) {
dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg), dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
GFP_KERNEL); GFP_KERNEL);
if (!dma_cfg) if (!dma_cfg) {
of_node_put(np);
return -ENOMEM; return -ENOMEM;
}
plat->dma_cfg = dma_cfg; plat->dma_cfg = dma_cfg;
of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
dma_cfg->fixed_burst = dma_cfg->fixed_burst =
......
...@@ -289,5 +289,7 @@ ...@@ -289,5 +289,7 @@
#define UBI32_CORE1_CLK 279 #define UBI32_CORE1_CLK 279
#define UBI32_CORE2_CLK 280 #define UBI32_CORE2_CLK 280
#define EBI2_AON_CLK 281 #define EBI2_AON_CLK 281
#define NSSTCM_CLK_SRC 282
#define NSSTCM_CLK 283
#endif #endif
...@@ -129,4 +129,47 @@ ...@@ -129,4 +129,47 @@
#define USB30_1_PHY_RESET 112 #define USB30_1_PHY_RESET 112
#define NSSFB0_RESET 113 #define NSSFB0_RESET 113
#define NSSFB1_RESET 114 #define NSSFB1_RESET 114
#define UBI32_CORE1_CLKRST_CLAMP_RESET 115
#define UBI32_CORE1_CLAMP_RESET 116
#define UBI32_CORE1_AHB_RESET 117
#define UBI32_CORE1_AXI_RESET 118
#define UBI32_CORE2_CLKRST_CLAMP_RESET 119
#define UBI32_CORE2_CLAMP_RESET 120
#define UBI32_CORE2_AHB_RESET 121
#define UBI32_CORE2_AXI_RESET 122
#define GMAC_CORE1_RESET 123
#define GMAC_CORE2_RESET 124
#define GMAC_CORE3_RESET 125
#define GMAC_CORE4_RESET 126
#define GMAC_AHB_RESET 127
#define NSS_CH0_RST_RX_CLK_N_RESET 128
#define NSS_CH0_RST_TX_CLK_N_RESET 129
#define NSS_CH0_RST_RX_125M_N_RESET 130
#define NSS_CH0_HW_RST_RX_125M_N_RESET 131
#define NSS_CH0_RST_TX_125M_N_RESET 132
#define NSS_CH1_RST_RX_CLK_N_RESET 133
#define NSS_CH1_RST_TX_CLK_N_RESET 134
#define NSS_CH1_RST_RX_125M_N_RESET 135
#define NSS_CH1_HW_RST_RX_125M_N_RESET 136
#define NSS_CH1_RST_TX_125M_N_RESET 137
#define NSS_CH2_RST_RX_CLK_N_RESET 138
#define NSS_CH2_RST_TX_CLK_N_RESET 139
#define NSS_CH2_RST_RX_125M_N_RESET 140
#define NSS_CH2_HW_RST_RX_125M_N_RESET 141
#define NSS_CH2_RST_TX_125M_N_RESET 142
#define NSS_CH3_RST_RX_CLK_N_RESET 143
#define NSS_CH3_RST_TX_CLK_N_RESET 144
#define NSS_CH3_RST_RX_125M_N_RESET 145
#define NSS_CH3_HW_RST_RX_125M_N_RESET 146
#define NSS_CH3_RST_TX_125M_N_RESET 147
#define NSS_RST_RX_250M_125M_N_RESET 148
#define NSS_RST_TX_250M_125M_N_RESET 149
#define NSS_QSGMII_TXPI_RST_N_RESET 150
#define NSS_QSGMII_CDR_RST_N_RESET 151
#define NSS_SGMII2_CDR_RST_N_RESET 152
#define NSS_SGMII3_CDR_RST_N_RESET 153
#define NSS_CAL_PRBS_RST_N_RESET 154
#define NSS_LCKDT_RST_N_RESET 155
#define NSS_SRDS_N_RESET 156
#endif #endif
...@@ -99,6 +99,7 @@ struct plat_stmmacenet_data { ...@@ -99,6 +99,7 @@ struct plat_stmmacenet_data {
int phy_addr; int phy_addr;
int interface; int interface;
struct stmmac_mdio_bus_data *mdio_bus_data; struct stmmac_mdio_bus_data *mdio_bus_data;
struct device_node *phy_node;
struct stmmac_dma_cfg *dma_cfg; struct stmmac_dma_cfg *dma_cfg;
int clk_csr; int clk_csr;
int has_gmac; int has_gmac;
......
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