Merge branch 'master' of git://git.denx.de/u-boot-net
authorTom Rini <trini@ti.com>
Tue, 25 Jun 2013 02:27:44 +0000 (22:27 -0400)
committerTom Rini <trini@ti.com>
Tue, 25 Jun 2013 02:27:44 +0000 (22:27 -0400)
34 files changed:
.checkpatch.conf
board/atmel/at91sam9n12ek/at91sam9n12ek.c
common/cmd_bootm.c
common/cmd_pxe.c
drivers/net/Makefile
drivers/net/designware.c
drivers/net/ftgmac100.c
drivers/net/ftmac110.c [new file with mode: 0644]
drivers/net/ftmac110.h [new file with mode: 0644]
drivers/net/ks8851_mll.c [new file with mode: 0644]
drivers/net/ks8851_mll.h [new file with mode: 0644]
drivers/net/macb.c
drivers/net/macb.h
drivers/net/mvgbe.c
drivers/net/mvgbe.h
drivers/net/phy/Makefile
drivers/net/phy/atheros.c
drivers/net/phy/icplus.c [new file with mode: 0644]
drivers/net/phy/marvell.c
drivers/net/phy/micrel.c
drivers/net/phy/natsemi.c
drivers/net/phy/phy.c
drivers/net/sunxi_wemac.c [new file with mode: 0644]
include/command.h
include/configs/at91sam9n12ek.h
include/linux/ethtool.h
include/linux/mii.h
include/micrel.h
include/net.h
include/netdev.h
include/phy.h
net/link_local.c
net/nfs.c
net/tftp.c

index d88af57129a82cf1b8cf772e9ca02d7c7a20efbb..35167e12015b202a910be77ed075af4dd8425b12 100644 (file)
@@ -18,3 +18,6 @@
 
 # Not Linux, so we don't recommend usleep_range() over udelay()
 --ignore USLEEP_RANGE
+
+# Ignore networking block comment style
+--ignore NETWORKING_BLOCK_COMMENT_STYLE
index 8752794c8435f2e242a50966b9778fdc54a3d889..3013a42a2ecf2123d0f8e963a342fdd8524d68c0 100644 (file)
@@ -33,6 +33,7 @@
 #include <lcd.h>
 #include <atmel_hlcdc.h>
 #include <atmel_mci.h>
+#include <netdev.h>
 
 #ifdef CONFIG_LCD_INFO
 #include <nand.h>
@@ -190,6 +191,30 @@ int board_mmc_init(bd_t *bd)
 }
 #endif
 
+#ifdef CONFIG_KS8851_MLL
+void at91sam9n12ek_ks8851_hw_init(void)
+{
+       struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC;
+
+       writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) |
+              AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
+              &smc->cs[2].setup);
+       writel(AT91_SMC_PULSE_NWE(7) | AT91_SMC_PULSE_NCS_WR(7) |
+              AT91_SMC_PULSE_NRD(7) | AT91_SMC_PULSE_NCS_RD(7),
+              &smc->cs[2].pulse);
+       writel(AT91_SMC_CYCLE_NWE(9) | AT91_SMC_CYCLE_NRD(9),
+              &smc->cs[2].cycle);
+       writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
+              AT91_SMC_MODE_EXNW_DISABLE |
+              AT91_SMC_MODE_BAT | AT91_SMC_MODE_DBW_16 |
+              AT91_SMC_MODE_TDF_CYCLE(1),
+              &smc->cs[2].mode);
+
+       /* Configure NCS2 PIN */
+       at91_set_b_periph(AT91_PIO_PORTD, 19, 0);
+}
+#endif
+
 int board_early_init_f(void)
 {
        /* Enable clocks for all PIOs */
@@ -217,9 +242,20 @@ int board_init(void)
        at91_lcd_hw_init();
 #endif
 
+#ifdef CONFIG_KS8851_MLL
+       at91sam9n12ek_ks8851_hw_init();
+#endif
+
        return 0;
 }
 
+#ifdef CONFIG_KS8851_MLL
+int board_eth_init(bd_t *bis)
+{
+       return ks8851_mll_initialize(0, CONFIG_KS8851_MLL_BASEADDR);
+}
+#endif
+
 int dram_init(void)
 {
        gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,
index 05130b69364c900d380e45fac9c5d27712ad52e7..e452fcac9308ee14e42f0162a561c540d4c763f9 100644 (file)
@@ -1707,7 +1707,7 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
        return 0;
 }
 
-static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        bootm_headers_t images;
 
index 2dbd49cbd6641352786a24110e0d3646f66f7dfc..1fb75d8ae9c1dcdf03e56bf5a3de8eaddfa1bafc 100644 (file)
 
 #define MAX_TFTP_PATH_LEN 127
 
+const char *pxe_default_paths[] = {
+#ifdef CONFIG_SYS_SOC
+       "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
+#endif
+       "default-" CONFIG_SYS_ARCH,
+       "default",
+       NULL
+};
+
 /*
  * Like getenv, but prints an error if envvar isn't defined in the
  * environment.  It always returns what getenv does, so it can be used in
  * place of getenv without changing error handling otherwise.
  */
-static char *from_env(char *envvar)
+static char *from_env(const char *envvar)
 {
        char *ret;
 
@@ -55,37 +64,21 @@ static char *from_env(char *envvar)
  */
 static int format_mac_pxe(char *outbuf, size_t outbuf_len)
 {
-       size_t ethaddr_len;
-       char *p, *ethaddr;
-
-       ethaddr = from_env("ethaddr");
+       uchar ethaddr[6];
 
-       if (!ethaddr)
-               return -ENOENT;
-
-       ethaddr_len = strlen(ethaddr);
-
-       /*
-        * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at
-        * the end.
-        */
-       if (outbuf_len < ethaddr_len + 4) {
-               printf("outbuf is too small (%d < %d)\n",
-                               outbuf_len, ethaddr_len + 4);
+       if (outbuf_len < 21) {
+               printf("outbuf is too small (%d < 21)\n", outbuf_len);
 
                return -EINVAL;
        }
 
-       strcpy(outbuf, "01-");
-
-       for (p = outbuf + 3; *ethaddr; ethaddr++, p++) {
-               if (*ethaddr == ':')
-                       *p = '-';
-               else
-                       *p = tolower(*ethaddr);
-       }
+       if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(),
+                                         ethaddr))
+               return -ENOENT;
 
-       *p = '\0';
+       sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x",
+               ethaddr[0], ethaddr[1], ethaddr[2],
+               ethaddr[3], ethaddr[4], ethaddr[5]);
 
        return 1;
 }
@@ -131,14 +124,14 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path,
        return 1;
 }
 
-static int (*do_getfile)(char *file_path, char *file_addr);
+static int (*do_getfile)(const char *file_path, char *file_addr);
 
-static int do_get_tftp(char *file_path, char *file_addr)
+static int do_get_tftp(const char *file_path, char *file_addr)
 {
        char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
 
        tftp_argv[1] = file_addr;
-       tftp_argv[2] = file_path;
+       tftp_argv[2] = (void *)file_path;
 
        if (do_tftpb(NULL, 0, 3, tftp_argv))
                return -ENOENT;
@@ -148,12 +141,12 @@ static int do_get_tftp(char *file_path, char *file_addr)
 
 static char *fs_argv[5];
 
-static int do_get_ext2(char *file_path, char *file_addr)
+static int do_get_ext2(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_EXT2
        fs_argv[0] = "ext2load";
        fs_argv[3] = file_addr;
-       fs_argv[4] = file_path;
+       fs_argv[4] = (void *)file_path;
 
        if (!do_ext2load(NULL, 0, 5, fs_argv))
                return 1;
@@ -161,12 +154,12 @@ static int do_get_ext2(char *file_path, char *file_addr)
        return -ENOENT;
 }
 
-static int do_get_fat(char *file_path, char *file_addr)
+static int do_get_fat(const char *file_path, char *file_addr)
 {
 #ifdef CONFIG_CMD_FAT
        fs_argv[0] = "fatload";
        fs_argv[3] = file_addr;
-       fs_argv[4] = file_path;
+       fs_argv[4] = (void *)file_path;
 
        if (!do_fat_fsload(NULL, 0, 5, fs_argv))
                return 1;
@@ -182,7 +175,7 @@ static int do_get_fat(char *file_path, char *file_addr)
  *
  * Returns 1 for success, or < 0 on error.
  */
-static int get_relfile(char *file_path, void *file_addr)
+static int get_relfile(const char *file_path, void *file_addr)
 {
        size_t path_len;
        char relfile[MAX_TFTP_PATH_LEN+1];
@@ -221,7 +214,7 @@ static int get_relfile(char *file_path, void *file_addr)
  *
  * Returns 1 on success, or < 0 for error.
  */
-static int get_pxe_file(char *file_path, void *file_addr)
+static int get_pxe_file(const char *file_path, void *file_addr)
 {
        unsigned long config_file_size;
        char *tftp_filesize;
@@ -258,7 +251,7 @@ static int get_pxe_file(char *file_path, void *file_addr)
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_pxelinux_path(char *file, void *pxefile_addr_r)
+static int get_pxelinux_path(const char *file, void *pxefile_addr_r)
 {
        size_t base_len = strlen(PXELINUX_DIR);
        char path[MAX_TFTP_PATH_LEN+1];
@@ -355,7 +348,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        char *pxefile_addr_str;
        unsigned long pxefile_addr_r;
-       int err;
+       int err, i = 0;
 
        do_getfile = do_get_tftp;
 
@@ -376,16 +369,23 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
         * Keep trying paths until we successfully get a file we're looking
         * for.
         */
-       if (pxe_uuid_path((void *)pxefile_addr_r) > 0
-               || pxe_mac_path((void *)pxefile_addr_r) > 0
-               || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0
-               || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) {
-
+       if (pxe_uuid_path((void *)pxefile_addr_r) > 0 ||
+           pxe_mac_path((void *)pxefile_addr_r) > 0 ||
+           pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) {
                printf("Config file found\n");
 
                return 0;
        }
 
+       while (pxe_default_paths[i]) {
+               if (get_pxelinux_path(pxe_default_paths[i],
+                                     (void *)pxefile_addr_r) > 0) {
+                       printf("Config file found\n");
+                       return 0;
+               }
+               i++;
+       }
+
        printf("Config file not found\n");
 
        return 1;
@@ -398,7 +398,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  *
  * Returns 1 on success or < 0 on error.
  */
-static int get_relfile_envaddr(char *file_path, char *envaddr_name)
+static int get_relfile_envaddr(const char *file_path, const char *envaddr_name)
 {
        unsigned long file_addr;
        char *envaddr;
@@ -445,14 +445,17 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name)
  * list - lets these form a list, which a pxe_menu struct will hold.
  */
 struct pxe_label {
+       char num[4];
        char *name;
        char *menu;
        char *kernel;
        char *append;
        char *initrd;
        char *fdt;
+       int ipappend;
        int attempted;
        int localboot;
+       int localboot_val;
        struct list_head list;
 };
 
@@ -533,21 +536,9 @@ static void label_destroy(struct pxe_label *label)
 static void label_print(void *data)
 {
        struct pxe_label *label = data;
-       const char *c = label->menu ? label->menu : label->kernel;
-
-       printf("%s:\t%s\n", label->name, c);
-
-       if (label->kernel)
-               printf("\t\tkernel: %s\n", label->kernel);
-
-       if (label->append)
-               printf("\t\tappend: %s\n", label->append);
+       const char *c = label->menu ? label->menu : label->name;
 
-       if (label->initrd)
-               printf("\t\tinitrd: %s\n", label->initrd);
-
-       if (label->fdt)
-               printf("\tfdt: %s\n", label->fdt);
+       printf("%s:\t%s\n", label->num, c);
 }
 
 /*
@@ -591,34 +582,43 @@ static int label_localboot(struct pxe_label *label)
  * If the label specifies an 'append' line, its contents will overwrite that
  * of the 'bootargs' environment variable.
  */
-static void label_boot(struct pxe_label *label)
+static int label_boot(struct pxe_label *label)
 {
        char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL };
+       char initrd_str[22];
+       char mac_str[29] = "";
+       char ip_str[68] = "";
+       char *bootargs;
        int bootm_argc = 3;
+       int len = 0;
 
        label_print(label);
 
        label->attempted = 1;
 
        if (label->localboot) {
-               label_localboot(label);
-               return;
+               if (label->localboot_val >= 0)
+                       label_localboot(label);
+               return 0;
        }
 
        if (label->kernel == NULL) {
                printf("No kernel given, skipping %s\n",
                                label->name);
-               return;
+               return 1;
        }
 
        if (label->initrd) {
                if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) {
                        printf("Skipping %s for failure retrieving initrd\n",
                                        label->name);
-                       return;
+                       return 1;
                }
 
-               bootm_argv[2] = getenv("ramdisk_addr_r");
+               bootm_argv[2] = initrd_str;
+               strcpy(bootm_argv[2], getenv("ramdisk_addr_r"));
+               strcat(bootm_argv[2], ":");
+               strcat(bootm_argv[2], getenv("filesize"));
        } else {
                bootm_argv[2] = "-";
        }
@@ -626,11 +626,43 @@ static void label_boot(struct pxe_label *label)
        if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) {
                printf("Skipping %s for failure retrieving kernel\n",
                                label->name);
-               return;
+               return 1;
+       }
+
+       if (label->ipappend & 0x1) {
+               sprintf(ip_str, " ip=%s:%s:%s:%s",
+                       getenv("ipaddr"), getenv("serverip"),
+                       getenv("gatewayip"), getenv("netmask"));
+               len += strlen(ip_str);
+       }
+
+       if (label->ipappend & 0x2) {
+               int err;
+               strcpy(mac_str, " BOOTIF=");
+               err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8);
+               if (err < 0)
+                       mac_str[0] = '\0';
+               len += strlen(mac_str);
        }
 
        if (label->append)
-               setenv("bootargs", label->append);
+               len += strlen(label->append);
+
+       if (len) {
+               bootargs = malloc(len + 1);
+               if (!bootargs)
+                       return 1;
+               bootargs[0] = '\0';
+               if (label->append)
+                       strcpy(bootargs, label->append);
+               strcat(bootargs, ip_str);
+               strcat(bootargs, mac_str);
+
+               setenv("bootargs", bootargs);
+               printf("append: %s\n", bootargs);
+
+               free(bootargs);
+       }
 
        bootm_argv[1] = getenv("kernel_addr_r");
 
@@ -654,7 +686,7 @@ static void label_boot(struct pxe_label *label)
                if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) {
                        printf("Skipping %s for failure retrieving fdt\n",
                                        label->name);
-                       return;
+                       return 1;
                }
        } else
                bootm_argv[3] = getenv("fdt_addr");
@@ -663,6 +695,12 @@ static void label_boot(struct pxe_label *label)
                bootm_argc = 4;
 
        do_bootm(NULL, 0, bootm_argc, bootm_argv);
+
+#ifdef CONFIG_CMD_BOOTZ
+       /* Try booting a zImage if do_bootm returns */
+       do_bootz(NULL, 0, bootm_argc, bootm_argv);
+#endif
+       return 1;
 }
 
 /*
@@ -685,6 +723,8 @@ enum token_type {
        T_PROMPT,
        T_INCLUDE,
        T_FDT,
+       T_ONTIMEOUT,
+       T_IPAPPEND,
        T_INVALID
 };
 
@@ -713,6 +753,8 @@ static const struct token keywords[] = {
        {"initrd", T_INITRD},
        {"include", T_INCLUDE},
        {"fdt", T_FDT},
+       {"ontimeout", T_ONTIMEOUT,},
+       {"ipappend", T_IPAPPEND,},
        {NULL, T_INVALID}
 };
 
@@ -903,7 +945,6 @@ static int parse_integer(char **c, int *dst)
 {
        struct token t;
        char *s = *c;
-       unsigned long temp;
 
        get_token(c, &t, L_SLITERAL);
 
@@ -912,12 +953,7 @@ static int parse_integer(char **c, int *dst)
                return -EINVAL;
        }
 
-       if (strict_strtoul(t.val, 10, &temp) < 0) {
-               printf("Expected unsigned integer: %s\n", t.val);
-               return -EINVAL;
-       }
-
-       *dst = (int)temp;
+       *dst = simple_strtol(t.val, NULL, 10);
 
        free(t.val);
 
@@ -1016,10 +1052,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg,
 
        switch (t.type) {
        case T_DEFAULT:
-               if (cfg->default_label)
-                       free(cfg->default_label);
-
-               cfg->default_label = strdup(label->name);
+               if (!cfg->default_label)
+                       cfg->default_label = strdup(label->name);
 
                if (!cfg->default_label)
                        return -ENOMEM;
@@ -1108,7 +1142,12 @@ static int parse_label(char **c, struct pxe_menu *cfg)
                        break;
 
                case T_LOCALBOOT:
-                       err = parse_integer(c, &label->localboot);
+                       label->localboot = 1;
+                       err = parse_integer(c, &label->localboot_val);
+                       break;
+
+               case T_IPAPPEND:
+                       err = parse_integer(c, &label->ipappend);
                        break;
 
                case T_EOL:
@@ -1164,6 +1203,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                err = 0;
                switch (t.type) {
                case T_MENU:
+                       cfg->prompt = 1;
                        err = parse_menu(&p, cfg, b, nest_level);
                        break;
 
@@ -1176,6 +1216,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                        break;
 
                case T_DEFAULT:
+               case T_ONTIMEOUT:
                        err = parse_sliteral(&p, &label_name);
 
                        if (label_name) {
@@ -1193,7 +1234,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level)
                        break;
 
                case T_PROMPT:
-                       err = parse_integer(&p, &cfg->prompt);
+                       eol_or_eof(&p);
                        break;
 
                case T_EOL:
@@ -1276,6 +1317,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        struct list_head *pos;
        struct menu *m;
        int err;
+       int i = 1;
+       char *default_num = NULL;
 
        /*
         * Create a menu and add items for all the labels.
@@ -1289,18 +1332,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg)
        list_for_each(pos, &cfg->labels) {
                label = list_entry(pos, struct pxe_label, list);
 
-               if (menu_item_add(m, label->name, label) != 1) {
+               sprintf(label->num, "%d", i++);
+               if (menu_item_add(m, label->num, label) != 1) {
                        menu_destroy(m);
                        return NULL;
                }
+               if (cfg->default_label &&
+                   (strcmp(label->name, cfg->default_label) == 0))
+                       default_num = label->num;
+
        }
 
        /*
         * After we've created items for each label in the menu, set the
         * menu's default label if one was specified.
         */
