blob: da1f3f4580805f70905760919e2c314668e3c3e9 [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
9#include <common.h>
Simon Glass85d65312019-12-28 10:44:58 -070010#include <clock_legacy.h>
Simon Glass63334482019-11-14 12:57:39 -070011#include <cpu_func.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020012#include <dm.h>
13#include <errno.h>
Simon Glass0f2af882020-05-10 11:40:05 -060014#include <log.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020015#include <miiphy.h>
16#include <malloc.h>
Simon Glass274e0b02020-05-10 11:39:56 -060017#include <net.h>
18#include <asm/cache.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060019#include <asm/global_data.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060020#include <linux/bitops.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020021#include <linux/compiler.h>
Simon Glassdbd79542020-05-10 11:40:11 -060022#include <linux/delay.h>
Marek Vasut0a3d0e12016-05-24 23:29:09 +020023#include <linux/err.h>
24#include <linux/mii.h>
25#include <wait_bit.h>
26#include <asm/io.h>
27
28#include <mach/ath79.h>
29
30DECLARE_GLOBAL_DATA_PTR;
31
32enum ag7xxx_model {
33 AG7XXX_MODEL_AG933X,
34 AG7XXX_MODEL_AG934X,
Rosy Song51ef2e72019-03-16 09:24:50 +080035 AG7XXX_MODEL_AG953X,
36 AG7XXX_MODEL_AG956X
Marek Vasut0a3d0e12016-05-24 23:29:09 +020037};
38
Joe Hershbergera1a837d2017-06-26 14:40:08 -050039/* MAC Configuration 1 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020040#define AG7XXX_ETH_CFG1 0x00
41#define AG7XXX_ETH_CFG1_SOFT_RST BIT(31)
42#define AG7XXX_ETH_CFG1_RX_RST BIT(19)
43#define AG7XXX_ETH_CFG1_TX_RST BIT(18)
44#define AG7XXX_ETH_CFG1_LOOPBACK BIT(8)
45#define AG7XXX_ETH_CFG1_RX_EN BIT(2)
46#define AG7XXX_ETH_CFG1_TX_EN BIT(0)
47
Joe Hershbergera1a837d2017-06-26 14:40:08 -050048/* MAC Configuration 2 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020049#define AG7XXX_ETH_CFG2 0x04
50#define AG7XXX_ETH_CFG2_IF_1000 BIT(9)
51#define AG7XXX_ETH_CFG2_IF_10_100 BIT(8)
52#define AG7XXX_ETH_CFG2_IF_SPEED_MASK (3 << 8)
53#define AG7XXX_ETH_CFG2_HUGE_FRAME_EN BIT(5)
54#define AG7XXX_ETH_CFG2_LEN_CHECK BIT(4)
55#define AG7XXX_ETH_CFG2_PAD_CRC_EN BIT(2)
56#define AG7XXX_ETH_CFG2_FDX BIT(0)
57
Joe Hershbergera1a837d2017-06-26 14:40:08 -050058/* MII Configuration */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020059#define AG7XXX_ETH_MII_MGMT_CFG 0x20
60#define AG7XXX_ETH_MII_MGMT_CFG_RESET BIT(31)
61
Joe Hershbergera1a837d2017-06-26 14:40:08 -050062/* MII Command */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020063#define AG7XXX_ETH_MII_MGMT_CMD 0x24
64#define AG7XXX_ETH_MII_MGMT_CMD_READ 0x1
65
Joe Hershbergera1a837d2017-06-26 14:40:08 -050066/* MII Address */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020067#define AG7XXX_ETH_MII_MGMT_ADDRESS 0x28
68#define AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT 8
69
Joe Hershbergera1a837d2017-06-26 14:40:08 -050070/* MII Control */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020071#define AG7XXX_ETH_MII_MGMT_CTRL 0x2c
72
Joe Hershbergera1a837d2017-06-26 14:40:08 -050073/* MII Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020074#define AG7XXX_ETH_MII_MGMT_STATUS 0x30
75
Joe Hershbergera1a837d2017-06-26 14:40:08 -050076/* MII Indicators */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020077#define AG7XXX_ETH_MII_MGMT_IND 0x34
78#define AG7XXX_ETH_MII_MGMT_IND_INVALID BIT(2)
79#define AG7XXX_ETH_MII_MGMT_IND_BUSY BIT(0)
80
Joe Hershbergera1a837d2017-06-26 14:40:08 -050081/* STA Address 1 & 2 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020082#define AG7XXX_ETH_ADDR1 0x40
83#define AG7XXX_ETH_ADDR2 0x44
84
Joe Hershbergera1a837d2017-06-26 14:40:08 -050085/* ETH Configuration 0 - 5 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020086#define AG7XXX_ETH_FIFO_CFG_0 0x48
87#define AG7XXX_ETH_FIFO_CFG_1 0x4c
88#define AG7XXX_ETH_FIFO_CFG_2 0x50
89#define AG7XXX_ETH_FIFO_CFG_3 0x54
90#define AG7XXX_ETH_FIFO_CFG_4 0x58
91#define AG7XXX_ETH_FIFO_CFG_5 0x5c
92
Joe Hershbergera1a837d2017-06-26 14:40:08 -050093/* DMA Transfer Control for Queue 0 */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020094#define AG7XXX_ETH_DMA_TX_CTRL 0x180
95#define AG7XXX_ETH_DMA_TX_CTRL_TXE BIT(0)
96
Joe Hershbergera1a837d2017-06-26 14:40:08 -050097/* Descriptor Address for Queue 0 Tx */
Marek Vasut0a3d0e12016-05-24 23:29:09 +020098#define AG7XXX_ETH_DMA_TX_DESC 0x184
99
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500100/* DMA Tx Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200101#define AG7XXX_ETH_DMA_TX_STATUS 0x188
102
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500103/* Rx Control */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200104#define AG7XXX_ETH_DMA_RX_CTRL 0x18c
105#define AG7XXX_ETH_DMA_RX_CTRL_RXE BIT(0)
106
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500107/* Pointer to Rx Descriptor */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200108#define AG7XXX_ETH_DMA_RX_DESC 0x190
109
Joe Hershbergera1a837d2017-06-26 14:40:08 -0500110/* Rx Status */
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200111#define AG7XXX_ETH_DMA_RX_STATUS 0x194
112
Rosy Song361c69e2019-02-05 17:50:44 +0800113/* Custom register at 0x1805002C */
114#define AG7XXX_ETH_XMII 0x2C
115#define AG7XXX_ETH_XMII_TX_INVERT BIT(31)
116#define AG7XXX_ETH_XMII_RX_DELAY_LSB 28
117#define AG7XXX_ETH_XMII_RX_DELAY_MASK 0x30000000
118#define AG7XXX_ETH_XMII_RX_DELAY_SET(x) \
119 (((x) << AG7XXX_ETH_XMII_RX_DELAY_LSB) & AG7XXX_ETH_XMII_RX_DELAY_MASK)
120#define AG7XXX_ETH_XMII_TX_DELAY_LSB 26
121#define AG7XXX_ETH_XMII_TX_DELAY_MASK 0x0c000000
122#define AG7XXX_ETH_XMII_TX_DELAY_SET(x) \
123 (((x) << AG7XXX_ETH_XMII_TX_DELAY_LSB) & AG7XXX_ETH_XMII_TX_DELAY_MASK)
124#define AG7XXX_ETH_XMII_GIGE BIT(25)
125
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200126/* Custom register at 0x18070000 */
127#define AG7XXX_GMAC_ETH_CFG 0x00
Rosy Song361c69e2019-02-05 17:50:44 +0800128#define AG7XXX_ETH_CFG_RXDV_DELAY_LSB 16
129#define AG7XXX_ETH_CFG_RXDV_DELAY_MASK 0x00030000
130#define AG7XXX_ETH_CFG_RXDV_DELAY_SET(x) \
131 (((x) << AG7XXX_ETH_CFG_RXDV_DELAY_LSB) & AG7XXX_ETH_CFG_RXDV_DELAY_MASK)
132#define AG7XXX_ETH_CFG_RXD_DELAY_LSB 14
133#define AG7XXX_ETH_CFG_RXD_DELAY_MASK 0x0000c000
134#define AG7XXX_ETH_CFG_RXD_DELAY_SET(x) \
135 (((x) << AG7XXX_ETH_CFG_RXD_DELAY_LSB) & AG7XXX_ETH_CFG_RXD_DELAY_MASK)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200136#define AG7XXX_ETH_CFG_SW_PHY_ADDR_SWAP BIT(8)
137#define AG7XXX_ETH_CFG_SW_PHY_SWAP BIT(7)
138#define AG7XXX_ETH_CFG_SW_ONLY_MODE BIT(6)
139#define AG7XXX_ETH_CFG_GE0_ERR_EN BIT(5)
140#define AG7XXX_ETH_CFG_MII_GE0_SLAVE BIT(4)
141#define AG7XXX_ETH_CFG_MII_GE0_MASTER BIT(3)
142#define AG7XXX_ETH_CFG_GMII_GE0 BIT(2)
143#define AG7XXX_ETH_CFG_MII_GE0 BIT(1)
144#define AG7XXX_ETH_CFG_RGMII_GE0 BIT(0)
145
Tom Rini364d0022023-01-10 11:19:45 -0500146#define CFG_TX_DESCR_NUM 8
147#define CFG_RX_DESCR_NUM 8
148#define CFG_ETH_BUFSIZE 2048
149#define TX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_TX_DESCR_NUM)
150#define RX_TOTAL_BUFSIZE (CFG_ETH_BUFSIZE * CFG_RX_DESCR_NUM)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200151
152/* DMA descriptor. */
153struct ag7xxx_dma_desc {
154 u32 data_addr;
155#define AG7XXX_DMADESC_IS_EMPTY BIT(31)
156#define AG7XXX_DMADESC_FTPP_OVERRIDE_OFFSET 16
157#define AG7XXX_DMADESC_PKT_SIZE_OFFSET 0
158#define AG7XXX_DMADESC_PKT_SIZE_MASK 0xfff
159 u32 config;
160 u32 next_desc;
161 u32 _pad[5];
162};
163
164struct ar7xxx_eth_priv {
Tom Rini364d0022023-01-10 11:19:45 -0500165 struct ag7xxx_dma_desc tx_mac_descrtable[CFG_TX_DESCR_NUM];
166 struct ag7xxx_dma_desc rx_mac_descrtable[CFG_RX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200167 char txbuffs[TX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
168 char rxbuffs[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
169
170 void __iomem *regs;
171 void __iomem *phyregs;
172
173 struct eth_device *dev;
174 struct phy_device *phydev;
175 struct mii_dev *bus;
176
177 u32 interface;
178 u32 tx_currdescnum;
179 u32 rx_currdescnum;
180 enum ag7xxx_model model;
181};
182
183/*
184 * Switch and MDIO access
185 */
186static int ag7xxx_switch_read(struct mii_dev *bus, int addr, int reg, u16 *val)
187{
188 struct ar7xxx_eth_priv *priv = bus->priv;
189 void __iomem *regs = priv->phyregs;
190 int ret;
191
192 writel(0x0, regs + AG7XXX_ETH_MII_MGMT_CMD);
193 writel((addr << AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT) | reg,
194 regs + AG7XXX_ETH_MII_MGMT_ADDRESS);
195 writel(AG7XXX_ETH_MII_MGMT_CMD_READ,
196 regs + AG7XXX_ETH_MII_MGMT_CMD);
197
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100198 ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
199 AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200200 if (ret)
201 return ret;
202
203 *val = readl(regs + AG7XXX_ETH_MII_MGMT_STATUS) & 0xffff;
204 writel(0x0, regs + AG7XXX_ETH_MII_MGMT_CMD);
205
206 return 0;
207}
208
209static int ag7xxx_switch_write(struct mii_dev *bus, int addr, int reg, u16 val)
210{
211 struct ar7xxx_eth_priv *priv = bus->priv;
212 void __iomem *regs = priv->phyregs;
213 int ret;
214
215 writel((addr << AG7XXX_ETH_MII_MGMT_ADDRESS_SHIFT) | reg,
216 regs + AG7XXX_ETH_MII_MGMT_ADDRESS);
217 writel(val, regs + AG7XXX_ETH_MII_MGMT_CTRL);
218
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100219 ret = wait_for_bit_le32(regs + AG7XXX_ETH_MII_MGMT_IND,
220 AG7XXX_ETH_MII_MGMT_IND_BUSY, 0, 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200221
222 return ret;
223}
224
225static int ag7xxx_switch_reg_read(struct mii_dev *bus, int reg, u32 *val)
226{
227 struct ar7xxx_eth_priv *priv = bus->priv;
228 u32 phy_addr;
229 u32 reg_addr;
230 u32 phy_temp;
231 u32 reg_temp;
Rosy Song51ef2e72019-03-16 09:24:50 +0800232 u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200233 u16 rv = 0;
234 int ret;
235
Rosy Song361c69e2019-02-05 17:50:44 +0800236 if (priv->model == AG7XXX_MODEL_AG933X ||
237 priv->model == AG7XXX_MODEL_AG953X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200238 phy_addr = 0x1f;
239 reg_addr = 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800240 } else if (priv->model == AG7XXX_MODEL_AG934X ||
241 priv->model == AG7XXX_MODEL_AG956X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200242 phy_addr = 0x18;
243 reg_addr = 0x00;
244 } else
245 return -EINVAL;
246
Rosy Song51ef2e72019-03-16 09:24:50 +0800247 if (priv->model == AG7XXX_MODEL_AG956X)
248 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
249 else
250 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200251 if (ret)
252 return ret;
253
254 phy_temp = ((reg >> 6) & 0x7) | 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800255 if (priv->model == AG7XXX_MODEL_AG956X)
256 reg_temp = reg_temp_w & 0x1f;
257 else
258 reg_temp = (reg >> 1) & 0x1e;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200259 *val = 0;
260
261 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 0, &rv);
262 if (ret < 0)
263 return ret;
264 *val |= rv;
265
Rosy Song51ef2e72019-03-16 09:24:50 +0800266 if (priv->model == AG7XXX_MODEL_AG956X) {
267 phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
268 reg_temp = (reg_temp_w + 1) & 0x1f;
269 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp, &rv);
270 } else {
271 ret = ag7xxx_switch_read(bus, phy_temp, reg_temp | 1, &rv);
272 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200273 if (ret < 0)
274 return ret;
275 *val |= (rv << 16);
276
277 return 0;
278}
279
280static int ag7xxx_switch_reg_write(struct mii_dev *bus, int reg, u32 val)
281{
282 struct ar7xxx_eth_priv *priv = bus->priv;
283 u32 phy_addr;
284 u32 reg_addr;
285 u32 phy_temp;
286 u32 reg_temp;
Rosy Song51ef2e72019-03-16 09:24:50 +0800287 u32 reg_temp_w = (reg & 0xfffffffc) >> 1;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200288 int ret;
289
Rosy Song361c69e2019-02-05 17:50:44 +0800290 if (priv->model == AG7XXX_MODEL_AG933X ||
291 priv->model == AG7XXX_MODEL_AG953X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200292 phy_addr = 0x1f;
293 reg_addr = 0x10;
Rosy Song51ef2e72019-03-16 09:24:50 +0800294 } else if (priv->model == AG7XXX_MODEL_AG934X ||
295 priv->model == AG7XXX_MODEL_AG956X) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200296 phy_addr = 0x18;
297 reg_addr = 0x00;
298 } else
299 return -EINVAL;
300
Rosy Song51ef2e72019-03-16 09:24:50 +0800301 if (priv->model == AG7XXX_MODEL_AG956X)
302 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, (reg >> 9) & 0x1ff);
303 else
304 ret = ag7xxx_switch_write(bus, phy_addr, reg_addr, reg >> 9);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200305 if (ret)
306 return ret;
307
Rosy Song51ef2e72019-03-16 09:24:50 +0800308 if (priv->model == AG7XXX_MODEL_AG956X) {
309 reg_temp = (reg_temp_w + 1) & 0x1f;
310 phy_temp = (((reg_temp_w + 1) >> 5) & 0x7) | 0x10;
311 } else {
312 phy_temp = ((reg >> 6) & 0x7) | 0x10;
313 reg_temp = (reg >> 1) & 0x1e;
314 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200315
316 /*
317 * The switch on AR933x has some special register behavior, which
318 * expects particular write order of their nibbles:
319 * 0x40 ..... MSB first, LSB second
320 * 0x50 ..... MSB first, LSB second
321 * 0x98 ..... LSB first, MSB second
322 * others ... don't care
323 */
324 if ((priv->model == AG7XXX_MODEL_AG933X) && (reg == 0x98)) {
325 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
326 if (ret < 0)
327 return ret;
328
329 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
330 if (ret < 0)
331 return ret;
332 } else {
Rosy Song51ef2e72019-03-16 09:24:50 +0800333 if (priv->model == AG7XXX_MODEL_AG956X)
334 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp, val >> 16);
335 else
336 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 1, val >> 16);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200337 if (ret < 0)
338 return ret;
339
Rosy Song51ef2e72019-03-16 09:24:50 +0800340 if (priv->model == AG7XXX_MODEL_AG956X) {
341 phy_temp = ((reg_temp_w >> 5) & 0x7) | 0x10;
342 reg_temp = reg_temp_w & 0x1f;
343 }
344
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200345 ret = ag7xxx_switch_write(bus, phy_temp, reg_temp | 0, val & 0xffff);
346 if (ret < 0)
347 return ret;
348 }
349
350 return 0;
351}
352
Joe Hershberger5a41d662017-06-26 14:40:09 -0500353static int ag7xxx_mdio_rw(struct mii_dev *bus, int addr, int reg, u32 val)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200354{
355 u32 data;
Joe Hershberger5a41d662017-06-26 14:40:09 -0500356 unsigned long start;
357 int ret;
358 /* No idea if this is long enough or too long */
359 int timeout_ms = 1000;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200360
361 /* Dummy read followed by PHY read/write command. */
Joe Hershberger5a41d662017-06-26 14:40:09 -0500362 ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
363 if (ret < 0)
364 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200365 data = val | (reg << 16) | (addr << 21) | BIT(30) | BIT(31);
Joe Hershberger5a41d662017-06-26 14:40:09 -0500366 ret = ag7xxx_switch_reg_write(bus, 0x98, data);
367 if (ret < 0)
368 return ret;
369
370 start = get_timer(0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200371
372 /* Wait for operation to finish */
373 do {
Joe Hershberger5a41d662017-06-26 14:40:09 -0500374 ret = ag7xxx_switch_reg_read(bus, 0x98, &data);
375 if (ret < 0)
376 return ret;
377
378 if (get_timer(start) > timeout_ms)
379 return -ETIMEDOUT;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200380 } while (data & BIT(31));
381
382 return data & 0xffff;
383}
384
385static int ag7xxx_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
386{
387 return ag7xxx_mdio_rw(bus, addr, reg, BIT(27));
388}
389
390static int ag7xxx_mdio_write(struct mii_dev *bus, int addr, int devad, int reg,
391 u16 val)
392{
Joe Hershberger5a41d662017-06-26 14:40:09 -0500393 int ret;
394
395 ret = ag7xxx_mdio_rw(bus, addr, reg, val);
396 if (ret < 0)
397 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200398 return 0;
399}
400
401/*
402 * DMA ring handlers
403 */
404static void ag7xxx_dma_clean_tx(struct udevice *dev)
405{
406 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
407 struct ag7xxx_dma_desc *curr, *next;
408 u32 start, end;
409 int i;
410
Tom Rini364d0022023-01-10 11:19:45 -0500411 for (i = 0; i < CFG_TX_DESCR_NUM; i++) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200412 curr = &priv->tx_mac_descrtable[i];
Tom Rini364d0022023-01-10 11:19:45 -0500413 next = &priv->tx_mac_descrtable[(i + 1) % CFG_TX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200414
Tom Rini364d0022023-01-10 11:19:45 -0500415 curr->data_addr = virt_to_phys(&priv->txbuffs[i * CFG_ETH_BUFSIZE]);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200416 curr->config = AG7XXX_DMADESC_IS_EMPTY;
417 curr->next_desc = virt_to_phys(next);
418 }
419
420 priv->tx_currdescnum = 0;
421
422 /* Cache: Flush descriptors, don't care about buffers. */
423 start = (u32)(&priv->tx_mac_descrtable[0]);
424 end = start + sizeof(priv->tx_mac_descrtable);
425 flush_dcache_range(start, end);
426}
427
428static void ag7xxx_dma_clean_rx(struct udevice *dev)
429{
430 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
431 struct ag7xxx_dma_desc *curr, *next;
432 u32 start, end;
433 int i;
434
Tom Rini364d0022023-01-10 11:19:45 -0500435 for (i = 0; i < CFG_RX_DESCR_NUM; i++) {
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200436 curr = &priv->rx_mac_descrtable[i];
Tom Rini364d0022023-01-10 11:19:45 -0500437 next = &priv->rx_mac_descrtable[(i + 1) % CFG_RX_DESCR_NUM];
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200438
Tom Rini364d0022023-01-10 11:19:45 -0500439 curr->data_addr = virt_to_phys(&priv->rxbuffs[i * CFG_ETH_BUFSIZE]);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200440 curr->config = AG7XXX_DMADESC_IS_EMPTY;
441 curr->next_desc = virt_to_phys(next);
442 }
443
444 priv->rx_currdescnum = 0;
445
446 /* Cache: Flush+Invalidate descriptors, Invalidate buffers. */
447 start = (u32)(&priv->rx_mac_descrtable[0]);
448 end = start + sizeof(priv->rx_mac_descrtable);
449 flush_dcache_range(start, end);
450 invalidate_dcache_range(start, end);
451
452 start = (u32)&priv->rxbuffs;
453 end = start + sizeof(priv->rxbuffs);
454 invalidate_dcache_range(start, end);
455}
456
457/*
458 * Ethernet I/O
459 */
460static int ag7xxx_eth_send(struct udevice *dev, void *packet, int length)
461{
462 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
463 struct ag7xxx_dma_desc *curr;
464 u32 start, end;
465
466 curr = &priv->tx_mac_descrtable[priv->tx_currdescnum];
467
468 /* Cache: Invalidate descriptor. */
469 start = (u32)curr;
470 end = start + sizeof(*curr);
471 invalidate_dcache_range(start, end);
472
473 if (!(curr->config & AG7XXX_DMADESC_IS_EMPTY)) {
474 printf("ag7xxx: Out of TX DMA descriptors!\n");
475 return -EPERM;
476 }
477
478 /* Copy the packet into the data buffer. */
479 memcpy(phys_to_virt(curr->data_addr), packet, length);
480 curr->config = length & AG7XXX_DMADESC_PKT_SIZE_MASK;
481
482 /* Cache: Flush descriptor, Flush buffer. */
483 start = (u32)curr;
484 end = start + sizeof(*curr);
485 flush_dcache_range(start, end);
486 start = (u32)phys_to_virt(curr->data_addr);
487 end = start + length;
488 flush_dcache_range(start, end);
489
490 /* Load the DMA descriptor and start TX DMA. */
491 writel(AG7XXX_ETH_DMA_TX_CTRL_TXE,
492 priv->regs + AG7XXX_ETH_DMA_TX_CTRL);
493
494 /* Switch to next TX descriptor. */
Tom Rini364d0022023-01-10 11:19:45 -0500495 priv->tx_currdescnum = (priv->tx_currdescnum + 1) % CFG_TX_DESCR_NUM;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200496
497 return 0;
498}
499
500static int ag7xxx_eth_recv(struct udevice *dev, int flags, uchar **packetp)
501{
502 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
503 struct ag7xxx_dma_desc *curr;
504 u32 start, end, length;
505
506 curr = &priv->rx_mac_descrtable[priv->rx_currdescnum];
507
508 /* Cache: Invalidate descriptor. */
509 start = (u32)curr;
510 end = start + sizeof(*curr);
511 invalidate_dcache_range(start, end);
512
513 /* No packets received. */
514 if (curr->config & AG7XXX_DMADESC_IS_EMPTY)
515 return -EAGAIN;
516
517 length = curr->config & AG7XXX_DMADESC_PKT_SIZE_MASK;
518
519 /* Cache: Invalidate buffer. */
520 start = (u32)phys_to_virt(curr->data_addr);
521 end = start + length;
522 invalidate_dcache_range(start, end);
523
524 /* Receive one packet and return length. */
525 *packetp = phys_to_virt(curr->data_addr);
526 return length;
527}
528
529static int ag7xxx_eth_free_pkt(struct udevice *dev, uchar *packet,
530 int length)
531{
532 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
533 struct ag7xxx_dma_desc *curr;
534 u32 start, end;
535
536 curr = &priv->rx_mac_descrtable[priv->rx_currdescnum];
537
538 curr->config = AG7XXX_DMADESC_IS_EMPTY;
539
540 /* Cache: Flush descriptor. */
541 start = (u32)curr;
542 end = start + sizeof(*curr);
543 flush_dcache_range(start, end);
544
545 /* Switch to next RX descriptor. */
Tom Rini364d0022023-01-10 11:19:45 -0500546 priv->rx_currdescnum = (priv->rx_currdescnum + 1) % CFG_RX_DESCR_NUM;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200547
548 return 0;
549}
550
551static int ag7xxx_eth_start(struct udevice *dev)
552{
553 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
554
555 /* FIXME: Check if link up */
556
557 /* Clear the DMA rings. */
558 ag7xxx_dma_clean_tx(dev);
559 ag7xxx_dma_clean_rx(dev);
560
561 /* Load DMA descriptors and start the RX DMA. */
562 writel(virt_to_phys(&priv->tx_mac_descrtable[priv->tx_currdescnum]),
563 priv->regs + AG7XXX_ETH_DMA_TX_DESC);
564 writel(virt_to_phys(&priv->rx_mac_descrtable[priv->rx_currdescnum]),
565 priv->regs + AG7XXX_ETH_DMA_RX_DESC);
566 writel(AG7XXX_ETH_DMA_RX_CTRL_RXE,
567 priv->regs + AG7XXX_ETH_DMA_RX_CTRL);
568
569 return 0;
570}
571
572static void ag7xxx_eth_stop(struct udevice *dev)
573{
574 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
575
576 /* Stop the TX DMA. */
577 writel(0, priv->regs + AG7XXX_ETH_DMA_TX_CTRL);
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100578 wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_TX_CTRL, ~0, 0,
579 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200580
581 /* Stop the RX DMA. */
582 writel(0, priv->regs + AG7XXX_ETH_DMA_RX_CTRL);
Álvaro Fernåndez Rojas918de032018-01-23 17:14:55 +0100583 wait_for_bit_le32(priv->regs + AG7XXX_ETH_DMA_RX_CTRL, ~0, 0,
584 1000, 0);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200585}
586
587/*
588 * Hardware setup
589 */
590static int ag7xxx_eth_write_hwaddr(struct udevice *dev)
591{
Simon Glassfa20e932020-12-03 16:55:20 -0700592 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200593 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
594 unsigned char *mac = pdata->enetaddr;
595 u32 macid_lo, macid_hi;
596
597 macid_hi = mac[3] | (mac[2] << 8) | (mac[1] << 16) | (mac[0] << 24);
598 macid_lo = (mac[5] << 16) | (mac[4] << 24);
599
600 writel(macid_lo, priv->regs + AG7XXX_ETH_ADDR1);
601 writel(macid_hi, priv->regs + AG7XXX_ETH_ADDR2);
602
603 return 0;
604}
605
606static void ag7xxx_hw_setup(struct udevice *dev)
607{
608 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
609 u32 speed;
610
611 setbits_be32(priv->regs + AG7XXX_ETH_CFG1,
612 AG7XXX_ETH_CFG1_RX_RST | AG7XXX_ETH_CFG1_TX_RST |
613 AG7XXX_ETH_CFG1_SOFT_RST);
614
615 mdelay(10);
616
617 writel(AG7XXX_ETH_CFG1_RX_EN | AG7XXX_ETH_CFG1_TX_EN,
618 priv->regs + AG7XXX_ETH_CFG1);
619
620 if (priv->interface == PHY_INTERFACE_MODE_RMII)
621 speed = AG7XXX_ETH_CFG2_IF_10_100;
622 else
623 speed = AG7XXX_ETH_CFG2_IF_1000;
624
625 clrsetbits_be32(priv->regs + AG7XXX_ETH_CFG2,
626 AG7XXX_ETH_CFG2_IF_SPEED_MASK,
627 speed | AG7XXX_ETH_CFG2_PAD_CRC_EN |
628 AG7XXX_ETH_CFG2_LEN_CHECK);
629
630 writel(0xfff0000, priv->regs + AG7XXX_ETH_FIFO_CFG_1);
631 writel(0x1fff, priv->regs + AG7XXX_ETH_FIFO_CFG_2);
632
633 writel(0x1f00, priv->regs + AG7XXX_ETH_FIFO_CFG_0);
634 setbits_be32(priv->regs + AG7XXX_ETH_FIFO_CFG_4, 0x3ffff);
635 writel(0x10ffff, priv->regs + AG7XXX_ETH_FIFO_CFG_1);
636 writel(0xaaa0555, priv->regs + AG7XXX_ETH_FIFO_CFG_2);
637 writel(0x7eccf, priv->regs + AG7XXX_ETH_FIFO_CFG_5);
638 writel(0x1f00140, priv->regs + AG7XXX_ETH_FIFO_CFG_3);
639}
640
641static int ag7xxx_mii_get_div(void)
642{
643 ulong freq = get_bus_freq(0);
644
645 switch (freq / 1000000) {
646 case 150: return 0x7;
647 case 175: return 0x5;
648 case 200: return 0x4;
649 case 210: return 0x9;
650 case 220: return 0x9;
651 default: return 0x7;
652 }
653}
654
655static int ag7xxx_mii_setup(struct udevice *dev)
656{
657 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
658 int i, ret, div = ag7xxx_mii_get_div();
659 u32 reg;
660
661 if (priv->model == AG7XXX_MODEL_AG933X) {
662 /* Unit 0 is PHY-less on AR9331, see datasheet Figure 2-3 */
663 if (priv->interface == PHY_INTERFACE_MODE_RMII)
664 return 0;
665 }
666
Rosy Song361c69e2019-02-05 17:50:44 +0800667 if (priv->model == AG7XXX_MODEL_AG934X)
668 reg = 0x4;
669 else if (priv->model == AG7XXX_MODEL_AG953X)
670 reg = 0x2;
Rosy Song51ef2e72019-03-16 09:24:50 +0800671 else if (priv->model == AG7XXX_MODEL_AG956X)
672 reg = 0x7;
Rosy Song361c69e2019-02-05 17:50:44 +0800673
674 if (priv->model == AG7XXX_MODEL_AG934X ||
Rosy Song51ef2e72019-03-16 09:24:50 +0800675 priv->model == AG7XXX_MODEL_AG953X ||
676 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800677 writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | reg,
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200678 priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
Rosy Song361c69e2019-02-05 17:50:44 +0800679 writel(reg, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200680 return 0;
681 }
682
683 for (i = 0; i < 10; i++) {
684 writel(AG7XXX_ETH_MII_MGMT_CFG_RESET | div,
685 priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
686 writel(div, priv->regs + AG7XXX_ETH_MII_MGMT_CFG);
687
688 /* Check the switch */
689 ret = ag7xxx_switch_reg_read(priv->bus, 0x10c, &reg);
690 if (ret)
691 continue;
692
693 if (reg != 0x18007fff)
694 continue;
695
696 return 0;
697 }
698
699 return -EINVAL;
700}
701
702static int ag933x_phy_setup_wan(struct udevice *dev)
703{
704 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
705
706 /* Configure switch port 4 (GMAC0) */
707 return ag7xxx_mdio_write(priv->bus, 4, 0, MII_BMCR, 0x9000);
708}
709
710static int ag933x_phy_setup_lan(struct udevice *dev)
711{
712 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
713 int i, ret;
714 u32 reg;
715
716 /* Reset the switch */
717 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
718 if (ret)
719 return ret;
720 reg |= BIT(31);
721 ret = ag7xxx_switch_reg_write(priv->bus, 0, reg);
722 if (ret)
723 return ret;
724
725 do {
726 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
727 if (ret)
728 return ret;
729 } while (reg & BIT(31));
730
731 /* Configure switch ports 0...3 (GMAC1) */
732 for (i = 0; i < 4; i++) {
733 ret = ag7xxx_mdio_write(priv->bus, 0x4, 0, MII_BMCR, 0x9000);
734 if (ret)
735 return ret;
736 }
737
738 /* Enable CPU port */
739 ret = ag7xxx_switch_reg_write(priv->bus, 0x78, BIT(8));
740 if (ret)
741 return ret;
742
743 for (i = 0; i < 4; i++) {
744 ret = ag7xxx_switch_reg_write(priv->bus, i * 0x100, BIT(9));
745 if (ret)
746 return ret;
747 }
748
749 /* QM Control */
750 ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
751 if (ret)
752 return ret;
753
754 /* Disable Atheros header */
755 ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
756 if (ret)
757 return ret;
758
759 /* Tag priority mapping */
760 ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
761 if (ret)
762 return ret;
763
764 /* Enable ARP packets to the CPU */
765 ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
766 if (ret)
767 return ret;
768 reg |= 0x100000;
769 ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg);
770 if (ret)
771 return ret;
772
Rosy Song361c69e2019-02-05 17:50:44 +0800773 return 0;
774}
775
776static int ag953x_phy_setup_wan(struct udevice *dev)
777{
778 int ret;
779 u32 reg = 0;
780 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
781
782 /* Set wan port connect to GE0 */
783 ret = ag7xxx_switch_reg_read(priv->bus, 0x8, &reg);
784 if (ret)
785 return ret;
786
787 ret = ag7xxx_switch_reg_write(priv->bus, 0x8, reg | BIT(28));
788 if (ret)
789 return ret;
790
791 /* Configure switch port 4 (GMAC0) */
792 ret = ag7xxx_switch_write(priv->bus, 4, MII_BMCR, 0x9000);
793 if (ret)
794 return ret;
795
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200796 return 0;
797}
798
Rosy Song361c69e2019-02-05 17:50:44 +0800799static int ag953x_phy_setup_lan(struct udevice *dev)
800{
801 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
802 int i, ret;
803 u32 reg = 0;
804
805 /* Reset the switch */
806 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
807 if (ret)
808 return ret;
809
810 ret = ag7xxx_switch_reg_write(priv->bus, 0, reg | BIT(31));
811 if (ret)
812 return ret;
813
814 do {
815 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
816 if (ret)
817 return ret;
818 } while (reg & BIT(31));
819
820 ret = ag7xxx_switch_reg_write(priv->bus, 0x100, 0x4e);
821 if (ret)
822 return ret;
823
824 /* Set GMII mode */
825 ret = ag7xxx_switch_reg_read(priv->bus, 0x4, &reg);
826 if (ret)
827 return ret;
828
829 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, reg | BIT(6));
830 if (ret)
831 return ret;
832
833 /* Configure switch ports 0...4 (GMAC1) */
834 for (i = 0; i < 5; i++) {
835 ret = ag7xxx_switch_write(priv->bus, i, MII_BMCR, 0x9000);
836 if (ret)
837 return ret;
838 }
839
840 for (i = 0; i < 5; i++) {
841 ret = ag7xxx_switch_reg_write(priv->bus, (i + 2) * 0x100, BIT(9));
842 if (ret)
843 return ret;
844 }
845
846 /* QM Control */
847 ret = ag7xxx_switch_reg_write(priv->bus, 0x38, 0xc000050e);
848 if (ret)
849 return ret;
850
851 /* Disable Atheros header */
852 ret = ag7xxx_switch_reg_write(priv->bus, 0x104, 0x4004);
853 if (ret)
854 return ret;
855
856 /* Tag priority mapping */
857 ret = ag7xxx_switch_reg_write(priv->bus, 0x70, 0xfa50);
858 if (ret)
859 return ret;
860
861 /* Enable ARP packets to the CPU */
862 ret = ag7xxx_switch_reg_read(priv->bus, 0x5c, &reg);
863 if (ret)
864 return ret;
865
866 ret = ag7xxx_switch_reg_write(priv->bus, 0x5c, reg | 0x100000);
867 if (ret)
868 return ret;
869
870 /* Enable broadcast packets to the CPU */
871 ret = ag7xxx_switch_reg_read(priv->bus, 0x2c, &reg);
872 if (ret)
873 return ret;
874
875 ret = ag7xxx_switch_reg_write(priv->bus, 0x2c, reg | BIT(25) | BIT(26));
876 if (ret)
877 return ret;
878
879 return 0;
880}
881
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200882static int ag933x_phy_setup_reset_set(struct udevice *dev, int port)
883{
884 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
885 int ret;
886
Rosy Song51ef2e72019-03-16 09:24:50 +0800887 if (priv->model == AG7XXX_MODEL_AG953X ||
888 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800889 ret = ag7xxx_switch_write(priv->bus, port, MII_ADVERTISE,
890 ADVERTISE_ALL);
891 } else {
892 ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_ADVERTISE,
893 ADVERTISE_ALL | ADVERTISE_PAUSE_CAP |
894 ADVERTISE_PAUSE_ASYM);
895 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200896 if (ret)
897 return ret;
898
899 if (priv->model == AG7XXX_MODEL_AG934X) {
900 ret = ag7xxx_mdio_write(priv->bus, port, 0, MII_CTRL1000,
901 ADVERTISE_1000FULL);
902 if (ret)
903 return ret;
Rosy Song51ef2e72019-03-16 09:24:50 +0800904 } else if (priv->model == AG7XXX_MODEL_AG956X) {
905 ret = ag7xxx_switch_write(priv->bus, port, MII_CTRL1000,
906 ADVERTISE_1000FULL);
907 if (ret)
908 return ret;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200909 }
910
Rosy Song51ef2e72019-03-16 09:24:50 +0800911 if (priv->model == AG7XXX_MODEL_AG953X ||
912 priv->model == AG7XXX_MODEL_AG956X)
Rosy Song361c69e2019-02-05 17:50:44 +0800913 return ag7xxx_switch_write(priv->bus, port, MII_BMCR,
914 BMCR_ANENABLE | BMCR_RESET);
915
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200916 return ag7xxx_mdio_write(priv->bus, port, 0, MII_BMCR,
917 BMCR_ANENABLE | BMCR_RESET);
918}
919
920static int ag933x_phy_setup_reset_fin(struct udevice *dev, int port)
921{
922 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
923 int ret;
Rosy Song361c69e2019-02-05 17:50:44 +0800924 u16 reg;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200925
Rosy Song51ef2e72019-03-16 09:24:50 +0800926 if (priv->model == AG7XXX_MODEL_AG953X ||
927 priv->model == AG7XXX_MODEL_AG956X) {
Rosy Song361c69e2019-02-05 17:50:44 +0800928 do {
929 ret = ag7xxx_switch_read(priv->bus, port, MII_BMCR, &reg);
930 if (ret < 0)
931 return ret;
932 mdelay(10);
933 } while (reg & BMCR_RESET);
934 } else {
935 do {
936 ret = ag7xxx_mdio_read(priv->bus, port, 0, MII_BMCR);
937 if (ret < 0)
938 return ret;
939 mdelay(10);
940 } while (ret & BMCR_RESET);
941 }
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200942
943 return 0;
944}
945
946static int ag933x_phy_setup_common(struct udevice *dev)
947{
948 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
949 int i, ret, phymax;
Rosy Song361c69e2019-02-05 17:50:44 +0800950 u16 reg;
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200951
952 if (priv->model == AG7XXX_MODEL_AG933X)
953 phymax = 4;
Rosy Song361c69e2019-02-05 17:50:44 +0800954 else if (priv->model == AG7XXX_MODEL_AG934X ||
Rosy Song51ef2e72019-03-16 09:24:50 +0800955 priv->model == AG7XXX_MODEL_AG953X ||
956 priv->model == AG7XXX_MODEL_AG956X)
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200957 phymax = 5;
958 else
959 return -EINVAL;
960
961 if (priv->interface == PHY_INTERFACE_MODE_RMII) {
962 ret = ag933x_phy_setup_reset_set(dev, phymax);
963 if (ret)
964 return ret;
965
966 ret = ag933x_phy_setup_reset_fin(dev, phymax);
967 if (ret)
968 return ret;
969
970 /* Read out link status */
Rosy Song361c69e2019-02-05 17:50:44 +0800971 if (priv->model == AG7XXX_MODEL_AG953X)
972 ret = ag7xxx_switch_read(priv->bus, phymax, MII_MIPSCR, &reg);
973 else
974 ret = ag7xxx_mdio_read(priv->bus, phymax, 0, MII_MIPSCR);
Marek Vasut0a3d0e12016-05-24 23:29:09 +0200975 if (ret < 0)
976 return ret;
977
978 return 0;
979 }
980
981 /* Switch ports */
982 for (i = 0; i < phymax; i++) {
983 ret = ag933x_phy_setup_reset_set(dev, i);
984 if (ret)
985 return ret;
986 }
987
988 for (i = 0; i < phymax; i++) {
989 ret = ag933x_phy_setup_reset_fin(dev, i);
990 if (ret)
991 return ret;
992 }
993
994 for (i = 0; i < phymax; i++) {
995 /* Read out link status */
Rosy Song51ef2e72019-03-16 09:24:50 +0800996 if (priv->model == AG7XXX_MODEL_AG953X ||
997 priv->model == AG7XXX_MODEL_AG956X)
Rosy Song361c69e2019-02-05 17:50:44 +0800998 ret = ag7xxx_switch_read(priv->bus, i, MII_MIPSCR, &reg);
999 else
1000 ret = ag7xxx_mdio_read(priv->bus, i, 0, MII_MIPSCR);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001001 if (ret < 0)
1002 return ret;
1003 }
1004
1005 return 0;
1006}
1007
1008static int ag934x_phy_setup(struct udevice *dev)
1009{
1010 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1011 int i, ret;
1012 u32 reg;
1013
1014 ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
1015 if (ret)
1016 return ret;
1017 ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x40000000);
1018 if (ret)
1019 return ret;
1020 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, 0x07600000);
1021 if (ret)
1022 return ret;
1023 ret = ag7xxx_switch_reg_write(priv->bus, 0xc, 0x01000000);
1024 if (ret)
1025 return ret;
1026 ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
1027 if (ret)
1028 return ret;
1029
1030 /* AR8327/AR8328 v1.0 fixup */
1031 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
1032 if (ret)
1033 return ret;
1034 if ((reg & 0xffff) == 0x1201) {
1035 for (i = 0; i < 5; i++) {
1036 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1d, 0x0);
1037 if (ret)
1038 return ret;
1039 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1e, 0x02ea);
1040 if (ret)
1041 return ret;
1042 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1d, 0x3d);
1043 if (ret)
1044 return ret;
1045 ret = ag7xxx_mdio_write(priv->bus, i, 0, 0x1e, 0x68a0);
1046 if (ret)
1047 return ret;
1048 }
1049 }
1050
1051 ret = ag7xxx_switch_reg_read(priv->bus, 0x66c, &reg);
1052 if (ret)
1053 return ret;
1054 reg &= ~0x70000;
1055 ret = ag7xxx_switch_reg_write(priv->bus, 0x66c, reg);
1056 if (ret)
1057 return ret;
1058
1059 return 0;
1060}
1061
Rosy Song51ef2e72019-03-16 09:24:50 +08001062static int ag956x_phy_setup(struct udevice *dev)
1063{
1064 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1065 int i, ret;
1066 u32 reg, ctrl;
1067
1068 ret = ag7xxx_switch_reg_read(priv->bus, 0x0, &reg);
1069 if (ret)
1070 return ret;
1071 if ((reg & 0xffff) >= 0x1301)
1072 ctrl = 0xc74164de;
1073 else
1074 ctrl = 0xc74164d0;
1075
1076 ret = ag7xxx_switch_reg_write(priv->bus, 0x4, BIT(7));
1077 if (ret)
1078 return ret;
1079
1080 ret = ag7xxx_switch_reg_write(priv->bus, 0xe0, ctrl);
1081 if (ret)
1082 return ret;
1083
1084 ret = ag7xxx_switch_reg_write(priv->bus, 0x624, 0x7f7f7f7f);
1085 if (ret)
1086 return ret;
1087
1088 /*
1089 * Values suggested by the switch team when s17 in sgmii
1090 * configuration. 0x10(S17_PWS_REG) = 0x602613a0
1091 */
1092 ret = ag7xxx_switch_reg_write(priv->bus, 0x10, 0x602613a0);
1093 if (ret)
1094 return ret;
1095
1096 ret = ag7xxx_switch_reg_write(priv->bus, 0x7c, 0x0000007e);
1097 if (ret)
1098 return ret;
1099
1100 /* AR8337/AR8334 v1.0 fixup */
1101 ret = ag7xxx_switch_reg_read(priv->bus, 0, &reg);
1102 if (ret)
1103 return ret;
1104 if ((reg & 0xffff) == 0x1301) {
1105 for (i = 0; i < 5; i++) {
1106 /* Turn on Gigabit clock */
1107 ret = ag7xxx_switch_write(priv->bus, i, 0x1d, 0x3d);
1108 if (ret)
1109 return ret;
1110 ret = ag7xxx_switch_write(priv->bus, i, 0x1e, 0x6820);
1111 if (ret)
1112 return ret;
1113 }
1114 }
1115
1116 return 0;
1117}
1118
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001119static int ag7xxx_mac_probe(struct udevice *dev)
1120{
1121 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1122 int ret;
1123
1124 ag7xxx_hw_setup(dev);
1125 ret = ag7xxx_mii_setup(dev);
1126 if (ret)
1127 return ret;
1128
1129 ag7xxx_eth_write_hwaddr(dev);
1130
1131 if (priv->model == AG7XXX_MODEL_AG933X) {
1132 if (priv->interface == PHY_INTERFACE_MODE_RMII)
1133 ret = ag933x_phy_setup_wan(dev);
1134 else
1135 ret = ag933x_phy_setup_lan(dev);
Rosy Song361c69e2019-02-05 17:50:44 +08001136 } else if (priv->model == AG7XXX_MODEL_AG953X) {
1137 if (priv->interface == PHY_INTERFACE_MODE_RMII)
1138 ret = ag953x_phy_setup_wan(dev);
1139 else
1140 ret = ag953x_phy_setup_lan(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001141 } else if (priv->model == AG7XXX_MODEL_AG934X) {
1142 ret = ag934x_phy_setup(dev);
Rosy Song51ef2e72019-03-16 09:24:50 +08001143 } else if (priv->model == AG7XXX_MODEL_AG956X) {
1144 ret = ag956x_phy_setup(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001145 } else {
1146 return -EINVAL;
1147 }
1148
1149 if (ret)
1150 return ret;
1151
1152 return ag933x_phy_setup_common(dev);
1153}
1154
1155static int ag7xxx_mdio_probe(struct udevice *dev)
1156{
1157 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1158 struct mii_dev *bus = mdio_alloc();
1159
1160 if (!bus)
1161 return -ENOMEM;
1162
1163 bus->read = ag7xxx_mdio_read;
1164 bus->write = ag7xxx_mdio_write;
1165 snprintf(bus->name, sizeof(bus->name), dev->name);
1166
1167 bus->priv = (void *)priv;
1168
1169 return mdio_register(bus);
1170}
1171
1172static int ag7xxx_get_phy_iface_offset(struct udevice *dev)
1173{
1174 int offset;
1175
Simon Glassdd79d6e2017-01-17 16:52:55 -07001176 offset = fdtdec_lookup_phandle(gd->fdt_blob, dev_of_offset(dev), "phy");
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001177 if (offset <= 0) {
1178 debug("%s: PHY OF node not found (ret=%i)\n", __func__, offset);
1179 return -EINVAL;
1180 }
1181
1182 offset = fdt_parent_offset(gd->fdt_blob, offset);
1183 if (offset <= 0) {
1184 debug("%s: PHY OF node parent MDIO bus not found (ret=%i)\n",
1185 __func__, offset);
1186 return -EINVAL;
1187 }
1188
1189 offset = fdt_parent_offset(gd->fdt_blob, offset);
1190 if (offset <= 0) {
1191 debug("%s: PHY MDIO OF node parent MAC not found (ret=%i)\n",
1192 __func__, offset);
1193 return -EINVAL;
1194 }
1195
1196 return offset;
1197}
1198
1199static int ag7xxx_eth_probe(struct udevice *dev)
1200{
Simon Glassfa20e932020-12-03 16:55:20 -07001201 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001202 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1203 void __iomem *iobase, *phyiobase;
1204 int ret, phyreg;
1205
1206 /* Decoding of convoluted PHY wiring on Atheros MIPS. */
1207 ret = ag7xxx_get_phy_iface_offset(dev);
1208 if (ret <= 0)
1209 return ret;
1210 phyreg = fdtdec_get_int(gd->fdt_blob, ret, "reg", -1);
1211
1212 iobase = map_physmem(pdata->iobase, 0x200, MAP_NOCACHE);
1213 phyiobase = map_physmem(phyreg, 0x200, MAP_NOCACHE);
1214
1215 debug("%s, iobase=%p, phyiobase=%p, priv=%p\n",
1216 __func__, iobase, phyiobase, priv);
1217 priv->regs = iobase;
1218 priv->phyregs = phyiobase;
1219 priv->interface = pdata->phy_interface;
1220 priv->model = dev_get_driver_data(dev);
1221
1222 ret = ag7xxx_mdio_probe(dev);
1223 if (ret)
1224 return ret;
1225
1226 priv->bus = miiphy_get_dev_by_name(dev->name);
1227
1228 ret = ag7xxx_mac_probe(dev);
1229 debug("%s, ret=%d\n", __func__, ret);
1230
1231 return ret;
1232}
1233
1234static int ag7xxx_eth_remove(struct udevice *dev)
1235{
1236 struct ar7xxx_eth_priv *priv = dev_get_priv(dev);
1237
1238 free(priv->phydev);
1239 mdio_unregister(priv->bus);
1240 mdio_free(priv->bus);
1241
1242 return 0;
1243}
1244
1245static const struct eth_ops ag7xxx_eth_ops = {
1246 .start = ag7xxx_eth_start,
1247 .send = ag7xxx_eth_send,
1248 .recv = ag7xxx_eth_recv,
1249 .free_pkt = ag7xxx_eth_free_pkt,
1250 .stop = ag7xxx_eth_stop,
1251 .write_hwaddr = ag7xxx_eth_write_hwaddr,
1252};
1253
Simon Glassaad29ae2020-12-03 16:55:21 -07001254static int ag7xxx_eth_of_to_plat(struct udevice *dev)
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001255{
Simon Glassfa20e932020-12-03 16:55:20 -07001256 struct eth_pdata *pdata = dev_get_plat(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001257 int ret;
1258
Masahiro Yamadaa89b4de2020-07-17 14:36:48 +09001259 pdata->iobase = dev_read_addr(dev);
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001260 pdata->phy_interface = -1;
1261
1262 /* Decoding of convoluted PHY wiring on Atheros MIPS. */
1263 ret = ag7xxx_get_phy_iface_offset(dev);
1264 if (ret <= 0)
1265 return ret;
1266
Marek BehĂșnbc194772022-04-07 00:33:01 +02001267 pdata->phy_interface = dev_read_phy_mode(dev);
Marek BehĂșn48631e42022-04-07 00:33:03 +02001268 if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001269 return -EINVAL;
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001270
1271 return 0;
1272}
1273
1274static const struct udevice_id ag7xxx_eth_ids[] = {
1275 { .compatible = "qca,ag933x-mac", .data = AG7XXX_MODEL_AG933X },
1276 { .compatible = "qca,ag934x-mac", .data = AG7XXX_MODEL_AG934X },
Rosy Song361c69e2019-02-05 17:50:44 +08001277 { .compatible = "qca,ag953x-mac", .data = AG7XXX_MODEL_AG953X },
Rosy Song51ef2e72019-03-16 09:24:50 +08001278 { .compatible = "qca,ag956x-mac", .data = AG7XXX_MODEL_AG956X },
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001279 { }
1280};
1281
1282U_BOOT_DRIVER(eth_ag7xxx) = {
1283 .name = "eth_ag7xxx",
1284 .id = UCLASS_ETH,
1285 .of_match = ag7xxx_eth_ids,
Simon Glassaad29ae2020-12-03 16:55:21 -07001286 .of_to_plat = ag7xxx_eth_of_to_plat,
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001287 .probe = ag7xxx_eth_probe,
1288 .remove = ag7xxx_eth_remove,
1289 .ops = &ag7xxx_eth_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -07001290 .priv_auto = sizeof(struct ar7xxx_eth_priv),
Simon Glass71fa5b42020-12-03 16:55:18 -07001291 .plat_auto = sizeof(struct eth_pdata),
Marek Vasut0a3d0e12016-05-24 23:29:09 +02001292 .flags = DM_FLAG_ALLOC_PRIV_DMA,
1293};