]>
git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/net/smc911x.c
2 * SMSC LAN9[12]1[567] Network driver
4 * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
6 * SPDX-License-Identifier: GPL-2.0+
17 u32
pkt_data_pull(struct eth_device
*dev
, u32 addr
) \
18 __attribute__ ((weak
, alias ("smc911x_reg_read")));
19 void pkt_data_push(struct eth_device
*dev
, u32 addr
, u32 val
) \
20 __attribute__ ((weak
, alias ("smc911x_reg_write")));
22 static void smc911x_handle_mac_address(struct eth_device
*dev
)
24 unsigned long addrh
, addrl
;
25 uchar
*m
= dev
->enetaddr
;
27 addrl
= m
[0] | (m
[1] << 8) | (m
[2] << 16) | (m
[3] << 24);
28 addrh
= m
[4] | (m
[5] << 8);
29 smc911x_set_mac_csr(dev
, ADDRL
, addrl
);
30 smc911x_set_mac_csr(dev
, ADDRH
, addrh
);
32 printf(DRIVERNAME
": MAC %pM\n", m
);
35 static int smc911x_eth_phy_read(struct eth_device
*dev
,
36 u8 phy
, u8 reg
, u16
*val
)
38 while (smc911x_get_mac_csr(dev
, MII_ACC
) & MII_ACC_MII_BUSY
)
41 smc911x_set_mac_csr(dev
, MII_ACC
, phy
<< 11 | reg
<< 6 |
44 while (smc911x_get_mac_csr(dev
, MII_ACC
) & MII_ACC_MII_BUSY
)
47 *val
= smc911x_get_mac_csr(dev
, MII_DATA
);
52 static int smc911x_eth_phy_write(struct eth_device
*dev
,
53 u8 phy
, u8 reg
, u16 val
)
55 while (smc911x_get_mac_csr(dev
, MII_ACC
) & MII_ACC_MII_BUSY
)
58 smc911x_set_mac_csr(dev
, MII_DATA
, val
);
59 smc911x_set_mac_csr(dev
, MII_ACC
,
60 phy
<< 11 | reg
<< 6 | MII_ACC_MII_BUSY
| MII_ACC_MII_WRITE
);
62 while (smc911x_get_mac_csr(dev
, MII_ACC
) & MII_ACC_MII_BUSY
)
67 static int smc911x_phy_reset(struct eth_device
*dev
)
71 reg
= smc911x_reg_read(dev
, PMT_CTRL
);
73 reg
|= PMT_CTRL_PHY_RST
;
74 smc911x_reg_write(dev
, PMT_CTRL
, reg
);
81 static void smc911x_phy_configure(struct eth_device
*dev
)
86 smc911x_phy_reset(dev
);
88 smc911x_eth_phy_write(dev
, 1, MII_BMCR
, BMCR_RESET
);
90 smc911x_eth_phy_write(dev
, 1, MII_ADVERTISE
, 0x01e1);
91 smc911x_eth_phy_write(dev
, 1, MII_BMCR
, BMCR_ANENABLE
|
100 if (smc911x_eth_phy_read(dev
, 1, MII_BMSR
, &status
) != 0)
102 } while (!(status
& BMSR_LSTATUS
));
104 printf(DRIVERNAME
": phy initialized\n");
109 printf(DRIVERNAME
": autonegotiation timed out\n");
112 static void smc911x_enable(struct eth_device
*dev
)
115 smc911x_reg_write(dev
, HW_CFG
, 8 << 16 | HW_CFG_SF
);
117 smc911x_reg_write(dev
, GPT_CFG
, GPT_CFG_TIMER_EN
| 10000);
119 smc911x_reg_write(dev
, TX_CFG
, TX_CFG_TX_ON
);
121 /* no padding to start of packets */
122 smc911x_reg_write(dev
, RX_CFG
, 0);
124 smc911x_set_mac_csr(dev
, MAC_CR
, MAC_CR_TXEN
| MAC_CR_RXEN
|
129 static int smc911x_init(struct eth_device
*dev
, bd_t
* bd
)
131 struct chip_id
*id
= dev
->priv
;
133 printf(DRIVERNAME
": detected %s controller\n", id
->name
);
137 /* Configure the PHY, initialize the link state */
138 smc911x_phy_configure(dev
);
140 smc911x_handle_mac_address(dev
);
142 /* Turn on Tx + Rx */
148 static int smc911x_send(struct eth_device
*dev
, void *packet
, int length
)
150 u32
*data
= (u32
*)packet
;
154 smc911x_reg_write(dev
, TX_DATA_FIFO
, TX_CMD_A_INT_FIRST_SEG
|
155 TX_CMD_A_INT_LAST_SEG
| length
);
156 smc911x_reg_write(dev
, TX_DATA_FIFO
, length
);
158 tmplen
= (length
+ 3) / 4;
161 pkt_data_push(dev
, TX_DATA_FIFO
, *data
++);
163 /* wait for transmission */
164 while (!((smc911x_reg_read(dev
, TX_FIFO_INF
) &
165 TX_FIFO_INF_TSUSED
) >> 16));
167 /* get status. Ignore 'no carrier' error, it has no meaning for
168 * full duplex operation
170 status
= smc911x_reg_read(dev
, TX_STATUS_FIFO
) &
171 (TX_STS_LOC
| TX_STS_LATE_COLL
| TX_STS_MANY_COLL
|
172 TX_STS_MANY_DEFER
| TX_STS_UNDERRUN
);
177 printf(DRIVERNAME
": failed to send packet: %s%s%s%s%s\n",
178 status
& TX_STS_LOC
? "TX_STS_LOC " : "",
179 status
& TX_STS_LATE_COLL
? "TX_STS_LATE_COLL " : "",
180 status
& TX_STS_MANY_COLL
? "TX_STS_MANY_COLL " : "",
181 status
& TX_STS_MANY_DEFER
? "TX_STS_MANY_DEFER " : "",
182 status
& TX_STS_UNDERRUN
? "TX_STS_UNDERRUN" : "");
187 static void smc911x_halt(struct eth_device
*dev
)
190 smc911x_handle_mac_address(dev
);
193 static int smc911x_rx(struct eth_device
*dev
)
195 u32
*data
= (u32
*)net_rx_packets
[0];
199 if ((smc911x_reg_read(dev
, RX_FIFO_INF
) & RX_FIFO_INF_RXSUSED
) >> 16) {
200 status
= smc911x_reg_read(dev
, RX_STATUS_FIFO
);
201 pktlen
= (status
& RX_STS_PKT_LEN
) >> 16;
203 smc911x_reg_write(dev
, RX_CFG
, 0);
205 tmplen
= (pktlen
+ 3) / 4;
207 *data
++ = pkt_data_pull(dev
, RX_DATA_FIFO
);
209 if (status
& RX_STS_ES
)
211 ": dropped bad packet. Status: 0x%08x\n",
214 net_process_received_packet(net_rx_packets
[0], pktlen
);
220 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
221 /* wrapper for smc911x_eth_phy_read */
222 static int smc911x_miiphy_read(struct mii_dev
*bus
, int phy
, int devad
,
226 struct eth_device
*dev
= eth_get_dev_by_name(bus
->name
);
228 int retval
= smc911x_eth_phy_read(dev
, phy
, reg
, &val
);
235 /* wrapper for smc911x_eth_phy_write */
236 static int smc911x_miiphy_write(struct mii_dev
*bus
, int phy
, int devad
,
239 struct eth_device
*dev
= eth_get_dev_by_name(bus
->name
);
241 return smc911x_eth_phy_write(dev
, phy
, reg
, val
);
246 int smc911x_initialize(u8 dev_num
, int base_addr
)
248 unsigned long addrl
, addrh
;
249 struct eth_device
*dev
;
251 dev
= malloc(sizeof(*dev
));
255 memset(dev
, 0, sizeof(*dev
));
257 dev
->iobase
= base_addr
;
259 /* Try to detect chip. Will fail if not present. */
260 if (smc911x_detect_chip(dev
)) {
265 addrh
= smc911x_get_mac_csr(dev
, ADDRH
);
266 addrl
= smc911x_get_mac_csr(dev
, ADDRL
);
267 if (!(addrl
== 0xffffffff && addrh
== 0x0000ffff)) {
268 /* address is obtained from optional eeprom */
269 dev
->enetaddr
[0] = addrl
;
270 dev
->enetaddr
[1] = addrl
>> 8;
271 dev
->enetaddr
[2] = addrl
>> 16;
272 dev
->enetaddr
[3] = addrl
>> 24;
273 dev
->enetaddr
[4] = addrh
;
274 dev
->enetaddr
[5] = addrh
>> 8;
277 dev
->init
= smc911x_init
;
278 dev
->halt
= smc911x_halt
;
279 dev
->send
= smc911x_send
;
280 dev
->recv
= smc911x_rx
;
281 sprintf(dev
->name
, "%s-%hu", DRIVERNAME
, dev_num
);
285 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
287 struct mii_dev
*mdiodev
= mdio_alloc();
290 strncpy(mdiodev
->name
, dev
->name
, MDIO_NAME_LEN
);
291 mdiodev
->read
= smc911x_miiphy_read
;
292 mdiodev
->write
= smc911x_miiphy_write
;
294 retval
= mdio_register(mdiodev
);