Merge branch 'master' of git://git.denx.de/u-boot-net

This commit is contained in:
Tom Rini 2013-06-24 22:27:44 -04:00
commit ca85eb8c42
34 changed files with 3117 additions and 221 deletions

View file

@ -18,3 +18,6 @@
# Not Linux, so we don't recommend usleep_range() over udelay()
--ignore USLEEP_RANGE
# Ignore networking block comment style
--ignore NETWORKING_BLOCK_COMMENT_STYLE

View file

@ -33,6 +33,7 @@
#include <lcd.h>
#include <atmel_hlcdc.h>
#include <atmel_mci.h>
#include <netdev.h>
#ifdef CONFIG_LCD_INFO
#include <nand.h>
@ -190,6 +191,30 @@ int board_mmc_init(bd_t *bd)
}
#endif
#ifdef CONFIG_KS8851_MLL
void at91sam9n12ek_ks8851_hw_init(void)
{
struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC;
writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) |
AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0),
&smc->cs[2].setup);
writel(AT91_SMC_PULSE_NWE(7) | AT91_SMC_PULSE_NCS_WR(7) |
AT91_SMC_PULSE_NRD(7) | AT91_SMC_PULSE_NCS_RD(7),
&smc->cs[2].pulse);
writel(AT91_SMC_CYCLE_NWE(9) | AT91_SMC_CYCLE_NRD(9),
&smc->cs[2].cycle);
writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE |
AT91_SMC_MODE_EXNW_DISABLE |
AT91_SMC_MODE_BAT | AT91_SMC_MODE_DBW_16 |
AT91_SMC_MODE_TDF_CYCLE(1),
&smc->cs[2].mode);
/* Configure NCS2 PIN */
at91_set_b_periph(AT91_PIO_PORTD, 19, 0);
}
#endif
int board_early_init_f(void)
{
/* Enable clocks for all PIOs */
@ -217,9 +242,20 @@ int board_init(void)
at91_lcd_hw_init();
#endif
#ifdef CONFIG_KS8851_MLL
at91sam9n12ek_ks8851_hw_init();
#endif
return 0;
}
#ifdef CONFIG_KS8851_MLL
int board_eth_init(bd_t *bis)
{
return ks8851_mll_initialize(0, CONFIG_KS8851_MLL_BASEADDR);
}
#endif
int dram_init(void)
{
gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE,

View file

@ -1707,7 +1707,7 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
return 0;
}
static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
bootm_headers_t images;

View file

@ -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;
uchar ethaddr[6];
ethaddr = from_env("ethaddr");
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-");
if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(),
ethaddr))
return -ENOENT;
for (p = outbuf + 3; *ethaddr; ethaddr++, p++) {
if (*ethaddr == ':')
*p = '-';
else
*p = tolower(*ethaddr);
}
*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;
const char *c = label->menu ? label->menu : label->name;
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);
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) {
if (label->localboot_val >= 0)
label_localboot(label);
return;
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,9 +1052,7 @@ 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);
if (!cfg->default_label)
cfg->default_label = strdup(label->name);
if (!cfg->default_label)
@ -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);
}

View file

@ -46,10 +46,12 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
COBJS-$(CONFIG_FTMAC110) += ftmac110.o
COBJS-$(CONFIG_FTMAC100) += ftmac100.o
COBJS-$(CONFIG_GRETH) += greth.o
COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
COBJS-$(CONFIG_LAN91C96) += lan91c96.o
COBJS-$(CONFIG_MACB) += macb.o
COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
@ -68,6 +70,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o
COBJS-$(CONFIG_SH_ETHER) += sh_eth.o
COBJS-$(CONFIG_SMC91111) += smc91111.o
COBJS-$(CONFIG_SMC911X) += smc911x.o
COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o
COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o
COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o
COBJS-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o

View file

@ -113,6 +113,8 @@ static int mac_reset(struct eth_device *dev)
int timeout = CONFIG_MACRESET_TIMEOUT;
writel(DMAMAC_SRST, &dma_p->busmode);
if (priv->interface != PHY_INTERFACE_MODE_RGMII)
writel(MII_PORTSELECT, &mac_p->conf);
start = get_timer(0);

View file

@ -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;

473
drivers/net/ftmac110.c Normal file
View file

