blob: 059a65d46610b3f121d4b33e8f0d7250c4490247 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marek Vasut0a3d0e12016-05-24 23:29:09 +02002/*
3 * Atheros AR71xx / AR9xxx GMAC driver
4 *
5 * Copyright (C) 2016 Marek Vasut <marex@denx.de>
Rosy Song51ef2e72019-03-16 09:24:50 +08006 * Copyright (C) 2019 Rosy Song <rosysong@rosinson.com>
Marek Vasut0a3d0e12016-05-24 23:29:09 +02007 */
8
Simon Glass85d65312019-12-28 10:44:58 -07009#include <clock_legacy.h>
Simon Glass63334482019-11-14 12:57:39 -070010#include <cpu_func.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020011#include <dm.h>
12#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060013#include <log.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020014#include <miiphy.h>
15#include <malloc.h>
Simon Glass274e0b02020-05-10 11:39:56 -060016#include <net.h>
17#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060018#include <asm/global_data.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060019#include <linux/bitops.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020020#include <linux/compiler.h>
Simon Glassdbd79542020-05-10 11:40:11 -060021#include <linux/delay.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020022#include <linux/err.h>
23#include <linux/mii.h>
24#include <wait_bit.h>
25#include <asm/io.h>
26
27#include <mach/ath79.h>
28
29DECLARE_GLOBAL_DATA_PTR;
30
31enum ag7xxx_model {
32 AG7XXX_MODEL_AG933X,
33 AG7XXX_MODEL_AG934X,
Rosy Song51ef2e72019-03-16 09:24:50 +080034 AG7XXX_MODEL_AG953X,
35 AG7XXX_MODEL_AG956X
Marek Vasut0a3d0e12016-05-24 23:29:09 +020036};
37
Joe Hershbergera1a837d2017-06-26 14:40:08 -050038/* MAC Configuration 1 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020039#define AG7XXX_ETH_CFG1 0x00
40#define AG7XXX_ETH_CFG1_SOFT_RST BIT(31)
41#define AG7XXX_ETH_CFG1_RX_RST BIT(19)
42#define AG7XXX_ETH_CFG1_TX_RST BIT(18)
43#define AG7XXX_ETH_CFG1_LOOPBACK BIT(8)
44#define AG7XXX_ETH_CFG1_RX_EN BIT(2)
45#define AG7XXX_ETH_CFG1_TX_EN BIT(0)
46
Joe Hershbergera1a837d2017-06-26 14:40:08 -050047/* MAC Configuration 2 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020048#define AG7XXX_ETH_CFG2 0x04
49#define AG7XXX_ETH_CFG2_IF_1000 BIT(9)
50#define AG7XXX_ETH_CFG2_IF_10_100 BIT(8)
51#define AG7XXX_ETH_CFG2_IF_SPEED_MASK (3 << 8)
52#define AG7XXX_ETH_CFG2_HUGE_FRAME_EN BIT(5)
53#define AG7XXX_ETH_CFG2_LEN_CHECK BIT(4)
54#define AG7XXX_ETH_CFG2_PAD_CRC_EN BIT(2)
55#define AG7XXX_ETH_CFG2_FDX BIT(0)
56
Joe Hershbergera1a837d2017-06-26 14:40:08 -050057/* MII Configuration */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020058#define AG7XXX_ETH_MII_MGMT_CFG 0x20
59#define AG7XXX_ETH_MII_MGMT_CFG_RESET BIT(31)
60
Joe Hershbergera1a837d2017-06-26 14:40:08 -050061/* MII Command */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020062#define AG7XXX_ETH_MII_MGMT_CMD 0x24
63#define AG7XXX_ETH_MII_MGMT_CMD_READ 0x1
64
Joe Hershbergera1a837d2017-06-26 14:40:08 -050065/* MII Address */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020066#define AG7XXX_ETH_MII_MGMT_ADDRESS 0x28
67#define AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT 8
68
Joe Hershbergera1a837d2017-06-26 14:40:08 -050069/* MII Control */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020070#define AG7XXX_ETH_MII_MGMT_CTRL 0x2c
71
Joe Hershbergera1a837d2017-06-26 14:40:08 -050072/* MII Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020073#define AG7XXX_ETH_MII_MGMT_STATUS 0x30
74
Joe Hershbergera1a837d2017-06-26 14:40:08 -050075/* MII Indicators */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020076#define AG7XXX_ETH_MII_MGMT_IND 0x34
77#define AG7XXX_ETH_MII_MGMT_IND_INVALID BIT(2)
78#define AG7XXX_ETH_MII_MGMT_IND_BUSY BIT(0)
79
Joe Hershbergera1a837d2017-06-26 14:40:08 -050080/* STA Address 1 & 2 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020081#define AG7XXX_ETH_ADDR1 0x40
82#define AG7XXX_ETH_ADDR2 0x44
83
Joe Hershbergera1a837d2017-06-26 14:40:08 -050084/* ETH Configuration 0 - 5 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020085#define AG7XXX_ETH_FIFO_CFG_0 0x48
86#define AG7XXX_ETH_FIFO_CFG_1 0x4c
87#define AG7XXX_ETH_FIFO_CFG_2 0x50
88#define AG7XXX_ETH_FIFO_CFG_3 0x54
89#define AG7XXX_ETH_FIFO_CFG_4 0x58
90#define AG7XXX_ETH_FIFO_CFG_5 0x5c
91
Joe Hershbergera1a837d2017-06-26 14:40:08 -050092/* DMA Transfer Control for Queue 0 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020093#define AG7XXX_ETH_DMA_TX_CTRL 0x180
94#define AG7XXX_ETH_DMA_TX_CTRL_TXE BIT(0)
95
Joe Hershbergera1a837d2017-06-26 14:40:08 -050096/* Descriptor Address for Queue 0 Tx */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020097#define AG7XXX_ETH_DMA_TX_DESC 0x184
98
Joe Hershbergera1a837d2017-06-26 14:40:08 -050099/* DMA Tx Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200100#define AG7XXX_ETH_DMA_TX_STATUS 0x188
101
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500102/* Rx Control */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200103#define AG7XXX_ETH_DMA_RX_CTRL 0x18c
104#define AG7XXX_ETH_DMA_RX_CTRL_RXE BIT(0)
105
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500106/* Pointer to Rx Descriptor */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200107#define AG7XXX_ETH_DMA_RX_DESC 0x190
108
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500109/* Rx Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200110#define AG7XXX_ETH_DMA_RX_STATUS 0x194
111
Rosy Song361c69e2019-02-05 17:50:44 +0800112/* Custom register at 0x1805002C */
113#define AG7XXX_ETH_XMII 0x2C
114#define AG7XXX_ETH_XMII_TX_INVERT BIT(31)
115#define AG7XXX_ETH_XMII_RX_DELAY_LSB 28
116#define AG7XXX_ETH_XMII_RX_DELAY_MASK 0x30000000
117#define AG7XXX_ETH_XMII_RX_DELAY_SET(x) \
118 (((x) << AG7XXX_ETH_XMII_RX_DELAY_LSB) & AG7XXX_ETH_XMII_RX_DELAY_MASK)
119#define AG7XXX_ETH_XMII_TX_DELAY_LSB 26
120#define AG7XXX_ETH_XMII_TX_DELAY_MASK 0x0c000000
121#define AG7XXX_ETH_XMII_TX_DELAY_SET(x) \
122 (((x) << AG7XXX_ETH_XMII_TX_DELAY_LSB) & AG7XXX_ETH_XMII_TX_DELAY_MASK)
123#define AG7XXX_ETH_XMII_GIGE BIT(25)
124
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200125/* Custom register at 0x18070000 */
126#define AG7XXX_GMAC_ETH_CFG 0x00
Rosy Song361c69e2019-02-05 17:50:44 +0800127#define AG7XXX_ETH_CFG_RXDV_DELAY_LSB 16
128#define AG7XXX_ETH_CFG_RXDV_DELAY_MASK 0x00030000
129#define AG7XXX_ETH_CFG_RXDV_DELAY_SET(x) \
130 (((x) << AG7XXX_ETH_CFG_RXDV_DELAY_LSB) & AG7XXX_ETH_CFG_RXDV_DELAY_MASK)
131#define AG7XXX_ETH_CFG_RXD_DELAY_LSB 14
132#define AG7XXX_ETH_CFG_RXD_DELAY_MASK 0x0000c000
133#define AG7XXX_ETH_CFG_RXD_DELAY_SET(x) \
134 (((x) << AG7XXX_ETH_CFG_RXD_DELAY_LSB) & AG7XXX_ETH_CFG_RXD_DELAY_MASK)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200135#define AG7XXX_ETH_CFG_SW_PHY_ADDR_SWAP BIT(8)
136#define AG7XXX_ETH_CFG_SW_PHY_SWAP BIT(7)
137#define AG7XXX_ETH_CFG_SW_ONLY_MODE BIT(6)
138#define AG7XXX_ETH_CFG_GE0_ERR_EN BIT(5)
139#define AG7XXX_ETH_CFG_MII_GE0_SLAVE BIT(4)
140#define AG7XXX_ETH_CFG_MII_GE0_MASTER BIT(3)
141#define AG7XXX_ETH_CFG_GMII_GE0 BIT(2)
142#define AG7XXX_ETH_CFG_MII_GE0 BIT(1)
143#define AG7XXX_ETH_CFG_RGMII_GE0 BIT(0)
144
Tom Rini364d0022023-01-10 11:19:45 -0500145#define CFG_TX_DESCR_NUM 8
146#define CFG_RX_DESCR_NUM 8
147#define CFG_ETH_BUFSIZE 2048
148#define TX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_TX_DESCR_NUM)
149#define RX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_RX_DESCR_NUM)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200150
151/* DMA descriptor. */
152struct ag7xxx_dma_desc {
153 u32 data_addr;
154#define AG7XXX_DMADESC_IS_EMPTY BIT(31)
155#define AG7XXX_DMADESC_FTPP_OVERRIDE_OFFSET 16
156#define AG7XXX_DMADESC_PKT_SIZE_OFFSET 0
157#define AG7XXX_DMADESC_PKT_SIZE_MASK 0xfff
158 u32 config;
159 u32 next_desc;
160 u32 _pad[5];
161};
162
163struct ar7xxx_eth_priv {
Tom Rini364d0022023-01-10 11:19:45 -0500164 struct ag7xxx_dma_desc tx_mac_descrtable[CFG_TX_DESCR_NUM];
165 struct ag7xxx_dma_desc rx_mac_descrtable[CFG_RX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200166 char txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
167 char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
168
169 void __iomem *regs;
170 void __iomem *phyregs;
171
172 struct eth_device *dev;
173 struct phy_device *phydev;
174 struct mii_dev *bus;
175
176 u32 interface;
177 u32 tx_currdescnum;
178 u32 rx_currdescnum;
179 enum ag7xxx_model model;
180};
181
182/*
183 * Switch and MDIO access
184 */
185static int ag7xxx_switch_read(struct mii_dev *bus, int addr, int reg, u16 *val)
186{
187 struct ar7xxx_eth_priv *priv = bus->priv;
188 void __iomem *regs = priv->phyregs;
189 int ret;
190
191 writel(0x0, regs + AG7XXX_ETH_MII_MGMT_CMD);
192 writel((addr << AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT) | reg,
193 regs + AG7XXX_ETH_MII_MGMT_ADDRESS);
194 writel(AG7XXX_ETH_MII_MGMT_CMD_READ,
195 regs + AG7XXX_ETH_MII_MGMT_CMD);
196
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100197 ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
198 AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200199 if (ret)
200 return ret;
201
202 *val = readl(regs + AG7XXX_ETH_MII_MGMT_STATUS) & 0xffff;
203 writel(0x0, regs + AG7XXX_ETH_MII_MGMT_CMD);
204
205 return 0;
206}
207
208static int ag7xxx_switch_write(struct mii_dev *bus, int addr, int reg, u16 val)
209{
210 struct ar7xxx_eth_priv *priv = bus->priv;
211 void __iomem *regs = priv->phyregs;
212 int ret;
213
214 writel((addr << AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT) | reg,
215 regs + AG7XXX_ETH_MII_MGMT_ADDRESS);
216 writel(val, regs + AG7XXX_ETH_MII_MGMT_CTRL);
217
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100218 ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
219 AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200220
221 return ret;
222}
223
224static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
225{
226 struct ar7xxx_eth_priv *priv = bus->priv;
227 u32 phy_addr;
228 u32 reg_addr;
229 u32 phy_temp;
230 u32 reg_temp;
Rosy Song51ef2e72019-03-16 09:24:50 +0800231 u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200232 u16 rv = 0;
233 int ret;
234
Rosy Song361c69e2019-02-05 17:50:44 +0800235 if (priv->model == AG7XXX_MODEL_AG933X ||
236 priv->model == AG7XXX_MODEL_AG953X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200237 phy_addr = 0x1f;
238 reg_addr = 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800239 } else if (priv->model == AG7XXX_MODEL_AG934X ||
240 priv->model == AG7XXX_MODEL_AG956X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200241 phy_addr = 0x18;
242 reg_addr = 0x00;
243 } else
244 return -EINVAL;
245
Rosy Song51ef2e72019-03-16 09:24:50 +0800246 if (priv->model == AG7XXX_MODEL_AG956X)
247 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
248 else
249 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200250 if (ret)
251 return ret;
252
253 phy_temp = ((reg >> 6) & 0x7) | 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800254 if (priv->model == AG7XXX_MODEL_AG956X)
255 reg_temp = reg_temp_w & 0x1f;
256 else
257 reg_temp = (reg >> 1) & 0x1e;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200258 *val = 0;
259
260 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 0, &rv);
261 if (ret < 0)
262 return ret;
263 *val |= rv;
264
Rosy Song51ef2e72019-03-16 09:24:50 +0800265 if (priv->model == AG7XXX_MODEL_AG956X) {
266 phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
267 reg_temp = (reg_temp_w + 1) & 0x1f;
268 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp, &rv);
269 } else {
270 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
271 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200272 if (ret < 0)
273 return ret;
274 *val |= (rv << 16);
275
276 return 0;
277}
278
279static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
280{
281 struct ar7xxx_eth_priv *priv = bus->priv;
282 u32 phy_addr;
283 u32 reg_addr;
284 u32 phy_temp;
285 u32 reg_temp;
Rosy Song51ef2e72019-03-16 09:24:50 +0800286 u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200287 int ret;
288
Rosy Song361c69e2019-02-05 17:50:44 +0800289 if (priv->model == AG7XXX_MODEL_AG933X ||
290 priv->model == AG7XXX_MODEL_AG953X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200291 phy_addr = 0x1f;
292 reg_addr = 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800293 } else if (priv->model == AG7XXX_MODEL_AG934X ||
294 priv->model == AG7XXX_MODEL_AG956X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200295 phy_addr = 0x18;
296 reg_addr = 0x00;
297 } else
298 return -EINVAL;
299
Rosy Song51ef2e72019-03-16 09:24:50 +0800300 if (priv->model == AG7XXX_MODEL_AG956X)
301 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
302 else
303 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200304 if (ret)
305 return ret;
306
Rosy Song51ef2e72019-03-16 09:24:50 +0800307 if (priv->model == AG7XXX_MODEL_AG956X) {
308 reg_temp = (reg_temp_w + 1) & 0x1f;
309 phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
310 } else {
311 phy_temp = ((reg >> 6) & 0x7) | 0x10;
312 reg_temp = (reg >> 1) & 0x1e;
313 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200314
315 /*
316 * The switch on AR933x has some special register behavior, which
317 * expects particular write order of their nibbles:
318 * 0x40 ..... MSB first, LSB second
319 * 0x50 ..... MSB first, LSB second
320 * 0x98 ..... LSB first, MSB second
321 * others ... don't care
322 */
323 if ((priv->model == AG7XXX_MODEL_AG933X) && (reg == 0x98)) {
324 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
325 if (ret < 0)
326 return ret;
327
328 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
329 if (ret < 0)
330 return ret;
331 } else {
Rosy Song51ef2e72019-03-16 09:24:50 +0800332 if (priv->model == AG7XXX_MODEL_AG956X)
333 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp, val >> 16);
334 else
335 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200336 if (ret < 0)
337 return ret;
338
Rosy Song51ef2e72019-03-16 09:24:50 +0800339 if (priv->model == AG7XXX_MODEL_AG956X) {
340 phy_temp = ((reg_temp_w >> 5) & 0x7) | 0x10;
341 reg_temp = reg_temp_w & 0x1f;
342 }
343
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200344 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
345 if (ret < 0)
346 return ret;
347 }
348
349 return 0;
350}
351
Joe Hershberger5a41d662017-06-26 14:40:09 -0500352static int ag7xxx_mdio_rw(struct mii_dev *bus, int addr, int reg, u32 val)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200353{
354 u32 data;
Joe Hershberger5a41d662017-06-26 14:40:09 -0500355 unsigned long start;
356 int ret;
357 /* No idea if this is long enough or too long */
358 int timeout_ms = 1000;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200359
360 /* Dummy read followed by PHY read/write command. */
Joe Hershberger5a41d662017-06-26 14:40:09 -0500361 ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
362 if (ret < 0)
363 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200364 data = val | (reg << 16) | (addr << 21) | BIT(30) | BIT(31);
Joe Hershberger5a41d662017-06-26 14:40:09 -0500365 ret = ag7xxx_switch_reg_write(bus, 0x98, data);
366 if (ret < 0)
367 return ret;
368
369 start = get_timer(0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200370
371 /* Wait for operation to finish */
372 do {
Joe Hershberger5a41d662017-06-26 14:40:09 -0500373 ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
374 if (ret < 0)
375 return ret;
376
377 if (get_timer(start) > timeout_ms)
378 return -ETIMEDOUT;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200379 } while (data & BIT(31));
380
381 return data & 0xffff;
382}
383
384static int ag7xxx_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
385{
386 return ag7xxx_mdio_rw(bus, addr, reg, BIT(27));
387}
388
389static int ag7xxx_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
390 u16 val)
391{
Joe Hershberger5a41d662017-06-26 14:40:09 -0500392 int ret;
393
394 ret = ag7xxx_mdio_rw(bus, addr, reg, val);
395 if (ret < 0)
396 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200397 return 0;
398}
399
400/*
401 * DMA ring handlers
402 */
403static void ag7xxx_dma_clean_tx(struct udevice *dev)
404{
405 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
406 struct ag7xxx_dma_desc *curr, *next;
407 u32 start, end;
408 int i;
409
Tom Rini364d0022023-01-10 11:19:45 -0500410 for (i = 0; i < CFG_TX_DESCR_NUM; i++) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200411 curr = &priv->tx_mac_descrtable[i];
Tom Rini364d0022023-01-10 11:19:45 -0500412 next = &priv->tx_mac_descrtable[(i + 1) % CFG_TX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200413
Tom Rini364d0022023-01-10 11:19:45 -0500414 curr->data_addr = virt_to_phys(&priv->txbuffs[i * CFG_ETH_BUFSIZE]);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200415 curr->config = AG7XXX_DMADESC_IS_EMPTY;
416 curr->next_desc = virt_to_phys(next);
417 }
418
419 priv->tx_currdescnum = 0;
420
421 /* Cache: Flush descriptors, don't care about buffers. */
422 start = (u32)(&priv->tx_mac_descrtable[0]);
423 end = start + sizeof(priv->tx_mac_descrtable);
424 flush_dcache_range(start, end);
425}
426
427static void ag7xxx_dma_clean_rx(struct udevice *dev)
428{
429 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
430 struct ag7xxx_dma_desc *curr, *next;
431 u32 start, end;
432 int i;
433
Tom Rini364d0022023-01-10 11:19:45 -0500434 for (i = 0; i < CFG_RX_DESCR_NUM; i++) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200435 curr = &priv->rx_mac_descrtable[i];
Tom Rini364d0022023-01-10 11:19:45 -0500436 next = &priv->rx_mac_descrtable[(i + 1) % CFG_RX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200437
Tom Rini364d0022023-01-10 11:19:45 -0500438 curr->data_addr = virt_to_phys(&priv->rxbuffs[i * CFG_ETH_BUFSIZE]);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200439 curr->config = AG7XXX_DMADESC_IS_EMPTY;
440 curr->next_desc = virt_to_phys(next);
441 }
442
443 priv->rx_currdescnum = 0;
444
445 /* Cache: Flush+Invalidate descriptors, Invalidate buffers. */
446 start = (u32)(&priv->rx_mac_descrtable[0]);
447 end = start + sizeof(priv->rx_mac_descrtable);
448 flush_dcache_range(start, end);
449 invalidate_dcache_range(start, end);
450
451 start = (u32)&priv->rxbuffs;
452 end = start + sizeof(priv->rxbuffs);
453 invalidate_dcache_range(start, end);
454}
455
456/*
457 * Ethernet I/O
458 */
459static int ag7xxx_eth_send(struct udevice *dev, void *packet, int length)
460{
461 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
462 struct ag7xxx_dma_desc *curr;
463 u32 start, end;
464
465 curr = &priv->tx_mac_descrtable[priv->tx_currdescnum];
466
467 /* Cache: Invalidate descriptor. */
468 start = (u32)curr;
469 end = start + sizeof(*curr);
470 invalidate_dcache_range(start, end);
471
472 if (!(curr->config & AG7XXX_DMADESC_IS_EMPTY)) {
473 printf("ag7xxx: Out of TX DMA descriptors!\n");
474 return -EPERM;
475 }
476
477 /* Copy the packet into the data buffer. */
478 memcpy(phys_to_virt(curr->data_addr), packet, length);
479 curr->config = length & AG7XXX_DMADESC_PKT_SIZE_MASK;
480
481 /* Cache: Flush descriptor, Flush buffer. */
482 start = (u32)curr;
483 end = start + sizeof(*curr);
484 flush_dcache_range(start, end);
485 start = (u32)phys_to_virt(curr->data_addr);
486 end = start + length;
487 flush_dcache_range(start, end);
488
489 /* Load the DMA descriptor and start TX DMA. */
490 writel(AG7XXX_ETH_DMA_TX_CTRL_TXE,
491 priv->regs + AG7XXX_ETH_DMA_TX_CTRL);
492
493 /* Switch to next TX descriptor. */
Tom Rini364d0022023-01-10 11:19:45 -0500494 priv->tx_currdescnum = (priv->tx_currdescnum + 1) % CFG_TX_DESCR_NUM;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200495
496 return 0;
497}
498
499static int ag7xxx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
500{
501 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
502 struct ag7xxx_dma_desc *curr;
503 u32 start, end, length;
504
505 curr = &priv->rx_mac_descrtable[priv->rx_currdescnum];
506
507 /* Cache: Invalidate descriptor. */
508 start = (u32)curr;
509 end = start + sizeof(*curr);
510 invalidate_dcache_range(start, end);
511
512 /* No packets received. */
513 if (curr->config & AG7XXX_DMADESC_IS_EMPTY)
514 return -EAGAIN;
515
516 length = curr->config & AG7XXX_DMADESC_PKT_SIZE_MASK;
517
518 /* Cache: Invalidate buffer. */
519 start = (u32)phys_to_virt(curr->data_addr);
520 end = start + length;
521 invalidate_dcache_range(start, end);
522
523 /* Receive one packet and return length. */
524 *packetp = phys_to_virt(curr->data_addr);
525 return length;
526}
527
528static int ag7xxx_eth_free_pkt(struct udevice *dev, uchar *packet,
529 int length)
530{
531 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
532 struct ag7xxx_dma_desc *curr;
533 u32 start, end;
534
535 curr = &priv->rx_mac_descrtable[priv->rx_currdescnum];
536
537 curr->config = AG7XXX_DMADESC_IS_EMPTY;
538
539 /* Cache: Flush descriptor. */
540 start = (u32)curr;
541 end = start + sizeof(*curr);
542 flush_dcache_range(start, end);
543
544 /* Switch to next RX descriptor. */
Tom Rini364d0022023-01-10 11:19:45 -0500545 priv->rx_currdescnum = (priv->rx_currdescnum + 1) % CFG_RX_DESCR_NUM;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200546
547 return 0;
548}
549
550static int ag7xxx_eth_start(struct udevice *dev)
551{
552 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
553
554 /* FIXME: Check if link up */
555
556 /* Clear the DMA rings. */
557 ag7xxx_dma_clean_tx(dev);
558 ag7xxx_dma_clean_rx(dev);
559
560 /* Load DMA descriptors and start the RX DMA. */
561 writel(virt_to_phys(&priv->tx_mac_descrtable[priv->tx_currdescnum]),
562 priv->regs + AG7XXX_ETH_DMA_TX_DESC);
563 writel(virt_to_phys(&priv->rx_mac_descrtable[priv->rx_currdescnum]),
564 priv->regs + AG7XXX_ETH_DMA_RX_DESC);
565 writel(AG7XXX_ETH_DMA_RX_CTRL_RXE,
566 priv->regs + AG7XXX_ETH_DMA_RX_CTRL);
567
568 return 0;
569}
570
571static void ag7xxx_eth_stop(struct udevice *dev)
572{
573 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
574
575 /* Stop the TX DMA. */
576 writel(0, priv->regs + AG7XXX_ETH_DMA_TX_CTRL);
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100577 wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0,
578 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200579
580 /* Stop the RX DMA. */
581 writel(0, priv->regs + AG7XXX_ETH_DMA_RX_CTRL);
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100582 wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0,
583 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200584}
585
586/*
587 * Hardware setup
588 */
589static int ag7xxx_eth_write_hwaddr(struct udevice *dev)
590{
Simon Glassfa20e932020-12-03 16:55:20 -0700591 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200592 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
593 unsigned char *mac = pdata->enetaddr;
594 u32 macid_lo, macid_hi;
595
596 macid_hi = mac[3] | (mac[2] << 8) | (mac[1] << 16) | (mac[0] << 24);
597 macid_lo = (mac[5] << 16) | (mac[4] << 24);
598
599 writel(macid_lo, priv->regs + AG7XXX_ETH_ADDR1);
600 writel(macid_hi, priv->regs + AG7XXX_ETH_ADDR2);
601
602 return 0;
603}
604
605static void ag7xxx_hw_setup(struct udevice *dev)
606{
607 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
608 u32 speed;
609
610 setbits_be32(priv->regs + AG7XXX_ETH_CFG1,
611 AG7XXX_ETH_CFG1_RX_RST | AG7XXX_ETH_CFG1_TX_RST |
612 AG7XXX_ETH_CFG1_SOFT_RST);
613
614 mdelay(10);
615
616 writel(AG7XXX_ETH_CFG1_RX_EN | AG7XXX_ETH_CFG1_TX_EN,
617 priv->regs + AG7XXX_ETH_CFG1);
618
619 if (priv->interface == PHY_INTERFACE_MODE_RMII)
620 speed = AG7XXX_ETH_CFG2_IF_10_100;
621 else
622 speed = AG7XXX_ETH_CFG2_IF_1000;
623
624 clrsetbits_be32(priv->regs + AG7XXX_ETH_CFG2,
625 AG7XXX_ETH_CFG2_IF_SPEED_MASK,
626 speed | AG7XXX_ETH_CFG2_PAD_CRC_EN |
627 AG7XXX_ETH_CFG2_LEN_CHECK);
628
629 writel(0xfff0000, priv->regs + AG7XXX_ETH_FIFO_CFG_1);
630 writel(0x1fff, priv->regs + AG7XXX_ETH_FIFO_CFG_2);
631
632 writel(0x1f00, priv->regs + AG7XXX_ETH_FIFO_CFG_0);
633 setbits_be32(priv->regs + AG7XXX_ETH_FIFO_CFG_4, 0x3ffff);
634 writel(0x10ffff, priv->regs + AG7XXX_ETH_FIFO_CFG_1);
635 writel(0xaaa0555, priv->regs + AG7XXX_ETH_FIFO_CFG_2);
636 writel(0x7eccf, priv->regs + AG7XXX_ETH_FIFO_CFG_5);
637 writel(0x1f00140, priv->regs + AG7XXX_ETH_FIFO_CFG_3);
638}
639
640static int ag7xxx_mii_get_div(void)
641{
642 ulong freq = get_bus_freq(0);
643
644 switch (freq / 1000000) {
645 case 150: return 0x7;
646 case 175: return 0x5;
647 case 200: return 0x4;
648 case 210: return 0x9;
649 case 220: return 0x9;
650 default: return 0x7;
651 }
652}
653
654static int ag7xxx_mii_setup(struct udevice *dev)
655{
656 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
657 int i, ret, div = ag7xxx_mii_get_div();
658 u32 reg;
659
660 if (priv->model == AG7XXX_MODEL_AG933X) {
661 /* Unit 0 is PHY-less on AR9331, see datasheet Figure 2-3 */
662 if (priv->interface == PHY_INTERFACE_MODE_RMII)
663 return 0;
664 }
665
Rosy Song361c69e2019-02-05 17:50:44 +0800666 if (priv->model == AG7XXX_MODEL_AG934X)
667 reg = 0x4;
668 else if (priv->model == AG7XXX_MODEL_AG953X)
669 reg = 0x2;
Rosy Song51ef2e72019-03-16 09:24:50 +0800670 else if (priv->model == AG7XXX_MODEL_AG956X)
671 reg = 0x7;
Rosy Song361c69e2019-02-05 17:50:44 +0800672
673 if (priv->model == AG7XXX_MODEL_AG934X ||
Rosy Song51ef2e72019-03-16 09:24:50 +0800674 priv->model == AG7XXX_MODEL_AG953X ||
675 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800676 writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | reg,
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200677 priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
Rosy Song361c69e2019-02-05 17:50:44 +0800678 writel(reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200679 return 0;
680 }
681
682 for (i = 0; i < 10; i++) {
683 writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | div,
684 priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
685 writel(div, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
686
687 /* Check the switch */
688 ret = ag7xxx_switch_reg_read(priv->bus, 0x10c, &reg);
689 if (ret)
690 continue;
691
692 if (reg != 0x18007fff)
693 continue;
694
695 return 0;
696 }
697
698 return -EINVAL;
699}
700
701static int ag933x_phy_setup_wan(struct udevice *dev)
702{
703 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
704
705 /* Configure switch port 4 (GMAC0) */
706 return ag7xxx_mdio_write(priv->bus, 4, 0, MII_BMCR, 0x9000);
707}
708
709static int ag933x_phy_setup_lan(struct udevice *dev)
710{
711 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
712 int i, ret;
713 u32 reg;
714
715 /* Reset the switch */
716 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
717 if (ret)
718 return ret;
719 reg |= BIT(31);
720 ret = ag7xxx_switch_reg_write(priv->bus, 0, reg);
721 if (ret)
722 return ret;
723
724 do {
725 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
726 if (ret)
727 return ret;
728 } while (reg & BIT(31));
729
730 /* Configure switch ports 0...3 (GMAC1) */
731 for (i = 0; i < 4; i++) {
732 ret = ag7xxx_mdio_write(priv->bus, 0x4, 0, MII_BMCR, 0x9000);
733 if (ret)
734 return ret;
735 }
736
737 /* Enable CPU port */
738 ret = ag7xxx_switch_reg_write(priv->bus, 0x78, BIT(8));
739 if (ret)
740 return ret;
741
742 for (i = 0; i < 4; i++) {
743 ret = ag7xxx_switch_reg_write(priv->bus, i * 0x100, BIT(9));
744 if (ret)
745 return ret;
746 }
747
748 /* QM Control */
749 ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
750 if (ret)
751 return ret;
752
753 /* Disable Atheros header */
754 ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
755 if (ret)
756 return ret;
757
758 /* Tag priority mapping */
759 ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
760 if (ret)
761 return ret;
762
763 /* Enable ARP packets to the CPU */
764 ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
765 if (ret)
766 return ret;
767 reg |= 0x100000;
768 ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg);
769 if (ret)
770 return ret;
771
Rosy Song361c69e2019-02-05 17:50:44 +0800772 return 0;
773}
774
775static int ag953x_phy_setup_wan(struct udevice *dev)
776{
777 int ret;
778 u32 reg = 0;
779 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
780
781 /* Set wan port connect to GE0 */
782 ret = ag7xxx_switch_reg_read(priv->bus, 0x8, &reg);
783 if (ret)
784 return ret;
785
786 ret = ag7xxx_switch_reg_write(priv->bus, 0x8, reg | BIT(28));
787 if (ret)
788 return ret;
789
790 /* Configure switch port 4 (GMAC0) */
791 ret = ag7xxx_switch_write(priv->bus, 4, MII_BMCR, 0x9000);
792 if (ret)
793 return ret;
794
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200795 return 0;
796}
797
Rosy Song361c69e2019-02-05 17:50:44 +0800798static int ag953x_phy_setup_lan(struct udevice *dev)
799{
800 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
801 int i, ret;
802 u32 reg = 0;
803
804 /* Reset the switch */
805 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
806 if (ret)
807 return ret;
808
809 ret = ag7xxx_switch_reg_write(priv->bus, 0, reg | BIT(31));
810 if (ret)
811 return ret;
812
813 do {
814 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
815 if (ret)
816 return ret;
817 } while (reg & BIT(31));
818
819 ret = ag7xxx_switch_reg_write(priv->bus, 0x100, 0x4e);
820 if (ret)
821 return ret;
822
823 /* Set GMII mode */
824 ret = ag7xxx_switch_reg_read(priv->bus, 0x4, &reg);
825 if (ret)
826 return ret;
827
828 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, reg | BIT(6));
829 if (ret)
830 return ret;
831
832 /* Configure switch ports 0...4 (GMAC1) */
833 for (i = 0; i < 5; i++) {
834 ret = ag7xxx_switch_write(priv->bus, i, MII_BMCR, 0x9000);
835 if (ret)
836 return ret;
837 }
838
839 for (i = 0; i < 5; i++) {
840 ret = ag7xxx_switch_reg_write(priv->bus, (i + 2) * 0x100, BIT(9));
841 if (ret)
842 return ret;
843 }
844
845 /* QM Control */
846 ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
847 if (ret)
848 return ret;
849
850 /* Disable Atheros header */
851 ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
852 if (ret)
853 return ret;
854
855 /* Tag priority mapping */
856 ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
857 if (ret)
858 return ret;
859
860 /* Enable ARP packets to the CPU */
861 ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
862 if (ret)
863 return ret;
864
865 ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg | 0x100000);
866 if (ret)
867 return ret;
868
869 /* Enable broadcast packets to the CPU */
870 ret = ag7xxx_switch_reg_read(priv->bus, 0x2c, &reg);
871 if (ret)
872 return ret;
873
874 ret = ag7xxx_switch_reg_write(priv->bus, 0x2c, reg | BIT(25) | BIT(26));
875 if (ret)
876 return ret;
877
878 return 0;
879}
880
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200881static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
882{
883 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
884 int ret;
885
Rosy Song51ef2e72019-03-16 09:24:50 +0800886 if (priv->model == AG7XXX_MODEL_AG953X ||
887 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800888 ret = ag7xxx_switch_write(priv->bus, port, MII_ADVERTISE,
889 ADVERTISE_ALL);
890 } else {
891 ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
892 ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
893 ADVERTISE_PAUSE_ASYM);
894 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200895 if (ret)
896 return ret;
897
898 if (priv->model == AG7XXX_MODEL_AG934X) {
899 ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_CTRL1000,
900 ADVERTISE_1000FULL);
901 if (ret)
902 return ret;
Rosy Song51ef2e72019-03-16 09:24:50 +0800903 } else if (priv->model == AG7XXX_MODEL_AG956X) {
904 ret = ag7xxx_switch_write(priv->bus, port, MII_CTRL1000,
905 ADVERTISE_1000FULL);
906 if (ret)
907 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200908 }
909
Rosy Song51ef2e72019-03-16 09:24:50 +0800910 if (priv->model == AG7XXX_MODEL_AG953X ||
911 priv->model == AG7XXX_MODEL_AG956X)
Rosy Song361c69e2019-02-05 17:50:44 +0800912 return ag7xxx_switch_write(priv->bus, port, MII_BMCR,
913 BMCR_ANENABLE | BMCR_RESET);
914
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200915 return ag7xxx_mdio_write(priv->bus, port, 0, MII_BMCR,
916 BMCR_ANENABLE | BMCR_RESET);
917}
918
919static int ag933x_phy_setup_reset_fin(struct udevice *dev, int port)
920{
921 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
922 int ret;
Rosy Song361c69e2019-02-05 17:50:44 +0800923 u16 reg;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200924
Rosy Song51ef2e72019-03-16 09:24:50 +0800925 if (priv->model == AG7XXX_MODEL_AG953X ||
926 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800927 do {
928 ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, &reg);
929 if (ret < 0)
930 return ret;
931 mdelay(10);
932 } while (reg & BMCR_RESET);
933 } else {
934 do {
935 ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
936 if (ret < 0)
937 return ret;
938 mdelay(10);
939 } while (ret & BMCR_RESET);
940 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200941
942 return 0;
943}
944
945static int ag933x_phy_setup_common(struct udevice *dev)
946{
947 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
948 int i, ret, phymax;
Rosy Song361c69e2019-02-05 17:50:44 +0800949 u16 reg;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200950
951 if (priv->model == AG7XXX_MODEL_AG933X)
952 phymax = 4;
Rosy Song361c69e2019-02-05 17:50:44 +0800953 else if (priv->model == AG7XXX_MODEL_AG934X ||
Rosy Song51ef2e72019-03-16 09:24:50 +0800954 priv->model == AG7XXX_MODEL_AG953X ||
955 priv->model == AG7XXX_MODEL_AG956X)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200956 phymax = 5;
957 else
958 return -EINVAL;
959
960 if (priv->interface == PHY_INTERFACE_MODE_RMII) {
961 ret = ag933x_phy_setup_reset_set(dev, phymax);
962 if (ret)
963 return ret;
964
965 ret = ag933x_phy_setup_reset_fin(dev, phymax);
966 if (ret)
967 return ret;
968
969 /* Read out link status */
Rosy Song361c69e2019-02-05 17:50:44 +0800970 if (priv->model == AG7XXX_MODEL_AG953X)
971 ret = ag7xxx_switch_read(priv->bus, phymax, MII_MIPSCR, &reg);
972 else
973 ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200974 if (ret < 0)
975 return ret;
976
977 return 0;
978 }
979
980 /* Switch ports */
981 for (i = 0; i < phymax; i++) {
982 ret = ag933x_phy_setup_reset_set(dev, i);
983 if (ret)
984 return ret;
985 }
986
987 for (i = 0; i < phymax; i++) {
988 ret = ag933x_phy_setup_reset_fin(dev, i);
989 if (ret)
990 return ret;
991 }
992
993 for (i = 0; i < phymax; i++) {
994 /* Read out link status */
Rosy Song51ef2e72019-03-16 09:24:50 +0800995 if (priv->model == AG7XXX_MODEL_AG953X ||
996 priv->model == AG7XXX_MODEL_AG956X)
Rosy Song361c69e2019-02-05 17:50:44 +0800997 ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, &reg);
998 else
999 ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001000 if (ret < 0)
1001 return ret;
1002 }
1003
1004 return 0;
1005}
1006
1007static int ag934x_phy_setup(struct udevice *dev)
1008{
1009 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1010 int i, ret;
1011 u32 reg;
1012
1013 ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
1014 if (ret)
1015 return ret;
1016 ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x40000000);
1017 if (ret)
1018 return ret;
1019 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, 0x07600000);
1020 if (ret)
1021 return ret;
1022 ret = ag7xxx_switch_reg_write(priv->bus, 0xc, 0x01000000);
1023 if (ret)
1024 return ret;
1025 ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
1026 if (ret)
1027 return ret;
1028
1029 /* AR8327/AR8328 v1.0 fixup */
1030 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
1031 if (ret)
1032 return ret;
1033 if ((reg & 0xffff) == 0x1201) {
1034 for (i = 0; i < 5; i++) {
1035 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1d, 0x0);
1036 if (ret)
1037 return ret;
1038 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1e, 0x02ea);
1039 if (ret)
1040 return ret;
1041 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1d, 0x3d);
1042 if (ret)
1043 return ret;
1044 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1e, 0x68a0);
1045 if (ret)
1046 return ret;
1047 }
1048 }
1049
1050 ret = ag7xxx_switch_reg_read(priv->bus, 0x66c, &reg);
1051 if (ret)
1052 return ret;
1053 reg &= ~0x70000;
1054 ret = ag7xxx_switch_reg_write(priv->bus, 0x66c, reg);
1055 if (ret)
1056 return ret;
1057
1058 return 0;
1059}
1060
Rosy Song51ef2e72019-03-16 09:24:50 +08001061static int ag956x_phy_setup(struct udevice *dev)
1062{
1063 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1064 int i, ret;
1065 u32 reg, ctrl;
1066
1067 ret = ag7xxx_switch_reg_read(priv->bus, 0x0, &reg);
1068 if (ret)
1069 return ret;
1070 if ((reg & 0xffff) >= 0x1301)
1071 ctrl = 0xc74164de;
1072 else
1073 ctrl = 0xc74164d0;
1074
1075 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, BIT(7));
1076 if (ret)
1077 return ret;
1078
1079 ret = ag7xxx_switch_reg_write(priv->bus, 0xe0, ctrl);
1080 if (ret)
1081 return ret;
1082
1083 ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
1084 if (ret)
1085 return ret;
1086
1087 /*
1088 * Values suggested by the switch team when s17 in sgmii
1089 * configuration. 0x10(S17_PWS_REG) = 0x602613a0
1090 */
1091 ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x602613a0);
1092 if (ret)
1093 return ret;
1094
1095 ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
1096 if (ret)
1097 return ret;
1098
1099 /* AR8337/AR8334 v1.0 fixup */
1100 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
1101 if (ret)
1102 return ret;
1103 if ((reg & 0xffff) == 0x1301) {
1104 for (i = 0; i < 5; i++) {
1105 /* Turn on Gigabit clock */
1106 ret = ag7xxx_switch_write(priv->bus, i, 0x1d, 0x3d);
1107 if (ret)
1108 return ret;
1109 ret = ag7xxx_switch_write(priv->bus, i, 0x1e, 0x6820);
1110 if (ret)
1111 return ret;
1112 }
1113 }
1114
1115 return 0;
1116}
1117
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001118static int ag7xxx_mac_probe(struct udevice *dev)
1119{
1120 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1121 int ret;
1122
1123 ag7xxx_hw_setup(dev);
1124 ret = ag7xxx_mii_setup(dev);
1125 if (ret)
1126 return ret;
1127
1128 ag7xxx_eth_write_hwaddr(dev);
1129
1130 if (priv->model == AG7XXX_MODEL_AG933X) {
1131 if (priv->interface == PHY_INTERFACE_MODE_RMII)
1132 ret = ag933x_phy_setup_wan(dev);
1133 else
1134 ret = ag933x_phy_setup_lan(dev);
Rosy Song361c69e2019-02-05 17:50:44 +08001135 } else if (priv->model == AG7XXX_MODEL_AG953X) {
1136 if (priv->interface == PHY_INTERFACE_MODE_RMII)
1137 ret = ag953x_phy_setup_wan(dev);
1138 else
1139 ret = ag953x_phy_setup_lan(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001140 } else if (priv->model == AG7XXX_MODEL_AG934X) {
1141 ret = ag934x_phy_setup(dev);
Rosy Song51ef2e72019-03-16 09:24:50 +08001142 } else if (priv->model == AG7XXX_MODEL_AG956X) {
1143 ret = ag956x_phy_setup(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001144 } else {
1145 return -EINVAL;
1146 }
1147
1148 if (ret)
1149 return ret;
1150
1151 return ag933x_phy_setup_common(dev);
1152}
1153
1154static int ag7xxx_mdio_probe(struct udevice *dev)
1155{
1156 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1157 struct mii_dev *bus = mdio_alloc();
1158
1159 if (!bus)
1160 return -ENOMEM;
1161
1162 bus->read = ag7xxx_mdio_read;
1163 bus->write = ag7xxx_mdio_write;
1164 snprintf(bus->name, sizeof(bus->name), dev->name);
1165
1166 bus->priv = (void *)priv;
1167
1168 return mdio_register(bus);
1169}
1170
1171static int ag7xxx_get_phy_iface_offset(struct udevice *dev)
1172{
1173 int offset;
1174
Simon Glassdd79d6e2017-01-17 16:52:55 -07001175 offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), "phy");
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001176 if (offset <= 0) {
1177 debug("%s: PHY OF node not found (ret=%i)\n", __func__, offset);
1178 return -EINVAL;
1179 }
1180
1181 offset = fdt_parent_offset(gd->fdt_blob, offset);
1182 if (offset <= 0) {
1183 debug("%s: PHY OF node parent MDIO bus not found (ret=%i)\n",
1184 __func__, offset);
1185 return -EINVAL;
1186 }
1187
1188 offset = fdt_parent_offset(gd->fdt_blob, offset);
1189 if (offset <= 0) {
1190 debug("%s: PHY MDIO OF node parent MAC not found (ret=%i)\n",
1191 __func__, offset);
1192 return -EINVAL;
1193 }
1194
1195 return offset;
1196}
1197
1198static int ag7xxx_eth_probe(struct udevice *dev)
1199{
Simon Glassfa20e932020-12-03 16:55:20 -07001200 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001201 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1202 void __iomem *iobase, *phyiobase;
1203 int ret, phyreg;
1204
1205 /* Decoding of convoluted PHY wiring on Atheros MIPS. */
1206 ret = ag7xxx_get_phy_iface_offset(dev);
1207 if (ret <= 0)
1208 return ret;
1209 phyreg = fdtdec_get_int(gd->fdt_blob, ret, "reg", -1);
1210
1211 iobase = map_physmem(pdata->iobase, 0x200, MAP_NOCACHE);
1212 phyiobase = map_physmem(phyreg, 0x200, MAP_NOCACHE);
1213
1214 debug("%s, iobase=%p, phyiobase=%p, priv=%p\n",
1215 __func__, iobase, phyiobase, priv);
1216 priv->regs = iobase;
1217 priv->phyregs = phyiobase;
1218 priv->interface = pdata->phy_interface;
1219 priv->model = dev_get_driver_data(dev);
1220
1221 ret = ag7xxx_mdio_probe(dev);
1222 if (ret)
1223 return ret;
1224
1225 priv->bus = miiphy_get_dev_by_name(dev->name);
1226
1227 ret = ag7xxx_mac_probe(dev);
1228 debug("%s, ret=%d\n", __func__, ret);
1229
1230 return ret;
1231}
1232
1233static int ag7xxx_eth_remove(struct udevice *dev)
1234{
1235 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1236
1237 free(priv->phydev);
1238 mdio_unregister(priv->bus);
1239 mdio_free(priv->bus);
1240
1241 return 0;
1242}
1243
1244static const struct eth_ops ag7xxx_eth_ops = {
1245 .start = ag7xxx_eth_start,
1246 .send = ag7xxx_eth_send,
1247 .recv = ag7xxx_eth_recv,
1248 .free_pkt = ag7xxx_eth_free_pkt,
1249 .stop = ag7xxx_eth_stop,
1250 .write_hwaddr = ag7xxx_eth_write_hwaddr,
1251};
1252
Simon Glassaad29ae2020-12-03 16:55:21 -07001253static int ag7xxx_eth_of_to_plat(struct udevice *dev)
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001254{
Simon Glassfa20e932020-12-03 16:55:20 -07001255 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001256 int ret;
1257
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +09001258 pdata->iobase = dev_read_addr(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001259 pdata->phy_interface = -1;
1260
1261 /* Decoding of convoluted PHY wiring on Atheros MIPS. */
1262 ret = ag7xxx_get_phy_iface_offset(dev);
1263 if (ret <= 0)
1264 return ret;
1265
Marek BehĂșnbc194772022-04-07 00:33:01 +02001266 pdata->phy_interface = dev_read_phy_mode(dev);
Marek BehĂșn48631e42022-04-07 00:33:03 +02001267 if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001268 return -EINVAL;
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001269
1270 return 0;
1271}
1272
1273static const struct udevice_id ag7xxx_eth_ids[] = {
1274 { .compatible = "qca,ag933x-mac", .data = AG7XXX_MODEL_AG933X },
1275 { .compatible = "qca,ag934x-mac", .data = AG7XXX_MODEL_AG934X },
Rosy Song361c69e2019-02-05 17:50:44 +08001276 { .compatible = "qca,ag953x-mac", .data = AG7XXX_MODEL_AG953X },
Rosy Song51ef2e72019-03-16 09:24:50 +08001277 { .compatible = "qca,ag956x-mac", .data = AG7XXX_MODEL_AG956X },
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001278 { }
1279};
1280
1281U_BOOT_DRIVER(eth_ag7xxx) = {
1282 .name = "eth_ag7xxx",
1283 .id = UCLASS_ETH,
1284 .of_match = ag7xxx_eth_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -07001285 .of_to_plat = ag7xxx_eth_of_to_plat,
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001286 .probe = ag7xxx_eth_probe,
1287 .remove = ag7xxx_eth_remove,
1288 .ops = &ag7xxx_eth_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001289 .priv_auto = sizeof(struct ar7xxx_eth_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -07001290 .plat_auto = sizeof(struct eth_pdata),
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001291 .flags = DM_FLAG_ALLOC_PRIV_DMA,
1292};