Skip to content
Snippets Groups Projects
tsec.c 39.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		/* Read the status */
    		{MIIM_BCM54xx_AUXSTATUS, miim_read, &mii_parse_BCM54xx_sr},
    		{miim_end,}
    	},
    	(struct phy_cmd[]) { /* shutdown */
    		{miim_end,}
    	},
    };
    
    
    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,}
    			   },
    
    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 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;
    
    			break;
    
    		default:
    			priv->speed = 100;
    			priv->duplexity = 1;
    		}
    	} 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)
    
    /*
     * 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;
    
    	if (NULL == priv) {
    
    		printf("Can't read PHY at address %d\n", addr);
    		return -1;
    	}
    
    	ret = (unsigned short)read_any_phy_reg(priv, addr, reg);
    
    
    	return 0;
    }
    
    /*
     * Write a MII PHY register.
     *
     * Returns:
    
    static int tsec_miiphy_write(char *devname, unsigned char addr,
    
    			     unsigned char reg, unsigned short value)
    
    	if (NULL == priv) {
    
    		printf("Can't write PHY at address %d\n", addr);
    		return -1;
    	}
    
    David Updegraff's avatar
    David Updegraff committed
    #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)
    {
     struct tsec_private *priv = privlist[1];
     volatile tsec_t *regs = priv->regs;
     volatile u32  *reg_array, value;
     u8 result, whichbit, whichreg;
    
    	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));
    
    	reg_array = &(regs->hash.gaddr0);
    
    	if (set) {
    		reg_array[whichreg] |= value;
    	} else {
    		reg_array[whichreg] &= ~value;
    	}
    	return 0;
    }
    #endif /* Multicast TFTP ? */
    
    
    #endif /* CONFIG_TSEC_ENET */