@ -0,0 +1,473 @@
/*
* Faraday 10/100Mbps Ethernet Controller
*
* (C) Copyright 2010 Faraday Technology
* Dante Su <dantesu@faraday-tech.com>
*
* This file is released under the terms of GPL v2 and any later version.
* See the file COPYING in the root directory of the source tree for details.
*/
#include <common.h>
#include <command.h>
#include <malloc.h>
#include <net.h>
#include <asm/errno.h>
#include <asm/io.h>
#include <asm/dma-mapping.h>
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#include <miiphy.h>
#endif
#include "ftmac110.h"
#define CFG_RXDES_NUM 8
#define CFG_TXDES_NUM 2
#define CFG_XBUF_SIZE 1536
#define CFG_MDIORD_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
#define CFG_MDIOWR_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */
#define CFG_LINKUP_TIMEOUT (CONFIG_SYS_HZ << 2) /* 4 sec */
/*
* FTMAC110 DMA design issue
*
* Its DMA engine has a weird restriction that its Rx DMA engine
* accepts only 16-bits aligned address, 32-bits aligned is not
* acceptable. However this restriction does not apply to Tx DMA.
*
* Conclusion:
* (1) Tx DMA Buffer Address:
* 1 bytes aligned: Invalid
* 2 bytes aligned: O.K
* 4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
* (2) Rx DMA Buffer Address:
* 1 bytes aligned: Invalid
* 2 bytes aligned: O.K
* 4 bytes aligned: Invalid
*/
struct ftmac110_chip {
void __iomem *regs;
uint32_t imr;
uint32_t maccr;
uint32_t lnkup;
uint32_t phy_addr;
struct ftmac110_rxd *rxd;
ulong rxd_dma;
uint32_t rxd_idx;
struct ftmac110_txd *txd;
ulong txd_dma;
uint32_t txd_idx;
};
static int ftmac110_reset(struct eth_device *dev);
static uint16_t mdio_read(struct eth_device *dev,
uint8_t phyaddr, uint8_t phyreg)
{
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_regs __iomem *regs = chip->regs;
uint32_t tmp, ts;
uint16_t ret = 0xffff;
tmp = PHYCR_READ
| (phyaddr << PHYCR_ADDR_SHIFT)
| (phyreg << PHYCR_REG_SHIFT);
writel(tmp, &regs->phycr);
for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
tmp = readl(&regs->phycr);
if (tmp & PHYCR_READ)
continue;
break;
}
if (tmp & PHYCR_READ)
printf("ftmac110: mdio read timeout\n");
else
ret = (uint16_t)(tmp & 0xffff);
return ret;
}
static void mdio_write(struct eth_device *dev,
uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
{
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_regs __iomem *regs = chip->regs;
uint32_t tmp, ts;
tmp = PHYCR_WRITE
| (phyaddr << PHYCR_ADDR_SHIFT)
| (phyreg << PHYCR_REG_SHIFT);
writel(phydata, &regs->phydr);
writel(tmp, &regs->phycr);
for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
if (readl(&regs->phycr) & PHYCR_WRITE)
continue;
break;
}
if (readl(&regs->phycr) & PHYCR_WRITE)
printf("ftmac110: mdio write timeout\n");
}
static uint32_t ftmac110_phyqry(struct eth_device *dev)
{
ulong ts;
uint32_t maccr;
uint16_t pa, tmp, bmsr, bmcr;
struct ftmac110_chip *chip = dev->priv;
/* Default = 100Mbps Full */
maccr = MACCR_100M | MACCR_FD;
/* 1. find the phy device */
for (pa = 0; pa < 32; ++pa) {
tmp = mdio_read(dev, pa, MII_PHYSID1);
if (tmp == 0xFFFF || tmp == 0x0000)
continue;
chip->phy_addr = pa;
break;
}
if (pa >= 32) {
puts("ftmac110: phy device not found!\n");
goto exit;
}
/* 2. wait until link-up & auto-negotiation complete */
chip->lnkup = 0;
bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
ts = get_timer(0);
do {
bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
if (!chip->lnkup)
continue;
if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
break;
} while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
if (!chip->lnkup) {
puts("ftmac110: link down\n");
goto exit;
}
if (!(bmcr & BMCR_ANENABLE))
puts("ftmac110: auto negotiation disabled\n");
else if (!(bmsr & BMSR_ANEGCOMPLETE))
puts("ftmac110: auto negotiation timeout\n");
/* 3. derive MACCR */
if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
tmp = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
if (tmp & LPA_100FULL) /* 100Mbps full-duplex */
maccr = MACCR_100M | MACCR_FD;
else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
maccr = MACCR_100M;
else if (tmp & LPA_10FULL) /* 10Mbps full-duplex */
maccr = MACCR_FD;
else if (tmp & LPA_10HALF) /* 10Mbps half-duplex */
maccr = 0;
} else {
if (bmcr & BMCR_SPEED100)
maccr = MACCR_100M;
else
maccr = 0;
if (bmcr & BMCR_FULLDPLX)
maccr |= MACCR_FD;
}
exit:
printf("ftmac110: %d Mbps, %s\n",
(maccr & MACCR_100M) ? 100 : 10,
(maccr & MACCR_FD) ? "Full" : "half");
return maccr;
}
static int ftmac110_reset(struct eth_device *dev)
{
uint8_t *a;
uint32_t i, maccr;
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_regs __iomem *regs = chip->regs;
/* 1. MAC reset */
writel(MACCR_RESET, &regs->maccr);
for (i = get_timer(0); get_timer(i) < 1000; ) {
if (readl(&regs->maccr) & MACCR_RESET)
continue;
break;
}
if (readl(&regs->maccr) & MACCR_RESET) {
printf("ftmac110: reset failed\n");
return -ENXIO;
}
/* 1-1. Init tx ring */
for (i = 0; i < CFG_TXDES_NUM; ++i) {
/* owned by SW */
chip->txd[i].ct[0] = 0;
}
chip->txd_idx = 0;
/* 1-2. Init rx ring */
for (i = 0; i < CFG_RXDES_NUM; ++i) {
/* owned by HW */
chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
}
chip->rxd_idx = 0;
/* 2. PHY status query */
maccr = ftmac110_phyqry(dev);
/* 3. Fix up the MACCR value */
chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
/* 4. MAC address setup */
a = dev->enetaddr;
writel(a[1] | (a[0] << 8), &regs->mac[0]);
writel(a[5] | (a[4] << 8) | (a[3] << 16)
| (a[2] << 24), &regs->mac[1]);
/* 5. MAC registers setup */
writel(chip->rxd_dma, &regs->rxba);
writel(chip->txd_dma, &regs->txba);
/* interrupt at each tx/rx */
writel(ITC_DEFAULT, &regs->itc);
/* no tx pool, rx poll = 1 normal cycle */
writel(APTC_DEFAULT, &regs->aptc);
/* rx threshold = [6/8 fifo, 2/8 fifo] */
writel(DBLAC_DEFAULT, &regs->dblac);
/* disable & clear all interrupt status */
chip->imr = 0;
writel(ISR_ALL, &regs->isr);
writel(chip->imr, &regs->imr);
/* enable mac */
writel(chip->maccr, &regs->maccr);
return 0;
}
static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
{
debug("ftmac110: probe\n");
if (ftmac110_reset(dev))
return -1;
return 0;
}
static void ftmac110_halt(struct eth_device *dev)
{
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_regs __iomem *regs = chip->regs;
writel(0, &regs->imr);
writel(0, &regs->maccr);
debug("ftmac110: halt\n");
}
static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
{
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_regs __iomem *regs = chip->regs;
struct ftmac110_txd *des;
if (!chip->lnkup)
return 0;
if (len <= 0 || len > CFG_XBUF_SIZE) {
printf("ftmac110: bad tx pkt len(%d)\n", len);
return 0;
}
len = max(60, len);
des = &chip->txd[chip->txd_idx];
if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
/* kick-off Tx DMA */
writel(0xffffffff, &regs->txpd);
printf("ftmac110: out of txd\n");
return 0;
}
memcpy(des->vbuf, (void *)pkt, len);
dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
/* update len, fts and lts */
des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
/* set owner bit and clear others */
des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
/* kick-off Tx DMA */
writel(0xffffffff, &regs->txpd);
chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
return len;
}
static int ftmac110_recv(struct eth_device *dev)
{
struct ftmac110_chip *chip = dev->priv;
struct ftmac110_rxd *des;
uint32_t ct0, len, rlen = 0;
uint8_t *buf;
if (!chip->lnkup)
return 0;
do {
des = &chip->rxd[chip->rxd_idx];
ct0 = le32_to_cpu(des->ct[0]);
if (ct0 & FTMAC110_RXCT0_OWNER)
break;
len = FTMAC110_RXCT0_LEN(ct0);
buf = des->vbuf;
if (ct0 & FTMAC110_RXCT0_ERRMASK) {
printf("ftmac110: rx error\n");
} else {
dma_map_single(buf, len, DMA_FROM_DEVICE);
NetReceive(buf, len);
rlen += len;
}
/* owned by hardware */
des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
} while (0);
return rlen;
}
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
static int ftmac110_mdio_read(
const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
{
int ret = 0;
struct eth_device *dev;
dev = eth_get_dev_by_name(devname);
if (dev == NULL) {
printf("%s: no such device\n", devname);
ret = -1;
} else {
*value = mdio_read(dev, addr, reg);
}
return ret;
}
static int ftmac110_mdio_write(
const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
{
int ret = 0;
struct eth_device *dev;
dev = eth_get_dev_by_name(devname);
if (dev == NULL) {
printf("%s: no such device\n", devname);
ret = -1;
} else {
mdio_write(dev, addr, reg, value);
}
return ret;
}
#endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
int ftmac110_initialize(bd_t *bis)
{
int i, card_nr = 0;
struct eth_device *dev;
struct ftmac110_chip *chip;
dev = malloc(sizeof(*dev) + sizeof(*chip));
if (dev == NULL) {
panic("ftmac110: out of memory 1\n");
return -1;
}
chip = (struct ftmac110_chip *)(dev + 1);
memset(dev, 0, sizeof(*dev) + sizeof(*chip));
sprintf(dev->name, "FTMAC110#%d", card_nr);
dev->iobase = CONFIG_FTMAC110_BASE;
chip->regs = (void __iomem *)dev->iobase;
dev->priv = chip;
dev->init = ftmac110_probe;
dev->halt = ftmac110_halt;
dev->send = ftmac110_send;
dev->recv = ftmac110_recv;
if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
eth_random_enetaddr(dev->enetaddr);
/* allocate tx descriptors (it must be 16 bytes aligned) */
chip->txd = dma_alloc_coherent(
sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
if (!chip->txd)
panic("ftmac110: out of memory 3\n");
memset(chip->txd, 0,
sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
for (i = 0; i < CFG_TXDES_NUM; ++i) {
void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
if (!va)
panic("ftmac110: out of memory 4\n");
chip->txd[i].vbuf = va;
chip->txd[i].buf = cpu_to_le32(virt_to_phys(va));
chip->txd[i].ct[1] = 0;
chip->txd[i].ct[0] = 0; /* owned by SW */
}
chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
chip->txd_idx = 0;
/* allocate rx descriptors (it must be 16 bytes aligned) */
chip->rxd = dma_alloc_coherent(
sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
if (!chip->rxd)
panic("ftmac110: out of memory 4\n");
memset((void *)chip->rxd, 0,
sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
for (i = 0; i < CFG_RXDES_NUM; ++i) {
void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
if (!va)
panic("ftmac110: out of memory 5\n");
/* it needs to be exactly 2 bytes aligned */
va = ((uint8_t *)va + 2);
chip->rxd[i].vbuf = va;
chip->rxd[i].buf = cpu_to_le32(virt_to_phys(va));
chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
}
chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
chip->rxd_idx = 0;
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
#endif
card_nr++;
return card_nr;
}

177
drivers/net/ftmac110.h Normal file
View file

@ -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 */

645
drivers/net/ks8851_mll.c Normal file
View file

@ -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;
}

357
drivers/net/ks8851_mll.h Normal file
View file

@ -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

View file

@ -103,9 +103,15 @@ struct macb_device {
const struct device *dev;
struct eth_device netdev;
unsigned short phy_addr;
struct mii_dev *bus;
};
#define to_macb(_nd) container_of(_nd, struct macb_device, netdev)
static int macb_is_gem(struct macb_device *macb)
{
return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2;
}
static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value)
{
unsigned long netctl;
@ -163,7 +169,12 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg)
return MACB_BFEXT(DATA, frame);
}
#if defined(CONFIG_CMD_MII)
void __weak arch_get_mdio_control(const char *name)
{
return;
}
#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB)
int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
{
@ -173,6 +184,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value)
if ( macb->phy_addr != phy_adr )
return -1;
arch_get_mdio_control(devname);
*value = macb_mdio_read(macb, reg);
return 0;
@ -186,6 +198,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value)
if ( macb->phy_addr != phy_adr )
return -1;
arch_get_mdio_control(devname);
macb_mdio_write(macb, reg, value);
return 0;
@ -372,11 +385,15 @@ static int macb_phy_find(struct macb_device *macb)
static int macb_phy_init(struct macb_device *macb)
{
struct eth_device *netdev = &macb->netdev;
#ifdef CONFIG_PHYLIB
struct phy_device *phydev;
#endif
u32 ncfgr;
u16 phy_id, status, adv, lpa;
int media, speed, duplex;
int i;
arch_get_mdio_control(netdev->name);
#ifdef CONFIG_MACB_SEARCH_PHY
/* Auto-detect phy_addr */
if (!macb_phy_find(macb)) {
@ -391,6 +408,13 @@ static int macb_phy_init(struct macb_device *macb)
return 0;
}
#ifdef CONFIG_PHYLIB
phydev->bus = macb->bus;
phydev->dev = netdev;
phydev->addr = macb->phy_addr;
phy_config(phydev);
#endif
status = macb_mdio_read(macb, MII_BMSR);
if (!(status & BMSR_LSTATUS)) {
/* Try to re-negotiate if we don't have link already. */
@ -408,7 +432,43 @@ static int macb_phy_init(struct macb_device *macb)
printf("%s: link down (status: 0x%04x)\n",
netdev->name, status);
return 0;
}
/* 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);
@ -428,9 +488,9 @@ static int macb_phy_init(struct macb_device *macb)
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;
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;
}

View file

@ -26,6 +26,7 @@
#define MACB_NCR 0x0000
#define MACB_NCFGR 0x0004
#define MACB_NSR 0x0008
#define GEM_UR 0x000c
#define MACB_TSR 0x0014
#define MACB_RBQP 0x0018
#define MACB_TBQP 0x001c
@ -71,6 +72,7 @@
#define MACB_TPQ 0x00bc
#define MACB_USRIO 0x00c0
#define MACB_WOL 0x00c4
#define MACB_MID 0x00fc
/* Bitfields in NCR */
#define MACB_LB_OFFSET 0
@ -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
@ -266,10 +292,27 @@
<< MACB_##name##_OFFSET)) \
| 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) \
readl((port)->regs + MACB_##reg)
#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__ */

View file

@ -43,6 +43,8 @@
#include <asm/arch/kirkwood.h>
#elif defined(CONFIG_ORION5X)
#include <asm/arch/orion5x.h>
#elif defined(CONFIG_DOVE)
#include <asm/arch/dove.h>
#endif
#include "mvgbe.h"
@ -52,7 +54,7 @@ DECLARE_GLOBAL_DATA_PTR;
#define MV_PHY_ADR_REQUEST 0xee
#define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi)
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
/*
* smi_reg_read - miiphy_read callback function.
*
@ -184,6 +186,25 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data)
}
#endif
#if defined(CONFIG_PHYLIB)
int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr)
{
u16 data;
int ret;
ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data);
if (ret)
return ret;
return data;
}
int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr,
int reg_addr, u16 data)
{
return smi_reg_write(bus->name, phy_addr, reg_addr, data);
}
#endif
/* Stop and checks all queues */
static void stop_queue(u32 * qreg)
{
@ -467,8 +488,9 @@ static int mvgbe_init(struct eth_device *dev)
/* Enable port Rx. */
MVGBE_REG_WR(regs->rqc, (1 << RXUQ));
#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \
&& defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \
!defined(CONFIG_PHYLIB) && \
defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN)
/* Wait up to 5s for the link status */
for (i = 0; i < 5; i++) {
u16 phyadr;
@ -647,6 +669,45 @@ static int mvgbe_recv(struct eth_device *dev)
return 0;
}
#if defined(CONFIG_PHYLIB)
int mvgbe_phylib_init(struct eth_device *dev, int phyid)
{
struct mii_dev *bus;
struct phy_device *phydev;
int ret;
bus = mdio_alloc();
if (!bus) {
printf("mdio_alloc failed\n");
return -ENOMEM;
}
bus->read = mvgbe_phy_read;
bus->write = mvgbe_phy_write;
sprintf(bus->name, dev->name);
ret = mdio_register(bus);
if (ret) {
printf("mdio_register failed\n");
free(bus);
return -ENOMEM;
}
/* Set phy address of the port */
mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid);
phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII);
if (!phydev) {
printf("phy_connect failed\n");
return -ENODEV;
}
phy_config(phydev);
phy_startup(phydev);
return 0;
}
#endif
int mvgbe_initialize(bd_t *bis)
{
struct mvgbe_device *dmvgbe;
@ -729,7 +790,9 @@ error1:
eth_register(dev);
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
#if defined(CONFIG_PHYLIB)
mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum);
#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
miiphy_register(dev->name, smi_reg_read, smi_reg_write);
/* Set phy address of the port */
miiphy_write(dev->name, MV_PHY_ADR_REQUEST,

View file

@ -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

View file

@ -35,6 +35,7 @@ COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o
COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o
COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o
COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o
COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o
COBJS-$(CONFIG_PHY_LXT) += lxt.o
COBJS-$(CONFIG_PHY_MARVELL) += marvell.o
COBJS-$(CONFIG_PHY_MICREL) += micrel.o

View file

@ -16,7 +16,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
* Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2011, 2013 Freescale Semiconductor, Inc.
* author Andy Fleming
*
*/
@ -30,6 +30,27 @@ static int ar8021_config(struct phy_device *phydev)
return 0;
}
static int ar8035_config(struct phy_device *phydev)
{
int regval;
phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007);
phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016);
phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007);
regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe);
phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018));
phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05);
regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e);
phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100));
genphy_config_aneg(phydev);
phy_reset(phydev);
return 0;
}
static struct phy_driver AR8021_driver = {
.name = "AR8021",
.uid = 0x4dd040,
@ -40,9 +61,31 @@ static struct phy_driver AR8021_driver = {
.shutdown = genphy_shutdown,
};
static struct phy_driver AR8031_driver = {
.name = "AR8031",
.uid = 0x4dd074,
.mask = 0xfffff0,
.features = PHY_GBIT_FEATURES,
.config = genphy_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
};
static struct phy_driver AR8035_driver = {
.name = "AR8035",
.uid = 0x4dd072,
.mask = 0x4fffff,
.features = PHY_GBIT_FEATURES,
.config = ar8035_config,
.startup = genphy_startup,
.shutdown = genphy_shutdown,
};
int phy_atheros_init(void)
{
phy_register(&AR8021_driver);
phy_register(&AR8031_driver);
phy_register(&AR8035_driver);
return 0;
}

94
drivers/net/phy/icplus.c Normal file
View file

@ -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;
}

