u-boot/drivers/net/smc911x.c
Wolfgang Denk c3147c1762 Revert "SMC911x driver fixed for NFS boot"
This reverts commit ca9c8a1e10,
which causes compile warnings ("large integer implicitly truncated
to unsigned type") on all systems that use this driver. The warning
results from passing long constants (TX_CFG, RX_CFG) into
smc911x_set_mac_csr() which is declared to accept "unsigned
character" arguments only.

Being close to a release, with nobody available to actually test the
code or the suggested fixes, it seems better to revert the patch.
2009-06-14 20:31:36 +02:00

256 lines
5.8 KiB
C

/*
* SMSC LAN9[12]1[567] Network driver
*
* (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <command.h>
#include <net.h>
#include <miiphy.h>
#include "smc911x.h"
u32 pkt_data_pull(u32 addr) \
__attribute__ ((weak, alias ("smc911x_reg_read")));
void pkt_data_push(u32 addr, u32 val) \
__attribute__ ((weak, alias ("smc911x_reg_write")));
#define mdelay(n) udelay((n)*1000)
static int smx911x_handle_mac_address(bd_t *bd)
{
unsigned long addrh, addrl;
uchar m[6];
if (eth_getenv_enetaddr("ethaddr", m)) {
/* if the environment has a valid mac address then use it */
addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
addrh = m[4] | (m[5] << 8);
smc911x_set_mac_csr(ADDRL, addrl);
smc911x_set_mac_csr(ADDRH, addrh);
} else {
/* if not, try to get one from the eeprom */
addrh = smc911x_get_mac_csr(ADDRH);
addrl = smc911x_get_mac_csr(ADDRL);
m[0] = (addrl ) & 0xff;
m[1] = (addrl >> 8 ) & 0xff;
m[2] = (addrl >> 16 ) & 0xff;
m[3] = (addrl >> 24 ) & 0xff;
m[4] = (addrh ) & 0xff;
m[5] = (addrh >> 8 ) & 0xff;
/* we get 0xff when there is no eeprom connected */
if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) {
printf(DRIVERNAME ": no valid mac address in environment "
"and no eeprom found\n");
return -1;
}
eth_setenv_enetaddr("ethaddr", m);
}
printf(DRIVERNAME ": MAC %pM\n", m);
return 0;
}
static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val)
{
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY);
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
*val = smc911x_get_mac_csr(MII_DATA);
return 0;
}
static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val)
{
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
smc911x_set_mac_csr(MII_DATA, val);
smc911x_set_mac_csr(MII_ACC,
phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE);
while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY)
;
return 0;
}
static int smc911x_phy_reset(void)
{
u32 reg;
reg = smc911x_reg_read(PMT_CTRL);
reg &= ~0xfffff030;
reg |= PMT_CTRL_PHY_RST;
smc911x_reg_write(PMT_CTRL, reg);
mdelay(100);
return 0;
}
static void smc911x_phy_configure(void)
{
int timeout;
u16 status;
smc911x_phy_reset();
smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET);
mdelay(1);
smc911x_miiphy_write(1, PHY_ANAR, 0x01e1);
smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG);
timeout = 5000;
do {
mdelay(1);
if ((timeout--) == 0)
goto err_out;
if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0)
goto err_out;
} while (!(status & PHY_BMSR_LS));
printf(DRIVERNAME ": phy initialized\n");
return;
err_out:
printf(DRIVERNAME ": autonegotiation timed out\n");
}
static void smc911x_enable(void)
{
/* Enable TX */
smc911x_reg_write(HW_CFG, 8 << 16 | HW_CFG_SF);
smc911x_reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000);
smc911x_reg_write(TX_CFG, TX_CFG_TX_ON);
/* no padding to start of packets */
smc911x_reg_write(RX_CFG, 0);
smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS);
}
int eth_init(bd_t *bd)
{
printf(DRIVERNAME ": initializing\n");
if (smc911x_detect_chip())
goto err_out;
smc911x_reset();
/* Configure the PHY, initialize the link state */
smc911x_phy_configure();
if (smx911x_handle_mac_address(bd))
goto err_out;
/* Turn on Tx + Rx */
smc911x_enable();
return 0;
err_out:
return -1;
}
int eth_send(volatile void *packet, int length)
{
u32 *data = (u32*)packet;
u32 tmplen;
u32 status;
smc911x_reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length);
smc911x_reg_write(TX_DATA_FIFO, length);
tmplen = (length + 3) / 4;
while (tmplen--)
pkt_data_push(TX_DATA_FIFO, *data++);
/* wait for transmission */
while (!((smc911x_reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16));
/* get status. Ignore 'no carrier' error, it has no meaning for
* full duplex operation
*/
status = smc911x_reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL |
TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN);
if (!status)
return 0;
printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n",
status & TX_STS_LOC ? "TX_STS_LOC " : "",
status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "",
status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "",
status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "",
status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : "");
return -1;
}
void eth_halt(void)
{
smc911x_reset();
}
int eth_rx(void)
{
u32 *data = (u32 *)NetRxPackets[0];
u32 pktlen, tmplen;
u32 status;
if ((smc911x_reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) {
status = smc911x_reg_read(RX_STATUS_FIFO);
pktlen = (status & RX_STS_PKT_LEN) >> 16;
smc911x_reg_write(RX_CFG, 0);
tmplen = (pktlen + 2+ 3) / 4;
while (tmplen--)
*data++ = pkt_data_pull(RX_DATA_FIFO);
if (status & RX_STS_ES)
printf(DRIVERNAME
": dropped bad packet. Status: 0x%08x\n",
status);
else
NetReceive(NetRxPackets[0], pktlen);
}
return 0;
}