-       if (cfg->default_label) {
-               err = menu_default_set(m, cfg->default_label);
+       if (default_num) {
+               err = menu_default_set(m, default_num);
                if (err != 1) {
                        if (err != -ENOENT) {
                                menu_destroy(m);
@@ -1367,10 +1415,13 @@ static void handle_pxe_menu(struct pxe_menu *cfg)
         * we give up.
         */
 
-       if (err == 1)
-               label_boot(choice);
-       else if (err != -ENOENT)
+       if (err == 1) {
+               err = label_boot(choice);
+               if (!err)
+                       return;
+       } else if (err != -ENOENT) {
                return;
+       }
 
        boot_unattempted_labels(cfg);
 }
index 786a6567a5fc9ba5dbfc2c68262a789c5338a2ea..9cf2983d1874a7ef7ac435e747d1c1e780911f42 100644 (file)
@@ -46,10 +46,12 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
 COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
+COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
 COBJS-$(CONFIG_LAN91C96) += lan91c96.o
 COBJS-$(CONFIG_MACB) += macb.o
 COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
@@ -68,6 +70,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o
 COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
 COBJS-$(CONFIG_SMC91111) += smc91111.o
 COBJS-$(CONFIG_SMC911X) += smc911x.o
+COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o
 COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
 COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
 COBJS-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o
index bf21a08bdf475afb81d6335f51cfb84cf4a7e8f9..46f6601fa32e4873f360613f003615d9393b7539 100644 (file)
@@ -113,7 +113,9 @@ static int mac_reset(struct eth_device *dev)
        int timeout = CONFIG_MACRESET_TIMEOUT;
 
        writel(DMAMAC_SRST, &dma_p->busmode);
-       writel(MII_PORTSELECT, &mac_p->conf);
+
+       if (priv->interface != PHY_INTERFACE_MODE_RGMII)
+               writel(MII_PORTSELECT, &mac_p->conf);
 
        start = get_timer(0);
        while (get_timer(start) < timeout) {
index 69ba57d3d006e7638b96106221966b7980389682..2dbb328b8859ef54b5f7e4a417830dd892e750fd 100644 (file)
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>
 
 #include "ftgmac100.h"
 
 #define ETH_ZLEN       60
+#define CFG_XBUF_SIZE  1536
 
 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE     0x640
 #define PKTBUFSTX      4       /* must be power of 2 */
 
 struct ftgmac100_data {
-       struct ftgmac100_txdes txdes[PKTBUFSTX];
-       struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+       ulong txdes_dma;
+       struct ftgmac100_txdes *txdes;
+       ulong rxdes_dma;
+       struct ftgmac100_rxdes *rxdes;
        int tx_index;
        int rx_index;
        int phy_addr;
@@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
        struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
        struct ftgmac100_data *priv = dev->priv;
-       struct ftgmac100_txdes *txdes = priv->txdes;
-       struct ftgmac100_rxdes *rxdes = priv->rxdes;
+       struct ftgmac100_txdes *txdes;
+       struct ftgmac100_rxdes *rxdes;
        unsigned int maccr;
+       void *buf;
        int i;
 
        debug("%s()\n", __func__);
 
+       if (!priv->txdes) {
+               txdes = dma_alloc_coherent(
+                       sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+               if (!txdes)
+                       panic("ftgmac100: out of memory\n");
+               memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+               priv->txdes = txdes;
+       }
+       txdes = priv->txdes;
+
+       if (!priv->rxdes) {
+               rxdes = dma_alloc_coherent(
+                       sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+               if (!rxdes)
+                       panic("ftgmac100: out of memory\n");
+               memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+               priv->rxdes = rxdes;
+       }
+       rxdes = priv->rxdes;
+
        /* set the ethernet address */
        ftgmac100_set_mac_from_env(dev);
 
@@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 
        for (i = 0; i < PKTBUFSTX; i++) {
                /* TXBUF_BADR */
-               txdes[i].txdes3 = 0;
+               if (!txdes[i].txdes2) {
+                       buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+                       if (!buf)
+                               panic("ftgmac100: out of memory\n");
+                       txdes[i].txdes3 = virt_to_phys(buf);
+                       txdes[i].txdes2 = (uint)buf;
+               }
                txdes[i].txdes1 = 0;
        }
 
        for (i = 0; i < PKTBUFSRX; i++) {
                /* RXBUF_BADR */
-               rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+               if (!rxdes[i].rxdes2) {
+                       buf = NetRxPackets[i];
+                       rxdes[i].rxdes3 = virt_to_phys(buf);
+                       rxdes[i].rxdes2 = (uint)buf;
+               }
                rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
        }
 
        /* transmit ring */
-       writel((unsigned int)txdes, &ftgmac100->txr_badr);
+       writel(priv->txdes_dma, &ftgmac100->txr_badr);
 
        /* receive ring */
-       writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+       writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
 
        /* poll receive descriptor automatically */
        writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)
        debug("%s(): RX buffer %d, %x received\n",
               __func__, priv->rx_index, rxlen);
 
+       /* invalidate d-cache */
+       dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
        /* pass the packet up to the protocol layers. */
-       NetReceive((void *)curr_des->rxdes3, rxlen);
+       NetReceive((void *)curr_des->rxdes2, rxlen);
 
        /* release buffer to DMA */
        curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
        struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
        struct ftgmac100_data *priv = dev->priv;
        struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-       int start;
 
        if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
                debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 
        length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
 
-       /* initiate a transmit sequence */
-       curr_des->txdes3 = (unsigned int)packet;        /* TXBUF_BADR */
+       memcpy((void *)curr_des->txdes2, (void *)packet, length);
+       dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
 
        /* only one descriptor on TXBUF */
        curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
        /* start transmit */
        writel(1, &ftgmac100->txpd);
 
-       /* wait for transfer to succeed */
-       start = get_timer(0);
-       while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-               if (get_timer(0) >= 5) {
-                       debug("%s(): timed out\n", __func__);
-                       return -1;
-               }
-       }
-
        debug("%s(): packet sent\n", __func__);
 
        priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644 (file)
index 0000000..579dcc7
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM   8
+#define CFG_TXDES_NUM   2
+#define CFG_XBUF_SIZE   1536
+
+#define CFG_MDIORD_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_MDIOWR_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_LINKUP_TIMEOUT  (CONFIG_SYS_HZ << 2) /* 4 sec */
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+       void __iomem *regs;
+       uint32_t imr;
+       uint32_t maccr;
+       uint32_t lnkup;
+       uint32_t phy_addr;
+
+       struct ftmac110_rxd *rxd;
+       ulong                rxd_dma;
+       uint32_t             rxd_idx;
+
+       struct ftmac110_txd *txd;
+       ulong                txd_dma;
+       uint32_t             txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+       uint8_t phyaddr, uint8_t phyreg)
+{
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_regs __iomem *regs = chip->regs;
+       uint32_t tmp, ts;
+       uint16_t ret = 0xffff;
+
+       tmp = PHYCR_READ
+               | (phyaddr << PHYCR_ADDR_SHIFT)
+               | (phyreg  << PHYCR_REG_SHIFT);
+
+       writel(tmp, &regs->phycr);
+
+       for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+               tmp = readl(&regs->phycr);
+               if (tmp & PHYCR_READ)
+                       continue;
+               break;
+       }
+
+       if (tmp & PHYCR_READ)
+               printf("ftmac110: mdio read timeout\n");
+       else
+               ret = (uint16_t)(tmp & 0xffff);
+
+       return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+       uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_regs __iomem *regs = chip->regs;
+       uint32_t tmp, ts;
+
+       tmp = PHYCR_WRITE
+               | (phyaddr << PHYCR_ADDR_SHIFT)
+               | (phyreg  << PHYCR_REG_SHIFT);
+
+       writel(phydata, &regs->phydr);
+       writel(tmp, &regs->phycr);
+
+       for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+               if (readl(&regs->phycr) & PHYCR_WRITE)
+                       continue;
+               break;
+       }
+
+       if (readl(&regs->phycr) & PHYCR_WRITE)
+               printf("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+       ulong ts;
+       uint32_t maccr;
+       uint16_t pa, tmp, bmsr, bmcr;
+       struct ftmac110_chip *chip = dev->priv;
+
+       /* Default = 100Mbps Full */
+       maccr = MACCR_100M | MACCR_FD;
+
+       /* 1. find the phy device  */
+       for (pa = 0; pa < 32; ++pa) {
+               tmp = mdio_read(dev, pa, MII_PHYSID1);
+               if (tmp == 0xFFFF || tmp == 0x0000)
+                       continue;
+               chip->phy_addr = pa;
+               break;
+       }
+       if (pa >= 32) {
+               puts("ftmac110: phy device not found!\n");
+               goto exit;
+       }
+
+       /* 2. wait until link-up & auto-negotiation complete */
+       chip->lnkup = 0;
+       bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
+       ts = get_timer(0);
+       do {
+               bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
+               chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
+               if (!chip->lnkup)
+                       continue;
+               if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
+                       break;
+       } while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
+       if (!chip->lnkup) {
+               puts("ftmac110: link down\n");
+               goto exit;
+       }
+       if (!(bmcr & BMCR_ANENABLE))
+               puts("ftmac110: auto negotiation disabled\n");
+       else if (!(bmsr & BMSR_ANEGCOMPLETE))
+               puts("ftmac110: auto negotiation timeout\n");
+
+       /* 3. derive MACCR */
+       if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
+               tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+               tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+               if (tmp & LPA_100FULL)      /* 100Mbps full-duplex */
+                       maccr = MACCR_100M | MACCR_FD;
+               else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
+                       maccr = MACCR_100M;
+               else if (tmp & LPA_10FULL)  /* 10Mbps full-duplex */
+                       maccr = MACCR_FD;
+               else if (tmp & LPA_10HALF)  /* 10Mbps half-duplex */
+                       maccr = 0;
+       } else {
+               if (bmcr & BMCR_SPEED100)
+                       maccr = MACCR_100M;
+               else
+                       maccr = 0;
+               if (bmcr & BMCR_FULLDPLX)
+                       maccr |= MACCR_FD;
+       }
+
+exit:
+       printf("ftmac110: %d Mbps, %s\n",
+              (maccr & MACCR_100M) ? 100 : 10,
+              (maccr & MACCR_FD) ? "Full" : "half");
+       return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+       uint8_t *a;
+       uint32_t i, maccr;
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_regs __iomem *regs = chip->regs;
+
+       /* 1. MAC reset */
+       writel(MACCR_RESET, &regs->maccr);
+       for (i = get_timer(0); get_timer(i) < 1000; ) {
+               if (readl(&regs->maccr) & MACCR_RESET)
+                       continue;
+               break;
+       }
+       if (readl(&regs->maccr) & MACCR_RESET) {
+               printf("ftmac110: reset failed\n");
+               return -ENXIO;
+       }
+
+       /* 1-1. Init tx ring */
+       for (i = 0; i < CFG_TXDES_NUM; ++i) {
+               /* owned by SW */
+               chip->txd[i].ct[0] = 0;
+       }
+       chip->txd_idx = 0;
+
+       /* 1-2. Init rx ring */
+       for (i = 0; i < CFG_RXDES_NUM; ++i) {
+               /* owned by HW */
+               chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+       }
+       chip->rxd_idx = 0;
+
+       /* 2. PHY status query */
+       maccr = ftmac110_phyqry(dev);
+
+       /* 3. Fix up the MACCR value */
+       chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+               | MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+
+       /* 4. MAC address setup */
+       a = dev->enetaddr;
+       writel(a[1] | (a[0] << 8), &regs->mac[0]);
+       writel(a[5] | (a[4] << 8) | (a[3] << 16)
+               | (a[2] << 24), &regs->mac[1]);
+
+       /* 5. MAC registers setup */
+       writel(chip->rxd_dma, &regs->rxba);
+       writel(chip->txd_dma, &regs->txba);
+       /* interrupt at each tx/rx */
+       writel(ITC_DEFAULT, &regs->itc);
+       /* no tx pool, rx poll = 1 normal cycle */
+       writel(APTC_DEFAULT, &regs->aptc);
+       /* rx threshold = [6/8 fifo, 2/8 fifo] */
+       writel(DBLAC_DEFAULT, &regs->dblac);
+       /* disable & clear all interrupt status */
+       chip->imr = 0;
+       writel(ISR_ALL, &regs->isr);
+       writel(chip->imr, &regs->imr);
+       /* enable mac */
+       writel(chip->maccr, &regs->maccr);
+
+       return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+       debug("ftmac110: probe\n");
+
+       if (ftmac110_reset(dev))
+               return -1;
+
+       return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_regs __iomem *regs = chip->regs;
+
+       writel(0, &regs->imr);
+       writel(0, &regs->maccr);
+
+       debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
+{
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_regs __iomem *regs = chip->regs;
+       struct ftmac110_txd *des;
+
+       if (!chip->lnkup)
+               return 0;
+
+       if (len <= 0 || len > CFG_XBUF_SIZE) {
+               printf("ftmac110: bad tx pkt len(%d)\n", len);
+               return 0;
+       }
+
+       len = max(60, len);
+
+       des = &chip->txd[chip->txd_idx];
+       if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
+               /* kick-off Tx DMA */
+               writel(0xffffffff, &regs->txpd);
+               printf("ftmac110: out of txd\n");
+               return 0;
+       }
+
+       memcpy(des->vbuf, (void *)pkt, len);
+       dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
+
+       /* update len, fts and lts */
+       des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
+       des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
+               | FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
+
+       /* set owner bit and clear others */
+       des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
+
+       /* kick-off Tx DMA */
+       writel(0xffffffff, &regs->txpd);
+
+       chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+       return len;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+       struct ftmac110_chip *chip = dev->priv;
+       struct ftmac110_rxd *des;
+       uint32_t ct0, len, rlen = 0;
+       uint8_t *buf;
+
+       if (!chip->lnkup)
+               return 0;
+
+       do {
+               des = &chip->rxd[chip->rxd_idx];
+               ct0 = le32_to_cpu(des->ct[0]);
+               if (ct0 & FTMAC110_RXCT0_OWNER)
+                       break;
+
+               len = FTMAC110_RXCT0_LEN(ct0);
+               buf = des->vbuf;
+
+               if (ct0 & FTMAC110_RXCT0_ERRMASK) {
+                       printf("ftmac110: rx error\n");
+               } else {
+                       dma_map_single(buf, len, DMA_FROM_DEVICE);
+                       NetReceive(buf, len);
+                       rlen += len;
+               }
+
+               /* owned by hardware */
+               des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+
+               chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+       } while (0);
+
+       return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+       const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+       int ret = 0;
+       struct eth_device *dev;
+
+       dev = eth_get_dev_by_name(devname);
+       if (dev == NULL) {
+               printf("%s: no such device\n", devname);
+               ret = -1;
+       } else {
+               *value = mdio_read(dev, addr, reg);
+       }
+
+       return ret;
+}
+
+static int ftmac110_mdio_write(
+       const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+       int ret = 0;
+       struct eth_device *dev;
+
+       dev = eth_get_dev_by_name(devname);
+       if (dev == NULL) {
+               printf("%s: no such device\n", devname);
+               ret = -1;
+       } else {
+               mdio_write(dev, addr, reg, value);
+       }
+
+       return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+       int i, card_nr = 0;
+       struct eth_device *dev;
+       struct ftmac110_chip *chip;
+
+       dev = malloc(sizeof(*dev) + sizeof(*chip));
+       if (dev == NULL) {
+               panic("ftmac110: out of memory 1\n");
+               return -1;
+       }
+       chip = (struct ftmac110_chip *)(dev + 1);
+       memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+       sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+       dev->iobase = CONFIG_FTMAC110_BASE;
+       chip->regs = (void __iomem *)dev->iobase;
+       dev->priv = chip;
+       dev->init = ftmac110_probe;
+       dev->halt = ftmac110_halt;
+       dev->send = ftmac110_send;
+       dev->recv = ftmac110_recv;
+
+       if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+               eth_random_enetaddr(dev->enetaddr);
+
+       /* allocate tx descriptors (it must be 16 bytes aligned) */
+       chip->txd = dma_alloc_coherent(
+               sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+       if (!chip->txd)
+               panic("ftmac110: out of memory 3\n");
+       memset(chip->txd, 0,
+              sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+       for (i = 0; i < CFG_TXDES_NUM; ++i) {
+               void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+               if (!va)
+                       panic("ftmac110: out of memory 4\n");
+               chip->txd[i].vbuf  = va;
+               chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va));
+               chip->txd[i].ct[1] = 0;
+               chip->txd[i].ct[0] = 0; /* owned by SW */
+       }
+       chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
+       chip->txd_idx = 0;
+
+       /* allocate rx descriptors (it must be 16 bytes aligned) */
+       chip->rxd = dma_alloc_coherent(
+               sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+       if (!chip->rxd)
+               panic("ftmac110: out of memory 4\n");
+       memset((void *)chip->rxd, 0,
+              sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+       for (i = 0; i < CFG_RXDES_NUM; ++i) {
+               void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+               if (!va)
+                       panic("ftmac110: out of memory 5\n");
+               /* it needs to be exactly 2 bytes aligned */
+               va = ((uint8_t *)va + 2);
+               chip->rxd[i].vbuf  = va;
+               chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va));
+               chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
+               chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+       }
+       chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
+       chip->rxd_idx = 0;
+
+       eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+       miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+       card_nr++;
+
+       return card_nr;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644 (file)
index 0000000..5b2d23b
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+       uint32_t isr;    /* 0x00: Interrups Status Register */
+       uint32_t imr;    /* 0x04: Interrupt Mask Register */
+       uint32_t mac[2]; /* 0x08: MAC Address */
+       uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */
+       uint32_t txpd;   /* 0x18: Tx Poll Demand Register */
+       uint32_t rxpd;   /* 0x1c: Rx Poll Demand Register */
+       uint32_t txba;   /* 0x20: Tx Ring Base Address Register */
+       uint32_t rxba;   /* 0x24: Rx Ring Base Address Register */
+       uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+       uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+       uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+       uint32_t revr;   /* 0x34: Revision Register */
+       uint32_t fear;   /* 0x38: Feature Register */
+       uint32_t rsvd[19];
+       uint32_t maccr;  /* 0x88: MAC Control Register */
+       uint32_t macsr;  /* 0x8C: MAC Status Register */
+       uint32_t phycr;  /* 0x90: PHY Control Register */
+       uint32_t phydr;  /* 0x94: PHY Data Register */
+       uint32_t fcr;    /* 0x98: Flow Control Register */
+       uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/*
+ * Interrupt status/mask register(ISR/IMR) bits
+ */
+#define ISR_ALL          0x3ff
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* tx to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* rx to buffer */
+
+/*
+ * MACCR control bits
+ */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* rx broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* rx multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* tx crc append */
+#define MACCR_RXALL      (1 << 12) /* rx all packets */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* tx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* rx dma enable */
+#define MACCR_TXDMAEN    (1 << 0)  /* tx dma enable */
+
+/*
+ * PHYCR control bits
+ */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * ITC control bits
+ */
+
+/* Tx Cycle Length */
+#define ITC_TX_CYCLONG   (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_TX_CYCNORM   (0 << 15) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_TX_THR(n)    (((n) & 0x7) << 12)
+/* Tx Interrupt Timeout = n * Tx Cycle */
+#define ITC_TX_ITMO(n)   (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define ITC_RX_CYCLONG   (1 << 7)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_RX_CYCNORM   (0 << 7)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_RX_THR(n)    (((n) & 0x7) << 4)
+/* Rx Interrupt Timeout = n * Rx Cycle */
+#define ITC_RX_ITMO(n)   (((n) & 0xf) << 0)
+
+#define ITC_DEFAULT \
+       (ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0))
+
+/*
+ * APTC contrl bits
+ */
+
+/* Tx Cycle Length */
+#define APTC_TX_CYCLONG  (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_TX_CYCNORM  (0 << 12) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */
+#define APTC_TX_PTMO(n)  (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define APTC_RX_CYCLONG  (1 << 4)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_RX_CYCNORM  (0 << 4)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */
+#define APTC_RX_PTMO(n)  (((n) & 0xf) << 0)
+
+#define APTC_DEFAULT     (APTC_TX_PTMO(0) | APTC_RX_PTMO(1))
+
+/*
+ * DBLAC contrl bits
+ */
+#define DBLAC_BURST_MAX_ANY  (0 << 14) /* un-limited */
+#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */
+#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */
+#define DBLAC_RXTHR_EN       (1 << 9)  /* enable rx threshold arbitration */
+#define DBLAC_RXTHR_HIGH(n)  (((n) & 0x7) << 6) /* upper bound = n/8 fifo */
+#define DBLAC_RXTHR_LOW(n)   (((n) & 0x7) << 3) /* lower bound = n/8 fifo */
+#define DBLAC_BURST_CAP16    (1 << 2)  /* support burst 16 */
+#define DBLAC_BURST_CAP8     (1 << 1)  /* support burst 8 */
+#define DBLAC_BURST_CAP4     (1 << 0)  /* support burst 4 */
+
+#define DBLAC_DEFAULT \
+       (DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2))
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+       uint32_t ct[2];
+       uint32_t buf;
+       void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_RXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXCT0_FRS         BIT_MASK(29) /* first pkt desc */
+#define FTMAC110_RXCT0_LRS         BIT_MASK(28) /* last pkt desc */
+#define FTMAC110_RXCT0_ODDNB       BIT_MASK(22) /* odd nibble */
+#define FTMAC110_RXCT0_RUNT        BIT_MASK(21) /* runt pkt */
+#define FTMAC110_RXCT0_FTL         BIT_MASK(20) /* frame too long */
+#define FTMAC110_RXCT0_CRC         BIT_MASK(19) /* pkt crc error */
+#define FTMAC110_RXCT0_ERR         BIT_MASK(18) /* bus error */
+#define FTMAC110_RXCT0_ERRMASK     (0x1f << 18) /* all errors */
+#define FTMAC110_RXCT0_BCST        BIT_MASK(17) /* Bcst pkt */
+#define FTMAC110_RXCT0_MCST        BIT_MASK(16) /* Mcst pkt */
+#define FTMAC110_RXCT0_LEN(x)      ((x) & 0x7ff)
+
+#define FTMAC110_RXCT1_END         BIT_MASK(31)
+#define FTMAC110_RXCT1_BUFSZ(x)    ((x) & 0x7ff)
+
+struct ftmac110_txd {
+       uint32_t ct[2];
+       uint32_t buf;
+       void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_TXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXCT0_COL         0x00000003   /* collision */
+
+#define FTMAC110_TXCT1_END         BIT_MASK(31) /* end of ring */
+#define FTMAC110_TXCT1_TXIC        BIT_MASK(30) /* tx done interrupt */
+#define FTMAC110_TXCT1_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */
+#define FTMAC110_TXCT1_FTS         BIT_MASK(28) /* first pkt desc */
+#define FTMAC110_TXCT1_LTS         BIT_MASK(27) /* last pkt desc */
+#define FTMAC110_TXCT1_LEN(x)      ((x) & 0x7ff)
+
+#endif  /* FTMAC110_H */
diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c
new file mode 100644 (file)
index 0000000..b02d59a
--- /dev/null
@@ -0,0 +1,645 @@
+/*
+ * Micrel KS8851_MLL 16bit Network driver
+ * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+
+#include "ks8851_mll.h"
+
+#define DRIVERNAME                     "ks8851_mll"
+
+#define MAX_RECV_FRAMES                        32
+#define MAX_BUF_SIZE                   2048
+#define TX_BUF_SIZE                    2000
+#define RX_BUF_SIZE                    2000
+
+static const struct chip_id chip_ids[] =  {
+       {CIDER_ID, "KSZ8851"},
+       {0, NULL},
+};
+
+/*
+ * union ks_tx_hdr - tx header data
+ * @txb: The header as bytes
+ * @txw: The header as 16bit, little-endian words
+ *
+ * A dual representation of the tx header data to allow
+ * access to individual bytes, and to allow 16bit accesses
+ * with 16bit alignment.
+ */
+union ks_tx_hdr {
+       u8      txb[4];
+       __le16  txw[2];
+};
+
+/*
+ * struct ks_net - KS8851 driver private data
+ * @net_device : The network device we're bound to
+ * @txh                : temporaly buffer to save status/length.
+ * @frame_head_info    : frame header information for multi-pkt rx.
+ * @statelock  : Lock on this structure for tx list.
+ * @msg_enable : The message flags controlling driver output (see ethtool).
+ * @frame_cnt  : number of frames received.
+ * @bus_width  : i/o bus width.
+ * @irq                : irq number assigned to this device.
+ * @rc_rxqcr   : Cached copy of KS_RXQCR.
+ * @rc_txcr    : Cached copy of KS_TXCR.
+ * @rc_ier     : Cached copy of KS_IER.
+ * @sharedbus  : Multipex(addr and data bus) mode indicator.
+ * @cmd_reg_cache      : command register cached.
+ * @cmd_reg_cache_int  : command register cached. Used in the irq handler.
+ * @promiscuous        : promiscuous mode indicator.
+ * @all_mcast  : mutlicast indicator.
+ * @mcast_lst_size     : size of multicast list.
+ * @mcast_lst          : multicast list.
+ * @mcast_bits         : multicast enabed.
+ * @mac_addr           : MAC address assigned to this device.
+ * @fid                        : frame id.
+ * @extra_byte         : number of extra byte prepended rx pkt.
+ * @enabled            : indicator this device works.
+ */
+
+/* Receive multiplex framer header info */
+struct type_frame_head {
+       u16     sts;         /* Frame status */
+       u16     len;         /* Byte count */
+} fr_h_i[MAX_RECV_FRAMES];
+
+struct ks_net {
+       struct net_device       *netdev;
+       union ks_tx_hdr         txh;
+       struct type_frame_head  *frame_head_info;
+       u32                     msg_enable;
+       u32                     frame_cnt;
+       int                     bus_width;
+       int                     irq;
+       u16                     rc_rxqcr;
+       u16                     rc_txcr;
+       u16                     rc_ier;
+       u16                     sharedbus;
+       u16                     cmd_reg_cache;
+       u16                     cmd_reg_cache_int;
+       u16                     promiscuous;
+       u16                     all_mcast;
+       u16                     mcast_lst_size;
+       u8                      mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN];
+       u8                      mcast_bits[HW_MCAST_SIZE];
+       u8                      mac_addr[6];
+       u8                      fid;
+       u8                      extra_byte;
+       u8                      enabled;
+} ks_str, *ks;
+
+#define BE3             0x8000      /* Byte Enable 3 */
+#define BE2             0x4000      /* Byte Enable 2 */
+#define BE1             0x2000      /* Byte Enable 1 */
+#define BE0             0x1000      /* Byte Enable 0 */
+
+static u8 ks_rdreg8(struct eth_device *dev, u16 offset)
+{
+       u8 shift_bit = offset & 0x03;
+       u8 shift_data = (offset & 1) << 3;
+
+       writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+
+       return (u8)(readw(dev->iobase) >> shift_data);
+}
+
+static u16 ks_rdreg16(struct eth_device *dev, u16 offset)
+{
+       writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+
+       return readw(dev->iobase);
+}
+
+static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val)
+{
+       u8 shift_bit = (offset & 0x03);
+       u16 value_write = (u16)(val << ((offset & 1) << 3));
+
+       writew(offset | (BE0 << shift_bit), dev->iobase + 2);
+       writew(value_write, dev->iobase);
+}
+
+static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val)
+{
+       writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2);
+       writew(val, dev->iobase);
+}
+
+/*
+ * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode
+ * enabled.
+ * @ks: The chip state
+ * @wptr: buffer address to save data
+ * @len: length in byte to read
+ */
+static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+       len >>= 1;
+
+       while (len--)
+               *wptr++ = readw(dev->iobase);
+}
+
+/*
+ * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled.
+ * @ks: The chip information
+ * @wptr: buffer address
+ * @len: length in byte to write
+ */
+static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len)
+{
+       len >>= 1;
+
+       while (len--)
+               writew(*wptr++, dev->iobase);
+}
+
+static void ks_enable_int(struct eth_device *dev)
+{
+       ks_wrreg16(dev, KS_IER, ks->rc_ier);
+}
+
+static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode)
+{
+       unsigned pmecr;
+
+       ks_rdreg16(dev, KS_GRR);
+       pmecr = ks_rdreg16(dev, KS_PMECR);
+       pmecr &= ~PMECR_PM_MASK;
+       pmecr |= pwrmode;
+
+       ks_wrreg16(dev, KS_PMECR, pmecr);
+}
+
+/*
+ * ks_read_config - read chip configuration of bus width.
+ * @ks: The chip information
+ */
+static void ks_read_config(struct eth_device *dev)
+{
+       u16 reg_data = 0;
+
+       /* Regardless of bus width, 8 bit read should always work. */
+       reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF;
+       reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8;
+
+       /* addr/data bus are multiplexed */
+       ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED;
+
+       /*
+        * There are garbage data when reading data from QMU,
+        * depending on bus-width.
+        */
+       if (reg_data & CCR_8BIT) {
+               ks->bus_width = ENUM_BUS_8BIT;
+               ks->extra_byte = 1;
+       } else if (reg_data & CCR_16BIT) {
+               ks->bus_width = ENUM_BUS_16BIT;
+               ks->extra_byte = 2;
+       } else {
+               ks->bus_width = ENUM_BUS_32BIT;
+               ks->extra_byte = 4;
+       }
+}
+
+/*
+ * ks_soft_reset - issue one of the soft reset to the device
+ * @ks: The device state.
+ * @op: The bit(s) to set in the GRR
+ *
+ * Issue the relevant soft-reset command to the device's GRR register
+ * specified by @op.
+ *
+ * Note, the delays are in there as a caution to ensure that the reset
+ * has time to take effect and then complete. Since the datasheet does
+ * not currently specify the exact sequence, we have chosen something
+ * that seems to work with our device.
+ */
+static void ks_soft_reset(struct eth_device *dev, unsigned op)
+{
+       /* Disable interrupt first */
+       ks_wrreg16(dev, KS_IER, 0x0000);
+       ks_wrreg16(dev, KS_GRR, op);
+       mdelay(10);     /* wait a short time to effect reset */
+       ks_wrreg16(dev, KS_GRR, 0);
+       mdelay(1);      /* wait for condition to clear */
+}
+
+void ks_enable_qmu(struct eth_device *dev)
+{
+       u16 w;
+
+       w = ks_rdreg16(dev, KS_TXCR);
+
+       /* Enables QMU Transmit (TXCR). */
+       ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE);
+
+       /* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */
+       w = ks_rdreg16(dev, KS_RXQCR);
+       ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE);
+
+       /* Enables QMU Receive (RXCR1). */
+       w = ks_rdreg16(dev, KS_RXCR1);
+       ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE);
+}
+
+static void ks_disable_qmu(struct eth_device *dev)
+{
+       u16 w;
+
+       w = ks_rdreg16(dev, KS_TXCR);
+
+       /* Disables QMU Transmit (TXCR). */
+       w &= ~TXCR_TXE;
+       ks_wrreg16(dev, KS_TXCR, w);
+
+       /* Disables QMU Receive (RXCR1). */
+       w = ks_rdreg16(dev, KS_RXCR1);
+       w &= ~RXCR1_RXE;
+       ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len)
+{
+       u32 r = ks->extra_byte & 0x1;
+       u32 w = ks->extra_byte - r;
+
+       /* 1. set sudo DMA mode */
+       ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+       ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+
+       /*
+        * 2. read prepend data
+        *
+        * read 4 + extra bytes and discard them.
+        * extra bytes for dummy, 2 for status, 2 for len
+        */
+
+       if (r)
+               ks_rdreg8(dev, 0);
+
+       ks_inblk(dev, buf, w + 2 + 2);
+
+       /* 3. read pkt data */
+       ks_inblk(dev, buf, ALIGN(len, 4));
+
+       /* 4. reset sudo DMA Mode */
+       ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+}
+
+static void ks_rcv(struct eth_device *dev, uchar **pv_data)
+{
+       struct type_frame_head *frame_hdr = ks->frame_head_info;
+       int i;
+
+       ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8;
+
+       /* read all header information */
+       for (i = 0; i < ks->frame_cnt; i++) {
+               /* Checking Received packet status */
+               frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR);
+               /* Get packet len from hardware */
+               frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR);
+               frame_hdr++;
+       }
+
+       frame_hdr = ks->frame_head_info;
+       while (ks->frame_cnt--) {
+               if ((frame_hdr->sts & RXFSHR_RXFV) &&
+                   (frame_hdr->len < RX_BUF_SIZE) &&
+                   frame_hdr->len) {
+                       /* read data block including CRC 4 bytes */
+                       ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len);
+
+                       /* NetRxPackets buffer size is ok (*pv_data pointer) */
+                       NetReceive(*pv_data, frame_hdr->len);
+                       pv_data++;
+               } else {
+                       ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF));
+                       printf(DRIVERNAME ": bad packet\n");
+               }
+               frame_hdr++;
+       }
+}
+
+/*
+ * ks_read_selftest - read the selftest memory info.
+ * @ks: The device state
+ *
+ * Read and check the TX/RX memory selftest information.
+ */
+static int ks_read_selftest(struct eth_device *dev)
+{
+       u16 both_done = MBIR_TXMBF | MBIR_RXMBF;
+       u16 mbir;
+       int ret = 0;
+
+       mbir = ks_rdreg16(dev, KS_MBIR);
+
+       if ((mbir & both_done) != both_done) {
+               printf(DRIVERNAME ": Memory selftest not finished\n");
+               return 0;
+       }
+
+       if (mbir & MBIR_TXMBFA) {
+               printf(DRIVERNAME ": TX memory selftest fails\n");
+               ret |= 1;
+       }
+
+       if (mbir & MBIR_RXMBFA) {
+               printf(DRIVERNAME ": RX memory selftest fails\n");
+               ret |= 2;
+       }
+
+       debug(DRIVERNAME ": the selftest passes\n");
+
+       return ret;
+}
+
+static void ks_setup(struct eth_device *dev)
+{
+       u16 w;
+
+       /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */
+       ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+
+       /* Setup Receive Frame Data Pointer Auto-Increment */
+       ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI);
+
+       /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */
+       ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK);
+
+       /* Setup RxQ Command Control (RXQCR) */
+       ks->rc_rxqcr = RXQCR_CMD_CNTL;
+       ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr);
+
+       /*
+        * set the force mode to half duplex, default is full duplex
+        * because if the auto-negotiation fails, most switch uses
+        * half-duplex.
+        */
+       w = ks_rdreg16(dev, KS_P1MBCR);
+       w &= ~P1MBCR_FORCE_FDX;
+       ks_wrreg16(dev, KS_P1MBCR, w);
+
+       w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP;
+       ks_wrreg16(dev, KS_TXCR, w);
+
+       w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC;
+
+       /* Normal mode */
+       w |= RXCR1_RXPAFMA;
+
+       ks_wrreg16(dev, KS_RXCR1, w);
+}
+
+static void ks_setup_int(struct eth_device *dev)
+{
+       ks->rc_ier = 0x00;
+
+       /* Clear the interrupts status of the hardware. */
+       ks_wrreg16(dev, KS_ISR, 0xffff);
+
+       /* Enables the interrupts of the hardware. */
+       ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI);
+}
+
+static int ks8851_mll_detect_chip(struct eth_device *dev)
+{
+       unsigned short val, i;
+
+       ks_read_config(dev);
+
+       val = ks_rdreg16(dev, KS_CIDER);
+
+       if (val == 0xffff) {
+               /* Special case -- no chip present */
+               printf(DRIVERNAME ":  is chip mounted ?\n");
+               return -1;
+       } else if ((val & 0xfff0) != CIDER_ID) {
+               printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val);
+               return -1;
+       }
+
+       debug("Read back KS8851 id 0x%x\n", val);
+
+       /* only one entry in the table */
+       val &= 0xfff0;
+       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 %04x\n", val);
+               return -1;
+       }
+
+       dev->priv = (void *)&chip_ids[i];
+
+       return 0;
+}
+
+static void ks8851_mll_reset(struct eth_device *dev)
+{
+       /* wake up powermode to normal mode */
+       ks_set_powermode(dev, PMECR_PM_NORMAL);
+       mdelay(1);      /* wait for normal mode to take effect */
+
+       /* Disable interrupt and reset */
+       ks_soft_reset(dev, GRR_GSR);
+
+       /* turn off the IRQs and ack any outstanding */
+       ks_wrreg16(dev, KS_IER, 0x0000);
+       ks_wrreg16(dev, KS_ISR, 0xffff);
+
+       /* shutdown RX/TX QMU */
+       ks_disable_qmu(dev);
+}
+
+static void ks8851_mll_phy_configure(struct eth_device *dev)
+{
+       u16 data;
+
+       ks_setup(dev);
+       ks_setup_int(dev);
+
+       /* Probing the phy */
+       data = ks_rdreg16(dev, KS_OBCR);
+       ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA);
+
+       debug(DRIVERNAME ": phy initialized\n");
+}
+
+static void ks8851_mll_enable(struct eth_device *dev)
+{
+       ks_wrreg16(dev, KS_ISR, 0xffff);
+       ks_enable_int(dev);
+       ks_enable_qmu(dev);
+}
+
+static int ks8851_mll_init(struct eth_device *dev, bd_t *bd)
+{
+       struct chip_id *id = dev->priv;
+
+       debug(DRIVERNAME ": detected %s controller\n", id->name);
+
+       if (ks_read_selftest(dev)) {
+               printf(DRIVERNAME ": Selftest failed\n");
+               return -1;
+       }
+
+       ks8851_mll_reset(dev);
+
+       /* Configure the PHY, initialize the link state */
+       ks8851_mll_phy_configure(dev);
+
+       /* static allocation of private informations */
+       ks->frame_head_info = fr_h_i;
+
+       /* Turn on Tx + Rx */
+       ks8851_mll_enable(dev);
+
+       return 0;
+}
+
+static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len)
+{
+       /* start header at txb[0] to align txw entries */
+       ks->txh.txw[0] = 0;
+       ks->txh.txw[1] = cpu_to_le16(len);
+
+       /* 1. set sudo-DMA mode */
+       ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI);
+       ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff);
+       /* 2. write status/lenth info */
+       ks_outblk(dev, ks->txh.txw, 4);
+       /* 3. write pkt data */
+       ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4));
+       /* 4. reset sudo-DMA mode */
+       ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff);
+       /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */
+       ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE);
+       /* 6. wait until TXQCR_METFE is auto-cleared */
+       do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE);
+}
+
+static int ks8851_mll_send(struct eth_device *dev, void *packet, int length)
+{
+       u8 *data = (u8 *)packet;
+       u16 tmplen = (u16)length;
+       u16 retv;
+
+       /*
+        * Extra space are required:
+        * 4 byte for alignment, 4 for status/length, 4 for CRC
+        */
+       retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff;
+       if (retv >= tmplen + 12) {
+               ks_write_qmu(dev, data, tmplen);
+               return 0;
+       } else {
+               printf(DRIVERNAME ": failed to send packet: No buffer\n");
+               return -1;
+       }
+}
+
+static void ks8851_mll_halt(struct eth_device *dev)
+{
+       ks8851_mll_reset(dev);
+}
+
+/*
+ * Maximum receive ring size; that is, the number of packets
+ * we can buffer before overflow happens. Basically, this just
+ * needs to be enough to prevent a packet being discarded while
+ * we are processing the previous one.
+ */
+static int ks8851_mll_recv(struct eth_device *dev)
+{
+       u16 status;
+
+       status = ks_rdreg16(dev, KS_ISR);
+
+       ks_wrreg16(dev, KS_ISR, status);
+
+       if ((status & IRQ_RXI))
+               ks_rcv(dev, (uchar **)NetRxPackets);
+
+       if ((status & IRQ_LDI)) {
+               u16 pmecr = ks_rdreg16(dev, KS_PMECR);
+               pmecr &= ~PMECR_WKEVT_MASK;
+               ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK);
+       }
+
+       return 0;
+}
+
+static int ks8851_mll_write_hwaddr(struct eth_device *dev)
+{
+       u16 addrl, addrm, addrh;
+
+       addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1];
+       addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3];
+       addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5];
+
+       ks_wrreg16(dev, KS_MARH, addrh);
+       ks_wrreg16(dev, KS_MARM, addrm);
+       ks_wrreg16(dev, KS_MARL, addrl);
+
+       return 0;
+}
+
+int ks8851_mll_initialize(u8 dev_num, int base_addr)
+{
+       struct eth_device *dev;
+
+       dev = malloc(sizeof(*dev));
+       if (!dev) {
+               printf("Error: Failed to allocate memory\n");
+               return -1;
+       }
+       memset(dev, 0, sizeof(*dev));
+
+       dev->iobase = base_addr;
+
+       ks = &ks_str;
+
+       /* Try to detect chip. Will fail if not present. */
+       if (ks8851_mll_detect_chip(dev)) {
+               free(dev);
+               return -1;
+       }
+
+       dev->init = ks8851_mll_init;
+       dev->halt = ks8851_mll_halt;
+       dev->send = ks8851_mll_send;
+       dev->recv = ks8851_mll_recv;
+       dev->write_hwaddr = ks8851_mll_write_hwaddr;
+       sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num);
+
+       eth_register(dev);
+
+       return 0;
+}
diff --git a/drivers/net/ks8851_mll.h b/drivers/net/ks8851_mll.h
new file mode 100644 (file)
index 0000000..7f90ae4
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * drivers/net/ks8851_mll.c
+ *
+ * Supports:
+ * KS8851 16bit MLL chip from Micrel Inc.
+ *
+ * Copyright (c) 2009 Micrel Inc.
+ *
+ * modified by
+ * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _KS8851_MLL_H_
+#define _KS8851_MLL_H_
+
+#include <linux/types.h>
+
+#define KS_CCR                         0x08
+#define CCR_EEPROM                     (1 << 9)
+#define CCR_SPI                                (1 << 8)
+#define CCR_8BIT                       (1 << 7)
+#define CCR_16BIT                      (1 << 6)
+#define CCR_32BIT                      (1 << 5)
+#define CCR_SHARED                     (1 << 4)
+#define CCR_32PIN                      (1 << 0)
+
+/* MAC address registers */
+#define KS_MARL                                0x10
+#define KS_MARM                                0x12
+#define KS_MARH                                0x14
+
+#define KS_OBCR                                0x20
+#define OBCR_ODS_16MA                  (1 << 6)
+
+#define KS_EEPCR                       0x22
+#define EEPCR_EESA                     (1 << 4)
+#define EEPCR_EESB                     (1 << 3)
+#define EEPCR_EEDO                     (1 << 2)
+#define EEPCR_EESCK                    (1 << 1)
+#define EEPCR_EECS                     (1 << 0)
+
+#define KS_MBIR                                0x24
+#define MBIR_TXMBF                     (1 << 12)
+#define MBIR_TXMBFA                    (1 << 11)
+#define MBIR_RXMBF                     (1 << 4)
+#define MBIR_RXMBFA                    (1 << 3)
+
+#define KS_GRR                         0x26
+#define GRR_QMU                                (1 << 1)
+#define GRR_GSR                                (1 << 0)
+
+#define KS_WFCR                                0x2A
+#define WFCR_MPRXE                     (1 << 7)
+#define WFCR_WF3E                      (1 << 3)
+#define WFCR_WF2E                      (1 << 2)
+#define WFCR_WF1E                      (1 << 1)
+#define WFCR_WF0E                      (1 << 0)
+
+#define KS_WF0CRC0                     0x30
+#define KS_WF0CRC1                     0x32
+#define KS_WF0BM0                      0x34
+#define KS_WF0BM1                      0x36
+#define KS_WF0BM2                      0x38
+#define KS_WF0BM3                      0x3A
+
+#define KS_WF1CRC0                     0x40
+#define KS_WF1CRC1                     0x42
+#define KS_WF1BM0                      0x44
+#define KS_WF1BM1                      0x46
+#define KS_WF1BM2                      0x48
+#define KS_WF1BM3                      0x4A
+
+#define KS_WF2CRC0                     0x50
+#define KS_WF2CRC1                     0x52
+#define KS_WF2BM0                      0x54
+#define KS_WF2BM1                      0x56
+#define KS_WF2BM2                      0x58
+#define KS_WF2BM3                      0x5A
+
+#define KS_WF3CRC0                     0x60
+#define KS_WF3CRC1                     0x62
+#define KS_WF3BM0                      0x64
+#define KS_WF3BM1                      0x66
+#define KS_WF3BM2                      0x68
+#define KS_WF3BM3                      0x6A
+
+#define KS_TXCR                                0x70
+#define TXCR_TCGICMP                   (1 << 8)
+#define TXCR_TCGUDP                    (1 << 7)
+#define TXCR_TCGTCP                    (1 << 6)
+#define TXCR_TCGIP                     (1 << 5)
+#define TXCR_FTXQ                      (1 << 4)
+#define TXCR_TXFCE                     (1 << 3)
+#define TXCR_TXPE                      (1 << 2)
+#define TXCR_TXCRC                     (1 << 1)
+#define TXCR_TXE                       (1 << 0)
+
+#define KS_TXSR                                0x72
+#define TXSR_TXLC                      (1 << 13)
+#define TXSR_TXMC                      (1 << 12)
+#define TXSR_TXFID_MASK                        (0x3f << 0)
+#define TXSR_TXFID_SHIFT               (0)
+#define TXSR_TXFID_GET(_v)             (((_v) >> 0) & 0x3f)
+
+
+#define KS_RXCR1                       0x74
+#define RXCR1_FRXQ                     (1 << 15)
+#define RXCR1_RXUDPFCC                 (1 << 14)
+#define RXCR1_RXTCPFCC                 (1 << 13)
+#define RXCR1_RXIPFCC                  (1 << 12)
+#define RXCR1_RXPAFMA                  (1 << 11)
+#define RXCR1_RXFCE                    (1 << 10)
+#define RXCR1_RXEFE                    (1 << 9)
+#define RXCR1_RXMAFMA                  (1 << 8)
+#define RXCR1_RXBE                     (1 << 7)
+#define RXCR1_RXME                     (1 << 6)
+#define RXCR1_RXUE                     (1 << 5)
+#define RXCR1_RXAE                     (1 << 4)
+#define RXCR1_RXINVF                   (1 << 1)
+#define RXCR1_RXE                      (1 << 0)
+#define RXCR1_FILTER_MASK              (RXCR1_RXINVF | RXCR1_RXAE | \
+                                        RXCR1_RXMAFMA | RXCR1_RXPAFMA)
+
+#define KS_RXCR2                       0x76
+#define RXCR2_SRDBL_MASK               (0x7 << 5)
+#define RXCR2_SRDBL_SHIFT              (5)
+#define RXCR2_SRDBL_4B                 (0x0 << 5)
+#define RXCR2_SRDBL_8B                 (0x1 << 5)
+#define RXCR2_SRDBL_16B                        (0x2 << 5)
+#define RXCR2_SRDBL_32B                        (0x3 << 5)
+/* #define RXCR2_SRDBL_FRAME           (0x4 << 5) */
+#define RXCR2_IUFFP                    (1 << 4)
+#define RXCR2_RXIUFCEZ                 (1 << 3)
+#define RXCR2_UDPLFE                   (1 << 2)
+#define RXCR2_RXICMPFCC                        (1 << 1)
+#define RXCR2_RXSAF                    (1 << 0)
+
+#define KS_TXMIR                       0x78
+
+#define KS_RXFHSR                      0x7C
+#define RXFSHR_RXFV                    (1 << 15)
+#define RXFSHR_RXICMPFCS               (1 << 13)
+#define RXFSHR_RXIPFCS                 (1 << 12)
+#define RXFSHR_RXTCPFCS                        (1 << 11)
+#define RXFSHR_RXUDPFCS                        (1 << 10)
+#define RXFSHR_RXBF                    (1 << 7)
+#define RXFSHR_RXMF                    (1 << 6)
+#define RXFSHR_RXUF                    (1 << 5)
+#define RXFSHR_RXMR                    (1 << 4)
+#define RXFSHR_RXFT                    (1 << 3)
+#define RXFSHR_RXFTL                   (1 << 2)
+#define RXFSHR_RXRF                    (1 << 1)
+#define RXFSHR_RXCE                    (1 << 0)
+#define RXFSHR_ERR                     (RXFSHR_RXCE | RXFSHR_RXRF |\
+                                       RXFSHR_RXFTL | RXFSHR_RXMR |\
+                                       RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\
+                                       RXFSHR_RXTCPFCS)
+#define KS_RXFHBCR                     0x7E
+#define RXFHBCR_CNT_MASK               0x0FFF
+
+#define KS_TXQCR                       0x80
+#define TXQCR_AETFE                    (1 << 2)
+#define TXQCR_TXQMAM                   (1 << 1)
+#define TXQCR_METFE                    (1 << 0)
+
+#define KS_RXQCR                       0x82
+#define RXQCR_RXDTTS                   (1 << 12)
+#define RXQCR_RXDBCTS                  (1 << 11)
+#define RXQCR_RXFCTS                   (1 << 10)
+#define RXQCR_RXIPHTOE                 (1 << 9)
+#define RXQCR_RXDTTE                   (1 << 7)
+#define RXQCR_RXDBCTE                  (1 << 6)
+#define RXQCR_RXFCTE                   (1 << 5)
+#define RXQCR_ADRFE                    (1 << 4)
+#define RXQCR_SDA                      (1 << 3)
+#define RXQCR_RRXEF                    (1 << 0)
+#define RXQCR_CMD_CNTL                 (RXQCR_RXFCTE|RXQCR_ADRFE)
+
+#define KS_TXFDPR                      0x84
+#define TXFDPR_TXFPAI                  (1 << 14)
+#define TXFDPR_TXFP_MASK               (0x7ff << 0)
+#define TXFDPR_TXFP_SHIFT              (0)
+
+#define KS_RXFDPR                      0x86
+#define RXFDPR_RXFPAI                  (1 << 14)
+
+#define KS_RXDTTR                      0x8C
+#define KS_RXDBCTR                     0x8E
+
+#define KS_IER                         0x90
+#define KS_ISR                         0x92
+#define IRQ_LCI                                (1 << 15)
+#define IRQ_TXI                                (1 << 14)
+#define IRQ_RXI                                (1 << 13)
+#define IRQ_RXOI                       (1 << 11)
+#define IRQ_TXPSI                      (1 << 9)
+#define IRQ_RXPSI                      (1 << 8)
+#define IRQ_TXSAI                      (1 << 6)
+#define IRQ_RXWFDI                     (1 << 5)
+#define IRQ_RXMPDI                     (1 << 4)
+#define IRQ_LDI                                (1 << 3)
+#define IRQ_EDI                                (1 << 2)
+#define IRQ_SPIBEI                     (1 << 1)
+#define IRQ_DEDI                       (1 << 0)
+
+#define KS_RXFCTR                      0x9C
+#define RXFCTR_THRESHOLD_MASK          0x00FF
+
+#define KS_RXFC                                0x9D
+#define RXFCTR_RXFC_MASK               (0xff << 8)
+#define RXFCTR_RXFC_SHIFT              (8)
+#define RXFCTR_RXFC_GET(_v)            (((_v) >> 8) & 0xff)
+#define RXFCTR_RXFCT_MASK              (0xff << 0)
+#define RXFCTR_RXFCT_SHIFT             (0)
+
+#define KS_TXNTFSR                     0x9E
+
+#define KS_MAHTR0                      0xA0
+#define KS_MAHTR1                      0xA2
+#define KS_MAHTR2                      0xA4
+#define KS_MAHTR3                      0xA6
+
+#define KS_FCLWR                       0xB0
+#define KS_FCHWR                       0xB2
+#define KS_FCOWR                       0xB4
+
+#define KS_CIDER                       0xC0
+#define CIDER_ID                       0x8870
+#define CIDER_REV_MASK                 (0x7 << 1)
+#define CIDER_REV_SHIFT                        (1)
+#define CIDER_REV_GET(_v)              (((_v) >> 1) & 0x7)
+
+#define KS_CGCR                                0xC6
+#define KS_IACR                                0xC8
+#define IACR_RDEN                      (1 << 12)
+#define IACR_TSEL_MASK                 (0x3 << 10)
+#define IACR_TSEL_SHIFT                        (10)
+#define IACR_TSEL_MIB                  (0x3 << 10)
+#define IACR_ADDR_MASK                 (0x1f << 0)
+#define IACR_ADDR_SHIFT                        (0)
+
+#define KS_IADLR                       0xD0
+#define KS_IAHDR                       0xD2
+
+#define KS_PMECR                       0xD4
+#define PMECR_PME_DELAY                        (1 << 14)
+#define PMECR_PME_POL                  (1 << 12)
+#define PMECR_WOL_WAKEUP               (1 << 11)
+#define PMECR_WOL_MAGICPKT             (1 << 10)
+#define PMECR_WOL_LINKUP               (1 << 9)
+#define PMECR_WOL_ENERGY               (1 << 8)
+#define PMECR_AUTO_WAKE_EN             (1 << 7)
+#define PMECR_WAKEUP_NORMAL            (1 << 6)
+#define PMECR_WKEVT_MASK               (0xf << 2)
+#define PMECR_WKEVT_SHIFT              (2)
+#define PMECR_WKEVT_GET(_v)            (((_v) >> 2) & 0xf)
+#define PMECR_WKEVT_ENERGY             (0x1 << 2)
+#define PMECR_WKEVT_LINK               (0x2 << 2)
+#define PMECR_WKEVT_MAGICPKT           (0x4 << 2)
+#define PMECR_WKEVT_FRAME              (0x8 << 2)
+#define PMECR_PM_MASK                  (0x3 << 0)
+#define PMECR_PM_SHIFT                 (0)
+#define PMECR_PM_NORMAL                        (0x0 << 0)
+#define PMECR_PM_ENERGY                        (0x1 << 0)
+#define PMECR_PM_SOFTDOWN              (0x2 << 0)
+#define PMECR_PM_POWERSAVE             (0x3 << 0)
+
+/* Standard MII PHY data */
+#define KS_P1MBCR                      0xE4
+#define P1MBCR_FORCE_FDX               (1 << 8)
+
+#define KS_P1MBSR                      0xE6
+#define P1MBSR_AN_COMPLETE             (1 << 5)
+#define P1MBSR_AN_CAPABLE              (1 << 3)
+#define P1MBSR_LINK_UP                 (1 << 2)
+
+#define KS_PHY1ILR                     0xE8
+#define KS_PHY1IHR                     0xEA
+#define KS_P1ANAR                      0xEC
+#define KS_P1ANLPR                     0xEE
+
+#define KS_P1SCLMD                     0xF4
+#define P1SCLMD_LEDOFF                 (1 << 15)
+#define P1SCLMD_TXIDS                  (1 << 14)
+#define P1SCLMD_RESTARTAN              (1 << 13)
+#define P1SCLMD_DISAUTOMDIX            (1 << 10)
+#define P1SCLMD_FORCEMDIX              (1 << 9)
+#define P1SCLMD_AUTONEGEN              (1 << 7)
+#define P1SCLMD_FORCE100               (1 << 6)
+#define P1SCLMD_FORCEFDX               (1 << 5)
+#define P1SCLMD_ADV_FLOW               (1 << 4)
+#define P1SCLMD_ADV_100BT_FDX          (1 << 3)
+#define P1SCLMD_ADV_100BT_HDX          (1 << 2)
+#define P1SCLMD_ADV_10BT_FDX           (1 << 1)
+#define P1SCLMD_ADV_10BT_HDX           (1 << 0)
+
+#define KS_P1CR                                0xF6
+#define P1CR_HP_MDIX                   (1 << 15)
+#define P1CR_REV_POL                   (1 << 13)
+#define P1CR_OP_100M                   (1 << 10)
+#define P1CR_OP_FDX                    (1 << 9)
+#define P1CR_OP_MDI                    (1 << 7)
+#define P1CR_AN_DONE                   (1 << 6)
+#define P1CR_LINK_GOOD                 (1 << 5)
+#define P1CR_PNTR_FLOW                 (1 << 4)
+#define P1CR_PNTR_100BT_FDX            (1 << 3)
+#define P1CR_PNTR_100BT_HDX            (1 << 2)
+#define P1CR_PNTR_10BT_FDX             (1 << 1)
+#define P1CR_PNTR_10BT_HDX             (1 << 0)
+
+/* TX Frame control */
+#define TXFR_TXIC                      (1 << 15)
+#define TXFR_TXFID_MASK                        (0x3f << 0)
+#define TXFR_TXFID_SHIFT               (0)
+
+#define KS_P1SR                                0xF8
+#define P1SR_HP_MDIX                   (1 << 15)
+#define P1SR_REV_POL                   (1 << 13)
+#define P1SR_OP_100M                   (1 << 10)
+#define P1SR_OP_FDX                    (1 << 9)
+#define P1SR_OP_MDI                    (1 << 7)
+#define P1SR_AN_DONE                   (1 << 6)
+#define P1SR_LINK_GOOD                 (1 << 5)
+#define P1SR_PNTR_FLOW                 (1 << 4)
+#define P1SR_PNTR_100BT_FDX            (1 << 3)
+#define P1SR_PNTR_100BT_HDX            (1 << 2)
+#define P1SR_PNTR_10BT_FDX             (1 << 1)
+#define P1SR_PNTR_10BT_HDX             (1 << 0)
+
+#define ENUM_BUS_NONE                  0
+#define ENUM_BUS_8BIT                  1
+#define ENUM_BUS_16BIT                 2
+#define ENUM_BUS_32BIT                 3
+
+#define MAX_MCAST_LST                  32
+#define HW_MCAST_SIZE                  8
+#define MAC_ADDR_LEN                   6
+
+/* Chip ID values */
+struct chip_id {
+       u16 id;
+       char *name;
+};
+
+#endif
index 8bacbda71966942c12944d148a7acce0d176c59b..b7802a2fed70828c7f9f38c10013a1f15d5abf25 100644 (file)
@@ -103,9 +103,15 @@ struct macb_device {
        const struct device     *dev;
        struct eth_device       netdev;
        unsigned short          phy_addr;
+       struct mii_dev          *bus;
 };
 #define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
 
