ipq5018: Update GMAC ethernet driver

This code changes update gmac configuration and
add Gephy, internal Mdio, uniphy and s17c switch.

Signed-off-by: Vandhiadevan Karunamoorthy <vkarunam@codeaurora.org>
Change-Id: I1759b5edf91de9a48f6d8ae46b3481f3a87f10eb
This commit is contained in:
Vandhiadevan Karunamoorthy 2020-04-23 20:52:08 +05:30
parent 6870c76758
commit 577c8ba9dc
16 changed files with 1936 additions and 132 deletions

View file

@ -127,11 +127,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";
};
@ -139,7 +140,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>;
};
};

View file

@ -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

View file

@ -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 <net.h>
#include <configs/ipq5018.h>
#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];

View file

@ -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

View file

@ -567,6 +567,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;
@ -578,6 +644,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++) {
@ -591,12 +666,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);

View file

@ -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
*/
@ -317,9 +345,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;

View file

@ -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

View file

@ -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 <common.h>
#include <asm/arch-ipq5018/athrs17_phy.h>
/*
* 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 = &regmap[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;
}

View file

@ -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 <malloc.h>
#include <phy.h>
#include <net.h>
#include <miiphy.h>
#include <asm/global_data.h>
#include <fdtdec.h>
#include "ipq_phy.h"
#include <asm/arch-ipq5018/ipq5018_gmac.h>
@ -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])

View file

@ -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 <common.h>
#include <command.h>
#include <miiphy.h>
#include <phy.h>
#include <asm/io.h>
#include <errno.h>
#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 <addr> <reg> - read IPQ5018 MDIO PHY <addr> register <reg>\n"
"ipq5018_mdio write <addr> <reg> <data> - write IPQ5018 MDIO PHY <addr> register <reg>\n"
"Addr and/or reg may be ranges, e.g. 0-7."
);

View file

@ -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 */

View file

@ -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 <common.h>
#include <net.h>
#include <asm-generic/errno.h>
#include <asm/io.h>
#include <malloc.h>
#include <phy.h>
#include <net.h>
#include <miiphy.h>
#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);
}

View file

@ -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

View file

@ -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 <common.h>
#include <net.h>
#include <asm-generic/errno.h>
#include <asm/io.h>
#include <malloc.h>
#include <phy.h>
#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;
}

View file

@ -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_ */

View file

@ -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
*/