18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright 2008-2015 Freescale Semiconductor Inc. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 58c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions are met: 68c2ecf20Sopenharmony_ci * * Redistributions of source code must retain the above copyright 78c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 88c2ecf20Sopenharmony_ci * * Redistributions in binary form must reproduce the above copyright 98c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 108c2ecf20Sopenharmony_ci * documentation and/or other materials provided with the distribution. 118c2ecf20Sopenharmony_ci * * Neither the name of Freescale Semiconductor nor the 128c2ecf20Sopenharmony_ci * names of its contributors may be used to endorse or promote products 138c2ecf20Sopenharmony_ci * derived from this software without specific prior written permission. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the 178c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software 188c2ecf20Sopenharmony_ci * Foundation, either version 2 of that License or (at your option) any 198c2ecf20Sopenharmony_ci * later version. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY 228c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 238c2ecf20Sopenharmony_ci * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 248c2ecf20Sopenharmony_ci * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY 258c2ecf20Sopenharmony_ci * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 268c2ecf20Sopenharmony_ci * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 278c2ecf20Sopenharmony_ci * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 288c2ecf20Sopenharmony_ci * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 298c2ecf20Sopenharmony_ci * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 308c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "fman_memac.h" 368c2ecf20Sopenharmony_ci#include "fman.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/io.h> 408c2ecf20Sopenharmony_ci#include <linux/phy.h> 418c2ecf20Sopenharmony_ci#include <linux/phy_fixed.h> 428c2ecf20Sopenharmony_ci#include <linux/of_mdio.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* PCS registers */ 458c2ecf20Sopenharmony_ci#define MDIO_SGMII_CR 0x00 468c2ecf20Sopenharmony_ci#define MDIO_SGMII_DEV_ABIL_SGMII 0x04 478c2ecf20Sopenharmony_ci#define MDIO_SGMII_LINK_TMR_L 0x12 488c2ecf20Sopenharmony_ci#define MDIO_SGMII_LINK_TMR_H 0x13 498c2ecf20Sopenharmony_ci#define MDIO_SGMII_IF_MODE 0x14 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* SGMII Control defines */ 528c2ecf20Sopenharmony_ci#define SGMII_CR_AN_EN 0x1000 538c2ecf20Sopenharmony_ci#define SGMII_CR_RESTART_AN 0x0200 548c2ecf20Sopenharmony_ci#define SGMII_CR_FD 0x0100 558c2ecf20Sopenharmony_ci#define SGMII_CR_SPEED_SEL1_1G 0x0040 568c2ecf20Sopenharmony_ci#define SGMII_CR_DEF_VAL (SGMII_CR_AN_EN | SGMII_CR_FD | \ 578c2ecf20Sopenharmony_ci SGMII_CR_SPEED_SEL1_1G) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* SGMII Device Ability for SGMII defines */ 608c2ecf20Sopenharmony_ci#define MDIO_SGMII_DEV_ABIL_SGMII_MODE 0x4001 618c2ecf20Sopenharmony_ci#define MDIO_SGMII_DEV_ABIL_BASEX_MODE 0x01A0 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Link timer define */ 648c2ecf20Sopenharmony_ci#define LINK_TMR_L 0xa120 658c2ecf20Sopenharmony_ci#define LINK_TMR_H 0x0007 668c2ecf20Sopenharmony_ci#define LINK_TMR_L_BASEX 0xaf08 678c2ecf20Sopenharmony_ci#define LINK_TMR_H_BASEX 0x002f 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* SGMII IF Mode defines */ 708c2ecf20Sopenharmony_ci#define IF_MODE_USE_SGMII_AN 0x0002 718c2ecf20Sopenharmony_ci#define IF_MODE_SGMII_EN 0x0001 728c2ecf20Sopenharmony_ci#define IF_MODE_SGMII_SPEED_100M 0x0004 738c2ecf20Sopenharmony_ci#define IF_MODE_SGMII_SPEED_1G 0x0008 748c2ecf20Sopenharmony_ci#define IF_MODE_SGMII_DUPLEX_HALF 0x0010 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* Num of additional exact match MAC adr regs */ 778c2ecf20Sopenharmony_ci#define MEMAC_NUM_OF_PADDRS 7 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* Control and Configuration Register (COMMAND_CONFIG) */ 808c2ecf20Sopenharmony_ci#define CMD_CFG_REG_LOWP_RXETY 0x01000000 /* 07 Rx low power indication */ 818c2ecf20Sopenharmony_ci#define CMD_CFG_TX_LOWP_ENA 0x00800000 /* 08 Tx Low Power Idle Enable */ 828c2ecf20Sopenharmony_ci#define CMD_CFG_PFC_MODE 0x00080000 /* 12 Enable PFC */ 838c2ecf20Sopenharmony_ci#define CMD_CFG_NO_LEN_CHK 0x00020000 /* 14 Payload length check disable */ 848c2ecf20Sopenharmony_ci#define CMD_CFG_SW_RESET 0x00001000 /* 19 S/W Reset, self clearing bit */ 858c2ecf20Sopenharmony_ci#define CMD_CFG_TX_PAD_EN 0x00000800 /* 20 Enable Tx padding of frames */ 868c2ecf20Sopenharmony_ci#define CMD_CFG_PAUSE_IGNORE 0x00000100 /* 23 Ignore Pause frame quanta */ 878c2ecf20Sopenharmony_ci#define CMD_CFG_CRC_FWD 0x00000040 /* 25 Terminate/frwd CRC of frames */ 888c2ecf20Sopenharmony_ci#define CMD_CFG_PAD_EN 0x00000020 /* 26 Frame padding removal */ 898c2ecf20Sopenharmony_ci#define CMD_CFG_PROMIS_EN 0x00000010 /* 27 Promiscuous operation enable */ 908c2ecf20Sopenharmony_ci#define CMD_CFG_RX_EN 0x00000002 /* 30 MAC receive path enable */ 918c2ecf20Sopenharmony_ci#define CMD_CFG_TX_EN 0x00000001 /* 31 MAC transmit path enable */ 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Transmit FIFO Sections Register (TX_FIFO_SECTIONS) */ 948c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_EMPTY_MASK 0xFFFF0000 958c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_AVAIL_MASK 0x0000FFFF 968c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G 0x00400000 978c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G 0x00100000 988c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_AVAIL_10G 0x00000019 998c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_AVAIL_1G 0x00000020 1008c2ecf20Sopenharmony_ci#define TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G 0x00000060 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci#define GET_TX_EMPTY_DEFAULT_VALUE(_val) \ 1038c2ecf20Sopenharmony_cido { \ 1048c2ecf20Sopenharmony_ci _val &= ~TX_FIFO_SECTIONS_TX_EMPTY_MASK; \ 1058c2ecf20Sopenharmony_ci ((_val == TX_FIFO_SECTIONS_TX_AVAIL_10G) ? \ 1068c2ecf20Sopenharmony_ci (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G) :\ 1078c2ecf20Sopenharmony_ci (_val |= TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G));\ 1088c2ecf20Sopenharmony_ci} while (0) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Interface Mode Register (IF_MODE) */ 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define IF_MODE_MASK 0x00000003 /* 30-31 Mask on i/f mode bits */ 1138c2ecf20Sopenharmony_ci#define IF_MODE_10G 0x00000000 /* 30-31 10G interface */ 1148c2ecf20Sopenharmony_ci#define IF_MODE_GMII 0x00000002 /* 30-31 GMII (1G) interface */ 1158c2ecf20Sopenharmony_ci#define IF_MODE_RGMII 0x00000004 1168c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_AUTO 0x00008000 1178c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_1000 0x00004000 /* 10 - 1000Mbps RGMII */ 1188c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_100 0x00000000 /* 00 - 100Mbps RGMII */ 1198c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_10 0x00002000 /* 01 - 10Mbps RGMII */ 1208c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_SP_MASK 0x00006000 /* Setsp mask bits */ 1218c2ecf20Sopenharmony_ci#define IF_MODE_RGMII_FD 0x00001000 /* Full duplex RGMII */ 1228c2ecf20Sopenharmony_ci#define IF_MODE_HD 0x00000040 /* Half duplex operation */ 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* Hash table Control Register (HASHTABLE_CTRL) */ 1258c2ecf20Sopenharmony_ci#define HASH_CTRL_MCAST_EN 0x00000100 1268c2ecf20Sopenharmony_ci/* 26-31 Hash table address code */ 1278c2ecf20Sopenharmony_ci#define HASH_CTRL_ADDR_MASK 0x0000003F 1288c2ecf20Sopenharmony_ci/* MAC mcast indication */ 1298c2ecf20Sopenharmony_ci#define GROUP_ADDRESS 0x0000010000000000LL 1308c2ecf20Sopenharmony_ci#define HASH_TABLE_SIZE 64 /* Hash tbl size */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci/* Interrupt Mask Register (IMASK) */ 1338c2ecf20Sopenharmony_ci#define MEMAC_IMASK_MGI 0x40000000 /* 1 Magic pkt detect indication */ 1348c2ecf20Sopenharmony_ci#define MEMAC_IMASK_TSECC_ER 0x20000000 /* 2 Timestamp FIFO ECC error evnt */ 1358c2ecf20Sopenharmony_ci#define MEMAC_IMASK_TECC_ER 0x02000000 /* 6 Transmit frame ECC error evnt */ 1368c2ecf20Sopenharmony_ci#define MEMAC_IMASK_RECC_ER 0x01000000 /* 7 Receive frame ECC error evnt */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci#define MEMAC_ALL_ERRS_IMASK \ 1398c2ecf20Sopenharmony_ci ((u32)(MEMAC_IMASK_TSECC_ER | \ 1408c2ecf20Sopenharmony_ci MEMAC_IMASK_TECC_ER | \ 1418c2ecf20Sopenharmony_ci MEMAC_IMASK_RECC_ER | \ 1428c2ecf20Sopenharmony_ci MEMAC_IMASK_MGI)) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_PCS 0x80000000 /* PCS (XG). Link sync (G) */ 1458c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_AN 0x40000000 /* Auto-negotiation */ 1468c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_LT 0x20000000 /* Link Training/New page */ 1478c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_MGI 0x00004000 /* Magic pkt detection */ 1488c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_TS_ECC_ER 0x00002000 /* Timestamp FIFO ECC error*/ 1498c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_RX_FIFO_OVFL 0x00001000 /* Rx FIFO overflow */ 1508c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_TX_FIFO_UNFL 0x00000800 /* Tx FIFO underflow */ 1518c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_TX_FIFO_OVFL 0x00000400 /* Tx FIFO overflow */ 1528c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_TX_ECC_ER 0x00000200 /* Tx frame ECC error */ 1538c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_RX_ECC_ER 0x00000100 /* Rx frame ECC error */ 1548c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_LI_FAULT 0x00000080 /* Link Interruption flt */ 1558c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_RX_EMPTY 0x00000040 /* Rx FIFO empty */ 1568c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_TX_EMPTY 0x00000020 /* Tx FIFO empty */ 1578c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_RX_LOWP 0x00000010 /* Low Power Idle */ 1588c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_PHY_LOS 0x00000004 /* Phy loss of signal */ 1598c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_REM_FAULT 0x00000002 /* Remote fault (XGMII) */ 1608c2ecf20Sopenharmony_ci#define MEMAC_IEVNT_LOC_FAULT 0x00000001 /* Local fault (XGMII) */ 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci#define DEFAULT_PAUSE_QUANTA 0xf000 1638c2ecf20Sopenharmony_ci#define DEFAULT_FRAME_LENGTH 0x600 1648c2ecf20Sopenharmony_ci#define DEFAULT_TX_IPG_LENGTH 12 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define CLXY_PAUSE_QUANTA_CLX_PQNT 0x0000FFFF 1678c2ecf20Sopenharmony_ci#define CLXY_PAUSE_QUANTA_CLY_PQNT 0xFFFF0000 1688c2ecf20Sopenharmony_ci#define CLXY_PAUSE_THRESH_CLX_QTH 0x0000FFFF 1698c2ecf20Sopenharmony_ci#define CLXY_PAUSE_THRESH_CLY_QTH 0xFFFF0000 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct mac_addr { 1728c2ecf20Sopenharmony_ci /* Lower 32 bits of 48-bit MAC address */ 1738c2ecf20Sopenharmony_ci u32 mac_addr_l; 1748c2ecf20Sopenharmony_ci /* Upper 16 bits of 48-bit MAC address */ 1758c2ecf20Sopenharmony_ci u32 mac_addr_u; 1768c2ecf20Sopenharmony_ci}; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* memory map */ 1798c2ecf20Sopenharmony_cistruct memac_regs { 1808c2ecf20Sopenharmony_ci u32 res0000[2]; /* General Control and Status */ 1818c2ecf20Sopenharmony_ci u32 command_config; /* 0x008 Ctrl and cfg */ 1828c2ecf20Sopenharmony_ci struct mac_addr mac_addr0; /* 0x00C-0x010 MAC_ADDR_0...1 */ 1838c2ecf20Sopenharmony_ci u32 maxfrm; /* 0x014 Max frame length */ 1848c2ecf20Sopenharmony_ci u32 res0018[1]; 1858c2ecf20Sopenharmony_ci u32 rx_fifo_sections; /* Receive FIFO configuration reg */ 1868c2ecf20Sopenharmony_ci u32 tx_fifo_sections; /* Transmit FIFO configuration reg */ 1878c2ecf20Sopenharmony_ci u32 res0024[2]; 1888c2ecf20Sopenharmony_ci u32 hashtable_ctrl; /* 0x02C Hash table control */ 1898c2ecf20Sopenharmony_ci u32 res0030[4]; 1908c2ecf20Sopenharmony_ci u32 ievent; /* 0x040 Interrupt event */ 1918c2ecf20Sopenharmony_ci u32 tx_ipg_length; /* 0x044 Transmitter inter-packet-gap */ 1928c2ecf20Sopenharmony_ci u32 res0048; 1938c2ecf20Sopenharmony_ci u32 imask; /* 0x04C Interrupt mask */ 1948c2ecf20Sopenharmony_ci u32 res0050; 1958c2ecf20Sopenharmony_ci u32 pause_quanta[4]; /* 0x054 Pause quanta */ 1968c2ecf20Sopenharmony_ci u32 pause_thresh[4]; /* 0x064 Pause quanta threshold */ 1978c2ecf20Sopenharmony_ci u32 rx_pause_status; /* 0x074 Receive pause status */ 1988c2ecf20Sopenharmony_ci u32 res0078[2]; 1998c2ecf20Sopenharmony_ci struct mac_addr mac_addr[MEMAC_NUM_OF_PADDRS];/* 0x80-0x0B4 mac padr */ 2008c2ecf20Sopenharmony_ci u32 lpwake_timer; /* 0x0B8 Low Power Wakeup Timer */ 2018c2ecf20Sopenharmony_ci u32 sleep_timer; /* 0x0BC Transmit EEE Low Power Timer */ 2028c2ecf20Sopenharmony_ci u32 res00c0[8]; 2038c2ecf20Sopenharmony_ci u32 statn_config; /* 0x0E0 Statistics configuration */ 2048c2ecf20Sopenharmony_ci u32 res00e4[7]; 2058c2ecf20Sopenharmony_ci /* Rx Statistics Counter */ 2068c2ecf20Sopenharmony_ci u32 reoct_l; 2078c2ecf20Sopenharmony_ci u32 reoct_u; 2088c2ecf20Sopenharmony_ci u32 roct_l; 2098c2ecf20Sopenharmony_ci u32 roct_u; 2108c2ecf20Sopenharmony_ci u32 raln_l; 2118c2ecf20Sopenharmony_ci u32 raln_u; 2128c2ecf20Sopenharmony_ci u32 rxpf_l; 2138c2ecf20Sopenharmony_ci u32 rxpf_u; 2148c2ecf20Sopenharmony_ci u32 rfrm_l; 2158c2ecf20Sopenharmony_ci u32 rfrm_u; 2168c2ecf20Sopenharmony_ci u32 rfcs_l; 2178c2ecf20Sopenharmony_ci u32 rfcs_u; 2188c2ecf20Sopenharmony_ci u32 rvlan_l; 2198c2ecf20Sopenharmony_ci u32 rvlan_u; 2208c2ecf20Sopenharmony_ci u32 rerr_l; 2218c2ecf20Sopenharmony_ci u32 rerr_u; 2228c2ecf20Sopenharmony_ci u32 ruca_l; 2238c2ecf20Sopenharmony_ci u32 ruca_u; 2248c2ecf20Sopenharmony_ci u32 rmca_l; 2258c2ecf20Sopenharmony_ci u32 rmca_u; 2268c2ecf20Sopenharmony_ci u32 rbca_l; 2278c2ecf20Sopenharmony_ci u32 rbca_u; 2288c2ecf20Sopenharmony_ci u32 rdrp_l; 2298c2ecf20Sopenharmony_ci u32 rdrp_u; 2308c2ecf20Sopenharmony_ci u32 rpkt_l; 2318c2ecf20Sopenharmony_ci u32 rpkt_u; 2328c2ecf20Sopenharmony_ci u32 rund_l; 2338c2ecf20Sopenharmony_ci u32 rund_u; 2348c2ecf20Sopenharmony_ci u32 r64_l; 2358c2ecf20Sopenharmony_ci u32 r64_u; 2368c2ecf20Sopenharmony_ci u32 r127_l; 2378c2ecf20Sopenharmony_ci u32 r127_u; 2388c2ecf20Sopenharmony_ci u32 r255_l; 2398c2ecf20Sopenharmony_ci u32 r255_u; 2408c2ecf20Sopenharmony_ci u32 r511_l; 2418c2ecf20Sopenharmony_ci u32 r511_u; 2428c2ecf20Sopenharmony_ci u32 r1023_l; 2438c2ecf20Sopenharmony_ci u32 r1023_u; 2448c2ecf20Sopenharmony_ci u32 r1518_l; 2458c2ecf20Sopenharmony_ci u32 r1518_u; 2468c2ecf20Sopenharmony_ci u32 r1519x_l; 2478c2ecf20Sopenharmony_ci u32 r1519x_u; 2488c2ecf20Sopenharmony_ci u32 rovr_l; 2498c2ecf20Sopenharmony_ci u32 rovr_u; 2508c2ecf20Sopenharmony_ci u32 rjbr_l; 2518c2ecf20Sopenharmony_ci u32 rjbr_u; 2528c2ecf20Sopenharmony_ci u32 rfrg_l; 2538c2ecf20Sopenharmony_ci u32 rfrg_u; 2548c2ecf20Sopenharmony_ci u32 rcnp_l; 2558c2ecf20Sopenharmony_ci u32 rcnp_u; 2568c2ecf20Sopenharmony_ci u32 rdrntp_l; 2578c2ecf20Sopenharmony_ci u32 rdrntp_u; 2588c2ecf20Sopenharmony_ci u32 res01d0[12]; 2598c2ecf20Sopenharmony_ci /* Tx Statistics Counter */ 2608c2ecf20Sopenharmony_ci u32 teoct_l; 2618c2ecf20Sopenharmony_ci u32 teoct_u; 2628c2ecf20Sopenharmony_ci u32 toct_l; 2638c2ecf20Sopenharmony_ci u32 toct_u; 2648c2ecf20Sopenharmony_ci u32 res0210[2]; 2658c2ecf20Sopenharmony_ci u32 txpf_l; 2668c2ecf20Sopenharmony_ci u32 txpf_u; 2678c2ecf20Sopenharmony_ci u32 tfrm_l; 2688c2ecf20Sopenharmony_ci u32 tfrm_u; 2698c2ecf20Sopenharmony_ci u32 tfcs_l; 2708c2ecf20Sopenharmony_ci u32 tfcs_u; 2718c2ecf20Sopenharmony_ci u32 tvlan_l; 2728c2ecf20Sopenharmony_ci u32 tvlan_u; 2738c2ecf20Sopenharmony_ci u32 terr_l; 2748c2ecf20Sopenharmony_ci u32 terr_u; 2758c2ecf20Sopenharmony_ci u32 tuca_l; 2768c2ecf20Sopenharmony_ci u32 tuca_u; 2778c2ecf20Sopenharmony_ci u32 tmca_l; 2788c2ecf20Sopenharmony_ci u32 tmca_u; 2798c2ecf20Sopenharmony_ci u32 tbca_l; 2808c2ecf20Sopenharmony_ci u32 tbca_u; 2818c2ecf20Sopenharmony_ci u32 res0258[2]; 2828c2ecf20Sopenharmony_ci u32 tpkt_l; 2838c2ecf20Sopenharmony_ci u32 tpkt_u; 2848c2ecf20Sopenharmony_ci u32 tund_l; 2858c2ecf20Sopenharmony_ci u32 tund_u; 2868c2ecf20Sopenharmony_ci u32 t64_l; 2878c2ecf20Sopenharmony_ci u32 t64_u; 2888c2ecf20Sopenharmony_ci u32 t127_l; 2898c2ecf20Sopenharmony_ci u32 t127_u; 2908c2ecf20Sopenharmony_ci u32 t255_l; 2918c2ecf20Sopenharmony_ci u32 t255_u; 2928c2ecf20Sopenharmony_ci u32 t511_l; 2938c2ecf20Sopenharmony_ci u32 t511_u; 2948c2ecf20Sopenharmony_ci u32 t1023_l; 2958c2ecf20Sopenharmony_ci u32 t1023_u; 2968c2ecf20Sopenharmony_ci u32 t1518_l; 2978c2ecf20Sopenharmony_ci u32 t1518_u; 2988c2ecf20Sopenharmony_ci u32 t1519x_l; 2998c2ecf20Sopenharmony_ci u32 t1519x_u; 3008c2ecf20Sopenharmony_ci u32 res02a8[6]; 3018c2ecf20Sopenharmony_ci u32 tcnp_l; 3028c2ecf20Sopenharmony_ci u32 tcnp_u; 3038c2ecf20Sopenharmony_ci u32 res02c8[14]; 3048c2ecf20Sopenharmony_ci /* Line Interface Control */ 3058c2ecf20Sopenharmony_ci u32 if_mode; /* 0x300 Interface Mode Control */ 3068c2ecf20Sopenharmony_ci u32 if_status; /* 0x304 Interface Status */ 3078c2ecf20Sopenharmony_ci u32 res0308[14]; 3088c2ecf20Sopenharmony_ci /* HiGig/2 */ 3098c2ecf20Sopenharmony_ci u32 hg_config; /* 0x340 Control and cfg */ 3108c2ecf20Sopenharmony_ci u32 res0344[3]; 3118c2ecf20Sopenharmony_ci u32 hg_pause_quanta; /* 0x350 Pause quanta */ 3128c2ecf20Sopenharmony_ci u32 res0354[3]; 3138c2ecf20Sopenharmony_ci u32 hg_pause_thresh; /* 0x360 Pause quanta threshold */ 3148c2ecf20Sopenharmony_ci u32 res0364[3]; 3158c2ecf20Sopenharmony_ci u32 hgrx_pause_status; /* 0x370 Receive pause status */ 3168c2ecf20Sopenharmony_ci u32 hg_fifos_status; /* 0x374 fifos status */ 3178c2ecf20Sopenharmony_ci u32 rhm; /* 0x378 rx messages counter */ 3188c2ecf20Sopenharmony_ci u32 thm; /* 0x37C tx messages counter */ 3198c2ecf20Sopenharmony_ci}; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistruct memac_cfg { 3228c2ecf20Sopenharmony_ci bool reset_on_init; 3238c2ecf20Sopenharmony_ci bool pause_ignore; 3248c2ecf20Sopenharmony_ci bool promiscuous_mode_enable; 3258c2ecf20Sopenharmony_ci struct fixed_phy_status *fixed_link; 3268c2ecf20Sopenharmony_ci u16 max_frame_length; 3278c2ecf20Sopenharmony_ci u16 pause_quanta; 3288c2ecf20Sopenharmony_ci u32 tx_ipg_length; 3298c2ecf20Sopenharmony_ci}; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistruct fman_mac { 3328c2ecf20Sopenharmony_ci /* Pointer to MAC memory mapped registers */ 3338c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs; 3348c2ecf20Sopenharmony_ci /* MAC address of device */ 3358c2ecf20Sopenharmony_ci u64 addr; 3368c2ecf20Sopenharmony_ci /* Ethernet physical interface */ 3378c2ecf20Sopenharmony_ci phy_interface_t phy_if; 3388c2ecf20Sopenharmony_ci u16 max_speed; 3398c2ecf20Sopenharmony_ci void *dev_id; /* device cookie used by the exception cbs */ 3408c2ecf20Sopenharmony_ci fman_mac_exception_cb *exception_cb; 3418c2ecf20Sopenharmony_ci fman_mac_exception_cb *event_cb; 3428c2ecf20Sopenharmony_ci /* Pointer to driver's global address hash table */ 3438c2ecf20Sopenharmony_ci struct eth_hash_t *multicast_addr_hash; 3448c2ecf20Sopenharmony_ci /* Pointer to driver's individual address hash table */ 3458c2ecf20Sopenharmony_ci struct eth_hash_t *unicast_addr_hash; 3468c2ecf20Sopenharmony_ci u8 mac_id; 3478c2ecf20Sopenharmony_ci u32 exceptions; 3488c2ecf20Sopenharmony_ci struct memac_cfg *memac_drv_param; 3498c2ecf20Sopenharmony_ci void *fm; 3508c2ecf20Sopenharmony_ci struct fman_rev_info fm_rev_info; 3518c2ecf20Sopenharmony_ci bool basex_if; 3528c2ecf20Sopenharmony_ci struct phy_device *pcsphy; 3538c2ecf20Sopenharmony_ci bool allmulti_enabled; 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void add_addr_in_paddr(struct memac_regs __iomem *regs, u8 *adr, 3578c2ecf20Sopenharmony_ci u8 paddr_num) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci u32 tmp0, tmp1; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci tmp0 = (u32)(adr[0] | adr[1] << 8 | adr[2] << 16 | adr[3] << 24); 3628c2ecf20Sopenharmony_ci tmp1 = (u32)(adr[4] | adr[5] << 8); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (paddr_num == 0) { 3658c2ecf20Sopenharmony_ci iowrite32be(tmp0, ®s->mac_addr0.mac_addr_l); 3668c2ecf20Sopenharmony_ci iowrite32be(tmp1, ®s->mac_addr0.mac_addr_u); 3678c2ecf20Sopenharmony_ci } else { 3688c2ecf20Sopenharmony_ci iowrite32be(tmp0, ®s->mac_addr[paddr_num - 1].mac_addr_l); 3698c2ecf20Sopenharmony_ci iowrite32be(tmp1, ®s->mac_addr[paddr_num - 1].mac_addr_u); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic int reset(struct memac_regs __iomem *regs) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci u32 tmp; 3768c2ecf20Sopenharmony_ci int count; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci tmp |= CMD_CFG_SW_RESET; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci count = 100; 3858c2ecf20Sopenharmony_ci do { 3868c2ecf20Sopenharmony_ci udelay(1); 3878c2ecf20Sopenharmony_ci } while ((ioread32be(®s->command_config) & CMD_CFG_SW_RESET) && 3888c2ecf20Sopenharmony_ci --count); 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (count == 0) 3918c2ecf20Sopenharmony_ci return -EBUSY; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_cistatic void set_exception(struct memac_regs __iomem *regs, u32 val, 3978c2ecf20Sopenharmony_ci bool enable) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci u32 tmp; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci tmp = ioread32be(®s->imask); 4028c2ecf20Sopenharmony_ci if (enable) 4038c2ecf20Sopenharmony_ci tmp |= val; 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci tmp &= ~val; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->imask); 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic int init(struct memac_regs __iomem *regs, struct memac_cfg *cfg, 4118c2ecf20Sopenharmony_ci phy_interface_t phy_if, u16 speed, bool slow_10g_if, 4128c2ecf20Sopenharmony_ci u32 exceptions) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci u32 tmp; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Config */ 4178c2ecf20Sopenharmony_ci tmp = 0; 4188c2ecf20Sopenharmony_ci if (cfg->promiscuous_mode_enable) 4198c2ecf20Sopenharmony_ci tmp |= CMD_CFG_PROMIS_EN; 4208c2ecf20Sopenharmony_ci if (cfg->pause_ignore) 4218c2ecf20Sopenharmony_ci tmp |= CMD_CFG_PAUSE_IGNORE; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Payload length check disable */ 4248c2ecf20Sopenharmony_ci tmp |= CMD_CFG_NO_LEN_CHK; 4258c2ecf20Sopenharmony_ci /* Enable padding of frames in transmit direction */ 4268c2ecf20Sopenharmony_ci tmp |= CMD_CFG_TX_PAD_EN; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci tmp |= CMD_CFG_CRC_FWD; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* Max Frame Length */ 4338c2ecf20Sopenharmony_ci iowrite32be((u32)cfg->max_frame_length, ®s->maxfrm); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Pause Time */ 4368c2ecf20Sopenharmony_ci iowrite32be((u32)cfg->pause_quanta, ®s->pause_quanta[0]); 4378c2ecf20Sopenharmony_ci iowrite32be((u32)0, ®s->pause_thresh[0]); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* IF_MODE */ 4408c2ecf20Sopenharmony_ci tmp = 0; 4418c2ecf20Sopenharmony_ci switch (phy_if) { 4428c2ecf20Sopenharmony_ci case PHY_INTERFACE_MODE_XGMII: 4438c2ecf20Sopenharmony_ci tmp |= IF_MODE_10G; 4448c2ecf20Sopenharmony_ci break; 4458c2ecf20Sopenharmony_ci default: 4468c2ecf20Sopenharmony_ci tmp |= IF_MODE_GMII; 4478c2ecf20Sopenharmony_ci if (phy_if == PHY_INTERFACE_MODE_RGMII || 4488c2ecf20Sopenharmony_ci phy_if == PHY_INTERFACE_MODE_RGMII_ID || 4498c2ecf20Sopenharmony_ci phy_if == PHY_INTERFACE_MODE_RGMII_RXID || 4508c2ecf20Sopenharmony_ci phy_if == PHY_INTERFACE_MODE_RGMII_TXID) 4518c2ecf20Sopenharmony_ci tmp |= IF_MODE_RGMII | IF_MODE_RGMII_AUTO; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->if_mode); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* TX_FIFO_SECTIONS */ 4568c2ecf20Sopenharmony_ci tmp = 0; 4578c2ecf20Sopenharmony_ci if (phy_if == PHY_INTERFACE_MODE_XGMII) { 4588c2ecf20Sopenharmony_ci if (slow_10g_if) { 4598c2ecf20Sopenharmony_ci tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_SLOW_10G | 4608c2ecf20Sopenharmony_ci TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_10G | 4638c2ecf20Sopenharmony_ci TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_10G); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci } else { 4668c2ecf20Sopenharmony_ci tmp |= (TX_FIFO_SECTIONS_TX_AVAIL_1G | 4678c2ecf20Sopenharmony_ci TX_FIFO_SECTIONS_TX_EMPTY_DEFAULT_1G); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->tx_fifo_sections); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* clear all pending events and set-up interrupts */ 4728c2ecf20Sopenharmony_ci iowrite32be(0xffffffff, ®s->ievent); 4738c2ecf20Sopenharmony_ci set_exception(regs, exceptions, true); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic void set_dflts(struct memac_cfg *cfg) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci cfg->reset_on_init = false; 4818c2ecf20Sopenharmony_ci cfg->promiscuous_mode_enable = false; 4828c2ecf20Sopenharmony_ci cfg->pause_ignore = false; 4838c2ecf20Sopenharmony_ci cfg->tx_ipg_length = DEFAULT_TX_IPG_LENGTH; 4848c2ecf20Sopenharmony_ci cfg->max_frame_length = DEFAULT_FRAME_LENGTH; 4858c2ecf20Sopenharmony_ci cfg->pause_quanta = DEFAULT_PAUSE_QUANTA; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic u32 get_mac_addr_hash_code(u64 eth_addr) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci u64 mask1, mask2; 4918c2ecf20Sopenharmony_ci u32 xor_val = 0; 4928c2ecf20Sopenharmony_ci u8 i, j; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci for (i = 0; i < 6; i++) { 4958c2ecf20Sopenharmony_ci mask1 = eth_addr & (u64)0x01; 4968c2ecf20Sopenharmony_ci eth_addr >>= 1; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci for (j = 0; j < 7; j++) { 4998c2ecf20Sopenharmony_ci mask2 = eth_addr & (u64)0x01; 5008c2ecf20Sopenharmony_ci mask1 ^= mask2; 5018c2ecf20Sopenharmony_ci eth_addr >>= 1; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci xor_val |= (mask1 << (5 - i)); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return xor_val; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic void setup_sgmii_internal_phy(struct fman_mac *memac, 5118c2ecf20Sopenharmony_ci struct fixed_phy_status *fixed_link) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci u16 tmp_reg16; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci if (WARN_ON(!memac->pcsphy)) 5168c2ecf20Sopenharmony_ci return; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci /* SGMII mode */ 5198c2ecf20Sopenharmony_ci tmp_reg16 = IF_MODE_SGMII_EN; 5208c2ecf20Sopenharmony_ci if (!fixed_link) 5218c2ecf20Sopenharmony_ci /* AN enable */ 5228c2ecf20Sopenharmony_ci tmp_reg16 |= IF_MODE_USE_SGMII_AN; 5238c2ecf20Sopenharmony_ci else { 5248c2ecf20Sopenharmony_ci switch (fixed_link->speed) { 5258c2ecf20Sopenharmony_ci case 10: 5268c2ecf20Sopenharmony_ci /* For 10M: IF_MODE[SPEED_10M] = 0 */ 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci case 100: 5298c2ecf20Sopenharmony_ci tmp_reg16 |= IF_MODE_SGMII_SPEED_100M; 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci case 1000: 5328c2ecf20Sopenharmony_ci default: 5338c2ecf20Sopenharmony_ci tmp_reg16 |= IF_MODE_SGMII_SPEED_1G; 5348c2ecf20Sopenharmony_ci break; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci if (!fixed_link->duplex) 5378c2ecf20Sopenharmony_ci tmp_reg16 |= IF_MODE_SGMII_DUPLEX_HALF; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_IF_MODE, tmp_reg16); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* Device ability according to SGMII specification */ 5428c2ecf20Sopenharmony_ci tmp_reg16 = MDIO_SGMII_DEV_ABIL_SGMII_MODE; 5438c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* Adjust link timer for SGMII - 5468c2ecf20Sopenharmony_ci * According to Cisco SGMII specification the timer should be 1.6 ms. 5478c2ecf20Sopenharmony_ci * The link_timer register is configured in units of the clock. 5488c2ecf20Sopenharmony_ci * - When running as 1G SGMII, Serdes clock is 125 MHz, so 5498c2ecf20Sopenharmony_ci * unit = 1 / (125*10^6 Hz) = 8 ns. 5508c2ecf20Sopenharmony_ci * 1.6 ms in units of 8 ns = 1.6ms / 8ns = 2*10^5 = 0x30d40 5518c2ecf20Sopenharmony_ci * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so 5528c2ecf20Sopenharmony_ci * unit = 1 / (312.5*10^6 Hz) = 3.2 ns. 5538c2ecf20Sopenharmony_ci * 1.6 ms in units of 3.2 ns = 1.6ms / 3.2ns = 5*10^5 = 0x7a120. 5548c2ecf20Sopenharmony_ci * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, 5558c2ecf20Sopenharmony_ci * we always set up here a value of 2.5 SGMII. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H); 5588c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci if (!fixed_link) 5618c2ecf20Sopenharmony_ci /* Restart AN */ 5628c2ecf20Sopenharmony_ci tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN; 5638c2ecf20Sopenharmony_ci else 5648c2ecf20Sopenharmony_ci /* AN disabled */ 5658c2ecf20Sopenharmony_ci tmp_reg16 = SGMII_CR_DEF_VAL & ~SGMII_CR_AN_EN; 5668c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, 0x0, tmp_reg16); 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_cistatic void setup_sgmii_internal_phy_base_x(struct fman_mac *memac) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci u16 tmp_reg16; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* AN Device capability */ 5748c2ecf20Sopenharmony_ci tmp_reg16 = MDIO_SGMII_DEV_ABIL_BASEX_MODE; 5758c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_DEV_ABIL_SGMII, tmp_reg16); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci /* Adjust link timer for SGMII - 5788c2ecf20Sopenharmony_ci * For Serdes 1000BaseX auto-negotiation the timer should be 10 ms. 5798c2ecf20Sopenharmony_ci * The link_timer register is configured in units of the clock. 5808c2ecf20Sopenharmony_ci * - When running as 1G SGMII, Serdes clock is 125 MHz, so 5818c2ecf20Sopenharmony_ci * unit = 1 / (125*10^6 Hz) = 8 ns. 5828c2ecf20Sopenharmony_ci * 10 ms in units of 8 ns = 10ms / 8ns = 1250000 = 0x1312d0 5838c2ecf20Sopenharmony_ci * - When running as 2.5G SGMII, Serdes clock is 312.5 MHz, so 5848c2ecf20Sopenharmony_ci * unit = 1 / (312.5*10^6 Hz) = 3.2 ns. 5858c2ecf20Sopenharmony_ci * 10 ms in units of 3.2 ns = 10ms / 3.2ns = 3125000 = 0x2faf08. 5868c2ecf20Sopenharmony_ci * Since link_timer value of 1G SGMII will be too short for 2.5 SGMII, 5878c2ecf20Sopenharmony_ci * we always set up here a value of 2.5 SGMII. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_H, LINK_TMR_H_BASEX); 5908c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, MDIO_SGMII_LINK_TMR_L, LINK_TMR_L_BASEX); 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Restart AN */ 5938c2ecf20Sopenharmony_ci tmp_reg16 = SGMII_CR_DEF_VAL | SGMII_CR_RESTART_AN; 5948c2ecf20Sopenharmony_ci phy_write(memac->pcsphy, 0x0, tmp_reg16); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int check_init_parameters(struct fman_mac *memac) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci if (!memac->exception_cb) { 6008c2ecf20Sopenharmony_ci pr_err("Uninitialized exception handler\n"); 6018c2ecf20Sopenharmony_ci return -EINVAL; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci if (!memac->event_cb) { 6048c2ecf20Sopenharmony_ci pr_warn("Uninitialize event handler\n"); 6058c2ecf20Sopenharmony_ci return -EINVAL; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci return 0; 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic int get_exception_flag(enum fman_mac_exceptions exception) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci u32 bit_mask; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci switch (exception) { 6168c2ecf20Sopenharmony_ci case FM_MAC_EX_10G_TX_ECC_ER: 6178c2ecf20Sopenharmony_ci bit_mask = MEMAC_IMASK_TECC_ER; 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci case FM_MAC_EX_10G_RX_ECC_ER: 6208c2ecf20Sopenharmony_ci bit_mask = MEMAC_IMASK_RECC_ER; 6218c2ecf20Sopenharmony_ci break; 6228c2ecf20Sopenharmony_ci case FM_MAC_EX_TS_FIFO_ECC_ERR: 6238c2ecf20Sopenharmony_ci bit_mask = MEMAC_IMASK_TSECC_ER; 6248c2ecf20Sopenharmony_ci break; 6258c2ecf20Sopenharmony_ci case FM_MAC_EX_MAGIC_PACKET_INDICATION: 6268c2ecf20Sopenharmony_ci bit_mask = MEMAC_IMASK_MGI; 6278c2ecf20Sopenharmony_ci break; 6288c2ecf20Sopenharmony_ci default: 6298c2ecf20Sopenharmony_ci bit_mask = 0; 6308c2ecf20Sopenharmony_ci break; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return bit_mask; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void memac_err_exception(void *handle) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci struct fman_mac *memac = (struct fman_mac *)handle; 6398c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 6408c2ecf20Sopenharmony_ci u32 event, imask; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci event = ioread32be(®s->ievent); 6438c2ecf20Sopenharmony_ci imask = ioread32be(®s->imask); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Imask include both error and notification/event bits. 6468c2ecf20Sopenharmony_ci * Leaving only error bits enabled by imask. 6478c2ecf20Sopenharmony_ci * The imask error bits are shifted by 16 bits offset from 6488c2ecf20Sopenharmony_ci * their corresponding location in the ievent - hence the >> 16 6498c2ecf20Sopenharmony_ci */ 6508c2ecf20Sopenharmony_ci event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci iowrite32be(event, ®s->ievent); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci if (event & MEMAC_IEVNT_TS_ECC_ER) 6558c2ecf20Sopenharmony_ci memac->exception_cb(memac->dev_id, FM_MAC_EX_TS_FIFO_ECC_ERR); 6568c2ecf20Sopenharmony_ci if (event & MEMAC_IEVNT_TX_ECC_ER) 6578c2ecf20Sopenharmony_ci memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_TX_ECC_ER); 6588c2ecf20Sopenharmony_ci if (event & MEMAC_IEVNT_RX_ECC_ER) 6598c2ecf20Sopenharmony_ci memac->exception_cb(memac->dev_id, FM_MAC_EX_10G_RX_ECC_ER); 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void memac_exception(void *handle) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci struct fman_mac *memac = (struct fman_mac *)handle; 6658c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 6668c2ecf20Sopenharmony_ci u32 event, imask; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci event = ioread32be(®s->ievent); 6698c2ecf20Sopenharmony_ci imask = ioread32be(®s->imask); 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci /* Imask include both error and notification/event bits. 6728c2ecf20Sopenharmony_ci * Leaving only error bits enabled by imask. 6738c2ecf20Sopenharmony_ci * The imask error bits are shifted by 16 bits offset from 6748c2ecf20Sopenharmony_ci * their corresponding location in the ievent - hence the >> 16 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci event &= ((imask & MEMAC_ALL_ERRS_IMASK) >> 16); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci iowrite32be(event, ®s->ievent); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (event & MEMAC_IEVNT_MGI) 6818c2ecf20Sopenharmony_ci memac->exception_cb(memac->dev_id, 6828c2ecf20Sopenharmony_ci FM_MAC_EX_MAGIC_PACKET_INDICATION); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cistatic void free_init_resources(struct fman_mac *memac) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci fman_unregister_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id, 6888c2ecf20Sopenharmony_ci FMAN_INTR_TYPE_ERR); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci fman_unregister_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id, 6918c2ecf20Sopenharmony_ci FMAN_INTR_TYPE_NORMAL); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* release the driver's group hash table */ 6948c2ecf20Sopenharmony_ci free_hash_table(memac->multicast_addr_hash); 6958c2ecf20Sopenharmony_ci memac->multicast_addr_hash = NULL; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* release the driver's individual hash table */ 6988c2ecf20Sopenharmony_ci free_hash_table(memac->unicast_addr_hash); 6998c2ecf20Sopenharmony_ci memac->unicast_addr_hash = NULL; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic bool is_init_done(struct memac_cfg *memac_drv_params) 7038c2ecf20Sopenharmony_ci{ 7048c2ecf20Sopenharmony_ci /* Checks if mEMAC driver parameters were initialized */ 7058c2ecf20Sopenharmony_ci if (!memac_drv_params) 7068c2ecf20Sopenharmony_ci return true; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci return false; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ciint memac_enable(struct fman_mac *memac, enum comm_mode mode) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 7148c2ecf20Sopenharmony_ci u32 tmp; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 7178c2ecf20Sopenharmony_ci return -EINVAL; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 7208c2ecf20Sopenharmony_ci if (mode & COMM_MODE_RX) 7218c2ecf20Sopenharmony_ci tmp |= CMD_CFG_RX_EN; 7228c2ecf20Sopenharmony_ci if (mode & COMM_MODE_TX) 7238c2ecf20Sopenharmony_ci tmp |= CMD_CFG_TX_EN; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci return 0; 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ciint memac_disable(struct fman_mac *memac, enum comm_mode mode) 7318c2ecf20Sopenharmony_ci{ 7328c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 7338c2ecf20Sopenharmony_ci u32 tmp; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 7368c2ecf20Sopenharmony_ci return -EINVAL; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 7398c2ecf20Sopenharmony_ci if (mode & COMM_MODE_RX) 7408c2ecf20Sopenharmony_ci tmp &= ~CMD_CFG_RX_EN; 7418c2ecf20Sopenharmony_ci if (mode & COMM_MODE_TX) 7428c2ecf20Sopenharmony_ci tmp &= ~CMD_CFG_TX_EN; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci} 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ciint memac_set_promiscuous(struct fman_mac *memac, bool new_val) 7508c2ecf20Sopenharmony_ci{ 7518c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 7528c2ecf20Sopenharmony_ci u32 tmp; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 7558c2ecf20Sopenharmony_ci return -EINVAL; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 7588c2ecf20Sopenharmony_ci if (new_val) 7598c2ecf20Sopenharmony_ci tmp |= CMD_CFG_PROMIS_EN; 7608c2ecf20Sopenharmony_ci else 7618c2ecf20Sopenharmony_ci tmp &= ~CMD_CFG_PROMIS_EN; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return 0; 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ciint memac_adjust_link(struct fman_mac *memac, u16 speed) 7698c2ecf20Sopenharmony_ci{ 7708c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 7718c2ecf20Sopenharmony_ci u32 tmp; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 7748c2ecf20Sopenharmony_ci return -EINVAL; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci tmp = ioread32be(®s->if_mode); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* Set full duplex */ 7798c2ecf20Sopenharmony_ci tmp &= ~IF_MODE_HD; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (phy_interface_mode_is_rgmii(memac->phy_if)) { 7828c2ecf20Sopenharmony_ci /* Configure RGMII in manual mode */ 7838c2ecf20Sopenharmony_ci tmp &= ~IF_MODE_RGMII_AUTO; 7848c2ecf20Sopenharmony_ci tmp &= ~IF_MODE_RGMII_SP_MASK; 7858c2ecf20Sopenharmony_ci /* Full duplex */ 7868c2ecf20Sopenharmony_ci tmp |= IF_MODE_RGMII_FD; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci switch (speed) { 7898c2ecf20Sopenharmony_ci case SPEED_1000: 7908c2ecf20Sopenharmony_ci tmp |= IF_MODE_RGMII_1000; 7918c2ecf20Sopenharmony_ci break; 7928c2ecf20Sopenharmony_ci case SPEED_100: 7938c2ecf20Sopenharmony_ci tmp |= IF_MODE_RGMII_100; 7948c2ecf20Sopenharmony_ci break; 7958c2ecf20Sopenharmony_ci case SPEED_10: 7968c2ecf20Sopenharmony_ci tmp |= IF_MODE_RGMII_10; 7978c2ecf20Sopenharmony_ci break; 7988c2ecf20Sopenharmony_ci default: 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->if_mode); 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ciint memac_cfg_max_frame_len(struct fman_mac *memac, u16 new_val) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci if (is_init_done(memac->memac_drv_param)) 8118c2ecf20Sopenharmony_ci return -EINVAL; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci memac->memac_drv_param->max_frame_length = new_val; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci return 0; 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciint memac_cfg_reset_on_init(struct fman_mac *memac, bool enable) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci if (is_init_done(memac->memac_drv_param)) 8218c2ecf20Sopenharmony_ci return -EINVAL; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci memac->memac_drv_param->reset_on_init = enable; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci return 0; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ciint memac_cfg_fixed_link(struct fman_mac *memac, 8298c2ecf20Sopenharmony_ci struct fixed_phy_status *fixed_link) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci if (is_init_done(memac->memac_drv_param)) 8328c2ecf20Sopenharmony_ci return -EINVAL; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci memac->memac_drv_param->fixed_link = fixed_link; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ciint memac_set_tx_pause_frames(struct fman_mac *memac, u8 priority, 8408c2ecf20Sopenharmony_ci u16 pause_time, u16 thresh_time) 8418c2ecf20Sopenharmony_ci{ 8428c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 8438c2ecf20Sopenharmony_ci u32 tmp; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 8468c2ecf20Sopenharmony_ci return -EINVAL; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci tmp = ioread32be(®s->tx_fifo_sections); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci GET_TX_EMPTY_DEFAULT_VALUE(tmp); 8518c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->tx_fifo_sections); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 8548c2ecf20Sopenharmony_ci tmp &= ~CMD_CFG_PFC_MODE; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci tmp = ioread32be(®s->pause_quanta[priority / 2]); 8598c2ecf20Sopenharmony_ci if (priority % 2) 8608c2ecf20Sopenharmony_ci tmp &= CLXY_PAUSE_QUANTA_CLX_PQNT; 8618c2ecf20Sopenharmony_ci else 8628c2ecf20Sopenharmony_ci tmp &= CLXY_PAUSE_QUANTA_CLY_PQNT; 8638c2ecf20Sopenharmony_ci tmp |= ((u32)pause_time << (16 * (priority % 2))); 8648c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->pause_quanta[priority / 2]); 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci tmp = ioread32be(®s->pause_thresh[priority / 2]); 8678c2ecf20Sopenharmony_ci if (priority % 2) 8688c2ecf20Sopenharmony_ci tmp &= CLXY_PAUSE_THRESH_CLX_QTH; 8698c2ecf20Sopenharmony_ci else 8708c2ecf20Sopenharmony_ci tmp &= CLXY_PAUSE_THRESH_CLY_QTH; 8718c2ecf20Sopenharmony_ci tmp |= ((u32)thresh_time << (16 * (priority % 2))); 8728c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->pause_thresh[priority / 2]); 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ciint memac_accept_rx_pause_frames(struct fman_mac *memac, bool en) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 8808c2ecf20Sopenharmony_ci u32 tmp; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 8838c2ecf20Sopenharmony_ci return -EINVAL; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci tmp = ioread32be(®s->command_config); 8868c2ecf20Sopenharmony_ci if (en) 8878c2ecf20Sopenharmony_ci tmp &= ~CMD_CFG_PAUSE_IGNORE; 8888c2ecf20Sopenharmony_ci else 8898c2ecf20Sopenharmony_ci tmp |= CMD_CFG_PAUSE_IGNORE; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci iowrite32be(tmp, ®s->command_config); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci return 0; 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ciint memac_modify_mac_address(struct fman_mac *memac, enet_addr_t *enet_addr) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 8998c2ecf20Sopenharmony_ci return -EINVAL; 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci add_addr_in_paddr(memac->regs, (u8 *)(*enet_addr), 0); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ciint memac_add_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 9098c2ecf20Sopenharmony_ci struct eth_hash_entry *hash_entry; 9108c2ecf20Sopenharmony_ci u32 hash; 9118c2ecf20Sopenharmony_ci u64 addr; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 9148c2ecf20Sopenharmony_ci return -EINVAL; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci addr = ENET_ADDR_TO_UINT64(*eth_addr); 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (!(addr & GROUP_ADDRESS)) { 9198c2ecf20Sopenharmony_ci /* Unicast addresses not supported in hash */ 9208c2ecf20Sopenharmony_ci pr_err("Unicast Address\n"); 9218c2ecf20Sopenharmony_ci return -EINVAL; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci /* Create element to be added to the driver hash table */ 9268c2ecf20Sopenharmony_ci hash_entry = kmalloc(sizeof(*hash_entry), GFP_ATOMIC); 9278c2ecf20Sopenharmony_ci if (!hash_entry) 9288c2ecf20Sopenharmony_ci return -ENOMEM; 9298c2ecf20Sopenharmony_ci hash_entry->addr = addr; 9308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hash_entry->node); 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci list_add_tail(&hash_entry->node, 9338c2ecf20Sopenharmony_ci &memac->multicast_addr_hash->lsts[hash]); 9348c2ecf20Sopenharmony_ci iowrite32be(hash | HASH_CTRL_MCAST_EN, ®s->hashtable_ctrl); 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciint memac_set_allmulti(struct fman_mac *memac, bool enable) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci u32 entry; 9428c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 9458c2ecf20Sopenharmony_ci return -EINVAL; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (enable) { 9488c2ecf20Sopenharmony_ci for (entry = 0; entry < HASH_TABLE_SIZE; entry++) 9498c2ecf20Sopenharmony_ci iowrite32be(entry | HASH_CTRL_MCAST_EN, 9508c2ecf20Sopenharmony_ci ®s->hashtable_ctrl); 9518c2ecf20Sopenharmony_ci } else { 9528c2ecf20Sopenharmony_ci for (entry = 0; entry < HASH_TABLE_SIZE; entry++) 9538c2ecf20Sopenharmony_ci iowrite32be(entry & ~HASH_CTRL_MCAST_EN, 9548c2ecf20Sopenharmony_ci ®s->hashtable_ctrl); 9558c2ecf20Sopenharmony_ci } 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci memac->allmulti_enabled = enable; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ciint memac_set_tstamp(struct fman_mac *memac, bool enable) 9638c2ecf20Sopenharmony_ci{ 9648c2ecf20Sopenharmony_ci return 0; /* Always enabled. */ 9658c2ecf20Sopenharmony_ci} 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ciint memac_del_hash_mac_address(struct fman_mac *memac, enet_addr_t *eth_addr) 9688c2ecf20Sopenharmony_ci{ 9698c2ecf20Sopenharmony_ci struct memac_regs __iomem *regs = memac->regs; 9708c2ecf20Sopenharmony_ci struct eth_hash_entry *hash_entry = NULL; 9718c2ecf20Sopenharmony_ci struct list_head *pos; 9728c2ecf20Sopenharmony_ci u32 hash; 9738c2ecf20Sopenharmony_ci u64 addr; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 9768c2ecf20Sopenharmony_ci return -EINVAL; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci addr = ENET_ADDR_TO_UINT64(*eth_addr); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci hash = get_mac_addr_hash_code(addr) & HASH_CTRL_ADDR_MASK; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci list_for_each(pos, &memac->multicast_addr_hash->lsts[hash]) { 9838c2ecf20Sopenharmony_ci hash_entry = ETH_HASH_ENTRY_OBJ(pos); 9848c2ecf20Sopenharmony_ci if (hash_entry && hash_entry->addr == addr) { 9858c2ecf20Sopenharmony_ci list_del_init(&hash_entry->node); 9868c2ecf20Sopenharmony_ci kfree(hash_entry); 9878c2ecf20Sopenharmony_ci break; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci if (!memac->allmulti_enabled) { 9928c2ecf20Sopenharmony_ci if (list_empty(&memac->multicast_addr_hash->lsts[hash])) 9938c2ecf20Sopenharmony_ci iowrite32be(hash & ~HASH_CTRL_MCAST_EN, 9948c2ecf20Sopenharmony_ci ®s->hashtable_ctrl); 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci return 0; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ciint memac_set_exception(struct fman_mac *memac, 10018c2ecf20Sopenharmony_ci enum fman_mac_exceptions exception, bool enable) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci u32 bit_mask = 0; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci if (!is_init_done(memac->memac_drv_param)) 10068c2ecf20Sopenharmony_ci return -EINVAL; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci bit_mask = get_exception_flag(exception); 10098c2ecf20Sopenharmony_ci if (bit_mask) { 10108c2ecf20Sopenharmony_ci if (enable) 10118c2ecf20Sopenharmony_ci memac->exceptions |= bit_mask; 10128c2ecf20Sopenharmony_ci else 10138c2ecf20Sopenharmony_ci memac->exceptions &= ~bit_mask; 10148c2ecf20Sopenharmony_ci } else { 10158c2ecf20Sopenharmony_ci pr_err("Undefined exception\n"); 10168c2ecf20Sopenharmony_ci return -EINVAL; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci set_exception(memac->regs, bit_mask, enable); 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ciint memac_init(struct fman_mac *memac) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct memac_cfg *memac_drv_param; 10268c2ecf20Sopenharmony_ci u8 i; 10278c2ecf20Sopenharmony_ci enet_addr_t eth_addr; 10288c2ecf20Sopenharmony_ci bool slow_10g_if = false; 10298c2ecf20Sopenharmony_ci struct fixed_phy_status *fixed_link; 10308c2ecf20Sopenharmony_ci int err; 10318c2ecf20Sopenharmony_ci u32 reg32 = 0; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci if (is_init_done(memac->memac_drv_param)) 10348c2ecf20Sopenharmony_ci return -EINVAL; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci err = check_init_parameters(memac); 10378c2ecf20Sopenharmony_ci if (err) 10388c2ecf20Sopenharmony_ci return err; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci memac_drv_param = memac->memac_drv_param; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci if (memac->fm_rev_info.major == 6 && memac->fm_rev_info.minor == 4) 10438c2ecf20Sopenharmony_ci slow_10g_if = true; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci /* First, reset the MAC if desired. */ 10468c2ecf20Sopenharmony_ci if (memac_drv_param->reset_on_init) { 10478c2ecf20Sopenharmony_ci err = reset(memac->regs); 10488c2ecf20Sopenharmony_ci if (err) { 10498c2ecf20Sopenharmony_ci pr_err("mEMAC reset failed\n"); 10508c2ecf20Sopenharmony_ci return err; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci /* MAC Address */ 10558c2ecf20Sopenharmony_ci if (memac->addr != 0) { 10568c2ecf20Sopenharmony_ci MAKE_ENET_ADDR_FROM_UINT64(memac->addr, eth_addr); 10578c2ecf20Sopenharmony_ci add_addr_in_paddr(memac->regs, (u8 *)eth_addr, 0); 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci fixed_link = memac_drv_param->fixed_link; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci init(memac->regs, memac->memac_drv_param, memac->phy_if, 10638c2ecf20Sopenharmony_ci memac->max_speed, slow_10g_if, memac->exceptions); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci /* FM_RX_FIFO_CORRUPT_ERRATA_10GMAC_A006320 errata workaround 10668c2ecf20Sopenharmony_ci * Exists only in FMan 6.0 and 6.3. 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci if ((memac->fm_rev_info.major == 6) && 10698c2ecf20Sopenharmony_ci ((memac->fm_rev_info.minor == 0) || 10708c2ecf20Sopenharmony_ci (memac->fm_rev_info.minor == 3))) { 10718c2ecf20Sopenharmony_ci /* MAC strips CRC from received frames - this workaround 10728c2ecf20Sopenharmony_ci * should decrease the likelihood of bug appearance 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_ci reg32 = ioread32be(&memac->regs->command_config); 10758c2ecf20Sopenharmony_ci reg32 &= ~CMD_CFG_CRC_FWD; 10768c2ecf20Sopenharmony_ci iowrite32be(reg32, &memac->regs->command_config); 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (memac->phy_if == PHY_INTERFACE_MODE_SGMII) { 10808c2ecf20Sopenharmony_ci /* Configure internal SGMII PHY */ 10818c2ecf20Sopenharmony_ci if (memac->basex_if) 10828c2ecf20Sopenharmony_ci setup_sgmii_internal_phy_base_x(memac); 10838c2ecf20Sopenharmony_ci else 10848c2ecf20Sopenharmony_ci setup_sgmii_internal_phy(memac, fixed_link); 10858c2ecf20Sopenharmony_ci } else if (memac->phy_if == PHY_INTERFACE_MODE_QSGMII) { 10868c2ecf20Sopenharmony_ci /* Configure 4 internal SGMII PHYs */ 10878c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 10888c2ecf20Sopenharmony_ci u8 qsmgii_phy_addr, phy_addr; 10898c2ecf20Sopenharmony_ci /* QSGMII PHY address occupies 3 upper bits of 5-bit 10908c2ecf20Sopenharmony_ci * phy_address; the lower 2 bits are used to extend 10918c2ecf20Sopenharmony_ci * register address space and access each one of 4 10928c2ecf20Sopenharmony_ci * ports inside QSGMII. 10938c2ecf20Sopenharmony_ci */ 10948c2ecf20Sopenharmony_ci phy_addr = memac->pcsphy->mdio.addr; 10958c2ecf20Sopenharmony_ci qsmgii_phy_addr = (u8)((phy_addr << 2) | i); 10968c2ecf20Sopenharmony_ci memac->pcsphy->mdio.addr = qsmgii_phy_addr; 10978c2ecf20Sopenharmony_ci if (memac->basex_if) 10988c2ecf20Sopenharmony_ci setup_sgmii_internal_phy_base_x(memac); 10998c2ecf20Sopenharmony_ci else 11008c2ecf20Sopenharmony_ci setup_sgmii_internal_phy(memac, fixed_link); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci memac->pcsphy->mdio.addr = phy_addr; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci /* Max Frame Length */ 11078c2ecf20Sopenharmony_ci err = fman_set_mac_max_frame(memac->fm, memac->mac_id, 11088c2ecf20Sopenharmony_ci memac_drv_param->max_frame_length); 11098c2ecf20Sopenharmony_ci if (err) { 11108c2ecf20Sopenharmony_ci pr_err("settings Mac max frame length is FAILED\n"); 11118c2ecf20Sopenharmony_ci return err; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci memac->multicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE); 11158c2ecf20Sopenharmony_ci if (!memac->multicast_addr_hash) { 11168c2ecf20Sopenharmony_ci free_init_resources(memac); 11178c2ecf20Sopenharmony_ci pr_err("allocation hash table is FAILED\n"); 11188c2ecf20Sopenharmony_ci return -ENOMEM; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci memac->unicast_addr_hash = alloc_hash_table(HASH_TABLE_SIZE); 11228c2ecf20Sopenharmony_ci if (!memac->unicast_addr_hash) { 11238c2ecf20Sopenharmony_ci free_init_resources(memac); 11248c2ecf20Sopenharmony_ci pr_err("allocation hash table is FAILED\n"); 11258c2ecf20Sopenharmony_ci return -ENOMEM; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci fman_register_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id, 11298c2ecf20Sopenharmony_ci FMAN_INTR_TYPE_ERR, memac_err_exception, memac); 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci fman_register_intr(memac->fm, FMAN_MOD_MAC, memac->mac_id, 11328c2ecf20Sopenharmony_ci FMAN_INTR_TYPE_NORMAL, memac_exception, memac); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci kfree(memac_drv_param); 11358c2ecf20Sopenharmony_ci memac->memac_drv_param = NULL; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci return 0; 11388c2ecf20Sopenharmony_ci} 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ciint memac_free(struct fman_mac *memac) 11418c2ecf20Sopenharmony_ci{ 11428c2ecf20Sopenharmony_ci free_init_resources(memac); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (memac->pcsphy) 11458c2ecf20Sopenharmony_ci put_device(&memac->pcsphy->mdio.dev); 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci kfree(memac->memac_drv_param); 11488c2ecf20Sopenharmony_ci kfree(memac); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci return 0; 11518c2ecf20Sopenharmony_ci} 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_cistruct fman_mac *memac_config(struct fman_mac_params *params) 11548c2ecf20Sopenharmony_ci{ 11558c2ecf20Sopenharmony_ci struct fman_mac *memac; 11568c2ecf20Sopenharmony_ci struct memac_cfg *memac_drv_param; 11578c2ecf20Sopenharmony_ci void __iomem *base_addr; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci base_addr = params->base_addr; 11608c2ecf20Sopenharmony_ci /* allocate memory for the m_emac data structure */ 11618c2ecf20Sopenharmony_ci memac = kzalloc(sizeof(*memac), GFP_KERNEL); 11628c2ecf20Sopenharmony_ci if (!memac) 11638c2ecf20Sopenharmony_ci return NULL; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci /* allocate memory for the m_emac driver parameters data structure */ 11668c2ecf20Sopenharmony_ci memac_drv_param = kzalloc(sizeof(*memac_drv_param), GFP_KERNEL); 11678c2ecf20Sopenharmony_ci if (!memac_drv_param) { 11688c2ecf20Sopenharmony_ci memac_free(memac); 11698c2ecf20Sopenharmony_ci return NULL; 11708c2ecf20Sopenharmony_ci } 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci /* Plant parameter structure pointer */ 11738c2ecf20Sopenharmony_ci memac->memac_drv_param = memac_drv_param; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci set_dflts(memac_drv_param); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci memac->addr = ENET_ADDR_TO_UINT64(params->addr); 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci memac->regs = base_addr; 11808c2ecf20Sopenharmony_ci memac->max_speed = params->max_speed; 11818c2ecf20Sopenharmony_ci memac->phy_if = params->phy_if; 11828c2ecf20Sopenharmony_ci memac->mac_id = params->mac_id; 11838c2ecf20Sopenharmony_ci memac->exceptions = (MEMAC_IMASK_TSECC_ER | MEMAC_IMASK_TECC_ER | 11848c2ecf20Sopenharmony_ci MEMAC_IMASK_RECC_ER | MEMAC_IMASK_MGI); 11858c2ecf20Sopenharmony_ci memac->exception_cb = params->exception_cb; 11868c2ecf20Sopenharmony_ci memac->event_cb = params->event_cb; 11878c2ecf20Sopenharmony_ci memac->dev_id = params->dev_id; 11888c2ecf20Sopenharmony_ci memac->fm = params->fm; 11898c2ecf20Sopenharmony_ci memac->basex_if = params->basex_if; 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci /* Save FMan revision */ 11928c2ecf20Sopenharmony_ci fman_get_revision(memac->fm, &memac->fm_rev_info); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (memac->phy_if == PHY_INTERFACE_MODE_SGMII || 11958c2ecf20Sopenharmony_ci memac->phy_if == PHY_INTERFACE_MODE_QSGMII) { 11968c2ecf20Sopenharmony_ci if (!params->internal_phy_node) { 11978c2ecf20Sopenharmony_ci pr_err("PCS PHY node is not available\n"); 11988c2ecf20Sopenharmony_ci memac_free(memac); 11998c2ecf20Sopenharmony_ci return NULL; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci memac->pcsphy = of_phy_find_device(params->internal_phy_node); 12038c2ecf20Sopenharmony_ci if (!memac->pcsphy) { 12048c2ecf20Sopenharmony_ci pr_err("of_phy_find_device (PCS PHY) failed\n"); 12058c2ecf20Sopenharmony_ci memac_free(memac); 12068c2ecf20Sopenharmony_ci return NULL; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci return memac; 12118c2ecf20Sopenharmony_ci} 1212