+static int macb_is_gem(struct macb_device *macb)
+{
+       return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
+}
+
 static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
 {
        unsigned long netctl;
@@ -163,7 +169,12 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
        return MACB_BFEXT(DATA, frame);
 }
 
-#if defined(CONFIG_CMD_MII)
+void __weak arch_get_mdio_control(const char *name)
+{
+       return;
+}
+
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
 
 int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
 {
@@ -173,6 +184,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
        if ( macb->phy_addr != phy_adr )
                return -1;
 
+       arch_get_mdio_control(devname);
        *value = macb_mdio_read(macb, reg);
 
        return 0;
@@ -186,6 +198,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
        if ( macb->phy_addr != phy_adr )
                return -1;
 
+       arch_get_mdio_control(devname);
        macb_mdio_write(macb, reg, value);
 
        return 0;
@@ -372,11 +385,15 @@ static int macb_phy_find(struct macb_device *macb)
 static int macb_phy_init(struct macb_device *macb)
 {
        struct eth_device *netdev = &macb->netdev;
+#ifdef CONFIG_PHYLIB
+       struct phy_device *phydev;
+#endif
        u32 ncfgr;
        u16 phy_id, status, adv, lpa;
        int media, speed, duplex;
        int i;
 
+       arch_get_mdio_control(netdev->name);
 #ifdef CONFIG_MACB_SEARCH_PHY
        /* Auto-detect phy_addr */
        if (!macb_phy_find(macb)) {
@@ -391,6 +408,13 @@ static int macb_phy_init(struct macb_device *macb)
                return 0;
        }
 
+#ifdef CONFIG_PHYLIB
+       phydev->bus = macb->bus;
+       phydev->dev = netdev;
+       phydev->addr = macb->phy_addr;
+       phy_config(phydev);
+#endif
+
        status = macb_mdio_read(macb, MII_BMSR);
        if (!(status & BMSR_LSTATUS)) {
                /* Try to re-negotiate if we don't have link already. */
@@ -408,28 +432,64 @@ static int macb_phy_init(struct macb_device *macb)
                printf("%s: link down (status: 0x%04x)\n",
                       netdev->name, status);
                return 0;
-       } else {
-               adv = macb_mdio_read(macb, MII_ADVERTISE);
-               lpa = macb_mdio_read(macb, MII_LPA);
-               media = mii_nway_result(lpa & adv);
-               speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
-                        ? 1 : 0);
-               duplex = (media & ADVERTISE_FULL) ? 1 : 0;
-               printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
-                      netdev->name,
-                      speed ? "100" : "10",
-                      duplex ? "full" : "half",
-                      lpa);
-
-               ncfgr = macb_readl(macb, NCFGR);
-               ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
-               if (speed)
-                       ncfgr |= MACB_BIT(SPD);
-               if (duplex)
-                       ncfgr |= MACB_BIT(FD);
-               macb_writel(macb, NCFGR, ncfgr);
-               return 1;
        }
