X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmvpp2.c;h=08adb68aa5322a5a302b03d5f631100afe94054f;hb=dd9999d5f4d3a0354c959fa3bccc0957a1164bf5;hp=9683439d231c224c0fa84da75982497f402e0b28;hpb=16a9898d80d3a3975034126aef8b38611a8ddf3b;p=oweals%2Fu-boot.git diff --git a/drivers/net/mvpp2.c b/drivers/net/mvpp2.c index 9683439d23..08adb68aa5 100644 --- a/drivers/net/mvpp2.c +++ b/drivers/net/mvpp2.c @@ -6,7 +6,7 @@ * Marcin Wojtas * * U-Boot version: - * Copyright (C) 2016 Stefan Roese + * Copyright (C) 2016-2017 Stefan Roese * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any @@ -91,9 +91,11 @@ do { \ #define MVPP2_SNOOP_PKT_SIZE_MASK 0x1ff #define MVPP2_SNOOP_BUF_HDR_MASK BIT(9) #define MVPP2_RXQ_POOL_SHORT_OFFS 20 -#define MVPP2_RXQ_POOL_SHORT_MASK 0x700000 +#define MVPP21_RXQ_POOL_SHORT_MASK 0x700000 +#define MVPP22_RXQ_POOL_SHORT_MASK 0xf00000 #define MVPP2_RXQ_POOL_LONG_OFFS 24 -#define MVPP2_RXQ_POOL_LONG_MASK 0x7000000 +#define MVPP21_RXQ_POOL_LONG_MASK 0x7000000 +#define MVPP22_RXQ_POOL_LONG_MASK 0xf000000 #define MVPP2_RXQ_PACKET_OFFSET_OFFS 28 #define MVPP2_RXQ_PACKET_OFFSET_MASK 0x70000000 #define MVPP2_RXQ_DISABLE_MASK BIT(31) @@ -141,6 +143,7 @@ do { \ /* Descriptor Manager Top Registers */ #define MVPP2_RXQ_NUM_REG 0x2040 #define MVPP2_RXQ_DESC_ADDR_REG 0x2044 +#define MVPP22_DESC_ADDR_OFFS 8 #define MVPP2_RXQ_DESC_SIZE_REG 0x2048 #define MVPP2_RXQ_DESC_SIZE_MASK 0x3ff0 #define MVPP2_RXQ_STATUS_UPDATE_REG(rxq) (0x3000 + 4 * (rxq)) @@ -182,6 +185,7 @@ do { \ #define MVPP2_TXQ_RSVD_CLR_REG 0x20b8 #define MVPP2_TXQ_RSVD_CLR_OFFSET 16 #define MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu) (0x2100 + 4 * (cpu)) +#define MVPP22_AGGR_TXQ_DESC_ADDR_OFFS 8 #define MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu) (0x2140 + 4 * (cpu)) #define MVPP2_AGGR_TXQ_DESC_SIZE_MASK 0x3ff0 #define MVPP2_AGGR_TXQ_STATUS_REG(cpu) (0x2180 + 4 * (cpu)) @@ -194,9 +198,51 @@ do { \ #define MVPP2_WIN_REMAP(w) (0x4040 + ((w) << 2)) #define MVPP2_BASE_ADDR_ENABLE 0x4060 +/* AXI Bridge Registers */ +#define MVPP22_AXI_BM_WR_ATTR_REG 0x4100 +#define MVPP22_AXI_BM_RD_ATTR_REG 0x4104 +#define MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG 0x4110 +#define MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG 0x4114 +#define MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG 0x4118 +#define MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG 0x411c +#define MVPP22_AXI_RX_DATA_WR_ATTR_REG 0x4120 +#define MVPP22_AXI_TX_DATA_RD_ATTR_REG 0x4130 +#define MVPP22_AXI_RD_NORMAL_CODE_REG 0x4150 +#define MVPP22_AXI_RD_SNOOP_CODE_REG 0x4154 +#define MVPP22_AXI_WR_NORMAL_CODE_REG 0x4160 +#define MVPP22_AXI_WR_SNOOP_CODE_REG 0x4164 + +/* Values for AXI Bridge registers */ +#define MVPP22_AXI_ATTR_CACHE_OFFS 0 +#define MVPP22_AXI_ATTR_DOMAIN_OFFS 12 + +#define MVPP22_AXI_CODE_CACHE_OFFS 0 +#define MVPP22_AXI_CODE_DOMAIN_OFFS 4 + +#define MVPP22_AXI_CODE_CACHE_NON_CACHE 0x3 +#define MVPP22_AXI_CODE_CACHE_WR_CACHE 0x7 +#define MVPP22_AXI_CODE_CACHE_RD_CACHE 0xb + +#define MVPP22_AXI_CODE_DOMAIN_OUTER_DOM 2 +#define MVPP22_AXI_CODE_DOMAIN_SYSTEM 3 + /* Interrupt Cause and Mask registers */ #define MVPP2_ISR_RX_THRESHOLD_REG(rxq) (0x5200 + 4 * (rxq)) -#define MVPP2_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) +#define MVPP21_ISR_RXQ_GROUP_REG(rxq) (0x5400 + 4 * (rxq)) + +#define MVPP22_ISR_RXQ_GROUP_INDEX_REG 0x5400 +#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf +#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380 +#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET 7 + +#define MVPP22_ISR_RXQ_GROUP_INDEX_SUBGROUP_MASK 0xf +#define MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_MASK 0x380 + +#define MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG 0x5404 +#define MVPP22_ISR_RXQ_SUB_GROUP_STARTQ_MASK 0x1f +#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_MASK 0xf00 +#define MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET 8 + #define MVPP2_ISR_ENABLE_REG(port) (0x5420 + 4 * (port)) #define MVPP2_ISR_ENABLE_INTERRUPT(mask) ((mask) & 0xffff) #define MVPP2_ISR_DISABLE_INTERRUPT(mask) (((mask) << 16) & 0xffff0000) @@ -251,14 +297,23 @@ do { \ #define MVPP2_BM_PHY_ALLOC_REG(pool) (0x6400 + ((pool) * 4)) #define MVPP2_BM_PHY_ALLOC_GRNTD_MASK BIT(0) #define MVPP2_BM_VIRT_ALLOC_REG 0x6440 +#define MVPP2_BM_ADDR_HIGH_ALLOC 0x6444 +#define MVPP2_BM_ADDR_HIGH_PHYS_MASK 0xff +#define MVPP2_BM_ADDR_HIGH_VIRT_MASK 0xff00 +#define MVPP2_BM_ADDR_HIGH_VIRT_SHIFT 8 #define MVPP2_BM_PHY_RLS_REG(pool) (0x6480 + ((pool) * 4)) #define MVPP2_BM_PHY_RLS_MC_BUFF_MASK BIT(0) #define MVPP2_BM_PHY_RLS_PRIO_EN_MASK BIT(1) #define MVPP2_BM_PHY_RLS_GRNTD_MASK BIT(2) #define MVPP2_BM_VIRT_RLS_REG 0x64c0 -#define MVPP2_BM_MC_RLS_REG 0x64c4 +#define MVPP21_BM_MC_RLS_REG 0x64c4 #define MVPP2_BM_MC_ID_MASK 0xfff #define MVPP2_BM_FORCE_RELEASE_MASK BIT(12) +#define MVPP22_BM_ADDR_HIGH_RLS_REG 0x64c4 +#define MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK 0xff +#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK 0xff00 +#define MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT 8 +#define MVPP22_BM_MC_RLS_REG 0x64d4 /* TX Scheduler registers */ #define MVPP2_TXP_SCHED_PORT_INDEX_REG 0x8000 @@ -300,6 +355,7 @@ do { \ /* Per-port registers */ #define MVPP2_GMAC_CTRL_0_REG 0x0 #define MVPP2_GMAC_PORT_EN_MASK BIT(0) +#define MVPP2_GMAC_PORT_TYPE_MASK BIT(1) #define MVPP2_GMAC_MAX_RX_SIZE_OFFS 2 #define MVPP2_GMAC_MAX_RX_SIZE_MASK 0x7ffc #define MVPP2_GMAC_MIB_CNTR_EN_MASK BIT(15) @@ -311,23 +367,131 @@ do { \ #define MVPP2_GMAC_SA_LOW_OFFS 7 #define MVPP2_GMAC_CTRL_2_REG 0x8 #define MVPP2_GMAC_INBAND_AN_MASK BIT(0) +#define MVPP2_GMAC_SGMII_MODE_MASK BIT(0) #define MVPP2_GMAC_PCS_ENABLE_MASK BIT(3) #define MVPP2_GMAC_PORT_RGMII_MASK BIT(4) +#define MVPP2_GMAC_PORT_DIS_PADING_MASK BIT(5) #define MVPP2_GMAC_PORT_RESET_MASK BIT(6) +#define MVPP2_GMAC_CLK_125_BYPS_EN_MASK BIT(9) #define MVPP2_GMAC_AUTONEG_CONFIG 0xc #define MVPP2_GMAC_FORCE_LINK_DOWN BIT(0) #define MVPP2_GMAC_FORCE_LINK_PASS BIT(1) +#define MVPP2_GMAC_EN_PCS_AN BIT(2) +#define MVPP2_GMAC_AN_BYPASS_EN BIT(3) #define MVPP2_GMAC_CONFIG_MII_SPEED BIT(5) #define MVPP2_GMAC_CONFIG_GMII_SPEED BIT(6) #define MVPP2_GMAC_AN_SPEED_EN BIT(7) #define MVPP2_GMAC_FC_ADV_EN BIT(9) +#define MVPP2_GMAC_EN_FC_AN BIT(11) #define MVPP2_GMAC_CONFIG_FULL_DUPLEX BIT(12) #define MVPP2_GMAC_AN_DUPLEX_EN BIT(13) +#define MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG BIT(15) #define MVPP2_GMAC_PORT_FIFO_CFG_1_REG 0x1c #define MVPP2_GMAC_TX_FIFO_MIN_TH_OFFS 6 #define MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK 0x1fc0 #define MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v) (((v) << 6) & \ MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK) +#define MVPP2_GMAC_CTRL_4_REG 0x90 +#define MVPP2_GMAC_CTRL4_EXT_PIN_GMII_SEL_MASK BIT(0) +#define MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK BIT(5) +#define MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK BIT(6) +#define MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK BIT(7) + +/* + * Per-port XGMAC registers. PPv2.2 only, only for GOP port 0, + * relative to port->base. + */ + +/* Port Mac Control0 */ +#define MVPP22_XLG_CTRL0_REG 0x100 +#define MVPP22_XLG_PORT_EN BIT(0) +#define MVPP22_XLG_MAC_RESETN BIT(1) +#define MVPP22_XLG_RX_FC_EN BIT(7) +#define MVPP22_XLG_MIBCNT_DIS BIT(13) +/* Port Mac Control1 */ +#define MVPP22_XLG_CTRL1_REG 0x104 +#define MVPP22_XLG_MAX_RX_SIZE_OFFS 0 +#define MVPP22_XLG_MAX_RX_SIZE_MASK 0x1fff +/* Port Interrupt Mask */ +#define MVPP22_XLG_INTERRUPT_MASK_REG 0x118 +#define MVPP22_XLG_INTERRUPT_LINK_CHANGE BIT(1) +/* Port Mac Control3 */ +#define MVPP22_XLG_CTRL3_REG 0x11c +#define MVPP22_XLG_CTRL3_MACMODESELECT_MASK (7 << 13) +#define MVPP22_XLG_CTRL3_MACMODESELECT_GMAC (0 << 13) +#define MVPP22_XLG_CTRL3_MACMODESELECT_10GMAC (1 << 13) +/* Port Mac Control4 */ +#define MVPP22_XLG_CTRL4_REG 0x184 +#define MVPP22_XLG_FORWARD_802_3X_FC_EN BIT(5) +#define MVPP22_XLG_FORWARD_PFC_EN BIT(6) +#define MVPP22_XLG_MODE_DMA_1G BIT(12) +#define MVPP22_XLG_EN_IDLE_CHECK_FOR_LINK BIT(14) + +/* XPCS registers */ + +/* Global Configuration 0 */ +#define MVPP22_XPCS_GLOBAL_CFG_0_REG 0x0 +#define MVPP22_XPCS_PCSRESET BIT(0) +#define MVPP22_XPCS_PCSMODE_OFFS 3 +#define MVPP22_XPCS_PCSMODE_MASK (0x3 << \ + MVPP22_XPCS_PCSMODE_OFFS) +#define MVPP22_XPCS_LANEACTIVE_OFFS 5 +#define MVPP22_XPCS_LANEACTIVE_MASK (0x3 << \ + MVPP22_XPCS_LANEACTIVE_OFFS) + +/* MPCS registers */ + +#define PCS40G_COMMON_CONTROL 0x14 +#define FORWARD_ERROR_CORRECTION_MASK BIT(1) + +#define PCS_CLOCK_RESET 0x14c +#define TX_SD_CLK_RESET_MASK BIT(0) +#define RX_SD_CLK_RESET_MASK BIT(1) +#define MAC_CLK_RESET_MASK BIT(2) +#define CLK_DIVISION_RATIO_OFFS 4 +#define CLK_DIVISION_RATIO_MASK (0x7 << CLK_DIVISION_RATIO_OFFS) +#define CLK_DIV_PHASE_SET_MASK BIT(11) + +/* System Soft Reset 1 */ +#define GOP_SOFT_RESET_1_REG 0x108 +#define NETC_GOP_SOFT_RESET_OFFS 6 +#define NETC_GOP_SOFT_RESET_MASK (0x1 << \ + NETC_GOP_SOFT_RESET_OFFS) + +/* Ports Control 0 */ +#define NETCOMP_PORTS_CONTROL_0_REG 0x110 +#define NETC_BUS_WIDTH_SELECT_OFFS 1 +#define NETC_BUS_WIDTH_SELECT_MASK (0x1 << \ + NETC_BUS_WIDTH_SELECT_OFFS) +#define NETC_GIG_RX_DATA_SAMPLE_OFFS 29 +#define NETC_GIG_RX_DATA_SAMPLE_MASK (0x1 << \ + NETC_GIG_RX_DATA_SAMPLE_OFFS) +#define NETC_CLK_DIV_PHASE_OFFS 31 +#define NETC_CLK_DIV_PHASE_MASK (0x1 << NETC_CLK_DIV_PHASE_OFFS) +/* Ports Control 1 */ +#define NETCOMP_PORTS_CONTROL_1_REG 0x114 +#define NETC_PORTS_ACTIVE_OFFSET(p) (0 + p) +#define NETC_PORTS_ACTIVE_MASK(p) (0x1 << \ + NETC_PORTS_ACTIVE_OFFSET(p)) +#define NETC_PORT_GIG_RF_RESET_OFFS(p) (28 + p) +#define NETC_PORT_GIG_RF_RESET_MASK(p) (0x1 << \ + NETC_PORT_GIG_RF_RESET_OFFS(p)) +#define NETCOMP_CONTROL_0_REG 0x120 +#define NETC_GBE_PORT0_SGMII_MODE_OFFS 0 +#define NETC_GBE_PORT0_SGMII_MODE_MASK (0x1 << \ + NETC_GBE_PORT0_SGMII_MODE_OFFS) +#define NETC_GBE_PORT1_SGMII_MODE_OFFS 1 +#define NETC_GBE_PORT1_SGMII_MODE_MASK (0x1 << \ + NETC_GBE_PORT1_SGMII_MODE_OFFS) +#define NETC_GBE_PORT1_MII_MODE_OFFS 2 +#define NETC_GBE_PORT1_MII_MODE_MASK (0x1 << \ + NETC_GBE_PORT1_MII_MODE_OFFS) + +#define MVPP22_SMI_MISC_CFG_REG (MVPP22_SMI + 0x04) +#define MVPP22_SMI_POLLING_EN BIT(10) + +#define MVPP22_SMI_PHY_ADDR_REG(port) (MVPP22_SMI + 0x04 + \ + (0x4 * (port))) #define MVPP2_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff @@ -336,7 +500,9 @@ do { \ (((index) < (q)->last_desc) ? ((index) + 1) : 0) /* SMI: 0xc0054 -> offset 0x54 to lms_base */ -#define MVPP2_SMI 0x0054 +#define MVPP21_SMI 0x0054 +/* PP2.2: SMI: 0x12a200 -> offset 0x1200 to iface_base */ +#define MVPP22_SMI 0x1200 #define MVPP2_PHY_REG_MASK 0x1f /* SMI register fields */ #define MVPP2_SMI_DATA_OFFS 0 /* Data */ @@ -351,6 +517,48 @@ do { \ #define MVPP2_PHY_ADDR_MASK 0x1f #define MVPP2_PHY_REG_MASK 0x1f +/* Additional PPv2.2 offsets */ +#define MVPP22_MPCS 0x007000 +#define MVPP22_XPCS 0x007400 +#define MVPP22_PORT_BASE 0x007e00 +#define MVPP22_PORT_OFFSET 0x001000 +#define MVPP22_RFU1 0x318000 + +/* Maximum number of ports */ +#define MVPP22_GOP_MAC_NUM 4 + +/* Sets the field located at the specified in data */ +#define MVPP2_RGMII_TX_FIFO_MIN_TH 0x41 +#define MVPP2_SGMII_TX_FIFO_MIN_TH 0x5 +#define MVPP2_SGMII2_5_TX_FIFO_MIN_TH 0xb + +/* Net Complex */ +enum mv_netc_topology { + MV_NETC_GE_MAC2_SGMII = BIT(0), + MV_NETC_GE_MAC3_SGMII = BIT(1), + MV_NETC_GE_MAC3_RGMII = BIT(2), +}; + +enum mv_netc_phase { + MV_NETC_FIRST_PHASE, + MV_NETC_SECOND_PHASE, +}; + +enum mv_netc_sgmii_xmi_mode { + MV_NETC_GBE_SGMII, + MV_NETC_GBE_XMII, +}; + +enum mv_netc_mii_mode { + MV_NETC_GBE_RGMII, + MV_NETC_GBE_MII, +}; + +enum mv_netc_lanes { + MV_NETC_LANE_23, + MV_NETC_LANE_45, +}; + /* Various constants */ /* Coalescing */ @@ -393,9 +601,6 @@ do { \ /* Maximum number of TXQs used by single port */ #define MVPP2_MAX_TXQ 8 -/* Maximum number of RXQs used by single port */ -#define MVPP2_MAX_RXQ 8 - /* Default number of TXQs in use */ #define MVPP2_DEFAULT_TXQ 1 @@ -403,9 +608,6 @@ do { \ #define MVPP2_DEFAULT_RXQ 1 #define CONFIG_MV_ETH_RXQ 8 /* increment by 8 */ -/* Total number of RXQs available to all ports */ -#define MVPP2_RXQ_TOTAL_NUM (MVPP2_MAX_PORTS * MVPP2_MAX_RXQ) - /* Max number of Rx descriptors */ #define MVPP2_MAX_RXD 16 @@ -425,9 +627,23 @@ do { \ #define MVPP2_TX_DESC_ALIGN (MVPP2_DESC_ALIGNED_SIZE - 1) /* RX FIFO constants */ -#define MVPP2_RX_FIFO_PORT_DATA_SIZE 0x2000 -#define MVPP2_RX_FIFO_PORT_ATTR_SIZE 0x80 -#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80 +#define MVPP21_RX_FIFO_PORT_DATA_SIZE 0x2000 +#define MVPP21_RX_FIFO_PORT_ATTR_SIZE 0x80 +#define MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE 0x8000 +#define MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE 0x2000 +#define MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE 0x1000 +#define MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE 0x200 +#define MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE 0x80 +#define MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE 0x40 +#define MVPP2_RX_FIFO_PORT_MIN_PKT 0x80 + +/* TX general registers */ +#define MVPP22_TX_FIFO_SIZE_REG(eth_tx_port) (0x8860 + ((eth_tx_port) << 2)) +#define MVPP22_TX_FIFO_SIZE_MASK 0xf + +/* TX FIFO constants */ +#define MVPP2_TX_FIFO_DATA_SIZE_10KB 0xa +#define MVPP2_TX_FIFO_DATA_SIZE_3KB 0x3 /* RX buffer constants */ #define MVPP2_SKB_SHINFO_SIZE \ @@ -689,6 +905,14 @@ struct mvpp2 { /* Shared registers' base addresses */ void __iomem *base; void __iomem *lms_base; + void __iomem *iface_base; + void __iomem *mdio_base; + + void __iomem *mpcs_base; + void __iomem *xpcs_base; + void __iomem *rfu1_base; + + u32 netc_config; /* List of pointers to port structures */ struct mvpp2_port **port_list; @@ -710,7 +934,12 @@ struct mvpp2 { /* HW version */ enum { MVPP21, MVPP22 } hw_version; + /* Maximum number of RXQs per port */ + unsigned int max_port_rxqs; + struct mii_dev *bus; + + int probe_done; }; struct mvpp2_pcpu_stats { @@ -723,6 +952,11 @@ struct mvpp2_pcpu_stats { struct mvpp2_port { u8 id; + /* Index of the port from the "group of ports" complex point + * of view + */ + int gop_id; + int irq; struct mvpp2 *priv; @@ -756,6 +990,8 @@ struct mvpp2_port { unsigned int duplex; unsigned int speed; + unsigned int phy_speed; /* SGMII 1Gbps vs 2.5Gbps */ + struct mvpp2_bm_pool *pool_long; struct mvpp2_bm_pool *pool_short; @@ -797,7 +1033,8 @@ struct mvpp2_port { #define MVPP2_RXD_L3_IP6 BIT(30) #define MVPP2_RXD_BUF_HDR BIT(31) -struct mvpp2_tx_desc { +/* HW TX descriptor for PPv2.1 */ +struct mvpp21_tx_desc { u32 command; /* Options used by HW for packet transmitting.*/ u8 packet_offset; /* the offset from the buffer beginning */ u8 phys_txq; /* destination queue ID */ @@ -808,7 +1045,8 @@ struct mvpp2_tx_desc { u32 reserved2; /* reserved (for future use) */ }; -struct mvpp2_rx_desc { +/* HW RX descriptor for PPv2.1 */ +struct mvpp21_rx_desc { u32 status; /* info about received packet */ u16 reserved1; /* parser_info (for future use, PnC) */ u16 data_size; /* size of received packet in bytes */ @@ -823,6 +1061,45 @@ struct mvpp2_rx_desc { u32 reserved8; }; +/* HW TX descriptor for PPv2.2 */ +struct mvpp22_tx_desc { + u32 command; + u8 packet_offset; + u8 phys_txq; + u16 data_size; + u64 reserved1; + u64 buf_dma_addr_ptp; + u64 buf_cookie_misc; +}; + +/* HW RX descriptor for PPv2.2 */ +struct mvpp22_rx_desc { + u32 status; + u16 reserved1; + u16 data_size; + u32 reserved2; + u32 reserved3; + u64 buf_dma_addr_key_hash; + u64 buf_cookie_misc; +}; + +/* Opaque type used by the driver to manipulate the HW TX and RX + * descriptors + */ +struct mvpp2_tx_desc { + union { + struct mvpp21_tx_desc pp21; + struct mvpp22_tx_desc pp22; + }; +}; + +struct mvpp2_rx_desc { + union { + struct mvpp21_rx_desc pp21; + struct mvpp22_rx_desc pp22; + }; +}; + /* Per-CPU Tx queue control */ struct mvpp2_txq_pcpu { int cpu; @@ -968,9 +1245,6 @@ struct mvpp2_bm_pool { /* Ports using BM pool */ u32 port_map; - - /* Occupied buffers indicator */ - int in_use_thresh; }; /* Static declaractions */ @@ -980,6 +1254,8 @@ static int rxq_number = MVPP2_DEFAULT_RXQ; /* Number of TXQs used by single port */ static int txq_number = MVPP2_DEFAULT_TXQ; +static int base_id; + #define MVPP2_DRIVER_NAME "mvpp2" #define MVPP2_DRIVER_VERSION "1.0" @@ -1023,59 +1299,90 @@ static void mvpp2_txdesc_dma_addr_set(struct mvpp2_port *port, struct mvpp2_tx_desc *tx_desc, dma_addr_t dma_addr) { - tx_desc->buf_dma_addr = dma_addr; + if (port->priv->hw_version == MVPP21) { + tx_desc->pp21.buf_dma_addr = dma_addr; + } else { + u64 val = (u64)dma_addr; + + tx_desc->pp22.buf_dma_addr_ptp &= ~GENMASK_ULL(40, 0); + tx_desc->pp22.buf_dma_addr_ptp |= val; + } } static void mvpp2_txdesc_size_set(struct mvpp2_port *port, struct mvpp2_tx_desc *tx_desc, size_t size) { - tx_desc->data_size = size; + if (port->priv->hw_version == MVPP21) + tx_desc->pp21.data_size = size; + else + tx_desc->pp22.data_size = size; } static void mvpp2_txdesc_txq_set(struct mvpp2_port *port, struct mvpp2_tx_desc *tx_desc, unsigned int txq) { - tx_desc->phys_txq = txq; + if (port->priv->hw_version == MVPP21) + tx_desc->pp21.phys_txq = txq; + else + tx_desc->pp22.phys_txq = txq; } static void mvpp2_txdesc_cmd_set(struct mvpp2_port *port, struct mvpp2_tx_desc *tx_desc, unsigned int command) { - tx_desc->command = command; + if (port->priv->hw_version == MVPP21) + tx_desc->pp21.command = command; + else + tx_desc->pp22.command = command; } static void mvpp2_txdesc_offset_set(struct mvpp2_port *port, struct mvpp2_tx_desc *tx_desc, unsigned int offset) { - tx_desc->packet_offset = offset; + if (port->priv->hw_version == MVPP21) + tx_desc->pp21.packet_offset = offset; + else + tx_desc->pp22.packet_offset = offset; } static dma_addr_t mvpp2_rxdesc_dma_addr_get(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc) { - return rx_desc->buf_dma_addr; + if (port->priv->hw_version == MVPP21) + return rx_desc->pp21.buf_dma_addr; + else + return rx_desc->pp22.buf_dma_addr_key_hash & GENMASK_ULL(40, 0); } static unsigned long mvpp2_rxdesc_cookie_get(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc) { - return rx_desc->buf_cookie; + if (port->priv->hw_version == MVPP21) + return rx_desc->pp21.buf_cookie; + else + return rx_desc->pp22.buf_cookie_misc & GENMASK_ULL(40, 0); } static size_t mvpp2_rxdesc_size_get(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc) { - return rx_desc->data_size; + if (port->priv->hw_version == MVPP21) + return rx_desc->pp21.data_size; + else + return rx_desc->pp22.data_size; } static u32 mvpp2_rxdesc_status_get(struct mvpp2_port *port, struct mvpp2_rx_desc *rx_desc) { - return rx_desc->status; + if (port->priv->hw_version == MVPP21) + return rx_desc->pp21.status; + else + return rx_desc->pp22.status; } static void mvpp2_txq_inc_get(struct mvpp2_txq_pcpu *txq_pcpu) @@ -2260,6 +2567,12 @@ static int mvpp2_bm_pool_create(struct udevice *dev, { u32 val; + /* Number of buffer pointers must be a multiple of 16, as per + * hardware constraints + */ + if (!IS_ALIGNED(size, 16)) + return -EINVAL; + bm_pool->virt_addr = buffer_loc.bm_pool[bm_pool->id]; bm_pool->dma_addr = (dma_addr_t)buffer_loc.bm_pool[bm_pool->id]; if (!bm_pool->virt_addr) @@ -2273,7 +2586,7 @@ static int mvpp2_bm_pool_create(struct udevice *dev, } mvpp2_write(priv, MVPP2_BM_POOL_BASE_REG(bm_pool->id), - bm_pool->dma_addr); + lower_32_bits(bm_pool->dma_addr)); mvpp2_write(priv, MVPP2_BM_POOL_SIZE_REG(bm_pool->id), size); val = mvpp2_read(priv, MVPP2_BM_POOL_CTRL_REG(bm_pool->id)); @@ -2305,6 +2618,13 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv, static void mvpp2_bm_bufs_free(struct udevice *dev, struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool) { + int i; + + for (i = 0; i < bm_pool->buf_num; i++) { + /* Allocate buffer back from the buffer manager */ + mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id)); + } + bm_pool->buf_num = 0; } @@ -2380,17 +2700,20 @@ static int mvpp2_bm_init(struct udevice *dev, struct mvpp2 *priv) static void mvpp2_rxq_long_pool_set(struct mvpp2_port *port, int lrxq, int long_pool) { - u32 val; + u32 val, mask; int prxq; /* Get queue physical ID */ prxq = port->rxqs[lrxq]->id; - val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq)); - val &= ~MVPP2_RXQ_POOL_LONG_MASK; - val |= ((long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & - MVPP2_RXQ_POOL_LONG_MASK); + if (port->priv->hw_version == MVPP21) + mask = MVPP21_RXQ_POOL_LONG_MASK; + else + mask = MVPP22_RXQ_POOL_LONG_MASK; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(prxq)); + val &= ~mask; + val |= (long_pool << MVPP2_RXQ_POOL_LONG_OFFS) & mask; mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(prxq), val); } @@ -2416,6 +2739,21 @@ static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool, dma_addr_t buf_dma_addr, unsigned long buf_phys_addr) { + if (port->priv->hw_version == MVPP22) { + u32 val = 0; + + if (sizeof(dma_addr_t) == 8) + val |= upper_32_bits(buf_dma_addr) & + MVPP22_BM_ADDR_HIGH_PHYS_RLS_MASK; + + if (sizeof(phys_addr_t) == 8) + val |= (upper_32_bits(buf_phys_addr) + << MVPP22_BM_ADDR_HIGH_VIRT_RLS_SHIFT) & + MVPP22_BM_ADDR_HIGH_VIRT_RLS_MASK; + + mvpp2_write(port->priv, MVPP22_BM_ADDR_HIGH_RLS_REG, val); + } + /* MVPP2_BM_VIRT_RLS_REG is not interpreted by HW, and simply * returned in the "cookie" field of the RX * descriptor. Instead of storing the virtual address, we @@ -2458,7 +2796,6 @@ static int mvpp2_bm_bufs_add(struct mvpp2_port *port, /* Update BM driver with number of buffers added to pool */ bm_pool->buf_num += i; - bm_pool->in_use_thresh = bm_pool->buf_num / 4; return i; } @@ -2552,6 +2889,7 @@ static void mvpp2_port_mii_set(struct mvpp2_port *port) val |= MVPP2_GMAC_INBAND_AN_MASK; break; case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: val |= MVPP2_GMAC_PORT_RGMII_MASK; default: val &= ~MVPP2_GMAC_PCS_ENABLE_MASK; @@ -2643,178 +2981,905 @@ static inline void mvpp2_gmac_max_rx_size_set(struct mvpp2_port *port) writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); } -/* Set defaults to the MVPP2 port */ -static void mvpp2_defaults_set(struct mvpp2_port *port) -{ - int tx_port_num, val, queue, ptxq, lrxq; - - /* Configure port to loopback if needed */ - if (port->flags & MVPP2_F_LOOPBACK) - mvpp2_port_loopback_set(port); - - /* Update TX FIFO MIN Threshold */ - val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); - val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; - /* Min. TX threshold must be less than minimal packet length */ - val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2); - writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); - - /* Disable Legacy WRR, Disable EJP, Release from reset */ - tx_port_num = mvpp2_egress_port(port); - mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, - tx_port_num); - mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0); - - /* Close bandwidth for all queues */ - for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) { - ptxq = mvpp2_txq_phys(port->id, queue); - mvpp2_write(port->priv, - MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0); - } +/* PPv2.2 GoP/GMAC config */ - /* Set refill period to 1 usec, refill tokens - * and bucket size to maximum - */ - mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG, 0xc8); - val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG); - val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK; - val |= MVPP2_TXP_REFILL_PERIOD_MASK(1); - val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK; - mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val); - val = MVPP2_TXP_TOKEN_SIZE_MAX; - mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val); +/* Set the MAC to reset or exit from reset */ +static int gop_gmac_reset(struct mvpp2_port *port, int reset) +{ + u32 val; - /* Set MaximumLowLatencyPacketSize value to 256 */ - mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id), - MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | - MVPP2_RX_LOW_LATENCY_PKT_SIZE(256)); + /* read - modify - write */ + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + if (reset) + val |= MVPP2_GMAC_PORT_RESET_MASK; + else + val &= ~MVPP2_GMAC_PORT_RESET_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); - /* Enable Rx cache snoop */ - for (lrxq = 0; lrxq < rxq_number; lrxq++) { - queue = port->rxqs[lrxq]->id; - val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); - val |= MVPP2_SNOOP_PKT_SIZE_MASK | - MVPP2_SNOOP_BUF_HDR_MASK; - mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); - } + return 0; } -/* Enable/disable receiving packets */ -static void mvpp2_ingress_enable(struct mvpp2_port *port) +/* + * gop_gpcs_mode_cfg + * + * Configure port to working with Gig PCS or don't. + */ +static int gop_gpcs_mode_cfg(struct mvpp2_port *port, int en) { u32 val; - int lrxq, queue; - for (lrxq = 0; lrxq < rxq_number; lrxq++) { - queue = port->rxqs[lrxq]->id; - val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); - val &= ~MVPP2_RXQ_DISABLE_MASK; - mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); - } + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + if (en) + val |= MVPP2_GMAC_PCS_ENABLE_MASK; + else + val &= ~MVPP2_GMAC_PCS_ENABLE_MASK; + /* enable / disable PCS on this port */ + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + return 0; } -static void mvpp2_ingress_disable(struct mvpp2_port *port) +static int gop_bypass_clk_cfg(struct mvpp2_port *port, int en) { u32 val; - int lrxq, queue; - for (lrxq = 0; lrxq < rxq_number; lrxq++) { - queue = port->rxqs[lrxq]->id; - val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); - val |= MVPP2_RXQ_DISABLE_MASK; - mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); - } + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + if (en) + val |= MVPP2_GMAC_CLK_125_BYPS_EN_MASK; + else + val &= ~MVPP2_GMAC_CLK_125_BYPS_EN_MASK; + /* enable / disable PCS on this port */ + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + return 0; } -/* Enable transmit via physical egress queue - * - HW starts take descriptors from DRAM - */ -static void mvpp2_egress_enable(struct mvpp2_port *port) +static void gop_gmac_sgmii2_5_cfg(struct mvpp2_port *port) { - u32 qmap; - int queue; - int tx_port_num = mvpp2_egress_port(port); + u32 val, thresh; - /* Enable all initialized TXs. */ - qmap = 0; - for (queue = 0; queue < txq_number; queue++) { - struct mvpp2_tx_queue *txq = port->txqs[queue]; + /* + * Configure minimal level of the Tx FIFO before the lower part + * starts to read a packet + */ + thresh = MVPP2_SGMII2_5_TX_FIFO_MIN_TH; + val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; + val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh); + writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); - if (txq->descs != NULL) - qmap |= (1 << queue); - } + /* Disable bypass of sync module */ + val = readl(port->base + MVPP2_GMAC_CTRL_4_REG); + val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK; + /* configure DP clock select according to mode */ + val |= MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK; + /* configure QSGMII bypass according to mode */ + val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_4_REG); - mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); - mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap); + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + val |= MVPP2_GMAC_PORT_DIS_PADING_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + /* + * Configure GIG MAC to 1000Base-X mode connected to a fiber + * transceiver + */ + val |= MVPP2_GMAC_PORT_TYPE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + + /* configure AN 0x9268 */ + val = MVPP2_GMAC_EN_PCS_AN | + MVPP2_GMAC_AN_BYPASS_EN | + MVPP2_GMAC_CONFIG_MII_SPEED | + MVPP2_GMAC_CONFIG_GMII_SPEED | + MVPP2_GMAC_FC_ADV_EN | + MVPP2_GMAC_CONFIG_FULL_DUPLEX | + MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); } -/* Disable transmit via physical egress queue - * - HW doesn't take descriptors from DRAM - */ -static void mvpp2_egress_disable(struct mvpp2_port *port) +static void gop_gmac_sgmii_cfg(struct mvpp2_port *port) { - u32 reg_data; - int delay; - int tx_port_num = mvpp2_egress_port(port); + u32 val, thresh; - /* Issue stop command for active channels only */ - mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); - reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & - MVPP2_TXP_SCHED_ENQ_MASK; - if (reg_data != 0) - mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, - (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET)); - - /* Wait for all Tx activity to terminate. */ - delay = 0; - do { - if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) { - netdev_warn(port->dev, - "Tx stop timed out, status=0x%08x\n", - reg_data); - break; - } - mdelay(1); - delay++; + /* + * Configure minimal level of the Tx FIFO before the lower part + * starts to read a packet + */ + thresh = MVPP2_SGMII_TX_FIFO_MIN_TH; + val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; + val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh); + writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); - /* Check port TX Command register that all - * Tx queues are stopped - */ - reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG); - } while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK); -} + /* Disable bypass of sync module */ + val = readl(port->base + MVPP2_GMAC_CTRL_4_REG); + val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK; + /* configure DP clock select according to mode */ + val &= ~MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK; + /* configure QSGMII bypass according to mode */ + val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_4_REG); -/* Rx descriptors helper methods */ + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + val |= MVPP2_GMAC_PORT_DIS_PADING_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); -/* Get number of Rx descriptors occupied by received packets */ -static inline int -mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id) -{ - u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id)); + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + /* configure GIG MAC to SGMII mode */ + val &= ~MVPP2_GMAC_PORT_TYPE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); - return val & MVPP2_RXQ_OCCUPIED_MASK; + /* configure AN */ + val = MVPP2_GMAC_EN_PCS_AN | + MVPP2_GMAC_AN_BYPASS_EN | + MVPP2_GMAC_AN_SPEED_EN | + MVPP2_GMAC_EN_FC_AN | + MVPP2_GMAC_AN_DUPLEX_EN | + MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); } -/* Update Rx queue status with the number of occupied and available - * Rx descriptor slots. - */ -static inline void -mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id, - int used_count, int free_count) +static void gop_gmac_rgmii_cfg(struct mvpp2_port *port) { - /* Decrement the number of used descriptors and increment count - * increment the number of free descriptors. - */ - u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET); + u32 val, thresh; - mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val); -} + /* + * Configure minimal level of the Tx FIFO before the lower part + * starts to read a packet + */ + thresh = MVPP2_RGMII_TX_FIFO_MIN_TH; + val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; + val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(thresh); + writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); -/* Get pointer to next RX descriptor to be processed by SW */ -static inline struct mvpp2_rx_desc * -mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq) -{ - int rx_desc = rxq->next_desc_to_proc; + /* Disable bypass of sync module */ + val = readl(port->base + MVPP2_GMAC_CTRL_4_REG); + val |= MVPP2_GMAC_CTRL4_SYNC_BYPASS_MASK; + /* configure DP clock select according to mode */ + val &= ~MVPP2_GMAC_CTRL4_DP_CLK_SEL_MASK; + val |= MVPP2_GMAC_CTRL4_QSGMII_BYPASS_ACTIVE_MASK; + val |= MVPP2_GMAC_CTRL4_EXT_PIN_GMII_SEL_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_4_REG); + + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + val &= ~MVPP2_GMAC_PORT_DIS_PADING_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + /* configure GIG MAC to SGMII mode */ + val &= ~MVPP2_GMAC_PORT_TYPE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + + /* configure AN 0xb8e8 */ + val = MVPP2_GMAC_AN_BYPASS_EN | + MVPP2_GMAC_AN_SPEED_EN | + MVPP2_GMAC_EN_FC_AN | + MVPP2_GMAC_AN_DUPLEX_EN | + MVPP2_GMAC_CHOOSE_SAMPLE_TX_CONFIG; + writel(val, port->base + MVPP2_GMAC_AUTONEG_CONFIG); +} + +/* Set the internal mux's to the required MAC in the GOP */ +static int gop_gmac_mode_cfg(struct mvpp2_port *port) +{ + u32 val; + + /* Set TX FIFO thresholds */ + switch (port->phy_interface) { + case PHY_INTERFACE_MODE_SGMII: + if (port->phy_speed == 2500) + gop_gmac_sgmii2_5_cfg(port); + else + gop_gmac_sgmii_cfg(port); + break; + + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + gop_gmac_rgmii_cfg(port); + break; + + default: + return -1; + } + + /* Jumbo frame support - 0x1400*2= 0x2800 bytes */ + val = readl(port->base + MVPP2_GMAC_CTRL_0_REG); + val &= ~MVPP2_GMAC_MAX_RX_SIZE_MASK; + val |= 0x1400 << MVPP2_GMAC_MAX_RX_SIZE_OFFS; + writel(val, port->base + MVPP2_GMAC_CTRL_0_REG); + + /* PeriodicXonEn disable */ + val = readl(port->base + MVPP2_GMAC_CTRL_1_REG); + val &= ~MVPP2_GMAC_PERIODIC_XON_EN_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_1_REG); + + return 0; +} + +static void gop_xlg_2_gig_mac_cfg(struct mvpp2_port *port) +{ + u32 val; + + /* relevant only for MAC0 (XLG0 and GMAC0) */ + if (port->gop_id > 0) + return; + + /* configure 1Gig MAC mode */ + val = readl(port->base + MVPP22_XLG_CTRL3_REG); + val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK; + val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC; + writel(val, port->base + MVPP22_XLG_CTRL3_REG); +} + +static int gop_gpcs_reset(struct mvpp2_port *port, int reset) +{ + u32 val; + + val = readl(port->base + MVPP2_GMAC_CTRL_2_REG); + if (reset) + val &= ~MVPP2_GMAC_SGMII_MODE_MASK; + else + val |= MVPP2_GMAC_SGMII_MODE_MASK; + writel(val, port->base + MVPP2_GMAC_CTRL_2_REG); + + return 0; +} + +/* Set the internal mux's to the required PCS in the PI */ +static int gop_xpcs_mode(struct mvpp2_port *port, int num_of_lanes) +{ + u32 val; + int lane; + + switch (num_of_lanes) { + case 1: + lane = 0; + break; + case 2: + lane = 1; + break; + case 4: + lane = 2; + break; + default: + return -1; + } + + /* configure XG MAC mode */ + val = readl(port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG); + val &= ~MVPP22_XPCS_PCSMODE_OFFS; + val &= ~MVPP22_XPCS_LANEACTIVE_MASK; + val |= (2 * lane) << MVPP22_XPCS_LANEACTIVE_OFFS; + writel(val, port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG); + + return 0; +} + +static int gop_mpcs_mode(struct mvpp2_port *port) +{ + u32 val; + + /* configure PCS40G COMMON CONTROL */ + val = readl(port->priv->mpcs_base + PCS40G_COMMON_CONTROL); + val &= ~FORWARD_ERROR_CORRECTION_MASK; + writel(val, port->priv->mpcs_base + PCS40G_COMMON_CONTROL); + + /* configure PCS CLOCK RESET */ + val = readl(port->priv->mpcs_base + PCS_CLOCK_RESET); + val &= ~CLK_DIVISION_RATIO_MASK; + val |= 1 << CLK_DIVISION_RATIO_OFFS; + writel(val, port->priv->mpcs_base + PCS_CLOCK_RESET); + + val &= ~CLK_DIV_PHASE_SET_MASK; + val |= MAC_CLK_RESET_MASK; + val |= RX_SD_CLK_RESET_MASK; + val |= TX_SD_CLK_RESET_MASK; + writel(val, port->priv->mpcs_base + PCS_CLOCK_RESET); + + return 0; +} + +/* Set the internal mux's to the required MAC in the GOP */ +static int gop_xlg_mac_mode_cfg(struct mvpp2_port *port, int num_of_act_lanes) +{ + u32 val; + + /* configure 10G MAC mode */ + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + val |= MVPP22_XLG_RX_FC_EN; + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + + val = readl(port->base + MVPP22_XLG_CTRL3_REG); + val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK; + val |= MVPP22_XLG_CTRL3_MACMODESELECT_10GMAC; + writel(val, port->base + MVPP22_XLG_CTRL3_REG); + + /* read - modify - write */ + val = readl(port->base + MVPP22_XLG_CTRL4_REG); + val &= ~MVPP22_XLG_MODE_DMA_1G; + val |= MVPP22_XLG_FORWARD_PFC_EN; + val |= MVPP22_XLG_FORWARD_802_3X_FC_EN; + val &= ~MVPP22_XLG_EN_IDLE_CHECK_FOR_LINK; + writel(val, port->base + MVPP22_XLG_CTRL4_REG); + + /* Jumbo frame support: 0x1400 * 2 = 0x2800 bytes */ + val = readl(port->base + MVPP22_XLG_CTRL1_REG); + val &= ~MVPP22_XLG_MAX_RX_SIZE_MASK; + val |= 0x1400 << MVPP22_XLG_MAX_RX_SIZE_OFFS; + writel(val, port->base + MVPP22_XLG_CTRL1_REG); + + /* unmask link change interrupt */ + val = readl(port->base + MVPP22_XLG_INTERRUPT_MASK_REG); + val |= MVPP22_XLG_INTERRUPT_LINK_CHANGE; + val |= 1; /* unmask summary bit */ + writel(val, port->base + MVPP22_XLG_INTERRUPT_MASK_REG); + + return 0; +} + +/* Set PCS to reset or exit from reset */ +static int gop_xpcs_reset(struct mvpp2_port *port, int reset) +{ + u32 val; + + /* read - modify - write */ + val = readl(port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG); + if (reset) + val &= ~MVPP22_XPCS_PCSRESET; + else + val |= MVPP22_XPCS_PCSRESET; + writel(val, port->priv->xpcs_base + MVPP22_XPCS_GLOBAL_CFG_0_REG); + + return 0; +} + +/* Set the MAC to reset or exit from reset */ +static int gop_xlg_mac_reset(struct mvpp2_port *port, int reset) +{ + u32 val; + + /* read - modify - write */ + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + if (reset) + val &= ~MVPP22_XLG_MAC_RESETN; + else + val |= MVPP22_XLG_MAC_RESETN; + writel(val, port->base + MVPP22_XLG_CTRL0_REG); + + return 0; +} + +/* + * gop_port_init + * + * Init physical port. Configures the port mode and all it's elements + * accordingly. + * Does not verify that the selected mode/port number is valid at the + * core level. + */ +static int gop_port_init(struct mvpp2_port *port) +{ + int mac_num = port->gop_id; + int num_of_act_lanes; + + if (mac_num >= MVPP22_GOP_MAC_NUM) { + netdev_err(NULL, "%s: illegal port number %d", __func__, + mac_num); + return -1; + } + + switch (port->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + gop_gmac_reset(port, 1); + + /* configure PCS */ + gop_gpcs_mode_cfg(port, 0); + gop_bypass_clk_cfg(port, 1); + + /* configure MAC */ + gop_gmac_mode_cfg(port); + /* pcs unreset */ + gop_gpcs_reset(port, 0); + + /* mac unreset */ + gop_gmac_reset(port, 0); + break; + + case PHY_INTERFACE_MODE_SGMII: + /* configure PCS */ + gop_gpcs_mode_cfg(port, 1); + + /* configure MAC */ + gop_gmac_mode_cfg(port); + /* select proper Mac mode */ + gop_xlg_2_gig_mac_cfg(port); + + /* pcs unreset */ + gop_gpcs_reset(port, 0); + /* mac unreset */ + gop_gmac_reset(port, 0); + break; + + case PHY_INTERFACE_MODE_SFI: + num_of_act_lanes = 2; + mac_num = 0; + /* configure PCS */ + gop_xpcs_mode(port, num_of_act_lanes); + gop_mpcs_mode(port); + /* configure MAC */ + gop_xlg_mac_mode_cfg(port, num_of_act_lanes); + + /* pcs unreset */ + gop_xpcs_reset(port, 0); + + /* mac unreset */ + gop_xlg_mac_reset(port, 0); + break; + + default: + netdev_err(NULL, "%s: Requested port mode (%d) not supported\n", + __func__, port->phy_interface); + return -1; + } + + return 0; +} + +static void gop_xlg_mac_port_enable(struct mvpp2_port *port, int enable) +{ + u32 val; + + val = readl(port->base + MVPP22_XLG_CTRL0_REG); + if (enable) { + /* Enable port and MIB counters update */ + val |= MVPP22_XLG_PORT_EN; + val &= ~MVPP22_XLG_MIBCNT_DIS; + } else { + /* Disable port */ + val &= ~MVPP22_XLG_PORT_EN; + } + writel(val, port->base + MVPP22_XLG_CTRL0_REG); +} + +static void gop_port_enable(struct mvpp2_port *port, int enable) +{ + switch (port->phy_interface) { + case PHY_INTERFACE_MODE_RGMII: + case PHY_INTERFACE_MODE_RGMII_ID: + case PHY_INTERFACE_MODE_SGMII: + if (enable) + mvpp2_port_enable(port); + else + mvpp2_port_disable(port); + break; + + case PHY_INTERFACE_MODE_SFI: + gop_xlg_mac_port_enable(port, enable); + + break; + default: + netdev_err(NULL, "%s: Wrong port mode (%d)\n", __func__, + port->phy_interface); + return; + } +} + +/* RFU1 functions */ +static inline u32 gop_rfu1_read(struct mvpp2 *priv, u32 offset) +{ + return readl(priv->rfu1_base + offset); +} + +static inline void gop_rfu1_write(struct mvpp2 *priv, u32 offset, u32 data) +{ + writel(data, priv->rfu1_base + offset); +} + +static u32 mvpp2_netc_cfg_create(int gop_id, phy_interface_t phy_type) +{ + u32 val = 0; + + if (gop_id == 2) { + if (phy_type == PHY_INTERFACE_MODE_SGMII) + val |= MV_NETC_GE_MAC2_SGMII; + } + + if (gop_id == 3) { + if (phy_type == PHY_INTERFACE_MODE_SGMII) + val |= MV_NETC_GE_MAC3_SGMII; + else if (phy_type == PHY_INTERFACE_MODE_RGMII || + phy_type == PHY_INTERFACE_MODE_RGMII_ID) + val |= MV_NETC_GE_MAC3_RGMII; + } + + return val; +} + +static void gop_netc_active_port(struct mvpp2 *priv, int gop_id, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_1_REG); + reg &= ~(NETC_PORTS_ACTIVE_MASK(gop_id)); + + val <<= NETC_PORTS_ACTIVE_OFFSET(gop_id); + val &= NETC_PORTS_ACTIVE_MASK(gop_id); + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_1_REG, reg); +} + +static void gop_netc_mii_mode(struct mvpp2 *priv, int gop_id, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_CONTROL_0_REG); + reg &= ~NETC_GBE_PORT1_MII_MODE_MASK; + + val <<= NETC_GBE_PORT1_MII_MODE_OFFS; + val &= NETC_GBE_PORT1_MII_MODE_MASK; + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_CONTROL_0_REG, reg); +} + +static void gop_netc_gop_reset(struct mvpp2 *priv, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, GOP_SOFT_RESET_1_REG); + reg &= ~NETC_GOP_SOFT_RESET_MASK; + + val <<= NETC_GOP_SOFT_RESET_OFFS; + val &= NETC_GOP_SOFT_RESET_MASK; + + reg |= val; + + gop_rfu1_write(priv, GOP_SOFT_RESET_1_REG, reg); +} + +static void gop_netc_gop_clock_logic_set(struct mvpp2 *priv, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG); + reg &= ~NETC_CLK_DIV_PHASE_MASK; + + val <<= NETC_CLK_DIV_PHASE_OFFS; + val &= NETC_CLK_DIV_PHASE_MASK; + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg); +} + +static void gop_netc_port_rf_reset(struct mvpp2 *priv, int gop_id, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_1_REG); + reg &= ~(NETC_PORT_GIG_RF_RESET_MASK(gop_id)); + + val <<= NETC_PORT_GIG_RF_RESET_OFFS(gop_id); + val &= NETC_PORT_GIG_RF_RESET_MASK(gop_id); + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_1_REG, reg); +} + +static void gop_netc_gbe_sgmii_mode_select(struct mvpp2 *priv, int gop_id, + u32 val) +{ + u32 reg, mask, offset; + + if (gop_id == 2) { + mask = NETC_GBE_PORT0_SGMII_MODE_MASK; + offset = NETC_GBE_PORT0_SGMII_MODE_OFFS; + } else { + mask = NETC_GBE_PORT1_SGMII_MODE_MASK; + offset = NETC_GBE_PORT1_SGMII_MODE_OFFS; + } + reg = gop_rfu1_read(priv, NETCOMP_CONTROL_0_REG); + reg &= ~mask; + + val <<= offset; + val &= mask; + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_CONTROL_0_REG, reg); +} + +static void gop_netc_bus_width_select(struct mvpp2 *priv, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG); + reg &= ~NETC_BUS_WIDTH_SELECT_MASK; + + val <<= NETC_BUS_WIDTH_SELECT_OFFS; + val &= NETC_BUS_WIDTH_SELECT_MASK; + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg); +} + +static void gop_netc_sample_stages_timing(struct mvpp2 *priv, u32 val) +{ + u32 reg; + + reg = gop_rfu1_read(priv, NETCOMP_PORTS_CONTROL_0_REG); + reg &= ~NETC_GIG_RX_DATA_SAMPLE_MASK; + + val <<= NETC_GIG_RX_DATA_SAMPLE_OFFS; + val &= NETC_GIG_RX_DATA_SAMPLE_MASK; + + reg |= val; + + gop_rfu1_write(priv, NETCOMP_PORTS_CONTROL_0_REG, reg); +} + +static void gop_netc_mac_to_xgmii(struct mvpp2 *priv, int gop_id, + enum mv_netc_phase phase) +{ + switch (phase) { + case MV_NETC_FIRST_PHASE: + /* Set Bus Width to HB mode = 1 */ + gop_netc_bus_width_select(priv, 1); + /* Select RGMII mode */ + gop_netc_gbe_sgmii_mode_select(priv, gop_id, MV_NETC_GBE_XMII); + break; + + case MV_NETC_SECOND_PHASE: + /* De-assert the relevant port HB reset */ + gop_netc_port_rf_reset(priv, gop_id, 1); + break; + } +} + +static void gop_netc_mac_to_sgmii(struct mvpp2 *priv, int gop_id, + enum mv_netc_phase phase) +{ + switch (phase) { + case MV_NETC_FIRST_PHASE: + /* Set Bus Width to HB mode = 1 */ + gop_netc_bus_width_select(priv, 1); + /* Select SGMII mode */ + if (gop_id >= 1) { + gop_netc_gbe_sgmii_mode_select(priv, gop_id, + MV_NETC_GBE_SGMII); + } + + /* Configure the sample stages */ + gop_netc_sample_stages_timing(priv, 0); + /* Configure the ComPhy Selector */ + /* gop_netc_com_phy_selector_config(netComplex); */ + break; + + case MV_NETC_SECOND_PHASE: + /* De-assert the relevant port HB reset */ + gop_netc_port_rf_reset(priv, gop_id, 1); + break; + } +} + +static int gop_netc_init(struct mvpp2 *priv, enum mv_netc_phase phase) +{ + u32 c = priv->netc_config; + + if (c & MV_NETC_GE_MAC2_SGMII) + gop_netc_mac_to_sgmii(priv, 2, phase); + else + gop_netc_mac_to_xgmii(priv, 2, phase); + + if (c & MV_NETC_GE_MAC3_SGMII) { + gop_netc_mac_to_sgmii(priv, 3, phase); + } else { + gop_netc_mac_to_xgmii(priv, 3, phase); + if (c & MV_NETC_GE_MAC3_RGMII) + gop_netc_mii_mode(priv, 3, MV_NETC_GBE_RGMII); + else + gop_netc_mii_mode(priv, 3, MV_NETC_GBE_MII); + } + + /* Activate gop ports 0, 2, 3 */ + gop_netc_active_port(priv, 0, 1); + gop_netc_active_port(priv, 2, 1); + gop_netc_active_port(priv, 3, 1); + + if (phase == MV_NETC_SECOND_PHASE) { + /* Enable the GOP internal clock logic */ + gop_netc_gop_clock_logic_set(priv, 1); + /* De-assert GOP unit reset */ + gop_netc_gop_reset(priv, 1); + } + + return 0; +} + +/* Set defaults to the MVPP2 port */ +static void mvpp2_defaults_set(struct mvpp2_port *port) +{ + int tx_port_num, val, queue, ptxq, lrxq; + + if (port->priv->hw_version == MVPP21) { + /* Configure port to loopback if needed */ + if (port->flags & MVPP2_F_LOOPBACK) + mvpp2_port_loopback_set(port); + + /* Update TX FIFO MIN Threshold */ + val = readl(port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + val &= ~MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK; + /* Min. TX threshold must be less than minimal packet length */ + val |= MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(64 - 4 - 2); + writel(val, port->base + MVPP2_GMAC_PORT_FIFO_CFG_1_REG); + } + + /* Disable Legacy WRR, Disable EJP, Release from reset */ + tx_port_num = mvpp2_egress_port(port); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, + tx_port_num); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_CMD_1_REG, 0); + + /* Close bandwidth for all queues */ + for (queue = 0; queue < MVPP2_MAX_TXQ; queue++) { + ptxq = mvpp2_txq_phys(port->id, queue); + mvpp2_write(port->priv, + MVPP2_TXQ_SCHED_TOKEN_CNTR_REG(ptxq), 0); + } + + /* Set refill period to 1 usec, refill tokens + * and bucket size to maximum + */ + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PERIOD_REG, 0xc8); + val = mvpp2_read(port->priv, MVPP2_TXP_SCHED_REFILL_REG); + val &= ~MVPP2_TXP_REFILL_PERIOD_ALL_MASK; + val |= MVPP2_TXP_REFILL_PERIOD_MASK(1); + val |= MVPP2_TXP_REFILL_TOKENS_ALL_MASK; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_REFILL_REG, val); + val = MVPP2_TXP_TOKEN_SIZE_MAX; + mvpp2_write(port->priv, MVPP2_TXP_SCHED_TOKEN_SIZE_REG, val); + + /* Set MaximumLowLatencyPacketSize value to 256 */ + mvpp2_write(port->priv, MVPP2_RX_CTRL_REG(port->id), + MVPP2_RX_USE_PSEUDO_FOR_CSUM_MASK | + MVPP2_RX_LOW_LATENCY_PKT_SIZE(256)); + + /* Enable Rx cache snoop */ + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val |= MVPP2_SNOOP_PKT_SIZE_MASK | + MVPP2_SNOOP_BUF_HDR_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } +} + +/* Enable/disable receiving packets */ +static void mvpp2_ingress_enable(struct mvpp2_port *port) +{ + u32 val; + int lrxq, queue; + + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val &= ~MVPP2_RXQ_DISABLE_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } +} + +static void mvpp2_ingress_disable(struct mvpp2_port *port) +{ + u32 val; + int lrxq, queue; + + for (lrxq = 0; lrxq < rxq_number; lrxq++) { + queue = port->rxqs[lrxq]->id; + val = mvpp2_read(port->priv, MVPP2_RXQ_CONFIG_REG(queue)); + val |= MVPP2_RXQ_DISABLE_MASK; + mvpp2_write(port->priv, MVPP2_RXQ_CONFIG_REG(queue), val); + } +} + +/* Enable transmit via physical egress queue + * - HW starts take descriptors from DRAM + */ +static void mvpp2_egress_enable(struct mvpp2_port *port) +{ + u32 qmap; + int queue; + int tx_port_num = mvpp2_egress_port(port); + + /* Enable all initialized TXs. */ + qmap = 0; + for (queue = 0; queue < txq_number; queue++) { + struct mvpp2_tx_queue *txq = port->txqs[queue]; + + if (txq->descs != NULL) + qmap |= (1 << queue); + } + + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, qmap); +} + +/* Disable transmit via physical egress queue + * - HW doesn't take descriptors from DRAM + */ +static void mvpp2_egress_disable(struct mvpp2_port *port) +{ + u32 reg_data; + int delay; + int tx_port_num = mvpp2_egress_port(port); + + /* Issue stop command for active channels only */ + mvpp2_write(port->priv, MVPP2_TXP_SCHED_PORT_INDEX_REG, tx_port_num); + reg_data = (mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG)) & + MVPP2_TXP_SCHED_ENQ_MASK; + if (reg_data != 0) + mvpp2_write(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG, + (reg_data << MVPP2_TXP_SCHED_DISQ_OFFSET)); + + /* Wait for all Tx activity to terminate. */ + delay = 0; + do { + if (delay >= MVPP2_TX_DISABLE_TIMEOUT_MSEC) { + netdev_warn(port->dev, + "Tx stop timed out, status=0x%08x\n", + reg_data); + break; + } + mdelay(1); + delay++; + + /* Check port TX Command register that all + * Tx queues are stopped + */ + reg_data = mvpp2_read(port->priv, MVPP2_TXP_SCHED_Q_CMD_REG); + } while (reg_data & MVPP2_TXP_SCHED_ENQ_MASK); +} + +/* Rx descriptors helper methods */ + +/* Get number of Rx descriptors occupied by received packets */ +static inline int +mvpp2_rxq_received(struct mvpp2_port *port, int rxq_id) +{ + u32 val = mvpp2_read(port->priv, MVPP2_RXQ_STATUS_REG(rxq_id)); + + return val & MVPP2_RXQ_OCCUPIED_MASK; +} + +/* Update Rx queue status with the number of occupied and available + * Rx descriptor slots. + */ +static inline void +mvpp2_rxq_status_update(struct mvpp2_port *port, int rxq_id, + int used_count, int free_count) +{ + /* Decrement the number of used descriptors and increment count + * increment the number of free descriptors. + */ + u32 val = used_count | (free_count << MVPP2_RXQ_NUM_NEW_OFFSET); + + mvpp2_write(port->priv, MVPP2_RXQ_STATUS_UPDATE_REG(rxq_id), val); +} + +/* Get pointer to next RX descriptor to be processed by SW */ +static inline struct mvpp2_rx_desc * +mvpp2_rxq_next_desc_get(struct mvpp2_rx_queue *rxq) +{ + int rx_desc = rxq->next_desc_to_proc; rxq->next_desc_to_proc = MVPP2_QUEUE_NEXT_DESC(rxq, rx_desc); prefetch(rxq->descs + rxq->next_desc_to_proc); @@ -2998,6 +4063,8 @@ static int mvpp2_aggr_txq_init(struct udevice *dev, int desc_num, int cpu, struct mvpp2 *priv) { + u32 txq_dma; + /* Allocate memory for TX descriptors */ aggr_txq->descs = buffer_loc.aggr_tx_descs; aggr_txq->descs_dma = (dma_addr_t)buffer_loc.aggr_tx_descs; @@ -3014,10 +4081,16 @@ static int mvpp2_aggr_txq_init(struct udevice *dev, aggr_txq->next_desc_to_proc = mvpp2_read(priv, MVPP2_AGGR_TXQ_INDEX_REG(cpu)); - /* Set Tx descriptors queue starting address */ - /* indirect access */ - mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), - aggr_txq->descs_dma); + /* Set Tx descriptors queue starting address indirect + * access + */ + if (priv->hw_version == MVPP21) + txq_dma = aggr_txq->descs_dma; + else + txq_dma = aggr_txq->descs_dma >> + MVPP22_AGGR_TXQ_DESC_ADDR_OFFS; + + mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_ADDR_REG(cpu), txq_dma); mvpp2_write(priv, MVPP2_AGGR_TXQ_DESC_SIZE_REG(cpu), desc_num); return 0; @@ -3028,6 +4101,8 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, struct mvpp2_rx_queue *rxq) { + u32 rxq_dma; + rxq->size = port->rx_ring_size; /* Allocate memory for RX descriptors */ @@ -3046,7 +4121,11 @@ static int mvpp2_rxq_init(struct mvpp2_port *port, /* Set Rx descriptors queue starting address - indirect access */ mvpp2_write(port->priv, MVPP2_RXQ_NUM_REG, rxq->id); - mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq->descs_dma); + if (port->priv->hw_version == MVPP21) + rxq_dma = rxq->descs_dma; + else + rxq_dma = rxq->descs_dma >> MVPP22_DESC_ADDR_OFFS; + mvpp2_write(port->priv, MVPP2_RXQ_DESC_ADDR_REG, rxq_dma); mvpp2_write(port->priv, MVPP2_RXQ_DESC_SIZE_REG, rxq->size); mvpp2_write(port->priv, MVPP2_RXQ_INDEX_REG, 0); @@ -3145,7 +4224,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, mvpp2_write(port->priv, MVPP2_TXQ_PREF_BUF_REG, MVPP2_PREF_BUF_PTR(desc) | MVPP2_PREF_BUF_SIZE_16 | - MVPP2_PREF_BUF_THRESH(desc_per_txq/2)); + MVPP2_PREF_BUF_THRESH(desc_per_txq / 2)); /* WRR / EJP configuration - indirect access */ tx_port_num = mvpp2_egress_port(port); @@ -3403,7 +4482,10 @@ static void mvpp2_start_dev(struct mvpp2_port *port) mvpp2_gmac_max_rx_size_set(port); mvpp2_txp_max_tx_size_set(port); - mvpp2_port_enable(port); + if (port->priv->hw_version == MVPP21) + mvpp2_port_enable(port); + else + gop_port_enable(port, 1); } /* Set hw internals when stopping port */ @@ -3413,7 +4495,11 @@ static void mvpp2_stop_dev(struct mvpp2_port *port) mvpp2_ingress_disable(port); mvpp2_egress_disable(port); - mvpp2_port_disable(port); + + if (port->priv->hw_version == MVPP21) + mvpp2_port_disable(port); + else + gop_port_enable(port, 0); } static int mvpp2_phy_connect(struct udevice *dev, struct mvpp2_port *port) @@ -3505,9 +4591,14 @@ static int mvpp2_open(struct udevice *dev, struct mvpp2_port *port) static void mvpp2_port_power_up(struct mvpp2_port *port) { - mvpp2_port_mii_set(port); + struct mvpp2 *priv = port->priv; + + /* On PPv2.2 the GoP / interface configuration has already been done */ + if (priv->hw_version == MVPP21) + mvpp2_port_mii_set(port); mvpp2_port_periodic_xon_disable(port); - mvpp2_port_fc_adv_enable(port); + if (priv->hw_version == MVPP21) + mvpp2_port_fc_adv_enable(port); mvpp2_port_reset(port); } @@ -3518,12 +4609,16 @@ static int mvpp2_port_init(struct udevice *dev, struct mvpp2_port *port) struct mvpp2_txq_pcpu *txq_pcpu; int queue, cpu, err; - if (port->first_rxq + rxq_number > MVPP2_RXQ_TOTAL_NUM) + if (port->first_rxq + rxq_number > + MVPP2_MAX_PORTS * priv->max_port_rxqs) return -EINVAL; /* Disable port */ mvpp2_egress_disable(port); - mvpp2_port_disable(port); + if (priv->hw_version == MVPP21) + mvpp2_port_disable(port); + else + gop_port_enable(port, 0); port->txqs = devm_kcalloc(dev, txq_number, sizeof(*port->txqs), GFP_KERNEL); @@ -3579,7 +4674,19 @@ static int mvpp2_port_init(struct udevice *dev, struct mvpp2_port *port) } /* Configure Rx queue group interrupt for this port */ - mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(port->id), CONFIG_MV_ETH_RXQ); + if (priv->hw_version == MVPP21) { + mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(port->id), + CONFIG_MV_ETH_RXQ); + } else { + u32 val; + + val = (port->id << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET); + mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); + + val = (CONFIG_MV_ETH_RXQ << + MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); + mvpp2_write(priv, MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); + } /* Create Rx descriptor rings */ for (queue = 0; queue < rxq_number; queue++) { @@ -3610,20 +4717,14 @@ static int mvpp2_port_init(struct udevice *dev, struct mvpp2_port *port) return 0; } -/* Ports initialization */ -static int mvpp2_port_probe(struct udevice *dev, - struct mvpp2_port *port, - int port_node, - struct mvpp2 *priv, - int *next_first_rxq) +static int phy_info_parse(struct udevice *dev, struct mvpp2_port *port) { + int port_node = dev_of_offset(dev); + const char *phy_mode_str; int phy_node; u32 id; u32 phyaddr; - const char *phy_mode_str; int phy_mode = -1; - int priv_common_regs_num = 2; - int err; phy_node = fdtdec_lookup_phandle(gd->fdt_blob, port_node, "phy"); if (phy_node < 0) { @@ -3645,34 +4746,48 @@ static int mvpp2_port_probe(struct udevice *dev, return -EINVAL; } + /* + * ToDo: + * Not sure if this DT property "phy-speed" will get accepted, so + * this might change later + */ + /* Get phy-speed for SGMII 2.5Gbps vs 1Gbps setup */ + port->phy_speed = fdtdec_get_int(gd->fdt_blob, port_node, + "phy-speed", 1000); + phyaddr = fdtdec_get_int(gd->fdt_blob, phy_node, "reg", 0); - port->priv = priv; port->id = id; - port->first_rxq = *next_first_rxq; + if (port->priv->hw_version == MVPP21) + port->first_rxq = port->id * rxq_number; + else + port->first_rxq = port->id * port->priv->max_port_rxqs; port->phy_node = phy_node; port->phy_interface = phy_mode; port->phyaddr = phyaddr; - port->base = (void __iomem *)dev_get_addr_index(dev->parent, - priv_common_regs_num - + id); - if (IS_ERR(port->base)) - return PTR_ERR(port->base); + return 0; +} + +/* Ports initialization */ +static int mvpp2_port_probe(struct udevice *dev, + struct mvpp2_port *port, + int port_node, + struct mvpp2 *priv) +{ + int err; port->tx_ring_size = MVPP2_MAX_TXD; port->rx_ring_size = MVPP2_MAX_RXD; err = mvpp2_port_init(dev, port); if (err < 0) { - dev_err(&pdev->dev, "failed to init port %d\n", id); + dev_err(&pdev->dev, "failed to init port %d\n", port->id); return err; } mvpp2_port_power_up(port); - /* Increment the first Rx queue number to be used by the next port */ - *next_first_rxq += CONFIG_MV_ETH_RXQ; - priv->port_list[id] = port; + priv->port_list[port->id] = port; return 0; } @@ -3715,10 +4830,35 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv) int port; for (port = 0; port < MVPP2_MAX_PORTS; port++) { - mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port), - MVPP2_RX_FIFO_PORT_DATA_SIZE); - mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port), - MVPP2_RX_FIFO_PORT_ATTR_SIZE); + if (priv->hw_version == MVPP22) { + if (port == 0) { + mvpp2_write(priv, + MVPP2_RX_DATA_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_10GB_PORT_DATA_SIZE); + mvpp2_write(priv, + MVPP2_RX_ATTR_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_10GB_PORT_ATTR_SIZE); + } else if (port == 1) { + mvpp2_write(priv, + MVPP2_RX_DATA_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_2_5GB_PORT_DATA_SIZE); + mvpp2_write(priv, + MVPP2_RX_ATTR_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_2_5GB_PORT_ATTR_SIZE); + } else { + mvpp2_write(priv, + MVPP2_RX_DATA_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_1GB_PORT_DATA_SIZE); + mvpp2_write(priv, + MVPP2_RX_ATTR_FIFO_SIZE_REG(port), + MVPP22_RX_FIFO_1GB_PORT_ATTR_SIZE); + } + } else { + mvpp2_write(priv, MVPP2_RX_DATA_FIFO_SIZE_REG(port), + MVPP21_RX_FIFO_PORT_DATA_SIZE); + mvpp2_write(priv, MVPP2_RX_ATTR_FIFO_SIZE_REG(port), + MVPP21_RX_FIFO_PORT_ATTR_SIZE); + } } mvpp2_write(priv, MVPP2_RX_MIN_PKT_SIZE_REG, @@ -3726,6 +4866,78 @@ static void mvpp2_rx_fifo_init(struct mvpp2 *priv) mvpp2_write(priv, MVPP2_RX_FIFO_INIT_REG, 0x1); } +/* Initialize Tx FIFO's */ +static void mvpp2_tx_fifo_init(struct mvpp2 *priv) +{ + int port, val; + + for (port = 0; port < MVPP2_MAX_PORTS; port++) { + /* Port 0 supports 10KB TX FIFO */ + if (port == 0) { + val = MVPP2_TX_FIFO_DATA_SIZE_10KB & + MVPP22_TX_FIFO_SIZE_MASK; + } else { + val = MVPP2_TX_FIFO_DATA_SIZE_3KB & + MVPP22_TX_FIFO_SIZE_MASK; + } + mvpp2_write(priv, MVPP22_TX_FIFO_SIZE_REG(port), val); + } +} + +static void mvpp2_axi_init(struct mvpp2 *priv) +{ + u32 val, rdval, wrval; + + mvpp2_write(priv, MVPP22_BM_ADDR_HIGH_RLS_REG, 0x0); + + /* AXI Bridge Configuration */ + + rdval = MVPP22_AXI_CODE_CACHE_RD_CACHE + << MVPP22_AXI_ATTR_CACHE_OFFS; + rdval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM + << MVPP22_AXI_ATTR_DOMAIN_OFFS; + + wrval = MVPP22_AXI_CODE_CACHE_WR_CACHE + << MVPP22_AXI_ATTR_CACHE_OFFS; + wrval |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM + << MVPP22_AXI_ATTR_DOMAIN_OFFS; + + /* BM */ + mvpp2_write(priv, MVPP22_AXI_BM_WR_ATTR_REG, wrval); + mvpp2_write(priv, MVPP22_AXI_BM_RD_ATTR_REG, rdval); + + /* Descriptors */ + mvpp2_write(priv, MVPP22_AXI_AGGRQ_DESCR_RD_ATTR_REG, rdval); + mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_WR_ATTR_REG, wrval); + mvpp2_write(priv, MVPP22_AXI_TXQ_DESCR_RD_ATTR_REG, rdval); + mvpp2_write(priv, MVPP22_AXI_RXQ_DESCR_WR_ATTR_REG, wrval); + + /* Buffer Data */ + mvpp2_write(priv, MVPP22_AXI_TX_DATA_RD_ATTR_REG, rdval); + mvpp2_write(priv, MVPP22_AXI_RX_DATA_WR_ATTR_REG, wrval); + + val = MVPP22_AXI_CODE_CACHE_NON_CACHE + << MVPP22_AXI_CODE_CACHE_OFFS; + val |= MVPP22_AXI_CODE_DOMAIN_SYSTEM + << MVPP22_AXI_CODE_DOMAIN_OFFS; + mvpp2_write(priv, MVPP22_AXI_RD_NORMAL_CODE_REG, val); + mvpp2_write(priv, MVPP22_AXI_WR_NORMAL_CODE_REG, val); + + val = MVPP22_AXI_CODE_CACHE_RD_CACHE + << MVPP22_AXI_CODE_CACHE_OFFS; + val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM + << MVPP22_AXI_CODE_DOMAIN_OFFS; + + mvpp2_write(priv, MVPP22_AXI_RD_SNOOP_CODE_REG, val); + + val = MVPP22_AXI_CODE_CACHE_WR_CACHE + << MVPP22_AXI_CODE_CACHE_OFFS; + val |= MVPP22_AXI_CODE_DOMAIN_OUTER_DOM + << MVPP22_AXI_CODE_DOMAIN_OFFS; + + mvpp2_write(priv, MVPP22_AXI_WR_SNOOP_CODE_REG, val); +} + /* Initialize network controller common part HW */ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) { @@ -3734,7 +4946,8 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) u32 val; /* Checks for hardware constraints (U-Boot uses only one rxq) */ - if ((rxq_number > MVPP2_MAX_RXQ) || (txq_number > MVPP2_MAX_TXQ)) { + if ((rxq_number > priv->max_port_rxqs) || + (txq_number > MVPP2_MAX_TXQ)) { dev_err(&pdev->dev, "invalid queue size parameter\n"); return -EINVAL; } @@ -3744,10 +4957,20 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) if (dram_target_info) mvpp2_conf_mbus_windows(dram_target_info, priv); - /* Disable HW PHY polling */ - val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG); - val |= MVPP2_PHY_AN_STOP_SMI0_MASK; - writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG); + if (priv->hw_version == MVPP22) + mvpp2_axi_init(priv); + + if (priv->hw_version == MVPP21) { + /* Disable HW PHY polling */ + val = readl(priv->lms_base + MVPP2_PHY_AN_CFG0_REG); + val |= MVPP2_PHY_AN_STOP_SMI0_MASK; + writel(val, priv->lms_base + MVPP2_PHY_AN_CFG0_REG); + } else { + /* Enable HW PHY polling */ + val = readl(priv->iface_base + MVPP22_SMI_MISC_CFG_REG); + val |= MVPP22_SMI_POLLING_EN; + writel(val, priv->iface_base + MVPP22_SMI_MISC_CFG_REG); + } /* Allocate and initialize aggregated TXQs */ priv->aggr_txqs = devm_kcalloc(dev, num_present_cpus(), @@ -3768,13 +4991,32 @@ static int mvpp2_init(struct udevice *dev, struct mvpp2 *priv) /* Rx Fifo Init */ mvpp2_rx_fifo_init(priv); + /* Tx Fifo Init */ + if (priv->hw_version == MVPP22) + mvpp2_tx_fifo_init(priv); + /* Reset Rx queue group interrupt configuration */ - for (i = 0; i < MVPP2_MAX_PORTS; i++) - mvpp2_write(priv, MVPP2_ISR_RXQ_GROUP_REG(i), - CONFIG_MV_ETH_RXQ); + for (i = 0; i < MVPP2_MAX_PORTS; i++) { + if (priv->hw_version == MVPP21) { + mvpp2_write(priv, MVPP21_ISR_RXQ_GROUP_REG(i), + CONFIG_MV_ETH_RXQ); + continue; + } else { + u32 val; + + val = (i << MVPP22_ISR_RXQ_GROUP_INDEX_GROUP_OFFSET); + mvpp2_write(priv, MVPP22_ISR_RXQ_GROUP_INDEX_REG, val); + + val = (CONFIG_MV_ETH_RXQ << + MVPP22_ISR_RXQ_SUB_GROUP_SIZE_OFFSET); + mvpp2_write(priv, + MVPP22_ISR_RXQ_SUB_GROUP_CONFIG_REG, val); + } + } - writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT, - priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG); + if (priv->hw_version == MVPP21) + writel(MVPP2_EXT_GLOBAL_CTRL_DEFAULT, + priv->lms_base + MVPP2_MNG_EXTENDED_GLOBAL_CTRL_REG); /* Allow cache snoop when transmiting packets */ mvpp2_write(priv, MVPP2_TX_SNOOP_REG, 0x1); @@ -3805,7 +5047,7 @@ static int smi_wait_ready(struct mvpp2 *priv) /* wait till the SMI is not busy */ do { /* read smi register */ - smi_reg = readl(priv->lms_base + MVPP2_SMI); + smi_reg = readl(priv->mdio_base); if (timeout-- == 0) { printf("Error: SMI busy timeout\n"); return -EFAULT; @@ -3847,14 +5089,14 @@ static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) | MVPP2_SMI_OPCODE_READ; /* write the smi register */ - writel(smi_reg, priv->lms_base + MVPP2_SMI); + writel(smi_reg, priv->mdio_base); /* wait till read value is ready */ timeout = MVPP2_SMI_TIMEOUT; do { /* read smi register */ - smi_reg = readl(priv->lms_base + MVPP2_SMI); + smi_reg = readl(priv->mdio_base); if (timeout-- == 0) { printf("Err: SMI read ready timeout\n"); return -EFAULT; @@ -3865,7 +5107,7 @@ static int mpp2_mdio_read(struct mii_dev *bus, int addr, int devad, int reg) for (timeout = 0; timeout < MVPP2_SMI_TIMEOUT; timeout++) ; - return readl(priv->lms_base + MVPP2_SMI) & MVPP2_SMI_DATA_MASK; + return readl(priv->mdio_base) & MVPP2_SMI_DATA_MASK; } /* @@ -3902,7 +5144,7 @@ static int mpp2_mdio_write(struct mii_dev *bus, int addr, int devad, int reg, smi_reg &= ~MVPP2_SMI_OPCODE_READ; /* write the smi register */ - writel(smi_reg, priv->lms_base + MVPP2_SMI); + writel(smi_reg, priv->mdio_base); return 0; } @@ -4090,43 +5332,14 @@ static void mvpp2_stop(struct udevice *dev) mvpp2_cleanup_txqs(port); } -static int mvpp2_probe(struct udevice *dev) +static int mvpp22_smi_phy_addr_cfg(struct mvpp2_port *port) { - struct mvpp2_port *port = dev_get_priv(dev); - struct mvpp2 *priv = dev_get_priv(dev->parent); - int err; - - /* Initialize network controller */ - err = mvpp2_init(dev, priv); - if (err < 0) { - dev_err(&pdev->dev, "failed to initialize controller\n"); - return err; - } + writel(port->phyaddr, port->priv->iface_base + + MVPP22_SMI_PHY_ADDR_REG(port->gop_id)); - return mvpp2_port_probe(dev, port, dev_of_offset(dev), priv, - &buffer_loc.first_rxq); + return 0; } -static const struct eth_ops mvpp2_ops = { - .start = mvpp2_start, - .send = mvpp2_send, - .recv = mvpp2_recv, - .stop = mvpp2_stop, -}; - -static struct driver mvpp2_driver = { - .name = "mvpp2", - .id = UCLASS_ETH, - .probe = mvpp2_probe, - .ops = &mvpp2_ops, - .priv_auto_alloc_size = sizeof(struct mvpp2_port), - .platdata_auto_alloc_size = sizeof(struct eth_pdata), -}; - -/* - * Use a MISC device to bind the n instances (child nodes) of the - * network base controller in UCLASS_ETH. - */ static int mvpp2_base_probe(struct udevice *dev) { struct mvpp2 *priv = dev_get_priv(dev); @@ -4165,7 +5378,10 @@ static int mvpp2_base_probe(struct udevice *dev) for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) { buffer_loc.bm_pool[i] = (unsigned long *)((unsigned long)bd_space + size); - size += MVPP2_BM_POOL_SIZE_MAX * sizeof(u32); + if (priv->hw_version == MVPP21) + size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u32); + else + size += MVPP2_BM_POOL_SIZE_MAX * 2 * sizeof(u64); } for (i = 0; i < MVPP2_BM_LONG_BUF_NUM; i++) { @@ -4174,14 +5390,37 @@ static int mvpp2_base_probe(struct udevice *dev) size += RX_BUFFER_SIZE; } + /* Clear the complete area so that all descriptors are cleared */ + memset(bd_space, 0, size); + /* Save base addresses for later use */ priv->base = (void *)dev_get_addr_index(dev, 0); if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - priv->lms_base = (void *)dev_get_addr_index(dev, 1); - if (IS_ERR(priv->lms_base)) - return PTR_ERR(priv->lms_base); + if (priv->hw_version == MVPP21) { + priv->lms_base = (void *)dev_get_addr_index(dev, 1); + if (IS_ERR(priv->lms_base)) + return PTR_ERR(priv->lms_base); + + priv->mdio_base = priv->lms_base + MVPP21_SMI; + } else { + priv->iface_base = (void *)dev_get_addr_index(dev, 1); + if (IS_ERR(priv->iface_base)) + return PTR_ERR(priv->iface_base); + + priv->mdio_base = priv->iface_base + MVPP22_SMI; + + /* Store common base addresses for all ports */ + priv->mpcs_base = priv->iface_base + MVPP22_MPCS; + priv->xpcs_base = priv->iface_base + MVPP22_XPCS; + priv->rfu1_base = priv->iface_base + MVPP22_RFU1; + } + + if (priv->hw_version == MVPP21) + priv->max_port_rxqs = 8; + else + priv->max_port_rxqs = 32; /* Finally create and register the MDIO bus driver */ bus = mdio_alloc(); @@ -4199,6 +5438,113 @@ static int mvpp2_base_probe(struct udevice *dev) return mdio_register(bus); } +static int mvpp2_probe(struct udevice *dev) +{ + struct mvpp2_port *port = dev_get_priv(dev); + struct mvpp2 *priv = dev_get_priv(dev->parent); + int err; + + /* Only call the probe function for the parent once */ + if (!priv->probe_done) { + err = mvpp2_base_probe(dev->parent); + priv->probe_done = 1; + } + + port->priv = dev_get_priv(dev->parent); + + err = phy_info_parse(dev, port); + if (err) + return err; + + /* + * We need the port specific io base addresses at this stage, since + * gop_port_init() accesses these registers + */ + if (priv->hw_version == MVPP21) { + int priv_common_regs_num = 2; + + port->base = (void __iomem *)dev_get_addr_index( + dev->parent, priv_common_regs_num + port->id); + if (IS_ERR(port->base)) + return PTR_ERR(port->base); + } else { + port->gop_id = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), + "gop-port-id", -1); + if (port->id == -1) { + dev_err(&pdev->dev, "missing gop-port-id value\n"); + return -EINVAL; + } + + port->base = priv->iface_base + MVPP22_PORT_BASE + + port->gop_id * MVPP22_PORT_OFFSET; + + /* Set phy address of the port */ + mvpp22_smi_phy_addr_cfg(port); + + /* GoP Init */ + gop_port_init(port); + } + + /* Initialize network controller */ + err = mvpp2_init(dev, priv); + if (err < 0) { + dev_err(&pdev->dev, "failed to initialize controller\n"); + return err; + } + + err = mvpp2_port_probe(dev, port, dev_of_offset(dev), priv); + if (err) + return err; + + if (priv->hw_version == MVPP22) { + priv->netc_config |= mvpp2_netc_cfg_create(port->gop_id, + port->phy_interface); + + /* Netcomplex configurations for all ports */ + gop_netc_init(priv, MV_NETC_FIRST_PHASE); + gop_netc_init(priv, MV_NETC_SECOND_PHASE); + } + + return 0; +} + +/* + * Empty BM pool and stop its activity before the OS is started + */ +static int mvpp2_remove(struct udevice *dev) +{ + struct mvpp2_port *port = dev_get_priv(dev); + struct mvpp2 *priv = port->priv; + int i; + + for (i = 0; i < MVPP2_BM_POOLS_NUM; i++) + mvpp2_bm_pool_destroy(dev, priv, &priv->bm_pools[i]); + + return 0; +} + +static const struct eth_ops mvpp2_ops = { + .start = mvpp2_start, + .send = mvpp2_send, + .recv = mvpp2_recv, + .stop = mvpp2_stop, +}; + +static struct driver mvpp2_driver = { + .name = "mvpp2", + .id = UCLASS_ETH, + .probe = mvpp2_probe, + .remove = mvpp2_remove, + .ops = &mvpp2_ops, + .priv_auto_alloc_size = sizeof(struct mvpp2_port), + .platdata_auto_alloc_size = sizeof(struct eth_pdata), + .flags = DM_FLAG_ACTIVE_DMA, +}; + +/* + * Use a MISC device to bind the n instances (child nodes) of the + * network base controller in UCLASS_ETH. + */ static int mvpp2_base_bind(struct udevice *parent) { const void *blob = gd->fdt_blob; @@ -4209,6 +5555,7 @@ static int mvpp2_base_bind(struct udevice *parent) char *name; int subnode; u32 id; + int base_id_add; /* Lookup eth driver */ drv = lists_uclass_lookup(UCLASS_ETH); @@ -4217,7 +5564,12 @@ static int mvpp2_base_bind(struct udevice *parent) return -ENOENT; } + base_id_add = base_id; + fdt_for_each_subnode(subnode, blob, node) { + /* Increment base_id for all subnodes, also the disabled ones */ + base_id++; + /* Skip disabled ports */ if (!fdtdec_get_is_enabled(blob, subnode)) continue; @@ -4227,6 +5579,7 @@ static int mvpp2_base_bind(struct udevice *parent) return -ENOMEM; id = fdtdec_get_int(blob, subnode, "port-id", -1); + id += base_id_add; name = calloc(1, 16); sprintf(name, "mvpp2-%d", id); @@ -4244,6 +5597,10 @@ static const struct udevice_id mvpp2_ids[] = { .compatible = "marvell,armada-375-pp2", .data = MVPP21, }, + { + .compatible = "marvell,armada-7k-pp22", + .data = MVPP22, + }, { } }; @@ -4252,6 +5609,5 @@ U_BOOT_DRIVER(mvpp2_base) = { .id = UCLASS_MISC, .of_match = mvpp2_ids, .bind = mvpp2_base_bind, - .probe = mvpp2_base_probe, .priv_auto_alloc_size = sizeof(struct mvpp2), };