Skip to content
Snippets Groups Projects
tsec.c 37.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			   {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,}
    			   },
    
    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},
    
    			   {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 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;
    }
    
    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,}
    			   },
    
    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,}
    			   },
    
    };
    
    /* Cicada 8201 */
    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,}
    			   },
    
    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,}
    			   },
    
    
    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,}
    			   },
    
    /* a generic flavor.  */
    struct phy_info phy_info_generic =  {
    	0,
    	"Unknown/Generic PHY",
    	32,
    	(struct phy_cmd[]) { /* config */
    		{PHY_BMCR, PHY_BMCR_RESET, NULL},
    		{PHY_BMCR, PHY_BMCR_AUTON|PHY_BMCR_RST_NEG, NULL},
    		{miim_end,}
    	},
    	(struct phy_cmd[]) { /* startup */
    		{PHY_BMSR, miim_read, NULL},
    		{PHY_BMSR, miim_read, &mii_parse_sr},
    		{PHY_BMSR, miim_read, &mii_parse_link},
    		{miim_end,}
    	},
    	(struct phy_cmd[]) { /* shutdown */
    		{miim_end,}
    	}
    };
    
    
    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;
    		default:
    			priv->speed = 100;
    			priv->duplexity = 1;
    			break;
    		}
    	} else {
    		priv->speed = 0;
    		priv->duplexity = 0;
    	}
    
    	return 0;
    
    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
    
    uint mii_parse_dp83865_lanr(uint mii_reg, struct tsec_private *priv)
    {
    	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;
    
    	}
    
    	if (mii_reg & MIIM_DP83865_DPX_FULL)
    		priv->duplexity = 1;
    	else
    		priv->duplexity = 0;
    
    	return 0;
    }
    
    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,}
    			   },
    
    struct phy_info *phy_info[] = {
    	&phy_info_cis8204,
    
    	&phy_info_cis8201,
    
    	&phy_info_BCM5461S,
    
    	&phy_info_BCM5464S,
    
    	&phy_info_M88E1011S,
    
    	&phy_info_M88E1111S,
    
    	&phy_info_M88E1145,
    
    	&phy_info_M88E1149S,
    
    	&phy_info_dm9161,
    
    	&phy_info_lxt971,
    
    	&phy_info_VSC8244,
    
    	NULL
    };
    
    /* 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
     */
    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];
    
    	if (theInfo == NULL) {
    
    		printf("%s: PHY id %x is not supported!\n", dev->name, phy_ID);
    		return NULL;
    	} else {
    
    		debug("%s: PHY is %s (%x)\n", dev->name, theInfo->name, phy_ID);
    
    /* Execute the given series of commands on the given device's
    
     * PHY, running functions as necessary
     */
    
    void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd)
    {
    	int i;
    	uint result;
    	volatile tsec_t *phyregs = priv->phyregs;
    
    	phyregs->miimcfg = MIIMCFG_RESET;
    
    	phyregs->miimcfg = MIIMCFG_INIT_VALUE;
    
    
    	while (phyregs->miimind & MIIMIND_BUSY) ;
    
    	for (i = 0; cmd->mii_reg != miim_end; i++) {
    		if (cmd->mii_data == miim_read) {
    
    			result = read_phy_reg(priv, cmd->mii_reg);
    
    
    			if (cmd->funct != NULL)
    				(*(cmd->funct)) (result, priv);
    
    			if (cmd->funct != NULL)
    				result = (*(cmd->funct)) (cmd->mii_reg, priv);
    
    			else
    				result = cmd->mii_data;
    
    			write_phy_reg(priv, cmd->mii_reg, result);
    
    		}
    		cmd++;
    	}
    }
    
    /* Relocate the function pointers in the phy cmd lists */
    static void relocate_cmds(void)
    {
    	struct phy_cmd **cmdlistptr;
    	struct phy_cmd *cmd;
    
    	for (i = 0; phy_info[i]; i++) {
    
    		/* First thing's first: relocate the pointers to the
    		 * PHY command structures (the structs were done) */
    
    		phy_info[i] = (struct phy_info *)((uint) phy_info[i]
    						  + gd->reloc_off);
    
    		phy_info[i]->name += gd->reloc_off;
    		phy_info[i]->config =
    
    		    (struct phy_cmd *)((uint) phy_info[i]->config
    				       + gd->reloc_off);
    
    		phy_info[i]->startup =
    
    		    (struct phy_cmd *)((uint) phy_info[i]->startup
    				       + gd->reloc_off);
    
    		phy_info[i]->shutdown =
    
    		    (struct phy_cmd *)((uint) phy_info[i]->shutdown
    				       + gd->reloc_off);
    
    
    		cmdlistptr = &phy_info[i]->config;
    
    		j = 0;
    		for (; cmdlistptr <= &phy_info[i]->shutdown; cmdlistptr++) {
    			k = 0;
    			for (cmd = *cmdlistptr;
    			     cmd->mii_reg != miim_end;
    			     cmd++) {
    
    				/* Only relocate non-NULL pointers */
    
    #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) \
    
    	&& !defined(BITBANGMII)
    
    struct tsec_private *get_priv_for_phy(unsigned char phyaddr)
    
    	for (i = 0; i < MAXCONTROLLERS; i++) {
    		if (privlist[i]->phyaddr == phyaddr)
    
    /*
     * Read a MII PHY register.
     *
     * Returns:
    
    static int tsec_miiphy_read(char *devname, unsigned char addr,
    
    			    unsigned char reg, unsigned short *value)
    
    	unsigned short ret;
    	struct tsec_private *priv = get_priv_for_phy(addr);
    
    
    	if (NULL == priv) {
    
    		printf("Can't read PHY at address %d\n", addr);
    		return -1;
    	}
    
    	ret = (unsigned short)read_phy_reg(priv, reg);
    	*value = ret;
    
    
    	return 0;
    }
    
    /*
     * Write a MII PHY register.
     *
     * Returns:
    
    static int tsec_miiphy_write(char *devname, unsigned char addr,
    
    			     unsigned char reg, unsigned short value)
    
    	struct tsec_private *priv = get_priv_for_phy(addr);
    
    
    	if (NULL == priv) {
    
    		printf("Can't write PHY at address %d\n", addr);
    		return -1;
    	}
    
    	write_phy_reg(priv, reg, value);
    
    #endif /* CONFIG_TSEC_ENET */