+
+       /* First check for GMAC */
+       if (macb_is_gem(macb)) {
+               lpa = macb_mdio_read(macb, MII_STAT1000);
+               if (lpa & (1 << 11)) {
+                       speed = 1000;
+                       duplex = 1;
+               } else {
+                      if (lpa & (1 << 10)) {
+                               speed = 1000;
+                               duplex = 1;
+                       } else {
+                               speed = 0;
+                       }
+               }
+
+               if (speed == 1000) {
+                       printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n",
+                              netdev->name,
+                              speed,
+                              duplex ? "full" : "half",
+                              lpa);
+
+                       ncfgr = macb_readl(macb, NCFGR);
+                       ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD));
+                       if (speed)
+                               ncfgr |= GEM_BIT(GBE);
+                       if (duplex)
+                               ncfgr |= MACB_BIT(FD);
+                       macb_writel(macb, NCFGR, ncfgr);
+
+                       return 1;
+               }
+       }
+
+       /* fall back for EMAC checking */
+       adv = macb_mdio_read(macb, MII_ADVERTISE);
+       lpa = macb_mdio_read(macb, MII_LPA);
+       media = mii_nway_result(lpa & adv);
+       speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF)
+                ? 1 : 0);
+       duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+       printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n",
+              netdev->name,
+              speed ? "100" : "10",
+              duplex ? "full" : "half",
+              lpa);
+
+       ncfgr = macb_readl(macb, NCFGR);
+       ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD));
+       if (speed)
+               ncfgr |= MACB_BIT(SPD);
+       if (duplex)
+               ncfgr |= MACB_BIT(FD);
+       macb_writel(macb, NCFGR, ncfgr);
+
+       return 1;
 }
 
 static int macb_init(struct eth_device *netdev, bd_t *bd)
