diff options
52 files changed, 4902 insertions, 2322 deletions
diff --git a/arch/powerpc/cpu/mpc8xxx/fdt.c b/arch/powerpc/cpu/mpc8xxx/fdt.c index 0c166fd..520cb90 100644 --- a/arch/powerpc/cpu/mpc8xxx/fdt.c +++ b/arch/powerpc/cpu/mpc8xxx/fdt.c @@ -27,8 +27,8 @@ #include <libfdt.h> #include <fdt_support.h> #include <asm/mp.h> -#include <asm/fsl_enet.h> #include <asm/fsl_serdes.h> +#include <phy.h> #if defined(CONFIG_MP) && (defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx)) static int ft_del_cpuhandle(void *blob, int cpuhandle) @@ -218,27 +218,10 @@ void fdt_fixup_crypto_node(void *blob, int sec_rev) } #endif -int fdt_fixup_phy_connection(void *blob, int offset, enum fsl_phy_enet_if phyc) +int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc) { - static const char *fsl_phy_enet_if_str[] = { - [MII] = "mii", - [RMII] = "rmii", - [GMII] = "gmii", - [RGMII] = "rgmii", - [RGMII_ID] = "rgmii-id", - [RGMII_RXID] = "rgmii-rxid", - [SGMII] = "sgmii", - [TBI] = "tbi", - [RTBI] = "rtbi", - [XAUI] = "xgmii", - [FSL_ETH_IF_NONE] = "", - }; - - if (phyc > ARRAY_SIZE(fsl_phy_enet_if_str)) - return fdt_setprop_string(blob, offset, "phy-connection-type", ""); - return fdt_setprop_string(blob, offset, "phy-connection-type", - fsl_phy_enet_if_str[phyc]); + phy_string_for_interface(phyc)); } #ifdef CONFIG_SYS_SRIO diff --git a/arch/powerpc/include/asm/config.h b/arch/powerpc/include/asm/config.h index 536f142..624d8c2 100644 --- a/arch/powerpc/include/asm/config.h +++ b/arch/powerpc/include/asm/config.h @@ -80,6 +80,15 @@ #endif #endif +/* The TSEC driver uses the PHYLIB infrastructure */ +#ifndef CONFIG_PHYLIB +#if defined(CONFIG_TSEC_ENET) +#define CONFIG_PHYLIB + +#include <config_phylib_all_drivers.h> +#endif /* TSEC_ENET */ +#endif /* !CONFIG_PHYLIB */ + /* All PPC boards must swap IDE bytes */ #define CONFIG_IDE_SWAP_IO diff --git a/arch/powerpc/include/asm/fsl_enet.h b/arch/powerpc/include/asm/fsl_enet.h index 4fb2857..8227b66 100644 --- a/arch/powerpc/include/asm/fsl_enet.h +++ b/arch/powerpc/include/asm/fsl_enet.h @@ -13,21 +13,18 @@ #ifndef __ASM_PPC_FSL_ENET_H #define __ASM_PPC_FSL_ENET_H -enum fsl_phy_enet_if { - MII, - RMII, - GMII, - RGMII, - RGMII_ID, - RGMII_RXID, - RGMII_TXID, - SGMII, - TBI, - RTBI, - XAUI, - FSL_ETH_IF_NONE, -}; +#include <phy.h> -int fdt_fixup_phy_connection(void *blob, int offset, enum fsl_phy_enet_if phyc); +struct tsec_mii_mng { + u32 miimcfg; /* MII management configuration reg */ + u32 miimcom; /* MII management command reg */ + u32 miimadd; /* MII management address reg */ + u32 miimcon; /* MII management control reg */ + u32 miimstat; /* MII management status reg */ + u32 miimind; /* MII management indication reg */ + u32 ifstat; /* Interface Status Register */ +} __attribute__ ((packed)); + +int fdt_fixup_phy_connection(void *blob, int offset, phy_interface_t phyc); #endif /* __ASM_PPC_FSL_ENET_H */ diff --git a/board/freescale/mpc8360emds/mpc8360emds.c b/board/freescale/mpc8360emds/mpc8360emds.c index 0babd26..51d8035 100644 --- a/board/freescale/mpc8360emds/mpc8360emds.c +++ b/board/freescale/mpc8360emds/mpc8360emds.c @@ -16,6 +16,7 @@ #include <mpc83xx.h> #include <i2c.h> #include <miiphy.h> +#include <phy.h> #if defined(CONFIG_PCI) #include <pci.h> #endif @@ -160,8 +161,9 @@ int board_eth_init(bd_t *bd) int i; for (i = 0; i < ARRAY_SIZE(uec_info); i++) - uec_info[i].enet_interface_type = RGMII_RXID; - uec_info[i].speed = 1000; + uec_info[i].enet_interface_type = + PHY_INTERFACE_MODE_RGMII_RXID; + uec_info[i].speed = SPEED_1000; } return uec_eth_init(bd, uec_info, ARRAY_SIZE(uec_info)); } @@ -398,7 +400,7 @@ void ft_board_setup(void *blob, bd_t *bd) "phy-connection-type", 0); if (prop && (strcmp(prop, "rgmii-id") == 0)) fdt_fixup_phy_connection(blob, path, - RGMII_RXID); + PHY_INTERFACE_MODE_RGMII_RXID); } #endif #if defined(CONFIG_HAS_ETH1) @@ -410,7 +412,7 @@ void ft_board_setup(void *blob, bd_t *bd) "phy-connection-type", 0); if (prop && (strcmp(prop, "rgmii-id") == 0)) fdt_fixup_phy_connection(blob, path, - RGMII_RXID); + PHY_INTERFACE_MODE_RGMII_RXID); } #endif } diff --git a/board/freescale/mpc837xemds/mpc837xemds.c b/board/freescale/mpc837xemds/mpc837xemds.c index 51dd692..650a4fe 100644 --- a/board/freescale/mpc837xemds/mpc837xemds.c +++ b/board/freescale/mpc837xemds/mpc837xemds.c @@ -21,6 +21,8 @@ #include <libfdt.h> #include <fdt_support.h> #include <fsl_esdhc.h> +#include <fsl_mdio.h> +#include <phy.h> #include "pci.h" #include "../common/pq-mds-pib.h" @@ -86,6 +88,7 @@ int board_mmc_init(bd_t *bd) #if defined(CONFIG_TSEC1) || defined(CONFIG_TSEC2) int board_eth_init(bd_t *bd) { + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[2]; struct immap __iomem *im = (struct immap __iomem *)CONFIG_SYS_IMMR; u32 rcwh = in_be32(&im->reset.rcwh); @@ -131,6 +134,11 @@ int board_eth_init(bd_t *bd) } num++; #endif + + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bd, &mdio_info); + return tsec_eth_init(bd, tsec_info, num); } @@ -148,7 +156,7 @@ static void __ft_tsec_fixup(void *blob, bd_t *bd, const char *alias, return; } - err = fdt_fixup_phy_connection(blob, off, SGMII); + err = fdt_fixup_phy_connection(blob, off, PHY_INTERFACE_MODE_SGMII); if (err) { printf("WARNING: could not set phy-connection-type for %s: " diff --git a/board/freescale/mpc8536ds/mpc8536ds.c b/board/freescale/mpc8536ds/mpc8536ds.c index f83f629..b292e13 100644 --- a/board/freescale/mpc8536ds/mpc8536ds.c +++ b/board/freescale/mpc8536ds/mpc8536ds.c @@ -36,6 +36,7 @@ #include <libfdt.h> #include <spd_sdram.h> #include <fdt_support.h> +#include <fsl_mdio.h> #include <tsec.h> #include <netdev.h> #include <sata.h> @@ -234,6 +235,7 @@ int board_early_init_r(void) int board_eth_init(bd_t *bis) { #ifdef CONFIG_TSEC_ENET + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[2]; int num = 0; @@ -268,6 +270,10 @@ int board_eth_init(bd_t *bis) } #endif + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bis, &mdio_info); + tsec_eth_init(bis, tsec_info, num); #endif return pci_eth_init(bis); diff --git a/board/freescale/mpc8544ds/mpc8544ds.c b/board/freescale/mpc8544ds/mpc8544ds.c index a48c815..6fe8d39 100644 --- a/board/freescale/mpc8544ds/mpc8544ds.c +++ b/board/freescale/mpc8544ds/mpc8544ds.c @@ -33,6 +33,7 @@ #include <miiphy.h> #include <libfdt.h> #include <fdt_support.h> +#include <fsl_mdio.h> #include <tsec.h> #include <netdev.h> @@ -248,9 +249,35 @@ get_board_sys_clk(ulong dummy) return val; } + +#define MIIM_CIS8204_SLED_CON 0x1b +#define MIIM_CIS8204_SLEDCON_INIT 0x1115 +/* + * Hack to write all 4 PHYs with the LED values + */ +int board_phy_config(struct phy_device *phydev) +{ + static int do_once; + uint phyid; + struct mii_dev *bus = phydev->bus; + + if (do_once) + return 0; + + for (phyid = 0; phyid < 4; phyid++) + bus->write(bus, phyid, MDIO_DEVAD_NONE, MIIM_CIS8204_SLED_CON, + MIIM_CIS8204_SLEDCON_INIT); + + do_once = 1; + + return 0; +} + + int board_eth_init(bd_t *bis) { #ifdef CONFIG_TSEC_ENET + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[2]; int num = 0; @@ -282,6 +309,9 @@ int board_eth_init(bd_t *bis) fsl_sgmii_riser_init(tsec_info, num); } + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bis, &mdio_info); tsec_eth_init(bis, tsec_info, num); #endif diff --git a/board/freescale/mpc8569mds/mpc8569mds.c b/board/freescale/mpc8569mds/mpc8569mds.c index ecda222..89557d2 100644 --- a/board/freescale/mpc8569mds/mpc8569mds.c +++ b/board/freescale/mpc8569mds/mpc8569mds.c @@ -39,6 +39,7 @@ #include <libfdt.h> #include <fdt_support.h> #include <fsl_esdhc.h> +#include <phy.h> #include "bcsr.h" #if defined(CONFIG_PQ_MDS_PIB) @@ -550,7 +551,8 @@ void ft_board_setup(void *blob, bd_t *bd) break; } - err = fdt_fixup_phy_connection(blob, nodeoff, RMII); + err = fdt_fixup_phy_connection(blob, nodeoff, + PHY_INTERFACE_MODE_RMII); if (err < 0) { printf("WARNING: could not set phy-connection-type " diff --git a/board/freescale/mpc8572ds/mpc8572ds.c b/board/freescale/mpc8572ds/mpc8572ds.c index f444805..b20299e 100644 --- a/board/freescale/mpc8572ds/mpc8572ds.c +++ b/board/freescale/mpc8572ds/mpc8572ds.c @@ -35,6 +35,7 @@ #include <libfdt.h> #include <fdt_support.h> #include <tsec.h> +#include <fsl_mdio.h> #include <netdev.h> #include "../common/sgmii_riser.h" @@ -187,6 +188,7 @@ int board_early_init_r(void) #ifdef CONFIG_TSEC_ENET int board_eth_init(bd_t *bis) { + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[4]; int num = 0; @@ -233,6 +235,10 @@ int board_eth_init(bd_t *bis) fsl_sgmii_riser_init(tsec_info, num); #endif + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bis, &mdio_info); + tsec_eth_init(bis, tsec_info, num); return pci_eth_init(bis); diff --git a/board/freescale/p1022ds/p1022ds.c b/board/freescale/p1022ds/p1022ds.c index 8b78404..73a1021 100644 --- a/board/freescale/p1022ds/p1022ds.c +++ b/board/freescale/p1022ds/p1022ds.c @@ -22,6 +22,7 @@ #include <asm/io.h> #include <libfdt.h> #include <fdt_support.h> +#include <fsl_mdio.h> #include <tsec.h> #include <asm/fsl_law.h> #include <netdev.h> @@ -279,6 +280,7 @@ int board_early_init_r(void) */ int board_eth_init(bd_t *bis) { + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[2]; unsigned int num = 0; @@ -291,6 +293,10 @@ int board_eth_init(bd_t *bis) num++; #endif + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bis, &mdio_info); + return tsec_eth_init(bis, tsec_info, num) + pci_eth_init(bis); } diff --git a/board/freescale/p1_p2_rdb/p1_p2_rdb.c b/board/freescale/p1_p2_rdb/p1_p2_rdb.c index 307c3e2..0b4ae9d 100644 --- a/board/freescale/p1_p2_rdb/p1_p2_rdb.c +++ b/board/freescale/p1_p2_rdb/p1_p2_rdb.c @@ -31,6 +31,7 @@ #include <miiphy.h> #include <libfdt.h> #include <fdt_support.h> +#include <fsl_mdio.h> #include <tsec.h> #include <vsc7385.h> #include <netdev.h> @@ -179,6 +180,7 @@ int board_early_init_r(void) #ifdef CONFIG_TSEC_ENET int board_eth_init(bd_t *bis) { + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[4]; int num = 0; char *tmp; @@ -216,6 +218,10 @@ int board_eth_init(bd_t *bis) puts("No address specified for VSC7385 microcode.\n"); #endif + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + fsl_pq_mdio_init(bis, &mdio_info); + tsec_eth_init(bis, tsec_info, num); return pci_eth_init(bis); diff --git a/board/freescale/p2020ds/p2020ds.c b/board/freescale/p2020ds/p2020ds.c index 238b4d9..d3af6cf 100644 --- a/board/freescale/p2020ds/p2020ds.c +++ b/board/freescale/p2020ds/p2020ds.c @@ -34,6 +34,7 @@ #include <miiphy.h> #include <libfdt.h> #include <fdt_support.h> +#include <fsl_mdio.h> #include <tsec.h> #include <asm/fsl_law.h> #include <netdev.h> @@ -201,6 +202,7 @@ int board_early_init_r(void) #ifdef CONFIG_TSEC_ENET int board_eth_init(bd_t *bis) { + struct fsl_pq_mdio_info mdio_info; struct tsec_info_struct tsec_info[4]; int num = 0; @@ -235,6 +237,11 @@ int board_eth_init(bd_t *bis) fsl_sgmii_riser_init(tsec_info, num); #endif + mdio_info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + mdio_info.name = DEFAULT_MII_NAME; + + fsl_pq_mdio_init(bis, &mdio_info); + tsec_eth_init(bis, tsec_info, num); return pci_eth_init(bis); diff --git a/common/Makefile b/common/Makefile index 4fb050e..f81cff9 100644 --- a/common/Makefile +++ b/common/Makefile @@ -117,7 +117,11 @@ COBJS-$(CONFIG_CMD_MFSL) += cmd_mfsl.o COBJS-$(CONFIG_CMD_MG_DISK) += cmd_mgdisk.o COBJS-$(CONFIG_MII) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += miiphyutil.o +COBJS-$(CONFIG_PHYLIB) += miiphyutil.o COBJS-$(CONFIG_CMD_MII) += cmd_mii.o +ifdef CONFIG_PHYLIB +COBJS-$(CONFIG_CMD_MII) += cmd_mdio.o +endif COBJS-$(CONFIG_CMD_MISC) += cmd_misc.o COBJS-$(CONFIG_CMD_MMC) += cmd_mmc.o COBJS-$(CONFIG_CMD_MMC_SPI) += cmd_mmc_spi.o diff --git a/common/cmd_mdio.c b/common/cmd_mdio.c new file mode 100644 index 0000000..cac0703 --- /dev/null +++ b/common/cmd_mdio.c @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2011 Freescale Semiconductor, Inc + * Andy Fleming + * + * See file CREDITS for list of people who contributed to this + * project. + * + * 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 + */ + +/* + * MDIO Commands + */ + +#include <common.h> +#include <command.h> +#include <miiphy.h> +#include <phy.h> + + +static char last_op[2]; +static uint last_data; +static uint last_addr_lo; +static uint last_addr_hi; +static uint last_devad_lo; +static uint last_devad_hi; +static uint last_reg_lo; +static uint last_reg_hi; + +static int extract_range(char *input, int *plo, int *phi) +{ + char *end; + *plo = simple_strtol(input, &end, 0); + if (end == input) + return -1; + + if ((*end == '-') && *(++end)) + *phi = simple_strtol(end, NULL, 0); + else if (*end == '\0') + *phi = *plo; + else + return -1; + + return 0; +} + +int mdio_write_ranges(struct mii_dev *bus, int addrlo, + int addrhi, int devadlo, int devadhi, + int reglo, int reghi, unsigned short data) +{ + int addr, devad, reg; + int err = 0; + + for (addr = addrlo; addr <= addrhi; addr++) { + for (devad = devadlo; devad <= devadhi; devad++) { + for (reg = reglo; reg <= reghi; reg++) { + err = bus->write(bus, addr, devad, reg, data); + + if (err) + goto err_out; + } + } + } + +err_out: + return err; +} + +int mdio_read_ranges(struct mii_dev *bus, int addrlo, + int addrhi, int devadlo, int devadhi, + int reglo, int reghi) +{ + int addr, devad, reg; + + printf("Reading from bus %s\n", bus->name); + for (addr = addrlo; addr <= addrhi; addr++) { + printf("PHY at address %d:\n", addr); + + for (devad = devadlo; devad <= devadhi; devad++) { + for (reg = reglo; reg <= reghi; reg++) { + u16 val; + val = bus->read(bus, addr, devad, reg); + + if (val < 0) { + printf("Error\n"); + + return val; + } + + if (devad >= 0) + printf("%d.", devad); + + printf("%d - 0x%x\n", reg, val & 0xffff); + } + } + } + + return 0; +} + +/* The register will be in the form [a[-b].]x[-y] */ +int extract_reg_range(char *input, int *devadlo, int *devadhi, + int *reglo, int *reghi) +{ + char *regstr; + + /* use strrchr to find the last string after a '.' */ + regstr = strrchr(input, '.'); + + /* If it exists, extract the devad(s) */ + if (regstr) { + char devadstr[32]; + + strncpy(devadstr, input, regstr - input); + devadstr[regstr - input] = '\0'; + + if (extract_range(devadstr, devadlo, devadhi)) + return -1; + + regstr++; + } else { + /* Otherwise, we have no devad, and we just got regs */ + *devadlo = *devadhi = MDIO_DEVAD_NONE; + + regstr = input; + } + + return extract_range(regstr, reglo, reghi); +} + +int extract_phy_range(char *const argv[], int argc, struct mii_dev **bus, + int *addrlo, int *addrhi) +{ + struct phy_device *phydev; + + if ((argc < 1) || (argc > 2)) + return -1; + + /* If there are two arguments, it's busname addr */ + if (argc == 2) { + *bus = miiphy_get_dev_by_name(argv[0]); + + if (!*bus) + return -1; + + return extract_range(argv[1], addrlo, addrhi); + } + + /* It must be one argument, here */ + + /* + * This argument can be one of two things: + * 1) Ethernet device name + * 2) Just an address (use the previously-used bus) + * + * We check all buses for a PHY which is connected to an ethernet + * device by the given name. If none are found, we call + * extract_range() on the string, and see if it's an address range. + */ + phydev = mdio_phydev_for_ethname(argv[0]); + + if (phydev) { + *addrlo = *addrhi = phydev->addr; + *bus = phydev->bus; + + return 0; + } + + /* It's an address or nothing useful */ + return extract_range(argv[0], addrlo, addrhi); +} + +/* ---------------------------------------------------------------- */ +static int do_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char op[2]; + int addrlo, addrhi, reglo, reghi, devadlo, devadhi; + unsigned short data; + int pos = argc - 1; + struct mii_dev *bus; + + if (argc < 2) + return cmd_usage(cmdtp); + + /* + * We use the last specified parameters, unless new ones are + * entered. + */ + op[0] = argv[1][0]; + addrlo = last_addr_lo; + addrhi = last_addr_hi; + devadlo = last_devad_lo; + devadhi = last_devad_hi; + reglo = last_reg_lo; + reghi = last_reg_hi; + data = last_data; + + bus = mdio_get_current_dev(); + + if (flag & CMD_FLAG_REPEAT) + op[0] = last_op[0]; + + switch (op[0]) { + case 'w': + if (pos > 1) + data = simple_strtoul(argv[pos--], NULL, 16); + case 'r': + if (pos > 1) + if (extract_reg_range(argv[pos--], &devadlo, &devadhi, + ®lo, ®hi)) + return -1; + + default: + if (pos > 1) + if (extract_phy_range(&(argv[2]), pos - 1, &bus, + &addrlo, &addrhi)) + return -1; + + break; + } + + if (op[0] == 'l') { + mdio_list_devices(); + + return 0; + } + + /* Save the chosen bus */ + miiphy_set_current_dev(bus->name); + + switch (op[0]) { + case 'w': + mdio_write_ranges(bus, addrlo, addrhi, devadlo, devadhi, + reglo, reghi, data); + break; + + case 'r': + mdio_read_ranges(bus, addrlo, addrhi, devadlo, devadhi, + reglo, reghi); + break; + } + + /* + * Save the parameters for repeats. + */ + last_op[0] = op[0]; + last_addr_lo = addrlo; + last_addr_hi = addrhi; + last_devad_lo = devadlo; + last_devad_hi = devadhi; + last_reg_lo = reglo; + last_reg_hi = reghi; + last_data = data; + + return 0; +} + +/***************************************************/ + +U_BOOT_CMD( + mdio, 6, 1, do_mdio, + "MDIO utility commands", + "list - List MDIO buses\n" + "mdio read <phydev> [<devad>.]<reg> - " + "read PHY's register at <devad>.<reg>\n" + "mdio write <phydev> [<devad>.]<reg> <data> - " + "write PHY's register at <devad>.<reg>\n" + "<phydev> may be:\n" + " <busname> <addr>\n" + " <addr>\n" + " <eth name>\n" + "<addr> <devad>, and <reg> may be ranges, e.g. 1-5.4-0x1f.\n" +); diff --git a/common/miiphyutil.c b/common/miiphyutil.c index e282096..243cae9 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -28,6 +28,7 @@ #include <common.h> #include <miiphy.h> +#include <phy.h> #include <asm/types.h> #include <linux/list.h> @@ -39,27 +40,18 @@ #undef debug #ifdef MII_DEBUG -#define debug(fmt,args...) printf (fmt ,##args) +#define debug(fmt, args...) printf(fmt, ##args) #else -#define debug(fmt,args...) +#define debug(fmt, args...) #endif /* MII_DEBUG */ -struct mii_dev { - struct list_head link; - const char *name; - int (*read) (const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value); - int (*write) (const char *devname, unsigned char addr, - unsigned char reg, unsigned short value); -}; - static struct list_head mii_devs; static struct mii_dev *current_mii; /* * Lookup the mii_dev struct by the registered device name. */ -static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) +struct mii_dev *miiphy_get_dev_by_name(const char *devname) { struct list_head *entry; struct mii_dev *dev; @@ -75,8 +67,6 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) return dev; } - if (!quiet) - printf("No such device: %s\n", devname); return NULL; } @@ -86,74 +76,190 @@ static struct mii_dev *miiphy_get_dev_by_name(const char *devname, int quiet) */ void miiphy_init(void) { - INIT_LIST_HEAD (&mii_devs); + INIT_LIST_HEAD(&mii_devs); current_mii = NULL; } +static int legacy_miiphy_read(struct mii_dev *bus, int addr, int devad, int reg) +{ + unsigned short val; + int ret; + struct legacy_mii_dev *ldev = bus->priv; + + ret = ldev->read(bus->name, addr, reg, &val); + + return ret ? -1 : (int)val; +} + +static int legacy_miiphy_write(struct mii_dev *bus, int addr, int devad, + int reg, u16 val) +{ + struct legacy_mii_dev *ldev = bus->priv; + + return ldev->write(bus->name, addr, reg, val); +} + /***************************************************************************** * * Register read and write MII access routines for the device <name>. */ void miiphy_register(const char *name, - int (*read) (const char *devname, unsigned char addr, + int (*read)(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value), - int (*write) (const char *devname, unsigned char addr, + int (*write)(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)) { struct mii_dev *new_dev; + struct legacy_mii_dev *ldev; unsigned int name_len; - char *new_name; /* check if we have unique name */ - new_dev = miiphy_get_dev_by_name(name, 1); + new_dev = miiphy_get_dev_by_name(name); if (new_dev) { printf("miiphy_register: non unique device name '%s'\n", name); return; } /* allocate memory */ - name_len = strlen (name); - new_dev = - (struct mii_dev *)malloc (sizeof (struct mii_dev) + name_len + 1); + name_len = strlen(name); + if (name_len > MDIO_NAME_LEN - 1) { + /* Hopefully this won't happen, but if it does, we'll know */ + printf("miiphy_register: MDIO name was longer than %d\n", + MDIO_NAME_LEN); + return; + } + + new_dev = mdio_alloc(); + ldev = malloc(sizeof(*ldev)); - if (new_dev == NULL) { - printf ("miiphy_register: cannot allocate memory for '%s'\n", + if (new_dev == NULL || ldev == NULL) { + printf("miiphy_register: cannot allocate memory for '%s'\n", name); return; } - memset (new_dev, 0, sizeof (struct mii_dev) + name_len); /* initalize mii_dev struct fields */ - INIT_LIST_HEAD (&new_dev->link); - new_dev->read = read; - new_dev->write = write; - new_dev->name = new_name = (char *)(new_dev + 1); - strncpy (new_name, name, name_len); - new_name[name_len] = '\0'; + new_dev->read = legacy_miiphy_read; + new_dev->write = legacy_miiphy_write; + sprintf(new_dev->name, name); + ldev->read = read; + ldev->write = write; + new_dev->priv = ldev; - debug ("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", - new_dev->name, new_dev->read, new_dev->write); + debug("miiphy_register: added '%s', read=0x%08lx, write=0x%08lx\n", + new_dev->name, ldev->read, ldev->write); /* add it to the list */ - list_add_tail (&new_dev->link, &mii_devs); + list_add_tail(&new_dev->link, &mii_devs); if (!current_mii) current_mii = new_dev; } +struct mii_dev *mdio_alloc(void) +{ + struct mii_dev *bus; + + bus = malloc(sizeof(*bus)); + if (!bus) + return bus; + + memset(bus, 0, sizeof(*bus)); + + /* initalize mii_dev struct fields */ + INIT_LIST_HEAD(&bus->link); + + return bus; +} + +int mdio_register(struct mii_dev *bus) +{ + if (!bus || !bus->name || !bus->read || !bus->write) + return -1; + + /* check if we have unique name */ + if (miiphy_get_dev_by_name(bus->name)) { + printf("mdio_register: non unique device name '%s'\n", + bus->name); + return -1; + } + + /* add it to the list */ + list_add_tail(&bus->link, &mii_devs); + + if (!current_mii) + current_mii = bus; + + return 0; +} + +void mdio_list_devices(void) +{ + struct list_head *entry; + + list_for_each(entry, &mii_devs) { + int i; + struct mii_dev *bus = list_entry(entry, struct mii_dev, link); + + printf("%s:\n", bus->name); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev = bus->phymap[i]; + + if (phydev) { + printf("%d - %s", i, phydev->drv->name); + + if (phydev->dev) + printf(" <--> %s\n", phydev->dev->name); + else + printf("\n"); + } + } + } +} + int miiphy_set_current_dev(const char *devname) { struct mii_dev *dev; - dev = miiphy_get_dev_by_name(devname, 0); + dev = miiphy_get_dev_by_name(devname); if (dev) { current_mii = dev; return 0; } + printf("No such device: %s\n", devname); + return 1; } +struct mii_dev *mdio_get_current_dev(void) +{ + return current_mii; +} + +struct phy_device *mdio_phydev_for_ethname(const char *ethname) +{ + struct list_head *entry; + struct mii_dev *bus; + + list_for_each(entry, &mii_devs) { + int i; + bus = list_entry(entry, struct mii_dev, link); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (!bus->phymap[i] || !bus->phymap[i]->dev) + continue; + + if (strcmp(bus->phymap[i]->dev->name, ethname) == 0) + return bus->phymap[i]; + } + } + + printf("%s is not a known ethernet\n", ethname); + return NULL; +} + const char *miiphy_get_current_dev(void) { if (current_mii) @@ -187,13 +293,15 @@ static struct mii_dev *miiphy_get_active_dev(const char *devname) int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value) { - struct mii_dev *dev; + struct mii_dev *bus; - dev = miiphy_get_active_dev(devname); - if (dev) - return dev->read(devname, addr, reg, value); + bus = miiphy_get_active_dev(devname); + if (bus) + *value = bus->read(bus, addr, MDIO_DEVAD_NONE, reg); + else + return 1; - return 1; + return (*value < 0) ? 1 : 0; } /***************************************************************************** @@ -207,11 +315,11 @@ int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value) { - struct mii_dev *dev; + struct mii_dev *bus; - dev = miiphy_get_active_dev(devname); - if (dev) - return dev->write(devname, addr, reg, value); + bus = miiphy_get_active_dev(devname); + if (bus) + return bus->write(bus, addr, MDIO_DEVAD_NONE, reg, value); return 1; } @@ -220,20 +328,20 @@ int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, * * Print out list of registered MII capable devices. */ -void miiphy_listdev (void) +void miiphy_listdev(void) { struct list_head *entry; struct mii_dev *dev; - puts ("MII devices: "); - list_for_each (entry, &mii_devs) { - dev = list_entry (entry, struct mii_dev, link); - printf ("'%s' ", dev->name); + puts("MII devices: "); + list_for_each(entry, &mii_devs) { + dev = list_entry(entry, struct mii_dev, link); + printf("'%s' ", dev->name); } - puts ("\n"); + puts("\n"); if (current_mii) - printf ("Current device: '%s'\n", current_mii->name); + printf("Current device: '%s'\n", current_mii->name); } /***************************************************************************** @@ -253,32 +361,33 @@ int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui, unsigned int reg = 0; unsigned short tmp; - if (miiphy_read (devname, addr, MII_PHYSID2, &tmp) != 0) { - debug ("PHY ID register 2 read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_PHYSID2, &tmp) != 0) { + debug("PHY ID register 2 read failed\n"); + return -1; } reg = tmp; - debug ("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); + debug("MII_PHYSID2 @ 0x%x = 0x%04x\n", addr, reg); if (reg == 0xFFFF) { /* No physical device present at this address */ - return (-1); + return -1; } - if (miiphy_read (devname, addr, MII_PHYSID1, &tmp) != 0) { - debug ("PHY ID register 1 read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_PHYSID1, &tmp) != 0) { + debug("PHY ID register 1 read failed\n"); + return -1; } reg |= tmp << 16; - debug ("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); + debug("PHY_PHYIDR[1,2] @ 0x%x = 0x%08x\n", addr, reg); *oui = (reg >> 10); *model = (unsigned char)((reg >> 4) & 0x0000003F); *rev = (unsigned char)(reg & 0x0000000F); - return (0); + return 0; } +#ifndef CONFIG_PHYLIB /***************************************************************************** * * Reset the PHY. @@ -290,16 +399,16 @@ int miiphy_reset(const char *devname, unsigned char addr) unsigned short reg; int timeout = 500; - if (miiphy_read (devname, addr, MII_BMCR, ®) != 0) { - debug ("PHY status read failed\n"); - return (-1); + if (miiphy_read(devname, addr, MII_BMCR, ®) != 0) { + debug("PHY status read failed\n"); + return -1; } - if (miiphy_write (devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { - debug ("PHY reset failed\n"); - return (-1); + if (miiphy_write(devname, addr, MII_BMCR, reg | BMCR_RESET) != 0) { + debug("PHY reset failed\n"); + return -1; } #ifdef CONFIG_PHY_RESET_DELAY - udelay (CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ + udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ #endif /* * Poll the control register for the reset bit to go to 0 (it is @@ -315,13 +424,14 @@ int miiphy_reset(const char *devname, unsigned char addr) udelay(1000); } if ((reg & 0x8000) == 0) { - return (0); + return 0; } else { - puts ("PHY reset timed out\n"); - return (-1); + puts("PHY reset timed out\n"); + return -1; } - return (0); + return 0; } +#endif /* !PHYLIB */ /***************************************************************************** * @@ -338,33 +448,32 @@ int miiphy_speed(const char *devname, unsigned char addr) * Check for 1000BASE-X. If it is supported, then assume that the speed * is 1000. */ - if (miiphy_is_1000base_x (devname, addr)) { + if (miiphy_is_1000base_x(devname, addr)) return _1000BASET; - } + /* * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. */ /* Check for 1000BASE-T. */ - if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { - printf ("PHY 1000BT status"); + if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { + printf("PHY 1000BT status"); goto miiphy_read_failed; } if (btsr != 0xFFFF && - (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) { + (btsr & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD))) return _1000BASET; - } #endif /* CONFIG_PHY_GIGE */ /* Check Basic Management Control Register first. */ - if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { - printf ("PHY speed"); + if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { + printf("PHY speed"); goto miiphy_read_failed; } /* Check if auto-negotiation is on. */ if (bmcr & BMCR_ANENABLE) { /* Get auto-negotiation results. */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - printf ("PHY AN speed"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + printf("PHY AN speed"); goto miiphy_read_failed; } return (anlpar & LPA_100) ? _100BASET : _10BASET; @@ -373,7 +482,7 @@ int miiphy_speed(const char *devname, unsigned char addr) return (bmcr & BMCR_SPEED100) ? _100BASET : _10BASET; miiphy_read_failed: - printf (" read failed, assuming 10BASE-T\n"); + printf(" read failed, assuming 10BASE-T\n"); return _10BASET; } @@ -389,10 +498,10 @@ int miiphy_duplex(const char *devname, unsigned char addr) u16 btsr; /* Check for 1000BASE-X. */ - if (miiphy_is_1000base_x (devname, addr)) { + if (miiphy_is_1000base_x(devname, addr)) { /* 1000BASE-X */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - printf ("1000BASE-X PHY AN duplex"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + printf("1000BASE-X PHY AN duplex"); goto miiphy_read_failed; } } @@ -400,8 +509,8 @@ int miiphy_duplex(const char *devname, unsigned char addr) * No 1000BASE-X, so assume 1000BASE-T/100BASE-TX/10BASE-T register set. */ /* Check for 1000BASE-T. */ - if (miiphy_read (devname, addr, MII_STAT1000, &btsr)) { - printf ("PHY 1000BT status"); + if (miiphy_read(devname, addr, MII_STAT1000, &btsr)) { + printf("PHY 1000BT status"); goto miiphy_read_failed; } if (btsr != 0xFFFF) { @@ -414,15 +523,15 @@ int miiphy_duplex(const char *devname, unsigned char addr) #endif /* CONFIG_PHY_GIGE */ /* Check Basic Management Control Register first. */ - if (miiphy_read (devname, addr, MII_BMCR, &bmcr)) { - puts ("PHY duplex"); + if (miiphy_read(devname, addr, MII_BMCR, &bmcr)) { + puts("PHY duplex"); goto miiphy_read_failed; } /* Check if auto-negotiation is on. */ if (bmcr & BMCR_ANENABLE) { /* Get auto-negotiation results. */ - if (miiphy_read (devname, addr, MII_LPA, &anlpar)) { - puts ("PHY AN duplex"); + if (miiphy_read(devname, addr, MII_LPA, &anlpar)) { + puts("PHY AN duplex"); goto miiphy_read_failed; } return (anlpar & (LPA_10FULL | LPA_100FULL)) ? @@ -432,7 +541,7 @@ int miiphy_duplex(const char *devname, unsigned char addr) return (bmcr & BMCR_FULLDPLX) ? FULL : HALF; miiphy_read_failed: - printf (" read failed, assuming half duplex\n"); + printf(" read failed, assuming half duplex\n"); return HALF; } @@ -446,8 +555,8 @@ int miiphy_is_1000base_x(const char *devname, unsigned char addr) #if defined(CONFIG_PHY_GIGE) u16 exsr; - if (miiphy_read (devname, addr, MII_ESTATUS, &exsr)) { - printf ("PHY extended status read failed, assuming no " + if (miiphy_read(devname, addr, MII_ESTATUS, &exsr)) { + printf("PHY extended status read failed, assuming no " "1000BASE-X\n"); return 0; } @@ -467,17 +576,17 @@ int miiphy_link(const char *devname, unsigned char addr) unsigned short reg; /* dummy read; needed to latch some phys */ - (void)miiphy_read (devname, addr, MII_BMSR, ®); - if (miiphy_read (devname, addr, MII_BMSR, ®)) { - puts ("MII_BMSR read failed, assuming no link\n"); - return (0); + (void)miiphy_read(devname, addr, MII_BMSR, ®); + if (miiphy_read(devname, addr, MII_BMSR, ®)) { + puts("MII_BMSR read failed, assuming no link\n"); + return 0; } /* Determine if a link is active */ if ((reg & BMSR_LSTATUS) != 0) { - return (1); + return 1; } else { - return (0); + return 0; } } #endif diff --git a/drivers/net/Makefile b/drivers/net/Makefile index fd9d0b4..819b197 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -79,7 +79,7 @@ COBJS-$(CONFIG_TIGON3) += tigon3.o COBJS-$(CONFIG_TIGON3) += bcm570x_autoneg.o COBJS-$(CONFIG_TIGON3) += 5701rls.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o -COBJS-$(CONFIG_TSEC_ENET) += tsec.o +COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o COBJS-$(CONFIG_TSI108_ETH) += tsi108_eth.o COBJS-$(CONFIG_ULI526X) += uli526x.o COBJS-$(CONFIG_VSC7385_ENET) += vsc7385.o diff --git a/drivers/net/dm9000x.c b/drivers/net/dm9000x.c index 709f67a..b5c5573 100644 --- a/drivers/net/dm9000x.c +++ b/drivers/net/dm9000x.c @@ -110,8 +110,8 @@ static board_info_t dm9000_info; /* function declaration ------------------------------------- */ static int dm9000_probe(void); -static u16 phy_read(int); -static void phy_write(int, u16); +static u16 dm9000_phy_read(int); +static void dm9000_phy_write(int, u16); static u8 DM9000_ior(int); static void DM9000_iow(int reg, u8 value); @@ -361,7 +361,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd) DM9000_iow(DM9000_IMR, IMR_PAR); i = 0; - while (!(phy_read(1) & 0x20)) { /* autonegation complete bit */ + while (!(dm9000_phy_read(1) & 0x20)) { /* autonegation complete bit */ udelay(1000); i++; if (i == 10000) { @@ -371,7 +371,7 @@ static int dm9000_init(struct eth_device *dev, bd_t *bd) } /* see what we've got */ - lnk = phy_read(17) >> 12; + lnk = dm9000_phy_read(17) >> 12; printf("operating at "); switch (lnk) { case 1: @@ -445,7 +445,7 @@ static void dm9000_halt(struct eth_device *netdev) DM9000_DBG("%s\n", __func__); /* RESET devie */ - phy_write(0, 0x8000); /* PHY RESET */ + dm9000_phy_write(0, 0x8000); /* PHY RESET */ DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */ DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */ DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */ @@ -581,7 +581,7 @@ DM9000_iow(int reg, u8 value) Read a word from phyxcer */ static u16 -phy_read(int reg) +dm9000_phy_read(int reg) { u16 val; @@ -593,7 +593,7 @@ phy_read(int reg) val = (DM9000_ior(DM9000_EPDRH) << 8) | DM9000_ior(DM9000_EPDRL); /* The read data keeps on REG_0D & REG_0E */ - DM9000_DBG("phy_read(0x%x): 0x%x\n", reg, val); + DM9000_DBG("dm9000_phy_read(0x%x): 0x%x\n", reg, val); return val; } @@ -601,7 +601,7 @@ phy_read(int reg) Write a word to phyxcer */ static void -phy_write(int reg, u16 value) +dm9000_phy_write(int reg, u16 value) { /* Fill the phyxcer register into REG_0C */ @@ -613,7 +613,7 @@ phy_write(int reg, u16 value) DM9000_iow(DM9000_EPCR, 0xa); /* Issue phyxcer write command */ udelay(500); /* Wait write complete */ DM9000_iow(DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - DM9000_DBG("phy_write(reg:0x%x, value:0x%x)\n", reg, value); + DM9000_DBG("dm9000_phy_write(reg:0x%x, value:0x%x)\n", reg, value); } int dm9000_initialize(bd_t *bis) diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 6c161b6..d55cacd 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -314,7 +314,7 @@ static void enc_release_bus(enc_dev_t *enc) /* * Read PHY register */ -static u16 phy_read(enc_dev_t *enc, const u8 addr) +static u16 enc_phy_read(enc_dev_t *enc, const u8 addr) { uint64_t etime; u8 status; @@ -339,7 +339,7 @@ static u16 phy_read(enc_dev_t *enc, const u8 addr) /* * Write PHY register */ -static void phy_write(enc_dev_t *enc, const u8 addr, const u16 data) +static void enc_phy_write(enc_dev_t *enc, const u8 addr, const u16 data) { uint64_t etime; u8 status; @@ -374,7 +374,7 @@ static int enc_phy_link_wait(enc_dev_t *enc) #ifdef CONFIG_ENC_SILENTLINK /* check if we have a link, then just return */ - status = phy_read(enc, PHY_REG_PHSTAT1); + status = enc_phy_read(enc, PHY_REG_PHSTAT1); if (status & ENC_PHSTAT1_LLSTAT) return 0; #endif @@ -382,10 +382,10 @@ static int enc_phy_link_wait(enc_dev_t *enc) /* wait for link with 1 second timeout */ etime = get_ticks() + get_tbclk(); while (get_ticks() <= etime) { - status = phy_read(enc, PHY_REG_PHSTAT1); + status = enc_phy_read(enc, PHY_REG_PHSTAT1); if (status & ENC_PHSTAT1_LLSTAT) { /* now we have a link */ - status = phy_read(enc, PHY_REG_PHSTAT2); + status = enc_phy_read(enc, PHY_REG_PHSTAT2); duplex = (status & ENC_PHSTAT2_DPXSTAT) ? 1 : 0; printf("%s: link up, 10Mbps %s-duplex\n", enc->dev->name, duplex ? "full" : "half"); @@ -678,8 +678,8 @@ static int enc_setup(enc_dev_t *enc) enc->bank = 0xff; /* invalidate current bank in enc28j60 */ /* verify PHY identification */ - phid1 = phy_read(enc, PHY_REG_PHID1); - phid2 = phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK; + phid1 = enc_phy_read(enc, PHY_REG_PHID1); + phid2 = enc_phy_read(enc, PHY_REG_PHID2) & ENC_PHID2_MASK; if (phid1 != ENC_PHID1_VALUE || phid2 != ENC_PHID2_VALUE) { printf("%s: failed to identify PHY. Found %04x:%04x\n", enc->dev->name, phid1, phid2); @@ -694,7 +694,7 @@ static int enc_setup(enc_dev_t *enc) * Prevent automatic loopback of data beeing transmitted by setting * ENC_PHCON2_HDLDIS */ - phy_write(enc, PHY_REG_PHCON2, (1<<8)); + enc_phy_write(enc, PHY_REG_PHCON2, (1<<8)); /* * LEDs configuration @@ -702,10 +702,10 @@ static int enc_setup(enc_dev_t *enc) * LEDB: LBCFG = 0111 -> display TX & RX activity * STRCH = 1 -> LED pulses */ - phy_write(enc, PHY_REG_PHLCON, 0x0472); + enc_phy_write(enc, PHY_REG_PHLCON, 0x0472); /* Reset PDPXMD-bit => half duplex */ - phy_write(enc, PHY_REG_PHCON1, 0); + enc_phy_write(enc, PHY_REG_PHCON1, 0); #ifdef CONFIG_USE_IRQ /* enable interrupts */ @@ -771,7 +771,7 @@ int enc_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) enc_release_bus(enc); return -1; } - *value = phy_read(enc, reg); + *value = enc_phy_read(enc, reg); enc_release_bus(enc); return 0; } @@ -796,7 +796,7 @@ int enc_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) enc_release_bus(enc); return -1; } - phy_write(enc, reg, value); + enc_phy_write(enc, reg, value); enc_release_bus(enc); return 0; } diff --git a/drivers/net/fsl_mdio.c b/drivers/net/fsl_mdio.c new file mode 100644 index 0000000..1aab307 --- /dev/null +++ b/drivers/net/fsl_mdio.c @@ -0,0 +1,120 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * Jun-jie Zhang <b18070@freescale.com> + * Mingkai Hu <Mingkai.hu@freescale.com> + * + * 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 + */ +#include <common.h> +#include <miiphy.h> +#include <phy.h> +#include <fsl_mdio.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/fsl_enet.h> + +void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int regnum, int value) +{ + int timeout = 1000000; + + out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); + out_be32(&phyregs->miimcon, value); + asm("sync"); + + while ((in_be32(&phyregs->miimind) & MIIMIND_BUSY) && timeout--) + ; +} + +int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int regnum) +{ + int value; + int timeout = 1000000; + + /* Put the address of the phy, and the register + * number into MIIMADD */ + out_be32(&phyregs->miimadd, (port_addr << 8) | (regnum & 0x1f)); + + /* Clear the command register, and wait */ + out_be32(&phyregs->miimcom, 0); + asm("sync"); + + /* Initiate a read command, and wait */ + out_be32(&phyregs->miimcom, MIIMCOM_READ_CYCLE); + asm("sync"); + + /* Wait for the the indication that the read is done */ + while ((in_be32(&phyregs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY)) + && timeout--) + ; + + /* Grab the value read from the PHY */ + value = in_be32(&phyregs->miimstat); + + return value; +} + +static int fsl_pq_mdio_reset(struct mii_dev *bus) +{ + struct tsec_mii_mng *regs = bus->priv; + + /* Reset MII (due to new addresses) */ + out_be32(®s->miimcfg, MIIMCFG_RESET_MGMT); + + out_be32(®s->miimcfg, MIIMCFG_INIT_VALUE); + + while (in_be32(®s->miimind) & MIIMIND_BUSY) + ; + + return 0; +} + +int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum) +{ + struct tsec_mii_mng *phyregs = bus->priv; + + return tsec_local_mdio_read(phyregs, addr, dev_addr, regnum); +} + +int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, + u16 value) +{ + struct tsec_mii_mng *phyregs = bus->priv; + + tsec_local_mdio_write(phyregs, addr, dev_addr, regnum, value); + + return 0; +} + +int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info) +{ + struct mii_dev *bus = mdio_alloc(); + + if (!bus) { + printf("Failed to allocate FSL MDIO bus\n"); + return -1; + } + + bus->read = tsec_phy_read; + bus->write = tsec_phy_write; + bus->reset = fsl_pq_mdio_reset; + sprintf(bus->name, info->name); + + bus->priv = info->regs; + + return mdio_register(bus); +} diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index bba8901..a59834b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -28,6 +28,19 @@ LIB := $(obj)libphy.o COBJS-$(CONFIG_BITBANGMII) += miiphybb.o COBJS-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o +COBJS-$(CONFIG_PHYLIB) += phy.o +COBJS-$(CONFIG_PHYLIB_10G) += generic_10g.o +COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o +COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o +COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o +COBJS-$(CONFIG_PHY_LXT) += lxt.o +COBJS-$(CONFIG_PHY_MARVELL) += marvell.o +COBJS-$(CONFIG_PHY_MICREL) += micrel.o +COBJS-$(CONFIG_PHY_NATSEMI) += natsemi.o +COBJS-$(CONFIG_PHY_REALTEK) += realtek.o +COBJS-$(CONFIG_PHY_TERANETICS) += teranetics.o +COBJS-$(CONFIG_PHY_VITESSE) += vitesse.o + COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c new file mode 100644 index 0000000..798473d --- /dev/null +++ b/drivers/net/phy/atheros.c @@ -0,0 +1,48 @@ +/* + * Atheros 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 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +static int ar8021_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x3D47); + + return 0; +} + +struct phy_driver AR8021_driver = { + .name = "AR8021", + .uid = 0x4dd040, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = ar8021_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +int phy_atheros_init(void) +{ + phy_register(&AR8021_driver); + + return 0; +} diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c new file mode 100644 index 0000000..427ac60 --- /dev/null +++ b/drivers/net/phy/broadcom.c @@ -0,0 +1,288 @@ +/* + * Broadcom 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +/* Broadcom BCM54xx -- taken from linux sungem_phy */ +#define MIIM_BCM54xx_AUXCNTL 0x18 +#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) (((val & 0x7) << 12)|(val & 0x7)) +#define MIIM_BCM54xx_AUXSTATUS 0x19 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 +#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 + +#define MIIM_BCM54XX_SHD 0x1c +#define MIIM_BCM54XX_SHD_WRITE 0x8000 +#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) +#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) +#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \ + (MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \ + MIIM_BCM54XX_SHD_DATA(data)) + +#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ +#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ +#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ +#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ + +/* Broadcom BCM5461S */ +static int bcm5461_config(struct phy_device *phydev) +{ + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int bcm54xx_parse_status(struct phy_device *phydev) +{ + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXSTATUS); + + switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> + MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) { + case 1: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_10; + break; + case 2: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_10; + break; + case 3: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_100; + break; + case 5: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_100; + break; + case 6: + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_1000; + break; + case 7: + phydev->duplex = DUPLEX_FULL; + phydev->speed = SPEED_1000; + break; + default: + printf("Auto-neg error, defaulting to 10BT/HD\n"); + phydev->duplex = DUPLEX_HALF; + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int bcm54xx_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + bcm54xx_parse_status(phydev); + + return 0; +} + +/* Broadcom BCM5482S */ +/* + * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain + * circumstances. eg a gigabit TSEC connected to a gigabit switch with + * a 4-wire ethernet cable. Both ends advertise gigabit, but can't + * link. "Ethernet@Wirespeed" reduces advertised speed until link + * can be achieved. + */ +static u32 bcm5482_read_wirespeed(struct phy_device *phydev, u32 reg) +{ + return (phy_read(phydev, MDIO_DEVAD_NONE, reg) & 0x8FFF) | 0x8010; +} + +static int bcm5482_config(struct phy_device *phydev) +{ + unsigned int reg; + + /* reset the PHY */ + reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + reg |= BMCR_RESET; + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, reg); + + /* Setup read from auxilary control shadow register 7 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, + MIIM_BCM54xx_AUXCNTL_ENCODE(7)); + /* Read Misc Control register and or in Ethernet@Wirespeed */ + reg = bcm5482_read_wirespeed(phydev, MIIM_BCM54xx_AUXCNTL); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54xx_AUXCNTL, reg); + + /* Initial config/enable of secondary SerDes interface */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf)); + /* Write intial value to secondary SerDes Contol */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_SSD | 0); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA, + BMCR_ANRESTART); + /* Enable copper/fiber auto-detect */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_SHD, + MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)); + + genphy_config_aneg(phydev); + + return 0; +} + +/* + * Find out if PHY is in copper or serdes mode by looking at Expansion Reg + * 0x42 - "Operating Mode Status Register" + */ +static int bcm5482_is_serdes(struct phy_device *phydev) +{ + u16 val; + int serdes = 0; + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + + switch (val & 0x1f) { + case 0x0d: /* RGMII-to-100Base-FX */ + case 0x0e: /* RGMII-to-SGMII */ + case 0x0f: /* RGMII-to-SerDes */ + case 0x12: /* SGMII-to-SerDes */ + case 0x13: /* SGMII-to-100Base-FX */ + case 0x16: /* SerDes-to-Serdes */ + serdes = 1; + break; + case 0x6: /* RGMII-to-Copper */ + case 0x14: /* SGMII-to-Copper */ + case 0x17: /* SerDes-to-Copper */ + break; + default: + printf("ERROR, invalid PHY mode (0x%x\n)", val); + break; + } + + return serdes; +} + +/* + * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating + * Mode Status Register" + */ +static u32 bcm5482_parse_serdes_sr(struct phy_device *phydev) +{ + u16 val; + int i = 0; + + /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ + while (1) { + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_SEL, + MIIM_BCM54XX_EXP_SEL_ER | 0x42); + val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_BCM54XX_EXP_DATA); + + if (val & 0x8000) + break; + + if (i++ > 1000) { + phydev->link = 0; + return 1; + } + + udelay(1000); /* 1 ms */ + } + + phydev->link = 1; + switch ((val >> 13) & 0x3) { + case (0x00): + phydev->speed = 10; + break; + case (0x01): + phydev->speed = 100; + break; + case (0x02): + phydev->speed = 1000; + break; + } + + phydev->duplex = (val & 0x1000) == 0x1000; + + return 0; +} + +/* + * Figure out if BCM5482 is in serdes or copper mode and determine link + * configuration accordingly + */ +static int bcm5482_startup(struct phy_device *phydev) +{ + if (bcm5482_is_serdes(phydev)) { + bcm5482_parse_serdes_sr(phydev); + phydev->port = PORT_FIBRE; + } else { + /* Wait for auto-negotiation to complete or fail */ + genphy_update_link(phydev); + /* Parse BCM54xx copper aux status register */ + bcm54xx_parse_status(phydev); + } + + return 0; +} + +static struct phy_driver BCM5461S_driver = { + .name = "Broadcom BCM5461S", + .uid = 0x2060c0, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5461_config, + .startup = &bcm54xx_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5464S_driver = { + .name = "Broadcom BCM5464S", + .uid = 0x2060b0, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5461_config, + .startup = &bcm54xx_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver BCM5482S_driver = { + .name = "Broadcom BCM5482S", + .uid = 0x143bcb0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &bcm5482_config, + .startup = &bcm5482_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_broadcom_init(void) +{ + phy_register(&BCM5482S_driver); + phy_register(&BCM5464S_driver); + phy_register(&BCM5461S_driver); + + return 0; +} diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c new file mode 100644 index 0000000..e96a4af --- /dev/null +++ b/drivers/net/phy/davicom.c @@ -0,0 +1,98 @@ +/* + * Davicom 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +#define MIIM_DM9161_SCR 0x10 +#define MIIM_DM9161_SCR_INIT 0x0610 + +/* DM9161 Specified Configuration and Status Register */ +#define MIIM_DM9161_SCSR 0x11 +#define MIIM_DM9161_SCSR_100F 0x8000 +#define MIIM_DM9161_SCSR_100H 0x4000 +#define MIIM_DM9161_SCSR_10F 0x2000 +#define MIIM_DM9161_SCSR_10H 0x1000 + +/* DM9161 10BT Configuration/Status */ +#define MIIM_DM9161_10BTCSR 0x12 +#define MIIM_DM9161_10BTCSR_INIT 0x7800 + + +/* Davicom DM9161E */ +static int dm9161_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_ISOLATE); + /* Do not bypass the scrambler/descrambler */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCR, + MIIM_DM9161_SCR_INIT); + /* Clear 10BTCSR to default */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_10BTCSR, + MIIM_DM9161_10BTCSR_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int dm9161_parse_status(struct phy_device *phydev) +{ + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DM9161_SCSR); + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) + phydev->speed = SPEED_100; + else + phydev->speed = SPEED_10; + + if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + return 0; +} + +static int dm9161_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + dm9161_parse_status(phydev); + + return 0; +} + +static struct phy_driver DM9161_driver = { + .name = "Davicom DM9161E", + .uid = 0x181b880, + .mask = 0xffffff0, + .features = PHY_BASIC_FEATURES, + .config = &dm9161_config, + .startup = &dm9161_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_davicom_init(void) +{ + phy_register(&DM9161_driver); + + return 0; +} diff --git a/drivers/net/phy/generic_10g.c b/drivers/net/phy/generic_10g.c new file mode 100644 index 0000000..315c508 --- /dev/null +++ b/drivers/net/phy/generic_10g.c @@ -0,0 +1,105 @@ +/* + * Generic PHY Management code + * + * 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 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + * Based loosely off of Linux's PHY Lib + */ + +#include <config.h> +#include <common.h> +#include <miiphy.h> +#include <phy.h> + +int gen10g_shutdown(struct phy_device *phydev) +{ + return 0; +} + +int gen10g_startup(struct phy_device *phydev) +{ + int devad, reg; + u32 mmd_mask = phydev->mmds; + + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { + if (!mmd_mask & 1) + continue; + + /* Read twice because link state is latched and a + * read moves the current state into the register */ + phy_read(phydev, devad, MDIO_STAT1); + reg = phy_read(phydev, devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} + +int gen10g_discover_mmds(struct phy_device *phydev) +{ + int mmd, stat2, devs1, devs2; + + /* Assume PHY must have at least one of PMA/PMD, WIS, PCS, PHY + * XS or DTE XS; give up if none is present. */ + for (mmd = 1; mmd <= 5; mmd++) { + /* Is this MMD present? */ + stat2 = phy_read(phydev, mmd, MDIO_STAT2); + if (stat2 < 0 || + (stat2 & MDIO_STAT2_DEVPRST) != MDIO_STAT2_DEVPRST_VAL) + continue; + + /* It should tell us about all the other MMDs */ + devs1 = phy_read(phydev, mmd, MDIO_DEVS1); + devs2 = phy_read(phydev, mmd, MDIO_DEVS2); + if (devs1 < 0 || devs2 < 0) + continue; + + phydev->mmds = devs1 | (devs2 << 16); + return 0; + } + + return 0; +} + +int gen10g_config(struct phy_device *phydev) +{ + /* For now, assume 10000baseT. Fill in later */ + phydev->supported = phydev->advertising = SUPPORTED_10000baseT_Full; + + return gen10g_discover_mmds(phydev); +} + +struct phy_driver gen10g_driver = { + .uid = 0xffffffff, + .mask = 0xffffffff, + .name = "Generic 10G PHY", + .features = 0, + .config = gen10g_config, + .startup = gen10g_startup, + .shutdown = gen10g_shutdown, +}; + diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c new file mode 100644 index 0000000..d67bbdd --- /dev/null +++ b/drivers/net/phy/lxt.c @@ -0,0 +1,87 @@ +/* + * LXT 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +/* LXT971 Status 2 registers */ +#define MIIM_LXT971_SR2 0x11 /* Status Register 2 */ +#define MIIM_LXT971_SR2_SPEED_MASK 0x4200 +#define MIIM_LXT971_SR2_10HDX 0x0000 /* 10 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_10FDX 0x0200 /* 10 Mbit full duplex selected */ +#define MIIM_LXT971_SR2_100HDX 0x4000 /* 100 Mbit half duplex selected */ +#define MIIM_LXT971_SR2_100FDX 0x4200 /* 100 Mbit full duplex selected */ + + +/* LXT971 */ +static int lxt971_parse_status(struct phy_device *phydev) +{ + int mii_reg; + int speed; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_LXT971_SR2); + speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; + + switch (speed) { + case MIIM_LXT971_SR2_10HDX: + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + break; + case MIIM_LXT971_SR2_10FDX: + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_FULL; + break; + case MIIM_LXT971_SR2_100HDX: + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_HALF; + break; + default: + phydev->speed = SPEED_100; + phydev->duplex = DUPLEX_FULL; + } + + return 0; +} + +static int lxt971_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + lxt971_parse_status(phydev); + + return 0; +} + +static struct phy_driver LXT971_driver = { + .name = "LXT971", + .uid = 0x1378e0, + .mask = 0xfffff0, + .features = PHY_BASIC_FEATURES, + .config = &genphy_config_aneg, + .startup = &lxt971_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_lxt_init(void) +{ + phy_register(&LXT971_driver); + + return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c new file mode 100644 index 0000000..bd1cdc4 --- /dev/null +++ b/drivers/net/phy/marvell.c @@ -0,0 +1,367 @@ +/* + * Marvell 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* 88E1011 PHY Status Register */ +#define MIIM_88E1xxx_PHY_STATUS 0x11 +#define MIIM_88E1xxx_PHYSTAT_SPEED 0xc000 +#define MIIM_88E1xxx_PHYSTAT_GBIT 0x8000 +#define MIIM_88E1xxx_PHYSTAT_100 0x4000 +#define MIIM_88E1xxx_PHYSTAT_DUPLEX 0x2000 +#define MIIM_88E1xxx_PHYSTAT_SPDDONE 0x0800 +#define MIIM_88E1xxx_PHYSTAT_LINK 0x0400 + +#define MIIM_88E1xxx_PHY_SCR 0x10 +#define MIIM_88E1xxx_PHY_MDI_X_AUTO 0x0060 + +/* 88E1111 PHY LED Control Register */ +#define MIIM_88E1111_PHY_LED_CONTROL 24 +#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 +#define MIIM_88E1111_PHY_LED_COMBINE 0x411C + +/* 88E1118 PHY defines */ +#define MIIM_88E1118_PHY_PAGE 22 +#define MIIM_88E1118_PHY_LED_PAGE 3 + +/* 88E1121 PHY LED Control Register */ +#define MIIM_88E1121_PHY_LED_CTRL 16 +#define MIIM_88E1121_PHY_LED_PAGE 3 +#define MIIM_88E1121_PHY_LED_DEF 0x0030 + +/* 88E1121 PHY IRQ Enable/Status Register */ +#define MIIM_88E1121_PHY_IRQ_EN 18 +#define MIIM_88E1121_PHY_IRQ_STATUS 19 + +#define MIIM_88E1121_PHY_PAGE 22 + +/* 88E1145 Extended PHY Specific Control Register */ +#define MIIM_88E1145_PHY_EXT_CR 20 +#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 +#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 + +#define MIIM_88E1145_PHY_LED_CONTROL 24 +#define MIIM_88E1145_PHY_LED_DIRECT 0x4100 + +#define MIIM_88E1145_PHY_PAGE 29 +#define MIIM_88E1145_PHY_CAL_OV 30 + +#define MIIM_88E1149_PHY_PAGE 29 + +/* Marvell 88E1011S */ +static int m88e1011s_config(struct phy_device *phydev) +{ + /* Reset and configure the PHY */ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x1f); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x5); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +/* Parse the 88E1011's status register for speed and duplex + * information + */ +static uint m88e1xxx_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_STATUS); + + if ((mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) && + !(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + int i = 0; + + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_88E1xxx_PHYSTAT_SPDDONE)) { + /* Timeout reached ? */ + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + puts(" TIMEOUT !\n"); + phydev->link = 0; + break; + } + + if ((i++ % 1000) == 0) + putc('.'); + udelay(1000); + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_88E1xxx_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_88E1xxx_PHYSTAT_LINK) + phydev->link = 1; + else + phydev->link = 0; + } + + if (mii_reg & MIIM_88E1xxx_PHYSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_88E1xxx_PHYSTAT_SPEED; + + switch (speed) { + case MIIM_88E1xxx_PHYSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_88E1xxx_PHYSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int m88e1011s_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1111S */ +static int m88e1111s_config(struct phy_device *phydev) +{ + int reg; + + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) { + reg = phy_read(phydev, MDIO_DEVAD_NONE, 0x1b); + reg = (reg & 0xfff0) | 0xb; + phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, reg); + } else { + phy_write(phydev, MDIO_DEVAD_NONE, 0x1b, 0x1f); + } + + phy_write(phydev, MDIO_DEVAD_NONE, 0x14, 0x0cd2); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +/* Marvell 88E1118 */ +static int m88e1118_config(struct phy_device *phydev) +{ + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0002); + /* Delay RGMII TX and RX */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x15, 0x1070); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0003); + /* Adjust LED control */ + phy_write(phydev, MDIO_DEVAD_NONE, 0x10, 0x021e); + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int m88e1118_startup(struct phy_device *phydev) +{ + /* Change Page Number */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1118_PHY_PAGE, 0x0000); + + genphy_update_link(phydev); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1121R */ +static int m88e1121_config(struct phy_device *phydev) +{ + int pg; + + /* Configure the PHY */ + genphy_config_aneg(phydev); + + /* Switch the page to access the led register */ + pg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, + MIIM_88E1121_PHY_LED_PAGE); + /* Configure leds */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_LED_CTRL, + MIIM_88E1121_PHY_LED_DEF); + /* Restore the page pointer */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_PAGE, pg); + + /* Disable IRQs and de-assert interrupt */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_EN, 0); + phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1121_PHY_IRQ_STATUS); + + return 0; +} + +/* Marvell 88E1145 */ +static int m88e1145_config(struct phy_device *phydev) +{ + int reg; + + /* Errata E0, E1 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x001b); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0x418f); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_PAGE, 0x0016); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_CAL_OV, 0xa2da); + + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1xxx_PHY_SCR, + MIIM_88E1xxx_PHY_MDI_X_AUTO); + + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR); + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + reg |= MIIM_M88E1145_RGMII_RX_DELAY | + MIIM_M88E1145_RGMII_TX_DELAY; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_EXT_CR, reg); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + +static int m88e1145_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1145_PHY_LED_CONTROL, + MIIM_88E1145_PHY_LED_DIRECT); + m88e1xxx_parse_status(phydev); + + return 0; +} + +/* Marvell 88E1149S */ +static int m88e1149_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x1f); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x200c); + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1149_PHY_PAGE, 0x5); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x0); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, 0x100); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + + +static struct phy_driver M88E1011S_driver = { + .name = "Marvell 88E1011S", + .uid = 0x1410c60, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1011s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1111S_driver = { + .name = "Marvell 88E1111S", + .uid = 0x1410cc0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1111s_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1118_driver = { + .name = "Marvell 88E1118", + .uid = 0x1410e10, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1118_config, + .startup = &m88e1118_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1121R_driver = { + .name = "Marvell 88E1121R", + .uid = 0x1410cb0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1121_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1145_driver = { + .name = "Marvell 88E1145", + .uid = 0x1410cd0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1145_config, + .startup = &m88e1145_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver M88E1149S_driver = { + .name = "Marvell 88E1149S", + .uid = 0x1410ca0, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1149_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_marvell_init(void) +{ + phy_register(&M88E1149S_driver); + phy_register(&M88E1145_driver); + phy_register(&M88E1121R_driver); + phy_register(&M88E1118_driver); + phy_register(&M88E1111S_driver); + phy_register(&M88E1011S_driver); + + return 0; +} diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c new file mode 100644 index 0000000..47064a1 --- /dev/null +++ b/drivers/net/phy/micrel.c @@ -0,0 +1,40 @@ +/* + * Micrel 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +static struct phy_driver KSZ804_driver = { + .name = "Micrel KSZ804", + .uid = 0x221510, + .mask = 0xfffff0, + .features = PHY_BASIC_FEATURES, + .config = &genphy_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_micrel_init(void) +{ + phy_register(&KSZ804_driver); + + return 0; +} diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c new file mode 100644 index 0000000..ea60ac1 --- /dev/null +++ b/drivers/net/phy/natsemi.c @@ -0,0 +1,96 @@ +/* + * National Semiconductor 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <phy.h> + +/* DP83865 Link and Auto-Neg Status Register */ +#define MIIM_DP83865_LANR 0x11 +#define MIIM_DP83865_SPD_MASK 0x0018 +#define MIIM_DP83865_SPD_1000 0x0010 +#define MIIM_DP83865_SPD_100 0x0008 +#define MIIM_DP83865_DPX_FULL 0x0002 + + +/* NatSemi DP83865 */ +static int dp83865_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + genphy_config_aneg(phydev); + + return 0; +} + +static int dp83865_parse_status(struct phy_device *phydev) +{ + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_DP83865_LANR); + + switch (mii_reg & MIIM_DP83865_SPD_MASK) { + + case MIIM_DP83865_SPD_1000: + phydev->speed = SPEED_1000; + break; + + case MIIM_DP83865_SPD_100: + phydev->speed = SPEED_100; + break; + + default: + phydev->speed = SPEED_10; + break; + + } + + if (mii_reg & MIIM_DP83865_DPX_FULL) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + return 0; +} + +static int dp83865_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + dp83865_parse_status(phydev); + + return 0; +} + + +static struct phy_driver DP83865_driver = { + .name = "NatSemi DP83865", + .uid = 0x20005c70, + .mask = 0xfffffff0, + .features = PHY_GBIT_FEATURES, + .config = &dp83865_config, + .startup = &dp83865_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_natsemi_init(void) +{ + phy_register(&DP83865_driver); + + return 0; +} diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c new file mode 100644 index 0000000..c7edcc0 --- /dev/null +++ b/drivers/net/phy/phy.c @@ -0,0 +1,755 @@ +/* + * Generic PHY Management code + * + * 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 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + * Based loosely off of Linux's PHY Lib + */ + +#include <config.h> +#include <common.h> +#include <malloc.h> +#include <net.h> +#include <command.h> +#include <miiphy.h> +#include <phy.h> +#include <errno.h> + +/* Generic PHY support and helper functions */ + +/** + * genphy_config_advert - sanitize and advertise auto-negotation parameters + * @phydev: target phy_device struct + * + * Description: Writes MII_ADVERTISE with the appropriate values, + * after sanitizing the values to make sure we only advertise + * what is supported. Returns < 0 on error, 0 if the PHY's advertisement + * hasn't changed, and > 0 if it has changed. + */ +int genphy_config_advert(struct phy_device *phydev) +{ + u32 advertise; + int oldadv, adv; + int err, changed = 0; + + /* Only allow advertising what + * this PHY supports */ + phydev->advertising &= phydev->supported; + advertise = phydev->advertising; + + /* Setup standard advertisement */ + oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4 | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + if (advertise & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (advertise & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (advertise & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (advertise & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + if (advertise & ADVERTISED_Pause) + adv |= ADVERTISE_PAUSE_CAP; + if (advertise & ADVERTISED_Asym_Pause) + adv |= ADVERTISE_PAUSE_ASYM; + + if (adv != oldadv) { + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); + + if (err < 0) + return err; + changed = 1; + } + + /* Configure gigabit if it's supported */ + if (phydev->supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) { + oldadv = adv = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000); + + if (adv < 0) + return adv; + + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (advertise & SUPPORTED_1000baseT_Half) + adv |= ADVERTISE_1000HALF; + if (advertise & SUPPORTED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + + if (adv != oldadv) { + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, + adv); + + if (err < 0) + return err; + changed = 1; + } + } + + return changed; +} + + +/** + * genphy_setup_forced - configures/forces speed/duplex from @phydev + * @phydev: target phy_device struct + * + * Description: Configures MII_BMCR to force speed/duplex + * to the values in phydev. Assumes that the values are valid. + */ +int genphy_setup_forced(struct phy_device *phydev) +{ + int err; + int ctl = 0; + + phydev->pause = phydev->asym_pause = 0; + + if (SPEED_1000 == phydev->speed) + ctl |= BMCR_SPEED1000; + else if (SPEED_100 == phydev->speed) + ctl |= BMCR_SPEED100; + + if (DUPLEX_FULL == phydev->duplex) + ctl |= BMCR_FULLDPLX; + + err = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); + + return err; +} + + +/** + * genphy_restart_aneg - Enable and Restart Autonegotiation + * @phydev: target phy_device struct + */ +int genphy_restart_aneg(struct phy_device *phydev) +{ + int ctl; + + ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + if (ctl < 0) + return ctl; + + ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); + + /* Don't isolate the PHY if we're negotiating */ + ctl &= ~(BMCR_ISOLATE); + + ctl = phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, ctl); + + return ctl; +} + + +/** + * genphy_config_aneg - restart auto-negotiation or write BMCR + * @phydev: target phy_device struct + * + * Description: If auto-negotiation is enabled, we configure the + * advertising, and then restart auto-negotiation. If it is not + * enabled, then we write the BMCR. + */ +int genphy_config_aneg(struct phy_device *phydev) +{ + int result; + + if (AUTONEG_ENABLE != phydev->autoneg) + return genphy_setup_forced(phydev); + + result = genphy_config_advert(phydev); + + if (result < 0) /* error */ + return result; + + if (result == 0) { + /* Advertisment hasn't changed, but maybe aneg was never on to + * begin with? Or maybe phy was isolated? */ + int ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + if (ctl < 0) + return ctl; + + if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE)) + result = 1; /* do restart aneg */ + } + + /* Only restart aneg if we are advertising something different + * than we were before. */ + if (result > 0) + result = genphy_restart_aneg(phydev); + + return result; +} + +/** + * genphy_update_link - update link status in @phydev + * @phydev: target phy_device struct + * + * Description: Update the value in phydev->link to reflect the + * current link value. In order to do this, we need to read + * the status register twice, keeping the second value. + */ +int genphy_update_link(struct phy_device *phydev) +{ + unsigned int mii_reg; + + /* + * Wait if the link is up, and autonegotiation is in progress + * (ie - we're capable and it's not done) + */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + /* + * If we already saw the link up, and it hasn't gone down, then + * we don't need to wait for autoneg again + */ + if (phydev->link && mii_reg & BMSR_LSTATUS) + return 0; + + if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { + int i = 0; + + printf("%s Waiting for PHY auto negotiation to complete", + phydev->dev->name); + while (!(mii_reg & BMSR_ANEGCOMPLETE)) { + /* + * Timeout reached ? + */ + if (i > PHY_ANEG_TIMEOUT) { + printf(" TIMEOUT !\n"); + phydev->link = 0; + return 0; + } + + if (ctrlc()) { + puts("user interrupt!\n"); + phydev->link = 0; + return -EINTR; + } + + if ((i++ % 500) == 0) + printf("."); + + udelay(1000); /* 1 ms */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + } + printf(" done\n"); + phydev->link = 1; + } else { + /* Read the link a second time to clear the latched state */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + if (mii_reg & BMSR_LSTATUS) + phydev->link = 1; + else + phydev->link = 0; + } + + return 0; +} + +/* + * Generic function which updates the speed and duplex. If + * autonegotiation is enabled, it uses the AND of the link + * partner's advertised capabilities and our advertised + * capabilities. If autonegotiation is disabled, we use the + * appropriate bits in the control register. + * + * Stolen from Linux's mii.c and phy_device.c + */ +static int genphy_parse_link(struct phy_device *phydev) +{ + int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + /* We're using autonegotiation */ + if (mii_reg & BMSR_ANEGCAPABLE) { + u32 lpa = 0; + u32 gblpa = 0; + + /* Check for gigabit capability */ + if (mii_reg & BMSR_ERCAP) { + /* We want a list of states supported by + * both PHYs in the link + */ + gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000); + gblpa &= phy_read(phydev, + MDIO_DEVAD_NONE, MII_CTRL1000) << 2; + } + + /* Set the baseline so we only have to set them + * if they're different + */ + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + /* Check the gigabit fields */ + if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { + phydev->speed = SPEED_1000; + + if (gblpa & PHY_1000BTSR_1000FD) + phydev->duplex = DUPLEX_FULL; + + /* We're done! */ + return 0; + } + + lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE); + lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA); + + if (lpa & (LPA_100FULL | LPA_100HALF)) { + phydev->speed = SPEED_100; + + if (lpa & LPA_100FULL) + phydev->duplex = DUPLEX_FULL; + + } else if (lpa & LPA_10FULL) + phydev->duplex = DUPLEX_FULL; + } else { + u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); + + phydev->speed = SPEED_10; + phydev->duplex = DUPLEX_HALF; + + if (bmcr & BMCR_FULLDPLX) + phydev->duplex = DUPLEX_FULL; + + if (bmcr & BMCR_SPEED1000) + phydev->speed = SPEED_1000; + else if (bmcr & BMCR_SPEED100) + phydev->speed = SPEED_100; + } + + return 0; +} + +int genphy_config(struct phy_device *phydev) +{ + int val; + u32 features; + + /* For now, I'll claim that the generic driver supports + * all possible port types */ + features = (SUPPORTED_TP | SUPPORTED_MII + | SUPPORTED_AUI | SUPPORTED_FIBRE | + SUPPORTED_BNC); + + /* Do we support autonegotiation? */ + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); + + if (val < 0) + return val; + + if (val & BMSR_ANEGCAPABLE) + features |= SUPPORTED_Autoneg; + + if (val & BMSR_100FULL) + features |= SUPPORTED_100baseT_Full; + if (val & BMSR_100HALF) + features |= SUPPORTED_100baseT_Half; + if (val & BMSR_10FULL) + features |= SUPPORTED_10baseT_Full; + if (val & BMSR_10HALF) + features |= SUPPORTED_10baseT_Half; + + if (val & BMSR_ESTATEN) { + val = phy_read(phydev, MDIO_DEVAD_NONE, MII_ESTATUS); + + if (val < 0) + return val; + + if (val & ESTATUS_1000_TFULL) + features |= SUPPORTED_1000baseT_Full; + if (val & ESTATUS_1000_THALF) + features |= SUPPORTED_1000baseT_Half; + } + + phydev->supported = features; + phydev->advertising = features; + + genphy_config_aneg(phydev); + + return 0; +} + +int genphy_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + genphy_parse_link(phydev); + + return 0; +} + +int genphy_shutdown(struct phy_device *phydev) +{ + return 0; +} + +static struct phy_driver genphy_driver = { + .uid = 0xffffffff, + .mask = 0xffffffff, + .name = "Generic PHY", + .features = 0, + .config = genphy_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +static LIST_HEAD(phy_drivers); + +int phy_init(void) +{ +#ifdef CONFIG_PHY_ATHEROS + phy_atheros_init(); +#endif +#ifdef CONFIG_PHY_BROADCOM + phy_broadcom_init(); +#endif +#ifdef CONFIG_PHY_DAVICOM + phy_davicom_init(); +#endif +#ifdef CONFIG_PHY_LXT + phy_lxt_init(); +#endif +#ifdef CONFIG_PHY_MARVELL + phy_marvell_init(); +#endif +#ifdef CONFIG_PHY_MICREL + phy_micrel_init(); +#endif +#ifdef CONFIG_PHY_NATSEMI + phy_natsemi_init(); +#endif +#ifdef CONFIG_PHY_REALTEK + phy_realtek_init(); +#endif +#ifdef CONFIG_PHY_TERANETICS + phy_teranetics_init(); +#endif +#ifdef CONFIG_PHY_VITESSE + phy_vitesse_init(); +#endif + + return 0; +} + +int phy_register(struct phy_driver *drv) +{ + INIT_LIST_HEAD(&drv->list); + list_add_tail(&drv->list, &phy_drivers); + + return 0; +} + +int phy_probe(struct phy_device *phydev) +{ + int err = 0; + + phydev->advertising = phydev->supported = phydev->drv->features; + phydev->mmds = phydev->drv->mmds; + + if (phydev->drv->probe) + err = phydev->drv->probe(phydev); + + return err; +} + +static struct phy_driver *generic_for_interface(phy_interface_t interface) +{ +#ifdef CONFIG_PHYLIB_10G + if (is_10g_interface(interface)) + return &gen10g_driver; +#endif + + return &genphy_driver; +} + +struct phy_driver *get_phy_driver(struct phy_device *phydev, + phy_interface_t interface) +{ + struct list_head *entry; + int phy_id = phydev->phy_id; + struct phy_driver *drv = NULL; + + list_for_each(entry, &phy_drivers) { + drv = list_entry(entry, struct phy_driver, list); + if ((drv->uid & drv->mask) == (phy_id & drv->mask)) + return drv; + } + + /* If we made it here, there's no driver for this PHY */ + return generic_for_interface(interface); +} + +struct phy_device *phy_device_create(struct mii_dev *bus, int addr, int phy_id, + phy_interface_t interface) +{ + struct phy_device *dev; + + /* We allocate the device, and initialize the + * default values */ + dev = malloc(sizeof(*dev)); + if (!dev) { + printf("Failed to allocate PHY device for %s:%d\n", + bus->name, addr); + return NULL; + } + + memset(dev, 0, sizeof(*dev)); + + dev->duplex = -1; + dev->link = 1; + dev->interface = interface; + + dev->autoneg = AUTONEG_ENABLE; + + dev->addr = addr; + dev->phy_id = phy_id; + dev->bus = bus; + + dev->drv = get_phy_driver(dev, interface); + + phy_probe(dev); + + bus->phymap[addr] = dev; + + return dev; +} + +/** + * get_phy_id - reads the specified addr for its ID. + * @bus: the target MII bus + * @addr: PHY address on the MII bus + * @phy_id: where to store the ID retrieved. + * + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, stores it in @phy_id and returns zero on success. + */ +int get_phy_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id) +{ + int phy_reg; + + /* Grab the bits from PHYIR1, and put them + * in the upper half */ + phy_reg = bus->read(bus, addr, devad, MII_PHYSID1); + + if (phy_reg < 0) + return -EIO; + + *phy_id = (phy_reg & 0xffff) << 16; + + /* Grab the bits from PHYIR2, and put them in the lower half */ + phy_reg = bus->read(bus, addr, devad, MII_PHYSID2); + + if (phy_reg < 0) + return -EIO; + + *phy_id |= (phy_reg & 0xffff); + + return 0; +} + +/** + * get_phy_device - reads the specified PHY device and returns its @phy_device struct + * @bus: the target MII bus + * @addr: PHY address on the MII bus + * + * Description: Reads the ID registers of the PHY at @addr on the + * @bus, then allocates and returns the phy_device to represent it. + */ +struct phy_device *get_phy_device(struct mii_dev *bus, int addr, + phy_interface_t interface) +{ + u32 phy_id = 0x1fffffff; + int i; + int r; + + /* If we have one, return the existing device, with new interface */ + if (bus->phymap[addr]) { + bus->phymap[addr]->interface = interface; + + return bus->phymap[addr]; + } + + /* Try Standard (ie Clause 22) access */ + r = get_phy_id(bus, addr, MDIO_DEVAD_NONE, &phy_id); + if (r) + return NULL; + + /* If the PHY ID is mostly f's, we didn't find anything */ + if ((phy_id & 0x1fffffff) != 0x1fffffff) + return phy_device_create(bus, addr, phy_id, interface); + + /* Otherwise we have to try Clause 45 */ + for (i = 1; i < 5; i++) { + r = get_phy_id(bus, addr, i, &phy_id); + if (r) + return NULL; + + /* If the phy_id is mostly Fs, there is no device there */ + if ((phy_id & 0x1fffffff) != 0x1fffffff) + break; + } + + return phy_device_create(bus, addr, phy_id, interface); +} + +int phy_reset(struct phy_device *phydev) +{ + int reg; + int timeout = 500; + int devad = MDIO_DEVAD_NONE; + +#ifdef CONFIG_PHYLIB_10G + /* If it's 10G, we need to issue reset through one of the MMDs */ + if (is_10g_interface(phydev->interface)) { + if (!phydev->mmds) + gen10g_discover_mmds(phydev); + + devad = ffs(phydev->mmds) - 1; + } +#endif + + reg = phy_read(phydev, devad, MII_BMCR); + if (reg < 0) { + debug("PHY status read failed\n"); + return -1; + } + + reg |= BMCR_RESET; + + if (phy_write(phydev, devad, MII_BMCR, reg) < 0) { + debug("PHY reset failed\n"); + return -1; + } + +#ifdef CONFIG_PHY_RESET_DELAY + udelay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */ +#endif + /* + * Poll the control register for the reset bit to go to 0 (it is + * auto-clearing). This should happen within 0.5 seconds per the + * IEEE spec. + */ + while ((reg & BMCR_RESET) && timeout--) { + reg = phy_read(phydev, devad, MII_BMCR); + + if (reg < 0) { + debug("PHY status read failed\n"); + return -1; + } + udelay(1000); + } + + if (reg & BMCR_RESET) { + puts("PHY reset timed out\n"); + return -1; + } + + return 0; +} + +int miiphy_reset(const char *devname, unsigned char addr) +{ + struct mii_dev *bus = miiphy_get_dev_by_name(devname); + struct phy_device *phydev; + + /* + * miiphy_reset was only used on standard PHYs, so we'll fake it here. + * If later code tries to connect with the right interface, this will + * be corrected by get_phy_device in phy_connect() + */ + phydev = get_phy_device(bus, addr, PHY_INTERFACE_MODE_MII); + + return phy_reset(phydev); +} + +struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct eth_device *dev, + phy_interface_t interface) +{ + struct phy_device *phydev; + + /* Reset the bus */ + bus->reset(bus); + + /* Wait 15ms to make sure the PHY has come out of hard reset */ + udelay(15000); + + phydev = get_phy_device(bus, addr, interface); + + if (!phydev) { + printf("Could not get PHY for %s:%d\n", bus->name, addr); + + return NULL; + } + + /* Soft Reset the PHY */ + phy_reset(phydev); + + if (phydev->dev) + printf("%s:%d is connected to %s. Reconnecting to %s\n", + bus->name, addr, phydev->dev->name, dev->name); + + phydev->dev = dev; + + printf("%s connected to %s\n", dev->name, phydev->drv->name); + + return phydev; +} + +int phy_startup(struct phy_device *phydev) +{ + if (phydev->drv->startup) + phydev->drv->startup(phydev); + + return 0; +} + +static int __board_phy_config(struct phy_device *phydev) +{ + return 0; +} + +int board_phy_config(struct phy_device *phydev) + __attribute__((weak, alias("__board_phy_config"))); + +int phy_config(struct phy_device *phydev) +{ + if (phydev->drv->config) + phydev->drv->config(phydev); + + /* Invoke an optional board-specific helper */ + board_phy_config(phydev); + + return 0; +} + +int phy_shutdown(struct phy_device *phydev) +{ + if (phydev->drv->shutdown) + phydev->drv->shutdown(phydev); + + return 0; +} diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c new file mode 100644 index 0000000..b7e2753 --- /dev/null +++ b/drivers/net/phy/realtek.c @@ -0,0 +1,130 @@ +/* + * RealTek 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <common.h> +#include <phy.h> + +#define PHY_AUTONEGOTIATE_TIMEOUT 5000 + +/* RTL8211B PHY Status Register */ +#define MIIM_RTL8211B_PHY_STATUS 0x11 +#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000 +#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000 +#define MIIM_RTL8211B_PHYSTAT_100 0x4000 +#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000 +#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800 +#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400 + + +/* RealTek RTL8211B */ +static int rtl8211b_config(struct phy_device *phydev) +{ + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + + genphy_config_aneg(phydev); + + return 0; +} + +static int rtl8211b_parse_status(struct phy_device *phydev) +{ + unsigned int speed; + unsigned int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211B_PHY_STATUS); + + if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + int i = 0; + + /* in case of timeout ->link is cleared */ + phydev->link = 1; + puts("Waiting for PHY realtime link"); + while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { + /* Timeout reached ? */ + if (i > PHY_AUTONEGOTIATE_TIMEOUT) { + puts(" TIMEOUT !\n"); + phydev->link = 0; + break; + } + + if ((i++ % 1000) == 0) + putc('.'); + udelay(1000); /* 1 ms */ + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, + MIIM_RTL8211B_PHY_STATUS); + } + puts(" done\n"); + udelay(500000); /* another 500 ms (results in faster booting) */ + } else { + if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) + phydev->link = 1; + else + phydev->link = 0; + } + + if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); + + switch (speed) { + case MIIM_RTL8211B_PHYSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_RTL8211B_PHYSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + } + + return 0; +} + +static int rtl8211b_startup(struct phy_device *phydev) +{ + /* Read the Status (2x to make sure link is right) */ + genphy_update_link(phydev); + rtl8211b_parse_status(phydev); + + return 0; +} + +static struct phy_driver RTL8211B_driver = { + .name = "RealTek RTL8211B", + .uid = 0x1cc910, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = &rtl8211b_config, + .startup = &rtl8211b_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_realtek_init(void) +{ + phy_register(&RTL8211B_driver); + + return 0; +} diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c new file mode 100644 index 0000000..a771791 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,62 @@ +/* + * Teranetics 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <config.h> +#include <phy.h> + +#ifndef CONFIG_PHYLIB_10G +#error The Teranetics PHY needs 10G support +#endif + +int tn2020_config(struct phy_device *phydev) +{ + if (phydev->port == PORT_FIBRE) { + unsigned short restart_an = (MDIO_AN_CTRL1_RESTART | + MDIO_AN_CTRL1_ENABLE | + MDIO_AN_CTRL1_XNP); + + phy_write(phydev, 30, 93, 2); + phy_write(phydev, MDIO_MMD_AN, MDIO_CTRL1, restart_an); + } + + return 0; +} + +struct phy_driver tn2020_driver = { + .name = "Teranetics TN2020", + .uid = 0x00a19410, + .mask = 0xfffffff0, + .features = PHY_10G_FEATURES, + .mmds = (MDIO_DEVS_PMAPMD | MDIO_DEVS_PCS | + MDIO_DEVS_PHYXS | MDIO_DEVS_AN | + MDIO_DEVS_VEND1 | MDIO_DEVS_VEND2), + .config = &tn2020_config, + .startup = &gen10g_startup, + .shutdown = &gen10g_shutdown, +}; + +int phy_teranetics_init(void) +{ + phy_register(&tn2020_driver); + + return 0; +} diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c new file mode 100644 index 0000000..d48d4fe --- /dev/null +++ b/drivers/net/phy/vitesse.c @@ -0,0 +1,242 @@ +/* + * Vitesse 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 2010-2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#include <miiphy.h> + +/* Cicada Auxiliary Control/Status Register */ +#define MIIM_CIS82xx_AUX_CONSTAT 0x1c +#define MIIM_CIS82xx_AUXCONSTAT_INIT 0x0004 +#define MIIM_CIS82xx_AUXCONSTAT_DUPLEX 0x0020 +#define MIIM_CIS82xx_AUXCONSTAT_SPEED 0x0018 +#define MIIM_CIS82xx_AUXCONSTAT_GBIT 0x0010 +#define MIIM_CIS82xx_AUXCONSTAT_100 0x0008 + +/* Cicada Extended Control Register 1 */ +#define MIIM_CIS82xx_EXT_CON1 0x17 +#define MIIM_CIS8201_EXTCON1_INIT 0x0000 + +/* Cicada 8204 Extended PHY Control Register 1 */ +#define MIIM_CIS8204_EPHY_CON 0x17 +#define MIIM_CIS8204_EPHYCON_INIT 0x0006 +#define MIIM_CIS8204_EPHYCON_RGMII 0x1100 + +/* Cicada 8204 Serial LED Control Register */ +#define MIIM_CIS8204_SLED_CON 0x1b +#define MIIM_CIS8204_SLEDCON_INIT 0x1115 + +/* Vitesse VSC8601 Extended PHY Control Register 1 */ +#define MIIM_VSC8601_EPHY_CON 0x17 +#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 +#define MIIM_VSC8601_SKEW_CTRL 0x1c + +#define PHY_EXT_PAGE_ACCESS 0x1f + +/* CIS8201 */ +static int vitesse_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, + MIIM_CIS82xx_AUXCONSTAT_INIT); + /* Set up the interface mode */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_EXT_CON1, + MIIM_CIS8201_EXTCON1_INIT); + + genphy_config_aneg(phydev); + + return 0; +} + +static int vitesse_parse_status(struct phy_device *phydev) +{ + int speed; + int mii_reg; + + mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT); + + if (mii_reg & MIIM_CIS82xx_AUXCONSTAT_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + speed = mii_reg & MIIM_CIS82xx_AUXCONSTAT_SPEED; + switch (speed) { + case MIIM_CIS82xx_AUXCONSTAT_GBIT: + phydev->speed = SPEED_1000; + break; + case MIIM_CIS82xx_AUXCONSTAT_100: + phydev->speed = SPEED_100; + break; + default: + phydev->speed = SPEED_10; + break; + } + + return 0; +} + +static int vitesse_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + vitesse_parse_status(phydev); + + return 0; +} + +static int cis8204_config(struct phy_device *phydev) +{ + /* Override PHY config settings */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS82xx_AUX_CONSTAT, + MIIM_CIS82xx_AUXCONSTAT_INIT); + + genphy_config_aneg(phydev); + + if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) || + (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, + MIIM_CIS8204_EPHYCON_INIT | + MIIM_CIS8204_EPHYCON_RGMII); + else + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_CIS8204_EPHY_CON, + MIIM_CIS8204_EPHYCON_INIT); + + return 0; +} + +/* Vitesse VSC8601 */ +int vsc8601_config(struct phy_device *phydev) +{ + /* Configure some basic stuff */ +#ifdef CONFIG_SYS_VSC8601_SKEWFIX + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_EPHY_CON, + MIIM_VSC8601_EPHY_CON_INIT_SKEW); +#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 1); +#define VSC8101_SKEW \ + ((CONFIG_SYS_VSC8601_SKEW_TX << 14) \ + | (CONFIG_SYS_VSC8601_SKEW_RX << 12)) + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8601_SKEW_CTRL, + VSC8101_SKEW); + phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS, 0); +#endif +#endif + + genphy_config_aneg(phydev); + + return 0; +} + +static struct phy_driver VSC8211_driver = { + .name = "Vitesse VSC8211", + .uid = 0xfc4b0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vitesse_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8221_driver = { + .name = "Vitesse VSC8221", + .uid = 0xfc550, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8244_driver = { + .name = "Vitesse VSC8244", + .uid = 0xfc6c0, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8234_driver = { + .name = "Vitesse VSC8234", + .uid = 0xfc620, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8601_driver = { + .name = "Vitesse VSC8601", + .uid = 0x70420, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vsc8601_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver VSC8641_driver = { + .name = "Vitesse VSC8641", + .uid = 0x70430, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config_aneg, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +/* Vitesse bought Cicada, so we'll put these here */ +static struct phy_driver cis8201_driver = { + .name = "CIS8201", + .uid = 0xfc410, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &vitesse_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +static struct phy_driver cis8204_driver = { + .name = "Cicada Cis8204", + .uid = 0xfc440, + .mask = 0xffff0, + .features = PHY_GBIT_FEATURES, + .config = &cis8204_config, + .startup = &vitesse_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_vitesse_init(void) +{ + phy_register(&VSC8641_driver); + phy_register(&VSC8601_driver); + phy_register(&VSC8234_driver); + phy_register(&VSC8244_driver); + phy_register(&VSC8211_driver); + phy_register(&VSC8221_driver); + phy_register(&cis8201_driver); + phy_register(&cis8204_driver); + + return 0; +} diff --git a/drivers/net/tsec.c b/drivers/net/tsec.c index 9a91b9e..06e5834 100644 --- a/drivers/net/tsec.c +++ b/drivers/net/tsec.c @@ -5,7 +5,7 @@ * terms of the GNU Public License, Version 2, incorporated * herein by reference. * - * Copyright 2004-2010 Freescale Semiconductor, Inc. + * Copyright 2004-2011 Freescale Semiconductor, Inc. * (C) Copyright 2003, Motorola, Inc. * author Andy Fleming * @@ -17,10 +17,9 @@ #include <net.h> #include <command.h> #include <tsec.h> +#include <fsl_mdio.h> #include <asm/errno.h> -#include "miiphy.h" - DECLARE_GLOBAL_DATA_PTR; #define TX_BUF_CNT 2 @@ -44,31 +43,6 @@ static RTXBD rtx __attribute__ ((aligned(8))); #error "rtx must be 64-bit aligned" #endif -static int tsec_send(struct eth_device *dev, - volatile void *packet, int length); -static int tsec_recv(struct eth_device *dev); -static int tsec_init(struct eth_device *dev, bd_t * bd); -static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info); -static void tsec_halt(struct eth_device *dev); -static void init_registers(volatile tsec_t * regs); -static void startup_tsec(struct eth_device *dev); -static int init_phy(struct eth_device *dev); -void write_phy_reg(struct tsec_private *priv, uint regnum, uint value); -uint read_phy_reg(struct tsec_private *priv, uint regnum); -static struct phy_info *get_phy_info(struct eth_device *dev); -static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd); -static void adjust_link(struct eth_device *dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) -static int tsec_miiphy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value); -static int tsec_miiphy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value); -#endif -#ifdef CONFIG_MCAST_TFTP -static int tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set); -#endif - /* Default initializations for TSEC controllers. */ static struct tsec_info_struct tsec_info[] = { @@ -81,10 +55,10 @@ static struct tsec_info_struct tsec_info[] = { #ifdef CONFIG_MPC85XX_FEC { .regs = (tsec_t *)(TSEC_BASE_ADDR + 0x2000), - .miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR), .devname = CONFIG_MPC85XX_FEC_NAME, .phyaddr = FEC_PHY_ADDR, - .flags = FEC_FLAGS + .flags = FEC_FLAGS, + .mii_devname = DEFAULT_MII_NAME }, /* FEC */ #endif #ifdef CONFIG_TSEC3 @@ -95,195 +69,6 @@ static struct tsec_info_struct tsec_info[] = { #endif }; -/* - * Initialize all the TSEC devices - * - * Returns the number of TSEC devices that were initialized - */ -int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) -{ - int i; - int ret, count = 0; - - for (i = 0; i < num; i++) { - ret = tsec_initialize(bis, &tsecs[i]); - if (ret > 0) - count += ret; - } - - return count; -} - -int tsec_standard_init(bd_t *bis) -{ - return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); -} - -/* Initialize device structure. Returns success if PHY - * initialization succeeded (i.e. if it recognizes the PHY) - */ -static int tsec_initialize(bd_t * bis, struct tsec_info_struct *tsec_info) -{ - struct eth_device *dev; - int i; - struct tsec_private *priv; - - dev = (struct eth_device *)malloc(sizeof *dev); - - if (NULL == dev) - return 0; - - memset(dev, 0, sizeof *dev); - - priv = (struct tsec_private *)malloc(sizeof(*priv)); - - if (NULL == priv) - return 0; - - privlist[num_tsecs++] = priv; - priv->regs = tsec_info->regs; - priv->phyregs = tsec_info->miiregs; - priv->phyregs_sgmii = tsec_info->miiregs_sgmii; - - priv->phyaddr = tsec_info->phyaddr; - priv->flags = tsec_info->flags; - - sprintf(dev->name, tsec_info->devname); - dev->iobase = 0; - dev->priv = priv; - dev->init = tsec_init; - dev->halt = tsec_halt; - dev->send = tsec_send; - dev->recv = tsec_recv; -#ifdef CONFIG_MCAST_TFTP - dev->mcast = tsec_mcast_addr; -#endif - - /* Tell u-boot to get the addr from the env */ - for (i = 0; i < 6; i++) - dev->enetaddr[i] = 0; - - eth_register(dev); - - /* Reset the MAC */ - priv->regs->maccfg1 |= MACCFG1_SOFT_RESET; - udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ - priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET); - -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) - miiphy_register(dev->name, tsec_miiphy_read, tsec_miiphy_write); -#endif - - /* Try to initialize PHY here, and return */ - return init_phy(dev); -} - -/* Initializes data structures and registers for the controller, - * and brings the interface up. Returns the link status, meaning - * that it returns success if the link is up, failure otherwise. - * This allows u-boot to find the first active controller. - */ -static int tsec_init(struct eth_device *dev, bd_t * bd) -{ - uint tempval; - char tmpbuf[MAC_ADDR_LEN]; - int i; - struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; - - /* Make sure the controller is stopped */ - tsec_halt(dev); - - /* Init MACCFG2. Defaults to GMII */ - regs->maccfg2 = MACCFG2_INIT_SETTINGS; - - /* Init ECNTRL */ - regs->ecntrl = ECNTRL_INIT_SETTINGS; - - /* Copy the station address into the address registers. - * Backwards, because little endian MACS are dumb */ - for (i = 0; i < MAC_ADDR_LEN; i++) { - tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; - } - tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | - tmpbuf[3]; - - regs->macstnaddr1 = tempval; - - tempval = *((uint *) (tmpbuf + 4)); - - regs->macstnaddr2 = tempval; - - /* reset the indices to zero */ - rxIdx = 0; - txIdx = 0; - - /* Clear out (for the most part) the other registers */ - init_registers(regs); - - /* Ready the device for tx/rx */ - startup_tsec(dev); - - /* If there's no link, fail */ - return (priv->link ? 0 : -1); -} - -/* Writes the given phy's reg with value, using the specified MDIO regs */ -static void tsec_local_mdio_write(volatile tsec_mdio_t *phyregs, uint addr, - uint reg, uint value) -{ - int timeout = 1000000; - - phyregs->miimadd = (addr << 8) | reg; - phyregs->miimcon = value; - asm("sync"); - - timeout = 1000000; - while ((phyregs->miimind & MIIMIND_BUSY) && timeout--) ; -} - - -/* Provide the default behavior of writing the PHY of this ethernet device */ -#define write_phy_reg(priv, regnum, value) \ - tsec_local_mdio_write(priv->phyregs,priv->phyaddr,regnum,value) - -/* Reads register regnum on the device's PHY through the - * specified registers. It lowers and raises the read - * command, and waits for the data to become valid (miimind - * notvalid bit cleared), and the bus to cease activity (miimind - * busy bit cleared), and then returns the value - */ -static uint tsec_local_mdio_read(volatile tsec_mdio_t *phyregs, - uint phyid, uint regnum) -{ - uint value; - - /* Put the address of the phy, and the register - * number into MIIMADD */ - phyregs->miimadd = (phyid << 8) | regnum; - - /* Clear the command register, and wait */ - phyregs->miimcom = 0; - asm("sync"); - - /* Initiate a read command, and wait */ - phyregs->miimcom = MIIM_READ_COMMAND; - asm("sync"); - - /* Wait for the the indication that the read is done */ - while ((phyregs->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ; - - /* Grab the value read from the PHY */ - value = phyregs->miimstat; - - return value; -} - -/* #define to provide old read_phy_reg functionality without duplicating code */ -#define read_phy_reg(priv,regnum) \ - tsec_local_mdio_read(priv->phyregs,priv->phyaddr,regnum) - #define TBIANA_SETTINGS ( \ TBIANA_ASYMMETRIC_PAUSE \ | TBIANA_SYMMETRIC_PAUSE \ @@ -305,661 +90,150 @@ static void tsec_configure_serdes(struct tsec_private *priv) { /* Access TBI PHY registers at given TSEC register offset as opposed * to the register offset used for external PHY accesses */ - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_ANA, - TBIANA_SETTINGS); - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_TBICON, - TBICON_CLK_SELECT); - tsec_local_mdio_write(priv->phyregs_sgmii, priv->regs->tbipa, TBI_CR, - CONFIG_TSEC_TBICR_SETTINGS); -} - -/* Discover which PHY is attached to the device, and configure it - * properly. If the PHY is not recognized, then return 0 - * (failure). Otherwise, return 1 - */ -static int init_phy(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - struct phy_info *curphy; - volatile tsec_t *regs = priv->regs; - - /* Assign a Physical address to the TBI */ - regs->tbipa = CONFIG_SYS_TBIPA_VALUE; - asm("sync"); - - /* Reset MII (due to new addresses) */ - priv->phyregs->miimcfg = MIIMCFG_RESET; - asm("sync"); - priv->phyregs->miimcfg = MIIMCFG_INIT_VALUE; - asm("sync"); - while (priv->phyregs->miimind & MIIMIND_BUSY) ; - - /* Get the cmd structure corresponding to the attached - * PHY */ - curphy = get_phy_info(dev); - - if (curphy == NULL) { - priv->phyinfo = NULL; - printf("%s: No PHY found\n", dev->name); - - return 0; - } - - if (regs->ecntrl & ECNTRL_SGMII_MODE) - tsec_configure_serdes(priv); - - priv->phyinfo = curphy; - - phy_run_commands(priv, priv->phyinfo->config); - - return 1; -} - -/* - * Returns which value to write to the control register. - * For 10/100, the value is slightly different - */ -static uint mii_cr_init(uint mii_reg, struct tsec_private * priv) -{ - if (priv->flags & TSEC_GIGABIT) - return MIIM_CONTROL_INIT; - else - return MIIM_CR_INIT; + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_ANA, TBIANA_SETTINGS); + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_TBICON, TBICON_CLK_SELECT); + tsec_local_mdio_write(priv->phyregs_sgmii, in_be32(&priv->regs->tbipa), + 0, TBI_CR, CONFIG_TSEC_TBICR_SETTINGS); } -/* - * Wait for auto-negotiation to complete, then determine link - */ -static uint mii_parse_sr(uint mii_reg, struct tsec_private * priv) -{ - /* - * Wait if the link is up, and autonegotiation is in progress - * (ie - we're capable and it's not done) - */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) { - int i = 0; - - puts("Waiting for PHY auto negotiation to complete"); - while (!(mii_reg & BMSR_ANEGCOMPLETE)) { - /* - * Timeout reached ? - */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - return 0; - } - - if (ctrlc()) { - puts("user interrupt!\n"); - priv->link = 0; - return -EINTR; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - } - puts(" done\n"); - - /* Link status bit is latched low, read it again */ - mii_reg = read_phy_reg(priv, MIIM_STATUS); - - udelay(500000); /* another 500 ms (results in faster booting) */ - } +#ifdef CONFIG_MCAST_TFTP - priv->link = mii_reg & MIIM_STATUS_LINK ? 1 : 0; +/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ - return 0; -} +/* Set the appropriate hash bit for the given addr */ -/* Generic function which updates the speed and duplex. If - * autonegotiation is enabled, it uses the AND of the link - * partner's advertised capabilities and our advertised - * capabilities. If autonegotiation is disabled, we use the - * appropriate bits in the control register. - * - * Stolen from Linux's mii.c and phy_device.c - */ -static uint mii_parse_link(uint mii_reg, struct tsec_private *priv) +/* The algorithm works like so: + * 1) Take the Destination Address (ie the multicast address), and + * do a CRC on it (little endian), and reverse the bits of the + * result. + * 2) Use the 8 most significant bits as a hash into a 256-entry + * table. The table is controlled through 8 32-bit registers: + * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is + * gaddr7. This means that the 3 most significant bits in the + * hash index which gaddr register to use, and the 5 other bits + * indicate which bit (assuming an IBM numbering scheme, which + * for PowerPC (tm) is usually the case) in the tregister holds + * the entry. */ +static int +tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) { - /* We're using autonegotiation */ - if (mii_reg & BMSR_ANEGCAPABLE) { - uint lpa = 0; - uint gblpa = 0; - - /* Check for gigabit capability */ - if (mii_reg & BMSR_ERCAP) { - /* We want a list of states supported by - * both PHYs in the link - */ - gblpa = read_phy_reg(priv, MII_STAT1000); - gblpa &= read_phy_reg(priv, MII_CTRL1000) << 2; - } - - /* Set the baseline so we only have to set them - * if they're different - */ - priv->speed = 10; - priv->duplexity = 0; - - /* Check the gigabit fields */ - if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) { - priv->speed = 1000; - - if (gblpa & PHY_1000BTSR_1000FD) - priv->duplexity = 1; - - /* We're done! */ - return 0; - } - - lpa = read_phy_reg(priv, MII_ADVERTISE); - lpa &= read_phy_reg(priv, MII_LPA); + struct tsec_private *priv = privlist[1]; + volatile tsec_t *regs = priv->regs; + volatile u32 *reg_array, value; + u8 result, whichbit, whichreg; - if (lpa & (LPA_100FULL | LPA_100HALF)) { - priv->speed = 100; + result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); + whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ + whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ + value = (1 << (31-whichbit)); - if (lpa & LPA_100FULL) - priv->duplexity = 1; + reg_array = &(regs->hash.gaddr0); - } else if (lpa & LPA_10FULL) - priv->duplexity = 1; + if (set) { + reg_array[whichreg] |= value; } else { - uint bmcr = read_phy_reg(priv, MII_BMCR); - - priv->speed = 10; - priv->duplexity = 0; - - if (bmcr & BMCR_FULLDPLX) - priv->duplexity = 1; - - if (bmcr & BMCR_SPEED1000) - priv->speed = 1000; - else if (bmcr & BMCR_SPEED100) - priv->speed = 100; - } - - return 0; -} - -/* - * "Ethernet@Wirespeed" needs to be enabled to achieve link in certain - * circumstances. eg a gigabit TSEC connected to a gigabit switch with - * a 4-wire ethernet cable. Both ends advertise gigabit, but can't - * link. "Ethernet@Wirespeed" reduces advertised speed until link - * can be achieved. - */ -static uint mii_BCM54xx_wirespeed(uint mii_reg, struct tsec_private *priv) -{ - return (read_phy_reg(priv, mii_reg) & 0x8FFF) | 0x8010; -} - -/* - * Parse the BCM54xx status register for speed and duplex information. - * The linux sungem_phy has this information, but in a table format. - */ -static uint mii_parse_BCM54xx_sr(uint mii_reg, struct tsec_private *priv) -{ - /* If there is no link, speed and duplex don't matter */ - if (!priv->link) - return 0; - - switch ((mii_reg & MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK) >> - MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT) { - case 1: - priv->duplexity = 0; - priv->speed = 10; - break; - case 2: - priv->duplexity = 1; - priv->speed = 10; - break; - case 3: - priv->duplexity = 0; - priv->speed = 100; - break; - case 5: - priv->duplexity = 1; - priv->speed = 100; - break; - case 6: - priv->duplexity = 0; - priv->speed = 1000; - break; - case 7: - priv->duplexity = 1; - priv->speed = 1000; - break; - default: - printf("Auto-neg error, defaulting to 10BT/HD\n"); - priv->duplexity = 0; - priv->speed = 10; - break; + reg_array[whichreg] &= ~value; } - return 0; } +#endif /* Multicast TFTP ? */ -/* - * Find out if PHY is in copper or serdes mode by looking at Expansion Reg - * 0x42 - "Operating Mode Status Register" - */ -static int BCM8482_is_serdes(struct tsec_private *priv) -{ - u16 val; - int serdes = 0; - - write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_ER | 0x42); - val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); - - switch (val & 0x1f) { - case 0x0d: /* RGMII-to-100Base-FX */ - case 0x0e: /* RGMII-to-SGMII */ - case 0x0f: /* RGMII-to-SerDes */ - case 0x12: /* SGMII-to-SerDes */ - case 0x13: /* SGMII-to-100Base-FX */ - case 0x16: /* SerDes-to-Serdes */ - serdes = 1; - break; - case 0x6: /* RGMII-to-Copper */ - case 0x14: /* SGMII-to-Copper */ - case 0x17: /* SerDes-to-Copper */ - break; - default: - printf("ERROR, invalid PHY mode (0x%x\n)", val); - break; - } - - return serdes; -} - -/* - * Determine SerDes link speed and duplex from Expansion reg 0x42 "Operating - * Mode Status Register" +/* Initialized required registers to appropriate values, zeroing + * those we don't care about (unless zero is bad, in which case, + * choose a more appropriate value) */ -uint mii_parse_BCM5482_serdes_sr(struct tsec_private *priv) +static void init_registers(tsec_t *regs) { - u16 val; - int i = 0; + /* Clear IEVENT */ + out_be32(®s->ievent, IEVENT_INIT_CLEAR); + + out_be32(®s->imask, IMASK_INIT_CLEAR); + + out_be32(®s->hash.iaddr0, 0); + out_be32(®s->hash.iaddr1, 0); + out_be32(®s->hash.iaddr2, 0); + out_be32(®s->hash.iaddr3, 0); + out_be32(®s->hash.iaddr4, 0); + out_be32(®s->hash.iaddr5, 0); + out_be32(®s->hash.iaddr6, 0); + out_be32(®s->hash.iaddr7, 0); + + out_be32(®s->hash.gaddr0, 0); + out_be32(®s->hash.gaddr1, 0); + out_be32(®s->hash.gaddr2, 0); + out_be32(®s->hash.gaddr3, 0); + out_be32(®s->hash.gaddr4, 0); + out_be32(®s->hash.gaddr5, 0); + out_be32(®s->hash.gaddr6, 0); + out_be32(®s->hash.gaddr7, 0); + + out_be32(®s->rctrl, 0x00000000); - /* Wait 1s for link - Clause 37 autonegotiation happens very fast */ - while (1) { - write_phy_reg(priv, MIIM_BCM54XX_EXP_SEL, - MIIM_BCM54XX_EXP_SEL_ER | 0x42); - val = read_phy_reg(priv, MIIM_BCM54XX_EXP_DATA); + /* Init RMON mib registers */ + memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); - if (val & 0x8000) - break; + out_be32(®s->rmon.cam1, 0xffffffff); + out_be32(®s->rmon.cam2, 0xffffffff); - if (i++ > 1000) { - priv->link = 0; - return 1; - } + out_be32(®s->mrblr, MRBLR_INIT_SETTINGS); - udelay(1000); /* 1 ms */ - } + out_be32(®s->minflr, MINFLR_INIT_SETTINGS); - priv->link = 1; - switch ((val >> 13) & 0x3) { - case (0x00): - priv->speed = 10; - break; - case (0x01): - priv->speed = 100; - break; - case (0x02): - priv->speed = 1000; - break; - } - - priv->duplexity = (val & 0x1000) == 0x1000; + out_be32(®s->attr, ATTR_INIT_SETTINGS); + out_be32(®s->attreli, ATTRELI_INIT_SETTINGS); - return 0; } -/* - * Figure out if BCM5482 is in serdes or copper mode and determine link - * configuration accordingly - */ -static uint mii_parse_BCM5482_sr(uint mii_reg, struct tsec_private *priv) -{ - if (BCM8482_is_serdes(priv)) { - mii_parse_BCM5482_serdes_sr(priv); - priv->flags |= TSEC_FIBER; - } else { - /* Wait for auto-negotiation to complete or fail */ - mii_parse_sr(mii_reg, priv); - - /* Parse BCM54xx copper aux status register */ - mii_reg = read_phy_reg(priv, MIIM_BCM54xx_AUXSTATUS); - mii_parse_BCM54xx_sr(mii_reg, priv); - } - - return 0; -} - -/* Parse the 88E1011's status register for speed and duplex - * information - */ -static uint mii_parse_88E1011_psr(uint mii_reg, struct tsec_private * priv) -{ - uint speed; - - mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS); - - if ((mii_reg & MIIM_88E1011_PHYSTAT_LINK) && - !(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { - int i = 0; - - puts("Waiting for PHY realtime link"); - while (!(mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE)) { - /* Timeout reached ? */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - break; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_88E1011_PHY_STATUS); - } - puts(" done\n"); - udelay(500000); /* another 500 ms (results in faster booting) */ - } else { - if (mii_reg & MIIM_88E1011_PHYSTAT_LINK) - priv->link = 1; - else - priv->link = 0; - } - - if (mii_reg & MIIM_88E1011_PHYSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = (mii_reg & MIIM_88E1011_PHYSTAT_SPEED); - - switch (speed) { - case MIIM_88E1011_PHYSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_88E1011_PHYSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - } - - return 0; -} - -/* Parse the RTL8211B's status register for speed and duplex - * information +/* Configure maccfg2 based on negotiated speed and duplex + * reported by PHY handling code */ -static uint mii_parse_RTL8211B_sr(uint mii_reg, struct tsec_private * priv) +static void adjust_link(struct tsec_private *priv, struct phy_device *phydev) { - uint speed; - - mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); - if (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { - int i = 0; - - /* in case of timeout ->link is cleared */ - priv->link = 1; - puts("Waiting for PHY realtime link"); - while (!(mii_reg & MIIM_RTL8211B_PHYSTAT_SPDDONE)) { - /* Timeout reached ? */ - if (i > PHY_AUTONEGOTIATE_TIMEOUT) { - puts(" TIMEOUT !\n"); - priv->link = 0; - break; - } - - if ((i++ % 1000) == 0) { - putc('.'); - } - udelay(1000); /* 1 ms */ - mii_reg = read_phy_reg(priv, MIIM_RTL8211B_PHY_STATUS); - } - puts(" done\n"); - udelay(500000); /* another 500 ms (results in faster booting) */ - } else { - if (mii_reg & MIIM_RTL8211B_PHYSTAT_LINK) - priv->link = 1; - else - priv->link = 0; - } + tsec_t *regs = priv->regs; + u32 ecntrl, maccfg2; - if (mii_reg & MIIM_RTL8211B_PHYSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = (mii_reg & MIIM_RTL8211B_PHYSTAT_SPEED); - - switch (speed) { - case MIIM_RTL8211B_PHYSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_RTL8211B_PHYSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; + if (!phydev->link) { + printf("%s: No link.\n", phydev->dev->name); + return; } - return 0; -} + /* clear all bits relative with interface mode */ + ecntrl = in_be32(®s->ecntrl); + ecntrl &= ~ECNTRL_R100; -/* Parse the cis8201's status register for speed and duplex - * information - */ -static uint mii_parse_cis8201(uint mii_reg, struct tsec_private * priv) -{ - uint speed; + maccfg2 = in_be32(®s->maccfg2); + maccfg2 &= ~(MACCFG2_IF | MACCFG2_FULL_DUPLEX); - if (mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; + if (phydev->duplex) + maccfg2 |= MACCFG2_FULL_DUPLEX; - speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED; - switch (speed) { - case MIIM_CIS8201_AUXCONSTAT_GBIT: - priv->speed = 1000; + switch (phydev->speed) { + case 1000: + maccfg2 |= MACCFG2_GMII; break; - case MIIM_CIS8201_AUXCONSTAT_100: - priv->speed = 100; - break; - default: - priv->speed = 10; - break; - } - - return 0; -} - -/* Parse the vsc8244's status register for speed and duplex - * information - */ -static uint mii_parse_vsc8244(uint mii_reg, struct tsec_private * priv) -{ - uint speed; + case 100: + case 10: + maccfg2 |= MACCFG2_MII; - if (mii_reg & MIIM_VSC8244_AUXCONSTAT_DUPLEX) - priv->duplexity = 1; - else - priv->duplexity = 0; - - speed = mii_reg & MIIM_VSC8244_AUXCONSTAT_SPEED; - switch (speed) { - case MIIM_VSC8244_AUXCONSTAT_GBIT: - priv->speed = 1000; - break; - case MIIM_VSC8244_AUXCONSTAT_100: - priv->speed = 100; + /* Set R100 bit in all modes although + * it is only used in RGMII mode + */ + if (phydev->speed == 100) + ecntrl |= ECNTRL_R100; break; default: - priv->speed = 10; + printf("%s: Speed was bad\n", phydev->dev->name); break; } - return 0; -} - -/* Parse the DM9161's status register for speed and duplex - * information - */ -static uint mii_parse_dm9161_scsr(uint mii_reg, struct tsec_private * priv) -{ - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_100H)) - priv->speed = 100; - else - priv->speed = 10; - - if (mii_reg & (MIIM_DM9161_SCSR_100F | MIIM_DM9161_SCSR_10F)) - priv->duplexity = 1; - else - priv->duplexity = 0; - - return 0; -} - -/* - * Hack to write all 4 PHYs with the LED values - */ -static uint mii_cis8204_fixled(uint mii_reg, struct tsec_private * priv) -{ - uint phyid; - volatile tsec_mdio_t *regbase = priv->phyregs; - int timeout = 1000000; - - for (phyid = 0; phyid < 4; phyid++) { - regbase->miimadd = (phyid << 8) | mii_reg; - regbase->miimcon = MIIM_CIS8204_SLEDCON_INIT; - asm("sync"); - - timeout = 1000000; - while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ; - } - - return MIIM_CIS8204_SLEDCON_INIT; -} - -static uint mii_cis8204_setmode(uint mii_reg, struct tsec_private * priv) -{ - if (priv->flags & TSEC_REDUCED) - return MIIM_CIS8204_EPHYCON_INIT | MIIM_CIS8204_EPHYCON_RGMII; - else - return MIIM_CIS8204_EPHYCON_INIT; -} - -static uint mii_m88e1111s_setmode(uint mii_reg, struct tsec_private *priv) -{ - uint mii_data = read_phy_reg(priv, mii_reg); - - if (priv->flags & TSEC_REDUCED) - mii_data = (mii_data & 0xfff0) | 0x000b; - return mii_data; -} - -/* Initialized required registers to appropriate values, zeroing - * those we don't care about (unless zero is bad, in which case, - * choose a more appropriate value) - */ -static void init_registers(volatile tsec_t * regs) -{ - /* Clear IEVENT */ - regs->ievent = IEVENT_INIT_CLEAR; - - regs->imask = IMASK_INIT_CLEAR; - - regs->hash.iaddr0 = 0; - regs->hash.iaddr1 = 0; - regs->hash.iaddr2 = 0; - regs->hash.iaddr3 = 0; - regs->hash.iaddr4 = 0; - regs->hash.iaddr5 = 0; - regs->hash.iaddr6 = 0; - regs->hash.iaddr7 = 0; - - regs->hash.gaddr0 = 0; - regs->hash.gaddr1 = 0; - regs->hash.gaddr2 = 0; - regs->hash.gaddr3 = 0; - regs->hash.gaddr4 = 0; - regs->hash.gaddr5 = 0; - regs->hash.gaddr6 = 0; - regs->hash.gaddr7 = 0; - - regs->rctrl = 0x00000000; - - /* Init RMON mib registers */ - memset((void *)&(regs->rmon), 0, sizeof(rmon_mib_t)); - - regs->rmon.cam1 = 0xffffffff; - regs->rmon.cam2 = 0xffffffff; - - regs->mrblr = MRBLR_INIT_SETTINGS; - - regs->minflr = MINFLR_INIT_SETTINGS; - - regs->attr = ATTR_INIT_SETTINGS; - regs->attreli = ATTRELI_INIT_SETTINGS; + out_be32(®s->ecntrl, ecntrl); + out_be32(®s->maccfg2, maccfg2); -} - -/* Configure maccfg2 based on negotiated speed and duplex - * reported by PHY handling code - */ -static void adjust_link(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; - - if (priv->link) { - if (priv->duplexity != 0) - regs->maccfg2 |= MACCFG2_FULL_DUPLEX; - else - regs->maccfg2 &= ~(MACCFG2_FULL_DUPLEX); - - switch (priv->speed) { - case 1000: - regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF)) - | MACCFG2_GMII); - break; - case 100: - case 10: - regs->maccfg2 = ((regs->maccfg2 & ~(MACCFG2_IF)) - | MACCFG2_MII); - - /* Set R100 bit in all modes although - * it is only used in RGMII mode - */ - if (priv->speed == 100) - regs->ecntrl |= ECNTRL_R100; - else - regs->ecntrl &= ~(ECNTRL_R100); - break; - default: - printf("%s: Speed was bad\n", dev->name); - break; - } - - printf("Speed: %d, %s duplex%s\n", priv->speed, - (priv->duplexity) ? "full" : "half", - (priv->flags & TSEC_FIBER) ? ", fiber mode" : ""); - - } else { - printf("%s: No link.\n", dev->name); - } + printf("Speed: %d, %s duplex%s\n", phydev->speed, + (phydev->duplex) ? "full" : "half", + (phydev->port == PORT_FIBRE) ? ", fiber mode" : ""); } /* Set up the buffers and their descriptors, and bring up the @@ -969,11 +243,15 @@ static void startup_tsec(struct eth_device *dev) { int i; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; + + /* reset the indices to zero */ + rxIdx = 0; + txIdx = 0; /* Point to the buffer descriptors */ - regs->tbase = (unsigned int)(&rtx.txbd[txIdx]); - regs->rbase = (unsigned int)(&rtx.rxbd[rxIdx]); + out_be32(®s->tbase, (unsigned int)(&rtx.txbd[txIdx])); + out_be32(®s->rbase, (unsigned int)(&rtx.rxbd[rxIdx])); /* Initialize the Rx Buffer descriptors */ for (i = 0; i < PKTBUFSRX; i++) { @@ -991,20 +269,14 @@ static void startup_tsec(struct eth_device *dev) } rtx.txbd[TX_BUF_CNT - 1].status |= TXBD_WRAP; - /* Start up the PHY */ - if(priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->startup); - - adjust_link(dev); - /* Enable Transmit and Receive */ - regs->maccfg1 |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + setbits_be32(®s->maccfg1, MACCFG1_RX_EN | MACCFG1_TX_EN); /* Tell the DMA it is clear to go */ - regs->dmactrl |= DMACTRL_INIT_SETTINGS; - regs->tstat = TSTAT_CLEAR_THALT; - regs->rstat = RSTAT_CLEAR_RHALT; - regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); + setbits_be32(®s->dmactrl, DMACTRL_INIT_SETTINGS); + out_be32(®s->tstat, TSTAT_CLEAR_THALT); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); } /* This returns the status bits of the device. The return value @@ -1017,7 +289,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length) int i; int result = 0; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; /* Find an empty buffer descriptor */ for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -1033,7 +305,7 @@ static int tsec_send(struct eth_device *dev, volatile void *packet, int length) (TXBD_READY | TXBD_LAST | TXBD_CRC | TXBD_INTERRUPT); /* Tell the DMA to go */ - regs->tstat = TSTAT_CLEAR_THALT; + out_be32(®s->tstat, TSTAT_CLEAR_THALT); /* Wait for buffer to be transmitted */ for (i = 0; rtx.txbd[txIdx].status & TXBD_READY; i++) { @@ -1053,7 +325,7 @@ static int tsec_recv(struct eth_device *dev) { int length; struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; while (!(rtx.rxbd[rxIdx].status & RXBD_EMPTY)) { @@ -1076,9 +348,9 @@ static int tsec_recv(struct eth_device *dev) rxIdx = (rxIdx + 1) % PKTBUFSRX; } - if (regs->ievent & IEVENT_BSY) { - regs->ievent = IEVENT_BSY; - regs->rstat = RSTAT_CLEAR_RHALT; + if (in_be32(®s->ievent) & IEVENT_BSY) { + out_be32(®s->ievent, IEVENT_BSY); + out_be32(®s->rstat, RSTAT_CLEAR_RHALT); } return -1; @@ -1089,936 +361,236 @@ static int tsec_recv(struct eth_device *dev) static void tsec_halt(struct eth_device *dev) { struct tsec_private *priv = (struct tsec_private *)dev->priv; - volatile tsec_t *regs = priv->regs; + tsec_t *regs = priv->regs; - regs->dmactrl &= ~(DMACTRL_GRS | DMACTRL_GTS); - regs->dmactrl |= (DMACTRL_GRS | DMACTRL_GTS); + clrbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); + setbits_be32(®s->dmactrl, DMACTRL_GRS | DMACTRL_GTS); - while ((regs->ievent & (IEVENT_GRSC | IEVENT_GTSC)) - != (IEVENT_GRSC | IEVENT_GTSC)) ; + while ((in_be32(®s->ievent) & (IEVENT_GRSC | IEVENT_GTSC)) + != (IEVENT_GRSC | IEVENT_GTSC)) + ; - regs->maccfg1 &= ~(MACCFG1_TX_EN | MACCFG1_RX_EN); + clrbits_be32(®s->maccfg1, MACCFG1_TX_EN | MACCFG1_RX_EN); /* Shut down the PHY, as needed */ - if(priv->phyinfo) - phy_run_commands(priv, priv->phyinfo->shutdown); + phy_shutdown(priv->phydev); } -static struct phy_info phy_info_M88E1149S = { - 0x1410ca, - "Marvell 88E1149S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1d, 0x1f, NULL}, - {0x1e, 0x200c, NULL}, - {0x1d, 0x5, NULL}, - {0x1e, 0x0, NULL}, - {0x1e, 0x100, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* The 5411 id is 0x206070, the 5421 is 0x2060e0 */ -static struct phy_info phy_info_BCM5461S = { - 0x02060c1, /* 5461 ID */ - "Broadcom BCM5461S", - 0, /* not clear to me what minor revisions we can shift away */ - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5464S = { - 0x02060b1, /* 5464 ID */ - "Broadcom BCM5464S", - 0, /* not clear to me what minor revisions we can shift away */ - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_BCM5482S = { - 0x0143bcb, - "Broadcom BCM5482S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - /* Setup read from auxilary control shadow register 7 */ - {MIIM_BCM54xx_AUXCNTL, MIIM_BCM54xx_AUXCNTL_ENCODE(7), NULL}, - /* Read Misc Control register and or in Ethernet@Wirespeed */ - {MIIM_BCM54xx_AUXCNTL, 0, &mii_BCM54xx_wirespeed}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - /* Initial config/enable of secondary SerDes interface */ - {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x14, 0xf), NULL}, - /* Write intial value to secondary SerDes Contol */ - {MIIM_BCM54XX_EXP_SEL, MIIM_BCM54XX_EXP_SEL_SSD | 0, NULL}, - {MIIM_BCM54XX_EXP_DATA, MIIM_CONTROL_RESTART, NULL}, - /* Enable copper/fiber auto-detect */ - {MIIM_BCM54XX_SHD, MIIM_BCM54XX_SHD_WR_ENCODE(0x1e, 0x201)}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Determine copper/fiber, auto-negotiate, and read the result */ - {MIIM_STATUS, miim_read, &mii_parse_BCM5482_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1011S = { - 0x01410c6, - "Marvell 88E1011S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1d, 0x1f, NULL}, - {0x1e, 0x200c, NULL}, - {0x1d, 0x5, NULL}, - {0x1e, 0x0, NULL}, - {0x1e, 0x100, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1111S = { - 0x01410cc, - "Marvell 88E1111S", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x1b, 0x848f, &mii_m88e1111s_setmode}, - {0x14, 0x0cd2, NULL}, /* Delay RGMII TX and RX */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -static struct phy_info phy_info_M88E1118 = { - 0x01410e1, - "Marvell 88E1118", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {0x16, 0x0002, NULL}, /* Change Page Number */ - {0x15, 0x1070, NULL}, /* Delay RGMII TX and RX */ - {0x16, 0x0003, NULL}, /* Change Page Number */ - {0x10, 0x021e, NULL}, /* Adjust LED control */ - {0x16, 0x0000, NULL}, /* Change Page Number */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {0x16, 0x0000, NULL}, /* Change Page Number */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_88E1011_PHY_STATUS, miim_read, - &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; - -/* - * Since to access LED register we need do switch the page, we - * do LED configuring in the miim_read-like function as follows +/* Initializes data structures and registers for the controller, + * and brings the interface up. Returns the link status, meaning + * that it returns success if the link is up, failure otherwise. + * This allows u-boot to find the first active controller. */ -static uint mii_88E1121_set_led (uint mii_reg, struct tsec_private *priv) +static int tsec_init(struct eth_device *dev, bd_t * bd) { - uint pg; + uint tempval; + char tmpbuf[MAC_ADDR_LEN]; + int i; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + tsec_t *regs = priv->regs; - /* Switch the page to access the led register */ - pg = read_phy_reg(priv, MIIM_88E1121_PHY_PAGE); - write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, MIIM_88E1121_PHY_LED_PAGE); + /* Make sure the controller is stopped */ + tsec_halt(dev); - /* Configure leds */ - write_phy_reg(priv, MIIM_88E1121_PHY_LED_CTRL, - MIIM_88E1121_PHY_LED_DEF); + /* Init MACCFG2. Defaults to GMII */ + out_be32(®s->maccfg2, MACCFG2_INIT_SETTINGS); - /* Restore the page pointer */ - write_phy_reg(priv, MIIM_88E1121_PHY_PAGE, pg); - return 0; -} + /* Init ECNTRL */ + out_be32(®s->ecntrl, ECNTRL_INIT_SETTINGS); -static struct phy_info phy_info_M88E1121R = { - 0x01410cb, - "Marvell 88E1121R", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - /* Configure leds */ - {MIIM_88E1121_PHY_LED_CTRL, miim_read, &mii_88E1121_set_led}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - /* Disable IRQs and de-assert interrupt */ - {MIIM_88E1121_PHY_IRQ_EN, 0, NULL}, - {MIIM_88E1121_PHY_IRQ_STATUS, miim_read, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_STATUS, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* Copy the station address into the address registers. + * Backwards, because little endian MACS are dumb */ + for (i = 0; i < MAC_ADDR_LEN; i++) + tmpbuf[MAC_ADDR_LEN - 1 - i] = dev->enetaddr[i]; -static unsigned int m88e1145_setmode(uint mii_reg, struct tsec_private *priv) -{ - uint mii_data = read_phy_reg(priv, mii_reg); - - /* Setting MIIM_88E1145_PHY_EXT_CR */ - if (priv->flags & TSEC_REDUCED) - return mii_data | - MIIM_M88E1145_RGMII_RX_DELAY | MIIM_M88E1145_RGMII_TX_DELAY; - else - return mii_data; -} + tempval = (tmpbuf[0] << 24) | (tmpbuf[1] << 16) | (tmpbuf[2] << 8) | + tmpbuf[3]; -static struct phy_info phy_info_M88E1145 = { - 0x01410cd, - "Marvell 88E1145", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - - /* Errata E0, E1 */ - {29, 0x001b, NULL}, - {30, 0x418f, NULL}, - {29, 0x0016, NULL}, - {30, 0xa2da, NULL}, - - /* Configure the PHY */ - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_88E1011_PHY_SCR, MIIM_88E1011_PHY_MDI_X_AUTO, NULL}, - {MIIM_88E1145_PHY_EXT_CR, 0, &m88e1145_setmode}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_88E1111_PHY_LED_CONTROL, MIIM_88E1111_PHY_LED_DIRECT, NULL}, - /* Read the Status */ - {MIIM_88E1011_PHY_STATUS, miim_read, &mii_parse_88E1011_psr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + out_be32(®s->macstnaddr1, tempval); -static struct phy_info phy_info_cis8204 = { - 0x3f11, - "Cicada Cis8204", - 6, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {MIIM_CIS8204_SLED_CON, MIIM_CIS8204_SLEDCON_INIT, - &mii_cis8204_fixled}, - {MIIM_CIS8204_EPHY_CON, MIIM_CIS8204_EPHYCON_INIT, - &mii_cis8204_setmode}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + tempval = *((uint *) (tmpbuf + 4)); -/* Cicada 8201 */ -static struct phy_info phy_info_cis8201 = { - 0xfc41, - "CIS8201", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + out_be32(®s->macstnaddr2, tempval); -static struct phy_info phy_info_VSC8211 = { - 0xfc4b, - "Vitesse VSC8211", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - {MIIM_CIS8201_AUX_CONSTAT, MIIM_CIS8201_AUXCONSTAT_INIT, NULL}, - /* Set up the interface mode */ - {MIIM_CIS8201_EXT_CON1, MIIM_CIS8201_EXTCON1_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_CIS8201_AUX_CONSTAT, miim_read, &mii_parse_cis8201}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* Clear out (for the most part) the other registers */ + init_registers(regs); -static struct phy_info phy_info_VSC8244 = { - 0x3f1b, - "Vitesse VSC8244", - 6, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* Ready the device for tx/rx */ + startup_tsec(dev); -static struct phy_info phy_info_VSC8641 = { - 0x7043, - "Vitesse VSC8641", - 4, - (struct phy_cmd[]) { /* config */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* Start up the PHY */ + phy_startup(priv->phydev); -static struct phy_info phy_info_VSC8221 = { - 0xfc55, - "Vitesse VSC8221", - 4, - (struct phy_cmd[]) { /* config */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + adjust_link(priv, priv->phydev); -static struct phy_info phy_info_VSC8601 = { - 0x00007042, - "Vitesse VSC8601", - 4, - (struct phy_cmd[]) { /* config */ - /* Override PHY config settings */ - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, -#ifdef CONFIG_SYS_VSC8601_SKEWFIX - {MIIM_VSC8601_EPHY_CON,MIIM_VSC8601_EPHY_CON_INIT_SKEW,NULL}, -#if defined(CONFIG_SYS_VSC8601_SKEW_TX) && defined(CONFIG_SYS_VSC8601_SKEW_RX) - {MIIM_EXT_PAGE_ACCESS,1,NULL}, -#define VSC8101_SKEW \ - (CONFIG_SYS_VSC8601_SKEW_TX << 14) | (CONFIG_SYS_VSC8601_SKEW_RX << 12) - {MIIM_VSC8601_SKEW_CTRL,VSC8101_SKEW,NULL}, - {MIIM_EXT_PAGE_ACCESS,0,NULL}, -#endif -#endif - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESTART, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Read the Status (2x to make sure link is right) */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_VSC8244_AUX_CONSTAT, miim_read, &mii_parse_vsc8244}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + /* If there's no link, fail */ + return priv->phydev->link ? 0 : -1; +} -static struct phy_info phy_info_dm9161 = { - 0x0181b88, - "Davicom DM9161E", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DM9161_CR_STOP, NULL}, - /* Do not bypass the scrambler/descrambler */ - {MIIM_DM9161_SCR, MIIM_DM9161_SCR_INIT, NULL}, - /* Clear 10BTCSR to default */ - {MIIM_DM9161_10BTCSR, MIIM_DM9161_10BTCSR_INIT, NULL}, - /* Configure some basic stuff */ - {MIIM_CONTROL, MIIM_CR_INIT, NULL}, - /* Restart Auto Negotiation */ - {MIIM_CONTROL, MIIM_DM9161_CR_RSTAN, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_DM9161_SCSR, miim_read, &mii_parse_dm9161_scsr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; +static phy_interface_t tsec_get_interface(struct tsec_private *priv) +{ + tsec_t *regs = priv->regs; + u32 ecntrl; -/* micrel KSZ804 */ -static struct phy_info phy_info_ksz804 = { - 0x0022151, - "Micrel KSZ804 PHY", - 4, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; + ecntrl = in_be32(®s->ecntrl); + + if (ecntrl & ECNTRL_SGMII_MODE) + return PHY_INTERFACE_MODE_SGMII; -/* a generic flavor. */ -static struct phy_info phy_info_generic = { - 0, - "Unknown/Generic PHY", - 32, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} + if (ecntrl & ECNTRL_TBI_MODE) { + if (ecntrl & ECNTRL_REDUCED_MODE) + return PHY_INTERFACE_MODE_RTBI; + else + return PHY_INTERFACE_MODE_TBI; } -}; -static uint mii_parse_lxt971_sr2(uint mii_reg, struct tsec_private *priv) -{ - unsigned int speed; - if (priv->link) { - speed = mii_reg & MIIM_LXT971_SR2_SPEED_MASK; - - switch (speed) { - case MIIM_LXT971_SR2_10HDX: - priv->speed = 10; - priv->duplexity = 0; - break; - case MIIM_LXT971_SR2_10FDX: - priv->speed = 10; - priv->duplexity = 1; - break; - case MIIM_LXT971_SR2_100HDX: - priv->speed = 100; - priv->duplexity = 0; - break; - default: - priv->speed = 100; - priv->duplexity = 1; + if (ecntrl & ECNTRL_REDUCED_MODE) { + if (ecntrl & ECNTRL_REDUCED_MII_MODE) + return PHY_INTERFACE_MODE_RMII; + else { + phy_interface_t interface = priv->interface; + + /* + * This isn't autodetected, so it must + * be set by the platform code. + */ + if ((interface == PHY_INTERFACE_MODE_RGMII_ID) || + (interface == PHY_INTERFACE_MODE_RGMII_TXID) || + (interface == PHY_INTERFACE_MODE_RGMII_RXID)) + return interface; + + return PHY_INTERFACE_MODE_RGMII; } - } else { - priv->speed = 0; - priv->duplexity = 0; } - return 0; + if (priv->flags & TSEC_GIGABIT) + return PHY_INTERFACE_MODE_GMII; + + return PHY_INTERFACE_MODE_MII; } -static struct phy_info phy_info_lxt971 = { - 0x0001378e, - "LXT971", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CR, MIIM_CR_INIT, mii_cr_init}, /* autonegotiate */ - {miim_end,} - }, - (struct phy_cmd[]) { /* startup - enable interrupts */ - /* { 0x12, 0x00f2, NULL }, */ - {MIIM_STATUS, miim_read, NULL}, - {MIIM_STATUS, miim_read, &mii_parse_sr}, - {MIIM_LXT971_SR2, miim_read, &mii_parse_lxt971_sr2}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown - disable interrupts */ - {miim_end,} - }, -}; -/* Parse the DP83865's link and auto-neg status register for speed and duplex - * information +/* Discover which PHY is attached to the device, and configure it + * properly. If the PHY is not recognized, then return 0 + * (failure). Otherwise, return 1 */ -static uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv) +static int init_phy(struct eth_device *dev) { - switch (mii_reg & MIIM_DP83865_SPD_MASK) { - - case MIIM_DP83865_SPD_1000: - priv->speed = 1000; - break; - - case MIIM_DP83865_SPD_100: - priv->speed = 100; - break; - - default: - priv->speed = 10; - break; + struct tsec_private *priv = (struct tsec_private *)dev->priv; + struct phy_device *phydev; + tsec_t *regs = priv->regs; + u32 supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full); - } + if (priv->flags & TSEC_GIGABIT) + supported |= SUPPORTED_1000baseT_Full; - if (mii_reg & MIIM_DP83865_DPX_FULL) - priv->duplexity = 1; - else - priv->duplexity = 0; + /* Assign a Physical address to the TBI */ + out_be32(®s->tbipa, CONFIG_SYS_TBIPA_VALUE); - return 0; -} + priv->interface = tsec_get_interface(priv); -static struct phy_info phy_info_dp83865 = { - 0x20005c7, - "NatSemi DP83865", - 4, - (struct phy_cmd[]) { /* config */ - {MIIM_CONTROL, MIIM_DP83865_CR_INIT, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the link and auto-neg status */ - {MIIM_DP83865_LANR, miim_read, &mii_parse_dp83865_lanr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + if (priv->interface == PHY_INTERFACE_MODE_SGMII) + tsec_configure_serdes(priv); -static struct phy_info phy_info_rtl8211b = { - 0x001cc91, - "RealTek RTL8211B", - 4, - (struct phy_cmd[]) { /* config */ - /* Reset and configure the PHY */ - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_GBIT_CONTROL, MIIM_GBIT_CONTROL_INIT, NULL}, - {MIIM_ANAR, MIIM_ANAR_INIT, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_RESET, NULL}, - {MIIM_CONTROL, MIIM_CONTROL_INIT, &mii_cr_init}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - /* Status is read once to clear old link state */ - {MIIM_STATUS, miim_read, NULL}, - /* Auto-negotiate */ - {MIIM_STATUS, miim_read, &mii_parse_sr}, - /* Read the status */ - {MIIM_RTL8211B_PHY_STATUS, miim_read, &mii_parse_RTL8211B_sr}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - }, -}; + phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface); -struct phy_info phy_info_AR8021 = { - 0x4dd04, - "AR8021", - 4, - (struct phy_cmd[]) { /* config */ - {MII_BMCR, BMCR_RESET, NULL}, - {MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART, NULL}, - {0x1d, 0x05, NULL}, - {0x1e, 0x3D47, NULL}, - {miim_end,} - }, - (struct phy_cmd[]) { /* startup */ - {MII_BMSR, miim_read, NULL}, - {MII_BMSR, miim_read, &mii_parse_sr}, - {MII_BMSR, miim_read, &mii_parse_link}, - {miim_end,} - }, - (struct phy_cmd[]) { /* shutdown */ - {miim_end,} - } -}; + phydev->supported &= supported; + phydev->advertising = phydev->supported; -static struct phy_info *phy_info[] = { - &phy_info_cis8204, - &phy_info_cis8201, - &phy_info_BCM5461S, - &phy_info_BCM5464S, - &phy_info_BCM5482S, - &phy_info_M88E1011S, - &phy_info_M88E1111S, - &phy_info_M88E1118, - &phy_info_M88E1121R, - &phy_info_M88E1145, - &phy_info_M88E1149S, - &phy_info_dm9161, - &phy_info_ksz804, - &phy_info_lxt971, - &phy_info_VSC8211, - &phy_info_VSC8244, - &phy_info_VSC8601, - &phy_info_VSC8641, - &phy_info_VSC8221, - &phy_info_dp83865, - &phy_info_rtl8211b, - &phy_info_AR8021, - &phy_info_generic, /* must be last; has ID 0 and 32 bit mask */ - NULL -}; + priv->phydev = phydev; -/* Grab the identifier of the device's PHY, and search through - * all of the known PHYs to see if one matches. If so, return - * it, if not, return NULL - */ -static struct phy_info *get_phy_info(struct eth_device *dev) -{ - struct tsec_private *priv = (struct tsec_private *)dev->priv; - uint phy_reg, phy_ID; - int i; - struct phy_info *theInfo = NULL; - - /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR1); - phy_ID = (phy_reg & 0xffff) << 16; - - /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = read_phy_reg(priv, MIIM_PHYIR2); - phy_ID |= (phy_reg & 0xffff); - - /* loop through all the known PHY types, and find one that */ - /* matches the ID we read from the PHY. */ - for (i = 0; phy_info[i]; i++) { - if (phy_info[i]->id == (phy_ID >> phy_info[i]->shift)) { - theInfo = phy_info[i]; - break; - } - } + phy_config(phydev); - if (theInfo == &phy_info_generic) { - printf("%s: No support for PHY id %x; assuming generic\n", - dev->name, phy_ID); - } else { - debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID); - } - - return theInfo; + return 1; } -/* Execute the given series of commands on the given device's - * PHY, running functions as necessary +/* Initialize device structure. Returns success if PHY + * initialization succeeded (i.e. if it recognizes the PHY) */ -static void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd) +static int tsec_initialize(bd_t *bis, struct tsec_info_struct *tsec_info) { + struct eth_device *dev; int i; - uint result; - volatile tsec_mdio_t *phyregs = priv->phyregs; - - phyregs->miimcfg = MIIMCFG_RESET; + struct tsec_private *priv; - phyregs->miimcfg = MIIMCFG_INIT_VALUE; + dev = (struct eth_device *)malloc(sizeof *dev); - while (phyregs->miimind & MIIMIND_BUSY) ; + if (NULL == dev) + return 0; - for (i = 0; cmd->mii_reg != miim_end; i++) { - if (cmd->mii_data == miim_read) { - result = read_phy_reg(priv, cmd->mii_reg); + memset(dev, 0, sizeof *dev); - if (cmd->funct != NULL) - (*(cmd->funct)) (result, priv); + priv = (struct tsec_private *)malloc(sizeof(*priv)); - } else { - if (cmd->funct != NULL) - result = (*(cmd->funct)) (cmd->mii_reg, priv); - else - result = cmd->mii_data; + if (NULL == priv) + return 0; - write_phy_reg(priv, cmd->mii_reg, result); + privlist[num_tsecs++] = priv; + priv->regs = tsec_info->regs; + priv->phyregs_sgmii = tsec_info->miiregs_sgmii; - } - cmd++; - } -} + priv->phyaddr = tsec_info->phyaddr; + priv->flags = tsec_info->flags; -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \ - && !defined(BITBANGMII) + sprintf(dev->name, tsec_info->devname); + priv->interface = tsec_info->interface; + priv->bus = miiphy_get_dev_by_name(tsec_info->mii_devname); + dev->iobase = 0; + dev->priv = priv; + dev->init = tsec_init; + dev->halt = tsec_halt; + dev->send = tsec_send; + dev->recv = tsec_recv; +#ifdef CONFIG_MCAST_TFTP + dev->mcast = tsec_mcast_addr; +#endif -/* - * Read a MII PHY register. - * - * Returns: - * 0 on success - */ -static int tsec_miiphy_read(const char *devname, unsigned char addr, - unsigned char reg, unsigned short *value) -{ - unsigned short ret; - struct tsec_private *priv = privlist[0]; + /* Tell u-boot to get the addr from the env */ + for (i = 0; i < 6; i++) + dev->enetaddr[i] = 0; - if (NULL == priv) { - printf("Can't read PHY at address %d\n", addr); - return -1; - } + eth_register(dev); - ret = (unsigned short)tsec_local_mdio_read(priv->phyregs, addr, reg); - *value = ret; + /* Reset the MAC */ + setbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); + udelay(2); /* Soft Reset must be asserted for 3 TX clocks */ + clrbits_be32(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); - return 0; + /* Try to initialize PHY here, and return */ + return init_phy(dev); } /* - * Write a MII PHY register. + * Initialize all the TSEC devices * - * Returns: - * 0 on success + * Returns the number of TSEC devices that were initialized */ -static int tsec_miiphy_write(const char *devname, unsigned char addr, - unsigned char reg, unsigned short value) +int tsec_eth_init(bd_t *bis, struct tsec_info_struct *tsecs, int num) { - struct tsec_private *priv = privlist[0]; + int i; + int ret, count = 0; - if (NULL == priv) { - printf("Can't write PHY at address %d\n", addr); - return -1; + for (i = 0; i < num; i++) { + ret = tsec_initialize(bis, &tsecs[i]); + if (ret > 0) + count += ret; } - tsec_local_mdio_write(priv->phyregs, addr, reg, value); - - return 0; + return count; } -#endif - -#ifdef CONFIG_MCAST_TFTP - -/* CREDITS: linux gianfar driver, slightly adjusted... thanx. */ - -/* Set the appropriate hash bit for the given addr */ - -/* The algorithm works like so: - * 1) Take the Destination Address (ie the multicast address), and - * do a CRC on it (little endian), and reverse the bits of the - * result. - * 2) Use the 8 most significant bits as a hash into a 256-entry - * table. The table is controlled through 8 32-bit registers: - * gaddr0-7. gaddr0's MSB is entry 0, and gaddr7's LSB is - * gaddr7. This means that the 3 most significant bits in the - * hash index which gaddr register to use, and the 5 other bits - * indicate which bit (assuming an IBM numbering scheme, which - * for PowerPC (tm) is usually the case) in the tregister holds - * the entry. */ -static int -tsec_mcast_addr (struct eth_device *dev, u8 mcast_mac, u8 set) +int tsec_standard_init(bd_t *bis) { - struct tsec_private *priv = privlist[1]; - volatile tsec_t *regs = priv->regs; - volatile u32 *reg_array, value; - u8 result, whichbit, whichreg; + struct fsl_pq_mdio_info info; - result = (u8)((ether_crc(MAC_ADDR_LEN,mcast_mac) >> 24) & 0xff); - whichbit = result & 0x1f; /* the 5 LSB = which bit to set */ - whichreg = result >> 5; /* the 3 MSB = which reg to set it in */ - value = (1 << (31-whichbit)); + info.regs = (struct tsec_mii_mng *)CONFIG_SYS_MDIO_BASE_ADDR; + info.name = DEFAULT_MII_NAME; - reg_array = &(regs->hash.gaddr0); + fsl_pq_mdio_init(bis, &info); - if (set) { - reg_array[whichreg] |= value; - } else { - reg_array[whichreg] &= ~value; - } - return 0; + return tsec_eth_init(bis, tsec_info, ARRAY_SIZE(tsec_info)); } -#endif /* Multicast TFTP ? */ + diff --git a/drivers/net/uli526x.c b/drivers/net/uli526x.c index a4624e1..5933bdd 100644 --- a/drivers/net/uli526x.c +++ b/drivers/net/uli526x.c @@ -175,9 +175,9 @@ static u16 read_srom_word(long, int); static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long); static void allocate_rx_buffer(struct uli526x_board_info *); static void update_cr6(u32, unsigned long); -static u16 phy_read(unsigned long, u8, u8, u32); +static u16 uli_phy_read(unsigned long, u8, u8, u32); static u16 phy_readby_cr10(unsigned long, u8, u8); -static void phy_write(unsigned long, u8, u8, u16, u32); +static void uli_phy_write(unsigned long, u8, u8, u16, u32); static void phy_writeby_cr10(unsigned long, u8, u8, u16); static void phy_write_1bit(unsigned long, u32, u32); static u16 phy_read_1bit(unsigned long, u32); @@ -349,7 +349,7 @@ static void uli526x_disable(struct eth_device *dev) /* Reset & stop ULI526X board */ outl(ULI526X_RESET, db->ioaddr + DCR0); udelay(5); - phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x8000, db->chip_id); /* reset the board */ db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); /* Disable Tx/Rx */ @@ -385,7 +385,7 @@ static void uli526x_init(struct eth_device *dev) db->tx_packet_cnt = 0; for (phy_tmp = 0; phy_tmp < 32; phy_tmp++) { /* peer add */ - phy_value = phy_read(db->ioaddr, phy_tmp, 3, db->chip_id); + phy_value = uli_phy_read(db->ioaddr, phy_tmp, 3, db->chip_id); if (phy_value != 0xffff && phy_value != 0) { db->phy_addr = phy_tmp; break; @@ -404,10 +404,10 @@ static void uli526x_init(struct eth_device *dev) if (!(inl(db->ioaddr + DCR12) & 0x8)) { /* Phyxcer capability setting */ - phy_reg_reset = phy_read(db->ioaddr, + phy_reg_reset = uli_phy_read(db->ioaddr, db->phy_addr, 0, db->chip_id); phy_reg_reset = (phy_reg_reset | 0x8000); - phy_write(db->ioaddr, db->phy_addr, 0, + uli_phy_write(db->ioaddr, db->phy_addr, 0, phy_reg_reset, db->chip_id); udelay(500); @@ -781,7 +781,8 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) u16 phy_reg; /* Phyxcer capability setting */ - phy_reg = phy_read(db->ioaddr, db->phy_addr, 4, db->chip_id) & ~0x01e0; + phy_reg = uli_phy_read(db->ioaddr, + db->phy_addr, 4, db->chip_id) & ~0x01e0; if (db->media_mode & ULI526X_AUTO) { /* AUTO Mode */ @@ -802,10 +803,10 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) phy_reg |= db->PHY_reg4; db->media_mode |= ULI526X_AUTO; } - phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 4, phy_reg, db->chip_id); /* Restart Auto-Negotiation */ - phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); + uli_phy_write(db->ioaddr, db->phy_addr, 0, 0x1200, db->chip_id); udelay(50); } @@ -813,7 +814,7 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *db) * Write a word to Phy register */ -static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, +static void uli_phy_write(unsigned long iobase, u8 phy_addr, u8 offset, u16 phy_data, u32 chip_id) { u16 i; @@ -862,7 +863,8 @@ static void phy_write(unsigned long iobase, u8 phy_addr, u8 offset, * Read a word data from phy register */ -static u16 phy_read(unsigned long iobase, u8 phy_addr, u8 offset, u32 chip_id) +static u16 uli_phy_read(unsigned long iobase, u8 phy_addr, u8 offset, + u32 chip_id) { int i; u16 phy_data; diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c index 811e3fc..1ecb137 100644 --- a/drivers/qe/uec.c +++ b/drivers/qe/uec.c @@ -30,6 +30,7 @@ #include "uec.h" #include "uec_phy.h" #include "miiphy.h" +#include <phy.h> /* Default UTBIPAR SMI address */ #ifndef CONFIG_UTBIPAR_INIT_TBIPA @@ -67,9 +68,6 @@ static uec_info_t uec_info[] = { static struct eth_device *devlist[MAXCONTROLLERS]; -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum); -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val); - static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) { uec_t *uec_regs; @@ -324,9 +322,9 @@ static int uec_set_mac_duplex(uec_private_t *uec, int duplex) } static int uec_set_mac_if_mode(uec_private_t *uec, - enum fsl_phy_enet_if if_mode, int speed) + phy_interface_t if_mode, int speed) { - enum fsl_phy_enet_if enet_if_mode; + phy_interface_t enet_if_mode; uec_info_t *uec_info; uec_t *uec_regs; u32 upsmr; @@ -348,15 +346,15 @@ static int uec_set_mac_if_mode(uec_private_t *uec, upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); switch (speed) { - case 10: + case SPEED_10: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; switch (enet_if_mode) { - case MII: + case PHY_INTERFACE_MODE_MII: break; - case RGMII: + case PHY_INTERFACE_MODE_RGMII: upsmr |= (UPSMR_RPM | UPSMR_R10M); break; - case RMII: + case PHY_INTERFACE_MODE_RMII: upsmr |= (UPSMR_R10M | UPSMR_RMM); break; default: @@ -364,15 +362,15 @@ static int uec_set_mac_if_mode(uec_private_t *uec, break; } break; - case 100: + case SPEED_100: maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; switch (enet_if_mode) { - case MII: + case PHY_INTERFACE_MODE_MII: break; - case RGMII: + case PHY_INTERFACE_MODE_RGMII: upsmr |= UPSMR_RPM; break; - case RMII: + case PHY_INTERFACE_MODE_RMII: upsmr |= UPSMR_RMM; break; default: @@ -380,23 +378,24 @@ static int uec_set_mac_if_mode(uec_private_t *uec, break; } break; - case 1000: + case SPEED_1000: maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; switch (enet_if_mode) { - case GMII: + case PHY_INTERFACE_MODE_GMII: break; - case TBI: + case PHY_INTERFACE_MODE_TBI: upsmr |= UPSMR_TBIM; break; - case RTBI: + case PHY_INTERFACE_MODE_RTBI: upsmr |= (UPSMR_RPM | UPSMR_TBIM); break; - case RGMII_RXID: - case RGMII_ID: - case RGMII: + case PHY_INTERFACE_MODE_RGMII_RXID: + case PHY_INTERFACE_MODE_RGMII_TXID: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_RGMII: upsmr |= UPSMR_RPM; break; - case SGMII: + case PHY_INTERFACE_MODE_SGMII: upsmr |= UPSMR_SGMM; break; default: @@ -521,7 +520,7 @@ static void adjust_link(struct eth_device *dev) struct uec_mii_info *mii_info = uec->mii_info; extern void change_phy_interface_mode(struct eth_device *dev, - enum fsl_phy_enet_if mode, int speed); + phy_interface_t mode, int speed); uec_regs = uec->uec_regs; if (mii_info->link) { @@ -539,19 +538,19 @@ static void adjust_link(struct eth_device *dev) } if (mii_info->speed != uec->oldspeed) { - enum fsl_phy_enet_if mode = \ + phy_interface_t mode = uec->uec_info->enet_interface_type; if (uec->uec_info->uf_info.eth_type == GIGA_ETH) { switch (mii_info->speed) { - case 1000: + case SPEED_1000: break; - case 100: + case SPEED_100: printf ("switching to rgmii 100\n"); - mode = RGMII; + mode = PHY_INTERFACE_MODE_RGMII; break; - case 10: + case SPEED_10: printf ("switching to rgmii 10\n"); - mode = RGMII; + mode = PHY_INTERFACE_MODE_RGMII; break; default: printf("%s: Ack,Speed(%d)is illegal\n", @@ -1115,8 +1114,8 @@ static int uec_startup(uec_private_t *uec) out_be32(&uec_regs->utbipar, utbipar); /* Configure the TBI for SGMII operation */ - if ((uec->uec_info->enet_interface_type == SGMII) && - (uec->uec_info->speed == 1000)) { + if ((uec->uec_info->enet_interface_type == PHY_INTERFACE_MODE_SGMII) && + (uec->uec_info->speed == SPEED_1000)) { uec_write_phy_reg(uec->dev, uec_regs->utbipar, ENET_TBI_MII_ANA, TBIANA_SETTINGS); diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h index 94eb9a2..e63bf3a 100644 --- a/drivers/qe/uec.h +++ b/drivers/qe/uec.h @@ -25,6 +25,7 @@ #include "qe.h" #include "uccf.h" +#include <phy.h> #include <asm/fsl_enet.h> #define MAX_TX_THREADS 8 @@ -691,7 +692,7 @@ typedef struct uec_info { u16 rx_bd_ring_len; u16 tx_bd_ring_len; u8 phy_address; - enum fsl_phy_enet_if enet_interface_type; + phy_interface_t enet_interface_type; int speed; } uec_info_t; diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c index 55c2622..e26218b 100644 --- a/drivers/qe/uec_phy.c +++ b/drivers/qe/uec_phy.c @@ -25,6 +25,7 @@ #include "uec.h" #include "uec_phy.h" #include "miiphy.h" +#include <phy.h> #define ugphy_printk(format, arg...) \ printf(format "\n", ## arg) @@ -121,8 +122,8 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info); static int genmii_config_aneg (struct uec_mii_info *mii_info); static int genmii_update_link (struct uec_mii_info *mii_info); static int genmii_read_status (struct uec_mii_info *mii_info); -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum); -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val); +u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum); +void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val); /* Write value to the PHY for this device to the register at regnum, */ /* waiting until the write is done before it returns. All PHY */ @@ -242,7 +243,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info) advertise = mii_info->advertising; /* Setup standard advertisement */ - adv = phy_read (mii_info, MII_ADVERTISE); + adv = uec_phy_read(mii_info, MII_ADVERTISE); adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); if (advertise & ADVERTISED_10baseT_Half) adv |= ADVERTISE_10HALF; @@ -252,7 +253,7 @@ static void config_genmii_advert (struct uec_mii_info *mii_info) adv |= ADVERTISE_100HALF; if (advertise & ADVERTISED_100baseT_Full) adv |= ADVERTISE_100FULL; - phy_write (mii_info, MII_ADVERTISE, adv); + uec_phy_write(mii_info, MII_ADVERTISE, adv); } static void genmii_setup_forced (struct uec_mii_info *mii_info) @@ -260,7 +261,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) u16 ctrl; u32 features = mii_info->phyinfo->features; - ctrl = phy_read (mii_info, MII_BMCR); + ctrl = uec_phy_read(mii_info, MII_BMCR); ctrl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); @@ -290,7 +291,7 @@ static void genmii_setup_forced (struct uec_mii_info *mii_info) break; } - phy_write (mii_info, MII_BMCR, ctrl); + uec_phy_write(mii_info, MII_BMCR, ctrl); } /* Enable and Restart Autonegotiation */ @@ -298,9 +299,9 @@ static void genmii_restart_aneg (struct uec_mii_info *mii_info) { u16 ctl; - ctl = phy_read (mii_info, MII_BMCR); + ctl = uec_phy_read(mii_info, MII_BMCR); ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); - phy_write (mii_info, MII_BMCR, ctl); + uec_phy_write(mii_info, MII_BMCR, ctl); } static int gbit_config_aneg (struct uec_mii_info *mii_info) @@ -313,14 +314,14 @@ static int gbit_config_aneg (struct uec_mii_info *mii_info) config_genmii_advert (mii_info); advertise = mii_info->advertising; - adv = phy_read (mii_info, MII_CTRL1000); + adv = uec_phy_read(mii_info, MII_CTRL1000); adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); if (advertise & SUPPORTED_1000baseT_Half) adv |= ADVERTISE_1000HALF; if (advertise & SUPPORTED_1000baseT_Full) adv |= ADVERTISE_1000FULL; - phy_write (mii_info, MII_CTRL1000, adv); + uec_phy_write(mii_info, MII_CTRL1000, adv); /* Start/Restart aneg */ genmii_restart_aneg (mii_info); @@ -335,13 +336,13 @@ static int marvell_config_aneg (struct uec_mii_info *mii_info) /* The Marvell PHY has an errata which requires * that certain registers get written in order * to restart autonegotiation */ - phy_write (mii_info, MII_BMCR, BMCR_RESET); + uec_phy_write(mii_info, MII_BMCR, BMCR_RESET); - phy_write (mii_info, 0x1d, 0x1f); - phy_write (mii_info, 0x1e, 0x200c); - phy_write (mii_info, 0x1d, 0x5); - phy_write (mii_info, 0x1e, 0); - phy_write (mii_info, 0x1e, 0x100); + uec_phy_write(mii_info, 0x1d, 0x1f); + uec_phy_write(mii_info, 0x1e, 0x200c); + uec_phy_write(mii_info, 0x1d, 0x5); + uec_phy_write(mii_info, 0x1e, 0); + uec_phy_write(mii_info, 0x1e, 0x100); gbit_config_aneg (mii_info); @@ -373,13 +374,13 @@ static int genmii_update_link (struct uec_mii_info *mii_info) u16 status; /* Status is read once to clear old link state */ - phy_read (mii_info, MII_BMSR); + uec_phy_read(mii_info, MII_BMSR); /* * Wait if the link is up, and autonegotiation is in progress * (ie - we're capable and it's not done) */ - status = phy_read(mii_info, MII_BMSR); + status = uec_phy_read(mii_info, MII_BMSR); if ((status & BMSR_LSTATUS) && (status & BMSR_ANEGCAPABLE) && !(status & BMSR_ANEGCOMPLETE)) { int i = 0; @@ -395,7 +396,7 @@ static int genmii_update_link (struct uec_mii_info *mii_info) i++; udelay(1000); /* 1 ms */ - status = phy_read(mii_info, MII_BMSR); + status = uec_phy_read(mii_info, MII_BMSR); } mii_info->link = 1; } else { @@ -420,7 +421,7 @@ static int genmii_read_status (struct uec_mii_info *mii_info) return err; if (mii_info->autoneg) { - status = phy_read(mii_info, MII_STAT1000); + status = uec_phy_read(mii_info, MII_STAT1000); if (status & (LPA_1000FULL | LPA_1000HALF)) { mii_info->speed = SPEED_1000; @@ -429,7 +430,7 @@ static int genmii_read_status (struct uec_mii_info *mii_info) else mii_info->duplex = DUPLEX_HALF; } else { - status = phy_read(mii_info, MII_LPA); + status = uec_phy_read(mii_info, MII_LPA); if (status & (LPA_10FULL | LPA_100FULL)) mii_info->duplex = DUPLEX_FULL; @@ -456,62 +457,63 @@ static int bcm_init(struct uec_mii_info *mii_info) gbit_config_aneg(mii_info); - if ((uec->uec_info->enet_interface_type == RGMII_RXID) && - (uec->uec_info->speed == 1000)) { + if ((uec->uec_info->enet_interface_type == + PHY_INTERFACE_MODE_RGMII_RXID) && + (uec->uec_info->speed == SPEED_1000)) { u16 val; int cnt = 50; /* Wait for aneg to complete. */ do - val = phy_read(mii_info, MII_BMSR); + val = uec_phy_read(mii_info, MII_BMSR); while (--cnt && !(val & BMSR_ANEGCOMPLETE)); /* Set RDX clk delay. */ - phy_write(mii_info, 0x18, 0x7 | (7 << 12)); + uec_phy_write(mii_info, 0x18, 0x7 | (7 << 12)); - val = phy_read(mii_info, 0x18); + val = uec_phy_read(mii_info, 0x18); /* Set RDX-RXC skew. */ val |= (1 << 8); val |= (7 | (7 << 12)); /* Write bits 14:0. */ val |= (1 << 15); - phy_write(mii_info, 0x18, val); + uec_phy_write(mii_info, 0x18, val); } return 0; } -static int marvell_init(struct uec_mii_info *mii_info) +static int uec_marvell_init(struct uec_mii_info *mii_info) { struct eth_device *edev = mii_info->dev; uec_private_t *uec = edev->priv; - enum fsl_phy_enet_if iface = uec->uec_info->enet_interface_type; + phy_interface_t iface = uec->uec_info->enet_interface_type; int speed = uec->uec_info->speed; - if ((speed == 1000) && - (iface == RGMII_ID || - iface == RGMII_RXID || - iface == RGMII_TXID)) { + if ((speed == SPEED_1000) && + (iface == PHY_INTERFACE_MODE_RGMII_ID || + iface == PHY_INTERFACE_MODE_RGMII_RXID || + iface == PHY_INTERFACE_MODE_RGMII_TXID)) { int temp; - temp = phy_read(mii_info, MII_M1111_PHY_EXT_CR); - if (iface == RGMII_ID) { + temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_CR); + if (iface == PHY_INTERFACE_MODE_RGMII_ID) { temp |= MII_M1111_RX_DELAY | MII_M1111_TX_DELAY; - } else if (iface == RGMII_RXID) { + } else if (iface == PHY_INTERFACE_MODE_RGMII_RXID) { temp &= ~MII_M1111_TX_DELAY; temp |= MII_M1111_RX_DELAY; - } else if (iface == RGMII_TXID) { + } else if (iface == PHY_INTERFACE_MODE_RGMII_TXID) { temp &= ~MII_M1111_RX_DELAY; temp |= MII_M1111_TX_DELAY; } - phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp); + uec_phy_write(mii_info, MII_M1111_PHY_EXT_CR, temp); - temp = phy_read(mii_info, MII_M1111_PHY_EXT_SR); + temp = uec_phy_read(mii_info, MII_M1111_PHY_EXT_SR); temp &= ~MII_M1111_HWCFG_MODE_MASK; temp |= MII_M1111_HWCFG_MODE_RGMII; - phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp); + uec_phy_write(mii_info, MII_M1111_PHY_EXT_SR, temp); - phy_write(mii_info, MII_BMCR, BMCR_RESET); + uec_phy_write(mii_info, MII_BMCR, BMCR_RESET); } return 0; @@ -534,7 +536,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info) if (mii_info->autoneg && mii_info->link) { int speed; - status = phy_read (mii_info, MII_M1011_PHY_SPEC_STATUS); + status = uec_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); /* Get the duplexity */ if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) @@ -564,7 +566,7 @@ static int marvell_read_status (struct uec_mii_info *mii_info) static int marvell_ack_interrupt (struct uec_mii_info *mii_info) { /* Clear the interrupts by reading the reg */ - phy_read (mii_info, MII_M1011_IEVENT); + uec_phy_read(mii_info, MII_M1011_IEVENT); return 0; } @@ -572,9 +574,10 @@ static int marvell_ack_interrupt (struct uec_mii_info *mii_info) static int marvell_config_intr (struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); + uec_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); else - phy_write (mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + uec_phy_write(mii_info, MII_M1011_IMASK, + MII_M1011_IMASK_CLEAR); return 0; } @@ -582,13 +585,13 @@ static int marvell_config_intr (struct uec_mii_info *mii_info) static int dm9161_init (struct uec_mii_info *mii_info) { /* Reset the PHY */ - phy_write (mii_info, MII_BMCR, phy_read (mii_info, MII_BMCR) | + uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) | BMCR_RESET); /* PHY and MAC connect */ - phy_write (mii_info, MII_BMCR, phy_read (mii_info, MII_BMCR) & + uec_phy_write(mii_info, MII_BMCR, uec_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); - phy_write (mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); + uec_phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); config_genmii_advert (mii_info); /* Start/restart aneg */ @@ -614,7 +617,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info) /* If the link is up, read the speed and duplex If we aren't autonegotiating assume speeds are as set */ if (mii_info->autoneg && mii_info->link) { - status = phy_read (mii_info, MII_DM9161_SCSR); + status = uec_phy_read(mii_info, MII_DM9161_SCSR); if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) mii_info->speed = SPEED_100; else @@ -632,7 +635,7 @@ static int dm9161_read_status (struct uec_mii_info *mii_info) static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) { /* Clear the interrupt by reading the reg */ - phy_read (mii_info, MII_DM9161_INTR); + uec_phy_read(mii_info, MII_DM9161_INTR); return 0; } @@ -640,9 +643,9 @@ static int dm9161_ack_interrupt (struct uec_mii_info *mii_info) static int dm9161_config_intr (struct uec_mii_info *mii_info) { if (mii_info->interrupts == MII_INTERRUPT_ENABLED) - phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); + uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); else - phy_write (mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + uec_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); return 0; } @@ -696,7 +699,7 @@ static int smsc_read_status (struct uec_mii_info *mii_info) if (mii_info->autoneg && mii_info->link) { int val; - status = phy_read (mii_info, 0x1f); + status = uec_phy_read(mii_info, 0x1f); val = (status & 0x1c) >> 2; switch (val) { @@ -751,7 +754,7 @@ static struct phy_info phy_info_marvell = { .phy_id_mask = 0xffffff00, .name = "Marvell 88E11x1", .features = MII_GBIT_FEATURES, - .init = &marvell_init, + .init = &uec_marvell_init, .config_aneg = &marvell_config_aneg, .read_status = &marvell_read_status, .ack_interrupt = &marvell_ack_interrupt, @@ -804,12 +807,12 @@ static struct phy_info *phy_info[] = { NULL }; -u16 phy_read (struct uec_mii_info *mii_info, u16 regnum) +u16 uec_phy_read(struct uec_mii_info *mii_info, u16 regnum) { return mii_info->mdio_read (mii_info->dev, mii_info->mii_id, regnum); } -void phy_write (struct uec_mii_info *mii_info, u16 regnum, u16 val) +void uec_phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val) { mii_info->mdio_write (mii_info->dev, mii_info->mii_id, regnum, val); } @@ -825,11 +828,11 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) struct phy_info *theInfo = NULL; /* Grab the bits from PHYIR1, and put them in the upper half */ - phy_reg = phy_read (mii_info, MII_PHYSID1); + phy_reg = uec_phy_read(mii_info, MII_PHYSID1); phy_ID = (phy_reg & 0xffff) << 16; /* Grab the bits from PHYIR2, and put them in the lower half */ - phy_reg = phy_read (mii_info, MII_PHYSID2); + phy_reg = uec_phy_read(mii_info, MII_PHYSID2); phy_ID |= (phy_reg & 0xffff); /* loop through all the known PHY types, and find one that */ @@ -852,10 +855,8 @@ struct phy_info *uec_get_phy_info (struct uec_mii_info *mii_info) return theInfo; } -void marvell_phy_interface_mode (struct eth_device *dev, - enum fsl_phy_enet_if type, - int speed - ) +void marvell_phy_interface_mode(struct eth_device *dev, phy_interface_t type, + int speed) { uec_private_t *uec = (uec_private_t *) dev->priv; struct uec_mii_info *mii_info; @@ -867,47 +868,47 @@ void marvell_phy_interface_mode (struct eth_device *dev, } mii_info = uec->mii_info; - if (type == RGMII) { - if (speed == 100) { - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x1d, 0x001f); - phy_write (mii_info, 0x1e, 0x200c); - phy_write (mii_info, 0x1d, 0x0005); - phy_write (mii_info, 0x1e, 0x0000); - phy_write (mii_info, 0x1e, 0x0100); - phy_write (mii_info, 0x09, 0x0e00); - phy_write (mii_info, 0x04, 0x01e1); - phy_write (mii_info, 0x00, 0x9140); - phy_write (mii_info, 0x00, 0x1000); + if (type == PHY_INTERFACE_MODE_RGMII) { + if (speed == SPEED_100) { + uec_phy_write(mii_info, 0x00, 0x9140); + uec_phy_write(mii_info, 0x1d, 0x001f); + uec_phy_write(mii_info, 0x1e, 0x200c); + uec_phy_write(mii_info, 0x1d, 0x0005); + uec_phy_write(mii_info, 0x1e, 0x0000); + uec_phy_write(mii_info, 0x1e, 0x0100); + uec_phy_write(mii_info, 0x09, 0x0e00); + uec_phy_write(mii_info, 0x04, 0x01e1); + uec_phy_write(mii_info, 0x00, 0x9140); + uec_phy_write(mii_info, 0x00, 0x1000); udelay (100000); - phy_write (mii_info, 0x00, 0x2900); - phy_write (mii_info, 0x14, 0x0cd2); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x09, 0x0000); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x04, 0x05e1); - phy_write (mii_info, 0x00, 0xa100); - phy_write (mii_info, 0x00, 0x2100); + uec_phy_write(mii_info, 0x00, 0x2900); + uec_phy_write(mii_info, 0x14, 0x0cd2); + uec_phy_write(mii_info, 0x00, 0xa100); + uec_phy_write(mii_info, 0x09, 0x0000); + uec_phy_write(mii_info, 0x1b, 0x800b); + uec_phy_write(mii_info, 0x04, 0x05e1); + uec_phy_write(mii_info, 0x00, 0xa100); + uec_phy_write(mii_info, 0x00, 0x2100); udelay (1000000); - } else if (speed == 10) { - phy_write (mii_info, 0x14, 0x8e40); - phy_write (mii_info, 0x1b, 0x800b); - phy_write (mii_info, 0x14, 0x0c82); - phy_write (mii_info, 0x00, 0x8100); + } else if (speed == SPEED_10) { + uec_phy_write(mii_info, 0x14, 0x8e40); + uec_phy_write(mii_info, 0x1b, 0x800b); + uec_phy_write(mii_info, 0x14, 0x0c82); + uec_phy_write(mii_info, 0x00, 0x8100); udelay (1000000); } } /* handle 88e1111 rev.B2 erratum 5.6 */ if (mii_info->autoneg) { - status = phy_read (mii_info, MII_BMCR); - phy_write (mii_info, MII_BMCR, status | BMCR_ANENABLE); + status = uec_phy_read(mii_info, MII_BMCR); + uec_phy_write(mii_info, MII_BMCR, status | BMCR_ANENABLE); } /* now the B2 will correctly report autoneg completion status */ } void change_phy_interface_mode (struct eth_device *dev, - enum fsl_phy_enet_if type, int speed) + phy_interface_t type, int speed) { #ifdef CONFIG_PHY_MODE_NEED_CHANGE marvell_phy_interface_mode (dev, type, speed); diff --git a/include/config_phylib_all_drivers.h b/include/config_phylib_all_drivers.h new file mode 100644 index 0000000..903c7a7 --- /dev/null +++ b/include/config_phylib_all_drivers.h @@ -0,0 +1,32 @@ +/* + * Enable all PHYs + * + * This software may be used and distributed according to the + * terms of the GNU Public License, Version 2, incorporated + * herein by reference. + * + * Copyright 2011 Freescale Semiconductor, Inc. + * author Andy Fleming + * + */ +#ifndef _CONFIG_PHYLIB_ALL_H +#define _CONFIG_PHYLIB_ALL_H + +#ifdef CONFIG_PHYLIB + +#define CONFIG_PHY_VITESSE +#define CONFIG_PHY_MARVELL +#define CONFIG_PHY_MICREL +#define CONFIG_PHY_BROADCOM +#define CONFIG_PHY_DAVICOM +#define CONFIG_PHY_REALTEK +#define CONFIG_PHY_NATSEMI +#define CONFIG_PHY_LXT + +#ifdef CONFIG_PHYLIB_10G +#define CONFIG_PHY_TERANETICS +#endif /* CONFIG_PHYLIB_10G */ + +#endif /* CONFIG_PHYLIB */ + +#endif /*_CONFIG_PHYLIB_ALL_H */ diff --git a/include/configs/MPC8323ERDB.h b/include/configs/MPC8323ERDB.h index 1191eea..e25d5ac 100644 --- a/include/configs/MPC8323ERDB.h +++ b/include/configs/MPC8323ERDB.h @@ -348,7 +348,7 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK10 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 4 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_MII #define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif @@ -360,7 +360,7 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK3 #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 0 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_MII #define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h index affa3a9..f136a8e 100644 --- a/include/configs/MPC832XEMDS.h +++ b/include/configs/MPC832XEMDS.h @@ -361,7 +361,7 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK10 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 3 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_MII #define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif @@ -373,7 +373,7 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK8 #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 4 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE MII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_MII #define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif diff --git a/include/configs/MPC8360EMDS.h b/include/configs/MPC8360EMDS.h index a959940..49d64a5 100644 --- a/include/configs/MPC8360EMDS.h +++ b/include/configs/MPC8360EMDS.h @@ -402,7 +402,7 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK9 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 0 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif @@ -414,7 +414,7 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK4 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif diff --git a/include/configs/MPC8360ERDK.h b/include/configs/MPC8360ERDK.h index b0cdc02..a4f42cf 100644 --- a/include/configs/MPC8360ERDK.h +++ b/include/configs/MPC8360ERDK.h @@ -319,7 +319,7 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK9 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 2 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_RXID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_RXID #define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif @@ -331,7 +331,7 @@ #define CONFIG_SYS_UEC2_TX_CLK QE_CLK4 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 4 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_RXID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_RXID #define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif diff --git a/include/configs/MPC8568MDS.h b/include/configs/MPC8568MDS.h index 3674e49..6237b23 100644 --- a/include/configs/MPC8568MDS.h +++ b/include/configs/MPC8568MDS.h @@ -334,7 +334,7 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC1_TX_CLK QE_CLK16 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 7 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #endif @@ -346,7 +346,7 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC2_TX_CLK QE_CLK16 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #endif #endif /* CONFIG_QE */ diff --git a/include/configs/MPC8569MDS.h b/include/configs/MPC8569MDS.h index 5a7e99e..8835ef5 100644 --- a/include/configs/MPC8569MDS.h +++ b/include/configs/MPC8569MDS.h @@ -385,13 +385,13 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC1_TX_CLK QE_CLK12 #define CONFIG_SYS_UEC1_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 7 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC1_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC1_TX_CLK QE_CLK16 /* CLK16 for RMII */ #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 8 /* 0x8 for RMII */ -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RMII #define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH1 */ @@ -406,13 +406,13 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC2_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC2_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 1 -#define CONFIG_SYS_UEC2_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC2_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC2_TX_CLK QE_CLK16 /* CLK 16 for RMII */ #define CONFIG_SYS_UEC2_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC2_PHY_ADDR 0x9 /* 0x9 for RMII */ -#define CONFIG_SYS_UEC2_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC2_INTERFACE_TYPE PHY_INTERFACE_MODE_RMII #define CONFIG_SYS_UEC2_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH2 */ @@ -427,13 +427,13 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC3_TX_CLK QE_CLK12 #define CONFIG_SYS_UEC3_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC3_PHY_ADDR 2 -#define CONFIG_SYS_UEC3_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC3_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC3_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC3_TX_CLK QE_CLK16 /* CLK_16 for RMII */ #define CONFIG_SYS_UEC3_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC3_PHY_ADDR 0xA /* 0xA for RMII */ -#define CONFIG_SYS_UEC3_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC3_INTERFACE_TYPE PHY_INTERFACE_MODE_RMII #define CONFIG_SYS_UEC3_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH3 */ @@ -448,13 +448,13 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC4_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC4_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC4_PHY_ADDR 3 -#define CONFIG_SYS_UEC4_INTERFACE_TYPE RGMII_ID +#define CONFIG_SYS_UEC4_INTERFACE_TYPE PHY_INTERFACE_MODE_RGMII_ID #define CONFIG_SYS_UEC4_INTERFACE_SPEED 1000 #elif defined(CONFIG_SYS_UCC_RMII_MODE) #define CONFIG_SYS_UEC4_TX_CLK QE_CLK16 /* CLK16 for RMII */ #define CONFIG_SYS_UEC4_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC4_PHY_ADDR 0xB /* 0xB for RMII */ -#define CONFIG_SYS_UEC4_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC4_INTERFACE_TYPE PHY_INTERFACE_MODE_RMII #define CONFIG_SYS_UEC4_INTERFACE_SPEED 100 #endif /* CONFIG_SYS_UCC_RGMII_MODE */ #endif /* CONFIG_UEC_ETH4 */ @@ -468,7 +468,7 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC6_TX_CLK QE_CLK_NONE #define CONFIG_SYS_UEC6_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC6_PHY_ADDR 4 -#define CONFIG_SYS_UEC6_INTERFACE_TYPE SGMII +#define CONFIG_SYS_UEC6_INTERFACE_TYPE PHY_INTERFACE_MODE_SGMII #define CONFIG_SYS_UEC6_INTERFACE_SPEED 1000 #endif /* CONFIG_UEC_ETH6 */ @@ -481,7 +481,7 @@ extern unsigned long get_clock_freq(void); #define CONFIG_SYS_UEC8_TX_CLK QE_CLK_NONE #define CONFIG_SYS_UEC8_ETH_TYPE GIGA_ETH #define CONFIG_SYS_UEC8_PHY_ADDR 6 -#define CONFIG_SYS_UEC8_INTERFACE_TYPE SGMII +#define CONFIG_SYS_UEC8_INTERFACE_TYPE PHY_INTERFACE_MODE_SGMII #define CONFIG_SYS_UEC8_INTERFACE_SPEED 1000 #endif /* CONFIG_UEC_ETH8 */ diff --git a/include/configs/kmeter1.h b/include/configs/kmeter1.h index 8fcadfe..b98e6a1 100644 --- a/include/configs/kmeter1.h +++ b/include/configs/kmeter1.h @@ -295,7 +295,7 @@ #define CONFIG_SYS_UEC1_TX_CLK QE_CLK17 #define CONFIG_SYS_UEC1_ETH_TYPE FAST_ETH #define CONFIG_SYS_UEC1_PHY_ADDR 0 -#define CONFIG_SYS_UEC1_INTERFACE_TYPE RMII +#define CONFIG_SYS_UEC1_INTERFACE_TYPE PHY_INTERFACE_MODE_RMII #define CONFIG_SYS_UEC1_INTERFACE_SPEED 100 #endif diff --git a/include/fsl_mdio.h b/include/fsl_mdio.h new file mode 100644 index 0000000..17ca79c --- /dev/null +++ b/include/fsl_mdio.h @@ -0,0 +1,62 @@ +/* + * Copyright 2009-2010 Freescale Semiconductor, Inc. + * Jun-jie Zhang <b18070@freescale.com> + * Mingkai Hu <Mingkai.hu@freescale.com> + * + * 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 + */ +#ifndef __FSL_PHY_H__ +#define __FSL_PHY_H__ + +#include <net.h> +#include <miiphy.h> +#include <asm/fsl_enet.h> + +/* PHY register offsets */ +#define PHY_EXT_PAGE_ACCESS 0x1f + +/* MII Management Configuration Register */ +#define MIIMCFG_RESET_MGMT 0x80000000 +#define MIIMCFG_MGMT_CLOCK_SELECT 0x00000007 +#define MIIMCFG_INIT_VALUE 0x00000003 + +/* MII Management Command Register */ +#define MIIMCOM_READ_CYCLE 0x00000001 +#define MIIMCOM_SCAN_CYCLE 0x00000002 + +/* MII Management Address Register */ +#define MIIMADD_PHY_ADDR_SHIFT 8 + +/* MII Management Indicator Register */ +#define MIIMIND_BUSY 0x00000001 +#define MIIMIND_NOTVALID 0x00000004 + +void tsec_local_mdio_write(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int reg, int value); +int tsec_local_mdio_read(struct tsec_mii_mng *phyregs, int port_addr, + int dev_addr, int regnum); +int tsec_phy_read(struct mii_dev *bus, int addr, int dev_addr, int regnum); +int tsec_phy_write(struct mii_dev *bus, int addr, int dev_addr, int regnum, + u16 value); + +struct fsl_pq_mdio_info { + struct tsec_mii_mng *regs; + char *name; +}; +int fsl_pq_mdio_init(bd_t *bis, struct fsl_pq_mdio_info *info); + +#endif /* __FSL_PHY_H__ */ + diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h new file mode 100644 index 0000000..fcb20fe --- /dev/null +++ b/include/linux/ethtool.h @@ -0,0 +1,721 @@ +/* + * ethtool.h: Defines for Linux ethtool. + * + * Copyright (C) 1998 David S. Miller (davem@redhat.com) + * Copyright 2001 Jeff Garzik <jgarzik@pobox.com> + * Portions Copyright 2001 Sun Microsystems (thockin@sun.com) + * Portions Copyright 2002 Intel (eli.kupermann@intel.com, + * christopher.leech@intel.com, + * scott.feldman@intel.com) + * Portions Copyright (C) Sun Microsystems 2008 + */ + +#ifndef _LINUX_ETHTOOL_H +#define _LINUX_ETHTOOL_H + +#include <linux/types.h> + +/* This should work for both 32 and 64 bit userland. */ +struct ethtool_cmd { + __u32 cmd; + __u32 supported; /* Features this interface supports */ + __u32 advertising; /* Features this interface advertises */ + __u16 speed; /* The forced speed, 10Mb, 100Mb, gigabit */ + __u8 duplex; /* Duplex, half or full */ + __u8 port; /* Which connector port */ + __u8 phy_address; + __u8 transceiver; /* Which transceiver to use */ + __u8 autoneg; /* Enable or disable autonegotiation */ + __u8 mdio_support; + __u32 maxtxpkt; /* Tx pkts before generating tx int */ + __u32 maxrxpkt; /* Rx pkts before generating rx int */ + __u16 speed_hi; + __u8 eth_tp_mdix; + __u8 reserved2; + __u32 lp_advertising; /* Features the link partner advertises */ + __u32 reserved[2]; +}; + +static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, + __u32 speed) +{ + + ep->speed = (__u16)speed; + ep->speed_hi = (__u16)(speed >> 16); +} + +static inline __u32 ethtool_cmd_speed(struct ethtool_cmd *ep) +{ + return (ep->speed_hi << 16) | ep->speed; +} + +#define ETHTOOL_FWVERS_LEN 32 +#define ETHTOOL_BUSINFO_LEN 32 +/* these strings are set to whatever the driver author decides... */ +struct ethtool_drvinfo { + __u32 cmd; + char driver[32]; /* driver short name, "tulip", "eepro100" */ + char version[32]; /* driver version string */ + char fw_version[ETHTOOL_FWVERS_LEN]; /* firmware version string */ + char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */ + /* For PCI devices, use pci_name(pci_dev). */ + char reserved1[32]; + char reserved2[12]; + /* + * Some struct members below are filled in + * using ops->get_sset_count(). Obtaining + * this info from ethtool_drvinfo is now + * deprecated; Use ETHTOOL_GSSET_INFO + * instead. + */ + __u32 n_priv_flags; /* number of flags valid in ETHTOOL_GPFLAGS */ + __u32 n_stats; /* number of u64's from ETHTOOL_GSTATS */ + __u32 testinfo_len; + __u32 eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ + __u32 regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ +}; + +#define SOPASS_MAX 6 +/* wake-on-lan settings */ +struct ethtool_wolinfo { + __u32 cmd; + __u32 supported; + __u32 wolopts; + __u8 sopass[SOPASS_MAX]; /* SecureOn(tm) password */ +}; + +/* for passing single values */ +struct ethtool_value { + __u32 cmd; + __u32 data; +}; + +/* for passing big chunks of data */ +struct ethtool_regs { + __u32 cmd; + __u32 version; /* driver-specific, indicates different chips/revs */ + __u32 len; /* bytes */ + __u8 data[0]; +}; + +/* for passing EEPROM chunks */ +struct ethtool_eeprom { + __u32 cmd; + __u32 magic; + __u32 offset; /* in bytes */ + __u32 len; /* in bytes */ + __u8 data[0]; +}; + +/* for configuring coalescing parameters of chip */ +struct ethtool_coalesce { + __u32 cmd; /* ETHTOOL_{G,S}COALESCE */ + + /* How many usecs to delay an RX interrupt after + * a packet arrives. If 0, only rx_max_coalesced_frames + * is used. + */ + __u32 rx_coalesce_usecs; + + /* How many packets to delay an RX interrupt after + * a packet arrives. If 0, only rx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause RX interrupts to never be + * generated. + */ + __u32 rx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + __u32 rx_coalesce_usecs_irq; + __u32 rx_max_coalesced_frames_irq; + + /* How many usecs to delay a TX interrupt after + * a packet is sent. If 0, only tx_max_coalesced_frames + * is used. + */ + __u32 tx_coalesce_usecs; + + /* How many packets to delay a TX interrupt after + * a packet is sent. If 0, only tx_coalesce_usecs is + * used. It is illegal to set both usecs and max frames + * to zero as this would cause TX interrupts to never be + * generated. + */ + __u32 tx_max_coalesced_frames; + + /* Same as above two parameters, except that these values + * apply while an IRQ is being serviced by the host. Not + * all cards support this feature and the values are ignored + * in that case. + */ + __u32 tx_coalesce_usecs_irq; + __u32 tx_max_coalesced_frames_irq; + + /* How many usecs to delay in-memory statistics + * block updates. Some drivers do not have an in-memory + * statistic block, and in such cases this value is ignored. + * This value must not be zero. + */ + __u32 stats_block_coalesce_usecs; + + /* Adaptive RX/TX coalescing is an algorithm implemented by + * some drivers to improve latency under low packet rates and + * improve throughput under high packet rates. Some drivers + * only implement one of RX or TX adaptive coalescing. Anything + * not implemented by the driver causes these values to be + * silently ignored. + */ + __u32 use_adaptive_rx_coalesce; + __u32 use_adaptive_tx_coalesce; + + /* When the packet rate (measured in packets per second) + * is below pkt_rate_low, the {rx,tx}_*_low parameters are + * used. + */ + __u32 pkt_rate_low; + __u32 rx_coalesce_usecs_low; + __u32 rx_max_coalesced_frames_low; + __u32 tx_coalesce_usecs_low; + __u32 tx_max_coalesced_frames_low; + + /* When the packet rate is below pkt_rate_high but above + * pkt_rate_low (both measured in packets per second) the + * normal {rx,tx}_* coalescing parameters are used. + */ + + /* When the packet rate is (measured in packets per second) + * is above pkt_rate_high, the {rx,tx}_*_high parameters are + * used. + */ + __u32 pkt_rate_high; + __u32 rx_coalesce_usecs_high; + __u32 rx_max_coalesced_frames_high; + __u32 tx_coalesce_usecs_high; + __u32 tx_max_coalesced_frames_high; + + /* How often to do adaptive coalescing packet rate sampling, + * measured in seconds. Must not be zero. + */ + __u32 rate_sample_interval; +}; + +/* for configuring RX/TX ring parameters */ +struct ethtool_ringparam { + __u32 cmd; /* ETHTOOL_{G,S}RINGPARAM */ + + /* Read only attributes. These indicate the maximum number + * of pending RX/TX ring entries the driver will allow the + * user to set. + */ + __u32 rx_max_pending; + __u32 rx_mini_max_pending; + __u32 rx_jumbo_max_pending; + __u32 tx_max_pending; + + /* Values changeable by the user. The valid values are + * in the range 1 to the "*_max_pending" counterpart above. + */ + __u32 rx_pending; + __u32 rx_mini_pending; + __u32 rx_jumbo_pending; + __u32 tx_pending; +}; + +/* for configuring link flow control parameters */ +struct ethtool_pauseparam { + __u32 cmd; /* ETHTOOL_{G,S}PAUSEPARAM */ + + /* If the link is being auto-negotiated (via ethtool_cmd.autoneg + * being true) the user may set 'autonet' here non-zero to have the + * pause parameters be auto-negotiated too. In such a case, the + * {rx,tx}_pause values below determine what capabilities are + * advertised. + * + * If 'autoneg' is zero or the link is not being auto-negotiated, + * then {rx,tx}_pause force the driver to use/not-use pause + * flow control. + */ + __u32 autoneg; + __u32 rx_pause; + __u32 tx_pause; +}; + +#define ETH_GSTRING_LEN 32 +enum ethtool_stringset { + ETH_SS_TEST = 0, + ETH_SS_STATS, + ETH_SS_PRIV_FLAGS, + ETH_SS_NTUPLE_FILTERS, + ETH_SS_FEATURES, +}; + +/* for passing string sets for data tagging */ +struct ethtool_gstrings { + __u32 cmd; /* ETHTOOL_GSTRINGS */ + __u32 string_set; /* string set id e.c. ETH_SS_TEST, etc*/ + __u32 len; /* number of strings in the string set */ + __u8 data[0]; +}; + +struct ethtool_sset_info { + __u32 cmd; /* ETHTOOL_GSSET_INFO */ + __u32 reserved; + __u64 sset_mask; /* input: each bit selects an sset to query */ + /* output: each bit a returned sset */ + __u32 data[0]; /* ETH_SS_xxx count, in order, based on bits + in sset_mask. One bit implies one + __u32, two bits implies two + __u32's, etc. */ +}; + +enum ethtool_test_flags { + ETH_TEST_FL_OFFLINE = (1 << 0), /* online / offline */ + ETH_TEST_FL_FAILED = (1 << 1), /* test passed / failed */ +}; + +/* for requesting NIC test and getting results*/ +struct ethtool_test { + __u32 cmd; /* ETHTOOL_TEST */ + __u32 flags; /* ETH_TEST_FL_xxx */ + __u32 reserved; + __u32 len; /* result length, in number of u64 elements */ + __u64 data[0]; +}; + +/* for dumping NIC-specific statistics */ +struct ethtool_stats { + __u32 cmd; /* ETHTOOL_GSTATS */ + __u32 n_stats; /* number of u64's being returned */ + __u64 data[0]; +}; + +struct ethtool_perm_addr { + __u32 cmd; /* ETHTOOL_GPERMADDR */ + __u32 size; + __u8 data[0]; +}; + +/* boolean flags controlling per-interface behavior characteristics. + * When reading, the flag indicates whether or not a certain behavior + * is enabled/present. When writing, the flag indicates whether + * or not the driver should turn on (set) or off (clear) a behavior. + * + * Some behaviors may read-only (unconditionally absent or present). + * If such is the case, return EINVAL in the set-flags operation if the + * flag differs from the read-only value. + */ +enum ethtool_flags { + ETH_FLAG_TXVLAN = (1 << 7), /* TX VLAN offload enabled */ + ETH_FLAG_RXVLAN = (1 << 8), /* RX VLAN offload enabled */ + ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ + ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */ + ETH_FLAG_RXHASH = (1 << 28), +}; + +/* The following structures are for supporting RX network flow + * classification and RX n-tuple configuration. Note, all multibyte + * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to + * be in network byte order. + */ + +/** + * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc. + * @ip4src: Source host + * @ip4dst: Destination host + * @psrc: Source port + * @pdst: Destination port + * @tos: Type-of-service + * + * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow. + */ +struct ethtool_tcpip4_spec { + __be32 ip4src; + __be32 ip4dst; + __be16 psrc; + __be16 pdst; + __u8 tos; +}; + +/** + * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4 + * @ip4src: Source host + * @ip4dst: Destination host + * @spi: Security parameters index + * @tos: Type-of-service + * + * This can be used to specify an IPsec transport or tunnel over IPv4. + */ +struct ethtool_ah_espip4_spec { + __be32 ip4src; + __be32 ip4dst; + __be32 spi; + __u8 tos; +}; + +#define ETH_RX_NFC_IP4 1 + +/** + * struct ethtool_usrip4_spec - general flow specification for IPv4 + * @ip4src: Source host + * @ip4dst: Destination host + * @l4_4_bytes: First 4 bytes of transport (layer 4) header + * @tos: Type-of-service + * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0 + * @proto: Transport protocol number; mask must be 0 + */ +struct ethtool_usrip4_spec { + __be32 ip4src; + __be32 ip4dst; + __be32 l4_4_bytes; + __u8 tos; + __u8 ip_ver; + __u8 proto; +}; + + +/** + * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection + * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR + * @size: On entry, the array size of the user buffer. On return from + * %ETHTOOL_GRXFHINDIR, the array size of the hardware indirection table. + * @ring_index: RX ring/queue index for each hash value + */ +struct ethtool_rxfh_indir { + __u32 cmd; + __u32 size; + __u32 ring_index[0]; +}; + +#define ETHTOOL_FLASH_MAX_FILENAME 128 +enum ethtool_flash_op_type { + ETHTOOL_FLASH_ALL_REGIONS = 0, +}; + +/* for passing firmware flashing related parameters */ +struct ethtool_flash { + __u32 cmd; + __u32 region; + char data[ETHTOOL_FLASH_MAX_FILENAME]; +}; + +/* for returning and changing feature sets */ + +/** + * struct ethtool_get_features_block - block with state of 32 features + * @available: mask of changeable features + * @requested: mask of features requested to be enabled if possible + * @active: mask of currently enabled features + * @never_changed: mask of features not changeable for any device + */ +struct ethtool_get_features_block { + __u32 available; + __u32 requested; + __u32 active; + __u32 never_changed; +}; + +/** + * struct ethtool_gfeatures - command to get state of device's features + * @cmd: command number = %ETHTOOL_GFEATURES + * @size: in: number of elements in the features[] array; + * out: number of elements in features[] needed to hold all features + * @features: state of features + */ +struct ethtool_gfeatures { + __u32 cmd; + __u32 size; + struct ethtool_get_features_block features[0]; +}; + +/** + * struct ethtool_set_features_block - block with request for 32 features + * @valid: mask of features to be changed + * @requested: values of features to be changed + */ +struct ethtool_set_features_block { + __u32 valid; + __u32 requested; +}; + +/** + * struct ethtool_sfeatures - command to request change in device's features + * @cmd: command number = %ETHTOOL_SFEATURES + * @size: array size of the features[] array + * @features: feature change masks + */ +struct ethtool_sfeatures { + __u32 cmd; + __u32 size; + struct ethtool_set_features_block features[0]; +}; + +/* + * %ETHTOOL_SFEATURES changes features present in features[].valid to the + * values of corresponding bits in features[].requested. Bits in .requested + * not set in .valid or not changeable are ignored. + * + * Returns %EINVAL when .valid contains undefined or never-changable bits + * or size is not equal to required number of features words (32-bit blocks). + * Returns >= 0 if request was completed; bits set in the value mean: + * %ETHTOOL_F_UNSUPPORTED - there were bits set in .valid that are not + * changeable (not present in %ETHTOOL_GFEATURES' features[].available) + * those bits were ignored. + * %ETHTOOL_F_WISH - some or all changes requested were recorded but the + * resulting state of bits masked by .valid is not equal to .requested. + * Probably there are other device-specific constraints on some features + * in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered + * here as though ignored bits were cleared. + * %ETHTOOL_F_COMPAT - some or all changes requested were made by calling + * compatibility functions. Requested offload state cannot be properly + * managed by kernel. + * + * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of + * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands + * for ETH_SS_FEATURES string set. First entry in the table corresponds to least + * significant bit in features[0] fields. Empty strings mark undefined features. + */ +enum ethtool_sfeatures_retval_bits { + ETHTOOL_F_UNSUPPORTED__BIT, + ETHTOOL_F_WISH__BIT, + ETHTOOL_F_COMPAT__BIT, +}; + +#define ETHTOOL_F_UNSUPPORTED (1 << ETHTOOL_F_UNSUPPORTED__BIT) +#define ETHTOOL_F_WISH (1 << ETHTOOL_F_WISH__BIT) +#define ETHTOOL_F_COMPAT (1 << ETHTOOL_F_COMPAT__BIT) + +/* CMDs currently supported */ +#define ETHTOOL_GSET 0x00000001 /* Get settings. */ +#define ETHTOOL_SSET 0x00000002 /* Set settings. */ +#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ +#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers. */ +#define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */ +#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options. */ +#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ +#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */ +#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation. */ +/* Get link status for host, i.e. whether the interface *and* the + * physical port (if there is one) are up (ethtool_value). */ +#define ETHTOOL_GLINK 0x0000000a +#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ +#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */ +#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ +#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ +#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ +#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters. */ +#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ +#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ +#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ +#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ +#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ +#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ +#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable + * (ethtool_value) */ +#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable + * (ethtool_value). */ +#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test. */ +#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ +#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ +#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ +#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ +#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ +#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */ +#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ +#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ +#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ +#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ +#define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */ +#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */ +#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */ +#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */ + +#define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */ +#define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */ +#define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */ +#define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */ +#define ETHTOOL_GRXRINGS 0x0000002d /* Get RX rings available for LB */ +#define ETHTOOL_GRXCLSRLCNT 0x0000002e /* Get RX class rule count */ +#define ETHTOOL_GRXCLSRULE 0x0000002f /* Get RX classification rule */ +#define ETHTOOL_GRXCLSRLALL 0x00000030 /* Get all RX classification rule */ +#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ +#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ +#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ +#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ +#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ +#define ETHTOOL_GRXNTUPLE 0x00000036 /* Get n-tuple filters from device */ +#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */ +#define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */ +#define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */ + +#define ETHTOOL_GFEATURES 0x0000003a /* Get device offload settings */ +#define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ + +/* compatibility with older code */ +#define SPARC_ETH_GSET ETHTOOL_GSET +#define SPARC_ETH_SSET ETHTOOL_SSET + +/* Indicates what features are supported by the interface. */ +#define SUPPORTED_10baseT_Half (1 << 0) +#define SUPPORTED_10baseT_Full (1 << 1) +#define SUPPORTED_100baseT_Half (1 << 2) +#define SUPPORTED_100baseT_Full (1 << 3) +#define SUPPORTED_1000baseT_Half (1 << 4) +#define SUPPORTED_1000baseT_Full (1 << 5) +#define SUPPORTED_Autoneg (1 << 6) +#define SUPPORTED_TP (1 << 7) +#define SUPPORTED_AUI (1 << 8) +#define SUPPORTED_MII (1 << 9) +#define SUPPORTED_FIBRE (1 << 10) +#define SUPPORTED_BNC (1 << 11) +#define SUPPORTED_10000baseT_Full (1 << 12) +#define SUPPORTED_Pause (1 << 13) +#define SUPPORTED_Asym_Pause (1 << 14) +#define SUPPORTED_2500baseX_Full (1 << 15) +#define SUPPORTED_Backplane (1 << 16) +#define SUPPORTED_1000baseKX_Full (1 << 17) +#define SUPPORTED_10000baseKX4_Full (1 << 18) +#define SUPPORTED_10000baseKR_Full (1 << 19) +#define SUPPORTED_10000baseR_FEC (1 << 20) + +/* Indicates what features are advertised by the interface. */ +#define ADVERTISED_10baseT_Half (1 << 0) +#define ADVERTISED_10baseT_Full (1 << 1) +#define ADVERTISED_100baseT_Half (1 << 2) +#define ADVERTISED_100baseT_Full (1 << 3) +#define ADVERTISED_1000baseT_Half (1 << 4) +#define ADVERTISED_1000baseT_Full (1 << 5) +#define ADVERTISED_Autoneg (1 << 6) +#define ADVERTISED_TP (1 << 7) +#define ADVERTISED_AUI (1 << 8) +#define ADVERTISED_MII (1 << 9) +#define ADVERTISED_FIBRE (1 << 10) +#define ADVERTISED_BNC (1 << 11) +#define ADVERTISED_10000baseT_Full (1 << 12) +#define ADVERTISED_Pause (1 << 13) +#define ADVERTISED_Asym_Pause (1 << 14) +#define ADVERTISED_2500baseX_Full (1 << 15) +#define ADVERTISED_Backplane (1 << 16) +#define ADVERTISED_1000baseKX_Full (1 << 17) +#define ADVERTISED_10000baseKX4_Full (1 << 18) +#define ADVERTISED_10000baseKR_Full (1 << 19) +#define ADVERTISED_10000baseR_FEC (1 << 20) + +/* The following are all involved in forcing a particular link + * mode for the device for setting things. When getting the + * devices settings, these indicate the current mode and whether + * it was foced up into this mode or autonegotiated. + */ + +/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */ +#define SPEED_10 10 +#define SPEED_100 100 +#define SPEED_1000 1000 +#define SPEED_2500 2500 +#define SPEED_10000 10000 + +/* Duplex, half or full. */ +#define DUPLEX_HALF 0x00 +#define DUPLEX_FULL 0x01 + +/* Which connector port. */ +#define PORT_TP 0x00 +#define PORT_AUI 0x01 +#define PORT_MII 0x02 +#define PORT_FIBRE 0x03 +#define PORT_BNC 0x04 +#define PORT_DA 0x05 +#define PORT_NONE 0xef +#define PORT_OTHER 0xff + +/* Which transceiver to use. */ +#define XCVR_INTERNAL 0x00 +#define XCVR_EXTERNAL 0x01 +#define XCVR_DUMMY1 0x02 +#define XCVR_DUMMY2 0x03 +#define XCVR_DUMMY3 0x04 + +/* Enable or disable autonegotiation. If this is set to enable, + * the forced link modes above are completely ignored. + */ +#define AUTONEG_DISABLE 0x00 +#define AUTONEG_ENABLE 0x01 + +/* Mode MDI or MDI-X */ +#define ETH_TP_MDI_INVALID 0x00 +#define ETH_TP_MDI 0x01 +#define ETH_TP_MDI_X 0x02 + +/* Wake-On-Lan options. */ +#define WAKE_PHY (1 << 0) +#define WAKE_UCAST (1 << 1) +#define WAKE_MCAST (1 << 2) +#define WAKE_BCAST (1 << 3) +#define WAKE_ARP (1 << 4) +#define WAKE_MAGIC (1 << 5) +#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */ + +/* L2-L4 network traffic flow types */ +#define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */ +#define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */ +#define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */ +#define AH_ESP_V4_FLOW 0x04 /* hash only */ +#define TCP_V6_FLOW 0x05 /* hash only */ +#define UDP_V6_FLOW 0x06 /* hash only */ +#define SCTP_V6_FLOW 0x07 /* hash only */ +#define AH_ESP_V6_FLOW 0x08 /* hash only */ +#define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */ +#define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */ +#define AH_V6_FLOW 0x0b /* hash only */ +#define ESP_V6_FLOW 0x0c /* hash only */ +#define IP_USER_FLOW 0x0d /* spec only (usr_ip4_spec) */ +#define IPV4_FLOW 0x10 /* hash only */ +#define IPV6_FLOW 0x11 /* hash only */ +#define ETHER_FLOW 0x12 /* spec only (ether_spec) */ + +/* L3-L4 network traffic flow hash options */ +#define RXH_L2DA (1 << 1) +#define RXH_VLAN (1 << 2) +#define RXH_L3_PROTO (1 << 3) +#define RXH_IP_SRC (1 << 4) +#define RXH_IP_DST (1 << 5) +#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ +#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ +#define RXH_DISCARD (1 << 31) + +#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL + +/* Reset flags */ +/* The reset() operation must clear the flags for the components which + * were actually reset. On successful return, the flags indicate the + * components which were not reset, either because they do not exist + * in the hardware or because they cannot be reset independently. The + * driver must never reset any components that were not requested. + */ +enum ethtool_reset_flags { + /* These flags represent components dedicated to the interface + * the command is addressed to. Shift any flag left by + * ETH_RESET_SHARED_SHIFT to reset a shared component of the + * same type. + */ + ETH_RESET_MGMT = 1 << 0, /* Management processor */ + ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */ + ETH_RESET_DMA = 1 << 2, /* DMA engine */ + ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */ + ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */ + ETH_RESET_MAC = 1 << 5, /* Media access controller */ + ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */ + ETH_RESET_RAM = 1 << 7, /* RAM shared between + * multiple components */ + + ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to + * this interface */ + ETH_RESET_ALL = 0xffffffff, /* All components used by this + * interface, even if shared */ +}; +#define ETH_RESET_SHARED_SHIFT 16 + +#endif /* _LINUX_ETHTOOL_H */ diff --git a/include/linux/mdio.h b/include/linux/mdio.h new file mode 100644 index 0000000..022d772 --- /dev/null +++ b/include/linux/mdio.h @@ -0,0 +1,278 @@ +/* + * linux/mdio.h: definitions for MDIO (clause 45) transceivers + * Copyright 2006-2009 Solarflare Communications Inc. + * + * 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, incorporated herein by reference. + */ + +#ifndef __LINUX_MDIO_H__ +#define __LINUX_MDIO_H__ + +#include <linux/mii.h> + +/* MDIO Manageable Devices (MMDs). */ +#define MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/ + * Physical Medium Dependent */ +#define MDIO_MMD_WIS 2 /* WAN Interface Sublayer */ +#define MDIO_MMD_PCS 3 /* Physical Coding Sublayer */ +#define MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */ +#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */ +#define MDIO_MMD_TC 6 /* Transmission Convergence */ +#define MDIO_MMD_AN 7 /* Auto-Negotiation */ +#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */ +#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */ +#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */ + +/* Generic MDIO registers. */ +#define MDIO_CTRL1 MII_BMCR +#define MDIO_STAT1 MII_BMSR +#define MDIO_DEVID1 MII_PHYSID1 +#define MDIO_DEVID2 MII_PHYSID2 +#define MDIO_SPEED 4 /* Speed ability */ +#define MDIO_DEVS1 5 /* Devices in package */ +#define MDIO_DEVS2 6 +#define MDIO_CTRL2 7 /* 10G control 2 */ +#define MDIO_STAT2 8 /* 10G status 2 */ +#define MDIO_PMA_TXDIS 9 /* 10G PMA/PMD transmit disable */ +#define MDIO_PMA_RXDET 10 /* 10G PMA/PMD receive signal detect */ +#define MDIO_PMA_EXTABLE 11 /* 10G PMA/PMD extended ability */ +#define MDIO_PKGID1 14 /* Package identifier */ +#define MDIO_PKGID2 15 +#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */ +#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */ +#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ + +/* Media-dependent registers. */ +#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ +#define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ +#define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. + * Lanes B-D are numbered 134-136. */ +#define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */ +#define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ +#define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ +#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ +#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */ +#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */ +#define MDIO_AN_EEE_ADV 60 /* EEE advertisement */ + +/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */ +#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */ +#define MDIO_PMA_LASI_TXCTRL 0x9001 /* TX_ALARM control */ +#define MDIO_PMA_LASI_CTRL 0x9002 /* LASI control */ +#define MDIO_PMA_LASI_RXSTAT 0x9003 /* RX_ALARM status */ +#define MDIO_PMA_LASI_TXSTAT 0x9004 /* TX_ALARM status */ +#define MDIO_PMA_LASI_STAT 0x9005 /* LASI status */ + +/* Control register 1. */ +/* Enable extended speed selection */ +#define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100) +/* All speed selection bits */ +#define MDIO_CTRL1_SPEEDSEL (MDIO_CTRL1_SPEEDSELEXT | 0x003c) +#define MDIO_CTRL1_FULLDPLX BMCR_FULLDPLX +#define MDIO_CTRL1_LPOWER BMCR_PDOWN +#define MDIO_CTRL1_RESET BMCR_RESET +#define MDIO_PMA_CTRL1_LOOPBACK 0x0001 +#define MDIO_PMA_CTRL1_SPEED1000 BMCR_SPEED1000 +#define MDIO_PMA_CTRL1_SPEED100 BMCR_SPEED100 +#define MDIO_PCS_CTRL1_LOOPBACK BMCR_LOOPBACK +#define MDIO_PHYXS_CTRL1_LOOPBACK BMCR_LOOPBACK +#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART +#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE +#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */ + +/* 10 Gb/s */ +#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) +/* 10PASS-TS/2BASE-TL */ +#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04) + +/* Status register 1. */ +#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */ +#define MDIO_STAT1_LSTATUS BMSR_LSTATUS +#define MDIO_STAT1_FAULT 0x0080 /* Fault */ +#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */ +#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE +#define MDIO_AN_STAT1_RFAULT BMSR_RFAULT +#define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE +#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */ +#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */ + +/* Speed register. */ +#define MDIO_SPEED_10G 0x0001 /* 10G capable */ +#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */ +#define MDIO_PMA_SPEED_10P 0x0004 /* 10PASS-TS capable */ +#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */ +#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */ +#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */ +#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */ + +/* Device present registers. */ +#define MDIO_DEVS_PRESENT(devad) (1 << (devad)) +#define MDIO_DEVS_PMAPMD MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD) +#define MDIO_DEVS_WIS MDIO_DEVS_PRESENT(MDIO_MMD_WIS) +#define MDIO_DEVS_PCS MDIO_DEVS_PRESENT(MDIO_MMD_PCS) +#define MDIO_DEVS_PHYXS MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS) +#define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS) +#define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC) +#define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN) +#define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT) +#define MDIO_DEVS_VEND1 MDIO_DEVS_PRESENT(MDIO_MMD_VEND1) +#define MDIO_DEVS_VEND2 MDIO_DEVS_PRESENT(MDIO_MMD_VEND2) + + +/* Control register 2. */ +#define MDIO_PMA_CTRL2_TYPE 0x000f /* PMA/PMD type selection */ +#define MDIO_PMA_CTRL2_10GBCX4 0x0000 /* 10GBASE-CX4 type */ +#define MDIO_PMA_CTRL2_10GBEW 0x0001 /* 10GBASE-EW type */ +#define MDIO_PMA_CTRL2_10GBLW 0x0002 /* 10GBASE-LW type */ +#define MDIO_PMA_CTRL2_10GBSW 0x0003 /* 10GBASE-SW type */ +#define MDIO_PMA_CTRL2_10GBLX4 0x0004 /* 10GBASE-LX4 type */ +#define MDIO_PMA_CTRL2_10GBER 0x0005 /* 10GBASE-ER type */ +#define MDIO_PMA_CTRL2_10GBLR 0x0006 /* 10GBASE-LR type */ +#define MDIO_PMA_CTRL2_10GBSR 0x0007 /* 10GBASE-SR type */ +#define MDIO_PMA_CTRL2_10GBLRM 0x0008 /* 10GBASE-LRM type */ +#define MDIO_PMA_CTRL2_10GBT 0x0009 /* 10GBASE-T type */ +#define MDIO_PMA_CTRL2_10GBKX4 0x000a /* 10GBASE-KX4 type */ +#define MDIO_PMA_CTRL2_10GBKR 0x000b /* 10GBASE-KR type */ +#define MDIO_PMA_CTRL2_1000BT 0x000c /* 1000BASE-T type */ +#define MDIO_PMA_CTRL2_1000BKX 0x000d /* 1000BASE-KX type */ +#define MDIO_PMA_CTRL2_100BTX 0x000e /* 100BASE-TX type */ +#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */ +#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */ +#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */ +#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */ +#define MDIO_PCS_CTRL2_10GBW 0x0002 /* 10GBASE-W type */ +#define MDIO_PCS_CTRL2_10GBT 0x0003 /* 10GBASE-T type */ + +/* Status register 2. */ +#define MDIO_STAT2_RXFAULT 0x0400 /* Receive fault */ +#define MDIO_STAT2_TXFAULT 0x0800 /* Transmit fault */ +#define MDIO_STAT2_DEVPRST 0xc000 /* Device present */ +#define MDIO_STAT2_DEVPRST_VAL 0x8000 /* Device present value */ +#define MDIO_PMA_STAT2_LBABLE 0x0001 /* PMA loopback ability */ +#define MDIO_PMA_STAT2_10GBEW 0x0002 /* 10GBASE-EW ability */ +#define MDIO_PMA_STAT2_10GBLW 0x0004 /* 10GBASE-LW ability */ +#define MDIO_PMA_STAT2_10GBSW 0x0008 /* 10GBASE-SW ability */ +#define MDIO_PMA_STAT2_10GBLX4 0x0010 /* 10GBASE-LX4 ability */ +#define MDIO_PMA_STAT2_10GBER 0x0020 /* 10GBASE-ER ability */ +#define MDIO_PMA_STAT2_10GBLR 0x0040 /* 10GBASE-LR ability */ +#define MDIO_PMA_STAT2_10GBSR 0x0080 /* 10GBASE-SR ability */ +#define MDIO_PMD_STAT2_TXDISAB 0x0100 /* PMD TX disable ability */ +#define MDIO_PMA_STAT2_EXTABLE 0x0200 /* Extended abilities */ +#define MDIO_PMA_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ +#define MDIO_PMA_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ +#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R capable */ +#define MDIO_PCS_STAT2_10GBX 0x0002 /* 10GBASE-X capable */ +#define MDIO_PCS_STAT2_10GBW 0x0004 /* 10GBASE-W capable */ +#define MDIO_PCS_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ +#define MDIO_PCS_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ + +/* Transmit disable register. */ +#define MDIO_PMD_TXDIS_GLOBAL 0x0001 /* Global PMD TX disable */ +#define MDIO_PMD_TXDIS_0 0x0002 /* PMD TX disable 0 */ +#define MDIO_PMD_TXDIS_1 0x0004 /* PMD TX disable 1 */ +#define MDIO_PMD_TXDIS_2 0x0008 /* PMD TX disable 2 */ +#define MDIO_PMD_TXDIS_3 0x0010 /* PMD TX disable 3 */ + +/* Receive signal detect register. */ +#define MDIO_PMD_RXDET_GLOBAL 0x0001 /* Global PMD RX signal detect */ +#define MDIO_PMD_RXDET_0 0x0002 /* PMD RX signal detect 0 */ +#define MDIO_PMD_RXDET_1 0x0004 /* PMD RX signal detect 1 */ +#define MDIO_PMD_RXDET_2 0x0008 /* PMD RX signal detect 2 */ +#define MDIO_PMD_RXDET_3 0x0010 /* PMD RX signal detect 3 */ + +/* Extended abilities register. */ +#define MDIO_PMA_EXTABLE_10GCX4 0x0001 /* 10GBASE-CX4 ability */ +#define MDIO_PMA_EXTABLE_10GBLRM 0x0002 /* 10GBASE-LRM ability */ +#define MDIO_PMA_EXTABLE_10GBT 0x0004 /* 10GBASE-T ability */ +#define MDIO_PMA_EXTABLE_10GBKX4 0x0008 /* 10GBASE-KX4 ability */ +#define MDIO_PMA_EXTABLE_10GBKR 0x0010 /* 10GBASE-KR ability */ +#define MDIO_PMA_EXTABLE_1000BT 0x0020 /* 1000BASE-T ability */ +#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */ +#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */ +#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */ + +/* PHY XGXS lane state register. */ +#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 +#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 +#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 +#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 +#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 + +/* PMA 10GBASE-T pair swap & polarity */ +#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */ +#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */ +#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */ + +/* PMA 10GBASE-T TX power register. */ +#define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ + +/* PMA 10GBASE-T SNR registers. */ +/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */ +#define MDIO_PMA_10GBT_SNR_BIAS 0x8000 +#define MDIO_PMA_10GBT_SNR_MAX 127 + +/* PMA 10GBASE-R FEC ability register. */ +#define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */ +#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */ + +/* PCS 10GBASE-R/-T status register 1. */ +#define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */ + +/* PCS 10GBASE-R/-T status register 2. */ +#define MDIO_PCS_10GBRT_STAT2_ERR 0x00ff +#define MDIO_PCS_10GBRT_STAT2_BER 0x3f00 + +/* AN 10GBASE-T control register. */ +#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */ + +/* AN 10GBASE-T status register. */ +#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */ +#define MDIO_AN_10GBT_STAT_LPLTABLE 0x0400 /* LP loop timing ability */ +#define MDIO_AN_10GBT_STAT_LP10G 0x0800 /* LP is 10GBT capable */ +#define MDIO_AN_10GBT_STAT_REMOK 0x1000 /* Remote OK */ +#define MDIO_AN_10GBT_STAT_LOCOK 0x2000 /* Local OK */ +#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */ +#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */ + +/* AN EEE Advertisement register. */ +#define MDIO_AN_EEE_ADV_100TX 0x0002 /* Advertise 100TX EEE cap */ +#define MDIO_AN_EEE_ADV_1000T 0x0004 /* Advertise 1000T EEE cap */ + +/* LASI RX_ALARM control/status registers. */ +#define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */ +#define MDIO_PMA_LASI_RX_PCSLFLT 0x0008 /* PCS RX local fault */ +#define MDIO_PMA_LASI_RX_PMALFLT 0x0010 /* PMA/PMD RX local fault */ +#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020 /* RX optical power fault */ +#define MDIO_PMA_LASI_RX_WISLFLT 0x0200 /* WIS local fault */ + +/* LASI TX_ALARM control/status registers. */ +#define MDIO_PMA_LASI_TX_PHYXSLFLT 0x0001 /* PHY XS TX local fault */ +#define MDIO_PMA_LASI_TX_PCSLFLT 0x0008 /* PCS TX local fault */ +#define MDIO_PMA_LASI_TX_PMALFLT 0x0010 /* PMA/PMD TX local fault */ +#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080 /* Laser output power fault */ +#define MDIO_PMA_LASI_TX_LASERTEMPFLT 0x0100 /* Laser temperature fault */ +#define MDIO_PMA_LASI_TX_LASERBICURRFLT 0x0200 /* Laser bias current fault */ + +/* LASI control/status registers. */ +#define MDIO_PMA_LASI_LSALARM 0x0001 /* LS_ALARM enable/status */ +#define MDIO_PMA_LASI_TXALARM 0x0002 /* TX_ALARM enable/status */ +#define MDIO_PMA_LASI_RXALARM 0x0004 /* RX_ALARM enable/status */ + +/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */ + +#define MDIO_PHY_ID_C45 0x8000 +#define MDIO_PHY_ID_PRTAD 0x03e0 +#define MDIO_PHY_ID_DEVAD 0x001f +#define MDIO_PHY_ID_C45_MASK \ + (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD) + +#define MDIO_PRTAD_NONE (-1) +#define MDIO_DEVAD_NONE (-1) +#define MDIO_EMULATE_C22 4 + +#endif /* __LINUX_MDIO_H__ */ diff --git a/include/miiphy.h b/include/miiphy.h index 42dc127..7e70cf8 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -34,35 +34,52 @@ #ifndef _miiphy_h_ #define _miiphy_h_ +#include <common.h> #include <linux/mii.h> +#include <linux/list.h> #include <net.h> +#include <phy.h> -int miiphy_read (const char *devname, unsigned char addr, unsigned char reg, +struct legacy_mii_dev { + int (*read)(const char *devname, unsigned char addr, + unsigned char reg, unsigned short *value); + int (*write)(const char *devname, unsigned char addr, + unsigned char reg, unsigned short value); +}; + +int miiphy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value); -int miiphy_write (const char *devname, unsigned char addr, unsigned char reg, +int miiphy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value); -int miiphy_info (const char *devname, unsigned char addr, unsigned int *oui, +int miiphy_info(const char *devname, unsigned char addr, unsigned int *oui, unsigned char *model, unsigned char *rev); -int miiphy_reset (const char *devname, unsigned char addr); -int miiphy_speed (const char *devname, unsigned char addr); -int miiphy_duplex (const char *devname, unsigned char addr); -int miiphy_is_1000base_x (const char *devname, unsigned char addr); +int miiphy_reset(const char *devname, unsigned char addr); +int miiphy_speed(const char *devname, unsigned char addr); +int miiphy_duplex(const char *devname, unsigned char addr); +int miiphy_is_1000base_x(const char *devname, unsigned char addr); #ifdef CONFIG_SYS_FAULT_ECHO_LINK_DOWN -int miiphy_link (const char *devname, unsigned char addr); +int miiphy_link(const char *devname, unsigned char addr); #endif -void miiphy_init (void); +void miiphy_init(void); -void miiphy_register (const char *devname, - int (*read) (const char *devname, unsigned char addr, +void miiphy_register(const char *devname, + int (*read)(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value), - int (*write) (const char *devname, unsigned char addr, + int (*write)(const char *devname, unsigned char addr, unsigned char reg, unsigned short value)); -int miiphy_set_current_dev (const char *devname); -const char *miiphy_get_current_dev (void); +int miiphy_set_current_dev(const char *devname); +const char *miiphy_get_current_dev(void); +struct mii_dev *mdio_get_current_dev(void); +struct mii_dev *miiphy_get_dev_by_name(const char *devname); +struct phy_device *mdio_phydev_for_ethname(const char *devname); + +void miiphy_listdev(void); -void miiphy_listdev (void); +struct mii_dev *mdio_alloc(void); +int mdio_register(struct mii_dev *bus); +void mdio_list_devices(void); #ifdef CONFIG_BITBANGMII @@ -85,10 +102,10 @@ struct bb_miiphy_bus { extern struct bb_miiphy_bus bb_miiphy_buses[]; extern int bb_miiphy_buses_num; -void bb_miiphy_init (void); -int bb_miiphy_read (const char *devname, unsigned char addr, +void bb_miiphy_init(void); +int bb_miiphy_read(const char *devname, unsigned char addr, unsigned char reg, unsigned short *value); -int bb_miiphy_write (const char *devname, unsigned char addr, +int bb_miiphy_write(const char *devname, unsigned char addr, unsigned char reg, unsigned short value); #endif diff --git a/include/phy.h b/include/phy.h new file mode 100644 index 0000000..d5817bf --- /dev/null +++ b/include/phy.h @@ -0,0 +1,229 @@ +/* + * Copyright 2011 Freescale Semiconductor, Inc. + * Andy Fleming <afleming@freescale.com> + * + * 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 + * + * This file pretty much stolen from Linux's mii.h/ethtool.h/phy.h + */ + +#ifndef _PHY_H +#define _PHY_H + +#include <linux/list.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/mdio.h> + +#define PHY_MAX_ADDR 32 + +#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full | \ + SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full | \ + SUPPORTED_Autoneg | \ + SUPPORTED_TP | \ + SUPPORTED_MII) + +#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ + SUPPORTED_1000baseT_Half | \ + SUPPORTED_1000baseT_Full) + +#define PHY_10G_FEATURES (PHY_GBIT_FEATURES | \ + SUPPORTED_10000baseT_Full) + +#define PHY_ANEG_TIMEOUT 4000 + + +typedef enum { + PHY_INTERFACE_MODE_MII, + PHY_INTERFACE_MODE_GMII, + PHY_INTERFACE_MODE_SGMII, + PHY_INTERFACE_MODE_TBI, + PHY_INTERFACE_MODE_RMII, + PHY_INTERFACE_MODE_RGMII, + PHY_INTERFACE_MODE_RGMII_ID, + PHY_INTERFACE_MODE_RGMII_RXID, + PHY_INTERFACE_MODE_RGMII_TXID, + PHY_INTERFACE_MODE_RTBI, + PHY_INTERFACE_MODE_XGMII, + PHY_INTERFACE_MODE_NONE /* Must be last */ +} phy_interface_t; + +static const char *phy_interface_strings[] = { + [PHY_INTERFACE_MODE_MII] = "mii", + [PHY_INTERFACE_MODE_GMII] = "gmii", + [PHY_INTERFACE_MODE_SGMII] = "sgmii", + [PHY_INTERFACE_MODE_TBI] = "tbi", + [PHY_INTERFACE_MODE_RMII] = "rmii", + [PHY_INTERFACE_MODE_RGMII] = "rgmii", + [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id", + [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid", + [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid", + [PHY_INTERFACE_MODE_RTBI] = "rtbi", + [PHY_INTERFACE_MODE_XGMII] = "xgmii", + [PHY_INTERFACE_MODE_NONE] = "", +}; + +static inline const char *phy_string_for_interface(phy_interface_t i) +{ + /* Default to unknown */ + if (i > PHY_INTERFACE_MODE_NONE) + i = PHY_INTERFACE_MODE_NONE; + + return phy_interface_strings[i]; +} + + +struct phy_device; + +#define MDIO_NAME_LEN 32 + +struct mii_dev { + struct list_head link; + char name[MDIO_NAME_LEN]; + void *priv; + int (*read)(struct mii_dev *bus, int addr, int devad, int reg); + int (*write)(struct mii_dev *bus, int addr, int devad, int reg, + u16 val); + int (*reset)(struct mii_dev *bus); + struct phy_device *phymap[PHY_MAX_ADDR]; + u32 phy_mask; +}; + +/* struct phy_driver: a structure which defines PHY behavior + * + * uid will contain a number which represents the PHY. During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is. The 32-bit result + * gotten from the PHY will be masked to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + */ +struct phy_driver { + char *name; + unsigned int uid; + unsigned int mask; + unsigned int mmds; + + u32 features; + + /* Called to do any driver startup necessities */ + /* Will be called during phy_connect */ + int (*probe)(struct phy_device *phydev); + + /* Called to configure the PHY, and modify the controller + * based on the results. Should be called after phy_connect */ + int (*config)(struct phy_device *phydev); + + /* Called when starting up the controller */ + int (*startup)(struct phy_device *phydev); + + /* Called when bringing down the controller */ + int (*shutdown)(struct phy_device *phydev); + + struct list_head list; +}; + +struct phy_device { + /* Information about the PHY type */ + /* And management functions */ + struct mii_dev *bus; + struct phy_driver *drv; + void *priv; + + struct eth_device *dev; + + /* forced speed & duplex (no autoneg) + * partner speed & duplex & pause (autoneg) + */ + int speed; + int duplex; + + /* The most recently read link state */ + int link; + int port; + phy_interface_t interface; + + u32 advertising; + u32 supported; + u32 mmds; + + int autoneg; + int addr; + int pause; + int asym_pause; + u32 phy_id; + u32 flags; +}; + +static inline int phy_read(struct phy_device *phydev, int devad, int regnum) +{ + struct mii_dev *bus = phydev->bus; + + return bus->read(bus, phydev->addr, devad, regnum); +} + +static inline int phy_write(struct phy_device *phydev, int devad, int regnum, + u16 val) +{ + struct mii_dev *bus = phydev->bus; + + return bus->write(bus, phydev->addr, devad, regnum, val); +} + +#ifdef CONFIG_PHYLIB_10G +extern struct phy_driver gen10g_driver; + +/* For now, XGMII is the only 10G interface */ +static inline int is_10g_interface(phy_interface_t interface) +{ + return interface == PHY_INTERFACE_MODE_XGMII; +} + +#endif + +int phy_init(void); +int phy_reset(struct phy_device *phydev); +struct phy_device *phy_connect(struct mii_dev *bus, int addr, + struct eth_device *dev, + phy_interface_t interface); +int phy_startup(struct phy_device *phydev); +int phy_config(struct phy_device *phydev); +int phy_shutdown(struct phy_device *phydev); +int phy_register(struct phy_driver *drv); +int genphy_config_aneg(struct phy_device *phydev); +int genphy_update_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); +int gen10g_config(struct phy_device *phydev); +int gen10g_startup(struct phy_device *phydev); +int gen10g_shutdown(struct phy_device *phydev); +int gen10g_discover_mmds(struct phy_device *phydev); + +int phy_atheros_init(void); +int phy_broadcom_init(void); +int phy_davicom_init(void); +int phy_lxt_init(void); +int phy_marvell_init(void); +int phy_micrel_init(void); +int phy_natsemi_init(void); +int phy_realtek_init(void); +int phy_teranetics_init(void); +int phy_vitesse_init(void); +#endif diff --git a/include/tsec.h b/include/tsec.h index d56ec2c..8ed30ac 100644 --- a/include/tsec.h +++ b/include/tsec.h @@ -7,7 +7,7 @@ * terms of the GNU Public License, Version 2, incorporated * herein by reference. * - * Copyright 2004, 2007, 2009 Freescale Semiconductor, Inc. + * Copyright 2004, 2007, 2009, 2011 Freescale Semiconductor, Inc. * (C) Copyright 2003, Motorola, Inc. * maintained by Xianghua Xiao (x.xiao@motorola.com) * author Andy Fleming @@ -19,30 +19,36 @@ #include <net.h> #include <config.h> +#include <phy.h> +#include <asm/fsl_enet.h> #define TSEC_SIZE 0x01000 #define TSEC_MDIO_OFFSET 0x01000 +#define CONFIG_SYS_MDIO_BASE_ADDR (TSEC_BASE_ADDR + 0x520) + +#define DEFAULT_MII_NAME "FSL_MDIO" + #define STD_TSEC_INFO(num) \ { \ .regs = (tsec_t *)(TSEC_BASE_ADDR + ((num - 1) * TSEC_SIZE)), \ - .miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR), \ - .miiregs_sgmii = (tsec_mdio_t *)(MDIO_BASE_ADDR \ + .miiregs_sgmii = (struct tsec_mii_mng *)(CONFIG_SYS_MDIO_BASE_ADDR \ + (num - 1) * TSEC_MDIO_OFFSET), \ .devname = CONFIG_TSEC##num##_NAME, \ .phyaddr = TSEC##num##_PHY_ADDR, \ - .flags = TSEC##num##_FLAGS \ + .flags = TSEC##num##_FLAGS, \ + .mii_devname = DEFAULT_MII_NAME \ } #define SET_STD_TSEC_INFO(x, num) \ { \ x.regs = (tsec_t *)(TSEC_BASE_ADDR + ((num - 1) * TSEC_SIZE)); \ - x.miiregs = (tsec_mdio_t *)(MDIO_BASE_ADDR); \ - x.miiregs_sgmii = (tsec_mdio_t *)(MDIO_BASE_ADDR \ + x.miiregs_sgmii = (struct tsec_mii_mng *)(CONFIG_SYS_MDIO_BASE_ADDR \ + (num - 1) * TSEC_MDIO_OFFSET); \ x.devname = CONFIG_TSEC##num##_NAME; \ x.phyaddr = TSEC##num##_PHY_ADDR; \ x.flags = TSEC##num##_FLAGS;\ + x.mii_devname = DEFAULT_MII_NAME;\ } #define MAC_ADDR_LEN 6 @@ -51,8 +57,6 @@ #define TSEC_TIMEOUT 1000 #define TOUT_LOOP 1000000 -#define PHY_AUTONEGOTIATE_TIMEOUT 5000 /* in ms */ - /* TBI register addresses */ #define TBI_CR 0x00 #define TBI_SR 0x01 @@ -96,204 +100,14 @@ #define ECNTRL_INIT_SETTINGS 0x00001000 #define ECNTRL_TBI_MODE 0x00000020 +#define ECNTRL_REDUCED_MODE 0x00000010 #define ECNTRL_R100 0x00000008 +#define ECNTRL_REDUCED_MII_MODE 0x00000004 #define ECNTRL_SGMII_MODE 0x00000002 -#define miim_end -2 -#define miim_read -1 - #ifndef CONFIG_SYS_TBIPA_VALUE #define CONFIG_SYS_TBIPA_VALUE 0x1f #endif -#define MIIMCFG_INIT_VALUE 0x00000003 -#define MIIMCFG_RESET 0x80000000 - -#define MIIMIND_BUSY 0x00000001 -#define MIIMIND_NOTVALID 0x00000004 - -#define MIIM_CONTROL 0x00 -#define MIIM_CONTROL_RESET 0x00009140 -#define MIIM_CONTROL_INIT 0x00001140 -#define MIIM_CONTROL_RESTART 0x00001340 -#define MIIM_ANEN 0x00001000 - -#define MIIM_CR 0x00 -#define MIIM_CR_RST 0x00008000 -#define MIIM_CR_INIT 0x00001000 - -#define MIIM_STATUS 0x1 -#define MIIM_STATUS_AN_DONE 0x00000020 -#define MIIM_STATUS_LINK 0x0004 - -#define MIIM_PHYIR1 0x2 -#define MIIM_PHYIR2 0x3 - -#define MIIM_ANAR 0x4 -#define MIIM_ANAR_INIT 0x1e1 - -#define MIIM_TBI_ANLPBPA 0x5 -#define MIIM_TBI_ANLPBPA_HALF 0x00000040 -#define MIIM_TBI_ANLPBPA_FULL 0x00000020 - -#define MIIM_TBI_ANEX 0x6 -#define MIIM_TBI_ANEX_NP 0x00000004 -#define MIIM_TBI_ANEX_PRX 0x00000002 - -#define MIIM_GBIT_CONTROL 0x9 -#define MIIM_GBIT_CONTROL_INIT 0xe00 - -#define MIIM_EXT_PAGE_ACCESS 0x1f - -/* Broadcom BCM54xx -- taken from linux sungem_phy */ -#define MIIM_BCM54xx_AUXCNTL 0x18 -#define MIIM_BCM54xx_AUXCNTL_ENCODE(val) ((val & 0x7) << 12)|(val & 0x7) -#define MIIM_BCM54xx_AUXSTATUS 0x19 -#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_MASK 0x0700 -#define MIIM_BCM54xx_AUXSTATUS_LINKMODE_SHIFT 8 - -#define MIIM_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ -#define MIIM_BCM54XX_SHD_WRITE 0x8000 -#define MIIM_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) -#define MIIM_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) -#define MIIM_BCM54XX_SHD_WR_ENCODE(val, data) \ - (MIIM_BCM54XX_SHD_WRITE | MIIM_BCM54XX_SHD_VAL(val) | \ - MIIM_BCM54XX_SHD_DATA(data)) - -#define MIIM_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ -#define MIIM_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ -#define MIIM_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ -#define MIIM_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ - -/* Cicada Auxiliary Control/Status Register */ -#define MIIM_CIS8201_AUX_CONSTAT 0x1c -#define MIIM_CIS8201_AUXCONSTAT_INIT 0x0004 -#define MIIM_CIS8201_AUXCONSTAT_DUPLEX 0x0020 -#define MIIM_CIS8201_AUXCONSTAT_SPEED 0x0018 -#define MIIM_CIS8201_AUXCONSTAT_GBIT 0x0010 -#define MIIM_CIS8201_AUXCONSTAT_100 0x0008 - -/* Cicada Extended Control Register 1 */ -#define MIIM_CIS8201_EXT_CON1 0x17 -#define MIIM_CIS8201_EXTCON1_INIT 0x0000 - -/* Cicada 8204 Extended PHY Control Register 1 */ -#define MIIM_CIS8204_EPHY_CON 0x17 -#define MIIM_CIS8204_EPHYCON_INIT 0x0006 -#define MIIM_CIS8204_EPHYCON_RGMII 0x1100 - -/* Cicada 8204 Serial LED Control Register */ -#define MIIM_CIS8204_SLED_CON 0x1b -#define MIIM_CIS8204_SLEDCON_INIT 0x1115 - -#define MIIM_GBIT_CON 0x09 -#define MIIM_GBIT_CON_ADVERT 0x0e00 - -/* Entry for Vitesse VSC8244 regs starts here */ -/* Vitesse VSC8244 Auxiliary Control/Status Register */ -#define MIIM_VSC8244_AUX_CONSTAT 0x1c -#define MIIM_VSC8244_AUXCONSTAT_INIT 0x0000 -#define MIIM_VSC8244_AUXCONSTAT_DUPLEX 0x0020 -#define MIIM_VSC8244_AUXCONSTAT_SPEED 0x0018 -#define MIIM_VSC8244_AUXCONSTAT_GBIT 0x0010 -#define MIIM_VSC8244_AUXCONSTAT_100 0x0008 -#define MIIM_CONTROL_INIT_LOOPBACK 0x4000 - -/* Vitesse VSC8244 Extended PHY Control Register 1 */ -#define MIIM_VSC8244_EPHY_CON 0x17 -#define MIIM_VSC8244_EPHYCON_INIT 0x0006 - -/* Vitesse VSC8244 Serial LED Control Register */ -#define MIIM_VSC8244_LED_CON 0x1b -#define MIIM_VSC8244_LEDCON_INIT 0xF011 - -/* Entry for Vitesse VSC8601 regs starts here (Not complete) */ -/* Vitesse VSC8601 Extended PHY Control Register 1 */ -#define MIIM_VSC8601_EPHY_CON 0x17 -#define MIIM_VSC8601_EPHY_CON_INIT_SKEW 0x1120 -#define MIIM_VSC8601_SKEW_CTRL 0x1c - -/* 88E1011 PHY Status Register */ -#define MIIM_88E1011_PHY_STATUS 0x11 -#define MIIM_88E1011_PHYSTAT_SPEED 0xc000 -#define MIIM_88E1011_PHYSTAT_GBIT 0x8000 -#define MIIM_88E1011_PHYSTAT_100 0x4000 -#define MIIM_88E1011_PHYSTAT_DUPLEX 0x2000 -#define MIIM_88E1011_PHYSTAT_SPDDONE 0x0800 -#define MIIM_88E1011_PHYSTAT_LINK 0x0400 - -#define MIIM_88E1011_PHY_SCR 0x10 -#define MIIM_88E1011_PHY_MDI_X_AUTO 0x0060 - -/* 88E1111 PHY LED Control Register */ -#define MIIM_88E1111_PHY_LED_CONTROL 24 -#define MIIM_88E1111_PHY_LED_DIRECT 0x4100 -#define MIIM_88E1111_PHY_LED_COMBINE 0x411C - -/* 88E1121 PHY LED Control Register */ -#define MIIM_88E1121_PHY_LED_CTRL 16 -#define MIIM_88E1121_PHY_LED_PAGE 3 -#define MIIM_88E1121_PHY_LED_DEF 0x0030 - -/* 88E1121 PHY IRQ Enable/Status Register */ -#define MIIM_88E1121_PHY_IRQ_EN 18 -#define MIIM_88E1121_PHY_IRQ_STATUS 19 - -#define MIIM_88E1121_PHY_PAGE 22 - -/* 88E1145 Extended PHY Specific Control Register */ -#define MIIM_88E1145_PHY_EXT_CR 20 -#define MIIM_M88E1145_RGMII_RX_DELAY 0x0080 -#define MIIM_M88E1145_RGMII_TX_DELAY 0x0002 - -#define MIIM_88E1145_PHY_PAGE 29 -#define MIIM_88E1145_PHY_CAL_OV 30 - -/* RTL8211B PHY Status Register */ -#define MIIM_RTL8211B_PHY_STATUS 0x11 -#define MIIM_RTL8211B_PHYSTAT_SPEED 0xc000 -#define MIIM_RTL8211B_PHYSTAT_GBIT 0x8000 -#define MIIM_RTL8211B_PHYSTAT_100 0x4000 -#define MIIM_RTL8211B_PHYSTAT_DUPLEX 0x2000 -#define MIIM_RTL8211B_PHYSTAT_SPDDONE 0x0800 -#define MIIM_RTL8211B_PHYSTAT_LINK 0x0400 - -/* DM9161 Control register values */ -#define MIIM_DM9161_CR_STOP 0x0400 -#define MIIM_DM9161_CR_RSTAN 0x1200 - -#define MIIM_DM9161_SCR 0x10 -#define MIIM_DM9161_SCR_INIT 0x0610 - -/* DM9161 Specified Configuration and Status Register */ -#define MIIM_DM9161_SCSR 0x11 -#define MIIM_DM9161_SCSR_100F 0x8000 -#define MIIM_DM9161_SCSR_100H 0x4000 -#define MIIM_DM9161_SCSR_10F 0x2000 -#define MIIM_DM9161_SCSR_10H 0x1000 - -/* DM9161 10BT Configuration/Status */ -#define MIIM_DM9161_10BTCSR 0x12 -#define MIIM_DM9161_10BTCSR_INIT 0x7800 - -/* LXT971 Status 2 registers */ -#define MIIM_LXT971_SR2 0x11 /* Status Register 2 */ -#define MIIM_LXT971_SR2_SPEED_MASK 0x4200 -#define MIIM_LXT971_SR2_10HDX 0x0000 /* 10 Mbit half duplex selected */ -#define MIIM_LXT971_SR2_10FDX 0x0200 /* 10 Mbit full duplex selected */ -#define MIIM_LXT971_SR2_100HDX 0x4000 /* 100 Mbit half duplex selected */ -#define MIIM_LXT971_SR2_100FDX 0x4200 /* 100 Mbit full duplex selected */ - -/* DP83865 Control register values */ -#define MIIM_DP83865_CR_INIT 0x9200 - -/* DP83865 Link and Auto-Neg Status Register */ -#define MIIM_DP83865_LANR 0x11 -#define MIIM_DP83865_SPD_MASK 0x0018 -#define MIIM_DP83865_SPD_1000 0x0010 -#define MIIM_DP83865_SPD_100 0x0008 -#define MIIM_DP83865_DPX_FULL 0x0002 - -#define MIIM_READ_COMMAND 0x00000001 #define MRBLR_INIT_SETTINGS PKTSIZE_ALIGN @@ -467,22 +281,6 @@ typedef struct tsec_hash_regs uint res2[24]; } tsec_hash_t; -typedef struct tsec_mdio { - uint res1[4]; - uint ieventm; - uint imaskm; - uint res2; - uint emapm; - uint res3[320]; - uint miimcfg; /* MII Management: Configuration */ - uint miimcom; /* MII Management: Command */ - uint miimadd; /* MII Management: Address */ - uint miimcon; /* MII Management: Control */ - uint miimstat; /* MII Management: Status */ - uint miimind; /* MII Management: Indicators */ - uint res4[690]; -} tsec_mdio_t; - typedef struct tsec { /* General Control and Status Registers (0x2_n000) */ @@ -578,79 +376,29 @@ typedef struct tsec uint resc00[256]; } tsec_t; -#define TSEC_GIGABIT (1) +#define TSEC_GIGABIT (1 << 0) -/* This flag currently only has - * meaning if we're using the eTSEC */ +/* These flags currently only have meaning if we're using the eTSEC */ #define TSEC_REDUCED (1 << 1) /* MAC-PHY interface uses RGMII */ #define TSEC_SGMII (1 << 2) /* MAC-PHY interface uses SGMII */ -#define TSEC_FIBER (1 << 3) /* PHY uses fiber, eg 1000 Base-X */ struct tsec_private { - volatile tsec_t *regs; - volatile tsec_mdio_t *phyregs; - volatile tsec_mdio_t *phyregs_sgmii; - struct phy_info *phyinfo; + tsec_t *regs; + struct tsec_mii_mng *phyregs_sgmii; + struct phy_device *phydev; + phy_interface_t interface; + struct mii_dev *bus; uint phyaddr; + char mii_devname[16]; u32 flags; - uint link; - uint duplexity; - uint speed; -}; - - -/* - * struct phy_cmd: A command for reading or writing a PHY register - * - * mii_reg: The register to read or write - * - * mii_data: For writes, the value to put in the register. - * A value of -1 indicates this is a read. - * - * funct: A function pointer which is invoked for each command. - * For reads, this function will be passed the value read - * from the PHY, and process it. - * For writes, the result of this function will be written - * to the PHY register - */ -struct phy_cmd { - uint mii_reg; - uint mii_data; - uint (*funct) (uint mii_reg, struct tsec_private * priv); -}; - -/* struct phy_info: a structure which defines attributes for a PHY - * - * id will contain a number which represents the PHY. During - * startup, the driver will poll the PHY to find out what its - * UID--as defined by registers 2 and 3--is. The 32-bit result - * gotten from the PHY will be shifted right by "shift" bits to - * discard any bits which may change based on revision numbers - * unimportant to functionality - * - * The struct phy_cmd entries represent pointers to an arrays of - * commands which tell the driver what to do to the PHY. - */ -struct phy_info { - uint id; - char *name; - uint shift; - /* Called to configure the PHY, and modify the controller - * based on the results */ - struct phy_cmd *config; - - /* Called when starting up the controller */ - struct phy_cmd *startup; - - /* Called when bringing down the controller */ - struct phy_cmd *shutdown; }; struct tsec_info_struct { tsec_t *regs; - tsec_mdio_t *miiregs; - tsec_mdio_t *miiregs_sgmii; + struct tsec_mii_mng *miiregs_sgmii; char *devname; + char *mii_devname; + phy_interface_t interface; unsigned int phyaddr; u32 flags; }; @@ -25,6 +25,7 @@ #include <command.h> #include <net.h> #include <miiphy.h> +#include <phy.h> void eth_parse_enetaddr(const char *addr, uchar *enetaddr) { @@ -217,6 +218,11 @@ int eth_initialize(bd_t *bis) #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_init(); #endif + +#ifdef CONFIG_PHYLIB + phy_init(); +#endif + /* * If board-specific initialization exists, call it. * If not, call a CPU-specific one |