From eef8109a37a2f2d190088eedea1df9c4faabfde1 Mon Sep 17 00:00:00 2001 From: Prabhu Jayakumar Date: Tue, 3 May 2016 18:44:54 +0530 Subject: [PATCH] MIPS: qca956x: enable the ethernet driver This change enables the GMAC and PHY driver for the AP152 target Change-Id: I2d4155754092a4d04d46a40624a68296f9c8fee0 Signed-off-by: Prabhu Jayakumar --- board/qca/mips32/common/ath_phy.h | 31 + board/qca/mips32/common/athrs17_phy.c | 777 +++++++++++++++ board/qca/mips32/common/athrs17_phy.h | 571 +++++++++++ board/qca/mips32/common/qca-eth-956x.c | 1014 ++++++++++++++++++++ board/qca/mips32/common/qca-eth-956x.h | 415 ++++++++ board/qca/mips32/common/qca-eth-956x_phy.h | 159 +++ board/qca/mips32/qca956x/Makefile | 4 +- 7 files changed, 2970 insertions(+), 1 deletion(-) create mode 100644 board/qca/mips32/common/ath_phy.h create mode 100644 board/qca/mips32/common/athrs17_phy.c create mode 100644 board/qca/mips32/common/athrs17_phy.h create mode 100644 board/qca/mips32/common/qca-eth-956x.c create mode 100644 board/qca/mips32/common/qca-eth-956x.h create mode 100644 board/qca/mips32/common/qca-eth-956x_phy.h diff --git a/board/qca/mips32/common/ath_phy.h b/board/qca/mips32/common/ath_phy.h new file mode 100644 index 0000000000..e8aa749dc5 --- /dev/null +++ b/board/qca/mips32/common/ath_phy.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _PHY_H +#define _PHY_H + +#include + +#define ath_gmac_unit2name(_unit) (_unit ? "eth1" : "eth0") + +extern int ath_gmac_miiphy_read(char *devname, uint32_t phaddr, uint8_t reg, uint16_t *data); +extern int ath_gmac_miiphy_write(char *devname, uint32_t phaddr, uint8_t reg, uint16_t data); + +#define phy_reg_read(base, addr, reg) \ + ath_gmac_miiphy_read(ath_gmac_unit2name(base), addr, reg, NULL) + +#define phy_reg_write(base, addr, reg, data) \ + ath_gmac_miiphy_write(ath_gmac_unit2name(base), addr, reg, data) + +#endif diff --git a/board/qca/mips32/common/athrs17_phy.c b/board/qca/mips32/common/athrs17_phy.c new file mode 100644 index 0000000000..c7125e5698 --- /dev/null +++ b/board/qca/mips32/common/athrs17_phy.c @@ -0,0 +1,777 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +/* + * Manage the atheros ethernet PHY. + * + * All definitions in this file are operating system independent! + */ + +#include +#include +#include +#include +//#include "ath_phy.h" +#include +#include +#include "athrs17_phy.h" + +#define ath_gmac_unit2name(_unit) (_unit ? "eth1" : "eth0") + +extern int ath_gmac_miiphy_read(char *devname, uint32_t phaddr, uint8_t reg, uint16_t *data); +extern int ath_gmac_miiphy_write(char *devname, uint32_t phaddr, uint8_t reg, uint16_t data); + +#define phy_reg_read(base, addr, reg) \ + ath_gmac_miiphy_read(ath_gmac_unit2name(base), addr, reg, NULL) + +#define phy_reg_write(base, addr, reg, data) \ + ath_gmac_miiphy_write(ath_gmac_unit2name(base), addr, reg, data) + +/* PHY selections and access functions */ +typedef enum { + PHY_SRCPORT_INFO, + PHY_PORTINFO_SIZE, +} PHY_CAP_TYPE; + +typedef enum { + PHY_SRCPORT_NONE, + PHY_SRCPORT_VLANTAG, + PHY_SRCPORT_TRAILER, +} PHY_SRCPORT_TYPE; + +#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6) +#define DRV_MSG(x,a,b,c,d,e,f) +#define DRV_PRINT(DBG_SW,X) + +#define ATHR_LAN_PORT_VLAN 1 +#define ATHR_WAN_PORT_VLAN 2 + +#define ENET_UNIT_GE0 0 +#define ENET_UNIT_GE1 1 + +#define TRUE 1 +#define FALSE 0 + +#define ATHR_PHY0_ADDR 0x0 +#define ATHR_PHY1_ADDR 0x1 +#define ATHR_PHY2_ADDR 0x2 +#define ATHR_PHY3_ADDR 0x3 +#define ATHR_PHY4_ADDR 0x4 +#define ATHR_IND_PHY 4 + +#define MODULE_NAME "ATHRS17" +#define S17_PHY_DEBUG 1 +extern int xmii_val; + +/* + * Track per-PHY port information. + */ +typedef struct { + BOOL isEnetPort; /* normal enet port */ + BOOL isPhyAlive; /* last known state of link */ + int ethUnit; /* MAC associated with this phy port */ + uint32_t phyBase; + uint32_t phyAddr; /* PHY registers associated with this phy port */ + uint32_t VLANTableSetting; /* Value to be written to VLAN table */ +} athrPhyInfo_t; + +#if defined(ATH_S17_MAC0_SGMII) +#if (CFG_ATH_GMAC_NMACS == 1) /* QCA9563 only have 1 GMAC working */ +#define ENET_UNIT ENET_UNIT_GE0 +#define ENET_UNIT_WAN ENET_UNIT_GE0 +#else +#define ENET_UNIT ENET_UNIT_GE1 +#define ENET_UNIT_WAN ENET_UNIT_GE0 +#endif +#else +#define ENET_UNIT ENET_UNIT_GE0 +#define ENET_UNIT_WAN ENET_UNIT_GE1 +#endif + +/* + * Per-PHY information, indexed by PHY unit number. + */ +static athrPhyInfo_t athrPhyInfo[] = { + { + TRUE, /* phy port 0 -- LAN port 0 */ + FALSE, + ENET_UNIT, + 0, + ATHR_PHY0_ADDR, + ATHR_LAN_PORT_VLAN + }, + { + TRUE, /* phy port 1 -- LAN port 1 */ + FALSE, + ENET_UNIT, + 0, + ATHR_PHY1_ADDR, + ATHR_LAN_PORT_VLAN + }, + { + TRUE, /* phy port 2 -- LAN port 2 */ + FALSE, + ENET_UNIT, + 0, + ATHR_PHY2_ADDR, + ATHR_LAN_PORT_VLAN + }, + { + TRUE, /* phy port 3 -- LAN port 3 */ + FALSE, + ENET_UNIT, + 0, + ATHR_PHY3_ADDR, + ATHR_LAN_PORT_VLAN + }, + { + TRUE, /* phy port 4 -- WAN port or LAN port 4 */ + FALSE, +#if defined(CONFIG_ATH_S17_WAN) || defined (ATH_S17_MAC0_SGMII) + ENET_UNIT_WAN, +#else + ENET_UNIT, +#endif + 0, + ATHR_PHY4_ADDR, + ATHR_LAN_PORT_VLAN /* Send to all ports */ + }, + { + FALSE, /* phy port 5 -- CPU port (no RJ45 connector) */ + TRUE, + ENET_UNIT, + 0, + 0x00, + ATHR_LAN_PORT_VLAN /* Send to all ports */ + }, +}; + +static uint8_t athr17_init_flag = 0; + +//#define ATHR_PHY_MAX (sizeof(ipPhyInfo) / sizeof(ipPhyInfo[0])) +#define ATHR_PHY_MAX 5 + +/* Range of valid PHY IDs is [MIN..MAX] */ +#define ATHR_ID_MIN 0 +#define ATHR_ID_MAX (ATHR_PHY_MAX-1) + +/* Convenience macros to access myPhyInfo */ +#define ATHR_IS_ENET_PORT(phyUnit) (athrPhyInfo[phyUnit].isEnetPort) +#define ATHR_IS_PHY_ALIVE(phyUnit) (athrPhyInfo[phyUnit].isPhyAlive) +#define ATHR_ETHUNIT(phyUnit) (athrPhyInfo[phyUnit].ethUnit) +#define ATHR_PHYBASE(phyUnit) (athrPhyInfo[phyUnit].phyBase) +#define ATHR_PHYADDR(phyUnit) (athrPhyInfo[phyUnit].phyAddr) +#define ATHR_VLAN_TABLE_SETTING(phyUnit) (athrPhyInfo[phyUnit].VLANTableSetting) + + +#define ATHR_IS_ETHUNIT(phyUnit, ethUnit) \ + (ATHR_IS_ENET_PORT(phyUnit) && \ + ATHR_ETHUNIT(phyUnit) == (ethUnit)) + +#define ATHR_IS_WAN_PORT(phyUnit) (!(ATHR_ETHUNIT(phyUnit)==ENET_UNIT_GE0)) + +/* Forward references */ +BOOL athrs17_phy_is_link_alive(int phyUnit); +uint32_t athrs17_reg_read(uint32_t reg_addr); +void athrs17_reg_write(uint32_t reg_addr, uint32_t reg_val); +static void phy_mode_setup(void); + +#define sysMsDelay(_x) udelay((_x) * 1000) + +static void phy_mode_setup(void) +{ +#ifdef ATHRS17_VER_1_0 + /*work around for phy4 rgmii mode*/ + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 29, 18); + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 30, 0x480c); + + /*rx delay*/ + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 29, 0); + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 30, 0x824e); + + /*tx delay*/ + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 29, 5); + phy_reg_write(ATHR_PHYBASE(ATHR_IND_PHY), ATHR_PHYADDR(ATHR_IND_PHY), 30, 0x3d47); +#endif +} +/* + * V-lan configuration given by Switch team + * Vlan 1:PHY0,1,2,3 and Mac 0 of s17 + * Vlam 2:PHY4 and Mac 6 of s17 + */ + +void athrs17_vlan_config() +{ + athrs17_reg_write(S17_P0LOOKUP_CTRL_REG, 0x0014001e); + athrs17_reg_write(S17_P0VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P1LOOKUP_CTRL_REG, 0x0014001d); + athrs17_reg_write(S17_P1VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P2LOOKUP_CTRL_REG, 0x0014001b); + athrs17_reg_write(S17_P2VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P3LOOKUP_CTRL_REG, 0x00140017); + athrs17_reg_write(S17_P3VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P4LOOKUP_CTRL_REG, 0x0014000f); + athrs17_reg_write(S17_P4VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P5LOOKUP_CTRL_REG, 0x00140040); + athrs17_reg_write(S17_P5VLAN_CTRL0_REG, 0x20001); + + athrs17_reg_write(S17_P6LOOKUP_CTRL_REG, 0x00140020); + athrs17_reg_write(S17_P6VLAN_CTRL0_REG, 0x20001); + + +} + +void athrs17_reg_init_wan(void) +{ + uint32_t sgmii_ctrl_value; + + /* SGMII control reg value based on switch id */ + if ((athrs17_reg_read(S17_MASK_CTRL_REG) & 0xFFFF) >= S17C_V1_DEVICEID) { + sgmii_ctrl_value = 0xc74164de; + } else { + sgmii_ctrl_value = 0xc74164d0; + } + + +#ifdef ATH_S17_MAC0_SGMII + athrs17_reg_write(S17_P6PAD_MODE_REG,0x07600000); + +#else + athrs17_reg_write(S17_P6PAD_MODE_REG, + athrs17_reg_read(S17_P6PAD_MODE_REG)|S17_MAC6_SGMII_EN); +#endif + athrs17_reg_write(S17_P6STATUS_REG, S17_PORT_STATUS_AZ_DEFAULT); + athrs17_reg_write(S17_SGMII_CTRL_REG , sgmii_ctrl_value); /* SGMII control */ + + athrs17_vlan_config(); + printf("%s done\n",__func__); + +} + +void athrs17_reg_init() +{ + int phy_addr = 0; + uint32_t sgmii_ctrl_value; + /* if using header for register configuration, we have to */ + /* configure s17 register after frame transmission is enabled */ + + if ((athrs17_reg_read(S17_MASK_CTRL_REG) & 0xFFFF) >= S17C_V1_DEVICEID) { + sgmii_ctrl_value = 0xc74164de; + } else { + sgmii_ctrl_value = 0xc74164d0; + } + if (athr17_init_flag) { + return; + } + +#if (CFG_ATH_GMAC_NMACS == 1) + athrs17_reg_write(S17_P0PAD_MODE_REG, S17_MAC0_SGMII_EN); + athrs17_reg_write(S17_SGMII_CTRL_REG , sgmii_ctrl_value); /* SGMII control */ + athrs17_reg_write(S17_GLOFW_CTRL1_REG, 0x7f7f7f7f); +#else + if (is_drqfn()) { + athrs17_reg_write(S17_P0PAD_MODE_REG, S17_MAC0_SGMII_EN); + athrs17_reg_write(S17_SGMII_CTRL_REG , sgmii_ctrl_value); /* SGMII control */ + } else { + athrs17_reg_write(S17_GLOFW_CTRL1_REG, 0x7f7f7f7f); + /* + * If defined S17 Mac0 sgmii val of 0x4(S17_P0PAD_MODE_REG) + * should be configured as 0x80 + */ +#ifdef ATH_S17_MAC0_SGMII + athrs17_reg_write(S17_P0PAD_MODE_REG, 0x80080); +#else + athrs17_reg_write(S17_P0PAD_MODE_REG, 0x07680000); +#endif + athrs17_reg_write(S17_P6PAD_MODE_REG, 0x01000000); + } +#endif /* CFG_ATH_GMAC_NMACS == 1 */ + +/* + * Values suggested by the swich team when s17 in sgmii configuration + * operates in forced mode. + * 0x10(S17_PWS_REG)=0x602613a0 + */ +#ifdef ATH_SGMII_FORCED_MODE + athrs17_reg_write(S17_PWS_REG, 0x602613a0); +#else + athrs17_reg_write(S17_PWS_REG, 0x40000000); +#endif + athrs17_reg_write(S17_P0STATUS_REG, 0x0000007e); + + /* AR8327/AR8328 v1.0 fixup */ + if ((athrs17_reg_read(0x0) & 0xffff) == 0x1201) { + for (phy_addr = 0x0; phy_addr <= ATHR_PHY_MAX; phy_addr++) { + /* For 100M waveform */ + phy_reg_write(0, phy_addr, 0x1d, 0x0); + phy_reg_write(0, phy_addr, 0x1e, 0x02ea); + /* Turn On Gigabit Clock */ + phy_reg_write(0, phy_addr, 0x1d, 0x3d); + phy_reg_write(0, phy_addr, 0x1e, 0x68a0); + } + } + + /* AR8337/AR8334 v1.0 fixup */ + if ((athrs17_reg_read(0x0) & 0xffff) == S17C_V1_DEVICEID) { + for (phy_addr = 0x0; phy_addr <= ATHR_PHY_MAX; phy_addr++) { + /* Turn On Gigabit Clock */ + phy_reg_write(0, phy_addr, 0x1d, 0x3d); + phy_reg_write(0, phy_addr, 0x1e, 0x6820); + } + printf("Set up QCA8337 V1.0 fixup\n"); + } + +#if CONFIG_S17_SWMAC6_CONNECTED + printf ("Configuring Mac6 of s17 to slave scorpion\n"); + athrs17_reg_write(S17_P6PAD_MODE_REG, S17_MAC6_RGMII_EN | S17_MAC6_RGMII_TXCLK_DELAY | \ + S17_MAC6_RGMII_RXCLK_DELAY | (1 << S17_MAC6_RGMII_TXCLK_SHIFT) | \ + (2 << S17_MAC6_RGMII_RXCLK_SHIFT)); + athrs17_reg_write(S17_P6STATUS_REG, 0x7e); + athrs17_vlan_config(); +#endif + athr17_init_flag = 1; + printf("%s: complete\n",__func__); +} + +/****************************************************************************** +* +* athrs17_phy_is_link_alive - test to see if the specified link is alive +* +* RETURNS: +* TRUE --> link is alive +* FALSE --> link is down +*/ +BOOL +athrs17_phy_is_link_alive(int phyUnit) +{ + uint16_t phyHwStatus; + uint32_t phyBase; + uint32_t phyAddr; + + phyBase = ATHR_PHYBASE(phyUnit); + phyAddr = ATHR_PHYADDR(phyUnit); + + phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_SPEC_STATUS); + + if (phyHwStatus & ATHR_STATUS_LINK_PASS) + return TRUE; + + return FALSE; +} + +/****************************************************************************** +* +* athrs17_phy_setup - reset and setup the PHY associated with +* the specified MAC unit number. +* +* Resets the associated PHY port. +* +* RETURNS: +* TRUE --> associated PHY is alive +* FALSE --> no LINKs on this ethernet unit +*/ + +BOOL +athrs17_phy_setup(int ethUnit) +{ + int phyUnit; + uint16_t phyHwStatus; + uint16_t timeout; + int liveLinks = 0; + uint32_t phyBase = 0; + BOOL foundPhy = FALSE; + uint32_t phyAddr = 0; + + /* See if there's any configuration data for this enet */ + /* start auto negogiation on each phy */ + if (is_drqfn()) + ethUnit=0; + for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + foundPhy = TRUE; + phyBase = ATHR_PHYBASE(phyUnit); + phyAddr = ATHR_PHYADDR(phyUnit); + + phy_reg_write(phyBase, phyAddr, ATHR_AUTONEG_ADVERT, + ATHR_ADVERTISE_ALL); + + phy_reg_write(phyBase, phyAddr, ATHR_1000BASET_CONTROL, + ATHR_ADVERTISE_1000FULL); + + /* Reset PHYs*/ + phy_reg_write(phyBase, phyAddr, ATHR_PHY_CONTROL, + ATHR_CTRL_AUTONEGOTIATION_ENABLE + | ATHR_CTRL_SOFTWARE_RESET); + + } + + if (!foundPhy) { + return FALSE; /* No PHY's configured for this ethUnit */ + } + + /* + * After the phy is reset, it takes a little while before + * it can respond properly. + */ + sysMsDelay(1000); + + + /* + * Wait up to 3 seconds for ALL associated PHYs to finish + * autonegotiation. The only way we get out of here sooner is + * if ALL PHYs are connected AND finish autonegotiation. + */ + for (phyUnit=0; (phyUnit < ATHR_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + timeout=20; + for (;;) { + phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_CONTROL); + + if (ATHR_RESET_DONE(phyHwStatus)) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Neg Success\n", phyUnit)); + break; + } + if (timeout == 0) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Negogiation timeout\n", phyUnit)); + break; + } + if (--timeout == 0) { + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("Port %d, Negogiation timeout\n", phyUnit)); + break; + } + + sysMsDelay(150); + } + } + + /* + * All PHYs have had adequate time to autonegotiate. + * Now initialize software status. + * + * It's possible that some ports may take a bit longer + * to autonegotiate; but we can't wait forever. They'll + * get noticed by mv_phyCheckStatusChange during regular + * polling activities. + */ + for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } +#if 0 + /* Enable RGMII */ + phy_reg_write(0,phyUnit,0x1d,0x12); + phy_reg_write(0,phyUnit,0x1e,0x8); + /* Tx delay on PHY */ + phy_reg_write(0,phyUnit,0x1d,0x5); + phy_reg_write(0,phyUnit,0x1e,0x100); + + /* Rx delay on PHY */ + phy_reg_write(0,phyUnit,0x1d,0x0); + phy_reg_write(0,phyUnit,0x1e,0x8000); +#endif + if (athrs17_phy_is_link_alive(phyUnit)) { + liveLinks++; + ATHR_IS_PHY_ALIVE(phyUnit) = TRUE; + } else { + ATHR_IS_PHY_ALIVE(phyUnit) = FALSE; + } + + DRV_PRINT(DRV_DEBUG_PHYSETUP, + ("eth%d: Phy Specific Status=%4.4x\n", + ethUnit, + phy_reg_read(ATHR_PHYBASE(phyUnit), + ATHR_PHYADDR(phyUnit), + ATHR_PHY_SPEC_STATUS))); + } + phy_mode_setup(); + return (liveLinks > 0); +} + +/****************************************************************************** +* +* athrs17_phy_is_fdx - Determines whether the phy ports associated with the +* specified device are FULL or HALF duplex. +* +* RETURNS: +* 1 --> FULL +* 0 --> HALF +*/ +int +athrs17_phy_is_fdx(int ethUnit) +{ + int phyUnit; + uint32_t phyBase; + uint32_t phyAddr; + uint16_t phyHwStatus; + int ii = 200; + + + if (is_drqfn()) + ethUnit = 0; + + + for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (athrs17_phy_is_link_alive(phyUnit)) { + + phyBase = ATHR_PHYBASE(phyUnit); + phyAddr = ATHR_PHYADDR(phyUnit); + + do { + phyHwStatus = phy_reg_read (phyBase, phyAddr, + ATHR_PHY_SPEC_STATUS); + if(phyHwStatus & ATHR_STATUS_RESOVLED) + break; + sysMsDelay(10); + } while(--ii); + + if (phyHwStatus & ATHER_STATUS_FULL_DEPLEX) + return TRUE; + } + } + + if (ethUnit == ENET_UNIT_GE0 || ethUnit == ENET_UNIT_GE1) + return TRUE; + + return FALSE; +} + +/****************************************************************************** +* +* athrs17_phy_speed - Determines the speed of phy ports associated with the +* specified device. +* +* RETURNS: _10BASET, _100BASETX, _1000BASET +*/ + +int +athrs17_phy_speed(int ethUnit) +{ + int phyUnit; + uint16_t phyHwStatus; + uint32_t phyBase; + uint32_t phyAddr; + int ii = 200; + + if ((ethUnit == ENET_UNIT_GE0) || (ethUnit == ENET_UNIT_GE1)) + return _1000BASET; + + for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + if (athrs17_phy_is_link_alive(phyUnit)) { + + phyBase = ATHR_PHYBASE(phyUnit); + phyAddr = ATHR_PHYADDR(phyUnit); + + do { + phyHwStatus = phy_reg_read(phyBase, phyAddr, + ATHR_PHY_SPEC_STATUS); + if(phyHwStatus & ATHR_STATUS_RESOVLED) + break; + sysMsDelay(10); + } while((!(phyHwStatus & ATHR_STATUS_RESOVLED)) && --ii); + + phyHwStatus = ((phyHwStatus & ATHER_STATUS_LINK_MASK) >> + ATHER_STATUS_LINK_SHIFT); + + switch(phyHwStatus) { + case 0: return _10BASET; + case 1: return _100BASET; + case 2: return _1000BASET; + default: printf("Unkown speed read!\n"); + } + } + + } + + return _10BASET; +} + +/***************************************************************************** +* +* athr_phy_is_up -- checks for significant changes in PHY state. +* +* A "significant change" is: +* dropped link (e.g. ethernet cable unplugged) OR +* autonegotiation completed + link (e.g. ethernet cable plugged in) +* +* When a PHY is plugged in, phyLinkGained is called. +* When a PHY is unplugged, phyLinkLost is called. +*/ + +int +athrs17_phy_is_up(int ethUnit) +{ + int phyUnit; + uint16_t phyHwStatus, phyHwControl; + athrPhyInfo_t *lastStatus; + int linkCount = 0; + int lostLinks = 0; + int gainedLinks = 0; + uint32_t phyBase; + uint32_t phyAddr; + + if (is_drqfn()) + ethUnit = 0; + for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) { + if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) { + continue; + } + + phyBase = ATHR_PHYBASE(phyUnit); + phyAddr = ATHR_PHYADDR(phyUnit); + + lastStatus = &athrPhyInfo[phyUnit]; + + if (lastStatus->isPhyAlive) { /* last known link status was ALIVE */ + phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_SPEC_STATUS); + + /* See if we've lost link */ + if (phyHwStatus & ATHR_STATUS_LINK_PASS) { + linkCount++; + } else { + lostLinks++; + DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d down\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = FALSE; + } + } else { /* last known link status was DEAD */ + /* Check for reset complete */ + phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_STATUS); + if (!ATHR_RESET_DONE(phyHwStatus)) { + continue; + } + + phyHwControl = phy_reg_read(phyBase, phyAddr, ATHR_PHY_CONTROL); + /* Check for AutoNegotiation complete */ + if ((!(phyHwControl & ATHR_CTRL_AUTONEGOTIATION_ENABLE)) + || ATHR_AUTONEG_DONE(phyHwStatus)) { + phyHwStatus = phy_reg_read(phyBase, phyAddr, + ATHR_PHY_SPEC_STATUS); + + if (phyHwStatus & ATHR_STATUS_LINK_PASS) { + gainedLinks++; + linkCount++; + DRV_PRINT(DRV_DEBUG_PHYCHANGE,("\nenet%d port%d up\n", + ethUnit, phyUnit)); + lastStatus->isPhyAlive = TRUE; + } + } + } + } + + return (linkCount); + +} + +uint32_t +athrs17_reg_read(uint32_t reg_addr) +{ + uint32_t reg_word_addr; + uint32_t phy_addr, tmp_val, reg_val; + uint16_t phy_val; + uint8_t phy_reg; + + /* change reg_addr to 16-bit word address, 32-bit aligned */ + reg_word_addr = (reg_addr & 0xfffffffc) >> 1; + + /* configure register high address */ + phy_addr = 0x18; + phy_reg = 0x0; + phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff); /* bit16-8 of reg address */ + phy_reg_write(0, phy_addr, phy_reg, phy_val); + + /* For some registers such as MIBs, since it is read/clear, we should */ + /* read the lower 16-bit register then the higher one */ + + /* read register in lower address */ + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + reg_val = (uint32_t) phy_reg_read(0, phy_addr, phy_reg); + + /* read register in higher address */ + reg_word_addr++; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + tmp_val = (uint32_t) phy_reg_read(0, phy_addr, phy_reg); + reg_val |= (tmp_val << 16); + + return reg_val; +} + +void +athrs17_reg_write(uint32_t reg_addr, uint32_t reg_val) +{ + uint32_t reg_word_addr; + uint32_t phy_addr; + uint16_t phy_val; + uint8_t phy_reg; + + /* change reg_addr to 16-bit word address, 32-bit aligned */ + reg_word_addr = (reg_addr & 0xfffffffc) >> 1; + + /* configure register high address */ + phy_addr = 0x18; + phy_reg = 0x0; + phy_val = (uint16_t) ((reg_word_addr >> 8) & 0x1ff); /* bit16-8 of reg address */ + phy_reg_write(0, phy_addr, phy_reg, phy_val); + + /* For some registers such as ARL and VLAN, since they include BUSY bit */ + /* in lower address, we should write the higher 16-bit register then the */ + /* lower one */ + + /* read register in higher address */ + reg_word_addr++; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + phy_val = (uint16_t) ((reg_val >> 16) & 0xffff); + phy_reg_write(0, phy_addr, phy_reg, phy_val); + + /* write register in lower address */ + reg_word_addr--; + phy_addr = 0x10 | ((reg_word_addr >> 5) & 0x7); /* bit7-5 of reg address */ + phy_reg = (uint8_t) (reg_word_addr & 0x1f); /* bit4-0 of reg address */ + phy_val = (uint16_t) (reg_val & 0xffff); + phy_reg_write(0, phy_addr, phy_reg, phy_val); +} + +unsigned int s17_rd_phy(unsigned int phy_addr, unsigned int reg_addr) +{ + return ((uint32_t) phy_reg_read(0, phy_addr, reg_addr)); +} + +void s17_wr_phy(unsigned int phy_addr, unsigned int reg_addr, unsigned int write_data) +{ + phy_reg_write(0, phy_addr, reg_addr, write_data); +} diff --git a/board/qca/mips32/common/athrs17_phy.h b/board/qca/mips32/common/athrs17_phy.h new file mode 100644 index 0000000000..f92aaa8560 --- /dev/null +++ b/board/qca/mips32/common/athrs17_phy.h @@ -0,0 +1,571 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _ATHRS17_PHY_H +#define _ATHRS17_PHY_H + +/*****************/ +/* PHY Registers */ +/*****************/ +#define ATHR_PHY_CONTROL 0 +#define ATHR_PHY_STATUS 1 +#define ATHR_PHY_ID1 2 +#define ATHR_PHY_ID2 3 +#define ATHR_AUTONEG_ADVERT 4 +#define ATHR_LINK_PARTNER_ABILITY 5 +#define ATHR_AUTONEG_EXPANSION 6 +#define ATHR_NEXT_PAGE_TRANSMIT 7 +#define ATHR_LINK_PARTNER_NEXT_PAGE 8 +#define ATHR_1000BASET_CONTROL 9 +#define ATHR_1000BASET_STATUS 10 +#define ATHR_PHY_SPEC_CONTROL 16 +#define ATHR_PHY_SPEC_STATUS 17 +#define ATHR_DEBUG_PORT_ADDRESS 29 +#define ATHR_DEBUG_PORT_DATA 30 + +/* ATHR_PHY_CONTROL fields */ +#define ATHR_CTRL_SOFTWARE_RESET 0x8000 +#define ATHR_CTRL_SPEED_LSB 0x2000 +#define ATHR_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define ATHR_CTRL_RESTART_AUTONEGOTIATION 0x0200 +#define ATHR_CTRL_SPEED_FULL_DUPLEX 0x0100 +#define ATHR_CTRL_SPEED_MSB 0x0040 + +#define ATHR_RESET_DONE(phy_control) \ + (((phy_control) & (ATHR_CTRL_SOFTWARE_RESET)) == 0) + +/* Phy status fields */ +#define ATHR_STATUS_AUTO_NEG_DONE 0x0020 + +#define ATHR_AUTONEG_DONE(ip_phy_status) \ + (((ip_phy_status) & \ + (ATHR_STATUS_AUTO_NEG_DONE)) == \ + (ATHR_STATUS_AUTO_NEG_DONE)) + +/* Link Partner ability */ +#define ATHR_LINK_100BASETX_FULL_DUPLEX 0x0100 +#define ATHR_LINK_100BASETX 0x0080 +#define ATHR_LINK_10BASETX_FULL_DUPLEX 0x0040 +#define ATHR_LINK_10BASETX 0x0020 + +/* Advertisement register. */ +#define ATHR_ADVERTISE_NEXT_PAGE 0x8000 +#define ATHR_ADVERTISE_ASYM_PAUSE 0x0800 +#define ATHR_ADVERTISE_PAUSE 0x0400 +#define ATHR_ADVERTISE_100FULL 0x0100 +#define ATHR_ADVERTISE_100HALF 0x0080 +#define ATHR_ADVERTISE_10FULL 0x0040 +#define ATHR_ADVERTISE_10HALF 0x0020 + +#define ATHR_ADVERTISE_ALL (ATHR_ADVERTISE_ASYM_PAUSE | ATHR_ADVERTISE_PAUSE | \ + ATHR_ADVERTISE_10HALF | ATHR_ADVERTISE_10FULL | \ + ATHR_ADVERTISE_100HALF | ATHR_ADVERTISE_100FULL) + +/* 1000BASET_CONTROL */ +#define ATHR_ADVERTISE_1000FULL 0x0200 + +/* Phy Specific status fields */ +#define ATHER_STATUS_LINK_MASK 0xC000 +#define ATHER_STATUS_LINK_SHIFT 14 +#define ATHER_STATUS_FULL_DEPLEX 0x2000 +#define ATHR_STATUS_LINK_PASS 0x0400 +#define ATHR_STATUS_RESOVLED 0x0800 + +/*phy debug port register */ +#define ATHER_DEBUG_SERDES_REG 5 + +/* Serdes debug fields */ +#define ATHER_SERDES_BEACON 0x0100 + +/* S17 CSR Registers */ + +#define S17_ENABLE_CPU_BROADCAST (1 << 26) + +#define S17_PHY_LINK_CHANGE_REG 0x4 +#define S17_PHY_LINK_UP 0x400 +#define S17_PHY_LINK_DOWN 0x800 +#define S17_PHY_LINK_DUPLEX_CHANGE 0x2000 +#define S17_PHY_LINK_SPEED_CHANGE 0x4000 +#define S17_PHY_LINK_INTRS (PHY_LINK_UP | PHY_LINK_DOWN | PHY_LINK_DUPLEX_CHANGE | PHY_LINK_SPEED_CHANGE) + +//defines from athrs17_phy.h driver +#define S17C_V1_DEVICEID 0x1301 +#define S17C_V2_DEVICEID 0x1302 + +#define S17_MASK_CTRL_REG 0x0000 +#define S17_P0PAD_MODE_REG 0x0004 +#define S17_P5PAD_MODE_REG 0x0008 +#define S17_P6PAD_MODE_REG 0x000c +#define S17_PWS_REG 0x0010 +#define S17_GLOBAL_INT0_REG 0x0020 +#define S17_GLOBAL_INT1_REG 0x0024 +#define S17_GLOBAL_INTMASK0 0x0028 +#define S17_GLOBAL_INTMASK1 0x002c +#define S17_MODULE_EN_REG 0x0030 +#define S17_MIB_REG 0x0034 +#define S17_INTF_HIADDR_REG 0x0038 +#define S17_MDIO_CTRL_REG 0x003c +#define S17_BIST_CTRL_REG 0x0040 +#define S17_BIST_REC_REG 0x0044 +#define S17_SERVICE_REG 0x0048 +#define S17_LED_CTRL0_REG 0x0050 +#define S17_LED_CTRL1_REG 0x0054 +#define S17_LED_CTRL2_REG 0x0058 +#define S17_LED_CTRL3_REG 0x005c +#define S17_MACADDR0_REG 0x0060 +#define S17_MACADDR1_REG 0x0064 +#define S17_MAX_FRAME_SIZE_REG 0x0078 +#define S17_P0STATUS_REG 0x007c +#define S17_P1STATUS_REG 0x0080 +#define S17_P2STATUS_REG 0x0084 +#define S17_P3STATUS_REG 0x0088 +#define S17_P4STATUS_REG 0x008c +#define S17_P5STATUS_REG 0x0090 +#define S17_P6STATUS_REG 0x0094 +#define S17_HDRCTRL_REG 0x0098 +#define S17_P0HDRCTRL_REG 0x009c +#define S17_P1HDRCTRL_REG 0x00A0 +#define S17_P2HDRCTRL_REG 0x00a4 +#define S17_P3HDRCTRL_REG 0x00a8 +#define S17_P4HDRCTRL_REG 0x00ac +#define S17_P5HDRCTRL_REG 0x00b0 +#define S17_P6HDRCTRL_REG 0x00b4 +#define S17_SGMII_CTRL_REG 0x00e0 +#define S17_EEE_CTRL_REG 0x0100 + +/* ACL Registers */ +#define S17_ACL_FUNC0_REG 0x0400 +#define S17_ACL_FUNC1_REG 0x0404 +#define S17_ACL_FUNC2_REG 0x0408 +#define S17_ACL_FUNC3_REG 0x040c +#define S17_ACL_FUNC4_REG 0x0410 +#define S17_ACL_FUNC5_REG 0x0414 +#define S17_PRIVATE_IP_REG 0x0418 +#define S17_P0VLAN_CTRL0_REG 0x0420 +#define S17_P0VLAN_CTRL1_REG 0x0424 +#define S17_P1VLAN_CTRL0_REG 0x0428 +#define S17_P1VLAN_CTRL1_REG 0x042c +#define S17_P2VLAN_CTRL0_REG 0x0430 +#define S17_P2VLAN_CTRL1_REG 0x0434 +#define S17_P3VLAN_CTRL0_REG 0x0438 +#define S17_P3VLAN_CTRL1_REG 0x043c +#define S17_P4VLAN_CTRL0_REG 0x0440 +#define S17_P4VLAN_CTRL1_REG 0x0444 +#define S17_P5VLAN_CTRL0_REG 0x0448 +#define S17_P5VLAN_CTRL1_REG 0x044c +#define S17_P6VLAN_CTRL0_REG 0x0450 +#define S17_P6VLAN_CTRL1_REG 0x0454 + +/* Table Lookup Registers */ +#define S17_ATU_DATA0_REG 0x0600 +#define S17_ATU_DATA1_REG 0x0604 +#define S17_ATU_DATA2_REG 0x0608 +#define S17_ATU_FUNC_REG 0x060C +#define S17_VTU_FUNC0_REG 0x0610 +#define S17_VTU_FUNC1_REG 0x0614 +#define S17_ARL_CTRL_REG 0x0618 +#define S17_GLOFW_CTRL0_REG 0x0620 +#define S17_GLOFW_CTRL1_REG 0x0624 +#define S17_GLOLEARN_LIMIT_REG 0x0628 +#define S17_TOS_PRIMAP_REG0 0x0630 +#define S17_TOS_PRIMAP_REG1 0x0634 +#define S17_TOS_PRIMAP_REG2 0x0638 +#define S17_TOS_PRIMAP_REG3 0x063c +#define S17_TOS_PRIMAP_REG4 0x0640 +#define S17_TOS_PRIMAP_REG5 0x0644 +#define S17_TOS_PRIMAP_REG6 0x0648 +#define S17_TOS_PRIMAP_REG7 0x064c +#define S17_VLAN_PRIMAP_REG0 0x0650 +#define S17_LOOP_CHECK_REG 0x0654 +#define S17_P0LOOKUP_CTRL_REG 0x0660 +#define S17_P0PRI_CTRL_REG 0x0664 +#define S17_P0LEARN_LMT_REG 0x0668 +#define S17_P1LOOKUP_CTRL_REG 0x066c +#define S17_P1PRI_CTRL_REG 0x0670 +#define S17_P1LEARN_LMT_REG 0x0674 +#define S17_P2LOOKUP_CTRL_REG 0x0678 +#define S17_P2PRI_CTRL_REG 0x067c +#define S17_P2LEARN_LMT_REG 0x0680 +#define S17_P3LOOKUP_CTRL_REG 0x0684 +#define S17_P3PRI_CTRL_REG 0x0688 +#define S17_P3LEARN_LMT_REG 0x068c +#define S17_P4LOOKUP_CTRL_REG 0x0690 +#define S17_P4PRI_CTRL_REG 0x0694 +#define S17_P4LEARN_LMT_REG 0x0698 +#define S17_P5LOOKUP_CTRL_REG 0x069c +#define S17_P5PRI_CTRL_REG 0x06a0 +#define S17_P5LEARN_LMT_REG 0x06a4 +#define S17_P6LOOKUP_CTRL_REG 0x06a8 +#define S17_P6PRI_CTRL_REG 0x06ac +#define S17_P6LEARN_LMT_REG 0x06b0 +#define S17_GLO_TRUNK_CTRL0_REG 0x0700 +#define S17_GLO_TRUNK_CTRL1_REG 0x0704 +#define S17_GLO_TRUNK_CTRL2_REG 0x0708 + +/* Queue Management Registers */ +#define S17_PORT0_HOL_CTRL0 0x0970 +#define S17_PORT0_HOL_CTRL1 0x0974 +#define S17_PORT1_HOL_CTRL0 0x0978 +#define S17_PORT1_HOL_CTRL1 0x097c +#define S17_PORT2_HOL_CTRL0 0x0980 +#define S17_PORT2_HOL_CTRL1 0x0984 +#define S17_PORT3_HOL_CTRL0 0x0988 +#define S17_PORT3_HOL_CTRL1 0x098c +#define S17_PORT4_HOL_CTRL0 0x0990 +#define S17_PORT4_HOL_CTRL1 0x0994 +#define S17_PORT5_HOL_CTRL0 0x0998 +#define S17_PORT5_HOL_CTRL1 0x099c +#define S17_PORT6_HOL_CTRL0 0x09a0 +#define S17_PORT6_HOL_CTRL1 0x09a4 + +/* Port flow control registers */ +#define S17_P0_FLCTL_REG 0x09b0 +#define S17_P1_FLCTL_REG 0x09b4 +#define S17_P2_FLCTL_REG 0x09b8 +#define S17_P3_FLCTL_REG 0x09bc +#define S17_P4_FLCTL_REG 0x09c0 +#define S17_P5_FLCTL_REG 0x09c4 + +/* Packet Edit registers */ +#define S17_PKT_EDIT_CTRL 0x0c00 +#define S17_P0Q_REMAP_REG0 0x0c40 +#define S17_P0Q_REMAP_REG1 0x0c44 +#define S17_P1Q_REMAP_REG0 0x0c48 +#define S17_P2Q_REMAP_REG0 0x0c4c +#define S17_P3Q_REMAP_REG0 0x0c50 +#define S17_P4Q_REMAP_REG0 0x0c54 +#define S17_P5Q_REMAP_REG0 0x0c58 +#define S17_P5Q_REMAP_REG1 0x0c5c +#define S17_P6Q_REMAP_REG0 0x0c60 +#define S17_P6Q_REMAP_REG1 0x0c64 +#define S17_ROUTER_VID0 0x0c70 +#define S17_ROUTER_VID1 0x0c74 +#define S17_ROUTER_VID2 0x0c78 +#define S17_ROUTER_VID3 0x0c7c +#define S17_ROUTER_EG_VLAN_MODE 0x0c80 + +/* L3 Registers */ +#define S17_HROUTER_CTRL_REG 0x0e00 +#define S17_HROUTER_PBCTRL0_REG 0x0e04 +#define S17_HROUTER_PBCTRL1_REG 0x0e08 +#define S17_HROUTER_PBCTRL2_REG 0x0e0c +#define S17_WCMP_HASH_TABLE0_REG 0x0e10 +#define S17_WCMP_HASH_TABLE1_REG 0x0e14 +#define S17_WCMP_HASH_TABLE2_REG 0x0e18 +#define S17_WCMP_HASH_TABLE3_REG 0x0e1c +#define S17_WCMP_NHOP_TABLE0_REG 0x0e20 +#define S17_WCMP_NHOP_TABLE1_REG 0x0e24 +#define S17_WCMP_NHOP_TABLE2_REG 0x0e28 +#define S17_WCMP_NHOP_TABLE3_REG 0x0e2c +#define S17_ARP_ENTRY_CTRL_REG 0x0e30 +#define S17_ARP_USECNT_REG 0x0e34 +#define S17_HNAT_CTRL_REG 0x0e38 +#define S17_NAPT_ENTRY_CTRL0_REG 0x0e3c +#define S17_NAPT_ENTRY_CTRL1_REG 0x0e40 +#define S17_NAPT_USECNT_REG 0x0e44 +#define S17_ENTRY_EDIT_DATA0_REG 0x0e48 +#define S17_ENTRY_EDIT_DATA1_REG 0x0e4c +#define S17_ENTRY_EDIT_DATA2_REG 0x0e50 +#define S17_ENTRY_EDIT_DATA3_REG 0x0e54 +#define S17_ENTRY_EDIT_CTRL_REG 0x0e58 +#define S17_HNAT_PRIVATE_IP_REG 0x0e5c + +/* MIB counters */ +#define S17_MIB_PORT0 0x1000 +#define S17_MIB_PORT1 0x1100 +#define S17_MIB_PORT2 0x1200 +#define S17_MIB_PORT3 0x1300 +#define S17_MIB_PORT4 0x1400 +#define S17_MIB_PORT5 0x1500 +#define S17_MIB_PORT6 0x1600 + +#define S17_MIB_RXBROAD 0x0 +#define S17_MIB_RXPAUSE 0x4 +#define S17_MIB_RXMULTI 0x8 +#define S17_MIB_RXFCSERR 0xC +#define S17_MIB_RXALIGNERR 0x10 +#define S17_MIB_RXUNDERSIZE 0x14 +#define S17_MIB_RXFRAG 0x18 +#define S17_MIB_RX64B 0x1C +#define S17_MIB_RX128B 0x20 +#define S17_MIB_RX256B 0x24 +#define S17_MIB_RX512B 0x28 +#define S17_MIB_RX1024B 0x2C +#define S17_MIB_RX1518B 0x30 +#define S17_MIB_RXMAXB 0x34 +#define S17_MIB_RXTOOLONG 0x38 +#define S17_MIB_RXBYTE1 0x3C +#define S17_MIB_RXBYTE2 0x40 +#define S17_MIB_RXOVERFLOW 0x4C +#define S17_MIB_FILTERED 0x50 +#define S17_MIB_TXBROAD 0x54 +#define S17_MIB_TXPAUSE 0x58 +#define S17_MIB_TXMULTI 0x5C +#define S17_MIB_TXUNDERRUN 0x60 +#define S17_MIB_TX64B 0x64 +#define S17_MIB_TX128B 0x68 +#define S17_MIB_TX256B 0x6c +#define S17_MIB_TX512B 0x70 +#define S17_MIB_TX1024B 0x74 +#define S17_MIB_TX1518B 0x78 +#define S17_MIB_TXMAXB 0x7C +#define S17_MIB_TXOVERSIZE 0x80 +#define S17_MIB_TXBYTE1 0x84 +#define S17_MIB_TXBYTE2 0x88 +#define S17_MIB_TXCOL 0x8C +#define S17_MIB_TXABORTCOL 0x90 +#define S17_MIB_TXMULTICOL 0x94 +#define S17_MIB_TXSINGLECOL 0x98 +#define S17_MIB_TXEXCDEFER 0x9C +#define S17_MIB_TXDEFER 0xA0 +#define S17_MIB_TXLATECOL 0xA4 + +/* Register fields */ +#define S17_CHIPID_V1_0 0x1201 +#define S17_CHIPID_V1_1 0x1202 + +#define S17_MAC0_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC0_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC0_MAC_MII_EN (1 << 2) +#define S17_MAC0_MAC_GMII_RXCLK_SEL (1 << 4) +#define S17_MAC0_MAC_GMII_TXCLK_SEL (1 << 5) +#define S17_MAC0_MAC_GMII_EN (1 << 6) +#define S17_MAC0_SGMII_EN (1 << 7) +#define S17_MAC0_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC0_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC0_PHY_MII_EN (1 << 10) +#define S17_MAC0_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC0_PHY_GMII_RXCLK_SEL (1 << 12) +#define S17_MAC0_PHY_GMII_TXCLK_SEL (1 << 13) +#define S17_MAC0_PHY_GMII_EN (1 << 14) +#define S17_MAC0_RGMII_RXCLK_SHIFT 20 +#define S17_MAC0_RGMII_TXCLK_SHIFT 22 +#define S17_MAC0_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC0_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC0_RGMII_EN (1 << 26) + +#define S17_MAC5_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC5_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC5_MAC_MII_EN (1 << 2) +#define S17_MAC5_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC5_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC5_PHY_MII_EN (1 << 10) +#define S17_MAC5_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC5_RGMII_RXCLK_SHIFT 20 +#define S17_MAC5_RGMII_TXCLK_SHIFT 22 +#define S17_MAC5_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC5_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC5_RGMII_EN (1 << 26) + +#define S17_MAC6_MAC_MII_RXCLK_SEL (1 << 0) +#define S17_MAC6_MAC_MII_TXCLK_SEL (1 << 1) +#define S17_MAC6_MAC_MII_EN (1 << 2) +#define S17_MAC6_MAC_GMII_RXCLK_SEL (1 << 4) +#define S17_MAC6_MAC_GMII_TXCLK_SEL (1 << 5) +#define S17_MAC6_MAC_GMII_EN (1 << 6) +#define S17_MAC6_SGMII_EN (1 << 7) +#define S17_MAC6_PHY_MII_RXCLK_SEL (1 << 8) +#define S17_MAC6_PHY_MII_TXCLK_SEL (1 << 9) +#define S17_MAC6_PHY_MII_EN (1 << 10) +#define S17_MAC6_PHY_MII_PIPE_SEL (1 << 11) +#define S17_MAC6_PHY_GMII_RXCLK_SEL (1 << 12) +#define S17_MAC6_PHY_GMII_TXCLK_SEL (1 << 13) +#define S17_MAC6_PHY_GMII_EN (1 << 14) +#define S17_PHY4_GMII_EN (1 << 16) +#define S17_PHY4_RGMII_EN (1 << 17) +#define S17_PHY4_MII_EN (1 << 18) +#define S17_MAC6_RGMII_RXCLK_SHIFT 20 +#define S17_MAC6_RGMII_TXCLK_SHIFT 22 +#define S17_MAC6_RGMII_RXCLK_DELAY (1 << 24) +#define S17_MAC6_RGMII_TXCLK_DELAY (1 << 25) +#define S17_MAC6_RGMII_EN (1 << 26) + +#define S17_SPEED_10M (0 << 0) +#define S17_SPEED_100M (1 << 0) +#define S17_SPEED_1000M (2 << 0) +#define S17_TXMAC_EN (1 << 2) +#define S17_RXMAC_EN (1 << 3) +#define S17_TX_FLOW_EN (1 << 4) +#define S17_RX_FLOW_EN (1 << 5) +#define S17_DUPLEX_FULL (1 << 6) +#define S17_DUPLEX_HALF (0 << 6) +#define S17_TX_HALF_FLOW_EN (1 << 7) +#define S17_LINK_EN (1 << 9) +#define S17_FLOW_LINK_EN (1 << 12) +#define S17_PORT_STATUS_DEFAULT (S17_SPEED_1000M | S17_TXMAC_EN | \ + S17_RXMAC_EN | S17_TX_FLOW_EN | \ + S17_RX_FLOW_EN | S17_DUPLEX_FULL | \ + S17_TX_HALF_FLOW_EN) + +#define S17_PORT_STATUS_AZ_DEFAULT (S17_SPEED_1000M | S17_TXMAC_EN | \ + S17_RXMAC_EN | S17_TX_FLOW_EN | \ + S17_RX_FLOW_EN | S17_DUPLEX_FULL) + + +#define S17_HDRLENGTH_SEL (1 << 16) +#define S17_HDR_VALUE 0xAAAA + +#define S17_TXHDR_MODE_NO 0 +#define S17_TXHDR_MODE_MGM 1 +#define S17_TXHDR_MODE_ALL 2 +#define S17_RXHDR_MODE_NO (0 << 2) +#define S17_RXHDR_MODE_MGM (1 << 2) +#define S17_RXHDR_MODE_ALL (2 << 2) + +#define S17_CPU_PORT_EN (1 << 10) +#define S17_PPPOE_REDIR_EN (1 << 8) +#define S17_MIRROR_PORT_SHIFT 4 +#define S17_IGMP_COPY_EN (1 << 3) +#define S17_RIP_COPY_EN (1 << 2) +#define S17_EAPOL_REDIR_EN (1 << 0) + +#define S17_IGMP_JOIN_LEAVE_DP_SHIFT 24 +#define S17_BROAD_DP_SHIFT 16 +#define S17_MULTI_FLOOD_DP_SHIFT 8 +#define S17_UNI_FLOOD_DP_SHIFT 0 +#define S17_IGMP_JOIN_LEAVE_DPALL (0x7f << S17_IGMP_JOIN_LEAVE_DP_SHIFT) +#define S17_BROAD_DPALL (0x7f << S17_BROAD_DP_SHIFT) +#define S17_MULTI_FLOOD_DPALL (0x7f << S17_MULTI_FLOOD_DP_SHIFT) +#define S17_UNI_FLOOD_DPALL (0x7f << S17_UNI_FLOOD_DP_SHIFT) + +#define S17_PWS_CHIP_AR8327 (1 << 30) + +/* S17_PHY_CONTROL fields */ +#define S17_CTRL_SOFTWARE_RESET 0x8000 +#define S17_CTRL_SPEED_LSB 0x2000 +#define S17_CTRL_AUTONEGOTIATION_ENABLE 0x1000 +#define S17_CTRL_RESTART_AUTONEGOTIATION 0x0200 +#define S17_CTRL_SPEED_FULL_DUPLEX 0x0100 +#define S17_CTRL_SPEED_MSB 0x0040 + +/* For EEE_CTRL_REG */ +#define S17_LPI_DISABLE_P1 (1 << 4) +#define S17_LPI_DISABLE_P2 (1 << 6) +#define S17_LPI_DISABLE_P3 (1 << 8) +#define S17_LPI_DISABLE_P4 (1 << 10) +#define S17_LPI_DISABLE_P5 (1 << 12) +#define S17_LPI_DISABLE_ALL 0x1550 + +/* For MMD register control */ +#define S17_MMD_FUNC_ADDR (0 << 14) +#define S17_MMD_FUNC_DATA (1 << 14) +#define S17_MMD_FUNC_DATA_2 (2 << 14) +#define S17_MMD_FUNC_DATA_3 (3 << 14) + +/* For phyInfo_t azFeature */ +#define S17_8023AZ_PHY_ENABLED (1 << 0) +#define S17_8023AZ_PHY_LINKED (1 << 1) + +/* Queue Management registe fields */ +#define S17_HOL_CTRL0_LAN 0x2a008888 /* egress priority 8, eg_portq = 0x2a */ +#define S17_HOL_CTRL0_WAN 0x2a666666 /* egress priority 6, eg_portq = 0x2a */ +#define S17_HOL_CTRL1_DEFAULT 0xc6 /* enable HOL control */ + +/* Packet Edit register fields */ +#define S17_ROUTER_EG_UNMOD 0x0 /* unmodified */ +#define S17_ROUTER_EG_WOVLAN 0x1 /* without VLAN */ +#define S17_ROUTER_EG_WVLAN 0x2 /* with VLAN */ +#define S17_ROUTER_EG_UNTOUCH 0x3 /* untouched */ +#define S17_ROUTER_EG_MODE_DEFAULT 0x01111111 /* all ports without VLAN */ + +#define S17_RESET_DONE(phy_control) \ + (((phy_control) & (S17_CTRL_SOFTWARE_RESET)) == 0) + +/* Phy status fields */ +#define S17_STATUS_AUTO_NEG_DONE 0x0020 + +#define S17_AUTONEG_DONE(ip_phy_status) \ + (((ip_phy_status) & \ + (S17_STATUS_AUTO_NEG_DONE)) == \ + (S17_STATUS_AUTO_NEG_DONE)) + +/* Link Partner ability */ +#define S17_LINK_100BASETX_FULL_DUPLEX 0x0100 +#define S17_LINK_100BASETX 0x0080 +#define S17_LINK_10BASETX_FULL_DUPLEX 0x0040 +#define S17_LINK_10BASETX 0x0020 + +/* Advertisement register. */ +#define S17_ADVERTISE_NEXT_PAGE 0x8000 +#define S17_ADVERTISE_ASYM_PAUSE 0x0800 +#define S17_ADVERTISE_PAUSE 0x0400 +#define S17_ADVERTISE_100FULL 0x0100 +#define S17_ADVERTISE_100HALF 0x0080 +#define S17_ADVERTISE_10FULL 0x0040 +#define S17_ADVERTISE_10HALF 0x0020 + +#define S17_ADVERTISE_ALL (S17_ADVERTISE_ASYM_PAUSE | S17_ADVERTISE_PAUSE | \ + S17_ADVERTISE_10HALF | S17_ADVERTISE_10FULL | \ + S17_ADVERTISE_100HALF | S17_ADVERTISE_100FULL) + +/* 1000BASET_CONTROL */ +#define S17_ADVERTISE_1000FULL 0x0200 + +/* Phy Specific status fields */ +#define S17_STATUS_LINK_MASK 0xC000 +#define S17_STATUS_LINK_SHIFT 14 +#define S17_STATUS_FULL_DEPLEX 0x2000 +#define S17_STATUS_LINK_PASS 0x0400 +#define S17_STATUS_RESOLVED 0x0800 +#define S17_STATUS_LINK_10M 0 +#define S17_STATUS_LINK_100M 1 +#define S17_STATUS_LINK_1000M 2 + +#define S17_GLOBAL_INT_PHYMASK (1 << 15) + +#define S17_PHY_LINK_UP 0x400 +#define S17_PHY_LINK_DOWN 0x800 +#define S17_PHY_LINK_DUPLEX_CHANGE 0x2000 +#define S17_PHY_LINK_SPEED_CHANGE 0x4000 + +/* For Port flow control registers */ +#define S17_PORT_FLCTL_XON_DEFAULT (0x3a << 16) +#define S17_PORT_FLCTL_XOFF_DEFAULT (0x4a) + +/* Module enable Register */ +#define S17_MODULE_L3_EN (1 << 2) +#define S17_MODULE_ACL_EN (1 << 1) +#define S17_MODULE_MIB_EN (1 << 0) + +/* MIB Function Register 1 */ +#define S17_MIB_FUNC_ALL (3 << 24) +#define S17_MIB_CPU_KEEP (1 << 20) +#define S17_MIB_BUSY (1 << 17) +#define S17_MIB_AT_HALF_EN (1 << 16) +#define S17_MIB_TIMER_DEFAULT 0x100 + +#define S17_MAC_MAX 7 + + +#ifndef BOOL +#define BOOL int +#endif + +/*add feature define here*/ +//#define FULL_FEATURE + +#ifdef CONFIG_AR7242_S17_PHY +#undef HEADER_REG_CONF +#undef HEADER_EN +#endif + +void athrs17_reg_init(void); +int athrs17_phy_is_up(int unit); +int athrs17_phy_is_fdx(int unit); +int athrs17_phy_speed(int unit); +BOOL athrs17_phy_setup(int unit); + +#endif + + diff --git a/board/qca/mips32/common/qca-eth-956x.c b/board/qca/mips32/common/qca-eth-956x.c new file mode 100644 index 0000000000..95d6dd1281 --- /dev/null +++ b/board/qca/mips32/common/qca-eth-956x.c @@ -0,0 +1,1014 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_ATH_NAND_BR +#include +#endif + +#include +#include "qca-eth-956x.h" +#include "qca-eth-956x_phy.h" +#define SGMII_LINK_WAR_MAX_TRY 10 + +#define ath_gmac_unit2mac(_unit) ath_gmac_macs[(_unit)] +#define ath_gmac_name2mac(name) is_drqfn() ? ath_gmac_unit2mac(1):strcmp(name,"eth0") ? ath_gmac_unit2mac(1) : ath_gmac_unit2mac(0) + +int ath_gmac_miiphy_read(char *devname, uint32_t phaddr, uint8_t reg, uint16_t *data); +int ath_gmac_miiphy_write(char *devname, uint32_t phaddr, uint8_t reg, uint16_t data); +extern void ath_sys_frequency(uint32_t *, uint32_t *, uint32_t *); + +#ifndef CFG_ATH_GMAC_NMACS +#define CFG_ATH_GMAC_NMACS 1 +#endif /* CFG_ATH_GMAC_NMACS */ + +ath_gmac_mac_t *ath_gmac_macs[CFG_ATH_GMAC_NMACS]; + + +#ifdef CONFIG_VIR_PHY +extern int athr_vir_phy_setup(int unit); +extern int athr_vir_phy_is_up(int unit); +extern int athr_vir_phy_is_fdx(int unit); +extern int athr_vir_phy_speed(int unit); +extern void athr_vir_reg_init(void); +#endif + +#ifdef CONFIG_ATHRS17_PHY +extern void athrs17_reg_init(void); +extern void athrs17_reg_init_wan(void); +#endif + +#ifdef CFG_ATHRS27_PHY +extern void athrs27_reg_init(); +extern void athrs27_reg_init_lan(); +#endif + + +#ifdef CONFIG_ATH_NAND_BR + +#define ATH_ETH_MAC_READ_SIZE 4096 +extern unsigned long long +ath_nand_get_cal_offset(const char *ba); +#endif + +static int +ath_gmac_send(struct eth_device *dev, volatile void *packet, int length) +{ + int i; + + ath_gmac_mac_t *mac = (ath_gmac_mac_t *)dev->priv; + + ath_gmac_desc_t *f = mac->fifo_tx[mac->next_tx]; + + f->pkt_size = length; + f->res1 = 0; + f->pkt_start_addr = virt_to_phys(packet); + + ath_gmac_tx_give_to_dma(f); + flush_cache((u32) packet, length); + + ath_gmac_reg_wr(mac, ATH_DMA_TX_DESC, virt_to_phys(f)); + ath_gmac_reg_wr(mac, ATH_DMA_TX_CTRL, ATH_TXE); + + for (i = 0; i < MAX_WAIT; i++) { + udelay(10); + if (!ath_gmac_tx_owned_by_dma(f)) + break; + } + if (i == MAX_WAIT) + printf("Tx Timed out\n"); + + f->pkt_start_addr = 0; + f->pkt_size = 0; + + if (++mac->next_tx >= NO_OF_TX_FIFOS) + mac->next_tx = 0; + + return (0); +} + +static int ath_gmac_recv(struct eth_device *dev) +{ + int length; + ath_gmac_desc_t *f; + ath_gmac_mac_t *mac; + volatile int dmaed_pkt=0; + int count = 0; + + mac = (ath_gmac_mac_t *)dev->priv; + + for (;;) { + f = mac->fifo_rx[mac->next_rx]; + if (ath_gmac_rx_owned_by_dma(f)) { + /* check if the current Descriptor is_empty is 1,But the DMAed count is not-zero + then move to desciprot where the packet is available */ + dmaed_pkt = (ath_gmac_reg_rd(mac, 0x194) >> 16); + if (!dmaed_pkt) { + break ; + } else { + if (f->is_empty == 1) { + while ( count < NO_OF_RX_FIFOS ) { + if (++mac->next_rx >= NO_OF_RX_FIFOS) { + mac->next_rx = 0; + } + f = mac->fifo_rx[mac->next_rx]; + /* + * Break on valid data in the desc by checking + * empty bit. + */ + if (!f->is_empty){ + count = 0; + break; + } + count++; + } + } + } + } + + length = f->pkt_size; + + net_process_received_packet(net_rx_packets[mac->next_rx] , length - 4); + flush_cache((u32) net_rx_packets[mac->next_rx] , PKTSIZE_ALIGN); + + ath_gmac_reg_wr(mac,0x194,1); + ath_gmac_rx_give_to_dma(f); + + if (++mac->next_rx >= NO_OF_RX_FIFOS) + mac->next_rx = 0; + } + + if (!(ath_gmac_reg_rd(mac, ATH_DMA_RX_CTRL))) { + ath_gmac_reg_wr(mac, ATH_DMA_RX_DESC, virt_to_phys(f)); + ath_gmac_reg_wr(mac, ATH_DMA_RX_CTRL, 1); + } + + return (0); +} + +void ath_gmac_mii_setup(ath_gmac_mac_t *mac) +{ + u32 mgmt_cfg_val; + + + if (RST_BOOTSTRAP_REF_CLK_GET(ath_reg_rd(RST_BOOTSTRAP_ADDRESS))) { + //40Mhz + ath_reg_wr(SWITCH_CLOCK_SPARE_ADDRESS, 0x45500); + } else { + //25Mhz + ath_reg_wr(SWITCH_CLOCK_SPARE_ADDRESS, 0xc5200); + } + + if (is_s27() && (mac->mac_unit == 0)) { + printf("Dragonfly----> S27 PHY *\n"); + + ath_reg_wr(ETH_XMII_ADDRESS, ETH_XMII_TX_INVERT_SET(1) | + ETH_XMII_RX_DELAY_SET(2) | + ETH_XMII_TX_DELAY_SET(1) | + ETH_XMII_GIGE_SET(1)); + + mgmt_cfg_val = 7; + udelay(1000); + ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31)); + udelay(1000); + ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val); + + //GMAC1 need to set for MDC/MDIO Works + udelay(1000); + ath_gmac_reg_wr(ath_gmac_macs[1], ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31)); + udelay(1000); + ath_gmac_reg_wr(ath_gmac_macs[1], ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val); + + return; + } + + if ( CFG_ATH_GMAC_NMACS == 1){ + printf("Dragonfly ----> S17 PHY *\n"); + mgmt_cfg_val = 7; + + ath_reg_wr(ATH_ETH_CFG, ETH_CFG_ETH_RXDV_DELAY_SET(3) | + ETH_CFG_ETH_RXD_DELAY_SET(3)| + ETH_CFG_RGMII_GE0_SET(1) | + ETH_CFG_GE0_SGMII_SET(1) ); + + ath_reg_wr(ETH_XMII_ADDRESS, ETH_XMII_TX_INVERT_SET(1) | + ETH_XMII_RX_DELAY_SET(2) | + ETH_XMII_TX_DELAY_SET(1) | + ETH_XMII_GIGE_SET(1)); + + udelay(1000); + ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val | (1 << 31)); + ath_gmac_reg_wr(mac, ATH_MAC_MII_MGMT_CFG, mgmt_cfg_val); + return; + } + +} + +void +athrs_sgmii_res_cal(void) +{ + unsigned int read_data; + unsigned int reversed_sgmii_value; + unsigned int i=0; + unsigned int vco_fast,vco_slow; + unsigned int startValue=0, endValue=0; + + ath_reg_wr(ETH_SGMII_SERDES_ADDRESS, + ETH_SGMII_SERDES_EN_LOCK_DETECT_MASK | + ETH_SGMII_SERDES_EN_PLL_MASK); + + read_data = ath_reg_rd(SGMII_SERDES_ADDRESS); + + vco_fast = SGMII_SERDES_VCO_FAST_GET(read_data); + vco_slow = SGMII_SERDES_VCO_SLOW_GET(read_data); + /* set resistor Calibration from 0000 -> 1111 */ + for (i=0; i < 0x10; i++) + { + read_data = (ath_reg_rd(SGMII_SERDES_ADDRESS) & + ~SGMII_SERDES_RES_CALIBRATION_MASK) | + SGMII_SERDES_RES_CALIBRATION_SET(i); + ath_reg_wr(SGMII_SERDES_ADDRESS, read_data); + + udelay(50); + + read_data = ath_reg_rd(SGMII_SERDES_ADDRESS); + if ((vco_fast != SGMII_SERDES_VCO_FAST_GET(read_data)) || + (vco_slow != SGMII_SERDES_VCO_SLOW_GET(read_data)) ){ + if (startValue == 0){ + startValue=endValue=i; + }else{ + endValue=i; + } + } + vco_fast = SGMII_SERDES_VCO_FAST_GET(read_data); + vco_slow = SGMII_SERDES_VCO_SLOW_GET(read_data); + } + + if (startValue == 0){ + /* No boundary found, use middle value for resistor calibration value */ + reversed_sgmii_value = 0x7; + }else{ + /* get resistor calibration from the middle of boundary */ + reversed_sgmii_value = (startValue + endValue)/2; + } + + read_data = (ath_reg_rd(SGMII_SERDES_ADDRESS) & + ~SGMII_SERDES_RES_CALIBRATION_MASK) | + SGMII_SERDES_RES_CALIBRATION_SET(reversed_sgmii_value); + + ath_reg_wr(SGMII_SERDES_ADDRESS, read_data); + + ath_reg_wr(ETH_SGMII_SERDES_ADDRESS, + ETH_SGMII_SERDES_EN_LOCK_DETECT_MASK | + /*ETH_SGMII_SERDES_PLL_REFCLK_SEL_MASK |*/ + ETH_SGMII_SERDES_EN_PLL_MASK); + + ath_reg_rmw_set(SGMII_SERDES_ADDRESS, + SGMII_SERDES_CDR_BW_SET(3) | + SGMII_SERDES_TX_DR_CTRL_SET(1) | + SGMII_SERDES_PLL_BW_SET(1) | + SGMII_SERDES_EN_SIGNAL_DETECT_SET(1) | + SGMII_SERDES_FIBER_SDO_SET(1) | + SGMII_SERDES_VCO_REG_SET(3)); + + ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_MASK); + udelay(25); + ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_RESET_MASK); + + while (!(ath_reg_rd(SGMII_SERDES_ADDRESS) & SGMII_SERDES_LOCK_DETECT_STATUS_MASK)); +} + + +static void athr_gmac_sgmii_setup() +{ + int status = 0, count = 0; + +#ifdef ATH_SGMII_FORCED_MODE + ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_SPEED_SEL1_SET(1) | + MR_AN_CONTROL_PHY_RESET_SET(1) | + MR_AN_CONTROL_DUPLEX_MODE_SET(1)); + udelay(10); + + ath_reg_wr(SGMII_CONFIG_ADDRESS, SGMII_CONFIG_MODE_CTRL_SET(2) | + SGMII_CONFIG_FORCE_SPEED_SET(1) | + SGMII_CONFIG_SPEED_SET(2)); + + printf ("SGMII in forced mode\n"); +#else + + ath_reg_wr(SGMII_CONFIG_ADDRESS, SGMII_CONFIG_MODE_CTRL_SET(2)); + + ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_AN_ENABLE_SET(1) + |MR_AN_CONTROL_PHY_RESET_SET(1)); + + ath_reg_wr(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_AN_ENABLE_SET(1)); +#endif +/* + * SGMII reset sequence suggested by systems team. + */ + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_RX_CLK_N_RESET); + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1)); + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1) + |SGMII_RESET_RX_125M_N_SET(1)); + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1) + |SGMII_RESET_TX_125M_N_SET(1) + |SGMII_RESET_RX_125M_N_SET(1)); + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1) + |SGMII_RESET_TX_125M_N_SET(1) + |SGMII_RESET_RX_125M_N_SET(1) + |SGMII_RESET_RX_CLK_N_SET(1)); + + ath_reg_wr(SGMII_RESET_ADDRESS, SGMII_RESET_HW_RX_125M_N_SET(1) + |SGMII_RESET_TX_125M_N_SET(1) + |SGMII_RESET_RX_125M_N_SET(1) + |SGMII_RESET_RX_CLK_N_SET(1) + |SGMII_RESET_TX_CLK_N_SET(1)); + + ath_reg_rmw_clear(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1)); + /* + * WAR::Across resets SGMII link status goes to weird + * state. + * if 0xb8070058 (SGMII_DEBUG register) reads other then 0x1f or 0x10 + * for sure we are in bad state. + * Issue a PHY reset in MR_AN_CONTROL_ADDRESS to keep going. + */ + status = (ath_reg_rd(SGMII_DEBUG_ADDRESS) & 0xff); + while (!(status == 0xf || status == 0x10)) { + + ath_reg_rmw_set(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1)); + udelay(100); + ath_reg_rmw_clear(MR_AN_CONTROL_ADDRESS, MR_AN_CONTROL_PHY_RESET_SET(1)); + if (count++ == SGMII_LINK_WAR_MAX_TRY) { + printf ("Max resets limit reached exiting...\n"); + break; + } + status = (ath_reg_rd(SGMII_DEBUG_ADDRESS) & 0xff); + } + + printf("%s SGMII done\n",__func__); + +} + +static void ath_gmac_hw_start(ath_gmac_mac_t *mac) +{ + + +#ifndef ATH_RGMII_CAL /* Moved after mii_setup since these registers are touched in RGMII cal code */ + if(mac->mac_unit) + { + ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN | + ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_1000)); + } else { + + + ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN | + ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_10_100)); + } + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00); +#endif + + +#ifdef ATH_RGMII_CAL + if(mac->mac_unit) + { + ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN | + ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_1000)); + } else { + + + ath_gmac_reg_rmw_set(mac, ATH_MAC_CFG2, (ATH_MAC_CFG2_PAD_CRC_EN | + ATH_MAC_CFG2_LEN_CHECK | ATH_MAC_CFG2_IF_10_100)); + } + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00); +#endif + + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_1, 0x10ffff); + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_2, 0xAAA0555); + + ath_gmac_reg_rmw_set(mac, ATH_MAC_FIFO_CFG_4, 0x3ffff); + /* + * Setting Drop CRC Errors, Pause Frames,Length Error frames + * and Multi/Broad cast frames. + */ + + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_5, 0x7eccf); + + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_3, 0x1f00140); + + printf(": cfg1 %#x cfg2 %#x\n", ath_gmac_reg_rd(mac, ATH_MAC_CFG1), + ath_gmac_reg_rd(mac, ATH_MAC_CFG2)); + + +} + +static int ath_gmac_check_link(ath_gmac_mac_t *mac) +{ + int link, duplex, speed; + + ath_gmac_phy_link(mac->mac_unit, &link); + ath_gmac_phy_duplex(mac->mac_unit, &duplex); + ath_gmac_phy_speed(mac->mac_unit, &speed); + + mac->link = link; + + if(!mac->link) { + printf("%s link down\n",mac->dev->name); + return 0; + } + + switch (speed) + { + case _1000BASET: + ath_gmac_set_mac_if(mac, 1); + ath_gmac_reg_rmw_set(mac, ATH_MAC_FIFO_CFG_5, (1 << 19)); + + if (is_ar8033() && mac->mac_unit == 1) { + ath_reg_wr(ETH_SGMII_ADDRESS, ETH_SGMII_GIGE_SET(1) | + ETH_SGMII_CLK_SEL_SET(1)); + } + + break; + + case _100BASET: + ath_gmac_set_mac_if(mac, 0); + ath_gmac_set_mac_speed(mac, 1); + ath_gmac_reg_rmw_clear(mac, ATH_MAC_FIFO_CFG_5, (1 << 19)); + + if (is_ar8033() && mac->mac_unit == 1) { + ath_reg_wr(ETH_SGMII_ADDRESS, ETH_SGMII_PHASE0_COUNT_SET(1) | + ETH_SGMII_PHASE1_COUNT_SET(1)); + } + + break; + + case _10BASET: + ath_gmac_set_mac_if(mac, 0); + ath_gmac_set_mac_speed(mac, 0); + ath_gmac_reg_rmw_clear(mac, ATH_MAC_FIFO_CFG_5, (1 << 19)); + + + break; + + default: + printf("Invalid speed detected\n"); + return 0; + } + + if (mac->link && (duplex == mac->duplex) && (speed == mac->speed)) + return 1; + + mac->duplex = duplex; + mac->speed = speed; + + printf("dup %d speed %d\n", duplex, speed); + + ath_gmac_set_mac_duplex(mac,duplex); + + return 1; +} + +/* + * For every command we re-setup the ring and start with clean h/w rx state + */ +static int ath_gmac_clean_rx(struct eth_device *dev, bd_t * bd) +{ + + int i; + ath_gmac_desc_t *fr; + ath_gmac_mac_t *mac = (ath_gmac_mac_t*)dev->priv; + + if (!ath_gmac_check_link(mac)) + return 0; + + mac->next_rx = 0; + + ath_gmac_reg_wr(mac, ATH_MAC_FIFO_CFG_0, 0x1f00); + ath_gmac_reg_wr(mac, ATH_MAC_CFG1, (ATH_MAC_CFG1_RX_EN | ATH_MAC_CFG1_TX_EN)); + + for (i = 0; i < NO_OF_RX_FIFOS; i++) { + fr = mac->fifo_rx[i]; + fr->pkt_start_addr = virt_to_phys(net_rx_packets[i]); + flush_cache((u32) net_rx_packets[i], PKTSIZE_ALIGN); + ath_gmac_rx_give_to_dma(fr); + } + ath_gmac_reg_wr(mac, ATH_DMA_RX_DESC, virt_to_phys(mac->fifo_rx[0])); + ath_gmac_reg_wr(mac, ATH_DMA_RX_CTRL, ATH_RXE); /* rx start */ + udelay(1000 * 1000); + + return 1; + +} + +static int ath_gmac_alloc_fifo(int ndesc, ath_gmac_desc_t ** fifo) +{ + int i; + u32 size; + uchar *p = NULL; + + size = sizeof(ath_gmac_desc_t) * ndesc; + size += CONFIG_SYS_CACHELINE_SIZE - 1; + + if ((p = malloc(size)) == NULL) { + printf("Cant allocate fifos\n"); + return -1; + } + + /* Desc gets overwritten maliciously, this is temp WAR */ + p = p+ 4096; + p = (uchar *) (((u32) p + CONFIG_SYS_CACHELINE_SIZE - 1) & + ~(CONFIG_SYS_CACHELINE_SIZE - 1)); + p = UNCACHED_SDRAM(p); + + for (i = 0; i < ndesc; i++) + { + fifo[i] = (ath_gmac_desc_t *) p + i; + memset(fifo[i], 0, sizeof (ath_gmac_desc_t)); + } + + return 0; +} + +static int ath_gmac_setup_fifos(ath_gmac_mac_t *mac) +{ + int i; + + if (ath_gmac_alloc_fifo(NO_OF_TX_FIFOS, mac->fifo_tx)) + return 1; + + for (i = 0; i < NO_OF_TX_FIFOS; i++) { + mac->fifo_tx[i]->next_desc = (i == NO_OF_TX_FIFOS - 1) ? + virt_to_phys(mac->fifo_tx[0]) : virt_to_phys(mac->fifo_tx[i + 1]); + ath_gmac_tx_own(mac->fifo_tx[i]); + } + if (ath_gmac_alloc_fifo(NO_OF_RX_FIFOS, mac->fifo_rx)) + return 1; + + for (i = 0; i < NO_OF_RX_FIFOS; i++) { + mac->fifo_rx[i]->next_desc = (i == NO_OF_RX_FIFOS - 1) ? + virt_to_phys(mac->fifo_rx[0]) : virt_to_phys(mac->fifo_rx[i + 1]); + } + return (1); +} + +static void ath_gmac_halt(struct eth_device *dev) +{ + ath_gmac_mac_t *mac = (ath_gmac_mac_t *)dev->priv; + ath_gmac_reg_rmw_clear(mac, ATH_MAC_CFG1,(ATH_MAC_CFG1_RX_EN | ATH_MAC_CFG1_TX_EN)); + ath_gmac_reg_wr(mac,ATH_MAC_FIFO_CFG_0,0x1f1f); + ath_gmac_reg_wr(mac,ATH_DMA_RX_CTRL, 0); + while (ath_gmac_reg_rd(mac, ATH_DMA_RX_CTRL)); +} + +#ifdef CONFIG_ATH_NAND_BR + +unsigned char * +ath_eth_mac_addr(unsigned char *sectorBuff) +{ + ulong off, size; + nand_info_t *nand; + unsigned char ret; + + /* + * caldata partition is of 128k + */ + nand = &nand_info[nand_curr_device]; + size = ATH_ETH_MAC_READ_SIZE; /* To read 4k setting size as 4k */ + + /* + * Get the Offset of Caldata partition + */ + off = ath_nand_get_cal_offset(getenv("bootargs")); + if(off == ATH_CAL_OFF_INVAL) { + printf("Invalid CAL offset \n"); + return NULL; + } + /* + * Get the values from flash, and program into the MAC address + * registers + */ + ret = nand_read(nand, (loff_t)off, &size, (u_char *)sectorBuff); + printf(" %d bytes %s: %s\n", size, + "read", ret ? "ERROR" : "OK"); + if(ret != 0 ) { + return NULL; + } + + return sectorBuff; +} + +#else /* CONFIG_ATH_NAND_BR */ + +unsigned char * +ath_gmac_mac_addr_loc(void) +{ + extern flash_info_t flash_info[]; + +#ifdef BOARDCAL + /* + ** BOARDCAL environmental variable has the address of the cal sector + */ + + return ((unsigned char *)BOARDCAL); + +#else + /* MAC address is store in the 2nd 4k of last sector */ + return ((unsigned char *) + (KSEG1ADDR(ATH_SPI_BASE) + (4 * 1024) + + flash_info[0].size - (64 * 1024) /* sector_size */ )); +#endif +} + +#endif /* CONFIG_ATH_NAND_BR */ + +static void ath_gmac_get_ethaddr(struct eth_device *dev) +{ + unsigned char *eeprom; + unsigned char *mac = dev->enetaddr; +#ifndef CONFIG_ATH_EMULATION + +#ifdef CONFIG_ATH_NAND_BR + unsigned char sectorBuff[ATH_ETH_MAC_READ_SIZE]; + + eeprom = ath_eth_mac_addr(sectorBuff); + if(eeprom == NULL) { + /* mac address will be set to default mac address */ + mac[0] = 0xff; + } + else { +#else /* CONFIG_ATH_NAND_BR */ + eeprom = ath_gmac_mac_addr_loc(); +#endif /* CONFIG_ATH_NAND_BR */ + + if (strcmp(dev->name, "eth0") == 0) { + memcpy(mac, eeprom, 6); + } else if (strcmp(dev->name, "eth1") == 0) { + eeprom += 6; + memcpy(mac, eeprom, 6); + } else { + printf("%s: unknown ethernet device %s\n", __func__, dev->name); + return; + } +#ifdef CONFIG_ATH_NAND_BR + } +#endif /* CONFIG_ATH_NAND_BR */ + /* Use fixed address if the above address is invalid */ + if (mac[0] != 0x00 || (mac[0] == 0xff && mac[5] == 0xff)) +#else + if (1) +#endif + { + mac[0] = 0x00; + mac[1] = 0x03; + mac[2] = 0x7f; + mac[3] = 0x09; + mac[4] = 0x0b; + mac[5] = 0xad; + printf("No valid address in Flash. Using fixed address\n"); + } else { + printf("Fetching MAC Address from 0x%p\n", __func__, eeprom); + } +} + +void +athr_mgmt_init(void) +{ +#if defined (CONFIG_ATHRS17_PHY) +uint32_t rddata; + +// init MDI/ MDO/ MDC +if (CFG_ATH_GMAC_NMACS == 1){ +/* + * GPIO 4 as MDI + */ +rddata = ath_reg_rd(GPIO_IN_ENABLE3_ADDRESS)& + ~GPIO_IN_ENABLE3_MII_GE1_MDI_MASK; +rddata |= GPIO_IN_ENABLE3_MII_GE1_MDI_SET(4); +ath_reg_wr(GPIO_IN_ENABLE3_ADDRESS, rddata); + +/* + * GPIO 4 as MDO + */ +rddata = ath_reg_rd(GPIO_OUT_FUNCTION1_ADDRESS) & + ~ (GPIO_OUT_FUNCTION1_ENABLE_GPIO_4_MASK); +rddata |= (GPIO_OUT_FUNCTION1_ENABLE_GPIO_4_SET(0x20)); +ath_reg_wr(GPIO_OUT_FUNCTION1_ADDRESS, rddata); + +/* + * GPIO 4 as MDO + */ +rddata = ath_reg_rd(GPIO_OE_ADDRESS); +rddata &= ~(1<<4); +ath_reg_wr(GPIO_OE_ADDRESS, rddata); + +/* + * GPIO 3 as MDC + */ +rddata = ath_reg_rd(GPIO_OE_ADDRESS); +rddata &= ~(1<<3); +ath_reg_wr(GPIO_OE_ADDRESS, rddata); + +rddata = ath_reg_rd(GPIO_OUT_FUNCTION0_ADDRESS) & + ~ (GPIO_OUT_FUNCTION0_ENABLE_GPIO_3_MASK); +rddata |= GPIO_OUT_FUNCTION0_ENABLE_GPIO_3_SET(0x21); +ath_reg_wr(GPIO_OUT_FUNCTION0_ADDRESS, rddata); + +} +#endif /* CONFIG_ATHRS17_PHY */ + + printf ("%s ::done\n",__func__); +} + + +int ath_gmac_enet_initialize(bd_t * bis) +{ + struct eth_device *dev[CFG_ATH_GMAC_NMACS]; + u32 mask, mac_h, mac_l; + int i; + u32 val; + + printf("%s...\n", __func__); + + if ( CFG_ATH_GMAC_NMACS == 1){ + athrs_sgmii_res_cal(); + } + + for (i = 0;i < CFG_ATH_GMAC_NMACS;i++) { + + if ((dev[i] = (struct eth_device *) malloc(sizeof (struct eth_device))) == NULL) { + puts("malloc failed\n"); + return 0; + } + + if ((ath_gmac_macs[i] = (ath_gmac_mac_t *) malloc(sizeof (ath_gmac_mac_t))) == NULL) { + puts("malloc failed\n"); + return 0; + } + + memset(ath_gmac_macs[i], 0, sizeof (ath_gmac_mac_t)); + memset(dev[i], 0, sizeof (struct eth_device)); + + sprintf(dev[i]->name, "eth%d", i); + ath_gmac_get_ethaddr(dev[i]); + + ath_gmac_macs[i]->mac_unit = i; + ath_gmac_macs[i]->mac_base = i ? ATH_GE1_BASE : ATH_GE0_BASE ; + ath_gmac_macs[i]->dev = dev[i]; + + dev[i]->iobase = 0; + dev[i]->init = ath_gmac_clean_rx; + dev[i]->halt = ath_gmac_halt; + dev[i]->send = ath_gmac_send; + dev[i]->recv = ath_gmac_recv; + dev[i]->priv = (void *)ath_gmac_macs[i]; + } + +#if !defined(CONFIG_ATH_NAND_BR) + ath_reg_rmw_set(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_SET(1)); + udelay(1000 * 100); + ath_reg_rmw_clear(RST_RESET_ADDRESS, RST_RESET_ETH_SGMII_ARESET_SET(1)); + udelay(100); +#endif + if ( CFG_ATH_GMAC_NMACS == 1){ + mask = RST_RESET_ETH_SGMII_RESET_SET(1) | RST_RESET_ETH_SGMII_ARESET_SET(1) | RST_RESET_EXTERNAL_RESET_SET(1) | + RST_RESET_ETH_SWITCH_ANALOG_RESET_SET(1) | RST_RESET_ETH_SWITCH_RESET_SET(1); + }else{ + mask = RST_RESET_ETH_SGMII_RESET_SET(1) | RST_RESET_EXTERNAL_RESET_SET(1) | + RST_RESET_ETH_SWITCH_ANALOG_RESET_SET(1) | RST_RESET_ETH_SWITCH_RESET_SET(1); + } + ath_reg_rmw_set(RST_RESET_ADDRESS, mask); + udelay(1000 * 100); + if ( CFG_ATH_GMAC_NMACS == 1){ + mask = RST_RESET_ETH_SGMII_RESET_SET(1) | RST_RESET_ETH_SGMII_ARESET_SET(1) | RST_RESET_EXTERNAL_RESET_SET(1); + } + + ath_reg_rmw_clear(RST_RESET_ADDRESS, mask); + udelay(1000 * 100); + +#if defined(CONFIG_ATHRS17_PHY) + if ( CFG_ATH_GMAC_NMACS == 1) { + // S17 SWITCH RESET + val = ath_reg_rd(GPIO_OE_ADDRESS) & ~(1 << 11); + ath_reg_wr(GPIO_OE_ADDRESS, val); + udelay(1000 * 100); + ath_reg_rmw_set(GPIO_OUT_ADDRESS, ( 1 << 11)); + udelay(1000 * 100); + ath_reg_rmw_clear(GPIO_OUT_ADDRESS, ( 1 << 11)); + udelay(1000 * 100); + ath_reg_rmw_set(GPIO_OUT_ADDRESS, ( 1 << 11)); + } +#endif + for (i = 0;i < CFG_ATH_GMAC_NMACS;i++) { + + ath_gmac_reg_rmw_set(ath_gmac_macs[i], ATH_MAC_CFG1, ATH_MAC_CFG1_SOFT_RST + | ATH_MAC_CFG1_RX_RST | ATH_MAC_CFG1_TX_RST); + + if(!i) { + mask = (ATH_RESET_GE0_MAC | ATH_RESET_GE1_MAC); + + mask = mask | ATH_RESET_GE0_MDIO | ATH_RESET_GE1_MDIO; + + printf("%s: reset mask:%x \n", __func__, mask); + + ath_reg_rmw_set(RST_RESET_ADDRESS, mask); + udelay(1000 * 100); + + ath_reg_rmw_clear(RST_RESET_ADDRESS, mask); + udelay(1000 * 100); + + udelay(10 * 1000); + } +#if defined(CONFIG_MGMT_INIT) && defined (CONFIG_ATHR_SWITCH_ONLY_MODE) || defined ATH_MDC_GPIO + if (!i) + athr_mgmt_init(); + + if (ath_gmac_macs[i]->mac_unit == 0) + continue; +#endif + if (CFG_ATH_GMAC_NMACS == 1){ + athr_mgmt_init(); + } + eth_register(dev[i]); +#if(CONFIG_COMMANDS & CFG_CMD_MII) + miiphy_register(dev[i]->name, ath_gmac_miiphy_read, ath_gmac_miiphy_write); +#endif + ath_gmac_mii_setup(ath_gmac_macs[i]); + + /* if using header for register configuration, we have to */ + /* configure s26 register after frame transmission is enabled */ + + if (ath_gmac_macs[i]->mac_unit == 0) { /* WAN Phy */ +#ifdef CONFIG_ATHRS17_PHY + athrs17_reg_init(); +#endif + +#ifdef CFG_ATHRS26_PHY + athrs26_reg_init(); +#endif + +#ifdef CFG_ATHRS27_PHY + athrs27_reg_init(); +#endif + + + } else { + +#if defined(CONFIG_MGMT_INIT) && defined (CONFIG_ATHR_SWITCH_ONLY_MODE) + athrs17_reg_init(); +#elif defined (CONFIG_ATHRS17_PHY) && !defined(CFG_DUAL_PHY_SUPPORT) + athrs17_reg_init_wan(); +#endif + +#ifdef CFG_ATHRS27_PHY + athrs27_reg_init_lan(); +#endif + + } +#ifdef CONFIG_ATHRS_GMAC_SGMII + /* + * MAC unit 1 or drqfn package call sgmii setup. + */ + if (i == 0 && CFG_ATH_GMAC_NMACS == 1) + athr_gmac_sgmii_setup(); +#endif + ath_gmac_hw_start(ath_gmac_macs[i]); + ath_gmac_setup_fifos(ath_gmac_macs[i]); + + + + udelay(100 * 1000); + + { + unsigned char *mac = dev[i]->enetaddr; + + printf("%s: %02x:%02x:%02x:%02x:%02x:%02x\n", dev[i]->name, + mac[0] & 0xff, mac[1] & 0xff, mac[2] & 0xff, + mac[3] & 0xff, mac[4] & 0xff, mac[5] & 0xff); + } + mac_l = (dev[i]->enetaddr[4] << 8) | (dev[i]->enetaddr[5]); + mac_h = (dev[i]->enetaddr[0] << 24) | (dev[i]->enetaddr[1] << 16) | + (dev[i]->enetaddr[2] << 8) | (dev[i]->enetaddr[3] << 0); + + ath_gmac_reg_wr(ath_gmac_macs[i], ATH_GE_MAC_ADDR1, mac_l); + ath_gmac_reg_wr(ath_gmac_macs[i], ATH_GE_MAC_ADDR2, mac_h); + + + ath_gmac_phy_setup(ath_gmac_macs[i]->mac_unit); + printf("%s up\n",dev[i]->name); + } + + + return 1; +} + +#if (CONFIG_COMMANDS & CFG_CMD_MII) +int +ath_gmac_miiphy_read(char *devname, uint32_t phy_addr, uint8_t reg, uint16_t *data) +{ + ath_gmac_mac_t *mac = ath_gmac_name2mac(devname); + uint16_t addr = (phy_addr << ATH_ADDR_SHIFT) | reg, val; + volatile int rddata; + uint16_t ii = 0xFFFF; + + + + + /* + * Check for previous transactions are complete. Added to avoid + * race condition while running at higher frequencies. + */ + do + { + udelay(5); + rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1; + }while(rddata && --ii); + + if (ii == 0) + printf("ERROR:%s:%d transaction failed\n",__func__,__LINE__); + + + ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, 0x0); + ath_gmac_reg_wr(mac, ATH_MII_MGMT_ADDRESS, addr); + ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, ATH_MGMT_CMD_READ); + + do + { + udelay(5); + rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1; + }while(rddata && --ii); + + if(ii==0) + printf("Error!!! Leave ath_gmac_miiphy_read without polling correct status!\n"); + + val = ath_gmac_reg_rd(mac, ATH_MII_MGMT_STATUS); + ath_gmac_reg_wr(mac, ATH_MII_MGMT_CMD, 0x0); + + if (data != NULL) + *data = val; + return val; +} + +int +ath_gmac_miiphy_write(char *devname, uint32_t phy_addr, uint8_t reg, uint16_t data) +{ + ath_gmac_mac_t *mac = ath_gmac_name2mac(devname); + uint16_t addr = (phy_addr << ATH_ADDR_SHIFT) | reg; + volatile int rddata; + uint16_t ii = 0xFFFF; + + + /* + * Check for previous transactions are complete. Added to avoid + * race condition while running at higher frequencies. + */ + do { + udelay(5); + rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1; + } while (rddata && --ii); + + if (ii == 0) + printf("ERROR:%s:%d transaction failed\n",__func__,__LINE__); + + ath_gmac_reg_wr(mac, ATH_MII_MGMT_ADDRESS, addr); + ath_gmac_reg_wr(mac, ATH_MII_MGMT_CTRL, data); + + do { + rddata = ath_gmac_reg_rd(mac, ATH_MII_MGMT_IND) & 0x1; + } while (rddata && --ii); + + if (ii == 0) + printf("Error!!! Leave ath_gmac_miiphy_write without polling correct status!\n"); + return 0; +} +#endif /* CONFIG_COMMANDS & CFG_CMD_MII */ + +int cpu_eth_init(bd_t *bis) +{ + ath_gmac_enet_initialize(bis); + return 0; +} + diff --git a/board/qca/mips32/common/qca-eth-956x.h b/board/qca/mips32/common/qca-eth-956x.h new file mode 100644 index 0000000000..e294f1fbdb --- /dev/null +++ b/board/qca/mips32/common/qca-eth-956x.h @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _AGxxxx_H +#define _AGxxxx_H + +#include + +#ifndef CONFIG_MACH_QCA956x +#ifdef ATH_RGMII_CAL +#define rgmii_cal_alg() rgmii_calib(mac); +#else +#define rgmii_cal_alg() +#endif +#endif + +/* + * h/w descriptor + */ +typedef struct { + uint32_t pkt_start_addr, + is_empty : 1, + res1 : 10, + ftpp_override : 5, + res2 : 4, + pkt_size : 12, + next_desc; +} ath_gmac_desc_t; + +#define NO_OF_TX_FIFOS 8 +#define NO_OF_RX_FIFOS 8 + +typedef struct { + ath_gmac_desc_t *fifo_tx[NO_OF_TX_FIFOS], + *fifo_rx[NO_OF_RX_FIFOS]; + struct eth_device *dev; + uint32_t next_tx, + next_rx, + link, + duplex, + speed, + mac_unit, + mac_base; +} ath_gmac_mac_t; + +#define ath_gmac_reg_wr(_mac, _x, _y) ath_reg_wr(((_x) + _mac->mac_base), (_y)) +#define ath_gmac_reg_rd(_mac, _x) ath_reg_rd(((_x) + _mac->mac_base)) + +#define ath_gmac_reg_rmw_set(_mac, _x, _y) \ + ath_reg_rmw_set(((_x) + _mac->mac_base ), (_y)) +#define ath_gmac_reg_rmw_clear(_mac, _x, _y) \ + ath_reg_rmw_clear(((_x) + _mac->mac_base), (_y)) + +#ifdef COMPRESSED_UBOOT +#define _1000BASET 1000 +#define _100BASET 100 +#define _10BASET 10 +#endif /* #ifdef COMPRESSED_UBOOT */ + +/* + * spd is _1000BASET, _100BASET etc. defined in include/miiphy.h + */ +#define mii_reg(_mac) (ATH_MII0_CTRL + ((_mac)->mac_unit * 4)) +#define mii_if(_mac) (((_mac)->mac_unit == 0) ? mii0_if : mii1_if) + +#define ath_gmac_set_mii_ctrl_speed(_mac, _spd) do { \ + ath_reg_rmw_clear(mii_reg(_mac), (3 << 4)); \ + ath_reg_rmw_set(mii_reg(_mac), ((_spd) << 4)); \ +} while (0) + +#if defined (CFG_MII0_GMII) +# define ath_gmac_get_mii_if() 0 +#elif defined (CFG_MII0_MII) +# define ath_gmac_get_mii_if() 0 +#elif defined (CFG_MII0_RGMII) +# define ath_gmac_get_mii_if() 0 +#elif defined (CFG_MII0_RMII) +# define ath_gmac_get_mii_if() 0 +#endif + +#define MAX_WAIT 1000 + +/* + * Config/Mac Register definitions + */ +#define ATH_MAC_CFG1 0x00 +#define ATH_MAC_CFG2 0x04 +#define ATH_MAC_IFCTL 0x38 + +/* + * fifo control registers + */ +#define ATH_MAC_FIFO_CFG_0 0x48 +#define ATH_MAC_FIFO_CFG_1 0x4c +#define ATH_MAC_FIFO_CFG_2 0x50 +#define ATH_MAC_FIFO_CFG_3 0x54 +#define ATH_MAC_FIFO_CFG_4 0x58 + +#define ATH_MAC_FIFO_CFG_5 0x5c +#define ATH_BYTE_PER_CLK_EN (1 << 19) + +#define ATH_MAC_FIFO_RAM_0 0x60 +#define ATH_MAC_FIFO_RAM_1 0x64 +#define ATH_MAC_FIFO_RAM_2 0x68 +#define ATH_MAC_FIFO_RAM_3 0x6c +#define ATH_MAC_FIFO_RAM_4 0x70 +#define ATH_MAC_FIFO_RAM_5 0x74 +#define ATH_MAC_FIFO_RAM_6 0x78 +#define ATH_MAC_FIFO_RAM_7 0x7c + +/* + * fields + */ +#define ATH_MAC_CFG1_SOFT_RST (1 << 31) +#define ATH_MAC_CFG1_RX_RST (1 << 19) +#define ATH_MAC_CFG1_TX_RST (1 << 18) +#define ATH_MAC_CFG1_LOOPBACK (1 << 8) +#define ATH_MAC_CFG1_RX_EN (1 << 2) +#define ATH_MAC_CFG1_TX_EN (1 << 0) + +#define ATH_MAC_CFG2_FDX (1 << 0) +#define ATH_MAC_CFG2_PAD_CRC_EN (1 << 2) +#define ATH_MAC_CFG2_LEN_CHECK (1 << 4) +#define ATH_MAC_CFG2_HUGE_FRAME_EN (1 << 5) +#define ATH_MAC_CFG2_IF_1000 (1 << 9) +#define ATH_MAC_CFG2_IF_10_100 (1 << 8) + +#define ATH_MAC_IFCTL_SPEED (1 << 16) + +/* + * DMA (tx/rx) register defines + */ +#define ATH_DMA_TX_CTRL 0x180 +#define ATH_DMA_TX_DESC 0x184 +#define ATH_DMA_TX_STATUS 0x188 +#define ATH_DMA_RX_CTRL 0x18c +#define ATH_DMA_RX_DESC 0x190 +#define ATH_DMA_RX_STATUS 0x194 +#define ATH_DMA_INTR_MASK 0x198 +#define ATH_DMA_INTR 0x19c + +/* + * tx/rx ctrl and status bits + */ +#define ATH_TXE (1 << 0) +#define ATH_TX_STATUS_PKTCNT_SHIFT 16 +#define ATH_TX_STATUS_PKT_SENT 0x1 +#define ATH_TX_STATUS_URN 0x2 +#define ATH_TX_STATUS_BUS_ERROR 0x8 + +#define ATH_RXE (1 << 0) + +#define ATH_RX_STATUS_PKTCNT_MASK 0xff0000 +#define ATH_RX_STATUS_PKT_RCVD (1 << 0) +#define ATH_RX_STATUS_OVF (1 << 2) +#define ATH_RX_STATUS_BUS_ERROR (1 << 3) + +/* + * Int and int mask + */ +#define ATH_INTR_TX (1 << 0) +#define ATH_INTR_TX_URN (1 << 1) +#define ATH_INTR_TX_BUS_ERROR (1 << 3) +#define ATH_INTR_RX (1 << 4) +#define ATH_INTR_RX_OVF (1 << 6) +#define ATH_INTR_RX_BUS_ERROR (1 << 7) + +/* + * MII registers + */ +#define ATH_MAC_MII_MGMT_CFG 0x20 +#define ATH_MGMT_CFG_CLK_DIV_20 0x07 + +#define ATH_MII_MGMT_CMD 0x24 +#define ATH_MGMT_CMD_READ 0x1 + +#define ATH_MII_MGMT_ADDRESS 0x28 +#define ATH_ADDR_SHIFT 8 + +#define ATH_MII_MGMT_CTRL 0x2c +#define ATH_MII_MGMT_STATUS 0x30 + +#define ATH_MII_MGMT_IND 0x34 +#define ATH_MGMT_IND_BUSY (1 << 0) +#define ATH_MGMT_IND_INVALID (1 << 2) + +#define ATH_GE_MAC_ADDR1 0x40 +#define ATH_GE_MAC_ADDR2 0x44 + +/* + * Ethernet config registers + */ +#define ATH_ETH_CFG 0x18070000 +#define ATH_ETH_CFG_RGMII_GE0 (1<<0) +#define ATH_ETH_CFG_MII_GE0 (1<<1) +#define ATH_ETH_CFG_GMII_GE0 (1<<2) +#define ATH_ETH_CFG_RMII_HISPD_GE0 (1<<11) +#define ATH_ETH_CFG_RMII_MASTER_MODE (1<<12) +#define ATH_ETH_CFG_MII_GE0_MASTER (1<<3) +#define ATH_ETH_CFG_MII_GE0_SLAVE (1<<4) +#define ATH_ETH_CFG_GE0_ERR_EN (1<<5) +#define ATH_ETH_CFG_SW_PHY_SWAP (1<<7) +#define ATH_ETH_CFG_SW_PHY_ADDR_SWAP (1<<8) +#define ATH_ETH_CFG_RXD_DELAY (1 << 14) +#define ATH_ETH_CFG_RDV_DELAY (1 << 16) +#define ATH_ETH_SWITCH_CLK_SPARE 0x18050024 + +#define ETH_XMII_TX_INVERT_MSB 31 +#define ETH_XMII_TX_INVERT_LSB 31 +#define ETH_XMII_TX_INVERT_MASK 0x80000000 +#define ETH_XMII_TX_INVERT_GET(x) (((x) & ETH_XMII_TX_INVERT_MASK) >> ETH_XMII_TX_INVERT_LSB) +#define ETH_XMII_TX_INVERT_SET(x) (((x) << ETH_XMII_TX_INVERT_LSB) & ETH_XMII_TX_INVERT_MASK) +#define ETH_XMII_TX_INVERT_RESET 0x0 // 0 +#define ETH_XMII_GIGE_QUAD_MSB 30 +#define ETH_XMII_GIGE_QUAD_LSB 30 +#define ETH_XMII_GIGE_QUAD_MASK 0x40000000 +#define ETH_XMII_GIGE_QUAD_GET(x) (((x) & ETH_XMII_GIGE_QUAD_MASK) >> ETH_XMII_GIGE_QUAD_LSB) +#define ETH_XMII_GIGE_QUAD_SET(x) (((x) << ETH_XMII_GIGE_QUAD_LSB) & ETH_XMII_GIGE_QUAD_MASK) +#define ETH_XMII_GIGE_QUAD_RESET 0x0 // 0 +#define ETH_XMII_RX_DELAY_MSB 29 +#define ETH_XMII_RX_DELAY_LSB 28 +#define ETH_XMII_RX_DELAY_MASK 0x30000000 +#define ETH_XMII_RX_DELAY_GET(x) (((x) & ETH_XMII_RX_DELAY_MASK) >> ETH_XMII_RX_DELAY_LSB) +#define ETH_XMII_RX_DELAY_SET(x) (((x) << ETH_XMII_RX_DELAY_LSB) & ETH_XMII_RX_DELAY_MASK) +#define ETH_XMII_RX_DELAY_RESET 0x0 // 0 +#define ETH_XMII_TX_DELAY_MSB 27 +#define ETH_XMII_TX_DELAY_LSB 26 +#define ETH_XMII_TX_DELAY_MASK 0x0c000000 +#define ETH_XMII_TX_DELAY_GET(x) (((x) & ETH_XMII_TX_DELAY_MASK) >> ETH_XMII_TX_DELAY_LSB) +#define ETH_XMII_TX_DELAY_SET(x) (((x) << ETH_XMII_TX_DELAY_LSB) & ETH_XMII_TX_DELAY_MASK) +#define ETH_XMII_TX_DELAY_RESET 0x0 // 0 +#define ETH_XMII_GIGE_MSB 25 +#define ETH_XMII_GIGE_LSB 25 +#define ETH_XMII_GIGE_MASK 0x02000000 +#define ETH_XMII_GIGE_GET(x) (((x) & ETH_XMII_GIGE_MASK) >> ETH_XMII_GIGE_LSB) +#define ETH_XMII_GIGE_SET(x) (((x) << ETH_XMII_GIGE_LSB) & ETH_XMII_GIGE_MASK) +#define ETH_XMII_GIGE_RESET 0x0 // 0 +#define ETH_XMII_OFFSET_PHASE_MSB 24 +#define ETH_XMII_OFFSET_PHASE_LSB 24 +#define ETH_XMII_OFFSET_PHASE_MASK 0x01000000 +#define ETH_XMII_OFFSET_PHASE_GET(x) (((x) & ETH_XMII_OFFSET_PHASE_MASK) >> ETH_XMII_OFFSET_PHASE_LSB) +#define ETH_XMII_OFFSET_PHASE_SET(x) (((x) << ETH_XMII_OFFSET_PHASE_LSB) & ETH_XMII_OFFSET_PHASE_MASK) +#define ETH_XMII_OFFSET_PHASE_RESET 0x0 // 0 +#define ETH_XMII_OFFSET_COUNT_MSB 23 +#define ETH_XMII_OFFSET_COUNT_LSB 16 +#define ETH_XMII_OFFSET_COUNT_MASK 0x00ff0000 +#define ETH_XMII_OFFSET_COUNT_GET(x) (((x) & ETH_XMII_OFFSET_COUNT_MASK) >> ETH_XMII_OFFSET_COUNT_LSB) +#define ETH_XMII_OFFSET_COUNT_SET(x) (((x) << ETH_XMII_OFFSET_COUNT_LSB) & ETH_XMII_OFFSET_COUNT_MASK) +#define ETH_XMII_OFFSET_COUNT_RESET 0x0 // 0 +#define ETH_XMII_PHASE1_COUNT_MSB 15 +#define ETH_XMII_PHASE1_COUNT_LSB 8 +#define ETH_XMII_PHASE1_COUNT_MASK 0x0000ff00 +#define ETH_XMII_PHASE1_COUNT_GET(x) (((x) & ETH_XMII_PHASE1_COUNT_MASK) >> ETH_XMII_PHASE1_COUNT_LSB) +#define ETH_XMII_PHASE1_COUNT_SET(x) (((x) << ETH_XMII_PHASE1_COUNT_LSB) & ETH_XMII_PHASE1_COUNT_MASK) +#define ETH_XMII_PHASE1_COUNT_RESET 0x1 // 1 +#define ETH_XMII_PHASE0_COUNT_MSB 7 +#define ETH_XMII_PHASE0_COUNT_LSB 0 +#define ETH_XMII_PHASE0_COUNT_MASK 0x000000ff +#define ETH_XMII_PHASE0_COUNT_GET(x) (((x) & ETH_XMII_PHASE0_COUNT_MASK) >> ETH_XMII_PHASE0_COUNT_LSB) +#define ETH_XMII_PHASE0_COUNT_SET(x) (((x) << ETH_XMII_PHASE0_COUNT_LSB) & ETH_XMII_PHASE0_COUNT_MASK) +#define ETH_XMII_PHASE0_COUNT_RESET 0x1 // 1 +#define ETH_XMII_ADDRESS 0x18050030 + + + +#define ETH_CFG_ETH_SPARE_MSB 31 +#define ETH_CFG_ETH_SPARE_LSB 22 +#define ETH_CFG_ETH_SPARE_MASK 0xffc00000 +#define ETH_CFG_ETH_SPARE_GET(x) (((x) & ETH_CFG_ETH_SPARE_MASK) >> ETH_CFG_ETH_SPARE_LSB) +#define ETH_CFG_ETH_SPARE_SET(x) (((x) << ETH_CFG_ETH_SPARE_LSB) & ETH_CFG_ETH_SPARE_MASK) +#define ETH_CFG_ETH_SPARE_RESET 0x0 // 0 +#define ETH_CFG_ETH_TXEN_DELAY_MSB 21 +#define ETH_CFG_ETH_TXEN_DELAY_LSB 20 +#define ETH_CFG_ETH_TXEN_DELAY_MASK 0x00300000 +#define ETH_CFG_ETH_TXEN_DELAY_GET(x) (((x) & ETH_CFG_ETH_TXEN_DELAY_MASK) >> ETH_CFG_ETH_TXEN_DELAY_LSB) +#define ETH_CFG_ETH_TXEN_DELAY_SET(x) (((x) << ETH_CFG_ETH_TXEN_DELAY_LSB) & ETH_CFG_ETH_TXEN_DELAY_MASK) +#define ETH_CFG_ETH_TXEN_DELAY_RESET 0x0 // 0 +#define ETH_CFG_ETH_TXD_DELAY_MSB 19 +#define ETH_CFG_ETH_TXD_DELAY_LSB 18 +#define ETH_CFG_ETH_TXD_DELAY_MASK 0x000c0000 +#define ETH_CFG_ETH_TXD_DELAY_GET(x) (((x) & ETH_CFG_ETH_TXD_DELAY_MASK) >> ETH_CFG_ETH_TXD_DELAY_LSB) +#define ETH_CFG_ETH_TXD_DELAY_SET(x) (((x) << ETH_CFG_ETH_TXD_DELAY_LSB) & ETH_CFG_ETH_TXD_DELAY_MASK) +#define ETH_CFG_ETH_TXD_DELAY_RESET 0x0 // 0 +#define ETH_CFG_ETH_RXDV_DELAY_MSB 17 +#define ETH_CFG_ETH_RXDV_DELAY_LSB 16 +#define ETH_CFG_ETH_RXDV_DELAY_MASK 0x00030000 +#define ETH_CFG_ETH_RXDV_DELAY_GET(x) (((x) & ETH_CFG_ETH_RXDV_DELAY_MASK) >> ETH_CFG_ETH_RXDV_DELAY_LSB) +#define ETH_CFG_ETH_RXDV_DELAY_SET(x) (((x) << ETH_CFG_ETH_RXDV_DELAY_LSB) & ETH_CFG_ETH_RXDV_DELAY_MASK) +#define ETH_CFG_ETH_RXDV_DELAY_RESET 0x0 // 0 +#define ETH_CFG_ETH_RXD_DELAY_MSB 15 +#define ETH_CFG_ETH_RXD_DELAY_LSB 14 +#define ETH_CFG_ETH_RXD_DELAY_MASK 0x0000c000 +#define ETH_CFG_ETH_RXD_DELAY_GET(x) (((x) & ETH_CFG_ETH_RXD_DELAY_MASK) >> ETH_CFG_ETH_RXD_DELAY_LSB) +#define ETH_CFG_ETH_RXD_DELAY_SET(x) (((x) << ETH_CFG_ETH_RXD_DELAY_LSB) & ETH_CFG_ETH_RXD_DELAY_MASK) +#define ETH_CFG_ETH_RXD_DELAY_RESET 0x0 // 0 +#define ETH_CFG_RMII_GE0_MASTER_MSB 12 +#define ETH_CFG_RMII_GE0_MASTER_LSB 12 +#define ETH_CFG_RMII_GE0_MASTER_MASK 0x00001000 +#define ETH_CFG_RMII_GE0_MASTER_GET(x) (((x) & ETH_CFG_RMII_GE0_MASTER_MASK) >> ETH_CFG_RMII_GE0_MASTER_LSB) +#define ETH_CFG_RMII_GE0_MASTER_SET(x) (((x) << ETH_CFG_RMII_GE0_MASTER_LSB) & ETH_CFG_RMII_GE0_MASTER_MASK) +#define ETH_CFG_RMII_GE0_MASTER_RESET 0x1 // 1 +#define ETH_CFG_MII_CNTL_SPEED_MSB 11 +#define ETH_CFG_MII_CNTL_SPEED_LSB 11 +#define ETH_CFG_MII_CNTL_SPEED_MASK 0x00000800 +#define ETH_CFG_MII_CNTL_SPEED_GET(x) (((x) & ETH_CFG_MII_CNTL_SPEED_MASK) >> ETH_CFG_MII_CNTL_SPEED_LSB) +#define ETH_CFG_MII_CNTL_SPEED_SET(x) (((x) << ETH_CFG_MII_CNTL_SPEED_LSB) & ETH_CFG_MII_CNTL_SPEED_MASK) +#define ETH_CFG_MII_CNTL_SPEED_RESET 0x0 // 0 +#define ETH_CFG_GE0_SGMII_MSB 6 +#define ETH_CFG_GE0_SGMII_LSB 6 +#define ETH_CFG_GE0_SGMII_MASK 0x00000040 +#define ETH_CFG_GE0_SGMII_GET(x) (((x) & ETH_CFG_GE0_SGMII_MASK) >> ETH_CFG_GE0_SGMII_LSB) +#define ETH_CFG_GE0_SGMII_SET(x) (((x) << ETH_CFG_GE0_SGMII_LSB) & ETH_CFG_GE0_SGMII_MASK) +#define ETH_CFG_GE0_SGMII_RESET 0x0 // 0 +#define ETH_CFG_GE0_ERR_EN_MSB 5 +#define ETH_CFG_GE0_ERR_EN_LSB 5 +#define ETH_CFG_GE0_ERR_EN_MASK 0x00000020 +#define ETH_CFG_GE0_ERR_EN_GET(x) (((x) & ETH_CFG_GE0_ERR_EN_MASK) >> ETH_CFG_GE0_ERR_EN_LSB) +#define ETH_CFG_GE0_ERR_EN_SET(x) (((x) << ETH_CFG_GE0_ERR_EN_LSB) & ETH_CFG_GE0_ERR_EN_MASK) +#define ETH_CFG_GE0_ERR_EN_RESET 0x0 // 0 +#define ETH_CFG_MII_GE0_SLAVE_MSB 4 +#define ETH_CFG_MII_GE0_SLAVE_LSB 4 +#define ETH_CFG_MII_GE0_SLAVE_MASK 0x00000010 +#define ETH_CFG_MII_GE0_SLAVE_GET(x) (((x) & ETH_CFG_MII_GE0_SLAVE_MASK) >> ETH_CFG_MII_GE0_SLAVE_LSB) +#define ETH_CFG_MII_GE0_SLAVE_SET(x) (((x) << ETH_CFG_MII_GE0_SLAVE_LSB) & ETH_CFG_MII_GE0_SLAVE_MASK) +#define ETH_CFG_MII_GE0_SLAVE_RESET 0x0 // 0 +#define ETH_CFG_MII_GE0_MASTER_MSB 3 +#define ETH_CFG_MII_GE0_MASTER_LSB 3 +#define ETH_CFG_MII_GE0_MASTER_MASK 0x00000008 +#define ETH_CFG_MII_GE0_MASTER_GET(x) (((x) & ETH_CFG_MII_GE0_MASTER_MASK) >> ETH_CFG_MII_GE0_MASTER_LSB) +#define ETH_CFG_MII_GE0_MASTER_SET(x) (((x) << ETH_CFG_MII_GE0_MASTER_LSB) & ETH_CFG_MII_GE0_MASTER_MASK) +#define ETH_CFG_MII_GE0_MASTER_RESET 0x0 // 0 +#define ETH_CFG_GMII_GE0_MSB 2 +#define ETH_CFG_GMII_GE0_LSB 2 +#define ETH_CFG_GMII_GE0_MASK 0x00000004 +#define ETH_CFG_GMII_GE0_GET(x) (((x) & ETH_CFG_GMII_GE0_MASK) >> ETH_CFG_GMII_GE0_LSB) +#define ETH_CFG_GMII_GE0_SET(x) (((x) << ETH_CFG_GMII_GE0_LSB) & ETH_CFG_GMII_GE0_MASK) +#define ETH_CFG_GMII_GE0_RESET 0x0 // 0 +#define ETH_CFG_MII_GE0_MSB 1 +#define ETH_CFG_MII_GE0_LSB 1 +#define ETH_CFG_MII_GE0_MASK 0x00000002 +#define ETH_CFG_MII_GE0_GET(x) (((x) & ETH_CFG_MII_GE0_MASK) >> ETH_CFG_MII_GE0_LSB) +#define ETH_CFG_MII_GE0_SET(x) (((x) << ETH_CFG_MII_GE0_LSB) & ETH_CFG_MII_GE0_MASK) +#define ETH_CFG_MII_GE0_RESET 0x0 // 0 +#define ETH_CFG_RGMII_GE0_MSB 0 +#define ETH_CFG_RGMII_GE0_LSB 0 +#define ETH_CFG_RGMII_GE0_MASK 0x00000001 +#define ETH_CFG_RGMII_GE0_GET(x) (((x) & ETH_CFG_RGMII_GE0_MASK) >> ETH_CFG_RGMII_GE0_LSB) +#define ETH_CFG_RGMII_GE0_SET(x) (((x) << ETH_CFG_RGMII_GE0_LSB) & ETH_CFG_RGMII_GE0_MASK) +#define ETH_CFG_RGMII_GE0_RESET 0x0 // 0 +#define ETH_CFG_ADDRESS 0x18070000 + + + + +/* + * ownership of descriptors between DMA and cpu + */ +#define ath_gmac_rx_owned_by_dma(_ds) ((_ds)->is_empty == 1) +#define ath_gmac_rx_give_to_dma(_ds) ((_ds)->is_empty = 1) +#define ath_gmac_tx_owned_by_dma(_ds) ((_ds)->is_empty == 0) +#define ath_gmac_tx_give_to_dma(_ds) ((_ds)->is_empty = 0) +#define ath_gmac_tx_own(_ds) ((_ds)->is_empty = 1) + +/* + * link settings + */ +#define ath_gmac_set_mac_duplex(_mac, _fdx) do { \ + if ((_fdx)) { \ + ath_gmac_reg_rmw_set(_mac, \ + ATH_MAC_CFG2, ATH_MAC_CFG2_FDX);\ + } else { \ + ath_gmac_reg_rmw_clear(_mac, \ + ATH_MAC_CFG2, ATH_MAC_CFG2_FDX);\ + } \ +} while (0) + +#define ath_gmac_set_mac_if(_mac, _isXGMII) do { \ + ath_gmac_reg_rmw_clear(_mac, ATH_MAC_CFG2, \ + ATH_MAC_CFG2_IF_1000 | \ + ATH_MAC_CFG2_IF_10_100); \ + if ((_isXGMII)) { \ + ath_gmac_reg_rmw_set(_mac, ATH_MAC_CFG2, \ + ATH_MAC_CFG2_IF_1000); \ + ath_gmac_reg_rmw_set(_mac, ATH_MAC_FIFO_CFG_5, \ + ATH_BYTE_PER_CLK_EN); \ + } else { \ + ath_gmac_reg_rmw_set(_mac, ATH_MAC_CFG2, \ + ATH_MAC_CFG2_IF_10_100); \ + ath_gmac_reg_rmw_clear(_mac, ATH_MAC_FIFO_CFG_5,\ + ATH_BYTE_PER_CLK_EN); \ + } \ +} while (0) + +#define ath_gmac_set_mac_speed(_mac, _is100) do { \ + if ((_is100)) { \ + ath_gmac_reg_rmw_set(_mac, ATH_MAC_IFCTL, \ + ATH_MAC_IFCTL_SPEED); \ + } else { \ + ath_gmac_reg_rmw_clear(_mac, ATH_MAC_IFCTL, \ + ATH_MAC_IFCTL_SPEED); \ + } \ +} while (0) + +#endif diff --git a/board/qca/mips32/common/qca-eth-956x_phy.h b/board/qca/mips32/common/qca-eth-956x_phy.h new file mode 100644 index 0000000000..d22c142d51 --- /dev/null +++ b/board/qca/mips32/common/qca-eth-956x_phy.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _QCA_ETH_956x_PHY_H +#define _QCA_ETH_956x_PHY_H +#include + + +#ifdef CONFIG_ATHR_8033_PHY +extern int athrs_ar8033_reg_init(void *arg); +extern int athrs_ar8033_phy_setup(void *arg); +extern int athrs_ar8033_phy_is_fdx(int ethUnit); +extern int athrs_ar8033_phy_is_link_alive(int phyUnit); +extern int athrs_ar8033_phy_is_up(int ethUnit); +extern int athrs_ar8033_phy_speed(int ethUnit,int phyUnit); +#endif + +#ifdef CONFIG_ATHRS17_PHY +extern int athrs17_phy_setup(int ethUnit); +extern int athrs17_phy_is_up(int ethUnit); +extern int athrs17_phy_is_fdx(int ethUnit); +extern int athrs17_phy_speed(int ethUnit); +#endif + +#ifdef CFG_ATHRS26_PHY +extern int athrs26_phy_setup(int ethUnit); +extern int athrs26_phy_is_up(int ethUnit); +extern int athrs26_phy_is_fdx(int ethUnit); +extern int athrs26_phy_speed(int ethUnit); +#endif + +#ifdef CFG_ATHRS27_PHY +extern int athrs27_phy_setup(int ethUnit); +extern int athrs27_phy_is_up(int ethUnit); +extern int athrs27_phy_is_fdx(int ethUnit); +extern int athrs27_phy_speed(int ethUnit); +#endif + +static inline void ath_gmac_phy_setup(int unit) +{ +#ifdef CONFIG_ATHRS17_PHY + if (unit == 0) { + athrs17_phy_setup(unit); + } else +#endif + { +#ifdef CFG_ATHRS26_PHY + athrs26_phy_setup(unit); +#endif + +#ifdef CFG_ATHRS27_PHY + athrs27_phy_setup(unit); +#endif + +#ifdef CONFIG_VIR_PHY + athr_vir_phy_setup(unit); +#endif +#if defined(CONFIG_ATHRS17_PHY) && !defined (CFG_DUAL_PHY_SUPPORT) + athrs17_phy_setup(unit); +#endif + + } +} + +static inline void ath_gmac_phy_link(int unit, int *link) +{ +#ifdef CONFIG_ATHRS17_PHY + if (unit == 0) { + *link = athrs17_phy_is_up(unit); + } else +#endif + { +#ifdef CFG_ATHRS26_PHY + *link = athrs26_phy_is_up(unit); +#endif +#ifdef CFG_ATHRS27_PHY + *link = athrs27_phy_is_up(unit); +#endif + +#ifdef CONFIG_VIR_PHY + *link = athr_vir_phy_is_up(unit); +#endif +#ifdef CONFIG_ATHR_8033_PHY + *link = athrs_ar8033_phy_is_up(unit); +#endif +#if defined(CONFIG_ATHRS17_PHY) && !defined (CFG_DUAL_PHY_SUPPORT) + *link = athrs17_phy_is_up(unit); +#endif + + } +} + +static inline void ath_gmac_phy_duplex(int unit, int *duplex) +{ +#ifdef CONFIG_ATHRS17_PHY + if (unit == 0) { + *duplex = athrs17_phy_is_fdx(unit); + } else +#endif + { +#ifdef CFG_ATHRS26_PHY + *duplex = athrs26_phy_is_fdx(unit); +#endif +#ifdef CFG_ATHRS27_PHY + *duplex = athrs27_phy_is_fdx(unit); +#endif + +#ifdef CONFIG_VIR_PHY + *duplex = athr_vir_phy_is_fdx(unit); +#endif +#ifdef CONFIG_ATHR_8033_PHY + *duplex = athrs_ar8033_phy_is_fdx(unit); +#endif +#if defined(CONFIG_ATHRS17_PHY) && !defined(CFG_DUAL_PHY_SUPPORT) + *duplex = athrs17_phy_is_fdx(unit); +#endif + } +} + +static inline void ath_gmac_phy_speed(int unit, int *speed) +{ +#ifdef CONFIG_ATHRS17_PHY + if (unit == 0) { + *speed = _1000BASET; + } else +#endif + { +#ifdef CFG_ATHRS26_PHY + *speed = athrs26_phy_speed(unit); +#endif +#ifdef CFG_ATHRS27_PHY + *speed = athrs27_phy_speed(unit); +#endif + +#ifdef CONFIG_VIR_PHY + *speed = athr_vir_phy_speed(unit); +#endif +#ifdef CONFIG_ATHR_8033_PHY + *speed = athrs_ar8033_phy_speed(unit, 5); +#endif + +#if defined(CONFIG_ATHRS17_PHY) && !defined (CFG_DUAL_PHY_SUPPORT) + *speed = _1000BASET; +#endif + } +} + +#endif /* _QCA_ETH_955x_PHY_H */ diff --git a/board/qca/mips32/qca956x/Makefile b/board/qca/mips32/qca956x/Makefile index c47f88ae4f..106adfac15 100644 --- a/board/qca/mips32/qca956x/Makefile +++ b/board/qca/mips32/qca956x/Makefile @@ -1,4 +1,6 @@ obj-y := board956x.o extra.o ../common/init-956x.o \ ../common/956x.o ../common/tap-956x.o \ ../common/ath_serial.o ../common/qca-mach-common.o \ - flash.o ../common/ath_flash.o + flash.o ../common/ath_flash.o \ + ../common/athrs17_phy.o \ + ../common/qca-eth-956x.o