View file

@ -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);

View file

@ -18,6 +18,7 @@
*
* Copyright 2010-2011 Freescale Semiconductor, Inc.
* author Andy Fleming
* (C) 2012 NetModule AG, David Andrey, added KSZ9031
*
*/
#include <config.h>
@ -52,16 +53,46 @@ static struct phy_driver KS8721_driver = {
};
#endif
/**
* KSZ9021 - KSZ9031 common
*/
#define MII_KSZ90xx_PHY_CTL 0x1f
#define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6)
#define MIIM_KSZ90xx_PHYCTL_100 (1 << 5)
#define MIIM_KSZ90xx_PHYCTL_10 (1 << 4)
#define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3)
static int ksz90xx_startup(struct phy_device *phydev)
{
unsigned phy_ctl;
genphy_update_link(phydev);
phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL);
if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000)
phydev->speed = SPEED_1000;
else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100)
phydev->speed = SPEED_100;
else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10)
phydev->speed = SPEED_10;
return 0;
}
#ifdef CONFIG_PHY_MICREL_KSZ9021
/* ksz9021 PHY Registers */
/*
* KSZ9021
*/
/* PHY Registers */
#define MII_KSZ9021_EXTENDED_CTRL 0x0b
#define MII_KSZ9021_EXTENDED_DATAW 0x0c
#define MII_KSZ9021_EXTENDED_DATAR 0x0d
#define MII_KSZ9021_PHY_CTL 0x1f
#define MIIM_KSZ9021_PHYCTL_1000 (1 << 6)
#define MIIM_KSZ9021_PHYCTL_100 (1 << 5)
#define MIIM_KSZ9021_PHYCTL_10 (1 << 4)
#define MIIM_KSZ9021_PHYCTL_DUPLEX (1 << 3)
#define CTRL1000_PREFER_MASTER (1 << 10)
#define CTRL1000_CONFIG_MASTER (1 << 11)
@ -106,37 +137,64 @@ static int ksz9021_config(struct phy_device *phydev)
return 0;
}
static int ksz9021_startup(struct phy_device *phydev)
{
unsigned phy_ctl;
genphy_update_link(phydev);
phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL);
if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000)
phydev->speed = SPEED_1000;
else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100)
phydev->speed = SPEED_100;
else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10)
phydev->speed = SPEED_10;
return 0;
}
static struct phy_driver ksz9021_driver = {
.name = "Micrel ksz9021",
.uid = 0x221610,
.mask = 0xfffff0,
.features = PHY_GBIT_FEATURES,
.config = &ksz9021_config,
.startup = &ksz9021_startup,
.startup = &ksz90xx_startup,
.shutdown = &genphy_shutdown,
};
#endif
/**
* KSZ9031
*/
/* PHY Registers */
#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d
#define MII_KSZ9031_MMD_REG_DATA 0x0e
/* Accessors to extended registers*/
int ksz9031_phy_extended_write(struct phy_device *phydev,
int devaddr, int regnum, u16 mode, u16 val)
{
/*select register addr for mmd*/
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
/*select register for mmd*/
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_REG_DATA, regnum);
/*setup mode*/
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr));
/*write the value*/
return phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_REG_DATA, val);
}
int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
int regnum, u16 mode)
{
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_ACCES_CTRL, devaddr);
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_REG_DATA, regnum);
phy_write(phydev, MDIO_DEVAD_NONE,
MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode));
return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA);
}
static struct phy_driver ksz9031_driver = {
.name = "Micrel ksz9031",
.uid = 0x221620,
.mask = 0xfffffe,
.features = PHY_GBIT_FEATURES,
.config = &genphy_config,
.startup = &ksz90xx_startup,
.shutdown = &genphy_shutdown,
};
int phy_micrel_init(void)
{
phy_register(&KSZ804_driver);
@ -145,5 +203,6 @@ int phy_micrel_init(void)
#else
phy_register(&KS8721_driver);
#endif
phy_register(&ksz9031_driver);
return 0;
}