@@ -464,26 +524,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd)
        macb_writel(macb, RBQP, macb->rx_ring_dma);
        macb_writel(macb, TBQP, macb->tx_ring_dma);
 
+       if (macb_is_gem(macb)) {
+#ifdef CONFIG_RGMII
+               gem_writel(macb, UR, GEM_BIT(RGMII));
+#else
+               gem_writel(macb, UR, 0);
+#endif
+       } else {
        /* choose RMII or MII mode. This depends on the board */
 #ifdef CONFIG_RMII
-#if    defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-       defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
-       defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
-       defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+#ifdef CONFIG_AT91FAMILY
        macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN));
 #else
        macb_writel(macb, USRIO, 0);
 #endif
 #else
-#if    defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \
-       defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \
-       defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \
-       defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5)
+#ifdef CONFIG_AT91FAMILY
        macb_writel(macb, USRIO, MACB_BIT(CLKEN));
 #else
        macb_writel(macb, USRIO, MACB_BIT(MII));
 #endif
 #endif /* CONFIG_RMII */
+       }
 
        if (!macb_phy_init(macb))
                return -1;
@@ -527,11 +589,48 @@ static int macb_write_hwaddr(struct eth_device *dev)
        return 0;
 }
 
+static u32 macb_mdc_clk_div(int id, struct macb_device *macb)
+{
+       u32 config;
+       unsigned long macb_hz = get_macb_pclk_rate(id);
+
+       if (macb_hz < 20000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV8);
+       else if (macb_hz < 40000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV16);
+       else if (macb_hz < 80000000)
+               config = MACB_BF(CLK, MACB_CLK_DIV32);
+       else
+               config = MACB_BF(CLK, MACB_CLK_DIV64);
+
+       return config;
+}
+
+static u32 gem_mdc_clk_div(int id, struct macb_device *macb)
+{
+       u32 config;
+       unsigned long macb_hz = get_macb_pclk_rate(id);
+
+       if (macb_hz < 20000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV8);
+       else if (macb_hz < 40000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV16);
+       else if (macb_hz < 80000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV32);
+       else if (macb_hz < 120000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV48);
+       else if (macb_hz < 160000000)
+               config = GEM_BF(CLK, GEM_CLK_DIV64);
+       else
+               config = GEM_BF(CLK, GEM_CLK_DIV96);
+
+       return config;
+}
+
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
 {
        struct macb_device *macb;
        struct eth_device *netdev;
-       unsigned long macb_hz;
        u32 ncfgr;
 
        macb = malloc(sizeof(struct macb_device));
@@ -555,7 +654,11 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
        macb->regs = regs;
        macb->phy_addr = phy_addr;
 
-       sprintf(netdev->name, "macb%d", id);
+       if (macb_is_gem(macb))
+               sprintf(netdev->name, "gmac%d", id);
+       else
+               sprintf(netdev->name, "macb%d", id);
+
        netdev->init = macb_init;
        netdev->halt = macb_halt;
        netdev->send = macb_send;
@@ -566,22 +669,20 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr)
         * Do some basic initialization so that we at least can talk
         * to the PHY
         */
-       macb_hz = get_macb_pclk_rate(id);
-       if (macb_hz < 20000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
-       else if (macb_hz < 40000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV16);
-       else if (macb_hz < 80000000)
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV32);
-       else
-               ncfgr = MACB_BF(CLK, MACB_CLK_DIV64);
+       if (macb_is_gem(macb)) {
+               ncfgr = gem_mdc_clk_div(id, macb);
+               ncfgr |= GEM_BF(DBW, 1);
+       } else {
+               ncfgr = macb_mdc_clk_div(id, macb);
+       }
 
        macb_writel(macb, NCFGR, ncfgr);
 
        eth_register(netdev);
 
-#if defined(CONFIG_CMD_MII)
+#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
        miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write);
+       macb->bus = miiphy_get_dev_by_name(netdev->name);
 #endif
        return 0;
 }
index f92a20c7015d04d496801ce7d9a5195095bbaac2..68eef00c03e67762e1369c3b2e4601b27975d5de 100644 (file)
@@ -26,6 +26,7 @@
 #define MACB_NCR                               0x0000
 #define MACB_NCFGR                             0x0004
 #define MACB_NSR                               0x0008
+#define GEM_UR                                 0x000c
 #define MACB_TSR                               0x0014
 #define MACB_RBQP                              0x0018
 #define MACB_TBQP                              0x001c
@@ -71,6 +72,7 @@
 #define MACB_TPQ                               0x00bc
 #define MACB_USRIO                             0x00c0
 #define MACB_WOL                               0x00c4
+#define MACB_MID                               0x00fc
 
 /* Bitfields in NCR */
 #define MACB_LB_OFFSET                         0
 #define MACB_IRXFCS_OFFSET                     19
 #define MACB_IRXFCS_SIZE                       1
 
+#define GEM_GBE_OFFSET                         10
+#define GEM_GBE_SIZE                           1
+#define GEM_CLK_OFFSET                         18
+#define GEM_CLK_SIZE                           3
+#define GEM_DBW_OFFSET                         21
+#define GEM_DBW_SIZE                           2
+
 /* Bitfields in NSR */
 #define MACB_NSR_LINK_OFFSET                   0
 #define MACB_NSR_LINK_SIZE                     1
 #define MACB_IDLE_OFFSET                       2
 #define MACB_IDLE_SIZE                         1
 
+/* Bitfields in UR */
+#define GEM_RGMII_OFFSET                       0
+#define GEM_RGMII_SIZE                         1
+
 /* Bitfields in TSR */
 #define MACB_UBR_OFFSET                                0
 #define MACB_UBR_SIZE                          1
 #define MACB_WOL_MTI_OFFSET                    19
 #define MACB_WOL_MTI_SIZE                      1
 
