diff --git a/arch/arm/dts/ipq5018-emulation.dts b/arch/arm/dts/ipq5018-emulation.dts index c7f3953661..b0fe1d4aaf 100644 --- a/arch/arm/dts/ipq5018-emulation.dts +++ b/arch/arm/dts/ipq5018-emulation.dts @@ -128,11 +128,12 @@ gmac_cfg { gmac_count = <2>; - + ext_mdio_gpio = <1>; gmac1_cfg { unit = <0>; base = <0x39C00000>; phy_address = <7>; + phy_interface_mode = <2>; phy_name = "IPQ MDIO0"; }; @@ -140,7 +141,11 @@ unit = <1>; base = <0x39D00000>; phy_address = <1>; + phy_interface_mode = <2>; phy_name = "IPQ MDIO1"; + mac_pwr0 = <0x00080000>; + mac_pwr1 = <0x00040000>; + s17c_switch_enable = <0>; }; }; diff --git a/arch/arm/include/asm/arch-ipq5018/athrs17_phy.h b/arch/arm/include/asm/arch-ipq5018/athrs17_phy.h new file mode 100644 index 0000000000..d5c1d4f193 --- /dev/null +++ b/arch/arm/include/asm/arch-ipq5018/athrs17_phy.h @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2015-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) + +#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_MAC_PWR_REG 0x00e4 +#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_MASK_CTRL_SOFT_RET (1 << 31) + +#define S17_GLOBAL_INT0_ACL_INI_INT (1<<29) +#define S17_GLOBAL_INT0_LOOKUP_INI_INT (1<<28) +#define S17_GLOBAL_INT0_QM_INI_INT (1<<27) +#define S17_GLOBAL_INT0_MIB_INI_INT (1<<26) +#define S17_GLOBAL_INT0_OFFLOAD_INI_INT (1<<25) +#define S17_GLOBAL_INT0_HARDWARE_INI_DONE (1<<24) + +#define S17_GLOBAL_INITIALIZED_STATUS \ + ( \ + S17_GLOBAL_INT0_ACL_INI_INT | \ + S17_GLOBAL_INT0_LOOKUP_INI_INT | \ + S17_GLOBAL_INT0_QM_INI_INT | \ + S17_GLOBAL_INT0_MIB_INI_INT | \ + S17_GLOBAL_INT0_OFFLOAD_INI_INT | \ + S17_GLOBAL_INT0_HARDWARE_INI_DONE \ + ) + +#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) +#define S17c_PWS_SERDES_ANEG_DISABLE (1 << 7) + +/* 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 + +/* MAC power selector bit definitions */ +#define S17_RGMII0_1_8V (1 << 19) +#define S17_RGMII1_1_8V (1 << 18) + +/* SGMII_CTRL bit definitions */ +#define S17c_SGMII_EN_LCKDT (1 << 0) +#define S17c_SGMII_EN_PLL (1 << 1) +#define S17c_SGMII_EN_RX (1 << 2) +#define S17c_SGMII_EN_TX (1 << 3) +#define S17c_SGMII_EN_SD (1 << 4) +#define S17c_SGMII_BW_HIGH (1 << 6) +#define S17c_SGMII_SEL_CLK125M (1 << 7) +#define S17c_SGMII_TXDR_CTRL_600mV (1 << 10) +#define S17c_SGMII_CDR_BW_8 (3 << 13) +#define S17c_SGMII_DIS_AUTO_LPI_25M (1 << 16) +#define S17c_SGMII_MODE_CTRL_SGMII_PHY (1 << 22) +#define S17c_SGMII_PAUSE_SG_TX_EN_25M (1 << 24) +#define S17c_SGMII_ASYM_PAUSE_25M (1 << 25) +#define S17c_SGMII_PAUSE_25M (1 << 26) +#define S17c_SGMII_HALF_DUPLEX_25M (1 << 30) +#define S17c_SGMII_FULL_DUPLEX_25M (1 << 31) + +#ifndef BOOL +#define BOOL int +#endif + +/*add feature define here*/ + +#ifdef CONFIG_AR7242_S17_PHY +#undef HEADER_REG_CONF +#undef HEADER_EN +#endif +int athrs17_init_switch(void); +void athrs17_reg_init(ipq_gmac_board_cfg_t *gmac_cfg); +void athrs17_reg_init_lan(ipq_gmac_board_cfg_t *gmac_cfg); +void athrs17_vlan_config(void); +#endif + + diff --git a/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h index e1643c5686..f0e4c53a58 100644 --- a/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h +++ b/arch/arm/include/asm/arch-ipq5018/ipq5018_gmac.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2020 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 @@ -17,6 +17,33 @@ #include #include +#define GEPHY 0x7 /* Dummy */ + +#define GEPHY_PHY_TYPE 0x1 +#define NAPA_PHY_TYPE 0x2 + +/* GMAC0 GCC clock */ +#define GCC_GMAC0_RX_CMD_RCGR 0x01868020 +#define GCC_GMAC0_RX_CFG_RCGR 0x01868024 +#define GCC_GMAC0_TX_CMD_RCGR 0x01868028 +#define GCC_GMAC0_TX_CFG_RCGR 0x0186802C +#define GCC_GMAC0_RX_CBCR 0x01868240 +#define GCC_GMAC0_TX_CBCR 0x01868244 +#define GCC_GMAC0_RX_MISC 0x01868420 +#define GCC_GMAC0_TX_MISC 0x01868424 +#define GCC_GMAC0_MISC 0x01868428 + +/* GMAC1 GCC Clock */ +#define GCC_GMAC1_RX_CMD_RCGR 0x01868030 +#define GCC_GMAC1_RX_CFG_RCGR 0x01868034 +#define GCC_GMAC1_TX_CMD_RCGR 0x01868038 +#define GCC_GMAC1_TX_CFG_RCGR 0x0186803C +#define GCC_GMAC1_RX_CBCR 0x01868248 +#define GCC_GMAC1_TX_CBCR 0x0186824C +#define GCC_GMAC1_RX_MISC 0x01868430 +#define GCC_GMAC1_TX_MISC 0x01868434 +#define GCC_GMAC1_MISC 0x01868438 + #define CONFIG_MACRESET_TIMEOUT (3 * CONFIG_SYS_HZ) #define CONFIG_MDIO_TIMEOUT (3 * CONFIG_SYS_HZ) #define CONFIG_PHYRESET_TIMEOUT (3 * CONFIG_SYS_HZ) @@ -235,7 +262,9 @@ struct ipq_eth_dev { uint duplex; uint phy_configured; uint mac_unit; + uint phy_type; uint mac_ps; + uint ipq_swith; int link_printed; u32 padding; ipq_gmac_desc_t *desc_tx[NO_OF_TX_DESC]; diff --git a/board/ipq5018/Kconfig b/board/ipq5018/Kconfig index d5bd0d79bd..fab9ee97b4 100644 --- a/board/ipq5018/Kconfig +++ b/board/ipq5018/Kconfig @@ -45,4 +45,7 @@ config IPQ_TINY_SPI_NOR config NAND_FLASH bool "Enable NAND driver for ipq5018" +config GEPHY + bool "Enable Internel GEPHY for ipq5018" + endif diff --git a/board/qca/arm/ipq5018/ipq5018.c b/board/qca/arm/ipq5018/ipq5018.c index ff745f14f6..12ce48cc1f 100644 --- a/board/qca/arm/ipq5018/ipq5018.c +++ b/board/qca/arm/ipq5018/ipq5018.c @@ -622,6 +622,72 @@ unsigned long timer_read_counter(void) return 0; } +static void set_ext_mdio_gpio(void) +{ + /* mdc */ + writel(0x7, (unsigned int *)GPIO_CONFIG_ADDR(36)); + /* mdio */ + writel(0x7, (unsigned int *)GPIO_CONFIG_ADDR(37)); +} + +static void set_napa_phy_gpio(int gpio) +{ + unsigned int *napa_gpio_base; + + napa_gpio_base = (unsigned int *)GPIO_CONFIG_ADDR(gpio); + writel(0x203, napa_gpio_base); + gpio_direction_output(gpio, 0x0); + mdelay(500); + gpio_set_value(gpio, 0x1); +} + +void gmac_clock_enable(void) +{ + /* GEPHY BCR Enable */ + writel(0x0, GCC_GEPHY_BCR); + udelay(10); + + /* GMAC0 BCR Enable */ + writel(0x0, GCC_GMAC0_BCR); + udelay(10); + /* GMAC0 AHB clock enable */ + writel(0x1, GCC_SNOC_GMAC0_AHB_CBCR); + udelay(10); + /* GMAC0 SYS clock */ + writel(0x1, GCC_GMAC0_SYS_CBCR); + udelay(10); + /* GMAC0 PTP clock */ + writel(0x1, GCC_GMAC0_PTP_CBCR); + udelay(10); + /* GMAC0 CFG clock */ + writel(0x1, GCC_GMAC0_CFG_CBCR); + udelay(10); + + /* UNIPHY BCR Enable */ + writel(0x0, GCC_UNIPHY_BCR); + udelay(10); + writel(0x1, GCC_UNIPHY_AHB_CBCR); + udelay(10); + writel(0x1, GCC_UNIPHY_SYS_CBCR); + udelay(10); + + /* GMAC1 BCR Enable */ + writel(0x0, GCC_GMAC1_BCR); + udelay(10); + /* GMAC0 AHB clock enable */ + writel(0x1, GCC_SNOC_GMAC1_AHB_CBCR); + udelay(10); + /* GMAC0 SYS clock */ + writel(0x1, GCC_GMAC1_SYS_CBCR); + udelay(10); + /* GMAC0 PTP clock */ + writel(0x1, GCC_GMAC1_PTP_CBCR); + udelay(10); + /* GMAC0 CFG clock */ + writel(0x1, GCC_GMAC1_CFG_CBCR); + udelay(10); +} + int board_eth_init(bd_t *bis) { int status; @@ -633,6 +699,15 @@ int board_eth_init(bd_t *bis) gmac_cfg_node = fdt_path_offset(gd->fdt_blob, "/gmac_cfg"); if (gmac_cfg_node >= 0) { + /* + * Clock enable + */ + gmac_clock_enable(); + + status = fdtdec_get_uint(gd->fdt_blob,offset, "ext_mdio_gpio", 0); + if (status){ + set_ext_mdio_gpio(); + } for (offset = fdt_first_subnode(gd->fdt_blob, gmac_cfg_node); offset > 0; offset = fdt_next_subnode(gd->fdt_blob, offset) , loop++) { @@ -646,12 +721,33 @@ int board_eth_init(bd_t *bis) gmac_cfg[loop].phy_addr = fdtdec_get_uint(gd->fdt_blob, offset, "phy_address", 0); + gmac_cfg[loop].phy_interface_mode = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_interface_mode", 0); + + gmac_cfg[loop].phy_napa_gpio = fdtdec_get_uint(gd->fdt_blob, + offset, "napa_gpio", 0); + if (gmac_cfg[loop].phy_napa_gpio){ + set_napa_phy_gpio(gmac_cfg[loop].phy_napa_gpio); + } + + gmac_cfg[loop].phy_type = fdtdec_get_uint(gd->fdt_blob, + offset, "phy_type", -1); + + gmac_cfg[loop].mac_pwr0 = fdtdec_get_uint(gd->fdt_blob, + offset, "mac_pwr0", 0); + + gmac_cfg[loop].mac_pwr1 = fdtdec_get_uint(gd->fdt_blob, + offset, "mac_pwr1", 0); + + gmac_cfg[loop].ipq_swith = fdtdec_get_uint(gd->fdt_blob, + offset, "s17c_switch_enable", 0); + phy_name_ptr = (char*)fdt_getprop(gd->fdt_blob, offset, "phy_name", &phy_name_len); strlcpy((char *)gmac_cfg[loop].phy_name, phy_name_ptr, phy_name_len); - } - } + } + } gmac_cfg[loop].unit = -1; ipq_gmac_common_init(gmac_cfg); diff --git a/board/qca/arm/ipq5018/ipq5018.h b/board/qca/arm/ipq5018/ipq5018.h index aa95cd7bf0..34a0da25dc 100644 --- a/board/qca/arm/ipq5018/ipq5018.h +++ b/board/qca/arm/ipq5018/ipq5018.h @@ -22,6 +22,34 @@ #define MSM_SDC1_BASE 0x7800000 #define MSM_SDC1_SDHCI_BASE 0x7804000 +/* + * GMAC Block Register + */ +#define GCC_GMAC0_BCR 0x01819000 +#define GCC_SNOC_GMAC0_AXI_CBCR 0x01826084 +#define GCC_SNOC_GMAC0_AHB_CBCR 0x018260A0 +#define GCC_GMAC0_PTP_CBCR 0x01868300 +#define GCC_GMAC0_CFG_CBCR 0x01868304 +#define GCC_GMAC0_SYS_CBCR 0x01868190 + +#define GCC_GMAC1_BCR 0x01819100 +#define GCC_SNOC_GMAC1_AXI_CBCR 0x01826088 +#define GCC_SNOC_GMAC1_AHB_CBCR 0x018260A4 +#define GCC_GMAC1_SYS_CBCR 0x01868310 +#define GCC_GMAC1_PTP_CBCR 0x01868320 +#define GCC_GMAC1_CFG_CBCR 0x01868324 +/* + * GEPHY Block Register + */ +#define GCC_GEPHY_BCR 0x01856000 +#define GCC_GEPHY_MISC 0x01856004 + +/* + * UNIPHY Block Register + */ +#define GCC_UNIPHY_BCR 0x01856100 +#define GCC_UNIPHY_AHB_CBCR 0x01856108 +#define GCC_UNIPHY_SYS_CBCR 0x0185610C /* * GCC-SDCC Registers */ @@ -330,9 +358,15 @@ unsigned int __invoke_psci_fn_smc(unsigned int, unsigned int, unsigned int, unsigned int); typedef struct { - uint base; + u32 base; int unit; - uint phy_addr; + int phy_addr; + int phy_interface_mode; + int phy_napa_gpio; + int phy_type; + u32 mac_pwr0; + u32 mac_pwr1; + int ipq_swith; const char phy_name[MDIO_NAME_LEN]; } ipq_gmac_board_cfg_t; diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3270843d63..ee3de33e5b 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -87,7 +87,11 @@ obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_edma.o obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_ppe.o obj-$(CONFIG_IPQ6018_EDMA) += ipq6018/ipq6018_uniphy.o obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_gmac.o +obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/ipq5018_uniphy.o +obj-$(CONFIG_IPQ5018_MDIO) += ipq5018/ipq5018_mdio.o +obj-$(CONFIG_IPQ5018_GMAC) += ipq5018/athrs17_phy.o obj-$(CONFIG_IPQ_MDIO) += ipq_common/ipq_mdio.o +obj-$(CONFIG_GEPHY) += ipq_common/ipq_gephy.o obj-$(CONFIG_QCA8075_PHY) += ipq_common/ipq_qca8075.o obj-$(CONFIG_QCA8033_PHY) += ipq_common/ipq_qca8033.o obj-$(CONFIG_QCA8081_PHY) += ipq_common/ipq_qca8081.o diff --git a/drivers/net/ipq5018/athrs17_phy.c b/drivers/net/ipq5018/athrs17_phy.c new file mode 100644 index 0000000000..5fdca97dad --- /dev/null +++ b/drivers/net/ipq5018/athrs17_phy.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2015-2016, 2020 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 + +/* + * Externel Common mdio read, PHY Name : IPQ MDIO1 + */ + +extern int ipq_mdio_write(int mii_id, + int regnum, u16 value); +extern int ipq_mdio_read(int mii_id, + int regnum, ushort *data); + +/****************************************************************************** + * FUNCTION DESCRIPTION: Read switch internal register. + * Switch internal register is accessed through the + * MDIO interface. MDIO access is only 16 bits wide so + * it needs the two time access to complete the internal + * register access. + * INPUT : register address + * OUTPUT : Register value + * + *****************************************************************************/ +static uint32_t +athrs17_reg_read(uint32_t reg_addr) +{ + uint32_t reg_word_addr; + uint32_t phy_addr, reg_val; + uint16_t phy_val; + uint16_t tmp_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 */ + ipq_mdio_write(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 */ + ipq_mdio_read(phy_addr, phy_reg, &phy_val); + + /* 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 */ + ipq_mdio_read(phy_addr, phy_reg, &tmp_val); + reg_val = (tmp_val << 16 | phy_val); + + return reg_val; +} + +/****************************************************************************** + * FUNCTION DESCRIPTION: Write switch internal register. + * Switch internal register is accessed through the + * MDIO interface. MDIO access is only 16 bits wide so + * it needs the two time access to complete the internal + * register access. + * INPUT : register address, value to be written + * OUTPUT : NONE + * + *****************************************************************************/ +static 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 */ + ipq_mdio_write(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); + ipq_mdio_write(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); + ipq_mdio_write(phy_addr, phy_reg, phy_val); +} + +/********************************************************************* + * FUNCTION DESCRIPTION: V-lan configuration given by Switch team + Vlan 1:PHY0,1,2,3 and Mac 6 of s17c + Vlan 2:PHY4 and Mac 0 of s17c + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_vlan_config(void) +{ + athrs17_reg_write(S17_P0LOOKUP_CTRL_REG, 0x00140020); + athrs17_reg_write(S17_P0VLAN_CTRL0_REG, 0x20001); + + athrs17_reg_write(S17_P1LOOKUP_CTRL_REG, 0x0014005c); + athrs17_reg_write(S17_P1VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P2LOOKUP_CTRL_REG, 0x0014005a); + athrs17_reg_write(S17_P2VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P3LOOKUP_CTRL_REG, 0x00140056); + athrs17_reg_write(S17_P3VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P4LOOKUP_CTRL_REG, 0x0014004e); + athrs17_reg_write(S17_P4VLAN_CTRL0_REG, 0x10001); + + athrs17_reg_write(S17_P5LOOKUP_CTRL_REG, 0x00140001); + athrs17_reg_write(S17_P5VLAN_CTRL0_REG, 0x20001); + + athrs17_reg_write(S17_P6LOOKUP_CTRL_REG, 0x0014001e); + athrs17_reg_write(S17_P6VLAN_CTRL0_REG, 0x10001); + printf("%s ...done\n", __func__); +} + +/******************************************************************* +* FUNCTION DESCRIPTION: Reset S17 register +* INPUT: NONE +* OUTPUT: NONE +*******************************************************************/ +int athrs17_init_switch(void) +{ + uint32_t data; + uint32_t i = 0; + + /* Reset the switch before initialization */ + athrs17_reg_write(S17_MASK_CTRL_REG, S17_MASK_CTRL_SOFT_RET); + do { + udelay(10); + data = athrs17_reg_read(S17_MASK_CTRL_REG); + } while (data & S17_MASK_CTRL_SOFT_RET); + + do { + udelay(10); + data = athrs17_reg_read(S17_GLOBAL_INT0_REG); + i++; + if (i == 10) + return -1; + } while ((data & S17_GLOBAL_INITIALIZED_STATUS) != S17_GLOBAL_INITIALIZED_STATUS); + + return 0; +} + +/********************************************************************* + * FUNCTION DESCRIPTION: Configure S17 register + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_reg_init(ipq_gmac_board_cfg_t *gmac_cfg) +{ + uint32_t data; + + data = athrs17_reg_read(S17_MAC_PWR_REG) | gmac_cfg->mac_pwr0; + athrs17_reg_write(S17_MAC_PWR_REG, data); + + athrs17_reg_write(S17_P0STATUS_REG, (S17_SPEED_1000M | S17_TXMAC_EN | + S17_RXMAC_EN | S17_TX_FLOW_EN | + S17_RX_FLOW_EN | S17_DUPLEX_FULL)); + + athrs17_reg_write(S17_GLOFW_CTRL1_REG, (S17_IGMP_JOIN_LEAVE_DPALL | + S17_BROAD_DPALL | + S17_MULTI_FLOOD_DPALL | + S17_UNI_FLOOD_DPALL)); + + athrs17_reg_write(S17_P5PAD_MODE_REG, S17_MAC0_RGMII_RXCLK_DELAY); + athrs17_reg_write(S17_P0PAD_MODE_REG, (S17_MAC0_RGMII_EN | \ + S17_MAC0_RGMII_TXCLK_DELAY | S17_MAC0_RGMII_RXCLK_DELAY | \ + (0x1 << S17_MAC0_RGMII_TXCLK_SHIFT) | \ + (0x3 << S17_MAC0_RGMII_RXCLK_SHIFT))); + + printf("%s: complete\n", __func__); +} + +/********************************************************************* + * FUNCTION DESCRIPTION: Configure S17 register + * INPUT : NONE + * OUTPUT: NONE + *********************************************************************/ +void athrs17_reg_init_lan(ipq_gmac_board_cfg_t *gmac_cfg) +{ + uint32_t reg_val; + + athrs17_reg_write(S17_P6STATUS_REG, (S17_SPEED_1000M | S17_TXMAC_EN | + S17_RXMAC_EN | + S17_DUPLEX_FULL)); + + reg_val = athrs17_reg_read(S17_MAC_PWR_REG) | gmac_cfg->mac_pwr1; + athrs17_reg_write(S17_MAC_PWR_REG, reg_val); + + reg_val = athrs17_reg_read(S17_P6PAD_MODE_REG); + athrs17_reg_write(S17_P6PAD_MODE_REG, (reg_val | S17_MAC6_SGMII_EN)); + + reg_val = athrs17_reg_read(S17_PWS_REG); + athrs17_reg_write(S17_PWS_REG, (reg_val | + S17c_PWS_SERDES_ANEG_DISABLE)); + + athrs17_reg_write(S17_SGMII_CTRL_REG,(S17c_SGMII_EN_PLL | + S17c_SGMII_EN_RX | + S17c_SGMII_EN_TX | + S17c_SGMII_EN_SD | + S17c_SGMII_BW_HIGH | + S17c_SGMII_SEL_CLK125M | + S17c_SGMII_TXDR_CTRL_600mV | + S17c_SGMII_CDR_BW_8 | + S17c_SGMII_DIS_AUTO_LPI_25M | + S17c_SGMII_MODE_CTRL_SGMII_PHY | + S17c_SGMII_PAUSE_SG_TX_EN_25M | + S17c_SGMII_ASYM_PAUSE_25M | + S17c_SGMII_PAUSE_25M | + S17c_SGMII_HALF_DUPLEX_25M | + S17c_SGMII_FULL_DUPLEX_25M)); +} + +struct athrs17_regmap { + uint32_t start; + uint32_t end; +}; + +struct athrs17_regmap regmap[] = { + { 0x000, 0x0e0 }, + { 0x100, 0x168 }, + { 0x200, 0x270 }, + { 0x400, 0x454 }, + { 0x600, 0x718 }, + { 0x800, 0xb70 }, + { 0xC00, 0xC80 }, +}; + +int do_ar8xxx_dump(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { + int i; + + for (i = 0; i < ARRAY_SIZE(regmap); i++) { + uint32_t reg; + struct athrs17_regmap *section = ®map[i]; + + for (reg = section->start; reg <= section->end; reg += sizeof(uint32_t)) { + uint32_t val = athrs17_reg_read(reg); + printf("%03zx: %08zx\n", reg, val); + } + } + + return 0; +}; +U_BOOT_CMD( + ar8xxx_dump, 1, 1, do_ar8xxx_dump, + "Dump ar8xxx registers", + "\n - print all ar8xxx registers\n" +); + +/********************************************************************* + * + * FUNCTION DESCRIPTION: This function invokes RGMII, + * SGMII switch init routines. + * INPUT : ipq_gmac_board_cfg_t * + * OUTPUT: NONE + * +**********************************************************************/ +int ipq_athrs17_init(ipq_gmac_board_cfg_t *gmac_cfg) +{ + int ret; + + if (gmac_cfg == NULL) + return -1; + + ret = athrs17_init_switch(); + if (ret != -1) { + athrs17_reg_init(gmac_cfg); + athrs17_reg_init_lan(gmac_cfg); + athrs17_vlan_config(); + printf ("S17c init done\n"); + } + + return ret; +} diff --git a/drivers/net/ipq5018/ipq5018_gmac.c b/drivers/net/ipq5018/ipq5018_gmac.c index 0c4ef71fc2..afa77afdf7 100644 --- a/drivers/net/ipq5018/ipq5018_gmac.c +++ b/drivers/net/ipq5018/ipq5018_gmac.c @@ -1,5 +1,5 @@ /* -* Copyright (c) 2019 The Linux Foundation. All rights reserved. +* Copyright (c) 2019-2020 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 @@ -18,9 +18,7 @@ #include #include #include -#include #include -#include #include "ipq_phy.h" #include @@ -39,10 +37,14 @@ uchar ipq_def_enetaddr[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55}; phy_info_t *phy_info[IPQ5018_PHY_MAX] = {0}; extern int ipq_mdio_read(int mii_id, int regnum, ushort *data); +extern int ipq5018_mdio_read(int mii_id, int regnum, ushort *data); extern int ipq_qca8033_phy_init(struct phy_ops **ops, u32 phy_id); -extern void ipq_qca8075_phy_map_ops(struct phy_ops **ops); extern int ipq_qca8081_phy_init(struct phy_ops **ops, u32 phy_id); +extern int ipq_gephy_phy_init(struct phy_ops **ops, u32 phy_id); extern int ipq_sw_mdio_init(const char *); +extern int ipq5018_sw_mdio_init(const char *); +extern void ppe_uniphy_mode_set(uint32_t mode); +extern int ipq_athrs17_init(ipq_gmac_board_cfg_t *gmac_cfg); static int ipq_eth_wr_macaddr(struct eth_device *dev) { @@ -238,69 +240,146 @@ static inline u32 ipq_gmac_is_desc_empty(ipq_gmac_desc_t *fr) { return ((fr->length & DescSize1Mask) == 0); } -#if 0 -static int ipq_eth_update(struct eth_device *dev, bd_t *this) +static void ipq5018_gmac0_speed_clock_set(int speed_clock1, + int speed_clock2, int gmacid) +{ + int iTxRx; + uint32_t reg_value; + /* + * iTxRx indicates Tx and RX register + * 0 = Rx and 1 = Tx + */ + for (iTxRx = 0; iTxRx < 2; ++iTxRx){ + /* gcc port first clock divider */ + reg_value = 0; + reg_value = readl(GCC_GMAC0_RX_CFG_RCGR + + (iTxRx * 8) + (gmacid * 0x10)); + reg_value &= ~0x71f; + reg_value |= speed_clock1; + writel(reg_value, GCC_GMAC0_RX_CFG_RCGR + + (iTxRx * 8) + (gmacid * 0x10)); + /* gcc port second clock divider */ + reg_value = 0; + reg_value = readl(GCC_GMAC0_RX_MISC + + (iTxRx * 4) + (gmacid * 0x10)); + reg_value &= ~0xf; + reg_value |= speed_clock2; + writel(reg_value, GCC_GMAC0_RX_MISC + + (iTxRx * 4) + (gmacid * 0x10)); + /* update above clock configuration */ + reg_value = 0; + reg_value = readl(GCC_GMAC0_RX_CMD_RCGR + + (iTxRx * 8) + (gmacid * 0x10)); + reg_value &= ~0x1; + reg_value |= 0x1; + writel(reg_value, GCC_GMAC0_RX_CMD_RCGR + + (iTxRx * 8) + (gmacid * 0x10)); + } +} + +static int ipq5018_phy_link_update(struct eth_device *dev) { struct ipq_eth_dev *priv = dev->priv; - struct phy_ops *phy_get_ops = priv->ops[priv->mac_unit]; - uint phy_status; - uint cur_speed; - uint cur_duplex; + int i; + u8 status; + struct phy_ops *phy_get_ops; + fal_port_speed_t speed; + fal_port_duplex_t duplex; + char *lstatus[] = {"up", "Down"}; + char *dp[] = {"Half", "Full"}; + int speed_clock1 = 0, speed_clock2 = 0; - phy_status = phy_get_ops->phy_get_link_status(priv->mac_unit, priv->phy_address); - phy_get_ops->phy_get_speed(priv->mac_unit, priv->phy_address, &curr_speed); - phy_get_ops->phy_get_duplex(priv->mac_unit, priv->phy_address, &duplex); + for (i = 0; i < IPQ5018_PHY_MAX; i++) { - if (cur_speed != priv->speed || cur_duplex != priv->duplex) { - ipq_info("Link %x status changed\n", priv->mac_unit); - if (priv->duplex) - ipq_info("Full duplex link\n"); - else - ipq_info("Half duplex link\n"); - - ipq_info("Link %x up, Phy_status = %x\n", - priv->mac_unit, phy_status); - - switch (cur_speed) { - case SPEED_1000M: - ipq_info("Port:%d speed 1000Mbps\n", - priv->mac_unit); - priv->mac_ps = GMII_PORT_SELECT; - break; - - case SPEED_100M: - ipq_info("Port:%d speed 100Mbps\n", - priv->mac_unit); - priv->mac_ps = MII_PORT_SELECT; - break; - - case SPEED_10M: - ipq_info("Port:%d speed 10Mbps\n", - priv->mac_unit); - priv->mac_ps = MII_PORT_SELECT; - break; - - default: - ipq_info("Port speed unknown\n"); - return -1; - } - - priv->speed = cur_speed; - priv->duplex = cur_duplex; + phy_get_ops = priv->ops[i]; + if (!phy_get_ops || !phy_get_ops->phy_get_link_status || + !phy_get_ops->phy_get_speed || + !phy_get_ops->phy_get_duplex) { + printf ("Link status/Get speed/Get duplex not mapped\n"); + return -1; } + status = phy_get_ops->phy_get_link_status(priv->mac_unit, + priv->phy_address); + phy_get_ops->phy_get_speed(priv->mac_unit, + priv->phy_address, &speed); + phy_get_ops->phy_get_duplex(priv->mac_unit, + priv->phy_address, &duplex); + + switch (speed) { + case FAL_SPEED_10: + speed_clock1 = 0x109; + speed_clock2 = 0x9; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + case FAL_SPEED_100: + speed_clock1 = 0x101; + speed_clock2 = 0x4; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + case FAL_SPEED_1000: + speed_clock1 = 0x101; + speed_clock2 = 0x0; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + case FAL_SPEED_10000: + speed_clock1 = 0x101; + speed_clock2 = 0x0; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + case FAL_SPEED_2500: + speed_clock1 = 0x107; + speed_clock2 = 0x0; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + case FAL_SPEED_5000: + speed_clock2 = 0x1; + speed_clock2 = 0x0; + printf ("eth%d PHY%d %s Speed :%d %s duplex\n", + priv->mac_unit, i, lstatus[status], speed, + dp[duplex]); + break; + default: + printf("Unknown speed\n"); + break; + } + } + if (priv->mac_unit){ + if (priv->phy_type == QCA8081_PHY_TYPE) + ppe_uniphy_mode_set(PORT_WRAPPER_SGMII_PLUS); + else + ppe_uniphy_mode_set(PORT_WRAPPER_SGMII_FIBER); + } + + ipq5018_gmac0_speed_clock_set(speed_clock1, speed_clock2, priv->mac_unit); + + if (status) { + /* No PHY link is alive */ + return -1; + } + return 0; } -#endif + int ipq_eth_init(struct eth_device *dev, bd_t *this) { struct ipq_eth_dev *priv = dev->priv; struct eth_dma_regs *dma_reg = (struct eth_dma_regs *)priv->dma_regs_p; u32 data; -#if 0 - ipq_phy_link_status(dev); -#endif + + if(ipq5018_phy_link_update(dev) < 0); + priv->next_rx = 0; priv->next_tx = 0; @@ -455,8 +534,7 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) { struct eth_device *dev[CONFIG_IPQ_NO_MACS]; uchar enet_addr[CONFIG_IPQ_NO_MACS * 6]; - char ethaddr[32] = "ethaddr"; - int i, phy_id; + int i; uint32_t phy_chip_id, phy_chip_id1, phy_chip_id2; int ret; memset(enet_addr, 0, sizeof(enet_addr)); @@ -468,11 +546,11 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) dev[i] = malloc(sizeof(struct eth_device)); if (dev[i] == NULL) - goto failed; + goto init_failed; ipq_gmac_macs[i] = malloc(sizeof(struct ipq_eth_dev)); if (ipq_gmac_macs[i] == NULL) - goto failed; + goto init_failed; memset(dev[i], 0, sizeof(struct eth_device)); memset(ipq_gmac_macs[i], 0, sizeof(struct ipq_eth_dev)); @@ -484,12 +562,9 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) dev[i]->send = ipq_eth_send; dev[i]->write_hwaddr = ipq_eth_wr_macaddr; dev[i]->priv = (void *) ipq_gmac_macs[i]; - - snprintf(dev[i]->name, sizeof(dev[i]->name), "eth%d", i); - /* - * Setting the Default MAC address if the MAC read from ART partition - * is invalid. + * Setting the Default MAC address + * if the MAC read from ART partition is invalid */ if ((ret < 0) || (!is_valid_ethaddr(&enet_addr[i * 6]))) { @@ -507,7 +582,7 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) dev[i]->enetaddr[4], dev[i]->enetaddr[5]); - snprintf(ethaddr, sizeof(ethaddr), "eth%daddr", (i + 1)); + snprintf(dev[i]->name, sizeof(dev[i]->name), "eth%d", i); ipq_gmac_macs[i]->dev = dev[i]; ipq_gmac_macs[i]->mac_unit = gmac_cfg->unit; @@ -515,82 +590,88 @@ int ipq_gmac_init(ipq_gmac_board_cfg_t *gmac_cfg) (struct eth_mac_regs *)(gmac_cfg->base); ipq_gmac_macs[i]->dma_regs_p = (struct eth_dma_regs *)(gmac_cfg->base + DW_DMA_BASE_OFFSET); -#if 0 - ipq_gmac_macs[i]->interface = gmac_cfg->phy; - ipq_gmac_macs[i]->phy_address = gmac_cfg->phy_addr.addr; - ipq_gmac_macs[i]->no_of_phys = gmac_cfg->phy_addr.count; -#endif ipq_gmac_macs[i]->phy_address = gmac_cfg->phy_addr; ipq_gmac_macs[i]->gmac_board_cfg = gmac_cfg; + ipq_gmac_macs[i]->interface = gmac_cfg->phy_interface_mode; + ipq_gmac_macs[i]->phy_type = gmac_cfg->phy_type; + ipq_gmac_macs[i]->ipq_swith = gmac_cfg->ipq_swith; -#if 0 - if (get_params.gmac_port == gmac_cfg->unit) { - ipq_gmac_macs[i]->forced_params = &get_params; - } -#endif - /* tx/rx Descriptor initialization */ - if (ipq_gmac_tx_rx_desc_ring(dev[i]->priv) == -1) - goto failed; -#if 0 - if(ipq_gmac_macs[i]->mac_unit == 0) - ipq_gmac_macs[i]->speed = SPEED_10M; - else - ipq_gmac_macs[i]->speed = SPEED_1000M; -#endif + strlcpy((char *)ipq_gmac_macs[i]->phy_name, + gmac_cfg->phy_name, + sizeof(ipq_gmac_macs[i]->phy_name)); - strlcpy((char *)ipq_gmac_macs[i]->phy_name, gmac_cfg->phy_name, - sizeof(ipq_gmac_macs[i]->phy_name)); + phy_chip_id = -1; -if (0){ - if (ipq_sw_mdio_init(gmac_cfg->phy_name)) - goto failed; - - for (phy_id = 0; phy_id < 2; phy_id++) { -#if 0 - if (phy_node >= 0) { - phy_addr = phy_info[phy_id]->phy_address; + if (gmac_cfg->unit){ + ret = ipq_sw_mdio_init(gmac_cfg->phy_name); + if (ret) + goto init_failed; + if (ipq_gmac_macs[i]->ipq_swith){ + ipq_athrs17_init(gmac_cfg); } else { - if (phy_id == port_8033) - phy_addr = QCA8033_PHY_ADDR; - else if (phy_id == aquantia_port) - phy_addr = AQU_PHY_ADDR; - else - phy_addr = phy_id; + phy_chip_id1 = ipq_mdio_read( + ipq_gmac_macs[i]->phy_address, + QCA_PHY_ID1, NULL); + phy_chip_id2 = ipq_mdio_read( + ipq_gmac_macs[i]->phy_address, + QCA_PHY_ID2, NULL); + phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2; } -#endif - phy_chip_id1 = ipq_mdio_read( - ipq_gmac_macs[i]->phy_address, QCA_PHY_ID1, NULL); - phy_chip_id2 = ipq_mdio_read( - ipq_gmac_macs[i]->phy_address, QCA_PHY_ID2, NULL); + } else { + ret = ipq5018_sw_mdio_init(gmac_cfg->phy_name); + if (ret) + goto init_failed; + phy_chip_id1 = ipq5018_mdio_read(ipq_gmac_macs[i]->phy_address, + QCA_PHY_ID1, NULL); + phy_chip_id2 = ipq5018_mdio_read(ipq_gmac_macs[i]->phy_address, + QCA_PHY_ID2, NULL); phy_chip_id = (phy_chip_id1 << 16) | phy_chip_id2; - - switch(phy_chip_id) { - case QCA8033_PHY: - ipq_qca8033_phy_init( - &ipq_gmac_macs[i]->ops[phy_id], - ipq_gmac_macs[i]->phy_address); - break; - case QCA8081_PHY: - case QCA8081_1_1_PHY: - ipq_qca8081_phy_init( - &ipq_gmac_macs[i]->ops[phy_id], - ipq_gmac_macs[i]->phy_address); - break; - default: - ipq_qca8075_phy_map_ops(&ipq_gmac_macs[i]->ops[phy_id]); - break; - } } -} - eth_register(dev[i]); + + switch(phy_chip_id) { + /* + * NAPA PHY For GMAC1 + */ + case QCA8081_PHY: + case QCA8081_1_1_PHY: + ipq_qca8081_phy_init( + &ipq_gmac_macs[i]->ops[i], + ipq_gmac_macs[i]->phy_address); + break; + /* + * Internel GEPHY only for GMAC0 + */ + case GEPHY: + ipq_gephy_phy_init( + &ipq_gmac_macs[i]->ops[i], + ipq_gmac_macs[i]->phy_address); + break; + /* + * 1G PHY + */ + case QCA8033_PHY: + ipq_qca8033_phy_init( + &ipq_gmac_macs[i]->ops[i], + ipq_gmac_macs[i]->phy_address); + break; + default: + printf("GMAC%d : Invalid PHY ID \n", i); + break; + } + /* + * Tx/Rx Descriptor initialization + */ + if (ipq_gmac_tx_rx_desc_ring(dev[i]->priv) == -1) + goto init_failed; + + eth_register(dev[i]); } return 0; -failed: +init_failed: for (i = 0; i < IPQ5018_GMAC_PORT; i++) { if (dev[i]) { - eth_unregister(dev[i]); free(dev[i]); } if (ipq_gmac_macs[i]) diff --git a/drivers/net/ipq5018/ipq5018_mdio.c b/drivers/net/ipq5018/ipq5018_mdio.c new file mode 100644 index 0000000000..8f4bf24db7 --- /dev/null +++ b/drivers/net/ipq5018/ipq5018_mdio.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2015-2017, 2020 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 "ipq5018_mdio.h" + +struct ipq5018_mdio_data { + struct mii_bus *bus; + int phy_irq[PHY_MAX_ADDR]; +}; + +static int ipq5018_mdio_wait_busy(void) +{ + int i; + u32 busy; + for (i = 0; i < IPQ5018_MDIO_RETRY; i++) { + udelay(IPQ5018_MDIO_DELAY); + busy = readl(IPQ5018_MDIO_BASE + + MDIO_CTRL_4_REG) & + MDIO_CTRL_4_ACCESS_BUSY; + + if (!busy) + return 0; + udelay(IPQ5018_MDIO_DELAY); + } + printf("%s: MDIO operation timed out\n", + __func__); + return -ETIMEDOUT; +} + +int ipq5018_mdio_write(int mii_id, int regnum, u16 value) +{ + u32 cmd; + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + + + if (regnum & MII_ADDR_C45) { + unsigned int mmd = (regnum >> 16) & 0x1F; + unsigned int reg = regnum & 0xFFFF; + + writel(CTRL_0_REG_C45_DEFAULT_VALUE, + IPQ5018_MDIO_BASE + MDIO_CTRL_0_REG); + + /* Issue the phy address and reg */ + writel((mii_id << 8) | mmd, + IPQ5018_MDIO_BASE + MDIO_CTRL_1_REG); + + writel(reg, IPQ5018_MDIO_BASE + MDIO_CTRL_2_REG); + + /* issue read command */ + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_C45_ADDR; + + writel(cmd, IPQ5018_MDIO_BASE + MDIO_CTRL_4_REG); + + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + } else { + writel(CTRL_0_REG_DEFAULT_VALUE, + IPQ5018_MDIO_BASE + MDIO_CTRL_0_REG); + + /* Issue the phy addreass and reg */ + writel((mii_id << 8 | regnum), + IPQ5018_MDIO_BASE + MDIO_CTRL_1_REG); + } + + /* Issue a write data */ + writel(value, IPQ5018_MDIO_BASE + MDIO_CTRL_2_REG); + + if (regnum & MII_ADDR_C45) { + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_C45_WRITE ; + } else { + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_WRITE ; + } + + writel(cmd, IPQ5018_MDIO_BASE + MDIO_CTRL_4_REG); + /* Wait for write complete */ + + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + + return 0; +} + +int ipq5018_mdio_read(int mii_id, int regnum, ushort *data) +{ + u32 val,cmd; + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + + if (regnum & MII_ADDR_C45) { + + unsigned int mmd = (regnum >> 16) & 0x1F; + unsigned int reg = regnum & 0xFFFF; + + writel(CTRL_0_REG_C45_DEFAULT_VALUE, + IPQ5018_MDIO_BASE + MDIO_CTRL_0_REG); + + /* Issue the phy address and reg */ + writel((mii_id << 8) | mmd, + IPQ5018_MDIO_BASE + MDIO_CTRL_1_REG); + + + writel(reg, IPQ5018_MDIO_BASE + MDIO_CTRL_2_REG); + + /* issue read command */ + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_C45_ADDR; + } else { + + writel(CTRL_0_REG_DEFAULT_VALUE, + IPQ5018_MDIO_BASE + MDIO_CTRL_0_REG); + + /* Issue the phy address and reg */ + writel((mii_id << 8 | regnum ) , + IPQ5018_MDIO_BASE + MDIO_CTRL_1_REG); + + /* issue read command */ + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_READ ; + } + + /* issue read command */ + writel(cmd, IPQ5018_MDIO_BASE + MDIO_CTRL_4_REG); + + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + + + if (regnum & MII_ADDR_C45) { + cmd = MDIO_CTRL_4_ACCESS_START | MDIO_CTRL_4_ACCESS_CODE_C45_READ; + writel(cmd, IPQ5018_MDIO_BASE + MDIO_CTRL_4_REG); + + if (ipq5018_mdio_wait_busy()) + return -ETIMEDOUT; + } + + /* Read data */ + val = readl(IPQ5018_MDIO_BASE + MDIO_CTRL_3_REG); + + if (data != NULL) + *data = val; + + return val; +} + +int ipq5018_phy_write(struct mii_dev *bus, + int addr, int dev_addr, + int regnum, ushort value) +{ + return ipq5018_mdio_write(addr, regnum, value); +} + +int ipq5018_phy_read(struct mii_dev *bus, + int addr, int dev_addr, int regnum) +{ + return ipq5018_mdio_read(addr, regnum, NULL); +} + +int ipq5018_sw_mdio_init(const char *name) +{ + struct mii_dev *bus = mdio_alloc(); + if(!bus) { + printf("Failed to allocate IPQ5018 MDIO bus\n"); + return -1; + } + bus->read = ipq5018_phy_read; + bus->write = ipq5018_phy_write; + bus->reset = NULL; + snprintf(bus->name, MDIO_NAME_LEN, name); + return mdio_register(bus); +} + +static int do_ipq5018_mdio(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + char op[2]; + unsigned int addr = 0, reg = 0; + unsigned short data = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + op[0] = argv[1][0]; + if (strlen(argv[1]) > 1) + op[1] = argv[1][1]; + else + op[1] = '\0'; + + if (argc >= 3) + addr = simple_strtoul(argv[2], NULL, 16); + if (argc >= 4) + reg = simple_strtoul(argv[3], NULL, 16); + if (argc >= 5) + data = simple_strtoul(argv[4], NULL, 16); + + if (op[0] == 'r') { + data = ipq5018_mdio_read(addr, reg, NULL); + printf("0x%x\n", data); + } else if (op[0] == 'w') { + ipq5018_mdio_write(addr, reg, data); + } else { + return CMD_RET_USAGE; + } + + return 0; +} + +U_BOOT_CMD( + ipq5018_mdio, 5, 1, do_ipq5018_mdio, + "IPQ5018 mdio utility commands", + "ipq5018_mdio read - read IPQ5018 MDIO PHY register \n" + "ipq5018_mdio write - write IPQ5018 MDIO PHY register \n" + "Addr and/or reg may be ranges, e.g. 0-7." +); diff --git a/drivers/net/ipq5018/ipq5018_mdio.h b/drivers/net/ipq5018/ipq5018_mdio.h new file mode 100644 index 0000000000..857dfe1622 --- /dev/null +++ b/drivers/net/ipq5018/ipq5018_mdio.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2015-2017, 2020 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 _IPQ5018_MDIO_H +#define _IPQ5018_MDIO_H + +#define IPQ5018_MDIO_BASE 0x88000 +#define MDIO_CTRL_0_REG 0x40 +#define MDIO_CTRL_1_REG 0x44 +#define MDIO_CTRL_2_REG 0x48 +#define MDIO_CTRL_3_REG 0x4c +#define MDIO_CTRL_4_REG 0x50 +#define MDIO_CTRL_4_ACCESS_BUSY (1 << 16) +#define MDIO_CTRL_4_ACCESS_START (1 << 8) +#define MDIO_CTRL_4_ACCESS_CODE_READ 0 +#define MDIO_CTRL_4_ACCESS_CODE_WRITE 1 +#define MDIO_CTRL_4_ACCESS_CODE_C45_ADDR 0 +#define MDIO_CTRL_4_ACCESS_CODE_C45_WRITE 1 +#define MDIO_CTRL_4_ACCESS_CODE_C45_READ 2 +#define CTRL_0_REG_DEFAULT_VALUE 0x1500F +#ifdef MDIO_12_5_MHZ +#define CTRL_0_REG_C45_DEFAULT_VALUE 0x15107 +#else +#define CTRL_0_REG_C45_DEFAULT_VALUE 0x1510F +#endif +#define IPQ5018_MDIO_RETRY 1000 +#define IPQ5018_MDIO_DELAY 5 +#endif /* End _IPQ5018_MDIO_H */ diff --git a/drivers/net/ipq5018/ipq5018_uniphy.c b/drivers/net/ipq5018/ipq5018_uniphy.c new file mode 100644 index 0000000000..616ff31590 --- /dev/null +++ b/drivers/net/ipq5018/ipq5018_uniphy.c @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017-2020, 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 "ipq5018_uniphy.h" +#include "ipq_phy.h" + +static int ppe_uniphy_calibration(void) +{ + int retries = 100, calibration_done = 0; + uint32_t reg_value = 0; + + while(calibration_done != UNIPHY_CALIBRATION_DONE) { + mdelay(1); + if (retries-- == 0) { + printf("uniphy callibration time out!\n"); + return -1; + } + reg_value = readl(PPE_UNIPHY_BASE + PPE_UNIPHY_OFFSET_CALIB_4); + calibration_done = (reg_value >> 0x7) & 0x1; + } + + return 0; +} + +static void ppe_gcc_uniphy_soft_reset(void) +{ + uint32_t reg_value; + + reg_value = readl(GCC_UNIPHY0_MISC); + + reg_value |= GCC_UNIPHY_SGMII_SOFT_RESET; + + writel(reg_value, GCC_UNIPHY0_MISC); + + udelay(500); + + reg_value &= ~GCC_UNIPHY_SGMII_SOFT_RESET; + + writel(reg_value, GCC_UNIPHY0_MISC); +} + +static void ppe_uniphy_sgmii_mode_set(uint32_t mode) +{ + writel(UNIPHY_MISC2_REG_SGMII_MODE, + PPE_UNIPHY_BASE + UNIPHY_MISC2_REG_OFFSET); + + writel(UNIPHY_PLL_RESET_REG_VALUE, PPE_UNIPHY_BASE + + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + writel(UNIPHY_PLL_RESET_REG_DEFAULT_VALUE, PPE_UNIPHY_BASE + + UNIPHY_PLL_RESET_REG_OFFSET); + mdelay(500); + + writel(0x0, GCC_UNIPHY_RX_CBCR); + writel(0x0, GCC_UNIPHY_TX_CBCR); + writel(0x0, GCC_GMAC1_RX_CBCR); + writel(0x0, GCC_GMAC1_TX_CBCR); + + switch (mode) { + case PORT_WRAPPER_SGMII_FIBER: + writel(UNIPHY_SG_MODE, PPE_UNIPHY_BASE + PPE_UNIPHY_MODE_CONTROL); + break; + + case PORT_WRAPPER_SGMII0_RGMII4: + case PORT_WRAPPER_SGMII1_RGMII4: + case PORT_WRAPPER_SGMII4_RGMII4: + writel((UNIPHY_SG_MODE | UNIPHY_PSGMII_MAC_MODE), + PPE_UNIPHY_BASE + PPE_UNIPHY_MODE_CONTROL); + break; + + case PORT_WRAPPER_SGMII_PLUS: + writel((UNIPHY_SG_PLUS_MODE | UNIPHY_PSGMII_MAC_MODE), + PPE_UNIPHY_BASE + PPE_UNIPHY_MODE_CONTROL); + break; + + default: + printf("SGMII Config. wrongly"); + break; + } + + ppe_gcc_uniphy_soft_reset(); + + writel(0x1, GCC_UNIPHY_RX_CBCR); + writel(0x1, GCC_UNIPHY_TX_CBCR); + writel(0x1, GCC_GMAC1_RX_CBCR); + writel(0x1, GCC_GMAC1_TX_CBCR); + + ppe_uniphy_calibration(); +} + +void ppe_uniphy_mode_set(uint32_t mode) +{ + /* + * SGMII and SHMII plus confugure in same function + */ + ppe_uniphy_sgmii_mode_set(mode); +} + diff --git a/drivers/net/ipq5018/ipq5018_uniphy.h b/drivers/net/ipq5018/ipq5018_uniphy.h new file mode 100644 index 0000000000..de1f599adf --- /dev/null +++ b/drivers/net/ipq5018/ipq5018_uniphy.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017-2020, 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 _IPQ5018_UNIPHY_H_ +#define _IPQ5018_UNIPHY_H + +#define PPE_UNIPHY_INSTANCE0 0 + +#define GCC_UNIPHY_RX_CBCR 0x01856110 +#define GCC_UNIPHY_TX_CBCR 0x01856114 + +#define GCC_GMAC1_RX_CBCR 0x01868248 +#define GCC_GMAC1_TX_CBCR 0x0186824C + +#define GCC_UNIPHY0_MISC 0x01856004 + +#define PPE_UNIPHY_OFFSET_CALIB_4 0x1E0 +#define UNIPHY_CALIBRATION_DONE 0x1 + +#define GCC_UNIPHY_PSGMII_SOFT_RESET 0x3ff2 +#define GCC_UNIPHY_SGMII_SOFT_RESET 0x32 + +#define PPE_UNIPHY_BASE 0x00098000 +#define PPE_UNIPHY_MODE_CONTROL 0x46C +#define UNIPHY_XPCS_MODE (1 << 12) +#define UNIPHY_SG_PLUS_MODE (1 << 11) +#define UNIPHY_SG_MODE (1 << 10) +#define UNIPHY_CH0_PSGMII_QSGMII (1 << 9) +#define UNIPHY_CH0_QSGMII_SGMII (1 << 8) +#define UNIPHY_PSGMII_MAC_MODE (1 << 5) +#define UNIPHY_CH4_CH1_0_SGMII (1 << 2) +#define UNIPHY_CH1_CH0_SGMII (1 << 1) +#define UNIPHY_CH0_ATHR_CSCO_MODE_25M (1 << 0) + +#define UNIPHY_INSTANCE_LINK_DETECT 0x570 + +#define UNIPHY_MISC2_REG_OFFSET 0x218 +#define UNIPHY_MISC2_REG_SGMII_MODE 0x30 +#define UNIPHY_MISC2_REG_SGMII_PLUS_MODE 0x50 + +#define UNIPHY_MISC2_REG_VALUE 0x70 + +#define UNIPHY_PLL_RESET_REG_OFFSET 0x780 +#define UNIPHY_PLL_RESET_REG_VALUE 0x02bf +#define UNIPHY_PLL_RESET_REG_DEFAULT_VALUE 0x02ff + +void ppe_uniphy_mode_set(uint32_t mode); +#endif diff --git a/drivers/net/ipq_common/ipq_gephy.c b/drivers/net/ipq_common/ipq_gephy.c new file mode 100644 index 0000000000..90b1c130fe --- /dev/null +++ b/drivers/net/ipq_common/ipq_gephy.c @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018, 2020 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 "ipq_gephy.h" +#include "ipq_phy.h" + +extern int ipq5018_mdio_read(int mii_id, + int regnum, ushort *data); +extern int ipq5018_mdio_write(int mii_id, + int regnum, u16 data); + +u16 gephy_phy_reg_read(u32 dev_id, u32 phy_id, u32 reg_id) +{ + return ipq5018_mdio_read(phy_id, reg_id, NULL); +} + +u16 gephy_phy_reg_write(u32 dev_id, u32 phy_id, u32 reg_id, u16 value) +{ + return ipq5018_mdio_write(phy_id, reg_id, value); +} + +u8 gephy_phy_get_link_status(u32 dev_id, u32 phy_id) +{ + u16 phy_data; + phy_data = gephy_phy_reg_read(dev_id, + phy_id, GEPHY_PHY_SPEC_STATUS); + if (phy_data & GEPHY_STATUS_LINK_PASS) + return 0; + + return 1; +} + +u32 gephy_phy_get_duplex(u32 dev_id, u32 phy_id, fal_port_duplex_t *duplex) +{ + u16 phy_data; + + phy_data = gephy_phy_reg_read(dev_id, phy_id, + GEPHY_PHY_SPEC_STATUS); + + /* + * Read duplex + */ + if (phy_data & GEPHY_STATUS_FULL_DUPLEX) + *duplex = FAL_FULL_DUPLEX; + else + *duplex = FAL_HALF_DUPLEX; + + return 0; +} + +u32 gephy_phy_get_speed(u32 dev_id, u32 phy_id, fal_port_speed_t *speed) +{ + u16 phy_data; + + phy_data = gephy_phy_reg_read(dev_id, + phy_id, GEPHY_PHY_SPEC_STATUS); + + switch (phy_data & GEPHY_STATUS_SPEED_MASK) { + case GEPHY_STATUS_SPEED_2500MBS: + *speed = FAL_SPEED_2500; + break; + case GEPHY_STATUS_SPEED_1000MBS: + *speed = FAL_SPEED_1000; + break; + case GEPHY_STATUS_SPEED_100MBS: + *speed = FAL_SPEED_100; + break; + case GEPHY_STATUS_SPEED_10MBS: + *speed = FAL_SPEED_10; + break; + default: + return -EINVAL; + } + return 0; +} + +int ipq_gephy_phy_init(struct phy_ops **ops, u32 phy_id) +{ + u16 phy_data; + struct phy_ops *gephy_ops; + + gephy_ops = (struct phy_ops *)malloc(sizeof(struct phy_ops)); + if (!gephy_ops) + return -ENOMEM; + gephy_ops->phy_get_link_status = gephy_phy_get_link_status; + gephy_ops->phy_get_speed = gephy_phy_get_speed; + gephy_ops->phy_get_duplex = gephy_phy_get_duplex; + *ops = gephy_ops; + + phy_data = gephy_phy_reg_read(0x0, phy_id, GEPHY_PHY_ID1); + printf ("PHY ID1: 0x%x\n", phy_data); + phy_data = gephy_phy_reg_read(0x0, phy_id, GEPHY_PHY_ID2); + printf ("PHY ID2: 0x%x\n", phy_data); + + /*enable vga when init napa to fix 8023az issue*/ + phy_data = gephy_phy_reg_read(0x0, phy_id, QCA808X_8023AZ_ENABLE_VGA); + phy_data &= (~QCA808X_PHY_8023AZ_AFE_CTRL_MASK); + phy_data |= QCA808X_PHY_8023AZ_AFE_EN; + phy_data = gephy_phy_reg_write(0x0, phy_id, QCA808X_8023AZ_ENABLE_VGA, phy_data); + if (phy_data != 0) + return phy_data; + + /*special configuration for AZ under 1G speed mode*/ + phy_data = QCA808X_PHY_MMD3_AZ_TRAINING_VAL; + phy_data = gephy_phy_reg_write(0x0, phy_id, QCA808X_AZ_CONFIG_UNDER_1G_SPEED, + phy_data); + return phy_data; +} diff --git a/drivers/net/ipq_common/ipq_gephy.h b/drivers/net/ipq_common/ipq_gephy.h new file mode 100644 index 0000000000..1491bfd4c4 --- /dev/null +++ b/drivers/net/ipq_common/ipq_gephy.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2018, 2020 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 _IPQ_GEPHY_H_ +#define _IPQ_GEPHY_H_ + +/* PHY Registers */ +#define GEPHY_PHY_CONTROL 0 +#define GEPHY_PHY_STATUS 1 +#define GEPHY_PHY_SPEC_STATUS 17 + +#define GEPHY_PHY_ID1 2 +#define GEPHY_PHY_ID2 3 +#define GEPHY_AUTONEG_ADVERT 4 +#define GEPHY_LINK_PARTNER_ABILITY 5 +#define GEPHY_1000BASET_CONTROL 9 +#define GEPHY_1000BASET_STATUS 10 +#define GEPHY_MMD_CTRL_REG 13 +#define GEPHY_MMD_DATA_REG 14 +#define GEPHY_EXTENDED_STATUS 15 +#define GEPHY_PHY_SPEC_CONTROL 16 +#define GEPHY_PHY_INTR_MASK 18 +#define GEPHY_PHY_INTR_STATUS 19 +#define GEPHY_PHY_CDT_CONTROL 22 +#define GEPHY_DEBUG_PORT_ADDRESS 29 +#define GEPHY_DEBUG_PORT_DATA 30 + +#define GEPHY_STATUS_LINK_PASS 0x0400 + +#define GEPHY_STATUS_FULL_DUPLEX 0x2000 + +#define GEPHY_STATUS_SPEED_MASK 0x380 +#define GEPHY_STATUS_SPEED_2500MBS 0x200 +#define GEPHY_STATUS_SPEED_1000MBS 0x100 +#define GEPHY_STATUS_SPEED_100MBS 0x80 +#define GEPHY_STATUS_SPEED_10MBS 0x0000 + +#define QCA808X_PHY_MMD3_AZ_TRAINING_VAL 0x1c32 +#define QCA808X_PHY_MMD3_NUM 3 +#define QCA808X_PHY_MMD3_ADDR_CLD_CTRL7 0x8007 +#define QCA808X_PHY_MMD3_AZ_TRAINING_CTRL 0x8008 +#define QCA808X_PHY_8023AZ_AFE_CTRL_MASK 0x01f0 +#define QCA808X_PHY_8023AZ_AFE_EN 0x0090 +#define QCA808X_MII_ADDR_C45 (1<<30) +#define QCA808X_REG_C45_ADDRESS(dev_type, reg_num) (QCA808X_MII_ADDR_C45 | \ + ((dev_type & 0x1f) << 16) | (reg_num & 0xffff)) +#define QCA808X_8023AZ_ENABLE_VGA QCA808X_REG_C45_ADDRESS(QCA808X_PHY_MMD3_NUM, \ + QCA808X_PHY_MMD3_ADDR_CLD_CTRL7) +#define QCA808X_AZ_CONFIG_UNDER_1G_SPEED QCA808X_REG_C45_ADDRESS(QCA808X_PHY_MMD3_NUM, \ + QCA808X_PHY_MMD3_AZ_TRAINING_CTRL) + +#endif /* _GEPHY_PHY_H_ */ diff --git a/include/configs/ipq5018.h b/include/configs/ipq5018.h index e6fd13eddc..3b1c9ca263 100644 --- a/include/configs/ipq5018.h +++ b/include/configs/ipq5018.h @@ -220,6 +220,7 @@ extern loff_t board_env_size; */ #define CONFIG_IPQ5018_GMAC +#define CONFIG_IPQ5018_MDIO #define CONFIG_NET_RETRY_COUNT 5 #define CONFIG_SYS_RX_ETH_BUFFER 16 @@ -231,11 +232,17 @@ extern loff_t board_env_size; #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_SERVERIP 192.168.10.19 #define CONFIG_CMD_TFTPPUT -#define CONFIG_IPQ_MDIO 2 +#define CONFIG_IPQ_MDIO 1 #define CONFIG_IPQ_ETH_INIT_DEFER - #define CONFIG_IPQ_NO_MACS 2 +/* + * PHY + */ +#define CONFIG_GEPHY +#define CONFIG_QCA8033_PHY +#define CONFIG_QCA8081_PHY + /* * USB Support */