View file

@ -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;

View file

@ -75,6 +75,10 @@ static int genphy_config_advert(struct phy_device *phydev)
adv |= ADVERTISE_PAUSE_CAP;
if (advertise & ADVERTISED_Asym_Pause)
adv |= ADVERTISE_PAUSE_ASYM;
if (advertise & ADVERTISED_1000baseX_Half)
adv |= ADVERTISE_1000XHALF;
if (advertise & ADVERTISED_1000baseX_Full)
adv |= ADVERTISE_1000XFULL;
if (adv != oldadv) {
err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv);
@ -280,7 +284,7 @@ int genphy_update_link(struct phy_device *phydev)
*
* Stolen from Linux's mii.c and phy_device.c
*/
static int genphy_parse_link(struct phy_device *phydev)
int genphy_parse_link(struct phy_device *phydev)
{
int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
@ -288,6 +292,7 @@ static int genphy_parse_link(struct phy_device *phydev)
if (mii_reg & BMSR_ANEGCAPABLE) {
u32 lpa = 0;
u32 gblpa = 0;
u32 estatus = 0;
/* Check for gigabit capability */
if (mii_reg & BMSR_ERCAP) {
@ -327,6 +332,18 @@ static int genphy_parse_link(struct phy_device *phydev)
} else if (lpa & LPA_10FULL)
phydev->duplex = DUPLEX_FULL;
if (mii_reg & BMSR_ESTATEN)
estatus = phy_read(phydev, MDIO_DEVAD_NONE,
MII_ESTATUS);
if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF |
ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
phydev->speed = SPEED_1000;
if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL))
phydev->duplex = DUPLEX_FULL;
}
} else {
u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
@ -384,6 +401,10 @@ int genphy_config(struct phy_device *phydev)
features |= SUPPORTED_1000baseT_Full;
if (val & ESTATUS_1000_THALF)
features |= SUPPORTED_1000baseT_Half;
if (val & ESTATUS_1000_XFULL)
features |= SUPPORTED_1000baseX_Full;
if (val & ESTATUS_1000_XHALF)
features |= SUPPORTED_1000baseX_Full;
}
phydev->supported = features;
@ -433,6 +454,9 @@ int phy_init(void)
#ifdef CONFIG_PHY_ET1011C
phy_et1011c_init();
#endif
#ifdef CONFIG_PHY_ICPLUS
phy_icplus_init();
#endif
#ifdef CONFIG_PHY_LXT
phy_lxt_init();
#endif

