diff options
author | Ley Foon Tan <lftan@altera.com> | 2014-08-20 02:33:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-08-22 15:33:48 -0400 |
commit | b4834c86e11bafc2bf7d3af6a6a5d9ea48b54b41 (patch) | |
tree | bc0c1a85f50ffa30ec39c80e8add7d162c91a82f /drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | |
parent | 6e1d0b8988188956dac091441c1492a79a342666 (diff) |
net: stmmac: add fix_mac_speed support for socfpga
This patch adds fix_mac_speed() support for
Altera socfpga Ethernet controller. Emac splitter is a
soft IP core in FPGA system that converts GMII interface from
Synopsys mac to RGMII/SGMII interface. This splitter core is
an optional IP if user would like to use RGMII/SGMII
interface in their system. Software needs to update a register
in splitter core when there is speed change.
Signed-off-by: Ley Foon Tan <lftan@altera.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c index ec632e666c56..cd613d711108 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/mfd/syscon.h> | 18 | #include <linux/mfd/syscon.h> |
19 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | ||
20 | #include <linux/of_net.h> | 21 | #include <linux/of_net.h> |
21 | #include <linux/phy.h> | 22 | #include <linux/phy.h> |
22 | #include <linux/regmap.h> | 23 | #include <linux/regmap.h> |
@@ -30,6 +31,12 @@ | |||
30 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 | 31 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_WIDTH 2 |
31 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 | 32 | #define SYSMGR_EMACGRP_CTRL_PHYSEL_MASK 0x00000003 |
32 | 33 | ||
34 | #define EMAC_SPLITTER_CTRL_REG 0x0 | ||
35 | #define EMAC_SPLITTER_CTRL_SPEED_MASK 0x3 | ||
36 | #define EMAC_SPLITTER_CTRL_SPEED_10 0x2 | ||
37 | #define EMAC_SPLITTER_CTRL_SPEED_100 0x3 | ||
38 | #define EMAC_SPLITTER_CTRL_SPEED_1000 0x0 | ||
39 | |||
33 | struct socfpga_dwmac { | 40 | struct socfpga_dwmac { |
34 | int interface; | 41 | int interface; |
35 | u32 reg_offset; | 42 | u32 reg_offset; |
@@ -37,14 +44,46 @@ struct socfpga_dwmac { | |||
37 | struct device *dev; | 44 | struct device *dev; |
38 | struct regmap *sys_mgr_base_addr; | 45 | struct regmap *sys_mgr_base_addr; |
39 | struct reset_control *stmmac_rst; | 46 | struct reset_control *stmmac_rst; |
47 | void __iomem *splitter_base; | ||
40 | }; | 48 | }; |
41 | 49 | ||
50 | static void socfpga_dwmac_fix_mac_speed(void *priv, unsigned int speed) | ||
51 | { | ||
52 | struct socfpga_dwmac *dwmac = (struct socfpga_dwmac *)priv; | ||
53 | void __iomem *splitter_base = dwmac->splitter_base; | ||
54 | u32 val; | ||
55 | |||
56 | if (!splitter_base) | ||
57 | return; | ||
58 | |||
59 | val = readl(splitter_base + EMAC_SPLITTER_CTRL_REG); | ||
60 | val &= ~EMAC_SPLITTER_CTRL_SPEED_MASK; | ||
61 | |||
62 | switch (speed) { | ||
63 | case 1000: | ||
64 | val |= EMAC_SPLITTER_CTRL_SPEED_1000; | ||
65 | break; | ||
66 | case 100: | ||
67 | val |= EMAC_SPLITTER_CTRL_SPEED_100; | ||
68 | break; | ||
69 | case 10: | ||
70 | val |= EMAC_SPLITTER_CTRL_SPEED_10; | ||
71 | break; | ||
72 | default: | ||
73 | return; | ||
74 | } | ||
75 | |||
76 | writel(val, splitter_base + EMAC_SPLITTER_CTRL_REG); | ||
77 | } | ||
78 | |||
42 | static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) | 79 | static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device *dev) |
43 | { | 80 | { |
44 | struct device_node *np = dev->of_node; | 81 | struct device_node *np = dev->of_node; |
45 | struct regmap *sys_mgr_base_addr; | 82 | struct regmap *sys_mgr_base_addr; |
46 | u32 reg_offset, reg_shift; | 83 | u32 reg_offset, reg_shift; |
47 | int ret; | 84 | int ret; |
85 | struct device_node *np_splitter; | ||
86 | struct resource res_splitter; | ||
48 | 87 | ||
49 | dwmac->stmmac_rst = devm_reset_control_get(dev, | 88 | dwmac->stmmac_rst = devm_reset_control_get(dev, |
50 | STMMAC_RESOURCE_NAME); | 89 | STMMAC_RESOURCE_NAME); |
@@ -73,6 +112,21 @@ static int socfpga_dwmac_parse_data(struct socfpga_dwmac *dwmac, struct device * | |||
73 | return -EINVAL; | 112 | return -EINVAL; |
74 | } | 113 | } |
75 | 114 | ||
115 | np_splitter = of_parse_phandle(np, "altr,emac-splitter", 0); | ||
116 | if (np_splitter) { | ||
117 | if (of_address_to_resource(np_splitter, 0, &res_splitter)) { | ||
118 | dev_info(dev, "Missing emac splitter address\n"); | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | |||
122 | dwmac->splitter_base = (void *)devm_ioremap_resource(dev, | ||
123 | &res_splitter); | ||
124 | if (!dwmac->splitter_base) { | ||
125 | dev_info(dev, "Failed to mapping emac splitter\n"); | ||
126 | return -EINVAL; | ||
127 | } | ||
128 | } | ||
129 | |||
76 | dwmac->reg_offset = reg_offset; | 130 | dwmac->reg_offset = reg_offset; |
77 | dwmac->reg_shift = reg_shift; | 131 | dwmac->reg_shift = reg_shift; |
78 | dwmac->sys_mgr_base_addr = sys_mgr_base_addr; | 132 | dwmac->sys_mgr_base_addr = sys_mgr_base_addr; |
@@ -91,6 +145,7 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) | |||
91 | 145 | ||
92 | switch (phymode) { | 146 | switch (phymode) { |
93 | case PHY_INTERFACE_MODE_RGMII: | 147 | case PHY_INTERFACE_MODE_RGMII: |
148 | case PHY_INTERFACE_MODE_RGMII_ID: | ||
94 | val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; | 149 | val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII; |
95 | break; | 150 | break; |
96 | case PHY_INTERFACE_MODE_MII: | 151 | case PHY_INTERFACE_MODE_MII: |
@@ -102,6 +157,13 @@ static int socfpga_dwmac_setup(struct socfpga_dwmac *dwmac) | |||
102 | return -EINVAL; | 157 | return -EINVAL; |
103 | } | 158 | } |
104 | 159 | ||
160 | /* Overwrite val to GMII if splitter core is enabled. The phymode here | ||
161 | * is the actual phy mode on phy hardware, but phy interface from | ||
162 | * EMAC core is GMII. | ||
163 | */ | ||
164 | if (dwmac->splitter_base) | ||
165 | val = SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_GMII_MII; | ||
166 | |||
105 | regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); | 167 | regmap_read(sys_mgr_base_addr, reg_offset, &ctrl); |
106 | ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); | 168 | ctrl &= ~(SYSMGR_EMACGRP_CTRL_PHYSEL_MASK << reg_shift); |
107 | ctrl |= val << reg_shift; | 169 | ctrl |= val << reg_shift; |
@@ -196,4 +258,5 @@ const struct stmmac_of_data socfpga_gmac_data = { | |||
196 | .setup = socfpga_dwmac_probe, | 258 | .setup = socfpga_dwmac_probe, |
197 | .init = socfpga_dwmac_init, | 259 | .init = socfpga_dwmac_init, |
198 | .exit = socfpga_dwmac_exit, | 260 | .exit = socfpga_dwmac_exit, |
261 | .fix_mac_speed = socfpga_dwmac_fix_mac_speed, | ||
199 | }; | 262 | }; |