⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tsec.c

📁 u-boot-1.1.6 源码包
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Freescale Three Speed Ethernet Controller driver * * This software may be used and distributed according to the * terms of the GNU Public License, Version 2, incorporated * herein by reference. * * Copyright 2004 Freescale Semiconductor. * (C) Copyright 2003, Motorola, Inc. * author Andy Fleming * */#include <config.h>#include <common.h>#include <malloc.h>#include <net.h>#include <command.h>#if defined(CONFIG_TSEC_ENET)#include "tsec.h"#include "miiphy.h"DECLARE_GLOBAL_DATA_PTR;#define TX_BUF_CNT		2static uint rxIdx;		/* index of the current RX buffer */static uint txIdx;		/* index of the current TX buffer */typedef volatile struct rtxbd {	txbd8_t txbd[TX_BUF_CNT];	rxbd8_t rxbd[PKTBUFSRX];} RTXBD;struct tsec_info_struct {	unsigned int phyaddr;	u32 flags;	unsigned int phyregidx;};/* The tsec_info structure contains 3 values which the * driver uses to determine how to operate a given ethernet * device. The information needed is: *  phyaddr - The address of the PHY which is attached to *	the given device. * *  flags - This variable indicates whether the device *	supports gigabit speed ethernet, and whether it should be *	in reduced mode. * *  phyregidx - This variable specifies which ethernet device *	controls the MII Management registers which are connected *	to the PHY.  For now, only TSEC1 (index 0) has *	access to the PHYs, so all of the entries have "0". * * The values specified in the table are taken from the board's * config file in include/configs/.  When implementing a new * board with ethernet capability, it is necessary to define: *   TSECn_PHY_ADDR *   TSECn_PHYIDX * * for n = 1,2,3, etc.  And for FEC: *   FEC_PHY_ADDR *   FEC_PHYIDX */static struct tsec_info_struct tsec_info[] = {#if defined(CONFIG_MPC85XX_TSEC1) || defined(CONFIG_MPC83XX_TSEC1)	{TSEC1_PHY_ADDR, TSEC_GIGABIT, TSEC1_PHYIDX},#elif defined(CONFIG_MPC86XX_TSEC1)	{TSEC1_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC1_PHYIDX},#else	{0, 0, 0},#endif#if defined(CONFIG_MPC85XX_TSEC2) || defined(CONFIG_MPC83XX_TSEC2)	{TSEC2_PHY_ADDR, TSEC_GIGABIT, TSEC2_PHYIDX},#elif defined(CONFIG_MPC86XX_TSEC2)	{TSEC2_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC2_PHYIDX},#else	{0, 0, 0},#endif#ifdef CONFIG_MPC85XX_FEC	{FEC_PHY_ADDR, 0, FEC_PHYIDX},#else#if defined(CONFIG_MPC85XX_TSEC3) || defined(CONFIG_MPC83XX_TSEC3) || defined(CONFIG_MPC86XX_TSEC3)	{TSEC3_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC3_PHYIDX},#else	{0, 0, 0},#endif#if defined(CONFIG_MPC85XX_TSEC4) || defined(CONFIG_MPC83XX_TSEC4) || defined(CONFIG_MPC86XX_TSEC4)	{TSEC4_PHY_ADDR, TSEC_GIGABIT | TSEC_REDUCED, TSEC4_PHYIDX},#else	{0, 0, 0},#endif#endif};#define MAXCONTROLLERS	(4)static int relocated = 0;static struct tsec_private *privlist[MAXCONTROLLERS];#ifdef __GNUC__static RTXBD rtx __attribute__ ((aligned(8)));#else#error "rtx must be 64-bit aligned"#endifstatic 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 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);struct phy_info *get_phy_info(struct eth_device *dev);void phy_run_commands(struct tsec_private *priv, struct phy_cmd *cmd);static void adjust_link(struct eth_device *dev);static void relocate_cmds(void);static int tsec_miiphy_write(char *devname, unsigned char addr,			     unsigned char reg, unsigned short value);static int tsec_miiphy_read(char *devname, unsigned char addr,			    unsigned char reg, unsigned short *value);/* Initialize device structure. Returns success if PHY * initialization succeeded (i.e. if it recognizes the PHY) */int tsec_initialize(bd_t * bis, int index, char *devname){	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[index] = priv;	priv->regs = (volatile tsec_t *)(TSEC_BASE_ADDR + index * TSEC_SIZE);	priv->phyregs = (volatile tsec_t *)(TSEC_BASE_ADDR +					    tsec_info[index].phyregidx *					    TSEC_SIZE);	priv->phyaddr = tsec_info[index].phyaddr;	priv->flags = tsec_info[index].flags;	sprintf(dev->name, devname);	dev->iobase = 0;	dev->priv = priv;	dev->init = tsec_init;	dev->halt = tsec_halt;	dev->send = tsec_send;	dev->recv = tsec_recv;	/* 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;	priv->regs->maccfg1 &= ~(MACCFG1_SOFT_RESET);#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_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. */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];	}	regs->macstnaddr1 = *((uint *) (tmpbuf));	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;}/* Write value to the device's PHY through the registers * specified in priv, modifying the register specified in regnum. * It will wait for the write to be done (or for a timeout to * expire) before exiting */void write_phy_reg(struct tsec_private *priv, uint regnum, uint value){	volatile tsec_t *regbase = priv->phyregs;	uint phyid = priv->phyaddr;	int timeout = 1000000;	regbase->miimadd = (phyid << 8) | regnum;	regbase->miimcon = value;	asm("sync");	timeout = 1000000;	while ((regbase->miimind & MIIMIND_BUSY) && timeout--) ;}/* Reads register regnum on the device's PHY through the * registers specified in priv.	 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 */uint read_phy_reg(struct tsec_private *priv, uint regnum){	uint value;	volatile tsec_t *regbase = priv->phyregs;	uint phyid = priv->phyaddr;	/* Put the address of the phy, and the register	 * number into MIIMADD */	regbase->miimadd = (phyid << 8) | regnum;	/* Clear the command register, and wait */	regbase->miimcom = 0;	asm("sync");	/* Initiate a read command, and wait */	regbase->miimcom = MIIM_READ_COMMAND;	asm("sync");	/* Wait for the the indication that the read is done */	while ((regbase->miimind & (MIIMIND_NOTVALID | MIIMIND_BUSY))) ;	/* Grab the value read from the PHY */	value = regbase->miimstat;	return value;}/* 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 = (volatile tsec_t *)(TSEC_BASE_ADDR);	/* Assign a Physical address to the TBI */	regs->tbipa = TBIPA_VALUE;	regs = (volatile tsec_t *)(TSEC_BASE_ADDR + TSEC_SIZE);	regs->tbipa = 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) ;	if (0 == relocated)		relocate_cmds();	/* 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;	}	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 */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;}/* Parse the status register for link, and then do * auto-negotiation */uint mii_parse_sr(uint mii_reg, struct tsec_private * priv){	/*	 * Wait if PHY is capable of autonegotiation and autonegotiation	 * is not complete.	 */	mii_reg = read_phy_reg(priv, MIIM_STATUS);	if ((mii_reg & PHY_BMSR_AUTN_ABLE)	    && !(mii_reg & PHY_BMSR_AUTN_COMP)) {		int i = 0;		puts("Waiting for PHY auto negotiation to complete");		while (!((mii_reg & PHY_BMSR_AUTN_COMP)			 && (mii_reg & MIIM_STATUS_LINK))) {			/*			 * Timeout reached ?			 */			if (i > PHY_AUTONEGOTIATE_TIMEOUT) {				puts(" TIMEOUT !\n");				priv->link = 0;				return 0;			}			if ((i++ % 1000) == 0) {				putc('.');			}			udelay(1000);	/* 1 ms */			mii_reg = read_phy_reg(priv, MIIM_STATUS);		}		puts(" done\n");		priv->link = 1;		udelay(500000);	/* another 500 ms (results in faster booting) */	} else {		priv->link = 1;	}	return 0;}/* Parse the 88E1011's status register for speed and duplex * information */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_SPDDONE) &&	      (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {		int i = 0;		puts("Waiting for PHY realtime link");		while (!((mii_reg & MIIM_88E1011_PHYSTAT_SPDDONE) &&			 (mii_reg & MIIM_88E1011_PHYSTAT_LINK))) {			/*			 * 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) */	}	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;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -