spl2sw_mac.c (8954B)
1// SPDX-License-Identifier: GPL-2.0 2/* Copyright Sunplus Technology Co., Ltd. 3 * All rights reserved. 4 */ 5 6#include <linux/platform_device.h> 7#include <linux/netdevice.h> 8#include <linux/bitfield.h> 9#include <linux/of_mdio.h> 10 11#include "spl2sw_register.h" 12#include "spl2sw_define.h" 13#include "spl2sw_desc.h" 14#include "spl2sw_mac.h" 15 16void spl2sw_mac_hw_stop(struct spl2sw_common *comm) 17{ 18 u32 reg; 19 20 if (comm->enable == 0) { 21 /* Mask and clear all interrupts. */ 22 writel(0xffffffff, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 23 writel(0xffffffff, comm->l2sw_reg_base + L2SW_SW_INT_STATUS_0); 24 25 /* Disable cpu 0 and cpu 1. */ 26 reg = readl(comm->l2sw_reg_base + L2SW_CPU_CNTL); 27 reg |= MAC_DIS_SOC1_CPU | MAC_DIS_SOC0_CPU; 28 writel(reg, comm->l2sw_reg_base + L2SW_CPU_CNTL); 29 } 30 31 /* Disable LAN ports. */ 32 reg = readl(comm->l2sw_reg_base + L2SW_PORT_CNTL0); 33 reg |= FIELD_PREP(MAC_DIS_PORT, ~comm->enable); 34 writel(reg, comm->l2sw_reg_base + L2SW_PORT_CNTL0); 35} 36 37void spl2sw_mac_hw_start(struct spl2sw_common *comm) 38{ 39 u32 reg; 40 41 /* Enable cpu port 0 (6) & CRC padding (8) */ 42 reg = readl(comm->l2sw_reg_base + L2SW_CPU_CNTL); 43 reg &= ~MAC_DIS_SOC0_CPU; 44 reg |= MAC_EN_CRC_SOC0; 45 writel(reg, comm->l2sw_reg_base + L2SW_CPU_CNTL); 46 47 /* Enable port 0 & port 1 */ 48 reg = readl(comm->l2sw_reg_base + L2SW_PORT_CNTL0); 49 reg &= FIELD_PREP(MAC_DIS_PORT, ~comm->enable) | ~MAC_DIS_PORT; 50 writel(reg, comm->l2sw_reg_base + L2SW_PORT_CNTL0); 51} 52 53int spl2sw_mac_addr_add(struct spl2sw_mac *mac) 54{ 55 struct spl2sw_common *comm = mac->comm; 56 u32 reg; 57 int ret; 58 59 /* Write 6-octet MAC address. */ 60 writel((mac->mac_addr[0] << 0) + (mac->mac_addr[1] << 8), 61 comm->l2sw_reg_base + L2SW_W_MAC_15_0); 62 writel((mac->mac_addr[2] << 0) + (mac->mac_addr[3] << 8) + 63 (mac->mac_addr[4] << 16) + (mac->mac_addr[5] << 24), 64 comm->l2sw_reg_base + L2SW_W_MAC_47_16); 65 66 /* Set learn port = cpu_port, aging = 1 */ 67 reg = MAC_W_CPU_PORT_0 | FIELD_PREP(MAC_W_VID, mac->vlan_id) | 68 FIELD_PREP(MAC_W_AGE, 1) | MAC_W_MAC_CMD; 69 writel(reg, comm->l2sw_reg_base + L2SW_WT_MAC_AD0); 70 71 /* Wait for completing. */ 72 ret = read_poll_timeout(readl, reg, reg & MAC_W_MAC_DONE, 1, 200, true, 73 comm->l2sw_reg_base + L2SW_WT_MAC_AD0); 74 if (ret) { 75 netdev_err(mac->ndev, "Failed to add address to table!\n"); 76 return ret; 77 } 78 79 netdev_dbg(mac->ndev, "mac_ad0 = %08x, mac_ad = %08x%04x\n", 80 readl(comm->l2sw_reg_base + L2SW_WT_MAC_AD0), 81 (u32)FIELD_GET(MAC_W_MAC_47_16, 82 readl(comm->l2sw_reg_base + L2SW_W_MAC_47_16)), 83 (u32)FIELD_GET(MAC_W_MAC_15_0, 84 readl(comm->l2sw_reg_base + L2SW_W_MAC_15_0))); 85 return 0; 86} 87 88int spl2sw_mac_addr_del(struct spl2sw_mac *mac) 89{ 90 struct spl2sw_common *comm = mac->comm; 91 u32 reg; 92 int ret; 93 94 /* Write 6-octet MAC address. */ 95 writel((mac->mac_addr[0] << 0) + (mac->mac_addr[1] << 8), 96 comm->l2sw_reg_base + L2SW_W_MAC_15_0); 97 writel((mac->mac_addr[2] << 0) + (mac->mac_addr[3] << 8) + 98 (mac->mac_addr[4] << 16) + (mac->mac_addr[5] << 24), 99 comm->l2sw_reg_base + L2SW_W_MAC_47_16); 100 101 /* Set learn port = lan_port0 and aging = 0 102 * to wipe (age) out the entry. 103 */ 104 reg = MAC_W_LAN_PORT_0 | FIELD_PREP(MAC_W_VID, mac->vlan_id) | MAC_W_MAC_CMD; 105 writel(reg, comm->l2sw_reg_base + L2SW_WT_MAC_AD0); 106 107 /* Wait for completing. */ 108 ret = read_poll_timeout(readl, reg, reg & MAC_W_MAC_DONE, 1, 200, true, 109 comm->l2sw_reg_base + L2SW_WT_MAC_AD0); 110 if (ret) { 111 netdev_err(mac->ndev, "Failed to delete address from table!\n"); 112 return ret; 113 } 114 115 netdev_dbg(mac->ndev, "mac_ad0 = %08x, mac_ad = %08x%04x\n", 116 readl(comm->l2sw_reg_base + L2SW_WT_MAC_AD0), 117 (u32)FIELD_GET(MAC_W_MAC_47_16, 118 readl(comm->l2sw_reg_base + L2SW_W_MAC_47_16)), 119 (u32)FIELD_GET(MAC_W_MAC_15_0, 120 readl(comm->l2sw_reg_base + L2SW_W_MAC_15_0))); 121 return 0; 122} 123 124void spl2sw_mac_hw_init(struct spl2sw_common *comm) 125{ 126 u32 reg; 127 128 /* Disable cpu0 and cpu 1 port. */ 129 reg = readl(comm->l2sw_reg_base + L2SW_CPU_CNTL); 130 reg |= MAC_DIS_SOC1_CPU | MAC_DIS_SOC0_CPU; 131 writel(reg, comm->l2sw_reg_base + L2SW_CPU_CNTL); 132 133 /* Set base addresses of TX and RX queues. */ 134 writel(comm->desc_dma, comm->l2sw_reg_base + L2SW_TX_LBASE_ADDR_0); 135 writel(comm->desc_dma + sizeof(struct spl2sw_mac_desc) * TX_DESC_NUM, 136 comm->l2sw_reg_base + L2SW_TX_HBASE_ADDR_0); 137 writel(comm->desc_dma + sizeof(struct spl2sw_mac_desc) * (TX_DESC_NUM + 138 MAC_GUARD_DESC_NUM), comm->l2sw_reg_base + L2SW_RX_HBASE_ADDR_0); 139 writel(comm->desc_dma + sizeof(struct spl2sw_mac_desc) * (TX_DESC_NUM + 140 MAC_GUARD_DESC_NUM + RX_QUEUE0_DESC_NUM), 141 comm->l2sw_reg_base + L2SW_RX_LBASE_ADDR_0); 142 143 /* Fc_rls_th=0x4a, Fc_set_th=0x3a, Drop_rls_th=0x2d, Drop_set_th=0x1d */ 144 writel(0x4a3a2d1d, comm->l2sw_reg_base + L2SW_FL_CNTL_TH); 145 146 /* Cpu_rls_th=0x4a, Cpu_set_th=0x3a, Cpu_th=0x12, Port_th=0x12 */ 147 writel(0x4a3a1212, comm->l2sw_reg_base + L2SW_CPU_FL_CNTL_TH); 148 149 /* mtcc_lmt=0xf, Pri_th_l=6, Pri_th_h=6, weigh_8x_en=1 */ 150 writel(0xf6680000, comm->l2sw_reg_base + L2SW_PRI_FL_CNTL); 151 152 /* High-active LED */ 153 reg = readl(comm->l2sw_reg_base + L2SW_LED_PORT0); 154 reg |= MAC_LED_ACT_HI; 155 writel(reg, comm->l2sw_reg_base + L2SW_LED_PORT0); 156 157 /* Disable aging of cpu port 0 & 1. 158 * Disable SA learning of cpu port 0 & 1. 159 * Enable UC and MC packets 160 */ 161 reg = readl(comm->l2sw_reg_base + L2SW_CPU_CNTL); 162 reg &= ~(MAC_EN_SOC1_AGING | MAC_EN_SOC0_AGING | 163 MAC_DIS_BC2CPU_P1 | MAC_DIS_BC2CPU_P0 | 164 MAC_DIS_MC2CPU_P1 | MAC_DIS_MC2CPU_P0); 165 reg |= MAC_DIS_LRN_SOC1 | MAC_DIS_LRN_SOC0; 166 writel(reg, comm->l2sw_reg_base + L2SW_CPU_CNTL); 167 168 /* Enable RMC2CPU for port 0 & 1 169 * Enable Flow control for port 0 & 1 170 * Enable Back pressure for port 0 & 1 171 */ 172 reg = readl(comm->l2sw_reg_base + L2SW_PORT_CNTL0); 173 reg &= ~(MAC_DIS_RMC2CPU_P1 | MAC_DIS_RMC2CPU_P0); 174 reg |= MAC_EN_FLOW_CTL_P1 | MAC_EN_FLOW_CTL_P0 | 175 MAC_EN_BACK_PRESS_P1 | MAC_EN_BACK_PRESS_P0; 176 writel(reg, comm->l2sw_reg_base + L2SW_PORT_CNTL0); 177 178 /* Disable LAN port SA learning. */ 179 reg = readl(comm->l2sw_reg_base + L2SW_PORT_CNTL1); 180 reg |= MAC_DIS_SA_LRN_P1 | MAC_DIS_SA_LRN_P0; 181 writel(reg, comm->l2sw_reg_base + L2SW_PORT_CNTL1); 182 183 /* Enable rmii force mode and 184 * set both external phy-address to 31. 185 */ 186 reg = readl(comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE); 187 reg &= ~(MAC_EXT_PHY1_ADDR | MAC_EXT_PHY0_ADDR); 188 reg |= FIELD_PREP(MAC_EXT_PHY1_ADDR, 31) | FIELD_PREP(MAC_EXT_PHY0_ADDR, 31); 189 reg |= MAC_FORCE_RMII_EN_1 | MAC_FORCE_RMII_EN_0; 190 writel(reg, comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE); 191 192 /* Port 0: VLAN group 0 193 * Port 1: VLAN group 1 194 */ 195 reg = FIELD_PREP(MAC_P1_PVID, 1) | FIELD_PREP(MAC_P0_PVID, 0); 196 writel(reg, comm->l2sw_reg_base + L2SW_PVID_CONFIG0); 197 198 /* VLAN group 0: cpu0 (bit3) + port0 (bit0) = 1001 = 0x9 199 * VLAN group 1: cpu0 (bit3) + port1 (bit1) = 1010 = 0xa 200 */ 201 reg = FIELD_PREP(MAC_VLAN_MEMSET_1, 0xa) | FIELD_PREP(MAC_VLAN_MEMSET_0, 9); 202 writel(reg, comm->l2sw_reg_base + L2SW_VLAN_MEMSET_CONFIG0); 203 204 /* RMC forward: to_cpu (1) 205 * LED: 60mS (1) 206 * BC storm prev: 31 BC (1) 207 */ 208 reg = readl(comm->l2sw_reg_base + L2SW_SW_GLB_CNTL); 209 reg &= ~(MAC_RMC_TB_FAULT_RULE | MAC_LED_FLASH_TIME | MAC_BC_STORM_PREV); 210 reg |= FIELD_PREP(MAC_RMC_TB_FAULT_RULE, 1) | 211 FIELD_PREP(MAC_LED_FLASH_TIME, 1) | 212 FIELD_PREP(MAC_BC_STORM_PREV, 1); 213 writel(reg, comm->l2sw_reg_base + L2SW_SW_GLB_CNTL); 214 215 writel(MAC_INT_MASK_DEF, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 216} 217 218void spl2sw_mac_rx_mode_set(struct spl2sw_mac *mac) 219{ 220 struct spl2sw_common *comm = mac->comm; 221 struct net_device *ndev = mac->ndev; 222 u32 mask, reg, rx_mode; 223 224 netdev_dbg(ndev, "ndev->flags = %08x\n", ndev->flags); 225 mask = FIELD_PREP(MAC_DIS_MC2CPU, mac->lan_port) | 226 FIELD_PREP(MAC_DIS_UN2CPU, mac->lan_port); 227 reg = readl(comm->l2sw_reg_base + L2SW_CPU_CNTL); 228 229 if (ndev->flags & IFF_PROMISC) { 230 /* Allow MC and unknown UC packets */ 231 rx_mode = FIELD_PREP(MAC_DIS_MC2CPU, mac->lan_port) | 232 FIELD_PREP(MAC_DIS_UN2CPU, mac->lan_port); 233 } else if ((!netdev_mc_empty(ndev) && (ndev->flags & IFF_MULTICAST)) || 234 (ndev->flags & IFF_ALLMULTI)) { 235 /* Allow MC packets */ 236 rx_mode = FIELD_PREP(MAC_DIS_MC2CPU, mac->lan_port); 237 } else { 238 /* Disable MC and unknown UC packets */ 239 rx_mode = 0; 240 } 241 242 writel((reg & (~mask)) | ((~rx_mode) & mask), comm->l2sw_reg_base + L2SW_CPU_CNTL); 243 netdev_dbg(ndev, "cpu_cntl = %08x\n", readl(comm->l2sw_reg_base + L2SW_CPU_CNTL)); 244} 245 246void spl2sw_mac_init(struct spl2sw_common *comm) 247{ 248 u32 i; 249 250 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) 251 comm->rx_pos[i] = 0; 252 mb(); /* make sure settings are effective. */ 253 254 spl2sw_mac_hw_init(comm); 255} 256 257void spl2sw_mac_soft_reset(struct spl2sw_common *comm) 258{ 259 u32 i; 260 261 spl2sw_mac_hw_stop(comm); 262 263 spl2sw_rx_descs_flush(comm); 264 comm->tx_pos = 0; 265 comm->tx_done_pos = 0; 266 comm->tx_desc_full = 0; 267 268 for (i = 0; i < RX_DESC_QUEUE_NUM; i++) 269 comm->rx_pos[i] = 0; 270 mb(); /* make sure settings are effective. */ 271 272 spl2sw_mac_hw_init(comm); 273 spl2sw_mac_hw_start(comm); 274}