diff options
author | J, KEERTHY | 2019-12-05 08:29:30 -0600 |
---|---|---|
committer | Murali Karicheri | 2019-12-10 15:40:39 -0600 |
commit | e2b89fe8e8a17570ba0785e91dedd15e0e006889 (patch) | |
tree | b21b8991cc4d435ae925c750c477025fd593c7d7 | |
parent | 8e7ad5c94d872f6fc312b35036707133ccffa4ee (diff) | |
download | processor-sdk-u-boot-e2b89fe8e8a17570ba0785e91dedd15e0e006889.tar.gz processor-sdk-u-boot-e2b89fe8e8a17570ba0785e91dedd15e0e006889.tar.xz processor-sdk-u-boot-e2b89fe8e8a17570ba0785e91dedd15e0e006889.zip |
net: ti: icssg-prueth: Add support for 100M links
Currently driver doesn't set the speed and full duplex parameters
in RGMII CFG based on PHY auto negotiated parameters. This patch
make updates so that both 100M/1G link speed and full duplex are
configured in RGMII CFG register based on PHY negotiated values.
Also Firmware requires that minimum inter packet gap (TX_IPG0/1 field of
ICSSG_TX_IPG0/1 register) is to be set to desired values based on the
PHY link speed. This patch updates the same based on PHY link speed.
Both of the above together add support for 100M.
Signed-off-by: Keerthy <j-keerthy@ti.com>
Acked-by: Roger Quadros <rogerq@ti.com>
-rw-r--r-- | drivers/net/ti/icssg-prueth.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/net/ti/icssg-prueth.c b/drivers/net/ti/icssg-prueth.c index 3a7f39da4b..4090d22d03 100644 --- a/drivers/net/ti/icssg-prueth.c +++ b/drivers/net/ti/icssg-prueth.c | |||
@@ -82,6 +82,7 @@ enum pruss_pru_id { | |||
82 | struct prueth { | 82 | struct prueth { |
83 | struct udevice *dev; | 83 | struct udevice *dev; |
84 | struct regmap *miig_rt; | 84 | struct regmap *miig_rt; |
85 | struct regmap *mii_rt; | ||
85 | fdt_addr_t mdio_base; | 86 | fdt_addr_t mdio_base; |
86 | phys_addr_t pruss_shrdram2; | 87 | phys_addr_t pruss_shrdram2; |
87 | phys_addr_t tmaddr; | 88 | phys_addr_t tmaddr; |
@@ -104,6 +105,85 @@ struct prueth { | |||
104 | int slice; | 105 | int slice; |
105 | }; | 106 | }; |
106 | 107 | ||
108 | /** | ||
109 | * TX IPG Values to be set for 100M and 1G link speeds. These values are | ||
110 | * in ocp_clk cycles. So need change if ocp_clk is changed for a specific | ||
111 | * h/w design. | ||
112 | */ | ||
113 | #define MII_RT_TX_IPG_100M 0x166 | ||
114 | #define MII_RT_TX_IPG_1G 0x18 | ||
115 | |||
116 | #define RGMII_CFG_OFFSET 4 | ||
117 | |||
118 | /* Constant to choose between MII0 and MII1 */ | ||
119 | #define ICSS_MII0 0 | ||
120 | #define ICSS_MII1 1 | ||
121 | |||
122 | /* RGMII CFG Register bits */ | ||
123 | #define RGMII_CFG_GIG_EN_MII0 BIT(17) | ||
124 | #define RGMII_CFG_GIG_EN_MII1 BIT(21) | ||
125 | #define RGMII_CFG_FULL_DUPLEX_MII0 BIT(18) | ||
126 | #define RGMII_CFG_FULL_DUPLEX_MII1 BIT(22) | ||
127 | |||
128 | /* PRUSS_MII_RT Registers */ | ||
129 | #define PRUSS_MII_RT_RXCFG0 0x0 | ||
130 | #define PRUSS_MII_RT_RXCFG1 0x4 | ||
131 | #define PRUSS_MII_RT_TXCFG0 0x10 | ||
132 | #define PRUSS_MII_RT_TXCFG1 0x14 | ||
133 | #define PRUSS_MII_RT_TX_CRC0 0x20 | ||
134 | #define PRUSS_MII_RT_TX_CRC1 0x24 | ||
135 | #define PRUSS_MII_RT_TX_IPG0 0x30 | ||
136 | #define PRUSS_MII_RT_TX_IPG1 0x34 | ||
137 | #define PRUSS_MII_RT_PRS0 0x38 | ||
138 | #define PRUSS_MII_RT_PRS1 0x3c | ||
139 | #define PRUSS_MII_RT_RX_FRMS0 0x40 | ||
140 | #define PRUSS_MII_RT_RX_FRMS1 0x44 | ||
141 | #define PRUSS_MII_RT_RX_PCNT0 0x48 | ||
142 | #define PRUSS_MII_RT_RX_PCNT1 0x4c | ||
143 | #define PRUSS_MII_RT_RX_ERR0 0x50 | ||
144 | #define PRUSS_MII_RT_RX_ERR1 0x54 | ||
145 | |||
146 | static inline void icssg_update_rgmii_cfg(struct regmap *miig_rt, bool gig_en, | ||
147 | bool full_duplex, int mii) | ||
148 | { | ||
149 | u32 gig_en_mask, gig_val = 0, full_duplex_mask, full_duplex_val = 0; | ||
150 | |||
151 | gig_en_mask = (mii == ICSS_MII0) ? RGMII_CFG_GIG_EN_MII0 : | ||
152 | RGMII_CFG_GIG_EN_MII1; | ||
153 | if (gig_en) | ||
154 | gig_val = gig_en_mask; | ||
155 | regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, gig_en_mask, gig_val); | ||
156 | |||
157 | full_duplex_mask = (mii == ICSS_MII0) ? RGMII_CFG_FULL_DUPLEX_MII0 : | ||
158 | RGMII_CFG_FULL_DUPLEX_MII1; | ||
159 | if (full_duplex) | ||
160 | full_duplex_val = full_duplex_mask; | ||
161 | regmap_update_bits(miig_rt, RGMII_CFG_OFFSET, full_duplex_mask, | ||
162 | full_duplex_val); | ||
163 | } | ||
164 | |||
165 | static inline void icssg_update_mii_rt_cfg(struct regmap *mii_rt, int speed, | ||
166 | int mii) | ||
167 | { | ||
168 | u32 ipg_reg, val; | ||
169 | |||
170 | ipg_reg = (mii == ICSS_MII0) ? PRUSS_MII_RT_TX_IPG0 : | ||
171 | PRUSS_MII_RT_TX_IPG1; | ||
172 | switch (speed) { | ||
173 | case SPEED_1000: | ||
174 | val = MII_RT_TX_IPG_1G; | ||
175 | break; | ||
176 | case SPEED_100: | ||
177 | val = MII_RT_TX_IPG_100M; | ||
178 | break; | ||
179 | default: | ||
180 | /* Other links speeds not supported */ | ||
181 | pr_err("Unsupported link speed\n"); | ||
182 | return; | ||
183 | } | ||
184 | regmap_write(mii_rt, ipg_reg, val); | ||
185 | } | ||
186 | |||
107 | static int icssg_phy_init(struct udevice *dev) | 187 | static int icssg_phy_init(struct udevice *dev) |
108 | { | 188 | { |
109 | struct prueth *priv = dev_get_priv(dev); | 189 | struct prueth *priv = dev_get_priv(dev); |
@@ -160,6 +240,34 @@ static void icssg_config_set(struct prueth *prueth) | |||
160 | memcpy_toio(va, &prueth->config[0], sizeof(prueth->config[0])); | 240 | memcpy_toio(va, &prueth->config[0], sizeof(prueth->config[0])); |
161 | } | 241 | } |
162 | 242 | ||
243 | static int icssg_update_link(struct prueth *priv) | ||
244 | { | ||
245 | struct phy_device *phy = priv->phydev; | ||
246 | bool gig_en = false, full_duplex = false; | ||
247 | |||
248 | if (phy->link) { /* link up */ | ||
249 | if (phy->speed == 1000) | ||
250 | gig_en = true; | ||
251 | if (phy->duplex == 0x1) | ||
252 | full_duplex = true; | ||
253 | if (phy->speed == 100) | ||
254 | gig_en = false; | ||
255 | /* Set the RGMII cfg for gig en and full duplex */ | ||
256 | icssg_update_rgmii_cfg(priv->miig_rt, gig_en, full_duplex, | ||
257 | priv->slice); | ||
258 | /* update the Tx IPG based on 100M/1G speed */ | ||
259 | icssg_update_mii_rt_cfg(priv->mii_rt, phy->speed, priv->slice); | ||
260 | |||
261 | printf("link up on port %d, speed %d, %s duplex\n", | ||
262 | priv->port_id, phy->speed, | ||
263 | (phy->duplex == DUPLEX_FULL) ? "full" : "half"); | ||
264 | } else { | ||
265 | printf("link down on port %d\n", priv->port_id); | ||
266 | } | ||
267 | |||
268 | return phy->link; | ||
269 | } | ||
270 | |||
163 | static int prueth_start(struct udevice *dev) | 271 | static int prueth_start(struct udevice *dev) |
164 | { | 272 | { |
165 | struct prueth *priv = dev_get_priv(dev); | 273 | struct prueth *priv = dev_get_priv(dev); |
@@ -210,7 +318,16 @@ static int prueth_start(struct udevice *dev) | |||
210 | goto phy_fail; | 318 | goto phy_fail; |
211 | } | 319 | } |
212 | 320 | ||
321 | ret = icssg_update_link(priv); | ||
322 | if (!ret) { | ||
323 | ret = -ENODEV; | ||
324 | goto phy_shut; | ||
325 | } | ||
326 | |||
213 | return 0; | 327 | return 0; |
328 | |||
329 | phy_shut: | ||
330 | phy_shutdown(priv->phydev); | ||
214 | phy_fail: | 331 | phy_fail: |
215 | dma_disable(&priv->dma_rx); | 332 | dma_disable(&priv->dma_rx); |
216 | rx_fail: | 333 | rx_fail: |
@@ -430,6 +547,12 @@ static int prueth_probe(struct udevice *dev) | |||
430 | return -ENODEV; | 547 | return -ENODEV; |
431 | } | 548 | } |
432 | 549 | ||
550 | prueth->mii_rt = syscon_regmap_lookup_by_phandle(dev, "mii-rt"); | ||
551 | if (!prueth->mii_rt) { | ||
552 | dev_err(dev, "couldn't get mii-rt syscon regmap\n"); | ||
553 | return -ENODEV; | ||
554 | } | ||
555 | |||
433 | ret = clk_get_by_name(dev, "mdio_fck", &prueth->mdiofck); | 556 | ret = clk_get_by_name(dev, "mdio_fck", &prueth->mdiofck); |
434 | if (ret) { | 557 | if (ret) { |
435 | dev_err(dev, "failed to get clock %d\n", ret); | 558 | dev_err(dev, "failed to get clock %d\n", ret); |