275 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 = 0102 * 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 packets160 */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 & 1169 * Enable Flow control for port 0 & 1170 * Enable Back pressure for port 0 & 1171 */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 and184 * 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 0193 * Port 1: VLAN group 1194 */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 = 0x9199 * VLAN group 1: cpu0 (bit3) + port1 (bit1) = 1010 = 0xa200 */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}275