+/* Bitfields in MID */
+#define MACB_IDNUM_OFFSET                      16
+#define MACB_IDNUM_SIZE                                16
+
+/* Bitfields in DCFG1 */
 /* Constants for CLK */
 #define MACB_CLK_DIV8                          0
 #define MACB_CLK_DIV16                         1
 #define MACB_CLK_DIV32                         2
 #define MACB_CLK_DIV64                         3
 
+/* GEM specific constants for CLK */
+#define GEM_CLK_DIV8                           0
+#define GEM_CLK_DIV16                          1
+#define GEM_CLK_DIV32                          2
+#define GEM_CLK_DIV48                          3
+#define GEM_CLK_DIV64                          4
+#define GEM_CLK_DIV96                          5
+
 /* Constants for MAN register */
 #define MACB_MAN_SOF                           1
 #define MACB_MAN_WRITE                         1
 /* Bit manipulation macros */
 #define MACB_BIT(name)                                 \
        (1 << MACB_##name##_OFFSET)
-#define MACB_BF(name,value)                            \
+#define MACB_BF(name, value)                           \
        (((value) & ((1 << MACB_##name##_SIZE) - 1))    \
         << MACB_##name##_OFFSET)
-#define MACB_BFEXT(name,value)\
+#define MACB_BFEXT(name, value)\
        (((value) >> MACB_##name##_OFFSET)              \
         & ((1 << MACB_##name##_SIZE) - 1))
-#define MACB_BFINS(name,value,old)                     \
+#define MACB_BFINS(name, value, old)                   \
        (((old) & ~(((1 << MACB_##name##_SIZE) - 1)     \
                    << MACB_##name##_OFFSET))           \
-        | MACB_BF(name,value))
+        | MACB_BF(name, value))
+
+#define GEM_BIT(name)                                  \
+       (1 << GEM_##name##_OFFSET)
+#define GEM_BF(name, value)                            \
+       (((value) & ((1 << GEM_##name##_SIZE) - 1))     \
+        << GEM_##name##_OFFSET)
+#define GEM_BFEXT(name, value)\
+       (((value) >> GEM_##name##_OFFSET)               \
+        & ((1 << GEM_##name##_SIZE) - 1))
+#define GEM_BFINS(name, value, old)                    \
+       (((old) & ~(((1 << GEM_##name##_SIZE) - 1)      \
+                   << GEM_##name##_OFFSET))            \
+        | GEM_BF(name, value))
 
 /* Register access macros */
-#define macb_readl(port,reg)                           \
+#define macb_readl(port, reg)                          \
        readl((port)->regs + MACB_##reg)
-#define macb_writel(port,reg,value)                    \
+#define macb_writel(port, reg, value)                  \
        writel((value), (port)->regs + MACB_##reg)
+#define gem_readl(port, reg)                           \
+       readl((port)->regs + GEM_##reg)
+#define gem_writel(port, reg, value)                   \
+       writel((value), (port)->regs + GEM_##reg)
 
 #endif /* __DRIVERS_MACB_H__ */
index 47bf27c8ba3981d0d060ad090aacad4e41ef85e8..319fe8aba9718710984735f15471983f04a71db3 100644 (file)
@@ -43,6 +43,8 @@
 #include <asm/arch/kirkwood.h>
 #elif defined(CONFIG_ORION5X)
 #include <asm/arch/orion5x.h>
+#elif defined(CONFIG_DOVE)
+#include <asm/arch/dove.h>
 #endif
 
 #include "mvgbe.h"
@@ -52,7 +54,7 @@ DECLARE_GLOBAL_DATA_PTR;
 #define MV_PHY_ADR_REQUEST 0xee
 #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
 
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
 /*
  * smi_reg_read - miiphy_read callback function.
  *
@@ -184,6 +186,25 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
 }
 #endif
 
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
+                  int reg_addr)
+{
+       u16 data;
+       int ret;
+       ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data);
+       if (ret)
+               return ret;
+       return data;
+}
+
+int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
+                   int reg_addr, u16 data)
+{
+       return smi_reg_write(bus->name, phy_addr, reg_addr, data);
+}
+#endif
+
 /* Stop and checks all queues */
 static void stop_queue(u32 * qreg)
 {
@@ -467,8 +488,9 @@ static int mvgbe_init(struct eth_device *dev)
        /* Enable port Rx. */
        MVGBE_REG_WR(regs->rqc, (1 << RXUQ));
 
-#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
-        && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
+#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
+       !defined(CONFIG_PHYLIB) && \
+       defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
        /* Wait up to 5s for the link status */
        for (i = 0; i < 5; i++) {
                u16 phyadr;
@@ -647,6 +669,45 @@ static int mvgbe_recv(struct eth_device *dev)
        return 0;
 }
 
+#if defined(CONFIG_PHYLIB)
+int mvgbe_phylib_init(struct eth_device *dev, int phyid)
+{
+       struct mii_dev *bus;
+       struct phy_device *phydev;
+       int ret;
+
+       bus = mdio_alloc();
+       if (!bus) {
+               printf("mdio_alloc failed\n");
+               return -ENOMEM;
+       }
+       bus->read = mvgbe_phy_read;
+       bus->write = mvgbe_phy_write;
+       sprintf(bus->name, dev->name);
+
+       ret = mdio_register(bus);
+       if (ret) {
+               printf("mdio_register failed\n");
+               free(bus);
+               return -ENOMEM;
+       }
+
+       /* Set phy address of the port */
+       mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid);
+
+       phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII);
+       if (!phydev) {
+               printf("phy_connect failed\n");
+               return -ENODEV;
+       }
+
+       phy_config(phydev);
+       phy_startup(phydev);
+
+       return 0;
+}
+#endif
+
 int mvgbe_initialize(bd_t *bis)
 {
        struct mvgbe_device *dmvgbe;
@@ -729,7 +790,9 @@ error1:
 
                eth_register(dev);
 
-#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#if defined(CONFIG_PHYLIB)
+               mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
+#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
                miiphy_register(dev->name, smi_reg_read, smi_reg_write);
                /* Set phy address of the port */
                miiphy_write(dev->name, MV_PHY_ADR_REQUEST,
index d8a5429de4acfbc8a589047cff46b3f88239d579..7f5d98ff5eda777a0074a14b141bf0ad3d23d29e 100644 (file)
 #define EBAR_TARGET_GUNIT                      0x00000007
 
 /* Window attrib */
+#if defined(CONFIG_DOVE)
+#define EBAR_DRAM_CS0                          0x00000000
+#define EBAR_DRAM_CS1                          0x00000000
+#define EBAR_DRAM_CS2                          0x00000000
+#define EBAR_DRAM_CS3                          0x00000000
+#else
 #define EBAR_DRAM_CS0                          0x00000E00
 #define EBAR_DRAM_CS1                          0x00000D00
 #define EBAR_DRAM_CS2                          0x00000B00
 #define EBAR_DRAM_CS3                          0x00000700
+#endif
 
 /* DRAM Target interface */
 #define EBAR_DRAM_NO_CACHE_COHERENCY           0x00000000
index af5f4b848ceefb14d535b5c79084bbfaf49ec89c..695873eaa451fee9975cade6a9abf1a2f28501a0 100644 (file)
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o
 COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o
 COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o
 COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o
+COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o
 COBJS-$(CONFIG_PHY_LXT) += lxt.o
 COBJS-$(CONFIG_PHY_MARVELL) += marvell.o
 COBJS-$(CONFIG_PHY_MICREL) += micrel.o
index 9b3808bfa921cca0514f91ae6b74d2e2de3e9cb7..09d487971f6c9dbb02cdd5d7ddf89a1811ac5d60 100644 (file)
@@ -16,7 +16,7 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  * MA 02111-1307 USA
  *
- * Copyright 2011 Freescale Semiconductor, Inc.
+ * Copyright 2011, 2013 Freescale Semiconductor, Inc.
  * author Andy Fleming
  *
  */
@@ -30,6 +30,27 @@ static int ar8021_config(struct phy_device *phydev)
        return 0;
 }
 
+static int ar8035_config(struct phy_device *phydev)
+{
+       int regval;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
+       phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
+       phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
+       regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
+       phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
+
+       phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
+       regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
+       phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
+
+       genphy_config_aneg(phydev);
+
+       phy_reset(phydev);
+
+       return 0;
+}
+
 static struct phy_driver AR8021_driver =  {
        .name = "AR8021",
        .uid = 0x4dd040,
@@ -40,9 +61,31 @@ static struct phy_driver AR8021_driver =  {
        .shutdown = genphy_shutdown,
 };
 
+static struct phy_driver AR8031_driver =  {
+       .name = "AR8031",
+       .uid = 0x4dd074,
+       .mask = 0xfffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = genphy_config,
+       .startup = genphy_startup,
+       .shutdown = genphy_shutdown,
+};
+
+static struct phy_driver AR8035_driver =  {
+       .name = "AR8035",
+       .uid = 0x4dd072,
+       .mask = 0x4fffff,
+       .features = PHY_GBIT_FEATURES,
+       .config = ar8035_config,
+       .startup = genphy_startup,
+       .shutdown = genphy_shutdown,
+};
+
 int phy_atheros_init(void)
 {
        phy_register(&AR8021_driver);
+       phy_register(&AR8031_driver);
+       phy_register(&AR8035_driver);
 
        return 0;
 }
diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c
new file mode 100644 (file)
index 0000000..dd5c592
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * ICPlus PHY drivers
+ *
+ * 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
+ *
+ * Copyright (c) 2007 Freescale Semiconductor, Inc.
+ *
+ */
+#include <phy.h>
+
+/* IP101A/G - IP1001 */
+#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */
+#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */
+#define IP1001_PHASE_SEL_MASK           3       /* IP1001 RX/TXPHASE_SEL */
+#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */
+#define IP101A_G_APS_ON                 2       /* IP101A/G APS Mode bit */
+#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */
+#define IP101A_G_IRQ_PIN_USED           (1<<15) /* INTR pin used */
+#define IP101A_G_IRQ_DEFAULT            IP101A_G_IRQ_PIN_USED
+
+static int ip1001_config(struct phy_device *phydev)
+{
+       int c;
+
+       /* Enable Auto Power Saving mode */
+       c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2);
+       if (c < 0)
+               return c;
+       c |= IP1001_APS_ON;
+       c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c);
+       if (c < 0)
+               return c;
+
+       /* INTR pin used: speed/link/duplex will cause an interrupt */
+       c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS,
+                     IP101A_G_IRQ_DEFAULT);
+       if (c < 0)
+               return c;
+
+       if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
+               /*
+                * Additional delay (2ns) used to adjust RX clock phase
+                * at RGMII interface
+                */
+               c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS);
+               if (c < 0)
+                       return c;
+
+               c |= IP1001_PHASE_SEL_MASK;
+               c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS,
+                             c);
+               if (c < 0)
+                       return c;
+       }
+
+       return 0;
+}
+
+static int ip1001_startup(struct phy_device *phydev)
+{
+       genphy_update_link(phydev);
+       genphy_parse_link(phydev);
+
+       return 0;
+}
+static struct phy_driver IP1001_driver = {
+       .name = "ICPlus IP1001",
+       .uid = 0x02430d90,
+       .mask = 0x0ffffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &ip1001_config,
+       .startup = &ip1001_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+int phy_icplus_init(void)
+{
+       phy_register(&IP1001_driver);
+
+       return 0;
+}
index 46801c791903efcd36167d267a70be0b1ec978c8..8397e32e1a0f8dccecfb1c3e1f10d21103e344dc 100644 (file)
 
 #define MIIM_88E1149_PHY_PAGE  29
 
+/* 88E1310 PHY defines */
+#define MIIM_88E1310_PHY_LED_CTRL      16
+#define MIIM_88E1310_PHY_IRQ_EN                18
+#define MIIM_88E1310_PHY_RGMII_CTRL    21
+#define MIIM_88E1310_PHY_PAGE          22
+
 /* Marvell 88E1011S */
 static int m88e1011s_config(struct phy_device *phydev)
 {
@@ -394,6 +400,37 @@ static int m88e1149_config(struct phy_device *phydev)
        return 0;
 }
 
+/* Marvell 88E1310 */
+static int m88e1310_config(struct phy_device *phydev)
+{
+       u16 reg;
+
+       /* LED link and activity */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL);
+       reg = (reg & ~0xf) | 0x1;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg);
+
+       /* Set LED2/INT to INT mode, low active */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN);
+       reg = (reg & 0x77ff) | 0x0880;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg);
+
+       /* Set RGMII delay */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002);
+       reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL);
+       reg |= 0x0030;
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg);
+
+       /* Ensure to return to page 0 */
+       phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000);
+
+       genphy_config_aneg(phydev);
+       phy_reset(phydev);
+
+       return 0;
+}
 
 static struct phy_driver M88E1011S_driver = {
        .name = "Marvell 88E1011S",
@@ -475,8 +512,19 @@ static struct phy_driver M88E1518_driver = {
        .shutdown = &genphy_shutdown,
 };
 
+static struct phy_driver M88E1310_driver = {
+       .name = "Marvell 88E1310",
+       .uid = 0x01410e90,
+       .mask = 0xffffff0,
+       .features = PHY_GBIT_FEATURES,
+       .config = &m88e1310_config,
+       .startup = &m88e1011s_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 int phy_marvell_init(void)
 {
+       phy_register(&M88E1310_driver);
        phy_register(&M88E1149S_driver);
        phy_register(&M88E1145_driver);
        phy_register(&M88E1121R_driver);
index 30f3264897479c35f49cc53c3600b7f5ca46665b..aa9cbcfffc0465075ed7574e7ac76ffea908db48 100644 (file)
@@ -18,6 +18,7 @@
  *
  * Copyright 2010-2011 Freescale Semiconductor, Inc.
  * author Andy Fleming
+ * (C) 2012 NetModule AG, David Andrey, added KSZ9031
  *
  */
 #include <config.h>
@@ -52,16 +53,46 @@ static struct phy_driver KS8721_driver = {
 };
 #endif
 
+
+/**
+ * KSZ9021 - KSZ9031 common
+ */
+
+#define MII_KSZ90xx_PHY_CTL            0x1f
+#define MIIM_KSZ90xx_PHYCTL_1000       (1 << 6)
+#define MIIM_KSZ90xx_PHYCTL_100                (1 << 5)
+#define MIIM_KSZ90xx_PHYCTL_10         (1 << 4)
+#define MIIM_KSZ90xx_PHYCTL_DUPLEX     (1 << 3)
+
+static int ksz90xx_startup(struct phy_device *phydev)
+{
+       unsigned phy_ctl;
+       genphy_update_link(phydev);
+       phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
+
+       if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
+               phydev->duplex = DUPLEX_FULL;
+       else
+               phydev->duplex = DUPLEX_HALF;
+
+       if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
+               phydev->speed = SPEED_1000;
+       else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
+               phydev->speed = SPEED_100;
+       else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
+               phydev->speed = SPEED_10;
+       return 0;
+}
 #ifdef CONFIG_PHY_MICREL_KSZ9021
-/* ksz9021 PHY Registers */
+
+/*
+ * KSZ9021
+ */
+
+/* PHY Registers */
 #define MII_KSZ9021_EXTENDED_CTRL      0x0b
 #define MII_KSZ9021_EXTENDED_DATAW     0x0c
 #define MII_KSZ9021_EXTENDED_DATAR     0x0d
-#define MII_KSZ9021_PHY_CTL            0x1f
-#define MIIM_KSZ9021_PHYCTL_1000       (1 << 6)
-#define MIIM_KSZ9021_PHYCTL_100                (1 << 5)
-#define MIIM_KSZ9021_PHYCTL_10         (1 << 4)
-#define MIIM_KSZ9021_PHYCTL_DUPLEX     (1 << 3)
 
 #define CTRL1000_PREFER_MASTER         (1 << 10)
 #define CTRL1000_CONFIG_MASTER         (1 << 11)
@@ -106,37 +137,64 @@ static int ksz9021_config(struct phy_device *phydev)
        return 0;
 }
 
-static int ksz9021_startup(struct phy_device *phydev)
-{
-       unsigned phy_ctl;
-       genphy_update_link(phydev);
-       phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL);
-
-       if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX)
-               phydev->duplex = DUPLEX_FULL;
-       else
-               phydev->duplex = DUPLEX_HALF;
-
-       if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000)
-               phydev->speed = SPEED_1000;
-       else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100)
-               phydev->speed = SPEED_100;
-       else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10)
-               phydev->speed = SPEED_10;
-       return 0;
-}
-
 static struct phy_driver ksz9021_driver = {
        .name = "Micrel ksz9021",
        .uid  = 0x221610,
        .mask = 0xfffff0,
        .features = PHY_GBIT_FEATURES,
        .config = &ksz9021_config,
-       .startup = &ksz9021_startup,
+       .startup = &ksz90xx_startup,
        .shutdown = &genphy_shutdown,
 };
 #endif
 
+/**
+ * KSZ9031
+ */
+/* PHY Registers */
+#define MII_KSZ9031_MMD_ACCES_CTRL     0x0d
+#define MII_KSZ9031_MMD_REG_DATA       0x0e
+
+/* Accessors to extended registers*/
+int ksz9031_phy_extended_write(struct phy_device *phydev,
+                              int devaddr, int regnum, u16 mode, u16 val)
+{
+       /*select register addr for mmd*/
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+       /*select register for mmd*/
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_REG_DATA, regnum);
+       /*setup mode*/
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
+       /*write the value*/
+       return  phy_write(phydev, MDIO_DEVAD_NONE,
+               MII_KSZ9031_MMD_REG_DATA, val);
+}
+
+int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
+                             int regnum, u16 mode)
+{
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_REG_DATA, regnum);
+       phy_write(phydev, MDIO_DEVAD_NONE,
+                 MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
+       return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
+}
+
+static struct phy_driver ksz9031_driver = {
+       .name = "Micrel ksz9031",
+       .uid  = 0x221620,
+       .mask = 0xfffffe,
+       .features = PHY_GBIT_FEATURES,
+       .config   = &genphy_config,
+       .startup  = &ksz90xx_startup,
+       .shutdown = &genphy_shutdown,
+};
+
 int phy_micrel_init(void)
 {
        phy_register(&KSZ804_driver);
@@ -145,5 +203,6 @@ int phy_micrel_init(void)
 #else
        phy_register(&KS8721_driver);
 #endif
+       phy_register(&ksz9031_driver);
        return 0;
 }
index ea60ac1b0e6513b930d2c3191cec090e68b5b69a..6dc7ed50598ea699b874460a9524bd1e6c7ba46f 100644 (file)
  */
 #include <phy.h>
 
+/* NatSemi DP83630 */
+
+#define DP83630_PHY_PAGESEL_REG                0x13
+#define DP83630_PHY_PTP_COC_REG                0x14
+#define DP83630_PHY_PTP_CLKOUT_EN      (1<<15)
+#define DP83630_PHY_RBR_REG            0x17
+
+static int dp83630_config(struct phy_device *phydev)
+{
+       int ptp_coc_reg;
+
+       phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
+       phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6);
+       ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE,
+                              DP83630_PHY_PTP_COC_REG);
+       ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN;
+       phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG,
+                 ptp_coc_reg);
+       phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0);
+
+       genphy_config_aneg(phydev);
+
+       return 0;
+}
+
+static struct phy_driver DP83630_driver = {
+       .name = "NatSemi DP83630",
+       .uid = 0x20005ce1,
+       .mask = 0xfffffff0,
+       .features = PHY_BASIC_FEATURES,
+       .config = &dp83630_config,
+       .startup = &genphy_startup,
+       .shutdown = &genphy_shutdown,
+};
+
+
 /* DP83865 Link and Auto-Neg Status Register */
 #define MIIM_DP83865_LANR      0x11
 #define MIIM_DP83865_SPD_MASK  0x0018
@@ -90,6 +126,7 @@ static struct phy_driver DP83865_driver = {
 
 int phy_natsemi_init(void)
 {
+       phy_register(&DP83630_driver);
        phy_register(&DP83865_driver);
 
        return 0;
index f8c54814777882e83d17e8ad22b69abcd047f42f..7c0eaec5137f8def0cfbf92b67793f74f0dc7e60 100644 (file)
@@ -75,6 +75,10 @@ static int genphy_config_advert(struct phy_device *phydev)
                adv |= ADVERTISE_PAUSE_CAP;
        if (advertise & ADVERTISED_Asym_Pause)
                adv |= ADVERTISE_PAUSE_ASYM;
+       if (advertise & ADVERTISED_1000baseX_Half)
+               adv |= ADVERTISE_1000XHALF;
+       if (advertise & ADVERTISED_1000baseX_Full)
+               adv |= ADVERTISE_1000XFULL;
 
        if (adv != oldadv) {
                err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
@@ -280,7 +284,7 @@ int genphy_update_link(struct phy_device *phydev)
  *
  * Stolen from Linux's mii.c and phy_device.c
  */
-static int genphy_parse_link(struct phy_device *phydev)
+int genphy_parse_link(struct phy_device *phydev)
 {
        int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
 
@@ -288,6 +292,7 @@ static int genphy_parse_link(struct phy_device *phydev)
        if (mii_reg & BMSR_ANEGCAPABLE) {
                u32 lpa = 0;
                u32 gblpa = 0;
+               u32 estatus = 0;
 
                /* Check for gigabit capability */
                if (mii_reg & BMSR_ERCAP) {
@@ -327,6 +332,18 @@ static int genphy_parse_link(struct phy_device *phydev)
 
                } else if (lpa & LPA_10FULL)
                        phydev->duplex = DUPLEX_FULL;
+
+               if (mii_reg & BMSR_ESTATEN)
+                       estatus = phy_read(phydev, MDIO_DEVAD_NONE,
+                                          MII_ESTATUS);
+
+               if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
+                               ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
+                       phydev->speed = SPEED_1000;
+                       if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL))
+                               phydev->duplex = DUPLEX_FULL;
+               }
+
        } else {
                u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
 
@@ -384,6 +401,10 @@ int genphy_config(struct phy_device *phydev)
                        features |= SUPPORTED_1000baseT_Full;
                if (val & ESTATUS_1000_THALF)
                        features |= SUPPORTED_1000baseT_Half;
+               if (val & ESTATUS_1000_XFULL)
+                       features |= SUPPORTED_1000baseX_Full;
+               if (val & ESTATUS_1000_XHALF)
+                       features |= SUPPORTED_1000baseX_Full;
        }
 
        phydev->supported = features;
@@ -433,6 +454,9 @@ int phy_init(void)
 #ifdef CONFIG_PHY_ET1011C
        phy_et1011c_init();
 #endif
+#ifdef CONFIG_PHY_ICPLUS
+       phy_icplus_init();
+#endif
 #ifdef CONFIG_PHY_LXT
        phy_lxt_init();
 #endif
diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c
new file mode 100644 (file)
index 0000000..1db3529
--- /dev/null
@@ -0,0 +1,533 @@
+/*
+ * sunxi_wemac.c -- Allwinner A10 ethernet driver
+ *
+ * (C) Copyright 2012, Stefan Roese <sr@denx.de>
+ *
+ * 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.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <net.h>
+#include <miiphy.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/gpio.h>
+
+/* EMAC register  */
+struct wemac_regs {
+       u32 ctl;        /* 0x00 */
+       u32 tx_mode;    /* 0x04 */
+       u32 tx_flow;    /* 0x08 */
+       u32 tx_ctl0;    /* 0x0c */
+       u32 tx_ctl1;    /* 0x10 */
+       u32 tx_ins;     /* 0x14 */
+       u32 tx_pl0;     /* 0x18 */
+       u32 tx_pl1;     /* 0x1c */
+       u32 tx_sta;     /* 0x20 */
+       u32 tx_io_data; /* 0x24 */
+       u32 tx_io_data1; /* 0x28 */
+       u32 tx_tsvl0;   /* 0x2c */
+       u32 tx_tsvh0;   /* 0x30 */
+       u32 tx_tsvl1;   /* 0x34 */
+       u32 tx_tsvh1;   /* 0x38 */
+       u32 rx_ctl;     /* 0x3c */
+       u32 rx_hash0;   /* 0x40 */
+       u32 rx_hash1;   /* 0x44 */
+       u32 rx_sta;     /* 0x48 */
+       u32 rx_io_data; /* 0x4c */
+       u32 rx_fbc;     /* 0x50 */
+       u32 int_ctl;    /* 0x54 */
+       u32 int_sta;    /* 0x58 */
+       u32 mac_ctl0;   /* 0x5c */
+       u32 mac_ctl1;   /* 0x60 */
+       u32 mac_ipgt;   /* 0x64 */
+       u32 mac_ipgr;   /* 0x68 */
+       u32 mac_clrt;   /* 0x6c */
+       u32 mac_maxf;   /* 0x70 */
+       u32 mac_supp;   /* 0x74 */
+       u32 mac_test;   /* 0x78 */
+       u32 mac_mcfg;   /* 0x7c */
+       u32 mac_mcmd;   /* 0x80 */
+       u32 mac_madr;   /* 0x84 */
+       u32 mac_mwtd;   /* 0x88 */
+       u32 mac_mrdd;   /* 0x8c */
+       u32 mac_mind;   /* 0x90 */
+       u32 mac_ssrr;   /* 0x94 */
+       u32 mac_a0;     /* 0x98 */
+       u32 mac_a1;     /* 0x9c */
+};
+
+/* SRAMC register  */
+struct sunxi_sramc_regs {
+       u32 ctrl0;
+       u32 ctrl1;
+};
+
+/* 0: Disable       1: Aborted frame enable(default) */
+#define EMAC_TX_AB_M           (0x1 << 0)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_TX_TM             (0x1 << 1)
+
+#define EMAC_TX_SETUP          (0)
+
+/* 0: DRQ asserted  1: DRQ automatically(default) */
+#define EMAC_RX_DRQ_MODE       (0x1 << 1)
+/* 0: CPU           1: DMA(default) */
+#define EMAC_RX_TM             (0x1 << 2)
+/* 0: Normal(default)        1: Pass all Frames */
+#define EMAC_RX_PA             (0x1 << 4)
+/* 0: Normal(default)        1: Pass Control Frames */
+#define EMAC_RX_PCF            (0x1 << 5)
+/* 0: Normal(default)        1: Pass Frames with CRC Error */
+#define EMAC_RX_PCRCE          (0x1 << 6)
+/* 0: Normal(default)        1: Pass Frames with Length Error */
+#define EMAC_RX_PLE            (0x1 << 7)
+/* 0: Normal                 1: Pass Frames length out of range(default) */
+#define EMAC_RX_POR            (0x1 << 8)
+/* 0: Not accept             1: Accept unicast Packets(default) */
+#define EMAC_RX_UCAD           (0x1 << 16)
+/* 0: Normal(default)        1: DA Filtering */
+#define EMAC_RX_DAF            (0x1 << 17)
+/* 0: Not accept             1: Accept multicast Packets(default) */
+#define EMAC_RX_MCO            (0x1 << 20)
+/* 0: Disable(default)       1: Enable Hash filter */
+#define EMAC_RX_MHF            (0x1 << 21)
+/* 0: Not accept             1: Accept Broadcast Packets(default) */
+#define EMAC_RX_BCO            (0x1 << 22)
+/* 0: Disable(default)       1: Enable SA Filtering */
+#define EMAC_RX_SAF            (0x1 << 24)
+/* 0: Normal(default)        1: Inverse Filtering */
+#define EMAC_RX_SAIF           (0x1 << 25)
+
+#define EMAC_RX_SETUP          (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
+                                EMAC_RX_MCO | EMAC_RX_BCO)
+
+/* 0: Disable                1: Enable Receive Flow Control(default) */
+#define EMAC_MAC_CTL0_RFC      (0x1 << 2)
+/* 0: Disable                1: Enable Transmit Flow Control(default) */
+#define EMAC_MAC_CTL0_TFC      (0x1 << 3)
+
+#define EMAC_MAC_CTL0_SETUP    (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
+
+/* 0: Disable                1: Enable MAC Frame Length Checking(default) */
+#define EMAC_MAC_CTL1_FLC      (0x1 << 1)
+/* 0: Disable(default)       1: Enable Huge Frame */
+#define EMAC_MAC_CTL1_HF       (0x1 << 2)
+/* 0: Disable(default)       1: Enable MAC Delayed CRC */
+#define EMAC_MAC_CTL1_DCRC     (0x1 << 3)
+/* 0: Disable                1: Enable MAC CRC(default) */
+#define EMAC_MAC_CTL1_CRC      (0x1 << 4)
+/* 0: Disable                1: Enable MAC PAD Short frames(default) */
+#define EMAC_MAC_CTL1_PC       (0x1 << 5)
+/* 0: Disable(default)       1: Enable MAC PAD Short frames and append CRC */
+#define EMAC_MAC_CTL1_VC       (0x1 << 6)
+/* 0: Disable(default)       1: Enable MAC auto detect Short frames */
+#define EMAC_MAC_CTL1_ADP      (0x1 << 7)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_PRE      (0x1 << 8)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_LPE      (0x1 << 9)
+/* 0: Disable(default)       1: Enable no back off */
+#define EMAC_MAC_CTL1_NB       (0x1 << 12)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_BNB      (0x1 << 13)
+/* 0: Disable(default)       1: Enable */
+#define EMAC_MAC_CTL1_ED       (0x1 << 14)
+
+#define EMAC_MAC_CTL1_SETUP    (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
+                                EMAC_MAC_CTL1_PC)
+
+#define EMAC_MAC_IPGT          0x15
+
+#define EMAC_MAC_NBTB_IPG1     0xC
+#define EMAC_MAC_NBTB_IPG2     0x12
+
+#define EMAC_MAC_CW            0x37
+#define EMAC_MAC_RM            0xF
+
+#define EMAC_MAC_MFL           0x0600
+
+/* Receive status */
+#define EMAC_CRCERR            (1 << 4)
+#define EMAC_LENERR            (3 << 5)
+
+#define DMA_CPU_TRRESHOLD      2000
+
+struct wemac_eth_dev {
+       u32 speed;
+       u32 duplex;
+       u32 phy_configured;
+       int link_printed;
+};
+
+struct wemac_rxhdr {
+       s16 rx_len;
+       u16 rx_status;
+};
+
+static void wemac_inblk_32bit(void *reg, void *data, int count)
+{
+       int cnt = (count + 3) >> 2;
+
+       if (cnt) {
+               u32 *buf = data;
+
+               do {
+                       u32 x = readl(reg);
+                       *buf++ = x;
+               } while (--cnt);
+       }
+}
+
+static void wemac_outblk_32bit(void *reg, void *data, int count)
+{
+       int cnt = (count + 3) >> 2;
+
+       if (cnt) {
+               const u32 *buf = data;
+
+               do {
+                       writel(*buf++, reg);
+               } while (--cnt);
+       }
+}
+
+/*
+ * Read a word from phyxcer
+ */
+static int wemac_phy_read(const char *devname, unsigned char addr,
+                         unsigned char reg, unsigned short *value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+       /* issue the phy address and reg */
+       writel(addr << 8 | reg, &regs->mac_madr);
+
+       /* pull up the phy io line */
+       writel(0x1, &regs->mac_mcmd);
+
+       /* Wait read complete */
+       mdelay(1);
+
+       /* push down the phy io line */
+       writel(0x0, &regs->mac_mcmd);
+
+       /* and write data */
+       *value = readl(&regs->mac_mrdd);
+
+       return 0;
+}
+
+/*
+ * Write a word to phyxcer
+ */
+static int wemac_phy_write(const char *devname, unsigned char addr,
+                          unsigned char reg, unsigned short value)
+{
+       struct eth_device *dev = eth_get_dev_by_name(devname);
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+       /* issue the phy address and reg */
+       writel(addr << 8 | reg, &regs->mac_madr);
+
+       /* pull up the phy io line */
+       writel(0x1, &regs->mac_mcmd);
+
+       /* Wait write complete */
+       mdelay(1);
+
+       /* push down the phy io line */
+       writel(0x0, &regs->mac_mcmd);
+
+       /* and write data */
+       writel(value, &regs->mac_mwtd);
+
+       return 0;
+}
+
+static void emac_setup(struct eth_device *dev)
+{
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+       u32 reg_val;
+       u16 phy_val;
+       u32 duplex_flag;
+
+       /* Set up TX */
+       writel(EMAC_TX_SETUP, &regs->tx_mode);
+
+       /* Set up RX */
+       writel(EMAC_RX_SETUP, &regs->rx_ctl);
+
+       /* Set MAC */
+       /* Set MAC CTL0 */
+       writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
+
+       /* Set MAC CTL1 */
+       wemac_phy_read(dev->name, 1, 0, &phy_val);
+       debug("PHY SETUP, reg 0 value: %x\n", phy_val);
+       duplex_flag = !!(phy_val & (1 << 8));
+
+       reg_val = 0;
+       if (duplex_flag)
+               reg_val = (0x1 << 0);
+       writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
+
+       /* Set up IPGT */
+       writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
+
+       /* Set up IPGR */
+       writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
+
+       /* Set up Collison window */
+       writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
+
+       /* Set up Max Frame Length */
+       writel(EMAC_MAC_MFL, &regs->mac_maxf);
+}
+
+static void wemac_reset(struct eth_device *dev)
+{
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+       debug("resetting device\n");
+
+       /* RESET device */
+       writel(0, &regs->ctl);
+       udelay(200);
+
+       writel(1, &regs->ctl);
+       udelay(200);
+}
+
+static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
+{
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+       struct wemac_eth_dev *priv = dev->priv;
+       u16 phy_reg;
+
+       /* Init EMAC */
+
+       /* Flush RX FIFO */
+       setbits_le32(&regs->rx_ctl, 0x8);
+       udelay(1);
+
+       /* Init MAC */
+
+       /* Soft reset MAC */
+       clrbits_le32(&regs->mac_ctl0, 1 << 15);
+
+       /* Set MII clock */
+       clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
+
+       /* Clear RX counter */
+       writel(0x0, &regs->rx_fbc);
+       udelay(1);
+
+       /* Set up EMAC */
+       emac_setup(dev);
+
+       writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
+              dev->enetaddr[2], &regs->mac_a1);
+       writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
+              dev->enetaddr[5], &regs->mac_a0);
+
+       mdelay(1);
+
+       wemac_reset(dev);
+
+       /* PHY POWER UP */
+       wemac_phy_read(dev->name, 1, 0, &phy_reg);
+       wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
+       mdelay(1);
+
+       wemac_phy_read(dev->name, 1, 0, &phy_reg);
+
+       priv->speed = miiphy_speed(dev->name, 0);
+       priv->duplex = miiphy_duplex(dev->name, 0);
+
+       /* Print link status only once */
+       if (!priv->link_printed) {
+               printf("ENET Speed is %d Mbps - %s duplex connection\n",
+                      priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
+               priv->link_printed = 1;
+       }
+
+       /* Set EMAC SPEED depend on PHY */
+       clrsetbits_le32(&regs->mac_supp, 1 << 8,
+                       ((phy_reg & (1 << 13)) >> 13) << 8);
+
+       /* Set duplex depend on phy */
+       clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
+                       ((phy_reg & (1 << 8)) >> 8) << 0);
+
+       /* Enable RX/TX */
+       setbits_le32(&regs->ctl, 0x7);
+
+       return 0;
+}
+
+static void sunxi_wemac_eth_halt(struct eth_device *dev)
+{
+       /* Nothing to do here */
+}
+
+static int sunxi_wemac_eth_recv(struct eth_device *dev)
+{
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+       struct wemac_rxhdr rxhdr;
+       u32 rxcount;
+       u32 reg_val;
+       int rx_len;
+       int rx_status;
+       int good_packet;
+
+       /* Check packet ready or not */
+
+       /*
+        * Race warning: The first packet might arrive with
+        * the interrupts disabled, but the second will fix
+        */
+       rxcount = readl(&regs->rx_fbc);
+       if (!rxcount) {
+               /* Had one stuck? */
+               rxcount = readl(&regs->rx_fbc);
+               if (!rxcount)
+                       return 0;
+       }
+
+       reg_val = readl(&regs->rx_io_data);
+       if (reg_val != 0x0143414d) {
+               /* Disable RX */
+               clrbits_le32(&regs->ctl, 1 << 2);
+
+               /* Flush RX FIFO */
+               setbits_le32(&regs->rx_ctl, 1 << 3);
+               while (readl(&regs->rx_ctl) & (1 << 3))
+                       ;
+
+               /* Enable RX */
+               setbits_le32(&regs->ctl, 1 << 2);
+
+               return 0;
+       }
+
+       /*
+        * A packet ready now
+        * Get status/length
+        */
+       good_packet = 1;
+
+       wemac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
+
+       rx_len = rxhdr.rx_len;
+       rx_status = rxhdr.rx_status;
+
+       /* Packet Status check */
+       if (rx_len < 0x40) {
+               good_packet = 0;
+               debug("RX: Bad Packet (runt)\n");
+       }
+
+       /* rx_status is identical to RSR register. */
+       if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
+               good_packet = 0;
+               if (rx_status & EMAC_CRCERR)
+                       printf("crc error\n");
+               if (rx_status & EMAC_LENERR)
+                       printf("length error\n");
+       }
+
+       /* Move data from WEMAC */
+       if (good_packet) {
+               if (rx_len > DMA_CPU_TRRESHOLD) {
+                       printf("Received packet is too big (len=%d)\n", rx_len);
+               } else {
+                       wemac_inblk_32bit((void *)&regs->rx_io_data,
+                                         NetRxPackets[0], rx_len);
+
+                       /* Pass to upper layer */
+                       NetReceive(NetRxPackets[0], rx_len);
+                       return rx_len;
+               }
+       }
+
+       return 0;
+}
+
+static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
+{
+       struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
+
+       /* Select channel 0 */
+       writel(0, &regs->tx_ins);
+
+       /* Write packet */
+       wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
+
+       /* Set TX len */
+       writel(len, &regs->tx_pl0);
+
+       /* Start translate from fifo to phy */
+       setbits_le32(&regs->tx_ctl0, 1);
+
+       return 0;
+}
+
+int sunxi_wemac_initialize(void)
+{
+       struct sunxi_ccm_reg *const ccm =
+               (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+       struct sunxi_sramc_regs *sram =
+               (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
+       struct eth_device *dev;
+       struct wemac_eth_dev *priv;
+       int pin;
+
+       dev = malloc(sizeof(*dev));
+       if (dev == NULL)
+               return -ENOMEM;
+
+       priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
+       if (!priv) {
+               free(dev);
+               return -ENOMEM;
+       }
+
+       memset(dev, 0, sizeof(*dev));
+       memset(priv, 0, sizeof(struct wemac_eth_dev));
+
+       /* Map SRAM to EMAC */
+       setbits_le32(&sram->ctrl1, 0x5 << 2);
+
+       /* Configure pin mux settings for MII Ethernet */
+       for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
+               sunxi_gpio_set_cfgpin(pin, 2);
+
+       /* Set up clock gating */
+       setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
+
+       dev->iobase = SUNXI_EMAC_BASE;
+       dev->priv = priv;
+       dev->init = sunxi_wemac_eth_init;
+       dev->halt = sunxi_wemac_eth_halt;
+       dev->send = sunxi_wemac_eth_send;
+       dev->recv = sunxi_wemac_eth_recv;
+       strcpy(dev->name, "wemac");
+
+       eth_register(dev);
+
+       miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
+
+       return 0;
+}
index 65692fd2a69f59b911fc64301e82b3bd21b95b93..9e05ddc1329ae2ce60fe7b2bfc84e6da66b41445 100644 (file)
@@ -110,6 +110,8 @@ static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
 }
 #endif
 
+extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
+
 extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
                           char *const argv[]);
 
index 8d2673dacbc6e1ab9b91cfa561df7a38ec4b0243..b4b1c319606828f037e823f1cb701649f533b4bf 100644 (file)
 #define CONFIG_DOS_PARTITION
 #endif
 
+/* Ethernet */
+#define CONFIG_KS8851_MLL
+#define CONFIG_KS8851_MLL_BASEADDR     0x30000000 /* use NCS2 */
+
 #define CONFIG_SYS_LOAD_ADDR           0x22000000 /* load address */
 
 #define CONFIG_SYS_MEMTEST_START       CONFIG_SYS_SDRAM_BASE
index fcb20fe1082f7047f9fe8037a514d3aea9c45742..f6dbdb096d34c220d12962fe627bc8eb3e401ea0 100644 (file)
@@ -580,6 +580,8 @@ enum ethtool_sfeatures_retval_bits {
 #define SUPPORTED_10000baseKX4_Full    (1 << 18)
 #define SUPPORTED_10000baseKR_Full     (1 << 19)
 #define SUPPORTED_10000baseR_FEC       (1 << 20)
+#define SUPPORTED_1000baseX_Half       (1 << 21)
+#define SUPPORTED_1000baseX_Full       (1 << 22)
 
 /* Indicates what features are advertised by the interface. */
 #define ADVERTISED_10baseT_Half                (1 << 0)
@@ -603,6 +605,8 @@ enum ethtool_sfeatures_retval_bits {
 #define ADVERTISED_10000baseKX4_Full   (1 << 18)
 #define ADVERTISED_10000baseKR_Full    (1 << 19)
 #define ADVERTISED_10000baseR_FEC      (1 << 20)
+#define ADVERTISED_1000baseX_Half      (1 << 21)
+#define ADVERTISED_1000baseX_Full      (1 << 22)
 
 /* The following are all involved in forcing a particular link
  * mode for the device for setting things.  When getting the
index 8b92692146d687db55c61e62c640f745176da509..66b83d83deb4fc5d285e8ad89ca27f0cab3acad4 100644 (file)
 #define EXPANSION_MFAULTS      0x0010  /* Multiple faults detected    */
 #define EXPANSION_RESV         0xffe0  /* Unused...                   */
 
+#define ESTATUS_1000_XFULL     0x8000  /* Can do 1000BX Full */
+#define ESTATUS_1000_XHALF     0x4000  /* Can do 1000BX Half */
 #define ESTATUS_1000_TFULL     0x2000  /* Can do 1000BT Full */
 #define ESTATUS_1000_THALF     0x1000  /* Can do 1000BT Half */
 
index 25e8a4624b75978c2af1f38508d9fc369c0e6db7..e1c62d83cb3d6a0cc890f7b696d6905b49c17ee7 100644 (file)
@@ -8,9 +8,20 @@
 #define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW     0x105
 #define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW     0x106
 #define MII_KSZ9021_EXT_ANALOG_TEST            0x107
+/* Register operations */
+#define MII_KSZ9031_MOD_REG                    0x0000
+/* Data operations */
+#define MII_KSZ9031_MOD_DATA_NO_POST_INC       0x4000
+#define MII_KSZ9031_MOD_DATA_POST_INC_RW       0x8000
+#define MII_KSZ9031_MOD_DATA_POST_INC_W                0xC000
 
 struct phy_device;
 int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val);
 int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum);
 
+int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr,
+                              int regnum, u16 mode, u16 val);
+int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
+                             int regnum, u16 mode);
+
 #endif
index 23fb947292ccf3e1e1b805e86c11ac75106f3107..7673470046f596263e170d0facbdffba74540299 100644 (file)
@@ -39,7 +39,7 @@
 #define PKTALIGN       ARCH_DMA_MINALIGN
 
 /* IPv4 addresses are always 32 bits in size */
-typedef u32            IPaddr_t;
+typedef __be32         IPaddr_t;
 
 
 /**
index df454b50c3bc4fdcff762313e4b958a165e342f7..917d8746fb04c7e7175c8faafda30c41748f22b1 100644 (file)
@@ -67,10 +67,12 @@ int fecmxc_initialize(bd_t *bis);
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
 int ks8695_eth_initialize(void);
+int ks8851_mll_initialize(u8 dev_num, int base_addr);
 int lan91c96_initialize(u8 dev_num, int base_addr);
 int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
 int mcdmafec_initialize(bd_t *bis);
@@ -93,6 +95,7 @@ int sh_eth_initialize(bd_t *bis);
 int skge_initialize(bd_t *bis);
 int smc91111_initialize(u8 dev_num, int base_addr);
 int smc911x_initialize(u8 dev_num, int base_addr);
+int sunxi_wemac_initialize(bd_t *bis);
 int tsi108_eth_initialize(bd_t *bis);
 int uec_standard_init(bd_t *bis);
 int uli526x_initialize(bd_t *bis);
index 75bf3b4728d62f8c8308b3fa642306d80145471f..dbf32740bb3c252c8090b507f1f8717089825895 100644 (file)
@@ -214,6 +214,7 @@ int phy_register(struct phy_driver *drv);
 int genphy_config_aneg(struct phy_device *phydev);
 int genphy_restart_aneg(struct phy_device *phydev);
 int genphy_update_link(struct phy_device *phydev);
+int genphy_parse_link(struct phy_device *phydev);
 int genphy_config(struct phy_device *phydev);
 int genphy_startup(struct phy_device *phydev);
 int genphy_shutdown(struct phy_device *phydev);
index 1ba796ebdf949999f8663ff30049c1c085d43f56..4152fae5bacba34c051bf2f877a11d435630325e 100644 (file)
@@ -206,6 +206,7 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)
 {
        int source_ip_conflict;
        int target_ip_conflict;
+       IPaddr_t null_ip = 0;
 
        if (state == DISABLED)
                return;
@@ -267,10 +268,18 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)
        ) {
                source_ip_conflict = 1;
        }
-       if (arp->ar_op == htons(ARPOP_REQUEST)
-        && memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0
-        && memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0
-       ) {
+
+       /*
+        * According to RFC 3927, section 2.2.1:
+        * Check if packet is an ARP probe by checking for a null source IP
+        * then check that target IP is equal to ours and source hw addr
+        * is not equal to ours. This condition should cause a conflict only
+        * during probe.
+        */
+       if (arp->ar_op == htons(ARPOP_REQUEST) &&
+           memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 &&
+           memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 &&
+           memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) {
                target_ip_conflict = 1;
        }
 
index 7f2393f6064c62976ea3bf0c5f10a2ac22e7d443..381b75f1c5b091799876aa77ec8997c97ea14fa9 100644 (file)
--- a/net/nfs.c
+++ b/net/nfs.c
 # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
 #endif
 
+#define NFS_RPC_ERR    1
+#define NFS_RPC_DROP   124
+
 static int fs_mounted;
 static unsigned long rpc_id;
 static int nfs_offset = -1;
 static int nfs_len;
+static ulong nfs_timeout = NFS_TIMEOUT;
 
 static char dirfh[NFS_FHSIZE]; /* file handle of directory */
 static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
@@ -399,8 +403,10 @@ rpc_lookup_reply(int prog, uchar *pkt, unsigned len)
 
        debug("%s\n", __func__);
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -428,8 +434,10 @@ nfs_mount_reply(uchar *pkt, unsigned len)
 
        memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -452,8 +460,10 @@ nfs_umountall_reply(uchar *pkt, unsigned len)
 
        memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -475,8 +485,10 @@ nfs_lookup_reply(uchar *pkt, unsigned len)
 
        memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -499,8 +511,10 @@ nfs_readlink_reply(uchar *pkt, unsigned len)
 
        memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -534,8 +548,10 @@ nfs_read_reply(uchar *pkt, unsigned len)
 
        memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
 
-       if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-               return -1;
+       if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+               return -NFS_RPC_ERR;
+       else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+               return -NFS_RPC_DROP;
 
        if (rpc_pkt.u.reply.rstatus  ||
            rpc_pkt.u.reply.verifier ||
@@ -574,7 +590,8 @@ NfsTimeout(void)
                NetStartAgain();
        } else {
                puts("T ");
-               NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+               NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount,
+                             NfsTimeout);
                NfsSend();
        }
 }
