blob: 45ecd6a263382cb5c2a70dec92b6b8c455147887 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Sascha Hauerde1b6862008-04-15 00:08:20 -04002/*
3 * SMSC LAN9[12]1[567] Network driver
4 *
Stelian Popcce9cfd2008-05-08 22:52:09 +02005 * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
Sascha Hauerde1b6862008-04-15 00:08:20 -04006 */
7
8#include <common.h>
Sascha Hauerde1b6862008-04-15 00:08:20 -04009#include <command.h>
Ben Warren736fead2009-07-20 22:01:11 -070010#include <malloc.h>
Sascha Hauerde1b6862008-04-15 00:08:20 -040011#include <net.h>
12#include <miiphy.h>
Marek Vasutba267c72020-03-15 14:42:23 +010013#include <linux/io.h>
Marek Vasuteb46efa2020-03-15 15:03:07 +010014#include <linux/types.h>
Sascha Hauerde1b6862008-04-15 00:08:20 -040015
Mike Frysinger75ba6d62009-02-23 10:29:47 -050016#include "smc911x.h"
Sascha Hauerde1b6862008-04-15 00:08:20 -040017
Marek Vasuteb46efa2020-03-15 15:03:07 +010018struct chip_id {
19 u16 id;
20 char *name;
21};
22
Marek Vasut3dbab922020-03-15 15:36:09 +010023struct smc911x_priv {
Marek Vasut81486932020-03-15 17:39:01 +010024#ifndef CONFIG_DM_ETH
Marek Vasut3dbab922020-03-15 15:36:09 +010025 struct eth_device dev;
Marek Vasut81486932020-03-15 17:39:01 +010026#endif
Marek Vasut3dbab922020-03-15 15:36:09 +010027 phys_addr_t iobase;
28 const struct chip_id *chipid;
29 unsigned char enetaddr[6];
30};
31
Marek Vasuteb46efa2020-03-15 15:03:07 +010032static const struct chip_id chip_ids[] = {
33 { CHIP_89218, "LAN89218" },
34 { CHIP_9115, "LAN9115" },
35 { CHIP_9116, "LAN9116" },
36 { CHIP_9117, "LAN9117" },
37 { CHIP_9118, "LAN9118" },
38 { CHIP_9211, "LAN9211" },
39 { CHIP_9215, "LAN9215" },
40 { CHIP_9216, "LAN9216" },
41 { CHIP_9217, "LAN9217" },
42 { CHIP_9218, "LAN9218" },
43 { CHIP_9220, "LAN9220" },
44 { CHIP_9221, "LAN9221" },
45 { 0, NULL },
46};
47
48#define DRIVERNAME "smc911x"
49
50#if defined (CONFIG_SMC911X_32_BIT) && \
51 defined (CONFIG_SMC911X_16_BIT)
52#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
53 CONFIG_SMC911X_16_BIT shall be set"
54#endif
55
56#if defined (CONFIG_SMC911X_32_BIT)
Marek Vasut3dbab922020-03-15 15:36:09 +010057static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset)
Marek Vasuteb46efa2020-03-15 15:03:07 +010058{
Marek Vasut3dbab922020-03-15 15:36:09 +010059 return readl(priv->iobase + offset);
Marek Vasuteb46efa2020-03-15 15:03:07 +010060}
Marek Vasuteb46efa2020-03-15 15:03:07 +010061
Marek Vasut3dbab922020-03-15 15:36:09 +010062static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val)
Marek Vasuteb46efa2020-03-15 15:03:07 +010063{
Marek Vasut3dbab922020-03-15 15:36:09 +010064 writel(val, priv->iobase + offset);
Marek Vasuteb46efa2020-03-15 15:03:07 +010065}
Marek Vasuteb46efa2020-03-15 15:03:07 +010066#elif defined (CONFIG_SMC911X_16_BIT)
Marek Vasut3dbab922020-03-15 15:36:09 +010067static u32 smc911x_reg_read(struct smc911x_priv *priv, u32 offset)
Marek Vasuteb46efa2020-03-15 15:03:07 +010068{
Marek Vasut3dbab922020-03-15 15:36:09 +010069 return (readw(priv->iobase + offset) & 0xffff) |
70 (readw(priv->iobase + offset + 2) << 16);
Marek Vasuteb46efa2020-03-15 15:03:07 +010071}
Marek Vasut3dbab922020-03-15 15:36:09 +010072static void smc911x_reg_write(struct smc911x_priv *priv, u32 offset, u32 val)
Marek Vasuteb46efa2020-03-15 15:03:07 +010073{
Marek Vasut3dbab922020-03-15 15:36:09 +010074 writew(val & 0xffff, priv->iobase + offset);
75 writew(val >> 16, priv->iobase + offset + 2);
Marek Vasuteb46efa2020-03-15 15:03:07 +010076}
77#else
78#error "SMC911X: undefined bus width"
79#endif /* CONFIG_SMC911X_16_BIT */
80
Marek Vasut3dbab922020-03-15 15:36:09 +010081static u32 smc911x_get_mac_csr(struct smc911x_priv *priv, u8 reg)
Marek Vasuteb46efa2020-03-15 15:03:07 +010082{
Marek Vasut3dbab922020-03-15 15:36:09 +010083 while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
Marek Vasuteb46efa2020-03-15 15:03:07 +010084 ;
Marek Vasut3dbab922020-03-15 15:36:09 +010085 smc911x_reg_write(priv, MAC_CSR_CMD,
Marek Vasuteb46efa2020-03-15 15:03:07 +010086 MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
Marek Vasut3dbab922020-03-15 15:36:09 +010087 while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
Marek Vasuteb46efa2020-03-15 15:03:07 +010088 ;
89
Marek Vasut3dbab922020-03-15 15:36:09 +010090 return smc911x_reg_read(priv, MAC_CSR_DATA);
Marek Vasuteb46efa2020-03-15 15:03:07 +010091}
92
Marek Vasut3dbab922020-03-15 15:36:09 +010093static void smc911x_set_mac_csr(struct smc911x_priv *priv, u8 reg, u32 data)
Marek Vasuteb46efa2020-03-15 15:03:07 +010094{
Marek Vasut3dbab922020-03-15 15:36:09 +010095 while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
Marek Vasuteb46efa2020-03-15 15:03:07 +010096 ;
Marek Vasut3dbab922020-03-15 15:36:09 +010097 smc911x_reg_write(priv, MAC_CSR_DATA, data);
98 smc911x_reg_write(priv, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
99 while (smc911x_reg_read(priv, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
Marek Vasuteb46efa2020-03-15 15:03:07 +0100100 ;
101}
102
Marek Vasut3dbab922020-03-15 15:36:09 +0100103static int smc911x_detect_chip(struct smc911x_priv *priv)
Marek Vasuteb46efa2020-03-15 15:03:07 +0100104{
105 unsigned long val, i;
106
Marek Vasut3dbab922020-03-15 15:36:09 +0100107 val = smc911x_reg_read(priv, BYTE_TEST);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100108 if (val == 0xffffffff) {
109 /* Special case -- no chip present */
110 return -1;
111 } else if (val != 0x87654321) {
112 printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
113 return -1;
114 }
115
Marek Vasut3dbab922020-03-15 15:36:09 +0100116 val = smc911x_reg_read(priv, ID_REV) >> 16;
Marek Vasuteb46efa2020-03-15 15:03:07 +0100117 for (i = 0; chip_ids[i].id != 0; i++) {
118 if (chip_ids[i].id == val) break;
119 }
120 if (!chip_ids[i].id) {
121 printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
122 return -1;
123 }
124
Marek Vasut3dbab922020-03-15 15:36:09 +0100125 priv->chipid = &chip_ids[i];
Marek Vasuteb46efa2020-03-15 15:03:07 +0100126
127 return 0;
128}
129
Marek Vasut3dbab922020-03-15 15:36:09 +0100130static void smc911x_reset(struct smc911x_priv *priv)
Marek Vasuteb46efa2020-03-15 15:03:07 +0100131{
132 int timeout;
133
134 /*
135 * Take out of PM setting first
136 * Device is already wake up if PMT_CTRL_READY bit is set
137 */
Marek Vasut3dbab922020-03-15 15:36:09 +0100138 if ((smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY) == 0) {
Marek Vasuteb46efa2020-03-15 15:03:07 +0100139 /* Write to the bytetest will take out of powerdown */
Marek Vasut3dbab922020-03-15 15:36:09 +0100140 smc911x_reg_write(priv, BYTE_TEST, 0x0);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100141
142 timeout = 10;
143
144 while (timeout-- &&
Marek Vasut3dbab922020-03-15 15:36:09 +0100145 !(smc911x_reg_read(priv, PMT_CTRL) & PMT_CTRL_READY))
Marek Vasuteb46efa2020-03-15 15:03:07 +0100146 udelay(10);
147 if (timeout < 0) {
148 printf(DRIVERNAME
149 ": timeout waiting for PM restore\n");
150 return;
151 }
152 }
153
154 /* Disable interrupts */
Marek Vasut3dbab922020-03-15 15:36:09 +0100155 smc911x_reg_write(priv, INT_EN, 0);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100156
Marek Vasut3dbab922020-03-15 15:36:09 +0100157 smc911x_reg_write(priv, HW_CFG, HW_CFG_SRST);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100158
159 timeout = 1000;
Marek Vasut3dbab922020-03-15 15:36:09 +0100160 while (timeout-- && smc911x_reg_read(priv, E2P_CMD) & E2P_CMD_EPC_BUSY)
Marek Vasuteb46efa2020-03-15 15:03:07 +0100161 udelay(10);
162
163 if (timeout < 0) {
164 printf(DRIVERNAME ": reset timeout\n");
165 return;
166 }
167
168 /* Reset the FIFO level and flow control settings */
Marek Vasut3dbab922020-03-15 15:36:09 +0100169 smc911x_set_mac_csr(priv, FLOW, FLOW_FCPT | FLOW_FCEN);
170 smc911x_reg_write(priv, AFC_CFG, 0x0050287F);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100171
172 /* Set to LED outputs */
Marek Vasut3dbab922020-03-15 15:36:09 +0100173 smc911x_reg_write(priv, GPIO_CFG, 0x70070000);
Marek Vasuteb46efa2020-03-15 15:03:07 +0100174}
175
Marek Vasut3dbab922020-03-15 15:36:09 +0100176static void smc911x_handle_mac_address(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400177{
178 unsigned long addrh, addrl;
Marek Vasut3dbab922020-03-15 15:36:09 +0100179 unsigned char *m = priv->enetaddr;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400180
Ben Warren736fead2009-07-20 22:01:11 -0700181 addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
182 addrh = m[4] | (m[5] << 8);
Marek Vasut3dbab922020-03-15 15:36:09 +0100183 smc911x_set_mac_csr(priv, ADDRL, addrl);
184 smc911x_set_mac_csr(priv, ADDRH, addrh);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400185
Mike Frysinger03f3d8d2009-02-11 19:09:54 -0500186 printf(DRIVERNAME ": MAC %pM\n", m);
Ben Warren736fead2009-07-20 22:01:11 -0700187}
188
Marek Vasut3dbab922020-03-15 15:36:09 +0100189static int smc911x_eth_phy_read(struct smc911x_priv *priv,
Ben Warren736fead2009-07-20 22:01:11 -0700190 u8 phy, u8 reg, u16 *val)
191{
Marek Vasut3dbab922020-03-15 15:36:09 +0100192 while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
Ben Warren736fead2009-07-20 22:01:11 -0700193 ;
194
Marek Vasut3dbab922020-03-15 15:36:09 +0100195 smc911x_set_mac_csr(priv, MII_ACC, phy << 11 | reg << 6 |
Ben Warren736fead2009-07-20 22:01:11 -0700196 MII_ACC_MII_BUSY);
197
Marek Vasut3dbab922020-03-15 15:36:09 +0100198 while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
Ben Warren736fead2009-07-20 22:01:11 -0700199 ;
200
Marek Vasut3dbab922020-03-15 15:36:09 +0100201 *val = smc911x_get_mac_csr(priv, MII_DATA);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400202
203 return 0;
204}
205
Marek Vasut3dbab922020-03-15 15:36:09 +0100206static int smc911x_eth_phy_write(struct smc911x_priv *priv,
Ben Warren736fead2009-07-20 22:01:11 -0700207 u8 phy, u8 reg, u16 val)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400208{
Marek Vasut3dbab922020-03-15 15:36:09 +0100209 while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
Guennadi Liakhovetski3e0f3312008-04-29 12:35:08 +0000210 ;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400211
Marek Vasut3dbab922020-03-15 15:36:09 +0100212 smc911x_set_mac_csr(priv, MII_DATA, val);
213 smc911x_set_mac_csr(priv, MII_ACC,
Sascha Hauerde1b6862008-04-15 00:08:20 -0400214 phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
215
Marek Vasut3dbab922020-03-15 15:36:09 +0100216 while (smc911x_get_mac_csr(priv, MII_ACC) & MII_ACC_MII_BUSY)
Guennadi Liakhovetski3e0f3312008-04-29 12:35:08 +0000217 ;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400218 return 0;
219}
220
Marek Vasut3dbab922020-03-15 15:36:09 +0100221static int smc911x_phy_reset(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400222{
223 u32 reg;
224
Marek Vasut3dbab922020-03-15 15:36:09 +0100225 reg = smc911x_reg_read(priv, PMT_CTRL);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400226 reg &= ~0xfffff030;
227 reg |= PMT_CTRL_PHY_RST;
Marek Vasut3dbab922020-03-15 15:36:09 +0100228 smc911x_reg_write(priv, PMT_CTRL, reg);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400229
230 mdelay(100);
231
232 return 0;
233}
234
Marek Vasut3dbab922020-03-15 15:36:09 +0100235static void smc911x_phy_configure(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400236{
237 int timeout;
238 u16 status;
239
Marek Vasut3dbab922020-03-15 15:36:09 +0100240 smc911x_phy_reset(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400241
Marek Vasut3dbab922020-03-15 15:36:09 +0100242 smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_RESET);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400243 mdelay(1);
Marek Vasut3dbab922020-03-15 15:36:09 +0100244 smc911x_eth_phy_write(priv, 1, MII_ADVERTISE, 0x01e1);
245 smc911x_eth_phy_write(priv, 1, MII_BMCR, BMCR_ANENABLE |
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500246 BMCR_ANRESTART);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400247
248 timeout = 5000;
249 do {
250 mdelay(1);
251 if ((timeout--) == 0)
252 goto err_out;
253
Marek Vasut3dbab922020-03-15 15:36:09 +0100254 if (smc911x_eth_phy_read(priv, 1, MII_BMSR, &status) != 0)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400255 goto err_out;
Mike Frysinger8ef583a2010-12-23 15:40:12 -0500256 } while (!(status & BMSR_LSTATUS));
Sascha Hauerde1b6862008-04-15 00:08:20 -0400257
258 printf(DRIVERNAME ": phy initialized\n");
259
260 return;
261
262err_out:
263 printf(DRIVERNAME ": autonegotiation timed out\n");
264}
265
Marek Vasut3dbab922020-03-15 15:36:09 +0100266static void smc911x_enable(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400267{
268 /* Enable TX */
Marek Vasut3dbab922020-03-15 15:36:09 +0100269 smc911x_reg_write(priv, HW_CFG, 8 << 16 | HW_CFG_SF);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400270
Marek Vasut3dbab922020-03-15 15:36:09 +0100271 smc911x_reg_write(priv, GPT_CFG, GPT_CFG_TIMER_EN | 10000);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400272
Marek Vasut3dbab922020-03-15 15:36:09 +0100273 smc911x_reg_write(priv, TX_CFG, TX_CFG_TX_ON);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400274
275 /* no padding to start of packets */
Marek Vasut3dbab922020-03-15 15:36:09 +0100276 smc911x_reg_write(priv, RX_CFG, 0);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400277
Marek Vasut3dbab922020-03-15 15:36:09 +0100278 smc911x_set_mac_csr(priv, MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN |
Ben Warren736fead2009-07-20 22:01:11 -0700279 MAC_CR_HBDIS);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400280}
281
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100282static int smc911x_init_common(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400283{
Marek Vasut3dbab922020-03-15 15:36:09 +0100284 const struct chip_id *id = priv->chipid;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400285
Wolfgang Denk49467752009-10-28 00:49:47 +0100286 printf(DRIVERNAME ": detected %s controller\n", id->name);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400287
Marek Vasut3dbab922020-03-15 15:36:09 +0100288 smc911x_reset(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400289
290 /* Configure the PHY, initialize the link state */
Marek Vasut3dbab922020-03-15 15:36:09 +0100291 smc911x_phy_configure(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400292
Marek Vasut3dbab922020-03-15 15:36:09 +0100293 smc911x_handle_mac_address(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400294
295 /* Turn on Tx + Rx */
Marek Vasut3dbab922020-03-15 15:36:09 +0100296 smc911x_enable(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400297
298 return 0;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400299}
300
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100301static int smc911x_send_common(struct smc911x_priv *priv,
302 void *packet, int length)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400303{
304 u32 *data = (u32*)packet;
305 u32 tmplen;
306 u32 status;
307
Marek Vasut3dbab922020-03-15 15:36:09 +0100308 smc911x_reg_write(priv, TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG |
Ben Warren736fead2009-07-20 22:01:11 -0700309 TX_CMD_A_INT_LAST_SEG | length);
Marek Vasut3dbab922020-03-15 15:36:09 +0100310 smc911x_reg_write(priv, TX_DATA_FIFO, length);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400311
312 tmplen = (length + 3) / 4;
313
Guennadi Liakhovetski3e0f3312008-04-29 12:35:08 +0000314 while (tmplen--)
Marek Vasut3dbab922020-03-15 15:36:09 +0100315 smc911x_reg_write(priv, TX_DATA_FIFO, *data++);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400316
317 /* wait for transmission */
Marek Vasut3dbab922020-03-15 15:36:09 +0100318 while (!((smc911x_reg_read(priv, TX_FIFO_INF) &
Ben Warren736fead2009-07-20 22:01:11 -0700319 TX_FIFO_INF_TSUSED) >> 16));
Sascha Hauerde1b6862008-04-15 00:08:20 -0400320
321 /* get status. Ignore 'no carrier' error, it has no meaning for
322 * full duplex operation
323 */
Marek Vasut3dbab922020-03-15 15:36:09 +0100324 status = smc911x_reg_read(priv, TX_STATUS_FIFO) &
Ben Warren736fead2009-07-20 22:01:11 -0700325 (TX_STS_LOC | TX_STS_LATE_COLL | TX_STS_MANY_COLL |
326 TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400327
Guennadi Liakhovetski3e0f3312008-04-29 12:35:08 +0000328 if (!status)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400329 return 0;
330
331 printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n",
332 status & TX_STS_LOC ? "TX_STS_LOC " : "",
333 status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
334 status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
335 status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
336 status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "");
337
338 return -1;
339}
340
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100341static void smc911x_halt_common(struct smc911x_priv *priv)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400342{
Marek Vasut3dbab922020-03-15 15:36:09 +0100343 smc911x_reset(priv);
344 smc911x_handle_mac_address(priv);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400345}
346
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100347static int smc911x_recv_common(struct smc911x_priv *priv, u32 *data)
Sascha Hauerde1b6862008-04-15 00:08:20 -0400348{
Sascha Hauerde1b6862008-04-15 00:08:20 -0400349 u32 pktlen, tmplen;
350 u32 status;
351
Marek Vasutb11c8bb2020-03-15 17:02:05 +0100352 status = smc911x_reg_read(priv, RX_FIFO_INF);
353 if (!(status & RX_FIFO_INF_RXSUSED))
354 return 0;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400355
Marek Vasutb11c8bb2020-03-15 17:02:05 +0100356 status = smc911x_reg_read(priv, RX_STATUS_FIFO);
357 pktlen = (status & RX_STS_PKT_LEN) >> 16;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400358
Marek Vasutb11c8bb2020-03-15 17:02:05 +0100359 smc911x_reg_write(priv, RX_CFG, 0);
Sascha Hauerde1b6862008-04-15 00:08:20 -0400360
Marek Vasutb11c8bb2020-03-15 17:02:05 +0100361 tmplen = (pktlen + 3) / 4;
362 while (tmplen--)
363 *data++ = smc911x_reg_read(priv, RX_DATA_FIFO);
364
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100365 if (status & RX_STS_ES) {
Marek Vasutb11c8bb2020-03-15 17:02:05 +0100366 printf(DRIVERNAME
367 ": dropped bad packet. Status: 0x%08x\n",
368 status);
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100369 return 0;
370 }
Sascha Hauerde1b6862008-04-15 00:08:20 -0400371
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100372 return pktlen;
Sascha Hauerde1b6862008-04-15 00:08:20 -0400373}
Ben Warren736fead2009-07-20 22:01:11 -0700374
Marek Vasut81486932020-03-15 17:39:01 +0100375#ifndef CONFIG_DM_ETH
376
Helmut Raiger6af1d412011-06-29 00:12:14 +0000377#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
378/* wrapper for smc911x_eth_phy_read */
Joe Hershberger5a49f172016-08-08 11:28:38 -0500379static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad,
380 int reg)
Helmut Raiger6af1d412011-06-29 00:12:14 +0000381{
Joe Hershberger5a49f172016-08-08 11:28:38 -0500382 struct eth_device *dev = eth_get_dev_by_name(bus->name);
Marek Vasut3dbab922020-03-15 15:36:09 +0100383 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
Marek Vasut6f6cf002020-03-15 15:43:20 +0100384 u16 val = 0;
385 int ret;
386
Marek Vasut3dbab922020-03-15 15:36:09 +0100387 if (!dev || !priv)
Marek Vasut6f6cf002020-03-15 15:43:20 +0100388 return -ENODEV;
389
Marek Vasut3dbab922020-03-15 15:36:09 +0100390 ret = smc911x_eth_phy_read(priv, phy, reg, &val);
Marek Vasut6f6cf002020-03-15 15:43:20 +0100391 if (ret < 0)
392 return ret;
393
394 return val;
Helmut Raiger6af1d412011-06-29 00:12:14 +0000395}
Marek Vasut3dbab922020-03-15 15:36:09 +0100396
Helmut Raiger6af1d412011-06-29 00:12:14 +0000397/* wrapper for smc911x_eth_phy_write */
Joe Hershberger5a49f172016-08-08 11:28:38 -0500398static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad,
399 int reg, u16 val)
Helmut Raiger6af1d412011-06-29 00:12:14 +0000400{
Joe Hershberger5a49f172016-08-08 11:28:38 -0500401 struct eth_device *dev = eth_get_dev_by_name(bus->name);
Marek Vasut3dbab922020-03-15 15:36:09 +0100402 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
Marek Vasut6f6cf002020-03-15 15:43:20 +0100403
Marek Vasut3dbab922020-03-15 15:36:09 +0100404 if (!dev || !priv)
Marek Vasut6f6cf002020-03-15 15:43:20 +0100405 return -ENODEV;
406
Marek Vasut3dbab922020-03-15 15:36:09 +0100407 return smc911x_eth_phy_write(priv, phy, reg, val);
Helmut Raiger6af1d412011-06-29 00:12:14 +0000408}
Marek Vasutf51a2f82020-03-21 17:25:41 +0100409
Marek Vasut3dbab922020-03-15 15:36:09 +0100410static int smc911x_initialize_mii(struct smc911x_priv *priv)
Marek Vasutf51a2f82020-03-21 17:25:41 +0100411{
412 struct mii_dev *mdiodev = mdio_alloc();
413 int ret;
414
415 if (!mdiodev)
416 return -ENOMEM;
417
Marek Vasut3dbab922020-03-15 15:36:09 +0100418 strncpy(mdiodev->name, priv->dev.name, MDIO_NAME_LEN);
Marek Vasutf51a2f82020-03-21 17:25:41 +0100419 mdiodev->read = smc911x_miiphy_read;
420 mdiodev->write = smc911x_miiphy_write;
421
422 ret = mdio_register(mdiodev);
423 if (ret < 0) {
424 mdio_free(mdiodev);
425 return ret;
426 }
427
428 return 0;
429}
430#else
Marek Vasut3dbab922020-03-15 15:36:09 +0100431static int smc911x_initialize_mii(struct smc911x_priv *priv)
Marek Vasutf51a2f82020-03-21 17:25:41 +0100432{
433 return 0;
434}
Helmut Raiger6af1d412011-06-29 00:12:14 +0000435#endif
436
Marek Vasut8eb4fef2020-03-15 17:25:27 +0100437static int smc911x_init(struct eth_device *dev, bd_t *bd)
438{
439 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
440
441 return smc911x_init_common(priv);
442}
443
444static void smc911x_halt(struct eth_device *dev)
445{
446 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
447
448 smc911x_halt_common(priv);
449}
450
451static int smc911x_send(struct eth_device *dev, void *packet, int length)
452{
453 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
454
455 return smc911x_send_common(priv, packet, length);
456}
457
458static int smc911x_recv(struct eth_device *dev)
459{
460 struct smc911x_priv *priv = container_of(dev, struct smc911x_priv, dev);
461 u32 *data = (u32 *)net_rx_packets[0];
462 int ret;
463
464 ret = smc911x_recv_common(priv, data);
465 if (ret)
466 net_process_received_packet(net_rx_packets[0], ret);
467
468 return ret;
469}
470
Ben Warren736fead2009-07-20 22:01:11 -0700471int smc911x_initialize(u8 dev_num, int base_addr)
472{
473 unsigned long addrl, addrh;
Marek Vasut3dbab922020-03-15 15:36:09 +0100474 struct smc911x_priv *priv;
Marek Vasutf51a2f82020-03-21 17:25:41 +0100475 int ret;
Ben Warren736fead2009-07-20 22:01:11 -0700476
Marek Vasut3dbab922020-03-15 15:36:09 +0100477 priv = calloc(1, sizeof(*priv));
478 if (!priv)
Marek Vasut882d5f62020-03-15 15:14:18 +0100479 return -ENOMEM;
Ben Warren736fead2009-07-20 22:01:11 -0700480
Marek Vasut3dbab922020-03-15 15:36:09 +0100481 priv->iobase = base_addr;
482 priv->dev.iobase = base_addr;
Ben Warren736fead2009-07-20 22:01:11 -0700483
Steve Sakoman4bc3d2a2009-10-20 18:21:18 +0200484 /* Try to detect chip. Will fail if not present. */
Marek Vasut3dbab922020-03-15 15:36:09 +0100485 ret = smc911x_detect_chip(priv);
Marek Vasutf51a2f82020-03-21 17:25:41 +0100486 if (ret) {
487 ret = 0; /* Card not detected is not an error */
488 goto err_detect;
Steve Sakoman4bc3d2a2009-10-20 18:21:18 +0200489 }
490
Marek Vasut3dbab922020-03-15 15:36:09 +0100491 addrh = smc911x_get_mac_csr(priv, ADDRH);
492 addrl = smc911x_get_mac_csr(priv, ADDRL);
Seunghyeon Rhee76771e52009-11-02 00:00:00 -0800493 if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) {
494 /* address is obtained from optional eeprom */
Marek Vasut3dbab922020-03-15 15:36:09 +0100495 priv->enetaddr[0] = addrl;
496 priv->enetaddr[1] = addrl >> 8;
497 priv->enetaddr[2] = addrl >> 16;
498 priv->enetaddr[3] = addrl >> 24;
499 priv->enetaddr[4] = addrh;
500 priv->enetaddr[5] = addrh >> 8;
Marek Vasut81486932020-03-15 17:39:01 +0100501 memcpy(priv->dev.enetaddr, priv->enetaddr, 6);
Seunghyeon Rhee76771e52009-11-02 00:00:00 -0800502 }
Ben Warren736fead2009-07-20 22:01:11 -0700503
Marek Vasut3dbab922020-03-15 15:36:09 +0100504 priv->dev.init = smc911x_init;
505 priv->dev.halt = smc911x_halt;
506 priv->dev.send = smc911x_send;
507 priv->dev.recv = smc911x_recv;
508 sprintf(priv->dev.name, "%s-%hu", DRIVERNAME, dev_num);
Ben Warren736fead2009-07-20 22:01:11 -0700509
Marek Vasut3dbab922020-03-15 15:36:09 +0100510 eth_register(&priv->dev);
Helmut Raiger6af1d412011-06-29 00:12:14 +0000511
Marek Vasut3dbab922020-03-15 15:36:09 +0100512 ret = smc911x_initialize_mii(priv);
Marek Vasutf51a2f82020-03-21 17:25:41 +0100513 if (ret)
514 goto err_mii;
Helmut Raiger6af1d412011-06-29 00:12:14 +0000515
Mike Rapoportfbd47b62009-11-12 15:35:08 +0200516 return 1;
Marek Vasutf51a2f82020-03-21 17:25:41 +0100517
518err_mii:
Marek Vasut3dbab922020-03-15 15:36:09 +0100519 eth_unregister(&priv->dev);
Marek Vasutf51a2f82020-03-21 17:25:41 +0100520err_detect:
Marek Vasut3dbab922020-03-15 15:36:09 +0100521 free(priv);
Marek Vasutf51a2f82020-03-21 17:25:41 +0100522 return ret;
Ben Warren736fead2009-07-20 22:01:11 -0700523}
Marek Vasut81486932020-03-15 17:39:01 +0100524
525#else /* ifdef CONFIG_DM_ETH */
526
527static int smc911x_start(struct udevice *dev)
528{
529 struct eth_pdata *plat = dev_get_platdata(dev);
530 struct smc911x_priv *priv = dev_get_priv(dev);
531
532 memcpy(priv->enetaddr, plat->enetaddr, sizeof(plat->enetaddr));
533
534 return smc911x_init_common(priv);
535}
536
537static void smc911x_stop(struct udevice *dev)
538{
539 struct smc911x_priv *priv = dev_get_priv(dev);
540
541 smc911x_halt_common(priv);
542}
543
544static int smc911x_send(struct udevice *dev, void *packet, int length)
545{
546 struct smc911x_priv *priv = dev_get_priv(dev);
547 int ret;
548
549 ret = smc911x_send_common(priv, packet, length);
550
551 return ret ? 0 : -ETIMEDOUT;
552}
553
554static int smc911x_recv(struct udevice *dev, int flags, uchar **packetp)
555{
556 struct smc911x_priv *priv = dev_get_priv(dev);
557 u32 *data = (u32 *)net_rx_packets[0];
558 int ret;
559
560 ret = smc911x_recv_common(priv, data);
561 if (ret)
562 *packetp = (void *)data;
563
564 return ret ? ret : -EAGAIN;
565}
566
567static int smc911x_bind(struct udevice *dev)
568{
569 return device_set_name(dev, dev->name);
570}
571
572static int smc911x_probe(struct udevice *dev)
573{
574 struct smc911x_priv *priv = dev_get_priv(dev);
575 unsigned long addrh, addrl;
576 int ret;
577
578 /* Try to detect chip. Will fail if not present. */
579 ret = smc911x_detect_chip(priv);
580 if (ret)
581 return ret;
582
583 addrh = smc911x_get_mac_csr(priv, ADDRH);
584 addrl = smc911x_get_mac_csr(priv, ADDRL);
585 if (!(addrl == 0xffffffff && addrh == 0x0000ffff)) {
586 /* address is obtained from optional eeprom */
587 priv->enetaddr[0] = addrl;
588 priv->enetaddr[1] = addrl >> 8;
589 priv->enetaddr[2] = addrl >> 16;
590 priv->enetaddr[3] = addrl >> 24;
591 priv->enetaddr[4] = addrh;
592 priv->enetaddr[5] = addrh >> 8;
593 }
594
595 return 0;
596}
597
598static int smc911x_ofdata_to_platdata(struct udevice *dev)
599{
600 struct smc911x_priv *priv = dev_get_priv(dev);
601 struct eth_pdata *pdata = dev_get_platdata(dev);
602
603 pdata->iobase = devfdt_get_addr(dev);
604 priv->iobase = pdata->iobase;
605
606 return 0;
607}
608
609static const struct eth_ops smc911x_ops = {
610 .start = smc911x_start,
611 .send = smc911x_send,
612 .recv = smc911x_recv,
613 .stop = smc911x_stop,
614};
615
616static const struct udevice_id smc911x_ids[] = {
617 { .compatible = "smsc,lan9115" },
618 { }
619};
620
621U_BOOT_DRIVER(smc911x) = {
622 .name = "eth_smc911x",
623 .id = UCLASS_ETH,
624 .of_match = smc911x_ids,
625 .bind = smc911x_bind,
626 .ofdata_to_platdata = smc911x_ofdata_to_platdata,
627 .probe = smc911x_probe,
628 .ops = &smc911x_ops,
629 .priv_auto_alloc_size = sizeof(struct smc911x_priv),
630 .platdata_auto_alloc_size = sizeof(struct eth_pdata),
631 .flags = DM_FLAG_ALLOC_PRIV_DMA,
632};
633#endif