533
drivers/net/sunxi_wemac.c Normal file
View file

@ -0,0 +1,533 @@
/*
* sunxi_wemac.c -- Allwinner A10 ethernet driver
*
* (C) Copyright 2012, Stefan Roese <sr@denx.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <common.h>
#include <malloc.h>
#include <net.h>
#include <miiphy.h>
#include <linux/err.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/gpio.h>
/* EMAC register */
struct wemac_regs {
u32 ctl; /* 0x00 */
u32 tx_mode; /* 0x04 */
u32 tx_flow; /* 0x08 */
u32 tx_ctl0; /* 0x0c */
u32 tx_ctl1; /* 0x10 */
u32 tx_ins; /* 0x14 */
u32 tx_pl0; /* 0x18 */
u32 tx_pl1; /* 0x1c */
u32 tx_sta; /* 0x20 */
u32 tx_io_data; /* 0x24 */
u32 tx_io_data1; /* 0x28 */
u32 tx_tsvl0; /* 0x2c */
u32 tx_tsvh0; /* 0x30 */
u32 tx_tsvl1; /* 0x34 */
u32 tx_tsvh1; /* 0x38 */
u32 rx_ctl; /* 0x3c */
u32 rx_hash0; /* 0x40 */
u32 rx_hash1; /* 0x44 */
u32 rx_sta; /* 0x48 */
u32 rx_io_data; /* 0x4c */
u32 rx_fbc; /* 0x50 */
u32 int_ctl; /* 0x54 */
u32 int_sta; /* 0x58 */
u32 mac_ctl0; /* 0x5c */
u32 mac_ctl1; /* 0x60 */
u32 mac_ipgt; /* 0x64 */
u32 mac_ipgr; /* 0x68 */
u32 mac_clrt; /* 0x6c */
u32 mac_maxf; /* 0x70 */
u32 mac_supp; /* 0x74 */
u32 mac_test; /* 0x78 */
u32 mac_mcfg; /* 0x7c */
u32 mac_mcmd; /* 0x80 */
u32 mac_madr; /* 0x84 */
u32 mac_mwtd; /* 0x88 */
u32 mac_mrdd; /* 0x8c */
u32 mac_mind; /* 0x90 */
u32 mac_ssrr; /* 0x94 */
u32 mac_a0; /* 0x98 */
u32 mac_a1; /* 0x9c */
};
/* SRAMC register */
struct sunxi_sramc_regs {
u32 ctrl0;
u32 ctrl1;
};
/* 0: Disable 1: Aborted frame enable(default) */
#define EMAC_TX_AB_M (0x1 << 0)
/* 0: CPU 1: DMA(default) */
#define EMAC_TX_TM (0x1 << 1)
#define EMAC_TX_SETUP (0)
/* 0: DRQ asserted 1: DRQ automatically(default) */
#define EMAC_RX_DRQ_MODE (0x1 << 1)
/* 0: CPU 1: DMA(default) */
#define EMAC_RX_TM (0x1 << 2)
/* 0: Normal(default) 1: Pass all Frames */
#define EMAC_RX_PA (0x1 << 4)
/* 0: Normal(default) 1: Pass Control Frames */
#define EMAC_RX_PCF (0x1 << 5)
/* 0: Normal(default) 1: Pass Frames with CRC Error */
#define EMAC_RX_PCRCE (0x1 << 6)
/* 0: Normal(default) 1: Pass Frames with Length Error */
#define EMAC_RX_PLE (0x1 << 7)
/* 0: Normal 1: Pass Frames length out of range(default) */
#define EMAC_RX_POR (0x1 << 8)
/* 0: Not accept 1: Accept unicast Packets(default) */
#define EMAC_RX_UCAD (0x1 << 16)
/* 0: Normal(default) 1: DA Filtering */
#define EMAC_RX_DAF (0x1 << 17)
/* 0: Not accept 1: Accept multicast Packets(default) */
#define EMAC_RX_MCO (0x1 << 20)
/* 0: Disable(default) 1: Enable Hash filter */
#define EMAC_RX_MHF (0x1 << 21)
/* 0: Not accept 1: Accept Broadcast Packets(default) */
#define EMAC_RX_BCO (0x1 << 22)
/* 0: Disable(default) 1: Enable SA Filtering */
#define EMAC_RX_SAF (0x1 << 24)
/* 0: Normal(default) 1: Inverse Filtering */
#define EMAC_RX_SAIF (0x1 << 25)
#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \
EMAC_RX_MCO | EMAC_RX_BCO)
/* 0: Disable 1: Enable Receive Flow Control(default) */
#define EMAC_MAC_CTL0_RFC (0x1 << 2)
/* 0: Disable 1: Enable Transmit Flow Control(default) */
#define EMAC_MAC_CTL0_TFC (0x1 << 3)
#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC)
/* 0: Disable 1: Enable MAC Frame Length Checking(default) */
#define EMAC_MAC_CTL1_FLC (0x1 << 1)
/* 0: Disable(default) 1: Enable Huge Frame */
#define EMAC_MAC_CTL1_HF (0x1 << 2)
/* 0: Disable(default) 1: Enable MAC Delayed CRC */
#define EMAC_MAC_CTL1_DCRC (0x1 << 3)
/* 0: Disable 1: Enable MAC CRC(default) */
#define EMAC_MAC_CTL1_CRC (0x1 << 4)
/* 0: Disable 1: Enable MAC PAD Short frames(default) */
#define EMAC_MAC_CTL1_PC (0x1 << 5)
/* 0: Disable(default) 1: Enable MAC PAD Short frames and append CRC */
#define EMAC_MAC_CTL1_VC (0x1 << 6)
/* 0: Disable(default) 1: Enable MAC auto detect Short frames */
#define EMAC_MAC_CTL1_ADP (0x1 << 7)
/* 0: Disable(default) 1: Enable */
#define EMAC_MAC_CTL1_PRE (0x1 << 8)
/* 0: Disable(default) 1: Enable */
#define EMAC_MAC_CTL1_LPE (0x1 << 9)
/* 0: Disable(default) 1: Enable no back off */
#define EMAC_MAC_CTL1_NB (0x1 << 12)
/* 0: Disable(default) 1: Enable */
#define EMAC_MAC_CTL1_BNB (0x1 << 13)
/* 0: Disable(default) 1: Enable */
#define EMAC_MAC_CTL1_ED (0x1 << 14)
#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \
EMAC_MAC_CTL1_PC)
#define EMAC_MAC_IPGT 0x15
#define EMAC_MAC_NBTB_IPG1 0xC
#define EMAC_MAC_NBTB_IPG2 0x12
#define EMAC_MAC_CW 0x37
#define EMAC_MAC_RM 0xF
#define EMAC_MAC_MFL 0x0600
/* Receive status */
#define EMAC_CRCERR (1 << 4)
#define EMAC_LENERR (3 << 5)
#define DMA_CPU_TRRESHOLD 2000
struct wemac_eth_dev {
u32 speed;
u32 duplex;
u32 phy_configured;
int link_printed;
};
struct wemac_rxhdr {
s16 rx_len;
u16 rx_status;
};
static void wemac_inblk_32bit(void *reg, void *data, int count)
{
int cnt = (count + 3) >> 2;
if (cnt) {
u32 *buf = data;
do {
u32 x = readl(reg);
*buf++ = x;
} while (--cnt);
}
}
static void wemac_outblk_32bit(void *reg, void *data, int count)
{
int cnt = (count + 3) >> 2;
if (cnt) {
const u32 *buf = data;
do {
writel(*buf++, reg);
} while (--cnt);
}
}
/*
* Read a word from phyxcer
*/
static int wemac_phy_read(const char *devname, unsigned char addr,
unsigned char reg, unsigned short *value)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
/* issue the phy address and reg */
writel(addr << 8 | reg, &regs->mac_madr);
/* pull up the phy io line */
writel(0x1, &regs->mac_mcmd);
/* Wait read complete */
mdelay(1);
/* push down the phy io line */
writel(0x0, &regs->mac_mcmd);
/* and write data */
*value = readl(&regs->mac_mrdd);
return 0;
}
/*
* Write a word to phyxcer
*/
static int wemac_phy_write(const char *devname, unsigned char addr,
unsigned char reg, unsigned short value)
{
struct eth_device *dev = eth_get_dev_by_name(devname);
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
/* issue the phy address and reg */
writel(addr << 8 | reg, &regs->mac_madr);
/* pull up the phy io line */
writel(0x1, &regs->mac_mcmd);
/* Wait write complete */
mdelay(1);
/* push down the phy io line */
writel(0x0, &regs->mac_mcmd);
/* and write data */
writel(value, &regs->mac_mwtd);
return 0;
}
static void emac_setup(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
u32 reg_val;
u16 phy_val;
u32 duplex_flag;
/* Set up TX */
writel(EMAC_TX_SETUP, &regs->tx_mode);
/* Set up RX */
writel(EMAC_RX_SETUP, &regs->rx_ctl);
/* Set MAC */
/* Set MAC CTL0 */
writel(EMAC_MAC_CTL0_SETUP, &regs->mac_ctl0);
/* Set MAC CTL1 */
wemac_phy_read(dev->name, 1, 0, &phy_val);
debug("PHY SETUP, reg 0 value: %x\n", phy_val);
duplex_flag = !!(phy_val & (1 << 8));
reg_val = 0;
if (duplex_flag)
reg_val = (0x1 << 0);
writel(EMAC_MAC_CTL1_SETUP | reg_val, &regs->mac_ctl1);
/* Set up IPGT */
writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
/* Set up IPGR */
writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
/* Set up Collison window */
writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
/* Set up Max Frame Length */
writel(EMAC_MAC_MFL, &regs->mac_maxf);
}
static void wemac_reset(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
debug("resetting device\n");
/* RESET device */
writel(0, &regs->ctl);
udelay(200);
writel(1, &regs->ctl);
udelay(200);
}
static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
struct wemac_eth_dev *priv = dev->priv;
u16 phy_reg;
/* Init EMAC */
/* Flush RX FIFO */
setbits_le32(&regs->rx_ctl, 0x8);
udelay(1);
/* Init MAC */
/* Soft reset MAC */
clrbits_le32(&regs->mac_ctl0, 1 << 15);
/* Set MII clock */
clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
/* Clear RX counter */
writel(0x0, &regs->rx_fbc);
udelay(1);
/* Set up EMAC */
emac_setup(dev);
writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
dev->enetaddr[2], &regs->mac_a1);
writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
dev->enetaddr[5], &regs->mac_a0);
mdelay(1);
wemac_reset(dev);
/* PHY POWER UP */
wemac_phy_read(dev->name, 1, 0, &phy_reg);
wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
mdelay(1);
wemac_phy_read(dev->name, 1, 0, &phy_reg);
priv->speed = miiphy_speed(dev->name, 0);
priv->duplex = miiphy_duplex(dev->name, 0);
/* Print link status only once */
if (!priv->link_printed) {
printf("ENET Speed is %d Mbps - %s duplex connection\n",
priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
priv->link_printed = 1;
}
/* Set EMAC SPEED depend on PHY */
clrsetbits_le32(&regs->mac_supp, 1 << 8,
((phy_reg & (1 << 13)) >> 13) << 8);
/* Set duplex depend on phy */
clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
((phy_reg & (1 << 8)) >> 8) << 0);
/* Enable RX/TX */
setbits_le32(&regs->ctl, 0x7);
return 0;
}
static void sunxi_wemac_eth_halt(struct eth_device *dev)
{
/* Nothing to do here */
}
static int sunxi_wemac_eth_recv(struct eth_device *dev)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
struct wemac_rxhdr rxhdr;
u32 rxcount;
u32 reg_val;
int rx_len;
int rx_status;
int good_packet;
/* Check packet ready or not */
/*
* Race warning: The first packet might arrive with
* the interrupts disabled, but the second will fix
*/
rxcount = readl(&regs->rx_fbc);
if (!rxcount) {
/* Had one stuck? */
rxcount = readl(&regs->rx_fbc);
if (!rxcount)
return 0;
}
reg_val = readl(&regs->rx_io_data);
if (reg_val != 0x0143414d) {
/* Disable RX */
clrbits_le32(&regs->ctl, 1 << 2);
/* Flush RX FIFO */
setbits_le32(&regs->rx_ctl, 1 << 3);
while (readl(&regs->rx_ctl) & (1 << 3))
;
/* Enable RX */
setbits_le32(&regs->ctl, 1 << 2);
return 0;
}
/*
* A packet ready now
* Get status/length
*/
good_packet = 1;
wemac_inblk_32bit(&regs->rx_io_data, &rxhdr, sizeof(rxhdr));
rx_len = rxhdr.rx_len;
rx_status = rxhdr.rx_status;
/* Packet Status check */
if (rx_len < 0x40) {
good_packet = 0;
debug("RX: Bad Packet (runt)\n");
}
/* rx_status is identical to RSR register. */
if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
good_packet = 0;
if (rx_status & EMAC_CRCERR)
printf("crc error\n");
if (rx_status & EMAC_LENERR)
printf("length error\n");
}
/* Move data from WEMAC */
if (good_packet) {
if (rx_len > DMA_CPU_TRRESHOLD) {
printf("Received packet is too big (len=%d)\n", rx_len);
} else {
wemac_inblk_32bit((void *)&regs->rx_io_data,
NetRxPackets[0], rx_len);
/* Pass to upper layer */
NetReceive(NetRxPackets[0], rx_len);
return rx_len;
}
}
return 0;
}
static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
{
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
/* Select channel 0 */
writel(0, &regs->tx_ins);
/* Write packet */
wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
/* Set TX len */
writel(len, &regs->tx_pl0);
/* Start translate from fifo to phy */
setbits_le32(&regs->tx_ctl0, 1);
return 0;
}
int sunxi_wemac_initialize(void)
{
struct sunxi_ccm_reg *const ccm =
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
struct sunxi_sramc_regs *sram =
(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
struct eth_device *dev;
struct wemac_eth_dev *priv;
int pin;
dev = malloc(sizeof(*dev));
if (dev == NULL)
return -ENOMEM;
priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
if (!priv) {
free(dev);
return -ENOMEM;
}
memset(dev, 0, sizeof(*dev));
memset(priv, 0, sizeof(struct wemac_eth_dev));
/* Map SRAM to EMAC */
setbits_le32(&sram->ctrl1, 0x5 << 2);
/* Configure pin mux settings for MII Ethernet */
for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
sunxi_gpio_set_cfgpin(pin, 2);
/* Set up clock gating */
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
dev->iobase = SUNXI_EMAC_BASE;
dev->priv = priv;
dev->init = sunxi_wemac_eth_init;
dev->halt = sunxi_wemac_eth_halt;
dev->send = sunxi_wemac_eth_send;
dev->recv = sunxi_wemac_eth_recv;
strcpy(dev->name, "wemac");
eth_register(dev);
miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
return 0;
}

View file

@ -110,6 +110,8 @@ static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd)
}
#endif
extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
char *const argv[]);

