mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-28 15:41:40 +00:00
Merge branch 'master' of git://git.denx.de/u-boot-net
This commit is contained in:
commit
ca85eb8c42
34 changed files with 3117 additions and 221 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
217
common/cmd_pxe.c
217
common/cmd_pxe.c
|
@ -26,12 +26,21 @@
|
|||
|
||||
#define MAX_TFTP_PATH_LEN 127
|
||||
|
||||
const char *pxe_default_paths[] = {
|
||||
#ifdef CONFIG_SYS_SOC
|
||||
"default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC,
|
||||
#endif
|
||||
"default-" CONFIG_SYS_ARCH,
|
||||
"default",
|
||||
NULL
|
||||
};
|
||||
|
||||
/*
|
||||
* Like getenv, but prints an error if envvar isn't defined in the
|
||||
* environment. It always returns what getenv does, so it can be used in
|
||||
* place of getenv without changing error handling otherwise.
|
||||
*/
|
||||
static char *from_env(char *envvar)
|
||||
static char *from_env(const char *envvar)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
|
@ -55,37 +64,21 @@ static char *from_env(char *envvar)
|
|||
*/
|
||||
static int format_mac_pxe(char *outbuf, size_t outbuf_len)
|
||||
{
|
||||
size_t ethaddr_len;
|
||||
char *p, *ethaddr;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
473
drivers/net/ftmac110.c
Normal 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, ®s->phycr);
|
||||
|
||||
for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
|
||||
tmp = readl(®s->phycr);
|
||||
if (tmp & PHYCR_READ)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (tmp & PHYCR_READ)
|
||||
printf("ftmac110: mdio read timeout\n");
|
||||
else
|
||||
ret = (uint16_t)(tmp & 0xffff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mdio_write(struct eth_device *dev,
|
||||
uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
|
||||
{
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
struct ftmac110_regs __iomem *regs = chip->regs;
|
||||
uint32_t tmp, ts;
|
||||
|
||||
tmp = PHYCR_WRITE
|
||||
| (phyaddr << PHYCR_ADDR_SHIFT)
|
||||
| (phyreg << PHYCR_REG_SHIFT);
|
||||
|
||||
writel(phydata, ®s->phydr);
|
||||
writel(tmp, ®s->phycr);
|
||||
|
||||
for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
|
||||
if (readl(®s->phycr) & PHYCR_WRITE)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
if (readl(®s->phycr) & PHYCR_WRITE)
|
||||
printf("ftmac110: mdio write timeout\n");
|
||||
}
|
||||
|
||||
static uint32_t ftmac110_phyqry(struct eth_device *dev)
|
||||
{
|
||||
ulong ts;
|
||||
uint32_t maccr;
|
||||
uint16_t pa, tmp, bmsr, bmcr;
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
|
||||
/* Default = 100Mbps Full */
|
||||
maccr = MACCR_100M | MACCR_FD;
|
||||
|
||||
/* 1. find the phy device */
|
||||
for (pa = 0; pa < 32; ++pa) {
|
||||
tmp = mdio_read(dev, pa, MII_PHYSID1);
|
||||
if (tmp == 0xFFFF || tmp == 0x0000)
|
||||
continue;
|
||||
chip->phy_addr = pa;
|
||||
break;
|
||||
}
|
||||
if (pa >= 32) {
|
||||
puts("ftmac110: phy device not found!\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 2. wait until link-up & auto-negotiation complete */
|
||||
chip->lnkup = 0;
|
||||
bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
|
||||
ts = get_timer(0);
|
||||
do {
|
||||
bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
|
||||
chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
|
||||
if (!chip->lnkup)
|
||||
continue;
|
||||
if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
|
||||
break;
|
||||
} while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
|
||||
if (!chip->lnkup) {
|
||||
puts("ftmac110: link down\n");
|
||||
goto exit;
|
||||
}
|
||||
if (!(bmcr & BMCR_ANENABLE))
|
||||
puts("ftmac110: auto negotiation disabled\n");
|
||||
else if (!(bmsr & BMSR_ANEGCOMPLETE))
|
||||
puts("ftmac110: auto negotiation timeout\n");
|
||||
|
||||
/* 3. derive MACCR */
|
||||
if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
|
||||
tmp = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
|
||||
tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
|
||||
if (tmp & LPA_100FULL) /* 100Mbps full-duplex */
|
||||
maccr = MACCR_100M | MACCR_FD;
|
||||
else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
|
||||
maccr = MACCR_100M;
|
||||
else if (tmp & LPA_10FULL) /* 10Mbps full-duplex */
|
||||
maccr = MACCR_FD;
|
||||
else if (tmp & LPA_10HALF) /* 10Mbps half-duplex */
|
||||
maccr = 0;
|
||||
} else {
|
||||
if (bmcr & BMCR_SPEED100)
|
||||
maccr = MACCR_100M;
|
||||
else
|
||||
maccr = 0;
|
||||
if (bmcr & BMCR_FULLDPLX)
|
||||
maccr |= MACCR_FD;
|
||||
}
|
||||
|
||||
exit:
|
||||
printf("ftmac110: %d Mbps, %s\n",
|
||||
(maccr & MACCR_100M) ? 100 : 10,
|
||||
(maccr & MACCR_FD) ? "Full" : "half");
|
||||
return maccr;
|
||||
}
|
||||
|
||||
static int ftmac110_reset(struct eth_device *dev)
|
||||
{
|
||||
uint8_t *a;
|
||||
uint32_t i, maccr;
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
struct ftmac110_regs __iomem *regs = chip->regs;
|
||||
|
||||
/* 1. MAC reset */
|
||||
writel(MACCR_RESET, ®s->maccr);
|
||||
for (i = get_timer(0); get_timer(i) < 1000; ) {
|
||||
if (readl(®s->maccr) & MACCR_RESET)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if (readl(®s->maccr) & MACCR_RESET) {
|
||||
printf("ftmac110: reset failed\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
/* 1-1. Init tx ring */
|
||||
for (i = 0; i < CFG_TXDES_NUM; ++i) {
|
||||
/* owned by SW */
|
||||
chip->txd[i].ct[0] = 0;
|
||||
}
|
||||
chip->txd_idx = 0;
|
||||
|
||||
/* 1-2. Init rx ring */
|
||||
for (i = 0; i < CFG_RXDES_NUM; ++i) {
|
||||
/* owned by HW */
|
||||
chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
|
||||
}
|
||||
chip->rxd_idx = 0;
|
||||
|
||||
/* 2. PHY status query */
|
||||
maccr = ftmac110_phyqry(dev);
|
||||
|
||||
/* 3. Fix up the MACCR value */
|
||||
chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
|
||||
| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
|
||||
|
||||
/* 4. MAC address setup */
|
||||
a = dev->enetaddr;
|
||||
writel(a[1] | (a[0] << 8), ®s->mac[0]);
|
||||
writel(a[5] | (a[4] << 8) | (a[3] << 16)
|
||||
| (a[2] << 24), ®s->mac[1]);
|
||||
|
||||
/* 5. MAC registers setup */
|
||||
writel(chip->rxd_dma, ®s->rxba);
|
||||
writel(chip->txd_dma, ®s->txba);
|
||||
/* interrupt at each tx/rx */
|
||||
writel(ITC_DEFAULT, ®s->itc);
|
||||
/* no tx pool, rx poll = 1 normal cycle */
|
||||
writel(APTC_DEFAULT, ®s->aptc);
|
||||
/* rx threshold = [6/8 fifo, 2/8 fifo] */
|
||||
writel(DBLAC_DEFAULT, ®s->dblac);
|
||||
/* disable & clear all interrupt status */
|
||||
chip->imr = 0;
|
||||
writel(ISR_ALL, ®s->isr);
|
||||
writel(chip->imr, ®s->imr);
|
||||
/* enable mac */
|
||||
writel(chip->maccr, ®s->maccr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
|
||||
{
|
||||
debug("ftmac110: probe\n");
|
||||
|
||||
if (ftmac110_reset(dev))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ftmac110_halt(struct eth_device *dev)
|
||||
{
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
struct ftmac110_regs __iomem *regs = chip->regs;
|
||||
|
||||
writel(0, ®s->imr);
|
||||
writel(0, ®s->maccr);
|
||||
|
||||
debug("ftmac110: halt\n");
|
||||
}
|
||||
|
||||
static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
|
||||
{
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
struct ftmac110_regs __iomem *regs = chip->regs;
|
||||
struct ftmac110_txd *des;
|
||||
|
||||
if (!chip->lnkup)
|
||||
return 0;
|
||||
|
||||
if (len <= 0 || len > CFG_XBUF_SIZE) {
|
||||
printf("ftmac110: bad tx pkt len(%d)\n", len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = max(60, len);
|
||||
|
||||
des = &chip->txd[chip->txd_idx];
|
||||
if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
|
||||
/* kick-off Tx DMA */
|
||||
writel(0xffffffff, ®s->txpd);
|
||||
printf("ftmac110: out of txd\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
memcpy(des->vbuf, (void *)pkt, len);
|
||||
dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
|
||||
|
||||
/* update len, fts and lts */
|
||||
des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
|
||||
des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
|
||||
| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
|
||||
|
||||
/* set owner bit and clear others */
|
||||
des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
|
||||
|
||||
/* kick-off Tx DMA */
|
||||
writel(0xffffffff, ®s->txpd);
|
||||
|
||||
chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int ftmac110_recv(struct eth_device *dev)
|
||||
{
|
||||
struct ftmac110_chip *chip = dev->priv;
|
||||
struct ftmac110_rxd *des;
|
||||
uint32_t ct0, len, rlen = 0;
|
||||
uint8_t *buf;
|
||||
|
||||
if (!chip->lnkup)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
des = &chip->rxd[chip->rxd_idx];
|
||||
ct0 = le32_to_cpu(des->ct[0]);
|
||||
if (ct0 & FTMAC110_RXCT0_OWNER)
|
||||
break;
|
||||
|
||||
len = FTMAC110_RXCT0_LEN(ct0);
|
||||
buf = des->vbuf;
|
||||
|
||||
if (ct0 & FTMAC110_RXCT0_ERRMASK) {
|
||||
printf("ftmac110: rx error\n");
|
||||
} else {
|
||||
dma_map_single(buf, len, DMA_FROM_DEVICE);
|
||||
NetReceive(buf, len);
|
||||
rlen += len;
|
||||
}
|
||||
|
||||
/* owned by hardware */
|
||||
des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
|
||||
|
||||
chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
|
||||
} while (0);
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
|
||||
static int ftmac110_mdio_read(
|
||||
const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
|
||||
{
|
||||
int ret = 0;
|
||||
struct eth_device *dev;
|
||||
|
||||
dev = eth_get_dev_by_name(devname);
|
||||
if (dev == NULL) {
|
||||
printf("%s: no such device\n", devname);
|
||||
ret = -1;
|
||||
} else {
|
||||
*value = mdio_read(dev, addr, reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ftmac110_mdio_write(
|
||||
const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
|
||||
{
|
||||
int ret = 0;
|
||||
struct eth_device *dev;
|
||||
|
||||
dev = eth_get_dev_by_name(devname);
|
||||
if (dev == NULL) {
|
||||
printf("%s: no such device\n", devname);
|
||||
ret = -1;
|
||||
} else {
|
||||
mdio_write(dev, addr, reg, value);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
|
||||
|
||||
int ftmac110_initialize(bd_t *bis)
|
||||
{
|
||||
int i, card_nr = 0;
|
||||
struct eth_device *dev;
|
||||
struct ftmac110_chip *chip;
|
||||
|
||||
dev = malloc(sizeof(*dev) + sizeof(*chip));
|
||||
if (dev == NULL) {
|
||||
panic("ftmac110: out of memory 1\n");
|
||||
return -1;
|
||||
}
|
||||
chip = (struct ftmac110_chip *)(dev + 1);
|
||||
memset(dev, 0, sizeof(*dev) + sizeof(*chip));
|
||||
|
||||
sprintf(dev->name, "FTMAC110#%d", card_nr);
|
||||
|
||||
dev->iobase = CONFIG_FTMAC110_BASE;
|
||||
chip->regs = (void __iomem *)dev->iobase;
|
||||
dev->priv = chip;
|
||||
dev->init = ftmac110_probe;
|
||||
dev->halt = ftmac110_halt;
|
||||
dev->send = ftmac110_send;
|
||||
dev->recv = ftmac110_recv;
|
||||
|
||||
if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
|
||||
eth_random_enetaddr(dev->enetaddr);
|
||||
|
||||
/* allocate tx descriptors (it must be 16 bytes aligned) */
|
||||
chip->txd = dma_alloc_coherent(
|
||||
sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
|
||||
if (!chip->txd)
|
||||
panic("ftmac110: out of memory 3\n");
|
||||
memset(chip->txd, 0,
|
||||
sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
|
||||
for (i = 0; i < CFG_TXDES_NUM; ++i) {
|
||||
void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
|
||||
if (!va)
|
||||
panic("ftmac110: out of memory 4\n");
|
||||
chip->txd[i].vbuf = va;
|
||||
chip->txd[i].buf = cpu_to_le32(virt_to_phys(va));
|
||||
chip->txd[i].ct[1] = 0;
|
||||
chip->txd[i].ct[0] = 0; /* owned by SW */
|
||||
}
|
||||
chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
|
||||
chip->txd_idx = 0;
|
||||
|
||||
/* allocate rx descriptors (it must be 16 bytes aligned) */
|
||||
chip->rxd = dma_alloc_coherent(
|
||||
sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
|
||||
if (!chip->rxd)
|
||||
panic("ftmac110: out of memory 4\n");
|
||||
memset((void *)chip->rxd, 0,
|
||||
sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
|
||||
for (i = 0; i < CFG_RXDES_NUM; ++i) {
|
||||
void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
|
||||
if (!va)
|
||||
panic("ftmac110: out of memory 5\n");
|
||||
/* it needs to be exactly 2 bytes aligned */
|
||||
va = ((uint8_t *)va + 2);
|
||||
chip->rxd[i].vbuf = va;
|
||||
chip->rxd[i].buf = cpu_to_le32(virt_to_phys(va));
|
||||
chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
|
||||
chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
|
||||
}
|
||||
chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
|
||||
chip->rxd_idx = 0;
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
|
||||
miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
|
||||
#endif
|
||||
|
||||
card_nr++;
|
||||
|
||||
return card_nr;
|
||||
}
|
177
drivers/net/ftmac110.h
Normal file
177
drivers/net/ftmac110.h
Normal 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
645
drivers/net/ks8851_mll.c
Normal 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
357
drivers/net/ks8851_mll.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
94
drivers/net/phy/icplus.c
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
533
drivers/net/sunxi_wemac.c
Normal 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, ®s->mac_madr);
|
||||
|
||||
/* pull up the phy io line */
|
||||
writel(0x1, ®s->mac_mcmd);
|
||||
|
||||
/* Wait read complete */
|
||||
mdelay(1);
|
||||
|
||||
/* push down the phy io line */
|
||||
writel(0x0, ®s->mac_mcmd);
|
||||
|
||||
/* and write data */
|
||||
*value = readl(®s->mac_mrdd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a word to phyxcer
|
||||
*/
|
||||
static int wemac_phy_write(const char *devname, unsigned char addr,
|
||||
unsigned char reg, unsigned short value)
|
||||
{
|
||||
struct eth_device *dev = eth_get_dev_by_name(devname);
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
|
||||
/* issue the phy address and reg */
|
||||
writel(addr << 8 | reg, ®s->mac_madr);
|
||||
|
||||
/* pull up the phy io line */
|
||||
writel(0x1, ®s->mac_mcmd);
|
||||
|
||||
/* Wait write complete */
|
||||
mdelay(1);
|
||||
|
||||
/* push down the phy io line */
|
||||
writel(0x0, ®s->mac_mcmd);
|
||||
|
||||
/* and write data */
|
||||
writel(value, ®s->mac_mwtd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void emac_setup(struct eth_device *dev)
|
||||
{
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
u32 reg_val;
|
||||
u16 phy_val;
|
||||
u32 duplex_flag;
|
||||
|
||||
/* Set up TX */
|
||||
writel(EMAC_TX_SETUP, ®s->tx_mode);
|
||||
|
||||
/* Set up RX */
|
||||
writel(EMAC_RX_SETUP, ®s->rx_ctl);
|
||||
|
||||
/* Set MAC */
|
||||
/* Set MAC CTL0 */
|
||||
writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0);
|
||||
|
||||
/* Set MAC CTL1 */
|
||||
wemac_phy_read(dev->name, 1, 0, &phy_val);
|
||||
debug("PHY SETUP, reg 0 value: %x\n", phy_val);
|
||||
duplex_flag = !!(phy_val & (1 << 8));
|
||||
|
||||
reg_val = 0;
|
||||
if (duplex_flag)
|
||||
reg_val = (0x1 << 0);
|
||||
writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1);
|
||||
|
||||
/* Set up IPGT */
|
||||
writel(EMAC_MAC_IPGT, ®s->mac_ipgt);
|
||||
|
||||
/* Set up IPGR */
|
||||
writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr);
|
||||
|
||||
/* Set up Collison window */
|
||||
writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt);
|
||||
|
||||
/* Set up Max Frame Length */
|
||||
writel(EMAC_MAC_MFL, ®s->mac_maxf);
|
||||
}
|
||||
|
||||
static void wemac_reset(struct eth_device *dev)
|
||||
{
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
|
||||
debug("resetting device\n");
|
||||
|
||||
/* RESET device */
|
||||
writel(0, ®s->ctl);
|
||||
udelay(200);
|
||||
|
||||
writel(1, ®s->ctl);
|
||||
udelay(200);
|
||||
}
|
||||
|
||||
static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd)
|
||||
{
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
struct wemac_eth_dev *priv = dev->priv;
|
||||
u16 phy_reg;
|
||||
|
||||
/* Init EMAC */
|
||||
|
||||
/* Flush RX FIFO */
|
||||
setbits_le32(®s->rx_ctl, 0x8);
|
||||
udelay(1);
|
||||
|
||||
/* Init MAC */
|
||||
|
||||
/* Soft reset MAC */
|
||||
clrbits_le32(®s->mac_ctl0, 1 << 15);
|
||||
|
||||
/* Set MII clock */
|
||||
clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2);
|
||||
|
||||
/* Clear RX counter */
|
||||
writel(0x0, ®s->rx_fbc);
|
||||
udelay(1);
|
||||
|
||||
/* Set up EMAC */
|
||||
emac_setup(dev);
|
||||
|
||||
writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
|
||||
dev->enetaddr[2], ®s->mac_a1);
|
||||
writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
|
||||
dev->enetaddr[5], ®s->mac_a0);
|
||||
|
||||
mdelay(1);
|
||||
|
||||
wemac_reset(dev);
|
||||
|
||||
/* PHY POWER UP */
|
||||
wemac_phy_read(dev->name, 1, 0, &phy_reg);
|
||||
wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11)));
|
||||
mdelay(1);
|
||||
|
||||
wemac_phy_read(dev->name, 1, 0, &phy_reg);
|
||||
|
||||
priv->speed = miiphy_speed(dev->name, 0);
|
||||
priv->duplex = miiphy_duplex(dev->name, 0);
|
||||
|
||||
/* Print link status only once */
|
||||
if (!priv->link_printed) {
|
||||
printf("ENET Speed is %d Mbps - %s duplex connection\n",
|
||||
priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL");
|
||||
priv->link_printed = 1;
|
||||
}
|
||||
|
||||
/* Set EMAC SPEED depend on PHY */
|
||||
clrsetbits_le32(®s->mac_supp, 1 << 8,
|
||||
((phy_reg & (1 << 13)) >> 13) << 8);
|
||||
|
||||
/* Set duplex depend on phy */
|
||||
clrsetbits_le32(®s->mac_ctl1, 1 << 0,
|
||||
((phy_reg & (1 << 8)) >> 8) << 0);
|
||||
|
||||
/* Enable RX/TX */
|
||||
setbits_le32(®s->ctl, 0x7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sunxi_wemac_eth_halt(struct eth_device *dev)
|
||||
{
|
||||
/* Nothing to do here */
|
||||
}
|
||||
|
||||
static int sunxi_wemac_eth_recv(struct eth_device *dev)
|
||||
{
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
struct wemac_rxhdr rxhdr;
|
||||
u32 rxcount;
|
||||
u32 reg_val;
|
||||
int rx_len;
|
||||
int rx_status;
|
||||
int good_packet;
|
||||
|
||||
/* Check packet ready or not */
|
||||
|
||||
/*
|
||||
* Race warning: The first packet might arrive with
|
||||
* the interrupts disabled, but the second will fix
|
||||
*/
|
||||
rxcount = readl(®s->rx_fbc);
|
||||
if (!rxcount) {
|
||||
/* Had one stuck? */
|
||||
rxcount = readl(®s->rx_fbc);
|
||||
if (!rxcount)
|
||||
return 0;
|
||||
}
|
||||
|
||||
reg_val = readl(®s->rx_io_data);
|
||||
if (reg_val != 0x0143414d) {
|
||||
/* Disable RX */
|
||||
clrbits_le32(®s->ctl, 1 << 2);
|
||||
|
||||
/* Flush RX FIFO */
|
||||
setbits_le32(®s->rx_ctl, 1 << 3);
|
||||
while (readl(®s->rx_ctl) & (1 << 3))
|
||||
;
|
||||
|
||||
/* Enable RX */
|
||||
setbits_le32(®s->ctl, 1 << 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* A packet ready now
|
||||
* Get status/length
|
||||
*/
|
||||
good_packet = 1;
|
||||
|
||||
wemac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr));
|
||||
|
||||
rx_len = rxhdr.rx_len;
|
||||
rx_status = rxhdr.rx_status;
|
||||
|
||||
/* Packet Status check */
|
||||
if (rx_len < 0x40) {
|
||||
good_packet = 0;
|
||||
debug("RX: Bad Packet (runt)\n");
|
||||
}
|
||||
|
||||
/* rx_status is identical to RSR register. */
|
||||
if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) {
|
||||
good_packet = 0;
|
||||
if (rx_status & EMAC_CRCERR)
|
||||
printf("crc error\n");
|
||||
if (rx_status & EMAC_LENERR)
|
||||
printf("length error\n");
|
||||
}
|
||||
|
||||
/* Move data from WEMAC */
|
||||
if (good_packet) {
|
||||
if (rx_len > DMA_CPU_TRRESHOLD) {
|
||||
printf("Received packet is too big (len=%d)\n", rx_len);
|
||||
} else {
|
||||
wemac_inblk_32bit((void *)®s->rx_io_data,
|
||||
NetRxPackets[0], rx_len);
|
||||
|
||||
/* Pass to upper layer */
|
||||
NetReceive(NetRxPackets[0], rx_len);
|
||||
return rx_len;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len)
|
||||
{
|
||||
struct wemac_regs *regs = (struct wemac_regs *)dev->iobase;
|
||||
|
||||
/* Select channel 0 */
|
||||
writel(0, ®s->tx_ins);
|
||||
|
||||
/* Write packet */
|
||||
wemac_outblk_32bit((void *)®s->tx_io_data, packet, len);
|
||||
|
||||
/* Set TX len */
|
||||
writel(len, ®s->tx_pl0);
|
||||
|
||||
/* Start translate from fifo to phy */
|
||||
setbits_le32(®s->tx_ctl0, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sunxi_wemac_initialize(void)
|
||||
{
|
||||
struct sunxi_ccm_reg *const ccm =
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct sunxi_sramc_regs *sram =
|
||||
(struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE;
|
||||
struct eth_device *dev;
|
||||
struct wemac_eth_dev *priv;
|
||||
int pin;
|
||||
|
||||
dev = malloc(sizeof(*dev));
|
||||
if (dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev));
|
||||
if (!priv) {
|
||||
free(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
memset(priv, 0, sizeof(struct wemac_eth_dev));
|
||||
|
||||
/* Map SRAM to EMAC */
|
||||
setbits_le32(&sram->ctrl1, 0x5 << 2);
|
||||
|
||||
/* Configure pin mux settings for MII Ethernet */
|
||||
for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++)
|
||||
sunxi_gpio_set_cfgpin(pin, 2);
|
||||
|
||||
/* Set up clock gating */
|
||||
setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC);
|
||||
|
||||
dev->iobase = SUNXI_EMAC_BASE;
|
||||
dev->priv = priv;
|
||||
dev->init = sunxi_wemac_eth_init;
|
||||
dev->halt = sunxi_wemac_eth_halt;
|
||||
dev->send = sunxi_wemac_eth_send;
|
||||
dev->recv = sunxi_wemac_eth_recv;
|
||||
strcpy(dev->name, "wemac");
|
||||
|
||||
eth_register(dev);
|
||||
|
||||
miiphy_register(dev->name, wemac_phy_read, wemac_phy_write);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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[]);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
74
net/nfs.c
74
net/nfs.c
|
@ -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;
|
||||
|
|
12
net/tftp.c
12
net/tftp.c
|
@ -446,8 +446,8 @@ static void
|
|||
TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
|
||||
unsigned len)
|
||||
{
|
||||
ushort proto;
|
||||
ushort *s;
|
||||
__be16 proto;
|
||||
__be16 *s;
|
||||
int i;
|
||||
|
||||
if (dest != TftpOurPort) {
|
||||
|
@ -465,7 +465,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
|
|||
return;
|
||||
len -= 2;
|
||||
/* warning: don't use increment (++) in ntohs() macros!! */
|
||||
s = (ushort *)pkt;
|
||||
s = (__be16 *)pkt;
|
||||
proto = *s++;
|
||||
pkt = (uchar *)s;
|
||||
switch (ntohs(proto)) {
|
||||
|
@ -556,7 +556,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
|
|||
if (len < 2)
|
||||
return;
|
||||
len -= 2;
|
||||
TftpBlock = ntohs(*(ushort *)pkt);
|
||||
TftpBlock = ntohs(*(__be16 *)pkt);
|
||||
|
||||
update_block_number();
|
||||
|
||||
|
@ -644,9 +644,9 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
|
|||
|
||||
case TFTP_ERROR:
|
||||
printf("\nTFTP error: '%s' (%d)\n",
|
||||
pkt + 2, ntohs(*(ushort *)pkt));
|
||||
pkt + 2, ntohs(*(__be16 *)pkt));
|
||||
|
||||
switch (ntohs(*(ushort *)pkt)) {
|
||||
switch (ntohs(*(__be16 *)pkt)) {
|
||||
case TFTP_ERR_FILE_NOT_FOUND:
|
||||
case TFTP_ERR_ACCESS_DENIED:
|
||||
puts("Not retrying...\n");
|
||||
|
|
Loading…
Reference in a new issue