@@ -583,6 +600,7 @@ static void
 NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 {
        int rlen;
+       int reply;
 
        debug("%s\n", __func__);
 
@@ -591,19 +609,24 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 
        switch (NfsState) {
        case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-               rpc_lookup_reply(PROG_MOUNT, pkt, len);
+               if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
+                       break;
                NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;
                NfsSend();
                break;
 
        case STATE_PRCLOOKUP_PROG_NFS_REQ:
-               rpc_lookup_reply(PROG_NFS, pkt, len);
+               if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
+                       break;
                NfsState = STATE_MOUNT_REQ;
                NfsSend();
                break;
 
        case STATE_MOUNT_REQ:
-               if (nfs_mount_reply(pkt, len)) {
+               reply = nfs_mount_reply(pkt, len);
+               if (reply == -NFS_RPC_DROP)
+                       break;
+               else if (reply == -NFS_RPC_ERR) {
                        puts("*** ERROR: Cannot mount\n");
                        /* just to be sure... */
                        NfsState = STATE_UMOUNT_REQ;
@@ -615,7 +638,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
                break;
 
        case STATE_UMOUNT_REQ:
-               if (nfs_umountall_reply(pkt, len)) {
+               reply = nfs_umountall_reply(pkt, len);
+               if (reply == -NFS_RPC_DROP)
+                       break;
+               else if (reply == -NFS_RPC_ERR) {
                        puts("*** ERROR: Cannot umount\n");
                        net_set_state(NETLOOP_FAIL);
                } else {
@@ -625,7 +651,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
                break;
 
        case STATE_LOOKUP_REQ:
-               if (nfs_lookup_reply(pkt, len)) {
+               reply = nfs_lookup_reply(pkt, len);
+               if (reply == -NFS_RPC_DROP)
+                       break;
+               else if (reply == -NFS_RPC_ERR) {
                        puts("*** ERROR: File lookup fail\n");
                        NfsState = STATE_UMOUNT_REQ;
                        NfsSend();
@@ -638,7 +667,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
                break;
 
        case STATE_READLINK_REQ:
-               if (nfs_readlink_reply(pkt, len)) {
+               reply = nfs_readlink_reply(pkt, len);
+               if (reply == -NFS_RPC_DROP)
+                       break;
+               else if (reply == -NFS_RPC_ERR) {
                        puts("*** ERROR: Symlink fail\n");
                        NfsState = STATE_UMOUNT_REQ;
                        NfsSend();
@@ -654,7 +686,7 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 
        case STATE_READ_REQ:
                rlen = nfs_read_reply(pkt, len);
-               NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+               NetSetTimeout(nfs_timeout, NfsTimeout);
                if (rlen > 0) {
                        nfs_offset += rlen;
                        NfsSend();
@@ -738,7 +770,7 @@ NfsStart(void)
        printf("\nLoad address: 0x%lx\n"
                "Loading: *\b", load_addr);
 
-       NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
+       NetSetTimeout(nfs_timeout, NfsTimeout);
        net_set_udp_handler(NfsHandler);
 
        NfsTimeoutCount = 0;
index 09790eb7cf8202c051d594b5243aa3f843746691..6d333d559c19db8a9eac6a26ec01eaf73096babb 100644 (file)
@@ -446,8 +446,8 @@ static void
 TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
            unsigned len)
 {
-       ushort proto;
-       ushort *s;
+       __be16 proto;
+       __be16 *s;
        int i;
 
        if (dest != TftpOurPort) {
@@ -465,7 +465,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                return;
        len -= 2;
        /* warning: don't use increment (++) in ntohs() macros!! */
-       s = (ushort *)pkt;
+       s = (__be16 *)pkt;
        proto = *s++;
        pkt = (uchar *)s;
        switch (ntohs(proto)) {
@@ -556,7 +556,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
                if (len < 2)
                        return;
                len -= 2;
-               TftpBlock = ntohs(*(ushort *)pkt);
+               TftpBlock = ntohs(*(__be16 *)pkt);
 
                update_block_number();
 
@@ -644,9 +644,9 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
 
        case TFTP_ERROR:
                printf("\nTFTP error: '%s' (%d)\n",
-                      pkt + 2, ntohs(*(ushort *)pkt));
+                      pkt + 2, ntohs(*(__be16 *)pkt));
 
-               switch (ntohs(*(ushort *)pkt)) {
+               switch (ntohs(*(__be16 *)pkt)) {
                case TFTP_ERR_FILE_NOT_FOUND:
                case TFTP_ERR_ACCESS_DENIED:
                        puts("Not retrying...\n");