diff options
34 files changed, 3116 insertions, 220 deletions
| diff --git a/.checkpatch.conf b/.checkpatch.conf index d88af5712..35167e120 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -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 diff --git a/board/atmel/at91sam9n12ek/at91sam9n12ek.c b/board/atmel/at91sam9n12ek/at91sam9n12ek.c index 8752794c8..3013a42a2 100644 --- a/board/atmel/at91sam9n12ek/at91sam9n12ek.c +++ b/board/atmel/at91sam9n12ek/at91sam9n12ek.c @@ -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, diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 05130b693..e452fcac9 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -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; diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 2dbd49cbd..1fb75d8ae 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -26,12 +26,21 @@  #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);  } diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 786a6567a..9cf2983d1 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -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 diff --git a/drivers/net/designware.c b/drivers/net/designware.c index bf21a08bd..46f6601fa 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -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) { diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 69ba57d3d..2dbb328b8 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,11 +27,13 @@  #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 @@ -40,8 +42,10 @@  #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 index 000000000..579dcc72f --- /dev/null +++ b/drivers/net/ftmac110.c @@ -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, ®s->phycr); + +	for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) { +		tmp = readl(®s->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, ®s->phydr); +	writel(tmp, ®s->phycr); + +	for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) { +		if (readl(®s->phycr) & PHYCR_WRITE) +			continue; +		break; +	} + +	if (readl(®s->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, ®s->maccr); +	for (i = get_timer(0); get_timer(i) < 1000; ) { +		if (readl(®s->maccr) & MACCR_RESET) +			continue; +		break; +	} +	if (readl(®s->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), ®s->mac[0]); +	writel(a[5] | (a[4] << 8) | (a[3] << 16) +		| (a[2] << 24), ®s->mac[1]); + +	/* 5. MAC registers setup */ +	writel(chip->rxd_dma, ®s->rxba); +	writel(chip->txd_dma, ®s->txba); +	/* interrupt at each tx/rx */ +	writel(ITC_DEFAULT, ®s->itc); +	/* no tx pool, rx poll = 1 normal cycle */ +	writel(APTC_DEFAULT, ®s->aptc); +	/* rx threshold = [6/8 fifo, 2/8 fifo] */ +	writel(DBLAC_DEFAULT, ®s->dblac); +	/* disable & clear all interrupt status */ +	chip->imr = 0; +	writel(ISR_ALL, ®s->isr); +	writel(chip->imr, ®s->imr); +	/* enable mac */ +	writel(chip->maccr, ®s->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, ®s->imr); +	writel(0, ®s->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, ®s->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, ®s->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 index 000000000..5b2d23b0d --- /dev/null +++ b/drivers/net/ftmac110.h @@ -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 index 000000000..b02d59a1b --- /dev/null +++ b/drivers/net/ks8851_mll.c @@ -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 index 000000000..7f90ae4e5 --- /dev/null +++ b/drivers/net/ks8851_mll.h @@ -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 diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 8bacbda71..b7802a2fe 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -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;  } diff --git a/drivers/net/macb.h b/drivers/net/macb.h index f92a20c70..68eef00c0 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -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 @@ -138,6 +140,13 @@  #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 @@ -146,6 +155,10 @@  #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 @@ -240,12 +253,25 @@  #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 @@ -255,21 +281,38 @@  /* 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__ */ diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 47bf27c8b..319fe8aba 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -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, diff --git a/drivers/net/mvgbe.h b/drivers/net/mvgbe.h index d8a5429de..7f5d98ff5 100644 --- a/drivers/net/mvgbe.h +++ b/drivers/net/mvgbe.h @@ -308,10 +308,17 @@  #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 diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index af5f4b848..695873eaa 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -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 diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 9b3808bfa..09d487971 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -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 index 000000000..dd5c59259 --- /dev/null +++ b/drivers/net/phy/icplus.c @@ -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; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 46801c791..8397e32e1 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -89,6 +89,12 @@  #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); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 30f326489..aa9cbcfff 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -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;  } diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c index ea60ac1b0..6dc7ed505 100644 --- a/drivers/net/phy/natsemi.c +++ b/drivers/net/phy/natsemi.c @@ -22,6 +22,42 @@   */  #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; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f8c548147..7c0eaec51 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -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 index 000000000..1db3529c2 --- /dev/null +++ b/drivers/net/sunxi_wemac.c @@ -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, ®s->mac_madr); + +	/* pull up the phy io line */ +	writel(0x1, ®s->mac_mcmd); + +	/* Wait read complete */ +	mdelay(1); + +	/* push down the phy io line */ +	writel(0x0, ®s->mac_mcmd); + +	/* and write data */ +	*value = readl(®s->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, ®s->mac_madr); + +	/* pull up the phy io line */ +	writel(0x1, ®s->mac_mcmd); + +	/* Wait write complete */ +	mdelay(1); + +	/* push down the phy io line */ +	writel(0x0, ®s->mac_mcmd); + +	/* and write data */ +	writel(value, ®s->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, ®s->tx_mode); + +	/* Set up RX */ +	writel(EMAC_RX_SETUP, ®s->rx_ctl); + +	/* Set MAC */ +	/* Set MAC CTL0 */ +	writel(EMAC_MAC_CTL0_SETUP, ®s->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, ®s->mac_ctl1); + +	/* Set up IPGT */ +	writel(EMAC_MAC_IPGT, ®s->mac_ipgt); + +	/* Set up IPGR */ +	writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr); + +	/* Set up Collison window */ +	writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt); + +	/* Set up Max Frame Length */ +	writel(EMAC_MAC_MFL, ®s->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, ®s->ctl); +	udelay(200); + +	writel(1, ®s->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(®s->rx_ctl, 0x8); +	udelay(1); + +	/* Init MAC */ + +	/* Soft reset MAC */ +	clrbits_le32(®s->mac_ctl0, 1 << 15); + +	/* Set MII clock */ +	clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); + +	/* Clear RX counter */ +	writel(0x0, ®s->rx_fbc); +	udelay(1); + +	/* Set up EMAC */ +	emac_setup(dev); + +	writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | +	       dev->enetaddr[2], ®s->mac_a1); +	writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | +	       dev->enetaddr[5], ®s->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(®s->mac_supp, 1 << 8, +			((phy_reg & (1 << 13)) >> 13) << 8); + +	/* Set duplex depend on phy */ +	clrsetbits_le32(®s->mac_ctl1, 1 << 0, +			((phy_reg & (1 << 8)) >> 8) << 0); + +	/* Enable RX/TX */ +	setbits_le32(®s->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(®s->rx_fbc); +	if (!rxcount) { +		/* Had one stuck? */ +		rxcount = readl(®s->rx_fbc); +		if (!rxcount) +			return 0; +	} + +	reg_val = readl(®s->rx_io_data); +	if (reg_val != 0x0143414d) { +		/* Disable RX */ +		clrbits_le32(®s->ctl, 1 << 2); + +		/* Flush RX FIFO */ +		setbits_le32(®s->rx_ctl, 1 << 3); +		while (readl(®s->rx_ctl) & (1 << 3)) +			; + +		/* Enable RX */ +		setbits_le32(®s->ctl, 1 << 2); + +		return 0; +	} + +	/* +	 * A packet ready now +	 * Get status/length +	 */ +	good_packet = 1; + +	wemac_inblk_32bit(®s->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 *)®s->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, ®s->tx_ins); + +	/* Write packet */ +	wemac_outblk_32bit((void *)®s->tx_io_data, packet, len); + +	/* Set TX len */ +	writel(len, ®s->tx_pl0); + +	/* Start translate from fifo to phy */ +	setbits_le32(®s->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; +} diff --git a/include/command.h b/include/command.h index 65692fd2a..9e05ddc13 100644 --- a/include/command.h +++ b/include/command.h @@ -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[]); diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h index 8d2673dac..b4b1c3196 100644 --- a/include/configs/at91sam9n12ek.h +++ b/include/configs/at91sam9n12ek.h @@ -167,6 +167,10 @@  #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 diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index fcb20fe10..f6dbdb096 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -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 diff --git a/include/linux/mii.h b/include/linux/mii.h index 8b9269214..66b83d83d 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -115,6 +115,8 @@  #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 */ diff --git a/include/micrel.h b/include/micrel.h index 25e8a4624..e1c62d83c 100644 --- a/include/micrel.h +++ b/include/micrel.h @@ -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 diff --git a/include/net.h b/include/net.h index 23fb94729..767347004 100644 --- a/include/net.h +++ b/include/net.h @@ -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;  /** diff --git a/include/netdev.h b/include/netdev.h index df454b50c..917d8746f 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -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); diff --git a/include/phy.h b/include/phy.h index 75bf3b472..dbf32740b 100644 --- a/include/phy.h +++ b/include/phy.h @@ -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); diff --git a/net/link_local.c b/net/link_local.c index 1ba796ebd..4152fae5b 100644 --- a/net/link_local.c +++ b/net/link_local.c @@ -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;  	} @@ -37,10 +37,14 @@  # 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; diff --git a/net/tftp.c b/net/tftp.c index 09790eb7c..6d333d559 100644 --- a/net/tftp.c +++ b/net/tftp.c @@ -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"); |