1de1b686bSSascha Hauer /* 2de1b686bSSascha Hauer * SMSC LAN9[12]1[567] Network driver 3de1b686bSSascha Hauer * 4*cce9cfdaSStelian Pop * (c) 2007 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> 5de1b686bSSascha Hauer * 6de1b686bSSascha Hauer * See file CREDITS for list of people who contributed to this 7de1b686bSSascha Hauer * project. 8de1b686bSSascha Hauer * 9de1b686bSSascha Hauer * This program is free software; you can redistribute it and/or 10de1b686bSSascha Hauer * modify it under the terms of the GNU General Public License as 11de1b686bSSascha Hauer * published by the Free Software Foundation; either version 2 of 12de1b686bSSascha Hauer * the License, or (at your option) any later version. 13de1b686bSSascha Hauer * 14de1b686bSSascha Hauer * This program is distributed in the hope that it will be useful, 15de1b686bSSascha Hauer * but WITHOUT ANY WARRANTY; without even the implied warranty of 16de1b686bSSascha Hauer * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17de1b686bSSascha Hauer * GNU General Public License for more details. 18de1b686bSSascha Hauer * 19de1b686bSSascha Hauer * You should have received a copy of the GNU General Public License 20de1b686bSSascha Hauer * along with this program; if not, write to the Free Software 21de1b686bSSascha Hauer * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22de1b686bSSascha Hauer * MA 02111-1307 USA 23de1b686bSSascha Hauer */ 24de1b686bSSascha Hauer 25de1b686bSSascha Hauer #include <common.h> 26de1b686bSSascha Hauer 27de1b686bSSascha Hauer #ifdef CONFIG_DRIVER_SMC911X 28de1b686bSSascha Hauer 29de1b686bSSascha Hauer #include <command.h> 30de1b686bSSascha Hauer #include <net.h> 31de1b686bSSascha Hauer #include <miiphy.h> 32de1b686bSSascha Hauer 333e0f331cSGuennadi Liakhovetski #ifdef CONFIG_DRIVER_SMC911X_32_BIT 343e0f331cSGuennadi Liakhovetski static inline u32 reg_read(u32 addr) 353e0f331cSGuennadi Liakhovetski { 363e0f331cSGuennadi Liakhovetski return *(volatile u32*)addr; 373e0f331cSGuennadi Liakhovetski } 383e0f331cSGuennadi Liakhovetski static inline void reg_write(u32 addr, u32 val) 393e0f331cSGuennadi Liakhovetski { 403e0f331cSGuennadi Liakhovetski *(volatile u32*)addr = val; 413e0f331cSGuennadi Liakhovetski } 423e0f331cSGuennadi Liakhovetski #else 433e0f331cSGuennadi Liakhovetski #error "SMC911X: Only 32-bit bus is supported" 443e0f331cSGuennadi Liakhovetski #endif 45de1b686bSSascha Hauer 463e0f331cSGuennadi Liakhovetski #define mdelay(n) udelay((n)*1000) 47de1b686bSSascha Hauer 48de1b686bSSascha Hauer /* Below are the register offsets and bit definitions 49de1b686bSSascha Hauer * of the Lan911x memory space 50de1b686bSSascha Hauer */ 513e0f331cSGuennadi Liakhovetski #define RX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x00) 52de1b686bSSascha Hauer 533e0f331cSGuennadi Liakhovetski #define TX_DATA_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x20) 543e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_ON_COMP 0x80000000 553e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_BUF_END_ALGN 0x03000000 563e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_4_BYTE_ALGN 0x00000000 573e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_16_BYTE_ALGN 0x01000000 583e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_32_BYTE_ALGN 0x02000000 593e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_DATA_OFFSET 0x001F0000 603e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_FIRST_SEG 0x00002000 613e0f331cSGuennadi Liakhovetski #define TX_CMD_A_INT_LAST_SEG 0x00001000 623e0f331cSGuennadi Liakhovetski #define TX_CMD_A_BUF_SIZE 0x000007FF 633e0f331cSGuennadi Liakhovetski #define TX_CMD_B_PKT_TAG 0xFFFF0000 643e0f331cSGuennadi Liakhovetski #define TX_CMD_B_ADD_CRC_DISABLE 0x00002000 653e0f331cSGuennadi Liakhovetski #define TX_CMD_B_DISABLE_PADDING 0x00001000 663e0f331cSGuennadi Liakhovetski #define TX_CMD_B_PKT_BYTE_LENGTH 0x000007FF 67de1b686bSSascha Hauer 683e0f331cSGuennadi Liakhovetski #define RX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x40) 693e0f331cSGuennadi Liakhovetski #define RX_STS_PKT_LEN 0x3FFF0000 703e0f331cSGuennadi Liakhovetski #define RX_STS_ES 0x00008000 713e0f331cSGuennadi Liakhovetski #define RX_STS_BCST 0x00002000 723e0f331cSGuennadi Liakhovetski #define RX_STS_LEN_ERR 0x00001000 733e0f331cSGuennadi Liakhovetski #define RX_STS_RUNT_ERR 0x00000800 743e0f331cSGuennadi Liakhovetski #define RX_STS_MCAST 0x00000400 753e0f331cSGuennadi Liakhovetski #define RX_STS_TOO_LONG 0x00000080 763e0f331cSGuennadi Liakhovetski #define RX_STS_COLL 0x00000040 773e0f331cSGuennadi Liakhovetski #define RX_STS_ETH_TYPE 0x00000020 783e0f331cSGuennadi Liakhovetski #define RX_STS_WDOG_TMT 0x00000010 793e0f331cSGuennadi Liakhovetski #define RX_STS_MII_ERR 0x00000008 803e0f331cSGuennadi Liakhovetski #define RX_STS_DRIBBLING 0x00000004 813e0f331cSGuennadi Liakhovetski #define RX_STS_CRC_ERR 0x00000002 823e0f331cSGuennadi Liakhovetski #define RX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x44) 833e0f331cSGuennadi Liakhovetski #define TX_STATUS_FIFO (CONFIG_DRIVER_SMC911X_BASE + 0x48) 843e0f331cSGuennadi Liakhovetski #define TX_STS_TAG 0xFFFF0000 853e0f331cSGuennadi Liakhovetski #define TX_STS_ES 0x00008000 863e0f331cSGuennadi Liakhovetski #define TX_STS_LOC 0x00000800 873e0f331cSGuennadi Liakhovetski #define TX_STS_NO_CARR 0x00000400 883e0f331cSGuennadi Liakhovetski #define TX_STS_LATE_COLL 0x00000200 893e0f331cSGuennadi Liakhovetski #define TX_STS_MANY_COLL 0x00000100 903e0f331cSGuennadi Liakhovetski #define TX_STS_COLL_CNT 0x00000078 913e0f331cSGuennadi Liakhovetski #define TX_STS_MANY_DEFER 0x00000004 923e0f331cSGuennadi Liakhovetski #define TX_STS_UNDERRUN 0x00000002 933e0f331cSGuennadi Liakhovetski #define TX_STS_DEFERRED 0x00000001 943e0f331cSGuennadi Liakhovetski #define TX_STATUS_FIFO_PEEK (CONFIG_DRIVER_SMC911X_BASE + 0x4C) 953e0f331cSGuennadi Liakhovetski #define ID_REV (CONFIG_DRIVER_SMC911X_BASE + 0x50) 963e0f331cSGuennadi Liakhovetski #define ID_REV_CHIP_ID 0xFFFF0000 /* RO */ 973e0f331cSGuennadi Liakhovetski #define ID_REV_REV_ID 0x0000FFFF /* RO */ 98de1b686bSSascha Hauer 993e0f331cSGuennadi Liakhovetski #define INT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x54) 1003e0f331cSGuennadi Liakhovetski #define INT_CFG_INT_DEAS 0xFF000000 /* R/W */ 1013e0f331cSGuennadi Liakhovetski #define INT_CFG_INT_DEAS_CLR 0x00004000 1023e0f331cSGuennadi Liakhovetski #define INT_CFG_INT_DEAS_STS 0x00002000 1033e0f331cSGuennadi Liakhovetski #define INT_CFG_IRQ_INT 0x00001000 /* RO */ 1043e0f331cSGuennadi Liakhovetski #define INT_CFG_IRQ_EN 0x00000100 /* R/W */ 1053e0f331cSGuennadi Liakhovetski #define INT_CFG_IRQ_POL 0x00000010 /* R/W Not Affected by SW Reset */ 1063e0f331cSGuennadi Liakhovetski #define INT_CFG_IRQ_TYPE 0x00000001 /* R/W Not Affected by SW Reset */ 107de1b686bSSascha Hauer 1083e0f331cSGuennadi Liakhovetski #define INT_STS (CONFIG_DRIVER_SMC911X_BASE + 0x58) 1093e0f331cSGuennadi Liakhovetski #define INT_STS_SW_INT 0x80000000 /* R/WC */ 1103e0f331cSGuennadi Liakhovetski #define INT_STS_TXSTOP_INT 0x02000000 /* R/WC */ 1113e0f331cSGuennadi Liakhovetski #define INT_STS_RXSTOP_INT 0x01000000 /* R/WC */ 1123e0f331cSGuennadi Liakhovetski #define INT_STS_RXDFH_INT 0x00800000 /* R/WC */ 1133e0f331cSGuennadi Liakhovetski #define INT_STS_RXDF_INT 0x00400000 /* R/WC */ 1143e0f331cSGuennadi Liakhovetski #define INT_STS_TX_IOC 0x00200000 /* R/WC */ 1153e0f331cSGuennadi Liakhovetski #define INT_STS_RXD_INT 0x00100000 /* R/WC */ 1163e0f331cSGuennadi Liakhovetski #define INT_STS_GPT_INT 0x00080000 /* R/WC */ 1173e0f331cSGuennadi Liakhovetski #define INT_STS_PHY_INT 0x00040000 /* RO */ 1183e0f331cSGuennadi Liakhovetski #define INT_STS_PME_INT 0x00020000 /* R/WC */ 1193e0f331cSGuennadi Liakhovetski #define INT_STS_TXSO 0x00010000 /* R/WC */ 1203e0f331cSGuennadi Liakhovetski #define INT_STS_RWT 0x00008000 /* R/WC */ 1213e0f331cSGuennadi Liakhovetski #define INT_STS_RXE 0x00004000 /* R/WC */ 1223e0f331cSGuennadi Liakhovetski #define INT_STS_TXE 0x00002000 /* R/WC */ 1233e0f331cSGuennadi Liakhovetski /*#define INT_STS_ERX 0x00001000*/ /* R/WC */ 1243e0f331cSGuennadi Liakhovetski #define INT_STS_TDFU 0x00000800 /* R/WC */ 1253e0f331cSGuennadi Liakhovetski #define INT_STS_TDFO 0x00000400 /* R/WC */ 1263e0f331cSGuennadi Liakhovetski #define INT_STS_TDFA 0x00000200 /* R/WC */ 1273e0f331cSGuennadi Liakhovetski #define INT_STS_TSFF 0x00000100 /* R/WC */ 1283e0f331cSGuennadi Liakhovetski #define INT_STS_TSFL 0x00000080 /* R/WC */ 1293e0f331cSGuennadi Liakhovetski /*#define INT_STS_RXDF 0x00000040*/ /* R/WC */ 1303e0f331cSGuennadi Liakhovetski #define INT_STS_RDFO 0x00000040 /* R/WC */ 1313e0f331cSGuennadi Liakhovetski #define INT_STS_RDFL 0x00000020 /* R/WC */ 1323e0f331cSGuennadi Liakhovetski #define INT_STS_RSFF 0x00000010 /* R/WC */ 1333e0f331cSGuennadi Liakhovetski #define INT_STS_RSFL 0x00000008 /* R/WC */ 1343e0f331cSGuennadi Liakhovetski #define INT_STS_GPIO2_INT 0x00000004 /* R/WC */ 1353e0f331cSGuennadi Liakhovetski #define INT_STS_GPIO1_INT 0x00000002 /* R/WC */ 1363e0f331cSGuennadi Liakhovetski #define INT_STS_GPIO0_INT 0x00000001 /* R/WC */ 1373e0f331cSGuennadi Liakhovetski #define INT_EN (CONFIG_DRIVER_SMC911X_BASE + 0x5C) 1383e0f331cSGuennadi Liakhovetski #define INT_EN_SW_INT_EN 0x80000000 /* R/W */ 1393e0f331cSGuennadi Liakhovetski #define INT_EN_TXSTOP_INT_EN 0x02000000 /* R/W */ 1403e0f331cSGuennadi Liakhovetski #define INT_EN_RXSTOP_INT_EN 0x01000000 /* R/W */ 1413e0f331cSGuennadi Liakhovetski #define INT_EN_RXDFH_INT_EN 0x00800000 /* R/W */ 1423e0f331cSGuennadi Liakhovetski /*#define INT_EN_RXDF_INT_EN 0x00400000*/ /* R/W */ 1433e0f331cSGuennadi Liakhovetski #define INT_EN_TIOC_INT_EN 0x00200000 /* R/W */ 1443e0f331cSGuennadi Liakhovetski #define INT_EN_RXD_INT_EN 0x00100000 /* R/W */ 1453e0f331cSGuennadi Liakhovetski #define INT_EN_GPT_INT_EN 0x00080000 /* R/W */ 1463e0f331cSGuennadi Liakhovetski #define INT_EN_PHY_INT_EN 0x00040000 /* R/W */ 1473e0f331cSGuennadi Liakhovetski #define INT_EN_PME_INT_EN 0x00020000 /* R/W */ 1483e0f331cSGuennadi Liakhovetski #define INT_EN_TXSO_EN 0x00010000 /* R/W */ 1493e0f331cSGuennadi Liakhovetski #define INT_EN_RWT_EN 0x00008000 /* R/W */ 1503e0f331cSGuennadi Liakhovetski #define INT_EN_RXE_EN 0x00004000 /* R/W */ 1513e0f331cSGuennadi Liakhovetski #define INT_EN_TXE_EN 0x00002000 /* R/W */ 1523e0f331cSGuennadi Liakhovetski /*#define INT_EN_ERX_EN 0x00001000*/ /* R/W */ 1533e0f331cSGuennadi Liakhovetski #define INT_EN_TDFU_EN 0x00000800 /* R/W */ 1543e0f331cSGuennadi Liakhovetski #define INT_EN_TDFO_EN 0x00000400 /* R/W */ 1553e0f331cSGuennadi Liakhovetski #define INT_EN_TDFA_EN 0x00000200 /* R/W */ 1563e0f331cSGuennadi Liakhovetski #define INT_EN_TSFF_EN 0x00000100 /* R/W */ 1573e0f331cSGuennadi Liakhovetski #define INT_EN_TSFL_EN 0x00000080 /* R/W */ 1583e0f331cSGuennadi Liakhovetski /*#define INT_EN_RXDF_EN 0x00000040*/ /* R/W */ 1593e0f331cSGuennadi Liakhovetski #define INT_EN_RDFO_EN 0x00000040 /* R/W */ 1603e0f331cSGuennadi Liakhovetski #define INT_EN_RDFL_EN 0x00000020 /* R/W */ 1613e0f331cSGuennadi Liakhovetski #define INT_EN_RSFF_EN 0x00000010 /* R/W */ 1623e0f331cSGuennadi Liakhovetski #define INT_EN_RSFL_EN 0x00000008 /* R/W */ 1633e0f331cSGuennadi Liakhovetski #define INT_EN_GPIO2_INT 0x00000004 /* R/W */ 1643e0f331cSGuennadi Liakhovetski #define INT_EN_GPIO1_INT 0x00000002 /* R/W */ 1653e0f331cSGuennadi Liakhovetski #define INT_EN_GPIO0_INT 0x00000001 /* R/W */ 166de1b686bSSascha Hauer 1673e0f331cSGuennadi Liakhovetski #define BYTE_TEST (CONFIG_DRIVER_SMC911X_BASE + 0x64) 1683e0f331cSGuennadi Liakhovetski #define FIFO_INT (CONFIG_DRIVER_SMC911X_BASE + 0x68) 1693e0f331cSGuennadi Liakhovetski #define FIFO_INT_TX_AVAIL_LEVEL 0xFF000000 /* R/W */ 1703e0f331cSGuennadi Liakhovetski #define FIFO_INT_TX_STS_LEVEL 0x00FF0000 /* R/W */ 1713e0f331cSGuennadi Liakhovetski #define FIFO_INT_RX_AVAIL_LEVEL 0x0000FF00 /* R/W */ 1723e0f331cSGuennadi Liakhovetski #define FIFO_INT_RX_STS_LEVEL 0x000000FF /* R/W */ 173de1b686bSSascha Hauer 1743e0f331cSGuennadi Liakhovetski #define RX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x6C) 1753e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_END_ALGN 0xC0000000 /* R/W */ 1763e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_END_ALGN4 0x00000000 /* R/W */ 1773e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_END_ALGN16 0x40000000 /* R/W */ 1783e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_END_ALGN32 0x80000000 /* R/W */ 1793e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_DMA_CNT 0x0FFF0000 /* R/W */ 1803e0f331cSGuennadi Liakhovetski #define RX_CFG_RX_DUMP 0x00008000 /* R/W */ 1813e0f331cSGuennadi Liakhovetski #define RX_CFG_RXDOFF 0x00001F00 /* R/W */ 1823e0f331cSGuennadi Liakhovetski /*#define RX_CFG_RXBAD 0x00000001*/ /* R/W */ 183de1b686bSSascha Hauer 1843e0f331cSGuennadi Liakhovetski #define TX_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x70) 1853e0f331cSGuennadi Liakhovetski /*#define TX_CFG_TX_DMA_LVL 0xE0000000*/ /* R/W */ 1863e0f331cSGuennadi Liakhovetski /*#define TX_CFG_TX_DMA_CNT 0x0FFF0000*/ /* R/W Self Clearing */ 1873e0f331cSGuennadi Liakhovetski #define TX_CFG_TXS_DUMP 0x00008000 /* Self Clearing */ 1883e0f331cSGuennadi Liakhovetski #define TX_CFG_TXD_DUMP 0x00004000 /* Self Clearing */ 1893e0f331cSGuennadi Liakhovetski #define TX_CFG_TXSAO 0x00000004 /* R/W */ 1903e0f331cSGuennadi Liakhovetski #define TX_CFG_TX_ON 0x00000002 /* R/W */ 1913e0f331cSGuennadi Liakhovetski #define TX_CFG_STOP_TX 0x00000001 /* Self Clearing */ 192de1b686bSSascha Hauer 1933e0f331cSGuennadi Liakhovetski #define HW_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x74) 1943e0f331cSGuennadi Liakhovetski #define HW_CFG_TTM 0x00200000 /* R/W */ 1953e0f331cSGuennadi Liakhovetski #define HW_CFG_SF 0x00100000 /* R/W */ 1963e0f331cSGuennadi Liakhovetski #define HW_CFG_TX_FIF_SZ 0x000F0000 /* R/W */ 1973e0f331cSGuennadi Liakhovetski #define HW_CFG_TR 0x00003000 /* R/W */ 1983e0f331cSGuennadi Liakhovetski #define HW_CFG_PHY_CLK_SEL 0x00000060 /* R/W */ 1993e0f331cSGuennadi Liakhovetski #define HW_CFG_PHY_CLK_SEL_INT_PHY 0x00000000 /* R/W */ 2003e0f331cSGuennadi Liakhovetski #define HW_CFG_PHY_CLK_SEL_EXT_PHY 0x00000020 /* R/W */ 2013e0f331cSGuennadi Liakhovetski #define HW_CFG_PHY_CLK_SEL_CLK_DIS 0x00000040 /* R/W */ 2023e0f331cSGuennadi Liakhovetski #define HW_CFG_SMI_SEL 0x00000010 /* R/W */ 2033e0f331cSGuennadi Liakhovetski #define HW_CFG_EXT_PHY_DET 0x00000008 /* RO */ 2043e0f331cSGuennadi Liakhovetski #define HW_CFG_EXT_PHY_EN 0x00000004 /* R/W */ 2053e0f331cSGuennadi Liakhovetski #define HW_CFG_32_16_BIT_MODE 0x00000004 /* RO */ 2063e0f331cSGuennadi Liakhovetski #define HW_CFG_SRST_TO 0x00000002 /* RO */ 2073e0f331cSGuennadi Liakhovetski #define HW_CFG_SRST 0x00000001 /* Self Clearing */ 208de1b686bSSascha Hauer 2093e0f331cSGuennadi Liakhovetski #define RX_DP_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x78) 2103e0f331cSGuennadi Liakhovetski #define RX_DP_CTRL_RX_FFWD 0x80000000 /* R/W */ 2113e0f331cSGuennadi Liakhovetski #define RX_DP_CTRL_FFWD_BUSY 0x80000000 /* RO */ 212de1b686bSSascha Hauer 2133e0f331cSGuennadi Liakhovetski #define RX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x7C) 2143e0f331cSGuennadi Liakhovetski #define RX_FIFO_INF_RXSUSED 0x00FF0000 /* RO */ 2153e0f331cSGuennadi Liakhovetski #define RX_FIFO_INF_RXDUSED 0x0000FFFF /* RO */ 216de1b686bSSascha Hauer 2173e0f331cSGuennadi Liakhovetski #define TX_FIFO_INF (CONFIG_DRIVER_SMC911X_BASE + 0x80) 2183e0f331cSGuennadi Liakhovetski #define TX_FIFO_INF_TSUSED 0x00FF0000 /* RO */ 2193e0f331cSGuennadi Liakhovetski #define TX_FIFO_INF_TDFREE 0x0000FFFF /* RO */ 220de1b686bSSascha Hauer 2213e0f331cSGuennadi Liakhovetski #define PMT_CTRL (CONFIG_DRIVER_SMC911X_BASE + 0x84) 2223e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PM_MODE 0x00003000 /* Self Clearing */ 2233e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PHY_RST 0x00000400 /* Self Clearing */ 2243e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WOL_EN 0x00000200 /* R/W */ 2253e0f331cSGuennadi Liakhovetski #define PMT_CTRL_ED_EN 0x00000100 /* R/W */ 2263e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PME_TYPE 0x00000040 /* R/W Not Affected by SW Reset */ 2273e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WUPS 0x00000030 /* R/WC */ 2283e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WUPS_NOWAKE 0x00000000 /* R/WC */ 2293e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WUPS_ED 0x00000010 /* R/WC */ 2303e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WUPS_WOL 0x00000020 /* R/WC */ 2313e0f331cSGuennadi Liakhovetski #define PMT_CTRL_WUPS_MULTI 0x00000030 /* R/WC */ 2323e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PME_IND 0x00000008 /* R/W */ 2333e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PME_POL 0x00000004 /* R/W */ 2343e0f331cSGuennadi Liakhovetski #define PMT_CTRL_PME_EN 0x00000002 /* R/W Not Affected by SW Reset */ 2353e0f331cSGuennadi Liakhovetski #define PMT_CTRL_READY 0x00000001 /* RO */ 236de1b686bSSascha Hauer 2373e0f331cSGuennadi Liakhovetski #define GPIO_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x88) 2383e0f331cSGuennadi Liakhovetski #define GPIO_CFG_LED3_EN 0x40000000 /* R/W */ 2393e0f331cSGuennadi Liakhovetski #define GPIO_CFG_LED2_EN 0x20000000 /* R/W */ 2403e0f331cSGuennadi Liakhovetski #define GPIO_CFG_LED1_EN 0x10000000 /* R/W */ 2413e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIO2_INT_POL 0x04000000 /* R/W */ 2423e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIO1_INT_POL 0x02000000 /* R/W */ 2433e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIO0_INT_POL 0x01000000 /* R/W */ 2443e0f331cSGuennadi Liakhovetski #define GPIO_CFG_EEPR_EN 0x00700000 /* R/W */ 2453e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOBUF2 0x00040000 /* R/W */ 2463e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOBUF1 0x00020000 /* R/W */ 2473e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOBUF0 0x00010000 /* R/W */ 2483e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIODIR2 0x00000400 /* R/W */ 2493e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIODIR1 0x00000200 /* R/W */ 2503e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIODIR0 0x00000100 /* R/W */ 2513e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOD4 0x00000010 /* R/W */ 2523e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOD3 0x00000008 /* R/W */ 2533e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOD2 0x00000004 /* R/W */ 2543e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOD1 0x00000002 /* R/W */ 2553e0f331cSGuennadi Liakhovetski #define GPIO_CFG_GPIOD0 0x00000001 /* R/W */ 256de1b686bSSascha Hauer 2573e0f331cSGuennadi Liakhovetski #define GPT_CFG (CONFIG_DRIVER_SMC911X_BASE + 0x8C) 2583e0f331cSGuennadi Liakhovetski #define GPT_CFG_TIMER_EN 0x20000000 /* R/W */ 2593e0f331cSGuennadi Liakhovetski #define GPT_CFG_GPT_LOAD 0x0000FFFF /* R/W */ 260de1b686bSSascha Hauer 2613e0f331cSGuennadi Liakhovetski #define GPT_CNT (CONFIG_DRIVER_SMC911X_BASE + 0x90) 2623e0f331cSGuennadi Liakhovetski #define GPT_CNT_GPT_CNT 0x0000FFFF /* RO */ 263de1b686bSSascha Hauer 2643e0f331cSGuennadi Liakhovetski #define ENDIAN (CONFIG_DRIVER_SMC911X_BASE + 0x98) 2653e0f331cSGuennadi Liakhovetski #define FREE_RUN (CONFIG_DRIVER_SMC911X_BASE + 0x9C) 2663e0f331cSGuennadi Liakhovetski #define RX_DROP (CONFIG_DRIVER_SMC911X_BASE + 0xA0) 2673e0f331cSGuennadi Liakhovetski #define MAC_CSR_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xA4) 2683e0f331cSGuennadi Liakhovetski #define MAC_CSR_CMD_CSR_BUSY 0x80000000 /* Self Clearing */ 2693e0f331cSGuennadi Liakhovetski #define MAC_CSR_CMD_R_NOT_W 0x40000000 /* R/W */ 2703e0f331cSGuennadi Liakhovetski #define MAC_CSR_CMD_CSR_ADDR 0x000000FF /* R/W */ 271de1b686bSSascha Hauer 2723e0f331cSGuennadi Liakhovetski #define MAC_CSR_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xA8) 2733e0f331cSGuennadi Liakhovetski #define AFC_CFG (CONFIG_DRIVER_SMC911X_BASE + 0xAC) 2743e0f331cSGuennadi Liakhovetski #define AFC_CFG_AFC_HI 0x00FF0000 /* R/W */ 2753e0f331cSGuennadi Liakhovetski #define AFC_CFG_AFC_LO 0x0000FF00 /* R/W */ 2763e0f331cSGuennadi Liakhovetski #define AFC_CFG_BACK_DUR 0x000000F0 /* R/W */ 2773e0f331cSGuennadi Liakhovetski #define AFC_CFG_FCMULT 0x00000008 /* R/W */ 2783e0f331cSGuennadi Liakhovetski #define AFC_CFG_FCBRD 0x00000004 /* R/W */ 2793e0f331cSGuennadi Liakhovetski #define AFC_CFG_FCADD 0x00000002 /* R/W */ 2803e0f331cSGuennadi Liakhovetski #define AFC_CFG_FCANY 0x00000001 /* R/W */ 281de1b686bSSascha Hauer 2823e0f331cSGuennadi Liakhovetski #define E2P_CMD (CONFIG_DRIVER_SMC911X_BASE + 0xB0) 2833e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_BUSY 0x80000000 /* Self Clearing */ 2843e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD 0x70000000 /* R/W */ 2853e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_READ 0x00000000 /* R/W */ 2863e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_EWDS 0x10000000 /* R/W */ 2873e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_EWEN 0x20000000 /* R/W */ 2883e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_WRITE 0x30000000 /* R/W */ 2893e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_WRAL 0x40000000 /* R/W */ 2903e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_ERASE 0x50000000 /* R/W */ 2913e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_ERAL 0x60000000 /* R/W */ 2923e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_CMD_RELOAD 0x70000000 /* R/W */ 2933e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_TIMEOUT 0x00000200 /* RO */ 2943e0f331cSGuennadi Liakhovetski #define E2P_CMD_MAC_ADDR_LOADED 0x00000100 /* RO */ 2953e0f331cSGuennadi Liakhovetski #define E2P_CMD_EPC_ADDR 0x000000FF /* R/W */ 296de1b686bSSascha Hauer 2973e0f331cSGuennadi Liakhovetski #define E2P_DATA (CONFIG_DRIVER_SMC911X_BASE + 0xB4) 2983e0f331cSGuennadi Liakhovetski #define E2P_DATA_EEPROM_DATA 0x000000FF /* R/W */ 299de1b686bSSascha Hauer /* end of LAN register offsets and bit definitions */ 300de1b686bSSascha Hauer 301de1b686bSSascha Hauer /* MAC Control and Status registers */ 3023e0f331cSGuennadi Liakhovetski #define MAC_CR 0x01 /* R/W */ 303de1b686bSSascha Hauer 304de1b686bSSascha Hauer /* MAC_CR - MAC Control Register */ 3053e0f331cSGuennadi Liakhovetski #define MAC_CR_RXALL 0x80000000 306de1b686bSSascha Hauer /* TODO: delete this bit? It is not described in the data sheet. */ 3073e0f331cSGuennadi Liakhovetski #define MAC_CR_HBDIS 0x10000000 3083e0f331cSGuennadi Liakhovetski #define MAC_CR_RCVOWN 0x00800000 3093e0f331cSGuennadi Liakhovetski #define MAC_CR_LOOPBK 0x00200000 3103e0f331cSGuennadi Liakhovetski #define MAC_CR_FDPX 0x00100000 3113e0f331cSGuennadi Liakhovetski #define MAC_CR_MCPAS 0x00080000 3123e0f331cSGuennadi Liakhovetski #define MAC_CR_PRMS 0x00040000 3133e0f331cSGuennadi Liakhovetski #define MAC_CR_INVFILT 0x00020000 3143e0f331cSGuennadi Liakhovetski #define MAC_CR_PASSBAD 0x00010000 3153e0f331cSGuennadi Liakhovetski #define MAC_CR_HFILT 0x00008000 3163e0f331cSGuennadi Liakhovetski #define MAC_CR_HPFILT 0x00002000 3173e0f331cSGuennadi Liakhovetski #define MAC_CR_LCOLL 0x00001000 3183e0f331cSGuennadi Liakhovetski #define MAC_CR_BCAST 0x00000800 3193e0f331cSGuennadi Liakhovetski #define MAC_CR_DISRTY 0x00000400 3203e0f331cSGuennadi Liakhovetski #define MAC_CR_PADSTR 0x00000100 3213e0f331cSGuennadi Liakhovetski #define MAC_CR_BOLMT_MASK 0x000000C0 3223e0f331cSGuennadi Liakhovetski #define MAC_CR_DFCHK 0x00000020 3233e0f331cSGuennadi Liakhovetski #define MAC_CR_TXEN 0x00000008 3243e0f331cSGuennadi Liakhovetski #define MAC_CR_RXEN 0x00000004 325de1b686bSSascha Hauer 3263e0f331cSGuennadi Liakhovetski #define ADDRH 0x02 /* R/W mask 0x0000FFFFUL */ 3273e0f331cSGuennadi Liakhovetski #define ADDRL 0x03 /* R/W mask 0xFFFFFFFFUL */ 3283e0f331cSGuennadi Liakhovetski #define HASHH 0x04 /* R/W */ 3293e0f331cSGuennadi Liakhovetski #define HASHL 0x05 /* R/W */ 330de1b686bSSascha Hauer 3313e0f331cSGuennadi Liakhovetski #define MII_ACC 0x06 /* R/W */ 3323e0f331cSGuennadi Liakhovetski #define MII_ACC_PHY_ADDR 0x0000F800 3333e0f331cSGuennadi Liakhovetski #define MII_ACC_MIIRINDA 0x000007C0 3343e0f331cSGuennadi Liakhovetski #define MII_ACC_MII_WRITE 0x00000002 3353e0f331cSGuennadi Liakhovetski #define MII_ACC_MII_BUSY 0x00000001 336de1b686bSSascha Hauer 3373e0f331cSGuennadi Liakhovetski #define MII_DATA 0x07 /* R/W mask 0x0000FFFFUL */ 338de1b686bSSascha Hauer 3393e0f331cSGuennadi Liakhovetski #define FLOW 0x08 /* R/W */ 3403e0f331cSGuennadi Liakhovetski #define FLOW_FCPT 0xFFFF0000 3413e0f331cSGuennadi Liakhovetski #define FLOW_FCPASS 0x00000004 3423e0f331cSGuennadi Liakhovetski #define FLOW_FCEN 0x00000002 3433e0f331cSGuennadi Liakhovetski #define FLOW_FCBSY 0x00000001 344de1b686bSSascha Hauer 3453e0f331cSGuennadi Liakhovetski #define VLAN1 0x09 /* R/W mask 0x0000FFFFUL */ 3463e0f331cSGuennadi Liakhovetski #define VLAN1_VTI1 0x0000ffff 347de1b686bSSascha Hauer 3483e0f331cSGuennadi Liakhovetski #define VLAN2 0x0A /* R/W mask 0x0000FFFFUL */ 3493e0f331cSGuennadi Liakhovetski #define VLAN2_VTI2 0x0000ffff 350de1b686bSSascha Hauer 3513e0f331cSGuennadi Liakhovetski #define WUFF 0x0B /* WO */ 352de1b686bSSascha Hauer 3533e0f331cSGuennadi Liakhovetski #define WUCSR 0x0C /* R/W */ 3543e0f331cSGuennadi Liakhovetski #define WUCSR_GUE 0x00000200 3553e0f331cSGuennadi Liakhovetski #define WUCSR_WUFR 0x00000040 3563e0f331cSGuennadi Liakhovetski #define WUCSR_MPR 0x00000020 3573e0f331cSGuennadi Liakhovetski #define WUCSR_WAKE_EN 0x00000004 3583e0f331cSGuennadi Liakhovetski #define WUCSR_MPEN 0x00000002 359de1b686bSSascha Hauer 360de1b686bSSascha Hauer /* Chip ID values */ 361de1b686bSSascha Hauer #define CHIP_9115 0x115 362de1b686bSSascha Hauer #define CHIP_9116 0x116 363de1b686bSSascha Hauer #define CHIP_9117 0x117 364de1b686bSSascha Hauer #define CHIP_9118 0x118 365de1b686bSSascha Hauer #define CHIP_9215 0x115a 366de1b686bSSascha Hauer #define CHIP_9216 0x116a 367de1b686bSSascha Hauer #define CHIP_9217 0x117a 368de1b686bSSascha Hauer #define CHIP_9218 0x118a 369de1b686bSSascha Hauer 370de1b686bSSascha Hauer struct chip_id { 371de1b686bSSascha Hauer u16 id; 372de1b686bSSascha Hauer char *name; 373de1b686bSSascha Hauer }; 374de1b686bSSascha Hauer 375de1b686bSSascha Hauer static const struct chip_id chip_ids[] = { 376de1b686bSSascha Hauer { CHIP_9115, "LAN9115" }, 377de1b686bSSascha Hauer { CHIP_9116, "LAN9116" }, 378de1b686bSSascha Hauer { CHIP_9117, "LAN9117" }, 379de1b686bSSascha Hauer { CHIP_9118, "LAN9118" }, 380de1b686bSSascha Hauer { CHIP_9215, "LAN9215" }, 381de1b686bSSascha Hauer { CHIP_9216, "LAN9216" }, 382de1b686bSSascha Hauer { CHIP_9217, "LAN9217" }, 383de1b686bSSascha Hauer { CHIP_9218, "LAN9218" }, 384de1b686bSSascha Hauer { 0, NULL }, 385de1b686bSSascha Hauer }; 386de1b686bSSascha Hauer 387de1b686bSSascha Hauer #define DRIVERNAME "smc911x" 388de1b686bSSascha Hauer 389de1b686bSSascha Hauer u32 smc911x_get_mac_csr(u8 reg) 390de1b686bSSascha Hauer { 3913e0f331cSGuennadi Liakhovetski while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) 3923e0f331cSGuennadi Liakhovetski ; 3933e0f331cSGuennadi Liakhovetski reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | MAC_CSR_CMD_R_NOT_W | reg); 3943e0f331cSGuennadi Liakhovetski while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) 3953e0f331cSGuennadi Liakhovetski ; 396de1b686bSSascha Hauer 3973e0f331cSGuennadi Liakhovetski return reg_read(MAC_CSR_DATA); 398de1b686bSSascha Hauer } 399de1b686bSSascha Hauer 400de1b686bSSascha Hauer void smc911x_set_mac_csr(u8 reg, u32 data) 401de1b686bSSascha Hauer { 4023e0f331cSGuennadi Liakhovetski while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) 4033e0f331cSGuennadi Liakhovetski ; 4043e0f331cSGuennadi Liakhovetski reg_write(MAC_CSR_DATA, data); 4053e0f331cSGuennadi Liakhovetski reg_write(MAC_CSR_CMD, MAC_CSR_CMD_CSR_BUSY | reg); 4063e0f331cSGuennadi Liakhovetski while (reg_read(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY) 4073e0f331cSGuennadi Liakhovetski ; 408de1b686bSSascha Hauer } 409de1b686bSSascha Hauer 410de1b686bSSascha Hauer static int smx911x_handle_mac_address(bd_t *bd) 411de1b686bSSascha Hauer { 412de1b686bSSascha Hauer unsigned long addrh, addrl; 413de1b686bSSascha Hauer unsigned char *m = bd->bi_enetaddr; 414de1b686bSSascha Hauer 415de1b686bSSascha Hauer /* if the environment has a valid mac address then use it */ 416de1b686bSSascha Hauer if ((m[0] | m[1] | m[2] | m[3] | m[4] | m[5])) { 417de1b686bSSascha Hauer addrl = m[0] | m[1] << 8 | m[2] << 16 | m[3] << 24; 418de1b686bSSascha Hauer addrh = m[4] | m[5] << 8; 419de1b686bSSascha Hauer smc911x_set_mac_csr(ADDRH, addrh); 420de1b686bSSascha Hauer smc911x_set_mac_csr(ADDRL, addrl); 421de1b686bSSascha Hauer } else { 422de1b686bSSascha Hauer /* if not, try to get one from the eeprom */ 423de1b686bSSascha Hauer addrh = smc911x_get_mac_csr(ADDRH); 424de1b686bSSascha Hauer addrl = smc911x_get_mac_csr(ADDRL); 425de1b686bSSascha Hauer 426de1b686bSSascha Hauer m[0] = (addrl ) & 0xff; 427de1b686bSSascha Hauer m[1] = (addrl >> 8 ) & 0xff; 428de1b686bSSascha Hauer m[2] = (addrl >> 16 ) & 0xff; 429de1b686bSSascha Hauer m[3] = (addrl >> 24 ) & 0xff; 430de1b686bSSascha Hauer m[4] = (addrh ) & 0xff; 431de1b686bSSascha Hauer m[5] = (addrh >> 8 ) & 0xff; 432de1b686bSSascha Hauer 433de1b686bSSascha Hauer /* we get 0xff when there is no eeprom connected */ 434de1b686bSSascha Hauer if ((m[0] & m[1] & m[2] & m[3] & m[4] & m[5]) == 0xff) { 435de1b686bSSascha Hauer printf(DRIVERNAME ": no valid mac address in environment " 436de1b686bSSascha Hauer "and no eeprom found\n"); 437de1b686bSSascha Hauer return -1; 438de1b686bSSascha Hauer } 439de1b686bSSascha Hauer } 440de1b686bSSascha Hauer 441de1b686bSSascha Hauer printf(DRIVERNAME ": MAC %02x:%02x:%02x:%02x:%02x:%02x\n", 442de1b686bSSascha Hauer m[0], m[1], m[2], m[3], m[4], m[5]); 443de1b686bSSascha Hauer 444de1b686bSSascha Hauer return 0; 445de1b686bSSascha Hauer } 446de1b686bSSascha Hauer 447de1b686bSSascha Hauer static int smc911x_miiphy_read(u8 phy, u8 reg, u16 *val) 448de1b686bSSascha Hauer { 4493e0f331cSGuennadi Liakhovetski while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) 4503e0f331cSGuennadi Liakhovetski ; 451de1b686bSSascha Hauer 452de1b686bSSascha Hauer smc911x_set_mac_csr(MII_ACC, phy << 11 | reg << 6 | MII_ACC_MII_BUSY); 453de1b686bSSascha Hauer 4543e0f331cSGuennadi Liakhovetski while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) 4553e0f331cSGuennadi Liakhovetski ; 456de1b686bSSascha Hauer 457de1b686bSSascha Hauer *val = smc911x_get_mac_csr(MII_DATA); 458de1b686bSSascha Hauer 459de1b686bSSascha Hauer return 0; 460de1b686bSSascha Hauer } 461de1b686bSSascha Hauer 462de1b686bSSascha Hauer static int smc911x_miiphy_write(u8 phy, u8 reg, u16 val) 463de1b686bSSascha Hauer { 4643e0f331cSGuennadi Liakhovetski while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) 4653e0f331cSGuennadi Liakhovetski ; 466de1b686bSSascha Hauer 467de1b686bSSascha Hauer smc911x_set_mac_csr(MII_DATA, val); 468de1b686bSSascha Hauer smc911x_set_mac_csr(MII_ACC, 469de1b686bSSascha Hauer phy << 11 | reg << 6 | MII_ACC_MII_BUSY | MII_ACC_MII_WRITE); 470de1b686bSSascha Hauer 4713e0f331cSGuennadi Liakhovetski while (smc911x_get_mac_csr(MII_ACC) & MII_ACC_MII_BUSY) 4723e0f331cSGuennadi Liakhovetski ; 473de1b686bSSascha Hauer return 0; 474de1b686bSSascha Hauer } 475de1b686bSSascha Hauer 476de1b686bSSascha Hauer static int smc911x_phy_reset(void) 477de1b686bSSascha Hauer { 478de1b686bSSascha Hauer u32 reg; 479de1b686bSSascha Hauer 4803e0f331cSGuennadi Liakhovetski reg = reg_read(PMT_CTRL); 481de1b686bSSascha Hauer reg &= ~0xfffff030; 482de1b686bSSascha Hauer reg |= PMT_CTRL_PHY_RST; 4833e0f331cSGuennadi Liakhovetski reg_write(PMT_CTRL, reg); 484de1b686bSSascha Hauer 485de1b686bSSascha Hauer mdelay(100); 486de1b686bSSascha Hauer 487de1b686bSSascha Hauer return 0; 488de1b686bSSascha Hauer } 489de1b686bSSascha Hauer 490de1b686bSSascha Hauer static void smc911x_phy_configure(void) 491de1b686bSSascha Hauer { 492de1b686bSSascha Hauer int timeout; 493de1b686bSSascha Hauer u16 status; 494de1b686bSSascha Hauer 495de1b686bSSascha Hauer smc911x_phy_reset(); 496de1b686bSSascha Hauer 497de1b686bSSascha Hauer smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_RESET); 498de1b686bSSascha Hauer mdelay(1); 499de1b686bSSascha Hauer smc911x_miiphy_write(1, PHY_ANAR, 0x01e1); 500de1b686bSSascha Hauer smc911x_miiphy_write(1, PHY_BMCR, PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); 501de1b686bSSascha Hauer 502de1b686bSSascha Hauer timeout = 5000; 503de1b686bSSascha Hauer do { 504de1b686bSSascha Hauer mdelay(1); 505de1b686bSSascha Hauer if ((timeout--) == 0) 506de1b686bSSascha Hauer goto err_out; 507de1b686bSSascha Hauer 508de1b686bSSascha Hauer if (smc911x_miiphy_read(1, PHY_BMSR, &status) != 0) 509de1b686bSSascha Hauer goto err_out; 510de1b686bSSascha Hauer } while (!(status & PHY_BMSR_LS)); 511de1b686bSSascha Hauer 512de1b686bSSascha Hauer printf(DRIVERNAME ": phy initialized\n"); 513de1b686bSSascha Hauer 514de1b686bSSascha Hauer return; 515de1b686bSSascha Hauer 516de1b686bSSascha Hauer err_out: 517de1b686bSSascha Hauer printf(DRIVERNAME ": autonegotiation timed out\n"); 518de1b686bSSascha Hauer } 519de1b686bSSascha Hauer 520de1b686bSSascha Hauer static void smc911x_reset(void) 521de1b686bSSascha Hauer { 522de1b686bSSascha Hauer int timeout; 523de1b686bSSascha Hauer 524de1b686bSSascha Hauer /* Take out of PM setting first */ 5253e0f331cSGuennadi Liakhovetski if (reg_read(PMT_CTRL) & PMT_CTRL_READY) { 526de1b686bSSascha Hauer /* Write to the bytetest will take out of powerdown */ 5273e0f331cSGuennadi Liakhovetski reg_write(BYTE_TEST, 0x0); 528de1b686bSSascha Hauer 529de1b686bSSascha Hauer timeout = 10; 530de1b686bSSascha Hauer 5313e0f331cSGuennadi Liakhovetski while (timeout-- && !(reg_read(PMT_CTRL) & PMT_CTRL_READY)) 532de1b686bSSascha Hauer udelay(10); 533de1b686bSSascha Hauer if (!timeout) { 534de1b686bSSascha Hauer printf(DRIVERNAME 535de1b686bSSascha Hauer ": timeout waiting for PM restore\n"); 536de1b686bSSascha Hauer return; 537de1b686bSSascha Hauer } 538de1b686bSSascha Hauer } 539de1b686bSSascha Hauer 540de1b686bSSascha Hauer /* Disable interrupts */ 5413e0f331cSGuennadi Liakhovetski reg_write(INT_EN, 0); 542de1b686bSSascha Hauer 5433e0f331cSGuennadi Liakhovetski reg_write(HW_CFG, HW_CFG_SRST); 544de1b686bSSascha Hauer 545de1b686bSSascha Hauer timeout = 1000; 5463e0f331cSGuennadi Liakhovetski while (timeout-- && reg_read(E2P_CMD) & E2P_CMD_EPC_BUSY) 547de1b686bSSascha Hauer udelay(10); 548de1b686bSSascha Hauer 549de1b686bSSascha Hauer if (!timeout) { 550de1b686bSSascha Hauer printf(DRIVERNAME ": reset timeout\n"); 551de1b686bSSascha Hauer return; 552de1b686bSSascha Hauer } 553de1b686bSSascha Hauer 554de1b686bSSascha Hauer /* Reset the FIFO level and flow control settings */ 555de1b686bSSascha Hauer smc911x_set_mac_csr(FLOW, FLOW_FCPT | FLOW_FCEN); 5563e0f331cSGuennadi Liakhovetski reg_write(AFC_CFG, 0x0050287F); 557de1b686bSSascha Hauer 558de1b686bSSascha Hauer /* Set to LED outputs */ 5593e0f331cSGuennadi Liakhovetski reg_write(GPIO_CFG, 0x70070000); 560de1b686bSSascha Hauer } 561de1b686bSSascha Hauer 562de1b686bSSascha Hauer static void smc911x_enable(void) 563de1b686bSSascha Hauer { 564de1b686bSSascha Hauer /* Enable TX */ 5653e0f331cSGuennadi Liakhovetski reg_write(HW_CFG, 8 << 16 | HW_CFG_SF); 566de1b686bSSascha Hauer 5673e0f331cSGuennadi Liakhovetski reg_write(GPT_CFG, GPT_CFG_TIMER_EN | 10000); 568de1b686bSSascha Hauer 5693e0f331cSGuennadi Liakhovetski reg_write(TX_CFG, TX_CFG_TX_ON); 570de1b686bSSascha Hauer 571de1b686bSSascha Hauer /* no padding to start of packets */ 5723e0f331cSGuennadi Liakhovetski reg_write(RX_CFG, 0); 573de1b686bSSascha Hauer 574de1b686bSSascha Hauer smc911x_set_mac_csr(MAC_CR, MAC_CR_TXEN | MAC_CR_RXEN | MAC_CR_HBDIS); 575de1b686bSSascha Hauer 576de1b686bSSascha Hauer } 577de1b686bSSascha Hauer 578de1b686bSSascha Hauer int eth_init(bd_t *bd) 579de1b686bSSascha Hauer { 580de1b686bSSascha Hauer unsigned long val, i; 581de1b686bSSascha Hauer 582de1b686bSSascha Hauer printf(DRIVERNAME ": initializing\n"); 583de1b686bSSascha Hauer 5843e0f331cSGuennadi Liakhovetski val = reg_read(BYTE_TEST); 585de1b686bSSascha Hauer if (val != 0x87654321) { 586de1b686bSSascha Hauer printf(DRIVERNAME ": Invalid chip endian 0x08%x\n", val); 587de1b686bSSascha Hauer goto err_out; 588de1b686bSSascha Hauer } 589de1b686bSSascha Hauer 5903e0f331cSGuennadi Liakhovetski val = reg_read(ID_REV) >> 16; 591de1b686bSSascha Hauer for (i = 0; chip_ids[i].id != 0; i++) { 592de1b686bSSascha Hauer if (chip_ids[i].id == val) break; 593de1b686bSSascha Hauer } 594de1b686bSSascha Hauer if (!chip_ids[i].id) { 595de1b686bSSascha Hauer printf(DRIVERNAME ": Unknown chip ID %04x\n", val); 596de1b686bSSascha Hauer goto err_out; 597de1b686bSSascha Hauer } 598de1b686bSSascha Hauer 599de1b686bSSascha Hauer printf(DRIVERNAME ": detected %s controller\n", chip_ids[i].name); 600de1b686bSSascha Hauer 601de1b686bSSascha Hauer smc911x_reset(); 602de1b686bSSascha Hauer 603de1b686bSSascha Hauer /* Configure the PHY, initialize the link state */ 604de1b686bSSascha Hauer smc911x_phy_configure(); 605de1b686bSSascha Hauer 606de1b686bSSascha Hauer if (smx911x_handle_mac_address(bd)) 607de1b686bSSascha Hauer goto err_out; 608de1b686bSSascha Hauer 609de1b686bSSascha Hauer /* Turn on Tx + Rx */ 610de1b686bSSascha Hauer smc911x_enable(); 611de1b686bSSascha Hauer 612de1b686bSSascha Hauer return 0; 613de1b686bSSascha Hauer 614de1b686bSSascha Hauer err_out: 615de1b686bSSascha Hauer return -1; 616de1b686bSSascha Hauer } 617de1b686bSSascha Hauer 618de1b686bSSascha Hauer int eth_send(volatile void *packet, int length) 619de1b686bSSascha Hauer { 620de1b686bSSascha Hauer u32 *data = (u32*)packet; 621de1b686bSSascha Hauer u32 tmplen; 622de1b686bSSascha Hauer u32 status; 623de1b686bSSascha Hauer 6243e0f331cSGuennadi Liakhovetski reg_write(TX_DATA_FIFO, TX_CMD_A_INT_FIRST_SEG | TX_CMD_A_INT_LAST_SEG | length); 6253e0f331cSGuennadi Liakhovetski reg_write(TX_DATA_FIFO, length); 626de1b686bSSascha Hauer 627de1b686bSSascha Hauer tmplen = (length + 3) / 4; 628de1b686bSSascha Hauer 629de1b686bSSascha Hauer while (tmplen--) 6303e0f331cSGuennadi Liakhovetski reg_write(TX_DATA_FIFO, *data++); 631de1b686bSSascha Hauer 632de1b686bSSascha Hauer /* wait for transmission */ 6333e0f331cSGuennadi Liakhovetski while (!((reg_read(TX_FIFO_INF) & TX_FIFO_INF_TSUSED) >> 16)); 634de1b686bSSascha Hauer 635de1b686bSSascha Hauer /* get status. Ignore 'no carrier' error, it has no meaning for 636de1b686bSSascha Hauer * full duplex operation 637de1b686bSSascha Hauer */ 6383e0f331cSGuennadi Liakhovetski status = reg_read(TX_STATUS_FIFO) & (TX_STS_LOC | TX_STS_LATE_COLL | 639de1b686bSSascha Hauer TX_STS_MANY_COLL | TX_STS_MANY_DEFER | TX_STS_UNDERRUN); 640de1b686bSSascha Hauer 641de1b686bSSascha Hauer if (!status) 642de1b686bSSascha Hauer return 0; 643de1b686bSSascha Hauer 644de1b686bSSascha Hauer printf(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n", 645de1b686bSSascha Hauer status & TX_STS_LOC ? "TX_STS_LOC " : "", 646de1b686bSSascha Hauer status & TX_STS_LATE_COLL ? "TX_STS_LATE_COLL " : "", 647de1b686bSSascha Hauer status & TX_STS_MANY_COLL ? "TX_STS_MANY_COLL " : "", 648de1b686bSSascha Hauer status & TX_STS_MANY_DEFER ? "TX_STS_MANY_DEFER " : "", 649de1b686bSSascha Hauer status & TX_STS_UNDERRUN ? "TX_STS_UNDERRUN" : ""); 650de1b686bSSascha Hauer 651de1b686bSSascha Hauer return -1; 652de1b686bSSascha Hauer } 653de1b686bSSascha Hauer 654de1b686bSSascha Hauer void eth_halt(void) 655de1b686bSSascha Hauer { 656de1b686bSSascha Hauer smc911x_reset(); 657de1b686bSSascha Hauer } 658de1b686bSSascha Hauer 659de1b686bSSascha Hauer int eth_rx(void) 660de1b686bSSascha Hauer { 661de1b686bSSascha Hauer u32 *data = (u32 *)NetRxPackets[0]; 662de1b686bSSascha Hauer u32 pktlen, tmplen; 663de1b686bSSascha Hauer u32 status; 664de1b686bSSascha Hauer 6653e0f331cSGuennadi Liakhovetski if ((reg_read(RX_FIFO_INF) & RX_FIFO_INF_RXSUSED) >> 16) { 6663e0f331cSGuennadi Liakhovetski status = reg_read(RX_STATUS_FIFO); 667de1b686bSSascha Hauer pktlen = (status & RX_STS_PKT_LEN) >> 16; 668de1b686bSSascha Hauer 6693e0f331cSGuennadi Liakhovetski reg_write(RX_CFG, 0); 670de1b686bSSascha Hauer 671de1b686bSSascha Hauer tmplen = (pktlen + 2+ 3) / 4; 672de1b686bSSascha Hauer while (tmplen--) 6733e0f331cSGuennadi Liakhovetski *data++ = reg_read(RX_DATA_FIFO); 674de1b686bSSascha Hauer 675de1b686bSSascha Hauer if (status & RX_STS_ES) 676de1b686bSSascha Hauer printf(DRIVERNAME 677de1b686bSSascha Hauer ": dropped bad packet. Status: 0x%08x\n", 678de1b686bSSascha Hauer status); 679de1b686bSSascha Hauer else 680de1b686bSSascha Hauer NetReceive(NetRxPackets[0], pktlen); 681de1b686bSSascha Hauer } 682de1b686bSSascha Hauer 683de1b686bSSascha Hauer return 0; 684de1b686bSSascha Hauer } 685de1b686bSSascha Hauer 686de1b686bSSascha Hauer #endif /* CONFIG_DRIVER_SMC911X */ 687