196 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*******************************************************************************3 This is the driver for the MAC 10/100 on-chip Ethernet controller4 currently tested on all the ST boards based on STb7109 and stx7200 SoCs.5 6 DWC Ether MAC 10/100 Universal version 4.0 has been used for developing7 this code.8 9 This only implements the mac core functions for this chip.10 11 Copyright (C) 2007-2009 STMicroelectronics Ltd12 13 14 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>15*******************************************************************************/16 17#include <linux/crc32.h>18#include <linux/io.h>19#include "stmmac.h"20#include "dwmac100.h"21 22static void dwmac100_core_init(struct mac_device_info *hw,23 struct net_device *dev)24{25 void __iomem *ioaddr = hw->pcsr;26 u32 value = readl(ioaddr + MAC_CONTROL);27 28 value |= MAC_CORE_INIT;29 30 writel(value, ioaddr + MAC_CONTROL);31 32#ifdef STMMAC_VLAN_TAG_USED33 writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);34#endif35}36 37static void dwmac100_dump_mac_regs(struct mac_device_info *hw, u32 *reg_space)38{39 void __iomem *ioaddr = hw->pcsr;40 41 reg_space[MAC_CONTROL / 4] = readl(ioaddr + MAC_CONTROL);42 reg_space[MAC_ADDR_HIGH / 4] = readl(ioaddr + MAC_ADDR_HIGH);43 reg_space[MAC_ADDR_LOW / 4] = readl(ioaddr + MAC_ADDR_LOW);44 reg_space[MAC_HASH_HIGH / 4] = readl(ioaddr + MAC_HASH_HIGH);45 reg_space[MAC_HASH_LOW / 4] = readl(ioaddr + MAC_HASH_LOW);46 reg_space[MAC_FLOW_CTRL / 4] = readl(ioaddr + MAC_FLOW_CTRL);47 reg_space[MAC_VLAN1 / 4] = readl(ioaddr + MAC_VLAN1);48 reg_space[MAC_VLAN2 / 4] = readl(ioaddr + MAC_VLAN2);49}50 51static int dwmac100_rx_ipc_enable(struct mac_device_info *hw)52{53 return 0;54}55 56static int dwmac100_irq_status(struct mac_device_info *hw,57 struct stmmac_extra_stats *x)58{59 return 0;60}61 62static void dwmac100_set_umac_addr(struct mac_device_info *hw,63 const unsigned char *addr,64 unsigned int reg_n)65{66 void __iomem *ioaddr = hw->pcsr;67 stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);68}69 70static void dwmac100_get_umac_addr(struct mac_device_info *hw,71 unsigned char *addr,72 unsigned int reg_n)73{74 void __iomem *ioaddr = hw->pcsr;75 stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);76}77 78static void dwmac100_set_filter(struct mac_device_info *hw,79 struct net_device *dev)80{81 void __iomem *ioaddr = (void __iomem *)dev->base_addr;82 u32 value = readl(ioaddr + MAC_CONTROL);83 84 if (dev->flags & IFF_PROMISC) {85 value |= MAC_CONTROL_PR;86 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |87 MAC_CONTROL_HP);88 } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)89 || (dev->flags & IFF_ALLMULTI)) {90 value |= MAC_CONTROL_PM;91 value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);92 writel(0xffffffff, ioaddr + MAC_HASH_HIGH);93 writel(0xffffffff, ioaddr + MAC_HASH_LOW);94 } else if (netdev_mc_empty(dev)) { /* no multicast */95 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |96 MAC_CONTROL_HO | MAC_CONTROL_HP);97 } else {98 u32 mc_filter[2];99 struct netdev_hw_addr *ha;100 101 /* Perfect filter mode for physical address and Hash102 * filter for multicast103 */104 value |= MAC_CONTROL_HP;105 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |106 MAC_CONTROL_IF | MAC_CONTROL_HO);107 108 memset(mc_filter, 0, sizeof(mc_filter));109 netdev_for_each_mc_addr(ha, dev) {110 /* The upper 6 bits of the calculated CRC are used to111 * index the contens of the hash table112 */113 int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;114 /* The most significant bit determines the register to115 * use (H/L) while the other 5 bits determine the bit116 * within the register.117 */118 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);119 }120 writel(mc_filter[0], ioaddr + MAC_HASH_LOW);121 writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);122 }123 124 writel(value, ioaddr + MAC_CONTROL);125}126 127static void dwmac100_flow_ctrl(struct mac_device_info *hw, unsigned int duplex,128 unsigned int fc, unsigned int pause_time,129 u32 tx_cnt)130{131 void __iomem *ioaddr = hw->pcsr;132 unsigned int flow = MAC_FLOW_CTRL_ENABLE;133 134 if (duplex)135 flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);136 writel(flow, ioaddr + MAC_FLOW_CTRL);137}138 139/* No PMT module supported on ST boards with this Eth chip. */140static void dwmac100_pmt(struct mac_device_info *hw, unsigned long mode)141{142 return;143}144 145static void dwmac100_set_mac_loopback(void __iomem *ioaddr, bool enable)146{147 u32 value = readl(ioaddr + MAC_CONTROL);148 149 if (enable)150 value |= MAC_CONTROL_OM;151 else152 value &= ~MAC_CONTROL_OM;153 154 writel(value, ioaddr + MAC_CONTROL);155}156 157const struct stmmac_ops dwmac100_ops = {158 .core_init = dwmac100_core_init,159 .set_mac = stmmac_set_mac,160 .rx_ipc = dwmac100_rx_ipc_enable,161 .dump_regs = dwmac100_dump_mac_regs,162 .host_irq_status = dwmac100_irq_status,163 .set_filter = dwmac100_set_filter,164 .flow_ctrl = dwmac100_flow_ctrl,165 .pmt = dwmac100_pmt,166 .set_umac_addr = dwmac100_set_umac_addr,167 .get_umac_addr = dwmac100_get_umac_addr,168 .set_mac_loopback = dwmac100_set_mac_loopback,169};170 171int dwmac100_setup(struct stmmac_priv *priv)172{173 struct mac_device_info *mac = priv->hw;174 175 dev_info(priv->device, "\tDWMAC100\n");176 177 mac->pcsr = priv->ioaddr;178 mac->link.caps = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |179 MAC_10 | MAC_100;180 mac->link.duplex = MAC_CONTROL_F;181 mac->link.speed10 = 0;182 mac->link.speed100 = 0;183 mac->link.speed1000 = 0;184 mac->link.speed_mask = MAC_CONTROL_PS;185 mac->mii.addr = MAC_MII_ADDR;186 mac->mii.data = MAC_MII_DATA;187 mac->mii.addr_shift = 11;188 mac->mii.addr_mask = 0x0000F800;189 mac->mii.reg_shift = 6;190 mac->mii.reg_mask = 0x000007C0;191 mac->mii.clk_csr_shift = 2;192 mac->mii.clk_csr_mask = GENMASK(5, 2);193 194 return 0;195}196