* Based on smc91111_eeprom.c which:
* Heavily borrowed from the following peoples GPL'ed software:
* - Wolfgang Denk, DENX Software Engineering, wd@denx.de
- * Das U-boot
+ * Das U-Boot
* - Ladislav Michl ladis@linux-mips.org
* A rejected patch on the U-Boot mailing list
*/
#include <common.h>
+#include <console.h>
#include <exports.h>
+#include <net.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
#include "../drivers/net/smc911x.h"
+#define DRIVERNAME "smc911x"
+
+#if defined (CONFIG_SMC911X_32_BIT) && \
+ defined (CONFIG_SMC911X_16_BIT)
+#error "SMC911X: Only one of CONFIG_SMC911X_32_BIT and \
+ CONFIG_SMC911X_16_BIT shall be set"
+#endif
+
+struct chip_id {
+ u16 id;
+ char *name;
+};
+
+static const struct chip_id chip_ids[] = {
+ { CHIP_89218, "LAN89218" },
+ { CHIP_9115, "LAN9115" },
+ { CHIP_9116, "LAN9116" },
+ { CHIP_9117, "LAN9117" },
+ { CHIP_9118, "LAN9118" },
+ { CHIP_9211, "LAN9211" },
+ { CHIP_9215, "LAN9215" },
+ { CHIP_9216, "LAN9216" },
+ { CHIP_9217, "LAN9217" },
+ { CHIP_9218, "LAN9218" },
+ { CHIP_9220, "LAN9220" },
+ { CHIP_9221, "LAN9221" },
+ { 0, NULL },
+};
+
+#if defined (CONFIG_SMC911X_32_BIT)
+static u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
+{
+ return *(volatile u32*)(dev->iobase + offset);
+}
+
+static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
+{
+ *(volatile u32*)(dev->iobase + offset) = val;
+}
+#elif defined (CONFIG_SMC911X_16_BIT)
+static u32 smc911x_reg_read(struct eth_device *dev, u32 offset)
+{
+ volatile u16 *addr_16 = (u16 *)(dev->iobase + offset);
+ return (*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16);
+}
+static void smc911x_reg_write(struct eth_device *dev, u32 offset, u32 val)
+{
+ *(volatile u16 *)(dev->iobase + offset) = (u16)val;
+ *(volatile u16 *)(dev->iobase + offset + 2) = (u16)(val >> 16);
+}
+#else
+#error "SMC911X: undefined bus width"
+#endif /* CONFIG_SMC911X_16_BIT */
+
+static u32 smc911x_get_mac_csr(struct eth_device *dev, u8 reg)
+{
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(dev, MAC_CSR_CMD,
+ MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg);
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+
+ return smc911x_reg_read(dev, MAC_CSR_DATA);
+}
+
+static void smc911x_set_mac_csr(struct eth_device *dev, u8 reg, u32 data)
+{
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+ smc911x_reg_write(dev, MAC_CSR_DATA, data);
+ smc911x_reg_write(dev, MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg);
+ while (smc911x_reg_read(dev, MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY)
+ ;
+}
+
+static int smc911x_detect_chip(struct eth_device *dev)
+{
+ unsigned long val, i;
+
+ val = smc911x_reg_read(dev, BYTE_TEST);
+ if (val == 0xffffffff) {
+ /* Special case -- no chip present */
+ return -1;
+ } else if (val != 0x87654321) {
+ printf(DRIVERNAME ": Invalid chip endian 0x%08lx\n", val);
+ return -1;
+ }
+
+ val = smc911x_reg_read(dev, ID_REV) >> 16;
+ for (i = 0; chip_ids[i].id != 0; i++) {
+ if (chip_ids[i].id == val) break;
+ }
+ if (!chip_ids[i].id) {
+ printf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
+ return -1;
+ }
+
+ dev->priv = (void *)&chip_ids[i];
+
+ return 0;
+}
+
+static void smc911x_reset(struct eth_device *dev)
+{
+ int timeout;
+
+ /*
+ * Take out of PM setting first
+ * Device is already wake up if PMT_CTRL_READY bit is set
+ */
+ if ((smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY) == 0) {
+ /* Write to the bytetest will take out of powerdown */
+ smc911x_reg_write(dev, BYTE_TEST, 0x0);
+
+ timeout = 10;
+
+ while (timeout-- &&
+ !(smc911x_reg_read(dev, PMT_CTRL) & PMT_CTRL_READY))
+ udelay(10);
+ if (timeout < 0) {
+ printf(DRIVERNAME
+ ": timeout waiting for PM restore\n");
+ return;
+ }
+ }
+
+ /* Disable interrupts */
+ smc911x_reg_write(dev, INT_EN, 0);
+
+ smc911x_reg_write(dev, HW_CFG, HW_CFG_SRST);
+
+ timeout = 1000;
+ while (timeout-- && smc911x_reg_read(dev, E2P_CMD) & E2P_CMD_EPC_BUSY)
+ udelay(10);
+
+ if (timeout < 0) {
+ printf(DRIVERNAME ": reset timeout\n");
+ return;
+ }
+
+ /* Reset the FIFO level and flow control settings */
+ smc911x_set_mac_csr(dev, FLOW, FLOW_FCPT | FLOW_FCEN);
+ smc911x_reg_write(dev, AFC_CFG, 0x0050287F);
+
+ /* Set to LED outputs */
+ smc911x_reg_write(dev, GPIO_CFG, 0x70070000);
+}
+
/**
* smsc_ctrlc - detect press of CTRL+C (common ctrlc() isnt exported!?)
*/
*/
static char *skip_space(char *buf)
{
- while (buf[0] == ' ' || buf[0] == '\t')
+ while (isblank(buf[0]))
++buf;
return buf;
}
static int smc911x_init(struct eth_device *dev)
{
/* See if there is anything there */
- if (!smc911x_detect_chip(dev))
+ if (smc911x_detect_chip(dev))
return 1;
smc911x_reset(dev);
/**
* smc911x_eeprom - our application's main() function
*/
-int smc911x_eeprom(int argc, char * const argv[])
+int smc911x_eeprom(int argc, char *const argv[])
{
/* Avoid initializing on stack as gcc likes to call memset() */
struct eth_device dev;
continue;
/* Only accept 1 letter commands */
- if (line[0] && line[1] && line[1] != ' ' && line[1] != '\t')
+ if (line[0] && line[1] && !isblank(line[1]))
goto unknown_cmd;
/* Now parse the command */