View file

@ -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

View file

@ -580,6 +580,8 @@ enum ethtool_sfeatures_retval_bits {
#define SUPPORTED_10000baseKX4_Full (1 << 18)
#define SUPPORTED_10000baseKR_Full (1 << 19)
#define SUPPORTED_10000baseR_FEC (1 << 20)
#define SUPPORTED_1000baseX_Half (1 << 21)
#define SUPPORTED_1000baseX_Full (1 << 22)
/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half (1 << 0)
@ -603,6 +605,8 @@ enum ethtool_sfeatures_retval_bits {
#define ADVERTISED_10000baseKX4_Full (1 << 18)
#define ADVERTISED_10000baseKR_Full (1 << 19)
#define ADVERTISED_10000baseR_FEC (1 << 20)
#define ADVERTISED_1000baseX_Half (1 << 21)
#define ADVERTISED_1000baseX_Full (1 << 22)
/* The following are all involved in forcing a particular link
* mode for the device for setting things. When getting the

View file

@ -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 */

View file

@ -8,9 +8,20 @@
#define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW 0x105
#define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW 0x106
#define MII_KSZ9021_EXT_ANALOG_TEST 0x107
/* Register operations */
#define MII_KSZ9031_MOD_REG 0x0000
/* Data operations */
#define MII_KSZ9031_MOD_DATA_NO_POST_INC 0x4000
#define MII_KSZ9031_MOD_DATA_POST_INC_RW 0x8000
#define MII_KSZ9031_MOD_DATA_POST_INC_W 0xC000
struct phy_device;
int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val);
int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum);
int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr,
int regnum, u16 mode, u16 val);
int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr,
int regnum, u16 mode);
#endif

