📄 tsi108_eth.c
字号:
*//* PHY Specific Status Register (MV1111_EXT_CTRL1_REG) */#define SPEC_STAT_SPEED_MASK (3 << 14)#define SPEC_STAT_FULL_DUP (1 << 13)#define SPEC_STAT_PAGE_RCVD (1 << 12)#define SPEC_STAT_RESOLVED (1 << 11) /* Speed and Duplex Resolved */#define SPEC_STAT_LINK_UP (1 << 10)#define SPEC_STAT_CABLE_LEN_MASK (7 << 7)/* Cable Length (100/1000 modes only) */#define SPEC_STAT_MDIX (1 << 6)#define SPEC_STAT_POLARITY (1 << 1)#define SPEC_STAT_JABBER (1 << 0)#define SPEED_1000 (2 << 14)#define SPEED_100 (1 << 14)#define SPEED_10 (0 << 14)#define TBI_ADDR 0x1E /* Ten Bit Interface address *//* negotiated link parameters */#define LINK_SPEED_UNKNOWN 0#define LINK_SPEED_10 1#define LINK_SPEED_100 2#define LINK_SPEED_1000 3#define LINK_DUPLEX_UNKNOWN 0#define LINK_DUPLEX_HALF 1#define LINK_DUPLEX_FULL 2static unsigned int phy_address[] = { 8, 9 };#define vuint32 volatile u32/* TX/RX buffer descriptors. MUST be cache line aligned in memory. (32 byte) * This structure is accessed by the ethernet DMA engine which means it * MUST be in LITTLE ENDIAN format */struct dma_descriptor { vuint32 start_addr0; /* buffer address, least significant bytes. */ vuint32 start_addr1; /* buffer address, most significant bytes. */ vuint32 next_descr_addr0;/* next descriptor address, least significant bytes. Must be 64-bit aligned. */ vuint32 next_descr_addr1;/* next descriptor address, most significant bytes. */ vuint32 vlan_byte_count;/* VLAN tag(top 2 bytes) and byte countt (bottom 2 bytes). */ vuint32 config_status; /* Configuration/Status. */ vuint32 reserved1; /* reserved to make the descriptor cache line aligned. */ vuint32 reserved2; /* reserved to make the descriptor cache line aligned. */};/* last next descriptor address flag */#define DMA_DESCR_LAST (1 << 31)/* TX DMA descriptor config status bits */#define DMA_DESCR_TX_EOF (1 << 0) /* end of frame */#define DMA_DESCR_TX_SOF (1 << 1) /* start of frame */#define DMA_DESCR_TX_PFVLAN (1 << 2)#define DMA_DESCR_TX_HUGE (1 << 3)#define DMA_DESCR_TX_PAD (1 << 4)#define DMA_DESCR_TX_CRC (1 << 5)#define DMA_DESCR_TX_DESCR_INT (1 << 14)#define DMA_DESCR_TX_RETRY_COUNT 0x000F0000#define DMA_DESCR_TX_ONE_COLLISION (1 << 20)#define DMA_DESCR_TX_LATE_COLLISION (1 << 24)#define DMA_DESCR_TX_UNDERRUN (1 << 25)#define DMA_DESCR_TX_RETRY_LIMIT (1 << 26)#define DMA_DESCR_TX_OK (1 << 30)#define DMA_DESCR_TX_OWNER (1 << 31)/* RX DMA descriptor status bits */#define DMA_DESCR_RX_EOF (1 << 0)#define DMA_DESCR_RX_SOF (1 << 1)#define DMA_DESCR_RX_VTF (1 << 2)#define DMA_DESCR_RX_FRAME_IS_TYPE (1 << 3)#define DMA_DESCR_RX_SHORT_FRAME (1 << 4)#define DMA_DESCR_RX_HASH_MATCH (1 << 7)#define DMA_DESCR_RX_BAD_FRAME (1 << 8)#define DMA_DESCR_RX_OVERRUN (1 << 9)#define DMA_DESCR_RX_MAX_FRAME_LEN (1 << 11)#define DMA_DESCR_RX_CRC_ERROR (1 << 12)#define DMA_DESCR_RX_DESCR_INT (1 << 13)#define DMA_DESCR_RX_OWNER (1 << 15)#define RX_BUFFER_SIZE PKTSIZE#define NUM_RX_DESC PKTBUFSRXstatic struct dma_descriptor tx_descriptor __attribute__ ((aligned(32)));static struct dma_descriptor rx_descr_array[NUM_RX_DESC] __attribute__ ((aligned(32)));static struct dma_descriptor *rx_descr_current;static int tsi108_eth_probe (struct eth_device *dev, bd_t * bis);static int tsi108_eth_send (struct eth_device *dev, volatile void *packet, int length);static int tsi108_eth_recv (struct eth_device *dev);static void tsi108_eth_halt (struct eth_device *dev);static unsigned int read_phy (unsigned int base, unsigned int phy_addr, unsigned int phy_reg);static void write_phy (unsigned int base, unsigned int phy_addr, unsigned int phy_reg, unsigned int phy_data);#if TSI108_ETH_DEBUG > 100/* * print phy debug infomation */static void dump_phy_regs (unsigned int phy_addr){ int i; printf ("PHY %d registers\n", phy_addr); for (i = 0; i <= 30; i++) { printf ("%2d 0x%04x\n", i, read_phy (ETH_BASE, phy_addr, i)); } printf ("\n");}#else#define dump_phy_regs(base) do{}while(0)#endif#if TSI108_ETH_DEBUG > 100/* * print debug infomation */static void tx_diag_regs (unsigned int base){ int i; unsigned long dummy; printf ("TX diagnostics registers\n"); reg_TX_DIAGNOSTIC_ADDR(base) = 0x00 | TX_DIAGNOSTIC_ADDR_AI; udelay (1000); dummy = reg_TX_DIAGNOSTIC_DATA(base); for (i = 0x00; i <= 0x05; i++) { udelay (1000); printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base)); } reg_TX_DIAGNOSTIC_ADDR(base) = 0x40 | TX_DIAGNOSTIC_ADDR_AI; udelay (1000); dummy = reg_TX_DIAGNOSTIC_DATA(base); for (i = 0x40; i <= 0x47; i++) { udelay (1000); printf ("0x%02x 0x%08x\n", i, reg_TX_DIAGNOSTIC_DATA(base)); } printf ("\n");}#else#define tx_diag_regs(base) do{}while(0)#endif#if TSI108_ETH_DEBUG > 100/* * print debug infomation */static void rx_diag_regs (unsigned int base){ int i; unsigned long dummy; printf ("RX diagnostics registers\n"); reg_RX_DIAGNOSTIC_ADDR(base) = 0x00 | RX_DIAGNOSTIC_ADDR_AI; udelay (1000); dummy = reg_RX_DIAGNOSTIC_DATA(base); for (i = 0x00; i <= 0x05; i++) { udelay (1000); printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base)); } reg_RX_DIAGNOSTIC_ADDR(base) = 0x40 | RX_DIAGNOSTIC_ADDR_AI; udelay (1000); dummy = reg_RX_DIAGNOSTIC_DATA(base); for (i = 0x08; i <= 0x0a; i++) { udelay (1000); printf ("0x%02x 0x%08x\n", i, reg_RX_DIAGNOSTIC_DATA(base)); } printf ("\n");}#else#define rx_diag_regs(base) do{}while(0)#endif#if TSI108_ETH_DEBUG > 100/* * print debug infomation */static void debug_mii_regs (unsigned int base){ printf ("MII_MGMT_CONFIG 0x%08x\n", reg_MII_MGMT_CONFIG(base)); printf ("MII_MGMT_COMMAND 0x%08x\n", reg_MII_MGMT_COMMAND(base)); printf ("MII_MGMT_ADDRESS 0x%08x\n", reg_MII_MGMT_ADDRESS(base)); printf ("MII_MGMT_CONTROL 0x%08x\n", reg_MII_MGMT_CONTROL(base)); printf ("MII_MGMT_STATUS 0x%08x\n", reg_MII_MGMT_STATUS(base)); printf ("MII_MGMT_INDICATORS 0x%08x\n", reg_MII_MGMT_INDICATORS(base)); printf ("\n");}#else#define debug_mii_regs(base) do{}while(0)#endif/* * Wait until the phy bus is non-busy */static void phy_wait (unsigned int base, unsigned int condition){ int timeout; timeout = 0; while (reg_MII_MGMT_INDICATORS(base) & condition) { udelay (10); if (++timeout > 10000) { printf ("ERROR: timeout waiting for phy bus (%d)\n", condition); break; } }}/* * read phy register */static unsigned int read_phy (unsigned int base, unsigned int phy_addr, unsigned int phy_reg){ unsigned int value; phy_wait (base, MII_MGMT_INDICATORS_BUSY); reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg; /* Ensure that the Read Cycle bit is cleared prior to next read cycle */ reg_MII_MGMT_COMMAND(base) = 0; /* start the read */ reg_MII_MGMT_COMMAND(base) = MII_MGMT_COMMAND_READ_CYCLE; /* wait for the read to complete */ phy_wait (base, MII_MGMT_INDICATORS_NOT_VALID | MII_MGMT_INDICATORS_BUSY); value = reg_MII_MGMT_STATUS(base); reg_MII_MGMT_COMMAND(base) = 0; return value;}/* * write phy register */static void write_phy (unsigned int base, unsigned int phy_addr, unsigned int phy_reg, unsigned int phy_data){ phy_wait (base, MII_MGMT_INDICATORS_BUSY); reg_MII_MGMT_ADDRESS(base) = (phy_addr << 8) | phy_reg; /* Ensure that the Read Cycle bit is cleared prior to next cycle */ reg_MII_MGMT_COMMAND(base) = 0; /* start the write */ reg_MII_MGMT_CONTROL(base) = phy_data;}/* * configure the marvell 88e1111 phy */static int marvell_88e_phy_config (struct eth_device *dev, int *speed, int *duplex){ unsigned long base; unsigned long phy_addr; unsigned int phy_status; unsigned int phy_spec_status; int timeout; int phy_speed; int phy_duplex; unsigned int value; phy_speed = LINK_SPEED_UNKNOWN; phy_duplex = LINK_DUPLEX_UNKNOWN; base = dev->iobase; phy_addr = (unsigned long)dev->priv; /* Take the PHY out of reset. */ write_phy (ETH_BASE, phy_addr, PHY_CTRL_REG, PHY_CTRL_RESET); /* Wait for the reset process to complete. */ udelay (10); timeout = 0; while ((phy_status = read_phy (ETH_BASE, phy_addr, PHY_CTRL_REG)) & PHY_CTRL_RESET) { udelay (10); if (++timeout > 10000) { printf ("ERROR: timeout waiting for phy reset\n"); break; } } /* TBI Configuration. */ write_phy (base, TBI_ADDR, TBI_CONTROL_2, TBI_CONTROL_2_G_MII_MODE | TBI_CONTROL_2_RECEIVE_CLOCK_SELECT); /* Wait for the link to be established. */ timeout = 0; do { udelay (20000); phy_status = read_phy (ETH_BASE, phy_addr, PHY_STATUS_REG); if (++timeout > 100) { debug_lev(1, "ERROR: unable to establish link!!!\n"); break; } } while ((phy_status & PHY_STAT_LINK_UP) == 0); if ((phy_status & PHY_STAT_LINK_UP) == 0) return 0; value = 0; phy_spec_status = read_phy (ETH_BASE, phy_addr, MV1111_SPEC_STAT_REG); if (phy_spec_status & SPEC_STAT_RESOLVED) { switch (phy_spec_status & SPEC_STAT_SPEED_MASK) { case SPEED_1000: phy_speed = LINK_SPEED_1000; value |= PHY_CTRL_SPEED1; break; case SPEED_100: phy_speed = LINK_SPEED_100; value |= PHY_CTRL_SPEED0; break; case SPEED_10: phy_speed = LINK_SPEED_10; break; } if (phy_spec_status & SPEC_STAT_FULL_DUP) { phy_duplex = LINK_DUPLEX_FULL; value |= PHY_CTRL_FULL_DUPLEX; } else phy_duplex = LINK_DUPLEX_HALF; } /* set TBI speed */ write_phy (base, TBI_ADDR, PHY_CTRL_REG, value); write_phy (base, TBI_ADDR, PHY_AN_ADV_REG, 0x0060);#if TSI108_ETH_DEBUG > 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -