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

📄 tsec.c

📁 U-Boot1.1.2是最为常用的嵌入式系统Bootloader
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * tsec.c * 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. * maintained by Jon Loeliger (loeliger@freescale.com) * author Andy Fleming * */#include <config.h>#include <mpc85xx.h>#include <common.h>#include <malloc.h>#include <net.h>#include <command.h>#if defined(CONFIG_TSEC_ENET)#include "tsec.h"#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;	unsigned int gigabit;	unsigned int phyregidx;};/* The tsec_info structure contains 3 values which the * driver uses to determine how to operate a given ethernet * device.  For now, the structure is initialized with the * knowledge that all current implementations have 2 TSEC * devices, and one FEC.  The information needed is: *  phyaddr - The address of the PHY which is attached to *      the given device. * *  gigabit - This variable indicates whether the device *      supports gigabit speed ethernet * *  phyregidx - This variable specifies which ethernet device *      controls the MII Management registers which are connected *      to the PHY.  For 8540/8560, 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: *   TSEC1_PHY_ADDR *   TSEC1_PHYIDX *   TSEC2_PHY_ADDR *   TSEC2_PHYIDX * * and for 8560: *   FEC_PHY_ADDR *   FEC_PHYIDX */static struct tsec_info_struct tsec_info[] = {#ifdef CONFIG_MPC85XX_TSEC1	{TSEC1_PHY_ADDR, 1, TSEC1_PHYIDX},#endif#ifdef CONFIG_MPC85XX_TSEC2	{TSEC2_PHY_ADDR, 1, TSEC2_PHYIDX},#endif#ifdef CONFIG_MPC85XX_FEC	{FEC_PHY_ADDR, 0, FEC_PHYIDX},#endif};#define MAXCONTROLLERS 3static 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);/* Initialize device structure. Returns success if PHY * initialization succeeded (i.e. if it recognizes the PHY) */int tsec_initialize(bd_t *bis, int index){	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->gigabit = tsec_info[index].gigabit;	sprintf(dev->name, "MOTO ENET%d", index);	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);	/* 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];	}	(uint)(regs->macstnaddr1) = *((uint *)(tmpbuf));	tempval = *((uint *)(tmpbuf +4));	(uint)(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("msync");	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("msync");	/* Initiate a read command, and wait */	regbase->miimcom = MIIM_READ_COMMAND;	asm("msync");	/* 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;	/* Assign a Physical address to the TBI */	priv->regs->tbipa=TBIPA_VALUE;	if(0 == relocated)		relocate_cmds();	/* Get the cmd structure corresponding to the attached	 * PHY */	curphy = get_phy_info(dev);	if(NULL == curphy) {		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->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){	uint timeout = TSEC_TIMEOUT;	if(mii_reg & MIIM_STATUS_LINK)		priv->link = 1;	else		priv->link = 0;	if(priv->link) {		while((!(mii_reg & MIIM_STATUS_AN_DONE)) && timeout--)			mii_reg = read_phy_reg(priv, MIIM_STATUS);	}	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;	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 cis8201's status register for speed and duplex * information */uint mii_parse_cis8201(uint mii_reg, struct tsec_private *priv){	uint speed;	if(mii_reg & MIIM_CIS8201_AUXCONSTAT_DUPLEX)		priv->duplexity = 1;	else		priv->duplexity = 0;	speed = mii_reg & MIIM_CIS8201_AUXCONSTAT_SPEED;	switch(speed) {		case MIIM_CIS8201_AUXCONSTAT_GBIT:			priv->speed = 1000;			break;		case MIIM_CIS8201_AUXCONSTAT_100:			priv->speed = 100;			break;		default:			priv->speed = 10;			break;	}	return 0;}/* Parse the DM9161's status register for speed and duplex * information */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 */uint mii_cis8204_fixled(uint mii_reg, struct tsec_private *priv){	uint phyid;	volatile tsec_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("msync");		timeout=1000000;		while((regbase->miimind & MIIMIND_BUSY) && timeout--);	}	return MIIM_CIS8204_SLEDCON_INIT;}/* 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;}/* 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;

⌨️ 快捷键说明

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