View file

@ -39,7 +39,7 @@
#define PKTALIGN ARCH_DMA_MINALIGN
/* IPv4 addresses are always 32 bits in size */
typedef u32 IPaddr_t;
typedef __be32 IPaddr_t;
/**

View file

@ -67,10 +67,12 @@ int fecmxc_initialize(bd_t *bis);
int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
int ftgmac100_initialize(bd_t *bits);
int ftmac100_initialize(bd_t *bits);
int ftmac110_initialize(bd_t *bits);
int greth_initialize(bd_t *bis);
void gt6426x_eth_initialize(bd_t *bis);
int inca_switch_initialize(bd_t *bis);
int ks8695_eth_initialize(void);
int ks8851_mll_initialize(u8 dev_num, int base_addr);
int lan91c96_initialize(u8 dev_num, int base_addr);
int macb_eth_initialize(int id, void *regs, unsigned int phy_addr);
int mcdmafec_initialize(bd_t *bis);
@ -93,6 +95,7 @@ int sh_eth_initialize(bd_t *bis);
int skge_initialize(bd_t *bis);
int smc91111_initialize(u8 dev_num, int base_addr);
int smc911x_initialize(u8 dev_num, int base_addr);
int sunxi_wemac_initialize(bd_t *bis);
int tsi108_eth_initialize(bd_t *bis);
int uec_standard_init(bd_t *bis);
int uli526x_initialize(bd_t *bis);

View file

@ -214,6 +214,7 @@ int phy_register(struct phy_driver *drv);
int genphy_config_aneg(struct phy_device *phydev);
int genphy_restart_aneg(struct phy_device *phydev);
int genphy_update_link(struct phy_device *phydev);
int genphy_parse_link(struct phy_device *phydev);
int genphy_config(struct phy_device *phydev);
int genphy_startup(struct phy_device *phydev);
int genphy_shutdown(struct phy_device *phydev);

View file

@ -206,6 +206,7 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)
{
int source_ip_conflict;
int target_ip_conflict;
IPaddr_t null_ip = 0;
if (state == DISABLED)
return;
@ -267,10 +268,18 @@ void link_local_receive_arp(struct arp_hdr *arp, int len)
) {
source_ip_conflict = 1;
}
if (arp->ar_op == htons(ARPOP_REQUEST)
&& memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0
&& memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0
) {
/*
* According to RFC 3927, section 2.2.1:
* Check if packet is an ARP probe by checking for a null source IP
* then check that target IP is equal to ours and source hw addr
* is not equal to ours. This condition should cause a conflict only
* during probe.
*/
if (arp->ar_op == htons(ARPOP_REQUEST) &&
memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 &&
memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 &&
memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) {
target_ip_conflict = 1;
}

View file

@ -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;

View file

@ -446,8 +446,8 @@ static void
TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
unsigned len)
{
ushort proto;
ushort *s;
__be16 proto;
__be16 *s;
int i;
if (dest != TftpOurPort) {
@ -465,7 +465,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
return;
len -= 2;
/* warning: don't use increment (++) in ntohs() macros!! */
s = (ushort *)pkt;
s = (__be16 *)pkt;
proto = *s++;
pkt = (uchar *)s;
switch (ntohs(proto)) {
@ -556,7 +556,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
if (len < 2)
return;
len -= 2;
TftpBlock = ntohs(*(ushort *)pkt);
TftpBlock = ntohs(*(__be16 *)pkt);
update_block_number();
@ -644,9 +644,9 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
case TFTP_ERROR:
printf("\nTFTP error: '%s' (%d)\n",
pkt + 2, ntohs(*(ushort *)pkt));
pkt + 2, ntohs(*(__be16 *)pkt));
switch (ntohs(*(ushort *)pkt)) {
switch (ntohs(*(__be16 *)pkt)) {
case TFTP_ERR_FILE_NOT_FOUND:
case TFTP_ERR_ACCESS_DENIED:
puts("Not retrying...\n");