19b6bcdcbSAlbert Aribaud /* 29b6bcdcbSAlbert Aribaud * (C) Copyright 2009 39b6bcdcbSAlbert Aribaud * Marvell Semiconductor <www.marvell.com> 49b6bcdcbSAlbert Aribaud * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 59b6bcdcbSAlbert Aribaud * 69b6bcdcbSAlbert Aribaud * (C) Copyright 2003 79b6bcdcbSAlbert Aribaud * Ingo Assmus <ingo.assmus@keymile.com> 89b6bcdcbSAlbert Aribaud * 99b6bcdcbSAlbert Aribaud * based on - Driver for MV64360X ethernet ports 109b6bcdcbSAlbert Aribaud * Copyright (C) 2002 rabeeh@galileo.co.il 119b6bcdcbSAlbert Aribaud * 129b6bcdcbSAlbert Aribaud * See file CREDITS for list of people who contributed to this 139b6bcdcbSAlbert Aribaud * project. 149b6bcdcbSAlbert Aribaud * 159b6bcdcbSAlbert Aribaud * This program is free software; you can redistribute it and/or 169b6bcdcbSAlbert Aribaud * modify it under the terms of the GNU General Public License as 179b6bcdcbSAlbert Aribaud * published by the Free Software Foundation; either version 2 of 189b6bcdcbSAlbert Aribaud * the License, or (at your option) any later version. 199b6bcdcbSAlbert Aribaud * 209b6bcdcbSAlbert Aribaud * This program is distributed in the hope that it will be useful, 219b6bcdcbSAlbert Aribaud * but WITHOUT ANY WARRANTY; without even the implied warranty of 229b6bcdcbSAlbert Aribaud * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 239b6bcdcbSAlbert Aribaud * GNU General Public License for more details. 249b6bcdcbSAlbert Aribaud * 259b6bcdcbSAlbert Aribaud * You should have received a copy of the GNU General Public License 269b6bcdcbSAlbert Aribaud * along with this program; if not, write to the Free Software 279b6bcdcbSAlbert Aribaud * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 289b6bcdcbSAlbert Aribaud * MA 02110-1301 USA 299b6bcdcbSAlbert Aribaud */ 309b6bcdcbSAlbert Aribaud 319b6bcdcbSAlbert Aribaud #include <common.h> 329b6bcdcbSAlbert Aribaud #include <net.h> 339b6bcdcbSAlbert Aribaud #include <malloc.h> 349b6bcdcbSAlbert Aribaud #include <miiphy.h> 35a7efd719SLei Wen #include <asm/io.h> 369b6bcdcbSAlbert Aribaud #include <asm/errno.h> 379b6bcdcbSAlbert Aribaud #include <asm/types.h> 38a7efd719SLei Wen #include <asm/system.h> 399b6bcdcbSAlbert Aribaud #include <asm/byteorder.h> 4036aaa918SAnatolij Gustschin #include <asm/arch/cpu.h> 41d44265adSAlbert Aribaud 42d44265adSAlbert Aribaud #if defined(CONFIG_KIRKWOOD) 439b6bcdcbSAlbert Aribaud #include <asm/arch/kirkwood.h> 44d3c9ffd0SAlbert Aribaud #elif defined(CONFIG_ORION5X) 45d3c9ffd0SAlbert Aribaud #include <asm/arch/orion5x.h> 46d44265adSAlbert Aribaud #endif 47d44265adSAlbert Aribaud 489b6bcdcbSAlbert Aribaud #include "mvgbe.h" 499b6bcdcbSAlbert Aribaud 509b6bcdcbSAlbert Aribaud DECLARE_GLOBAL_DATA_PTR; 519b6bcdcbSAlbert Aribaud 52d44265adSAlbert Aribaud #define MV_PHY_ADR_REQUEST 0xee 53d44265adSAlbert Aribaud #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi) 549b6bcdcbSAlbert Aribaud 55*cd3ca3ffSSebastian Hesselbarth #if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 569b6bcdcbSAlbert Aribaud /* 579b6bcdcbSAlbert Aribaud * smi_reg_read - miiphy_read callback function. 589b6bcdcbSAlbert Aribaud * 599b6bcdcbSAlbert Aribaud * Returns 16bit phy register value, or 0xffff on error 609b6bcdcbSAlbert Aribaud */ 615700bb63SMike Frysinger static int smi_reg_read(const char *devname, u8 phy_adr, u8 reg_ofs, u16 * data) 629b6bcdcbSAlbert Aribaud { 639b6bcdcbSAlbert Aribaud struct eth_device *dev = eth_get_dev_by_name(devname); 64d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 65d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 669b6bcdcbSAlbert Aribaud u32 smi_reg; 679b6bcdcbSAlbert Aribaud u32 timeout; 689b6bcdcbSAlbert Aribaud 699b6bcdcbSAlbert Aribaud /* Phyadr read request */ 70d44265adSAlbert Aribaud if (phy_adr == MV_PHY_ADR_REQUEST && 71d44265adSAlbert Aribaud reg_ofs == MV_PHY_ADR_REQUEST) { 729b6bcdcbSAlbert Aribaud /* */ 73d44265adSAlbert Aribaud *data = (u16) (MVGBE_REG_RD(regs->phyadr) & PHYADR_MASK); 749b6bcdcbSAlbert Aribaud return 0; 759b6bcdcbSAlbert Aribaud } 769b6bcdcbSAlbert Aribaud /* check parameters */ 779b6bcdcbSAlbert Aribaud if (phy_adr > PHYADR_MASK) { 789b6bcdcbSAlbert Aribaud printf("Err..(%s) Invalid PHY address %d\n", 799b6bcdcbSAlbert Aribaud __FUNCTION__, phy_adr); 809b6bcdcbSAlbert Aribaud return -EFAULT; 819b6bcdcbSAlbert Aribaud } 829b6bcdcbSAlbert Aribaud if (reg_ofs > PHYREG_MASK) { 839b6bcdcbSAlbert Aribaud printf("Err..(%s) Invalid register offset %d\n", 849b6bcdcbSAlbert Aribaud __FUNCTION__, reg_ofs); 859b6bcdcbSAlbert Aribaud return -EFAULT; 869b6bcdcbSAlbert Aribaud } 879b6bcdcbSAlbert Aribaud 88d44265adSAlbert Aribaud timeout = MVGBE_PHY_SMI_TIMEOUT; 899b6bcdcbSAlbert Aribaud /* wait till the SMI is not busy */ 909b6bcdcbSAlbert Aribaud do { 919b6bcdcbSAlbert Aribaud /* read smi register */ 92d44265adSAlbert Aribaud smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG); 939b6bcdcbSAlbert Aribaud if (timeout-- == 0) { 949b6bcdcbSAlbert Aribaud printf("Err..(%s) SMI busy timeout\n", __FUNCTION__); 959b6bcdcbSAlbert Aribaud return -EFAULT; 969b6bcdcbSAlbert Aribaud } 97d44265adSAlbert Aribaud } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK); 989b6bcdcbSAlbert Aribaud 999b6bcdcbSAlbert Aribaud /* fill the phy address and regiser offset and read opcode */ 100d44265adSAlbert Aribaud smi_reg = (phy_adr << MVGBE_PHY_SMI_DEV_ADDR_OFFS) 101d44265adSAlbert Aribaud | (reg_ofs << MVGBE_SMI_REG_ADDR_OFFS) 102d44265adSAlbert Aribaud | MVGBE_PHY_SMI_OPCODE_READ; 1039b6bcdcbSAlbert Aribaud 1049b6bcdcbSAlbert Aribaud /* write the smi register */ 105d44265adSAlbert Aribaud MVGBE_REG_WR(MVGBE_SMI_REG, smi_reg); 1069b6bcdcbSAlbert Aribaud 1079b6bcdcbSAlbert Aribaud /*wait till read value is ready */ 108d44265adSAlbert Aribaud timeout = MVGBE_PHY_SMI_TIMEOUT; 1099b6bcdcbSAlbert Aribaud 1109b6bcdcbSAlbert Aribaud do { 1119b6bcdcbSAlbert Aribaud /* read smi register */ 112d44265adSAlbert Aribaud smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG); 1139b6bcdcbSAlbert Aribaud if (timeout-- == 0) { 1149b6bcdcbSAlbert Aribaud printf("Err..(%s) SMI read ready timeout\n", 1159b6bcdcbSAlbert Aribaud __FUNCTION__); 1169b6bcdcbSAlbert Aribaud return -EFAULT; 1179b6bcdcbSAlbert Aribaud } 118d44265adSAlbert Aribaud } while (!(smi_reg & MVGBE_PHY_SMI_READ_VALID_MASK)); 1199b6bcdcbSAlbert Aribaud 1209b6bcdcbSAlbert Aribaud /* Wait for the data to update in the SMI register */ 121d44265adSAlbert Aribaud for (timeout = 0; timeout < MVGBE_PHY_SMI_TIMEOUT; timeout++) 122d44265adSAlbert Aribaud ; 1239b6bcdcbSAlbert Aribaud 124d44265adSAlbert Aribaud *data = (u16) (MVGBE_REG_RD(MVGBE_SMI_REG) & MVGBE_PHY_SMI_DATA_MASK); 1259b6bcdcbSAlbert Aribaud 1269b6bcdcbSAlbert Aribaud debug("%s:(adr %d, off %d) value= %04x\n", __FUNCTION__, phy_adr, 1279b6bcdcbSAlbert Aribaud reg_ofs, *data); 1289b6bcdcbSAlbert Aribaud 1299b6bcdcbSAlbert Aribaud return 0; 1309b6bcdcbSAlbert Aribaud } 1319b6bcdcbSAlbert Aribaud 1329b6bcdcbSAlbert Aribaud /* 1339b6bcdcbSAlbert Aribaud * smi_reg_write - imiiphy_write callback function. 1349b6bcdcbSAlbert Aribaud * 1359b6bcdcbSAlbert Aribaud * Returns 0 if write succeed, -EINVAL on bad parameters 1369b6bcdcbSAlbert Aribaud * -ETIME on timeout 1379b6bcdcbSAlbert Aribaud */ 1385700bb63SMike Frysinger static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data) 1399b6bcdcbSAlbert Aribaud { 1409b6bcdcbSAlbert Aribaud struct eth_device *dev = eth_get_dev_by_name(devname); 141d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 142d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 1439b6bcdcbSAlbert Aribaud u32 smi_reg; 1449b6bcdcbSAlbert Aribaud u32 timeout; 1459b6bcdcbSAlbert Aribaud 1469b6bcdcbSAlbert Aribaud /* Phyadr write request*/ 147d44265adSAlbert Aribaud if (phy_adr == MV_PHY_ADR_REQUEST && 148d44265adSAlbert Aribaud reg_ofs == MV_PHY_ADR_REQUEST) { 149d44265adSAlbert Aribaud MVGBE_REG_WR(regs->phyadr, data); 1509b6bcdcbSAlbert Aribaud return 0; 1519b6bcdcbSAlbert Aribaud } 1529b6bcdcbSAlbert Aribaud 1539b6bcdcbSAlbert Aribaud /* check parameters */ 1549b6bcdcbSAlbert Aribaud if (phy_adr > PHYADR_MASK) { 1559b6bcdcbSAlbert Aribaud printf("Err..(%s) Invalid phy address\n", __FUNCTION__); 1569b6bcdcbSAlbert Aribaud return -EINVAL; 1579b6bcdcbSAlbert Aribaud } 1589b6bcdcbSAlbert Aribaud if (reg_ofs > PHYREG_MASK) { 1599b6bcdcbSAlbert Aribaud printf("Err..(%s) Invalid register offset\n", __FUNCTION__); 1609b6bcdcbSAlbert Aribaud return -EINVAL; 1619b6bcdcbSAlbert Aribaud } 1629b6bcdcbSAlbert Aribaud 1639b6bcdcbSAlbert Aribaud /* wait till the SMI is not busy */ 164d44265adSAlbert Aribaud timeout = MVGBE_PHY_SMI_TIMEOUT; 1659b6bcdcbSAlbert Aribaud do { 1669b6bcdcbSAlbert Aribaud /* read smi register */ 167d44265adSAlbert Aribaud smi_reg = MVGBE_REG_RD(MVGBE_SMI_REG); 1689b6bcdcbSAlbert Aribaud if (timeout-- == 0) { 1699b6bcdcbSAlbert Aribaud printf("Err..(%s) SMI busy timeout\n", __FUNCTION__); 1709b6bcdcbSAlbert Aribaud return -ETIME; 1719b6bcdcbSAlbert Aribaud } 172d44265adSAlbert Aribaud } while (smi_reg & MVGBE_PHY_SMI_BUSY_MASK); 1739b6bcdcbSAlbert Aribaud 1749b6bcdcbSAlbert Aribaud /* fill the phy addr and reg offset and write opcode and data */ 175d44265adSAlbert Aribaud smi_reg = (data << MVGBE_PHY_SMI_DATA_OFFS); 176d44265adSAlbert Aribaud smi_reg |= (phy_adr << MVGBE_PHY_SMI_DEV_ADDR_OFFS) 177d44265adSAlbert Aribaud | (reg_ofs << MVGBE_SMI_REG_ADDR_OFFS); 178d44265adSAlbert Aribaud smi_reg &= ~MVGBE_PHY_SMI_OPCODE_READ; 1799b6bcdcbSAlbert Aribaud 1809b6bcdcbSAlbert Aribaud /* write the smi register */ 181d44265adSAlbert Aribaud MVGBE_REG_WR(MVGBE_SMI_REG, smi_reg); 1829b6bcdcbSAlbert Aribaud 1839b6bcdcbSAlbert Aribaud return 0; 1849b6bcdcbSAlbert Aribaud } 185cc79697cSStefan Bigler #endif 1869b6bcdcbSAlbert Aribaud 187*cd3ca3ffSSebastian Hesselbarth #if defined(CONFIG_PHYLIB) 188*cd3ca3ffSSebastian Hesselbarth int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, 189*cd3ca3ffSSebastian Hesselbarth int reg_addr) 190*cd3ca3ffSSebastian Hesselbarth { 191*cd3ca3ffSSebastian Hesselbarth u16 data; 192*cd3ca3ffSSebastian Hesselbarth int ret; 193*cd3ca3ffSSebastian Hesselbarth ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data); 194*cd3ca3ffSSebastian Hesselbarth if (ret) 195*cd3ca3ffSSebastian Hesselbarth return ret; 196*cd3ca3ffSSebastian Hesselbarth return data; 197*cd3ca3ffSSebastian Hesselbarth } 198*cd3ca3ffSSebastian Hesselbarth 199*cd3ca3ffSSebastian Hesselbarth int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr, 200*cd3ca3ffSSebastian Hesselbarth int reg_addr, u16 data) 201*cd3ca3ffSSebastian Hesselbarth { 202*cd3ca3ffSSebastian Hesselbarth return smi_reg_write(bus->name, phy_addr, reg_addr, data); 203*cd3ca3ffSSebastian Hesselbarth } 204*cd3ca3ffSSebastian Hesselbarth #endif 205*cd3ca3ffSSebastian Hesselbarth 2069b6bcdcbSAlbert Aribaud /* Stop and checks all queues */ 2079b6bcdcbSAlbert Aribaud static void stop_queue(u32 * qreg) 2089b6bcdcbSAlbert Aribaud { 2099b6bcdcbSAlbert Aribaud u32 reg_data; 2109b6bcdcbSAlbert Aribaud 2119b6bcdcbSAlbert Aribaud reg_data = readl(qreg); 2129b6bcdcbSAlbert Aribaud 2139b6bcdcbSAlbert Aribaud if (reg_data & 0xFF) { 2149b6bcdcbSAlbert Aribaud /* Issue stop command for active channels only */ 2159b6bcdcbSAlbert Aribaud writel((reg_data << 8), qreg); 2169b6bcdcbSAlbert Aribaud 2179b6bcdcbSAlbert Aribaud /* Wait for all queue activity to terminate. */ 2189b6bcdcbSAlbert Aribaud do { 2199b6bcdcbSAlbert Aribaud /* 2209b6bcdcbSAlbert Aribaud * Check port cause register that all queues 2219b6bcdcbSAlbert Aribaud * are stopped 2229b6bcdcbSAlbert Aribaud */ 2239b6bcdcbSAlbert Aribaud reg_data = readl(qreg); 2249b6bcdcbSAlbert Aribaud } 2259b6bcdcbSAlbert Aribaud while (reg_data & 0xFF); 2269b6bcdcbSAlbert Aribaud } 2279b6bcdcbSAlbert Aribaud } 2289b6bcdcbSAlbert Aribaud 2299b6bcdcbSAlbert Aribaud /* 2309b6bcdcbSAlbert Aribaud * set_access_control - Config address decode parameters for Ethernet unit 2319b6bcdcbSAlbert Aribaud * 2329b6bcdcbSAlbert Aribaud * This function configures the address decode parameters for the Gigabit 2339b6bcdcbSAlbert Aribaud * Ethernet Controller according the given parameters struct. 2349b6bcdcbSAlbert Aribaud * 2359b6bcdcbSAlbert Aribaud * @regs Register struct pointer. 2369b6bcdcbSAlbert Aribaud * @param Address decode parameter struct. 2379b6bcdcbSAlbert Aribaud */ 238d44265adSAlbert Aribaud static void set_access_control(struct mvgbe_registers *regs, 239d44265adSAlbert Aribaud struct mvgbe_winparam *param) 2409b6bcdcbSAlbert Aribaud { 2419b6bcdcbSAlbert Aribaud u32 access_prot_reg; 2429b6bcdcbSAlbert Aribaud 2439b6bcdcbSAlbert Aribaud /* Set access control register */ 244d44265adSAlbert Aribaud access_prot_reg = MVGBE_REG_RD(regs->epap); 2459b6bcdcbSAlbert Aribaud /* clear window permission */ 2469b6bcdcbSAlbert Aribaud access_prot_reg &= (~(3 << (param->win * 2))); 2479b6bcdcbSAlbert Aribaud access_prot_reg |= (param->access_ctrl << (param->win * 2)); 248d44265adSAlbert Aribaud MVGBE_REG_WR(regs->epap, access_prot_reg); 2499b6bcdcbSAlbert Aribaud 2509b6bcdcbSAlbert Aribaud /* Set window Size reg (SR) */ 251d44265adSAlbert Aribaud MVGBE_REG_WR(regs->barsz[param->win].size, 2529b6bcdcbSAlbert Aribaud (((param->size / 0x10000) - 1) << 16)); 2539b6bcdcbSAlbert Aribaud 2549b6bcdcbSAlbert Aribaud /* Set window Base address reg (BA) */ 255d44265adSAlbert Aribaud MVGBE_REG_WR(regs->barsz[param->win].bar, 2569b6bcdcbSAlbert Aribaud (param->target | param->attrib | param->base_addr)); 2579b6bcdcbSAlbert Aribaud /* High address remap reg (HARR) */ 2589b6bcdcbSAlbert Aribaud if (param->win < 4) 259d44265adSAlbert Aribaud MVGBE_REG_WR(regs->ha_remap[param->win], param->high_addr); 2609b6bcdcbSAlbert Aribaud 2619b6bcdcbSAlbert Aribaud /* Base address enable reg (BARER) */ 2629b6bcdcbSAlbert Aribaud if (param->enable == 1) 263d44265adSAlbert Aribaud MVGBE_REG_BITS_RESET(regs->bare, (1 << param->win)); 2649b6bcdcbSAlbert Aribaud else 265d44265adSAlbert Aribaud MVGBE_REG_BITS_SET(regs->bare, (1 << param->win)); 2669b6bcdcbSAlbert Aribaud } 2679b6bcdcbSAlbert Aribaud 268d44265adSAlbert Aribaud static void set_dram_access(struct mvgbe_registers *regs) 2699b6bcdcbSAlbert Aribaud { 270d44265adSAlbert Aribaud struct mvgbe_winparam win_param; 2719b6bcdcbSAlbert Aribaud int i; 2729b6bcdcbSAlbert Aribaud 2739b6bcdcbSAlbert Aribaud for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 2749b6bcdcbSAlbert Aribaud /* Set access parameters for DRAM bank i */ 2759b6bcdcbSAlbert Aribaud win_param.win = i; /* Use Ethernet window i */ 2769b6bcdcbSAlbert Aribaud /* Window target - DDR */ 277d44265adSAlbert Aribaud win_param.target = MVGBE_TARGET_DRAM; 2789b6bcdcbSAlbert Aribaud /* Enable full access */ 2799b6bcdcbSAlbert Aribaud win_param.access_ctrl = EWIN_ACCESS_FULL; 2809b6bcdcbSAlbert Aribaud win_param.high_addr = 0; 2819b6bcdcbSAlbert Aribaud /* Get bank base and size */ 2829b6bcdcbSAlbert Aribaud win_param.base_addr = gd->bd->bi_dram[i].start; 2839b6bcdcbSAlbert Aribaud win_param.size = gd->bd->bi_dram[i].size; 2849b6bcdcbSAlbert Aribaud if (win_param.size == 0) 2859b6bcdcbSAlbert Aribaud win_param.enable = 0; 2869b6bcdcbSAlbert Aribaud else 2879b6bcdcbSAlbert Aribaud win_param.enable = 1; /* Enable the access */ 2889b6bcdcbSAlbert Aribaud 2899b6bcdcbSAlbert Aribaud /* Enable DRAM bank */ 2909b6bcdcbSAlbert Aribaud switch (i) { 2919b6bcdcbSAlbert Aribaud case 0: 2929b6bcdcbSAlbert Aribaud win_param.attrib = EBAR_DRAM_CS0; 2939b6bcdcbSAlbert Aribaud break; 2949b6bcdcbSAlbert Aribaud case 1: 2959b6bcdcbSAlbert Aribaud win_param.attrib = EBAR_DRAM_CS1; 2969b6bcdcbSAlbert Aribaud break; 2979b6bcdcbSAlbert Aribaud case 2: 2989b6bcdcbSAlbert Aribaud win_param.attrib = EBAR_DRAM_CS2; 2999b6bcdcbSAlbert Aribaud break; 3009b6bcdcbSAlbert Aribaud case 3: 3019b6bcdcbSAlbert Aribaud win_param.attrib = EBAR_DRAM_CS3; 3029b6bcdcbSAlbert Aribaud break; 3039b6bcdcbSAlbert Aribaud default: 3049b6bcdcbSAlbert Aribaud /* invalid bank, disable access */ 3059b6bcdcbSAlbert Aribaud win_param.enable = 0; 3069b6bcdcbSAlbert Aribaud win_param.attrib = 0; 3079b6bcdcbSAlbert Aribaud break; 3089b6bcdcbSAlbert Aribaud } 3099b6bcdcbSAlbert Aribaud /* Set the access control for address window(EPAPR) RD/WR */ 3109b6bcdcbSAlbert Aribaud set_access_control(regs, &win_param); 3119b6bcdcbSAlbert Aribaud } 3129b6bcdcbSAlbert Aribaud } 3139b6bcdcbSAlbert Aribaud 3149b6bcdcbSAlbert Aribaud /* 3159b6bcdcbSAlbert Aribaud * port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables 3169b6bcdcbSAlbert Aribaud * 3179b6bcdcbSAlbert Aribaud * Go through all the DA filter tables (Unicast, Special Multicast & Other 3189b6bcdcbSAlbert Aribaud * Multicast) and set each entry to 0. 3199b6bcdcbSAlbert Aribaud */ 320d44265adSAlbert Aribaud static void port_init_mac_tables(struct mvgbe_registers *regs) 3219b6bcdcbSAlbert Aribaud { 3229b6bcdcbSAlbert Aribaud int table_index; 3239b6bcdcbSAlbert Aribaud 3249b6bcdcbSAlbert Aribaud /* Clear DA filter unicast table (Ex_dFUT) */ 3259b6bcdcbSAlbert Aribaud for (table_index = 0; table_index < 4; ++table_index) 326d44265adSAlbert Aribaud MVGBE_REG_WR(regs->dfut[table_index], 0); 3279b6bcdcbSAlbert Aribaud 3289b6bcdcbSAlbert Aribaud for (table_index = 0; table_index < 64; ++table_index) { 3299b6bcdcbSAlbert Aribaud /* Clear DA filter special multicast table (Ex_dFSMT) */ 330d44265adSAlbert Aribaud MVGBE_REG_WR(regs->dfsmt[table_index], 0); 3319b6bcdcbSAlbert Aribaud /* Clear DA filter other multicast table (Ex_dFOMT) */ 332d44265adSAlbert Aribaud MVGBE_REG_WR(regs->dfomt[table_index], 0); 3339b6bcdcbSAlbert Aribaud } 3349b6bcdcbSAlbert Aribaud } 3359b6bcdcbSAlbert Aribaud 3369b6bcdcbSAlbert Aribaud /* 3379b6bcdcbSAlbert Aribaud * port_uc_addr - This function Set the port unicast address table 3389b6bcdcbSAlbert Aribaud * 3399b6bcdcbSAlbert Aribaud * This function locates the proper entry in the Unicast table for the 3409b6bcdcbSAlbert Aribaud * specified MAC nibble and sets its properties according to function 3419b6bcdcbSAlbert Aribaud * parameters. 3429b6bcdcbSAlbert Aribaud * This function add/removes MAC addresses from the port unicast address 3439b6bcdcbSAlbert Aribaud * table. 3449b6bcdcbSAlbert Aribaud * 3459b6bcdcbSAlbert Aribaud * @uc_nibble Unicast MAC Address last nibble. 3469b6bcdcbSAlbert Aribaud * @option 0 = Add, 1 = remove address. 3479b6bcdcbSAlbert Aribaud * 3489b6bcdcbSAlbert Aribaud * RETURN: 1 if output succeeded. 0 if option parameter is invalid. 3499b6bcdcbSAlbert Aribaud */ 350d44265adSAlbert Aribaud static int port_uc_addr(struct mvgbe_registers *regs, u8 uc_nibble, 3519b6bcdcbSAlbert Aribaud int option) 3529b6bcdcbSAlbert Aribaud { 3539b6bcdcbSAlbert Aribaud u32 unicast_reg; 3549b6bcdcbSAlbert Aribaud u32 tbl_offset; 3559b6bcdcbSAlbert Aribaud u32 reg_offset; 3569b6bcdcbSAlbert Aribaud 3579b6bcdcbSAlbert Aribaud /* Locate the Unicast table entry */ 3589b6bcdcbSAlbert Aribaud uc_nibble = (0xf & uc_nibble); 3599b6bcdcbSAlbert Aribaud /* Register offset from unicast table base */ 3609b6bcdcbSAlbert Aribaud tbl_offset = (uc_nibble / 4); 3619b6bcdcbSAlbert Aribaud /* Entry offset within the above register */ 3629b6bcdcbSAlbert Aribaud reg_offset = uc_nibble % 4; 3639b6bcdcbSAlbert Aribaud 3649b6bcdcbSAlbert Aribaud switch (option) { 3659b6bcdcbSAlbert Aribaud case REJECT_MAC_ADDR: 3669b6bcdcbSAlbert Aribaud /* 3679b6bcdcbSAlbert Aribaud * Clear accepts frame bit at specified unicast 3689b6bcdcbSAlbert Aribaud * DA table entry 3699b6bcdcbSAlbert Aribaud */ 370d44265adSAlbert Aribaud unicast_reg = MVGBE_REG_RD(regs->dfut[tbl_offset]); 3719b6bcdcbSAlbert Aribaud unicast_reg &= (0xFF << (8 * reg_offset)); 372d44265adSAlbert Aribaud MVGBE_REG_WR(regs->dfut[tbl_offset], unicast_reg); 3739b6bcdcbSAlbert Aribaud break; 3749b6bcdcbSAlbert Aribaud case ACCEPT_MAC_ADDR: 3759b6bcdcbSAlbert Aribaud /* Set accepts frame bit at unicast DA filter table entry */ 376d44265adSAlbert Aribaud unicast_reg = MVGBE_REG_RD(regs->dfut[tbl_offset]); 3779b6bcdcbSAlbert Aribaud unicast_reg &= (0xFF << (8 * reg_offset)); 3789b6bcdcbSAlbert Aribaud unicast_reg |= ((0x01 | (RXUQ << 1)) << (8 * reg_offset)); 379d44265adSAlbert Aribaud MVGBE_REG_WR(regs->dfut[tbl_offset], unicast_reg); 3809b6bcdcbSAlbert Aribaud break; 3819b6bcdcbSAlbert Aribaud default: 3829b6bcdcbSAlbert Aribaud return 0; 3839b6bcdcbSAlbert Aribaud } 3849b6bcdcbSAlbert Aribaud return 1; 3859b6bcdcbSAlbert Aribaud } 3869b6bcdcbSAlbert Aribaud 3879b6bcdcbSAlbert Aribaud /* 3889b6bcdcbSAlbert Aribaud * port_uc_addr_set - This function Set the port Unicast address. 3899b6bcdcbSAlbert Aribaud */ 390d44265adSAlbert Aribaud static void port_uc_addr_set(struct mvgbe_registers *regs, u8 * p_addr) 3919b6bcdcbSAlbert Aribaud { 3929b6bcdcbSAlbert Aribaud u32 mac_h; 3939b6bcdcbSAlbert Aribaud u32 mac_l; 3949b6bcdcbSAlbert Aribaud 3959b6bcdcbSAlbert Aribaud mac_l = (p_addr[4] << 8) | (p_addr[5]); 3969b6bcdcbSAlbert Aribaud mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | 3979b6bcdcbSAlbert Aribaud (p_addr[3] << 0); 3989b6bcdcbSAlbert Aribaud 399d44265adSAlbert Aribaud MVGBE_REG_WR(regs->macal, mac_l); 400d44265adSAlbert Aribaud MVGBE_REG_WR(regs->macah, mac_h); 4019b6bcdcbSAlbert Aribaud 4029b6bcdcbSAlbert Aribaud /* Accept frames of this address */ 4039b6bcdcbSAlbert Aribaud port_uc_addr(regs, p_addr[5], ACCEPT_MAC_ADDR); 4049b6bcdcbSAlbert Aribaud } 4059b6bcdcbSAlbert Aribaud 4069b6bcdcbSAlbert Aribaud /* 407d44265adSAlbert Aribaud * mvgbe_init_rx_desc_ring - Curve a Rx chain desc list and buffer in memory. 4089b6bcdcbSAlbert Aribaud */ 409d44265adSAlbert Aribaud static void mvgbe_init_rx_desc_ring(struct mvgbe_device *dmvgbe) 4109b6bcdcbSAlbert Aribaud { 411d44265adSAlbert Aribaud struct mvgbe_rxdesc *p_rx_desc; 4129b6bcdcbSAlbert Aribaud int i; 4139b6bcdcbSAlbert Aribaud 4149b6bcdcbSAlbert Aribaud /* initialize the Rx descriptors ring */ 415d44265adSAlbert Aribaud p_rx_desc = dmvgbe->p_rxdesc; 4169b6bcdcbSAlbert Aribaud for (i = 0; i < RINGSZ; i++) { 4179b6bcdcbSAlbert Aribaud p_rx_desc->cmd_sts = 418d44265adSAlbert Aribaud MVGBE_BUFFER_OWNED_BY_DMA | MVGBE_RX_EN_INTERRUPT; 4199b6bcdcbSAlbert Aribaud p_rx_desc->buf_size = PKTSIZE_ALIGN; 4209b6bcdcbSAlbert Aribaud p_rx_desc->byte_cnt = 0; 421d44265adSAlbert Aribaud p_rx_desc->buf_ptr = dmvgbe->p_rxbuf + i * PKTSIZE_ALIGN; 4229b6bcdcbSAlbert Aribaud if (i == (RINGSZ - 1)) 423d44265adSAlbert Aribaud p_rx_desc->nxtdesc_p = dmvgbe->p_rxdesc; 4249b6bcdcbSAlbert Aribaud else { 425d44265adSAlbert Aribaud p_rx_desc->nxtdesc_p = (struct mvgbe_rxdesc *) 426d44265adSAlbert Aribaud ((u32) p_rx_desc + MV_RXQ_DESC_ALIGNED_SIZE); 4279b6bcdcbSAlbert Aribaud p_rx_desc = p_rx_desc->nxtdesc_p; 4289b6bcdcbSAlbert Aribaud } 4299b6bcdcbSAlbert Aribaud } 430d44265adSAlbert Aribaud dmvgbe->p_rxdesc_curr = dmvgbe->p_rxdesc; 4319b6bcdcbSAlbert Aribaud } 4329b6bcdcbSAlbert Aribaud 433d44265adSAlbert Aribaud static int mvgbe_init(struct eth_device *dev) 4349b6bcdcbSAlbert Aribaud { 435d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 436d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 4379b6bcdcbSAlbert Aribaud #if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \ 4389b6bcdcbSAlbert Aribaud && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN) 4399b6bcdcbSAlbert Aribaud int i; 4409b6bcdcbSAlbert Aribaud #endif 4419b6bcdcbSAlbert Aribaud /* setup RX rings */ 442d44265adSAlbert Aribaud mvgbe_init_rx_desc_ring(dmvgbe); 4439b6bcdcbSAlbert Aribaud 4449b6bcdcbSAlbert Aribaud /* Clear the ethernet port interrupts */ 445d44265adSAlbert Aribaud MVGBE_REG_WR(regs->ic, 0); 446d44265adSAlbert Aribaud MVGBE_REG_WR(regs->ice, 0); 4479b6bcdcbSAlbert Aribaud /* Unmask RX buffer and TX end interrupt */ 448d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pim, INT_CAUSE_UNMASK_ALL); 4499b6bcdcbSAlbert Aribaud /* Unmask phy and link status changes interrupts */ 450d44265adSAlbert Aribaud MVGBE_REG_WR(regs->peim, INT_CAUSE_UNMASK_ALL_EXT); 4519b6bcdcbSAlbert Aribaud 4529b6bcdcbSAlbert Aribaud set_dram_access(regs); 4539b6bcdcbSAlbert Aribaud port_init_mac_tables(regs); 454d44265adSAlbert Aribaud port_uc_addr_set(regs, dmvgbe->dev.enetaddr); 4559b6bcdcbSAlbert Aribaud 4569b6bcdcbSAlbert Aribaud /* Assign port configuration and command. */ 457d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pxc, PRT_CFG_VAL); 458d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pxcx, PORT_CFG_EXTEND_VALUE); 459d44265adSAlbert Aribaud MVGBE_REG_WR(regs->psc0, PORT_SERIAL_CONTROL_VALUE); 4609b6bcdcbSAlbert Aribaud 4619b6bcdcbSAlbert Aribaud /* Assign port SDMA configuration */ 462d44265adSAlbert Aribaud MVGBE_REG_WR(regs->sdc, PORT_SDMA_CFG_VALUE); 463d44265adSAlbert Aribaud MVGBE_REG_WR(regs->tqx[0].qxttbc, QTKNBKT_DEF_VAL); 464d44265adSAlbert Aribaud MVGBE_REG_WR(regs->tqx[0].tqxtbc, 465d44265adSAlbert Aribaud (QMTBS_DEF_VAL << 16) | QTKNRT_DEF_VAL); 4669b6bcdcbSAlbert Aribaud /* Turn off the port/RXUQ bandwidth limitation */ 467d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pmtu, 0); 4689b6bcdcbSAlbert Aribaud 4699b6bcdcbSAlbert Aribaud /* Set maximum receive buffer to 9700 bytes */ 470d44265adSAlbert Aribaud MVGBE_REG_WR(regs->psc0, MVGBE_MAX_RX_PACKET_9700BYTE 471d44265adSAlbert Aribaud | (MVGBE_REG_RD(regs->psc0) & MRU_MASK)); 4729b6bcdcbSAlbert Aribaud 4739b6bcdcbSAlbert Aribaud /* Enable port initially */ 474d44265adSAlbert Aribaud MVGBE_REG_BITS_SET(regs->psc0, MVGBE_SERIAL_PORT_EN); 4759b6bcdcbSAlbert Aribaud 4769b6bcdcbSAlbert Aribaud /* 4779b6bcdcbSAlbert Aribaud * Set ethernet MTU for leaky bucket mechanism to 0 - this will 4789b6bcdcbSAlbert Aribaud * disable the leaky bucket mechanism . 4799b6bcdcbSAlbert Aribaud */ 480d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pmtu, 0); 4819b6bcdcbSAlbert Aribaud 4829b6bcdcbSAlbert Aribaud /* Assignment of Rx CRDB of given RXUQ */ 483d44265adSAlbert Aribaud MVGBE_REG_WR(regs->rxcdp[RXUQ], (u32) dmvgbe->p_rxdesc_curr); 4849b6bcdcbSAlbert Aribaud /* ensure previous write is done before enabling Rx DMA */ 4859b6bcdcbSAlbert Aribaud isb(); 4869b6bcdcbSAlbert Aribaud /* Enable port Rx. */ 487d44265adSAlbert Aribaud MVGBE_REG_WR(regs->rqc, (1 << RXUQ)); 4889b6bcdcbSAlbert Aribaud 489*cd3ca3ffSSebastian Hesselbarth #if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \ 490*cd3ca3ffSSebastian Hesselbarth !defined(CONFIG_PHYLIB) && \ 491*cd3ca3ffSSebastian Hesselbarth defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) 4929b6bcdcbSAlbert Aribaud /* Wait up to 5s for the link status */ 4939b6bcdcbSAlbert Aribaud for (i = 0; i < 5; i++) { 4949b6bcdcbSAlbert Aribaud u16 phyadr; 4959b6bcdcbSAlbert Aribaud 496d44265adSAlbert Aribaud miiphy_read(dev->name, MV_PHY_ADR_REQUEST, 497d44265adSAlbert Aribaud MV_PHY_ADR_REQUEST, &phyadr); 4989b6bcdcbSAlbert Aribaud /* Return if we get link up */ 4999b6bcdcbSAlbert Aribaud if (miiphy_link(dev->name, phyadr)) 5009b6bcdcbSAlbert Aribaud return 0; 5019b6bcdcbSAlbert Aribaud udelay(1000000); 5029b6bcdcbSAlbert Aribaud } 5039b6bcdcbSAlbert Aribaud 5049b6bcdcbSAlbert Aribaud printf("No link on %s\n", dev->name); 5059b6bcdcbSAlbert Aribaud return -1; 5069b6bcdcbSAlbert Aribaud #endif 5079b6bcdcbSAlbert Aribaud return 0; 5089b6bcdcbSAlbert Aribaud } 5099b6bcdcbSAlbert Aribaud 510d44265adSAlbert Aribaud static int mvgbe_halt(struct eth_device *dev) 5119b6bcdcbSAlbert Aribaud { 512d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 513d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 5149b6bcdcbSAlbert Aribaud 5159b6bcdcbSAlbert Aribaud /* Disable all gigE address decoder */ 516d44265adSAlbert Aribaud MVGBE_REG_WR(regs->bare, 0x3f); 5179b6bcdcbSAlbert Aribaud 5189b6bcdcbSAlbert Aribaud stop_queue(®s->tqc); 5199b6bcdcbSAlbert Aribaud stop_queue(®s->rqc); 5209b6bcdcbSAlbert Aribaud 5219b6bcdcbSAlbert Aribaud /* Disable port */ 522d44265adSAlbert Aribaud MVGBE_REG_BITS_RESET(regs->psc0, MVGBE_SERIAL_PORT_EN); 5239b6bcdcbSAlbert Aribaud /* Set port is not reset */ 524d44265adSAlbert Aribaud MVGBE_REG_BITS_RESET(regs->psc1, 1 << 4); 5259b6bcdcbSAlbert Aribaud #ifdef CONFIG_SYS_MII_MODE 5269b6bcdcbSAlbert Aribaud /* Set MMI interface up */ 527d44265adSAlbert Aribaud MVGBE_REG_BITS_RESET(regs->psc1, 1 << 3); 5289b6bcdcbSAlbert Aribaud #endif 5299b6bcdcbSAlbert Aribaud /* Disable & mask ethernet port interrupts */ 530d44265adSAlbert Aribaud MVGBE_REG_WR(regs->ic, 0); 531d44265adSAlbert Aribaud MVGBE_REG_WR(regs->ice, 0); 532d44265adSAlbert Aribaud MVGBE_REG_WR(regs->pim, 0); 533d44265adSAlbert Aribaud MVGBE_REG_WR(regs->peim, 0); 5349b6bcdcbSAlbert Aribaud 5359b6bcdcbSAlbert Aribaud return 0; 5369b6bcdcbSAlbert Aribaud } 5379b6bcdcbSAlbert Aribaud 538d44265adSAlbert Aribaud static int mvgbe_write_hwaddr(struct eth_device *dev) 5399b6bcdcbSAlbert Aribaud { 540d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 541d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 5429b6bcdcbSAlbert Aribaud 5439b6bcdcbSAlbert Aribaud /* Programs net device MAC address after initialization */ 544d44265adSAlbert Aribaud port_uc_addr_set(regs, dmvgbe->dev.enetaddr); 5459b6bcdcbSAlbert Aribaud return 0; 5469b6bcdcbSAlbert Aribaud } 5479b6bcdcbSAlbert Aribaud 54810cbe3b6SJoe Hershberger static int mvgbe_send(struct eth_device *dev, void *dataptr, int datasize) 5499b6bcdcbSAlbert Aribaud { 550d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 551d44265adSAlbert Aribaud struct mvgbe_registers *regs = dmvgbe->regs; 552d44265adSAlbert Aribaud struct mvgbe_txdesc *p_txdesc = dmvgbe->p_txdesc; 5539b6bcdcbSAlbert Aribaud void *p = (void *)dataptr; 5549b6bcdcbSAlbert Aribaud u32 cmd_sts; 555e6e556c1SAnatolij Gustschin u32 txuq0_reg_addr; 5569b6bcdcbSAlbert Aribaud 5579b6bcdcbSAlbert Aribaud /* Copy buffer if it's misaligned */ 5589b6bcdcbSAlbert Aribaud if ((u32) dataptr & 0x07) { 5599b6bcdcbSAlbert Aribaud if (datasize > PKTSIZE_ALIGN) { 5609b6bcdcbSAlbert Aribaud printf("Non-aligned data too large (%d)\n", 5619b6bcdcbSAlbert Aribaud datasize); 5629b6bcdcbSAlbert Aribaud return -1; 5639b6bcdcbSAlbert Aribaud } 5649b6bcdcbSAlbert Aribaud 565d44265adSAlbert Aribaud memcpy(dmvgbe->p_aligned_txbuf, p, datasize); 566d44265adSAlbert Aribaud p = dmvgbe->p_aligned_txbuf; 5679b6bcdcbSAlbert Aribaud } 5689b6bcdcbSAlbert Aribaud 569d44265adSAlbert Aribaud p_txdesc->cmd_sts = MVGBE_ZERO_PADDING | MVGBE_GEN_CRC; 570d44265adSAlbert Aribaud p_txdesc->cmd_sts |= MVGBE_TX_FIRST_DESC | MVGBE_TX_LAST_DESC; 571d44265adSAlbert Aribaud p_txdesc->cmd_sts |= MVGBE_BUFFER_OWNED_BY_DMA; 572d44265adSAlbert Aribaud p_txdesc->cmd_sts |= MVGBE_TX_EN_INTERRUPT; 5739b6bcdcbSAlbert Aribaud p_txdesc->buf_ptr = (u8 *) p; 5749b6bcdcbSAlbert Aribaud p_txdesc->byte_cnt = datasize; 5759b6bcdcbSAlbert Aribaud 5769b6bcdcbSAlbert Aribaud /* Set this tc desc as zeroth TXUQ */ 577e6e556c1SAnatolij Gustschin txuq0_reg_addr = (u32)®s->tcqdp[TXUQ]; 578e6e556c1SAnatolij Gustschin writel((u32) p_txdesc, txuq0_reg_addr); 5799b6bcdcbSAlbert Aribaud 5809b6bcdcbSAlbert Aribaud /* ensure tx desc writes above are performed before we start Tx DMA */ 5819b6bcdcbSAlbert Aribaud isb(); 5829b6bcdcbSAlbert Aribaud 5839b6bcdcbSAlbert Aribaud /* Apply send command using zeroth TXUQ */ 584d44265adSAlbert Aribaud MVGBE_REG_WR(regs->tqc, (1 << TXUQ)); 5859b6bcdcbSAlbert Aribaud 5869b6bcdcbSAlbert Aribaud /* 5879b6bcdcbSAlbert Aribaud * wait for packet xmit completion 5889b6bcdcbSAlbert Aribaud */ 5899b6bcdcbSAlbert Aribaud cmd_sts = readl(&p_txdesc->cmd_sts); 590d44265adSAlbert Aribaud while (cmd_sts & MVGBE_BUFFER_OWNED_BY_DMA) { 5919b6bcdcbSAlbert Aribaud /* return fail if error is detected */ 592d44265adSAlbert Aribaud if ((cmd_sts & (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME)) == 593d44265adSAlbert Aribaud (MVGBE_ERROR_SUMMARY | MVGBE_TX_LAST_FRAME) && 594d44265adSAlbert Aribaud cmd_sts & (MVGBE_UR_ERROR | MVGBE_RL_ERROR)) { 5959b6bcdcbSAlbert Aribaud printf("Err..(%s) in xmit packet\n", __FUNCTION__); 5969b6bcdcbSAlbert Aribaud return -1; 5979b6bcdcbSAlbert Aribaud } 5989b6bcdcbSAlbert Aribaud cmd_sts = readl(&p_txdesc->cmd_sts); 5999b6bcdcbSAlbert Aribaud }; 6009b6bcdcbSAlbert Aribaud return 0; 6019b6bcdcbSAlbert Aribaud } 6029b6bcdcbSAlbert Aribaud 603d44265adSAlbert Aribaud static int mvgbe_recv(struct eth_device *dev) 6049b6bcdcbSAlbert Aribaud { 605d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe = to_mvgbe(dev); 606d44265adSAlbert Aribaud struct mvgbe_rxdesc *p_rxdesc_curr = dmvgbe->p_rxdesc_curr; 6079b6bcdcbSAlbert Aribaud u32 cmd_sts; 6089b6bcdcbSAlbert Aribaud u32 timeout = 0; 609e6e556c1SAnatolij Gustschin u32 rxdesc_curr_addr; 6109b6bcdcbSAlbert Aribaud 6119b6bcdcbSAlbert Aribaud /* wait untill rx packet available or timeout */ 6129b6bcdcbSAlbert Aribaud do { 613d44265adSAlbert Aribaud if (timeout < MVGBE_PHY_SMI_TIMEOUT) 6149b6bcdcbSAlbert Aribaud timeout++; 6159b6bcdcbSAlbert Aribaud else { 6169b6bcdcbSAlbert Aribaud debug("%s time out...\n", __FUNCTION__); 6179b6bcdcbSAlbert Aribaud return -1; 6189b6bcdcbSAlbert Aribaud } 619d44265adSAlbert Aribaud } while (readl(&p_rxdesc_curr->cmd_sts) & MVGBE_BUFFER_OWNED_BY_DMA); 6209b6bcdcbSAlbert Aribaud 6219b6bcdcbSAlbert Aribaud if (p_rxdesc_curr->byte_cnt != 0) { 6229b6bcdcbSAlbert Aribaud debug("%s: Received %d byte Packet @ 0x%x (cmd_sts= %08x)\n", 6239b6bcdcbSAlbert Aribaud __FUNCTION__, (u32) p_rxdesc_curr->byte_cnt, 6249b6bcdcbSAlbert Aribaud (u32) p_rxdesc_curr->buf_ptr, 6259b6bcdcbSAlbert Aribaud (u32) p_rxdesc_curr->cmd_sts); 6269b6bcdcbSAlbert Aribaud } 6279b6bcdcbSAlbert Aribaud 6289b6bcdcbSAlbert Aribaud /* 6299b6bcdcbSAlbert Aribaud * In case received a packet without first/last bits on 6309b6bcdcbSAlbert Aribaud * OR the error summary bit is on, 6319b6bcdcbSAlbert Aribaud * the packets needs to be dropeed. 6329b6bcdcbSAlbert Aribaud */ 6339b6bcdcbSAlbert Aribaud cmd_sts = readl(&p_rxdesc_curr->cmd_sts); 6349b6bcdcbSAlbert Aribaud 6359b6bcdcbSAlbert Aribaud if ((cmd_sts & 636d44265adSAlbert Aribaud (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC)) 637d44265adSAlbert Aribaud != (MVGBE_RX_FIRST_DESC | MVGBE_RX_LAST_DESC)) { 6389b6bcdcbSAlbert Aribaud 6399b6bcdcbSAlbert Aribaud printf("Err..(%s) Dropping packet spread on" 6409b6bcdcbSAlbert Aribaud " multiple descriptors\n", __FUNCTION__); 6419b6bcdcbSAlbert Aribaud 642d44265adSAlbert Aribaud } else if (cmd_sts & MVGBE_ERROR_SUMMARY) { 6439b6bcdcbSAlbert Aribaud 6449b6bcdcbSAlbert Aribaud printf("Err..(%s) Dropping packet with errors\n", 6459b6bcdcbSAlbert Aribaud __FUNCTION__); 6469b6bcdcbSAlbert Aribaud 6479b6bcdcbSAlbert Aribaud } else { 6489b6bcdcbSAlbert Aribaud /* !!! call higher layer processing */ 6499b6bcdcbSAlbert Aribaud debug("%s: Sending Received packet to" 6509b6bcdcbSAlbert Aribaud " upper layer (NetReceive)\n", __FUNCTION__); 6519b6bcdcbSAlbert Aribaud 6529b6bcdcbSAlbert Aribaud /* let the upper layer handle the packet */ 6539b6bcdcbSAlbert Aribaud NetReceive((p_rxdesc_curr->buf_ptr + RX_BUF_OFFSET), 6549b6bcdcbSAlbert Aribaud (int)(p_rxdesc_curr->byte_cnt - RX_BUF_OFFSET)); 6559b6bcdcbSAlbert Aribaud } 6569b6bcdcbSAlbert Aribaud /* 6579b6bcdcbSAlbert Aribaud * free these descriptors and point next in the ring 6589b6bcdcbSAlbert Aribaud */ 6599b6bcdcbSAlbert Aribaud p_rxdesc_curr->cmd_sts = 660d44265adSAlbert Aribaud MVGBE_BUFFER_OWNED_BY_DMA | MVGBE_RX_EN_INTERRUPT; 6619b6bcdcbSAlbert Aribaud p_rxdesc_curr->buf_size = PKTSIZE_ALIGN; 6629b6bcdcbSAlbert Aribaud p_rxdesc_curr->byte_cnt = 0; 6639b6bcdcbSAlbert Aribaud 664e6e556c1SAnatolij Gustschin rxdesc_curr_addr = (u32)&dmvgbe->p_rxdesc_curr; 665e6e556c1SAnatolij Gustschin writel((unsigned)p_rxdesc_curr->nxtdesc_p, rxdesc_curr_addr); 6669b6bcdcbSAlbert Aribaud 6679b6bcdcbSAlbert Aribaud return 0; 6689b6bcdcbSAlbert Aribaud } 6699b6bcdcbSAlbert Aribaud 670*cd3ca3ffSSebastian Hesselbarth #if defined(CONFIG_PHYLIB) 671*cd3ca3ffSSebastian Hesselbarth int mvgbe_phylib_init(struct eth_device *dev, int phyid) 672*cd3ca3ffSSebastian Hesselbarth { 673*cd3ca3ffSSebastian Hesselbarth struct mii_dev *bus; 674*cd3ca3ffSSebastian Hesselbarth struct phy_device *phydev; 675*cd3ca3ffSSebastian Hesselbarth int ret; 676*cd3ca3ffSSebastian Hesselbarth 677*cd3ca3ffSSebastian Hesselbarth bus = mdio_alloc(); 678*cd3ca3ffSSebastian Hesselbarth if (!bus) { 679*cd3ca3ffSSebastian Hesselbarth printf("mdio_alloc failed\n"); 680*cd3ca3ffSSebastian Hesselbarth return -ENOMEM; 681*cd3ca3ffSSebastian Hesselbarth } 682*cd3ca3ffSSebastian Hesselbarth bus->read = mvgbe_phy_read; 683*cd3ca3ffSSebastian Hesselbarth bus->write = mvgbe_phy_write; 684*cd3ca3ffSSebastian Hesselbarth sprintf(bus->name, dev->name); 685*cd3ca3ffSSebastian Hesselbarth 686*cd3ca3ffSSebastian Hesselbarth ret = mdio_register(bus); 687*cd3ca3ffSSebastian Hesselbarth if (ret) { 688*cd3ca3ffSSebastian Hesselbarth printf("mdio_register failed\n"); 689*cd3ca3ffSSebastian Hesselbarth free(bus); 690*cd3ca3ffSSebastian Hesselbarth return -ENOMEM; 691*cd3ca3ffSSebastian Hesselbarth } 692*cd3ca3ffSSebastian Hesselbarth 693*cd3ca3ffSSebastian Hesselbarth /* Set phy address of the port */ 694*cd3ca3ffSSebastian Hesselbarth mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid); 695*cd3ca3ffSSebastian Hesselbarth 696*cd3ca3ffSSebastian Hesselbarth phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII); 697*cd3ca3ffSSebastian Hesselbarth if (!phydev) { 698*cd3ca3ffSSebastian Hesselbarth printf("phy_connect failed\n"); 699*cd3ca3ffSSebastian Hesselbarth return -ENODEV; 700*cd3ca3ffSSebastian Hesselbarth } 701*cd3ca3ffSSebastian Hesselbarth 702*cd3ca3ffSSebastian Hesselbarth phy_config(phydev); 703*cd3ca3ffSSebastian Hesselbarth phy_startup(phydev); 704*cd3ca3ffSSebastian Hesselbarth 705*cd3ca3ffSSebastian Hesselbarth return 0; 706*cd3ca3ffSSebastian Hesselbarth } 707*cd3ca3ffSSebastian Hesselbarth #endif 708*cd3ca3ffSSebastian Hesselbarth 709d44265adSAlbert Aribaud int mvgbe_initialize(bd_t *bis) 7109b6bcdcbSAlbert Aribaud { 711d44265adSAlbert Aribaud struct mvgbe_device *dmvgbe; 7129b6bcdcbSAlbert Aribaud struct eth_device *dev; 7139b6bcdcbSAlbert Aribaud int devnum; 714d44265adSAlbert Aribaud u8 used_ports[MAX_MVGBE_DEVS] = CONFIG_MVGBE_PORTS; 7159b6bcdcbSAlbert Aribaud 716d44265adSAlbert Aribaud for (devnum = 0; devnum < MAX_MVGBE_DEVS; devnum++) { 7179b6bcdcbSAlbert Aribaud /*skip if port is configured not to use */ 7189b6bcdcbSAlbert Aribaud if (used_ports[devnum] == 0) 7199b6bcdcbSAlbert Aribaud continue; 7209b6bcdcbSAlbert Aribaud 721d44265adSAlbert Aribaud dmvgbe = malloc(sizeof(struct mvgbe_device)); 722d44265adSAlbert Aribaud 723d44265adSAlbert Aribaud if (!dmvgbe) 7249b6bcdcbSAlbert Aribaud goto error1; 7259b6bcdcbSAlbert Aribaud 726d44265adSAlbert Aribaud memset(dmvgbe, 0, sizeof(struct mvgbe_device)); 7279b6bcdcbSAlbert Aribaud 728d44265adSAlbert Aribaud dmvgbe->p_rxdesc = 729d44265adSAlbert Aribaud (struct mvgbe_rxdesc *)memalign(PKTALIGN, 730d44265adSAlbert Aribaud MV_RXQ_DESC_ALIGNED_SIZE*RINGSZ + 1); 731d44265adSAlbert Aribaud 732d44265adSAlbert Aribaud if (!dmvgbe->p_rxdesc) 7339b6bcdcbSAlbert Aribaud goto error2; 7349b6bcdcbSAlbert Aribaud 735d44265adSAlbert Aribaud dmvgbe->p_rxbuf = (u8 *) memalign(PKTALIGN, 736d44265adSAlbert Aribaud RINGSZ*PKTSIZE_ALIGN + 1); 737d44265adSAlbert Aribaud 738d44265adSAlbert Aribaud if (!dmvgbe->p_rxbuf) 7399b6bcdcbSAlbert Aribaud goto error3; 7409b6bcdcbSAlbert Aribaud 741d44265adSAlbert Aribaud dmvgbe->p_aligned_txbuf = memalign(8, PKTSIZE_ALIGN); 742d44265adSAlbert Aribaud 743d44265adSAlbert Aribaud if (!dmvgbe->p_aligned_txbuf) 7449b6bcdcbSAlbert Aribaud goto error4; 7459b6bcdcbSAlbert Aribaud 746d44265adSAlbert Aribaud dmvgbe->p_txdesc = (struct mvgbe_txdesc *) memalign( 747d44265adSAlbert Aribaud PKTALIGN, sizeof(struct mvgbe_txdesc) + 1); 748d44265adSAlbert Aribaud 749d44265adSAlbert Aribaud if (!dmvgbe->p_txdesc) { 750d44265adSAlbert Aribaud free(dmvgbe->p_aligned_txbuf); 7519b6bcdcbSAlbert Aribaud error4: 752d44265adSAlbert Aribaud free(dmvgbe->p_rxbuf); 7539b6bcdcbSAlbert Aribaud error3: 754d44265adSAlbert Aribaud free(dmvgbe->p_rxdesc); 7559b6bcdcbSAlbert Aribaud error2: 756d44265adSAlbert Aribaud free(dmvgbe); 7579b6bcdcbSAlbert Aribaud error1: 7589b6bcdcbSAlbert Aribaud printf("Err.. %s Failed to allocate memory\n", 7599b6bcdcbSAlbert Aribaud __FUNCTION__); 7609b6bcdcbSAlbert Aribaud return -1; 7619b6bcdcbSAlbert Aribaud } 7629b6bcdcbSAlbert Aribaud 763d44265adSAlbert Aribaud dev = &dmvgbe->dev; 7649b6bcdcbSAlbert Aribaud 765f6add132SMike Frysinger /* must be less than sizeof(dev->name) */ 7669b6bcdcbSAlbert Aribaud sprintf(dev->name, "egiga%d", devnum); 7679b6bcdcbSAlbert Aribaud 7689b6bcdcbSAlbert Aribaud switch (devnum) { 7699b6bcdcbSAlbert Aribaud case 0: 770d44265adSAlbert Aribaud dmvgbe->regs = (void *)MVGBE0_BASE; 7719b6bcdcbSAlbert Aribaud break; 772d44265adSAlbert Aribaud #if defined(MVGBE1_BASE) 7739b6bcdcbSAlbert Aribaud case 1: 774d44265adSAlbert Aribaud dmvgbe->regs = (void *)MVGBE1_BASE; 7759b6bcdcbSAlbert Aribaud break; 776d44265adSAlbert Aribaud #endif 7779b6bcdcbSAlbert Aribaud default: /* this should never happen */ 7789b6bcdcbSAlbert Aribaud printf("Err..(%s) Invalid device number %d\n", 7799b6bcdcbSAlbert Aribaud __FUNCTION__, devnum); 7809b6bcdcbSAlbert Aribaud return -1; 7819b6bcdcbSAlbert Aribaud } 7829b6bcdcbSAlbert Aribaud 783d44265adSAlbert Aribaud dev->init = (void *)mvgbe_init; 784d44265adSAlbert Aribaud dev->halt = (void *)mvgbe_halt; 785d44265adSAlbert Aribaud dev->send = (void *)mvgbe_send; 786d44265adSAlbert Aribaud dev->recv = (void *)mvgbe_recv; 787d44265adSAlbert Aribaud dev->write_hwaddr = (void *)mvgbe_write_hwaddr; 7889b6bcdcbSAlbert Aribaud 7899b6bcdcbSAlbert Aribaud eth_register(dev); 7909b6bcdcbSAlbert Aribaud 791*cd3ca3ffSSebastian Hesselbarth #if defined(CONFIG_PHYLIB) 792*cd3ca3ffSSebastian Hesselbarth mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum); 793*cd3ca3ffSSebastian Hesselbarth #elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII) 7949b6bcdcbSAlbert Aribaud miiphy_register(dev->name, smi_reg_read, smi_reg_write); 7959b6bcdcbSAlbert Aribaud /* Set phy address of the port */ 796d44265adSAlbert Aribaud miiphy_write(dev->name, MV_PHY_ADR_REQUEST, 797d44265adSAlbert Aribaud MV_PHY_ADR_REQUEST, PHY_BASE_ADR + devnum); 7989b6bcdcbSAlbert Aribaud #endif 7999b6bcdcbSAlbert Aribaud } 8009b6bcdcbSAlbert Aribaud return 0; 8019b6bcdcbSAlbert Aribaud } 802