1fd3040b9SWells Lu // SPDX-License-Identifier: GPL-2.0 2fd3040b9SWells Lu /* Copyright Sunplus Technology Co., Ltd. 3fd3040b9SWells Lu * All rights reserved. 4fd3040b9SWells Lu */ 5fd3040b9SWells Lu 6fd3040b9SWells Lu #include <linux/platform_device.h> 7fd3040b9SWells Lu #include <linux/nvmem-consumer.h> 8fd3040b9SWells Lu #include <linux/etherdevice.h> 9fd3040b9SWells Lu #include <linux/netdevice.h> 10fd3040b9SWells Lu #include <linux/spinlock.h> 11fd3040b9SWells Lu #include <linux/of_net.h> 12fd3040b9SWells Lu #include <linux/reset.h> 13fd3040b9SWells Lu #include <linux/clk.h> 14fd3040b9SWells Lu #include <linux/of.h> 15fd3040b9SWells Lu 16fd3040b9SWells Lu #include "spl2sw_register.h" 17fd3040b9SWells Lu #include "spl2sw_define.h" 18fd3040b9SWells Lu #include "spl2sw_desc.h" 19fd3040b9SWells Lu #include "spl2sw_mdio.h" 20fd3040b9SWells Lu #include "spl2sw_phy.h" 21fd3040b9SWells Lu #include "spl2sw_int.h" 22fd3040b9SWells Lu #include "spl2sw_mac.h" 23fd3040b9SWells Lu 24fd3040b9SWells Lu /* net device operations */ 25fd3040b9SWells Lu static int spl2sw_ethernet_open(struct net_device *ndev) 26fd3040b9SWells Lu { 27fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 28fd3040b9SWells Lu struct spl2sw_common *comm = mac->comm; 29fd3040b9SWells Lu u32 mask; 30fd3040b9SWells Lu 31fd3040b9SWells Lu netdev_dbg(ndev, "Open port = %x\n", mac->lan_port); 32fd3040b9SWells Lu 33fd3040b9SWells Lu comm->enable |= mac->lan_port; 34fd3040b9SWells Lu 35fd3040b9SWells Lu spl2sw_mac_hw_start(comm); 36fd3040b9SWells Lu 37fd3040b9SWells Lu /* Enable TX and RX interrupts */ 38fd3040b9SWells Lu mask = readl(comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 39fd3040b9SWells Lu mask &= ~(MAC_INT_TX | MAC_INT_RX); 40fd3040b9SWells Lu writel(mask, comm->l2sw_reg_base + L2SW_SW_INT_MASK_0); 41fd3040b9SWells Lu 42fd3040b9SWells Lu phy_start(ndev->phydev); 43fd3040b9SWells Lu 44fd3040b9SWells Lu netif_start_queue(ndev); 45fd3040b9SWells Lu 46fd3040b9SWells Lu return 0; 47fd3040b9SWells Lu } 48fd3040b9SWells Lu 49fd3040b9SWells Lu static int spl2sw_ethernet_stop(struct net_device *ndev) 50fd3040b9SWells Lu { 51fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 52fd3040b9SWells Lu struct spl2sw_common *comm = mac->comm; 53fd3040b9SWells Lu 54fd3040b9SWells Lu netif_stop_queue(ndev); 55fd3040b9SWells Lu 56fd3040b9SWells Lu comm->enable &= ~mac->lan_port; 57fd3040b9SWells Lu 58fd3040b9SWells Lu phy_stop(ndev->phydev); 59fd3040b9SWells Lu 60fd3040b9SWells Lu spl2sw_mac_hw_stop(comm); 61fd3040b9SWells Lu 62fd3040b9SWells Lu return 0; 63fd3040b9SWells Lu } 64fd3040b9SWells Lu 657b620e15SGUO Zihua static netdev_tx_t spl2sw_ethernet_start_xmit(struct sk_buff *skb, 667b620e15SGUO Zihua struct net_device *ndev) 67fd3040b9SWells Lu { 68fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 69fd3040b9SWells Lu struct spl2sw_common *comm = mac->comm; 70fd3040b9SWells Lu struct spl2sw_skb_info *skbinfo; 71fd3040b9SWells Lu struct spl2sw_mac_desc *txdesc; 72fd3040b9SWells Lu unsigned long flags; 73fd3040b9SWells Lu u32 mapping; 74fd3040b9SWells Lu u32 tx_pos; 75fd3040b9SWells Lu u32 cmd1; 76fd3040b9SWells Lu u32 cmd2; 77fd3040b9SWells Lu 78fd3040b9SWells Lu if (unlikely(comm->tx_desc_full == 1)) { 79fd3040b9SWells Lu /* No TX descriptors left. Wait for tx interrupt. */ 80fd3040b9SWells Lu netdev_dbg(ndev, "TX descriptor queue full when xmit!\n"); 81fd3040b9SWells Lu return NETDEV_TX_BUSY; 82fd3040b9SWells Lu } 83fd3040b9SWells Lu 84fd3040b9SWells Lu /* If skb size is shorter than ETH_ZLEN (60), pad it with 0. */ 85fd3040b9SWells Lu if (unlikely(skb->len < ETH_ZLEN)) { 86fd3040b9SWells Lu if (skb_padto(skb, ETH_ZLEN)) 87fd3040b9SWells Lu return NETDEV_TX_OK; 88fd3040b9SWells Lu 89fd3040b9SWells Lu skb_put(skb, ETH_ZLEN - skb->len); 90fd3040b9SWells Lu } 91fd3040b9SWells Lu 92fd3040b9SWells Lu mapping = dma_map_single(&comm->pdev->dev, skb->data, 93fd3040b9SWells Lu skb->len, DMA_TO_DEVICE); 94fd3040b9SWells Lu if (dma_mapping_error(&comm->pdev->dev, mapping)) { 95fd3040b9SWells Lu ndev->stats.tx_errors++; 96fd3040b9SWells Lu dev_kfree_skb(skb); 97fd3040b9SWells Lu return NETDEV_TX_OK; 98fd3040b9SWells Lu } 99fd3040b9SWells Lu 100fd3040b9SWells Lu spin_lock_irqsave(&comm->tx_lock, flags); 101fd3040b9SWells Lu 102fd3040b9SWells Lu tx_pos = comm->tx_pos; 103fd3040b9SWells Lu txdesc = &comm->tx_desc[tx_pos]; 104fd3040b9SWells Lu skbinfo = &comm->tx_temp_skb_info[tx_pos]; 105fd3040b9SWells Lu skbinfo->mapping = mapping; 106fd3040b9SWells Lu skbinfo->len = skb->len; 107fd3040b9SWells Lu skbinfo->skb = skb; 108fd3040b9SWells Lu 109fd3040b9SWells Lu /* Set up a TX descriptor */ 110fd3040b9SWells Lu cmd1 = TXD_OWN | TXD_SOP | TXD_EOP | (mac->to_vlan << 12) | 111fd3040b9SWells Lu (skb->len & TXD_PKT_LEN); 112fd3040b9SWells Lu cmd2 = skb->len & TXD_BUF_LEN1; 113fd3040b9SWells Lu 114fd3040b9SWells Lu if (tx_pos == (TX_DESC_NUM - 1)) 115fd3040b9SWells Lu cmd2 |= TXD_EOR; 116fd3040b9SWells Lu 117fd3040b9SWells Lu txdesc->addr1 = skbinfo->mapping; 118fd3040b9SWells Lu txdesc->cmd2 = cmd2; 119fd3040b9SWells Lu wmb(); /* Set TXD_OWN after other fields are effective. */ 120fd3040b9SWells Lu txdesc->cmd1 = cmd1; 121fd3040b9SWells Lu 122fd3040b9SWells Lu /* Move tx_pos to next position */ 123fd3040b9SWells Lu tx_pos = ((tx_pos + 1) == TX_DESC_NUM) ? 0 : tx_pos + 1; 124fd3040b9SWells Lu 125fd3040b9SWells Lu if (unlikely(tx_pos == comm->tx_done_pos)) { 126fd3040b9SWells Lu netif_stop_queue(ndev); 127fd3040b9SWells Lu comm->tx_desc_full = 1; 128fd3040b9SWells Lu } 129fd3040b9SWells Lu comm->tx_pos = tx_pos; 130fd3040b9SWells Lu wmb(); /* make sure settings are effective. */ 131fd3040b9SWells Lu 132fd3040b9SWells Lu /* Trigger mac to transmit */ 133fd3040b9SWells Lu writel(MAC_TRIG_L_SOC0, comm->l2sw_reg_base + L2SW_CPU_TX_TRIG); 134fd3040b9SWells Lu 135fd3040b9SWells Lu spin_unlock_irqrestore(&comm->tx_lock, flags); 136fd3040b9SWells Lu return NETDEV_TX_OK; 137fd3040b9SWells Lu } 138fd3040b9SWells Lu 139fd3040b9SWells Lu static void spl2sw_ethernet_set_rx_mode(struct net_device *ndev) 140fd3040b9SWells Lu { 141fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 142fd3040b9SWells Lu 143fd3040b9SWells Lu spl2sw_mac_rx_mode_set(mac); 144fd3040b9SWells Lu } 145fd3040b9SWells Lu 146fd3040b9SWells Lu static int spl2sw_ethernet_set_mac_address(struct net_device *ndev, void *addr) 147fd3040b9SWells Lu { 148fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 149fd3040b9SWells Lu int err; 150fd3040b9SWells Lu 151fd3040b9SWells Lu err = eth_mac_addr(ndev, addr); 152fd3040b9SWells Lu if (err) 153fd3040b9SWells Lu return err; 154fd3040b9SWells Lu 155fd3040b9SWells Lu /* Delete the old MAC address */ 156fd3040b9SWells Lu netdev_dbg(ndev, "Old Ethernet (MAC) address = %pM\n", mac->mac_addr); 157fd3040b9SWells Lu if (is_valid_ether_addr(mac->mac_addr)) { 158fd3040b9SWells Lu err = spl2sw_mac_addr_del(mac); 159fd3040b9SWells Lu if (err) 160fd3040b9SWells Lu return err; 161fd3040b9SWells Lu } 162fd3040b9SWells Lu 163fd3040b9SWells Lu /* Set the MAC address */ 164fd3040b9SWells Lu ether_addr_copy(mac->mac_addr, ndev->dev_addr); 165fd3040b9SWells Lu return spl2sw_mac_addr_add(mac); 166fd3040b9SWells Lu } 167fd3040b9SWells Lu 168fd3040b9SWells Lu static void spl2sw_ethernet_tx_timeout(struct net_device *ndev, unsigned int txqueue) 169fd3040b9SWells Lu { 170fd3040b9SWells Lu struct spl2sw_mac *mac = netdev_priv(ndev); 171fd3040b9SWells Lu struct spl2sw_common *comm = mac->comm; 172fd3040b9SWells Lu unsigned long flags; 173fd3040b9SWells Lu int i; 174fd3040b9SWells Lu 175fd3040b9SWells Lu netdev_err(ndev, "TX timed out!\n"); 176fd3040b9SWells Lu ndev->stats.tx_errors++; 177fd3040b9SWells Lu 178fd3040b9SWells Lu spin_lock_irqsave(&comm->tx_lock, flags); 179fd3040b9SWells Lu 180fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) 181fd3040b9SWells Lu if (comm->ndev[i]) 182fd3040b9SWells Lu netif_stop_queue(comm->ndev[i]); 183fd3040b9SWells Lu 184fd3040b9SWells Lu spl2sw_mac_soft_reset(comm); 185fd3040b9SWells Lu 186fd3040b9SWells Lu /* Accept TX packets again. */ 187fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) 188fd3040b9SWells Lu if (comm->ndev[i]) { 189fd3040b9SWells Lu netif_trans_update(comm->ndev[i]); 190fd3040b9SWells Lu netif_wake_queue(comm->ndev[i]); 191fd3040b9SWells Lu } 192fd3040b9SWells Lu 193fd3040b9SWells Lu spin_unlock_irqrestore(&comm->tx_lock, flags); 194fd3040b9SWells Lu } 195fd3040b9SWells Lu 196fd3040b9SWells Lu static const struct net_device_ops netdev_ops = { 197fd3040b9SWells Lu .ndo_open = spl2sw_ethernet_open, 198fd3040b9SWells Lu .ndo_stop = spl2sw_ethernet_stop, 199fd3040b9SWells Lu .ndo_start_xmit = spl2sw_ethernet_start_xmit, 200fd3040b9SWells Lu .ndo_set_rx_mode = spl2sw_ethernet_set_rx_mode, 201fd3040b9SWells Lu .ndo_set_mac_address = spl2sw_ethernet_set_mac_address, 202fd3040b9SWells Lu .ndo_do_ioctl = phy_do_ioctl, 203fd3040b9SWells Lu .ndo_tx_timeout = spl2sw_ethernet_tx_timeout, 204fd3040b9SWells Lu }; 205fd3040b9SWells Lu 206fd3040b9SWells Lu static void spl2sw_check_mac_vendor_id_and_convert(u8 *mac_addr) 207fd3040b9SWells Lu { 208fd3040b9SWells Lu /* Byte order of MAC address of some samples are reversed. 209fd3040b9SWells Lu * Check vendor id and convert byte order if it is wrong. 210fd3040b9SWells Lu * OUI of Sunplus: fc:4b:bc 211fd3040b9SWells Lu */ 212fd3040b9SWells Lu if (mac_addr[5] == 0xfc && mac_addr[4] == 0x4b && mac_addr[3] == 0xbc && 213fd3040b9SWells Lu (mac_addr[0] != 0xfc || mac_addr[1] != 0x4b || mac_addr[2] != 0xbc)) { 214fd3040b9SWells Lu 215a19cef45SJiapeng Chong swap(mac_addr[0], mac_addr[5]); 216a19cef45SJiapeng Chong swap(mac_addr[1], mac_addr[4]); 217a19cef45SJiapeng Chong swap(mac_addr[2], mac_addr[3]); 218fd3040b9SWells Lu } 219fd3040b9SWells Lu } 220fd3040b9SWells Lu 221fd3040b9SWells Lu static int spl2sw_nvmem_get_mac_address(struct device *dev, struct device_node *np, 222fd3040b9SWells Lu void *addrbuf) 223fd3040b9SWells Lu { 224fd3040b9SWells Lu struct nvmem_cell *cell; 225fd3040b9SWells Lu ssize_t len; 226fd3040b9SWells Lu u8 *mac; 227fd3040b9SWells Lu 228fd3040b9SWells Lu /* Get nvmem cell of mac-address from dts. */ 229fd3040b9SWells Lu cell = of_nvmem_cell_get(np, "mac-address"); 230fd3040b9SWells Lu if (IS_ERR(cell)) 231fd3040b9SWells Lu return PTR_ERR(cell); 232fd3040b9SWells Lu 233fd3040b9SWells Lu /* Read mac address from nvmem cell. */ 234fd3040b9SWells Lu mac = nvmem_cell_read(cell, &len); 235fd3040b9SWells Lu nvmem_cell_put(cell); 236fd3040b9SWells Lu if (IS_ERR(mac)) 237fd3040b9SWells Lu return PTR_ERR(mac); 238fd3040b9SWells Lu 239fd3040b9SWells Lu if (len != ETH_ALEN) { 240fd3040b9SWells Lu kfree(mac); 241fd3040b9SWells Lu dev_info(dev, "Invalid length of mac address in nvmem!\n"); 242fd3040b9SWells Lu return -EINVAL; 243fd3040b9SWells Lu } 244fd3040b9SWells Lu 245fd3040b9SWells Lu /* Byte order of some samples are reversed. 246fd3040b9SWells Lu * Convert byte order here. 247fd3040b9SWells Lu */ 248fd3040b9SWells Lu spl2sw_check_mac_vendor_id_and_convert(mac); 249fd3040b9SWells Lu 250fd3040b9SWells Lu /* Check if mac address is valid */ 251fd3040b9SWells Lu if (!is_valid_ether_addr(mac)) { 252fd3040b9SWells Lu kfree(mac); 253fd3040b9SWells Lu dev_info(dev, "Invalid mac address in nvmem (%pM)!\n", mac); 254fd3040b9SWells Lu return -EINVAL; 255fd3040b9SWells Lu } 256fd3040b9SWells Lu 257fd3040b9SWells Lu ether_addr_copy(addrbuf, mac); 258fd3040b9SWells Lu kfree(mac); 259fd3040b9SWells Lu return 0; 260fd3040b9SWells Lu } 261fd3040b9SWells Lu 262fd3040b9SWells Lu static u32 spl2sw_init_netdev(struct platform_device *pdev, u8 *mac_addr, 263fd3040b9SWells Lu struct net_device **r_ndev) 264fd3040b9SWells Lu { 265fd3040b9SWells Lu struct net_device *ndev; 266fd3040b9SWells Lu struct spl2sw_mac *mac; 267fd3040b9SWells Lu int ret; 268fd3040b9SWells Lu 269fd3040b9SWells Lu /* Allocate the devices, and also allocate spl2sw_mac, 270fd3040b9SWells Lu * we can get it by netdev_priv(). 271fd3040b9SWells Lu */ 272fd3040b9SWells Lu ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*mac)); 273fd3040b9SWells Lu if (!ndev) { 274fd3040b9SWells Lu *r_ndev = NULL; 275fd3040b9SWells Lu return -ENOMEM; 276fd3040b9SWells Lu } 277fd3040b9SWells Lu SET_NETDEV_DEV(ndev, &pdev->dev); 278fd3040b9SWells Lu ndev->netdev_ops = &netdev_ops; 279fd3040b9SWells Lu mac = netdev_priv(ndev); 280fd3040b9SWells Lu mac->ndev = ndev; 281fd3040b9SWells Lu ether_addr_copy(mac->mac_addr, mac_addr); 282fd3040b9SWells Lu 283fd3040b9SWells Lu eth_hw_addr_set(ndev, mac_addr); 284fd3040b9SWells Lu dev_info(&pdev->dev, "Ethernet (MAC) address = %pM\n", mac_addr); 285fd3040b9SWells Lu 286fd3040b9SWells Lu ret = register_netdev(ndev); 287fd3040b9SWells Lu if (ret) { 288fd3040b9SWells Lu dev_err(&pdev->dev, "Failed to register net device \"%s\"!\n", 289fd3040b9SWells Lu ndev->name); 290fd3040b9SWells Lu free_netdev(ndev); 291fd3040b9SWells Lu *r_ndev = NULL; 292fd3040b9SWells Lu return ret; 293fd3040b9SWells Lu } 294fd3040b9SWells Lu netdev_dbg(ndev, "Registered net device \"%s\" successfully.\n", ndev->name); 295fd3040b9SWells Lu 296fd3040b9SWells Lu *r_ndev = ndev; 297fd3040b9SWells Lu return 0; 298fd3040b9SWells Lu } 299fd3040b9SWells Lu 300fd3040b9SWells Lu static struct device_node *spl2sw_get_eth_child_node(struct device_node *ether_np, int id) 301fd3040b9SWells Lu { 302fd3040b9SWells Lu struct device_node *port_np; 303fd3040b9SWells Lu int port_id; 304fd3040b9SWells Lu 305fd3040b9SWells Lu for_each_child_of_node(ether_np, port_np) { 306fd3040b9SWells Lu /* It is not a 'port' node, continue. */ 307fd3040b9SWells Lu if (strcmp(port_np->name, "port")) 308fd3040b9SWells Lu continue; 309fd3040b9SWells Lu 310fd3040b9SWells Lu if (of_property_read_u32(port_np, "reg", &port_id) < 0) 311fd3040b9SWells Lu continue; 312fd3040b9SWells Lu 313fd3040b9SWells Lu if (port_id == id) 314fd3040b9SWells Lu return port_np; 315fd3040b9SWells Lu } 316fd3040b9SWells Lu 317fd3040b9SWells Lu /* Not found! */ 318fd3040b9SWells Lu return NULL; 319fd3040b9SWells Lu } 320fd3040b9SWells Lu 321fd3040b9SWells Lu static int spl2sw_probe(struct platform_device *pdev) 322fd3040b9SWells Lu { 323fd3040b9SWells Lu struct device_node *eth_ports_np; 324fd3040b9SWells Lu struct device_node *port_np; 325fd3040b9SWells Lu struct spl2sw_common *comm; 326fd3040b9SWells Lu struct device_node *phy_np; 327fd3040b9SWells Lu phy_interface_t phy_mode; 328fd3040b9SWells Lu struct net_device *ndev; 329fd3040b9SWells Lu struct spl2sw_mac *mac; 330fd3040b9SWells Lu u8 mac_addr[ETH_ALEN]; 331fd3040b9SWells Lu int irq, i, ret; 332fd3040b9SWells Lu 333fd3040b9SWells Lu if (platform_get_drvdata(pdev)) 334fd3040b9SWells Lu return -ENODEV; 335fd3040b9SWells Lu 336fd3040b9SWells Lu /* Allocate memory for 'spl2sw_common' area. */ 337fd3040b9SWells Lu comm = devm_kzalloc(&pdev->dev, sizeof(*comm), GFP_KERNEL); 338fd3040b9SWells Lu if (!comm) 339fd3040b9SWells Lu return -ENOMEM; 340fd3040b9SWells Lu 341fd3040b9SWells Lu comm->pdev = pdev; 342fd3040b9SWells Lu platform_set_drvdata(pdev, comm); 343fd3040b9SWells Lu 344fd3040b9SWells Lu spin_lock_init(&comm->tx_lock); 345fd3040b9SWells Lu spin_lock_init(&comm->mdio_lock); 346fd3040b9SWells Lu spin_lock_init(&comm->int_mask_lock); 347fd3040b9SWells Lu 348fd3040b9SWells Lu /* Get memory resource 0 from dts. */ 349fd3040b9SWells Lu comm->l2sw_reg_base = devm_platform_ioremap_resource(pdev, 0); 350fd3040b9SWells Lu if (IS_ERR(comm->l2sw_reg_base)) 351fd3040b9SWells Lu return PTR_ERR(comm->l2sw_reg_base); 352fd3040b9SWells Lu 353fd3040b9SWells Lu /* Get irq resource from dts. */ 354fd3040b9SWells Lu ret = platform_get_irq(pdev, 0); 355fd3040b9SWells Lu if (ret < 0) 356fd3040b9SWells Lu return ret; 357fd3040b9SWells Lu irq = ret; 358fd3040b9SWells Lu 359fd3040b9SWells Lu /* Get clock controller. */ 360fd3040b9SWells Lu comm->clk = devm_clk_get(&pdev->dev, NULL); 361fd3040b9SWells Lu if (IS_ERR(comm->clk)) { 362fd3040b9SWells Lu dev_err_probe(&pdev->dev, PTR_ERR(comm->clk), 363fd3040b9SWells Lu "Failed to retrieve clock controller!\n"); 364fd3040b9SWells Lu return PTR_ERR(comm->clk); 365fd3040b9SWells Lu } 366fd3040b9SWells Lu 367fd3040b9SWells Lu /* Get reset controller. */ 368fd3040b9SWells Lu comm->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); 369fd3040b9SWells Lu if (IS_ERR(comm->rstc)) { 370fd3040b9SWells Lu dev_err_probe(&pdev->dev, PTR_ERR(comm->rstc), 371fd3040b9SWells Lu "Failed to retrieve reset controller!\n"); 372fd3040b9SWells Lu return PTR_ERR(comm->rstc); 373fd3040b9SWells Lu } 374fd3040b9SWells Lu 375fd3040b9SWells Lu /* Enable clock. */ 376fd3040b9SWells Lu ret = clk_prepare_enable(comm->clk); 377fd3040b9SWells Lu if (ret) 378fd3040b9SWells Lu return ret; 379fd3040b9SWells Lu udelay(1); 380fd3040b9SWells Lu 381fd3040b9SWells Lu /* Reset MAC */ 382fd3040b9SWells Lu reset_control_assert(comm->rstc); 383fd3040b9SWells Lu udelay(1); 384fd3040b9SWells Lu reset_control_deassert(comm->rstc); 385fd3040b9SWells Lu usleep_range(1000, 2000); 386fd3040b9SWells Lu 387fd3040b9SWells Lu /* Request irq. */ 388fd3040b9SWells Lu ret = devm_request_irq(&pdev->dev, irq, spl2sw_ethernet_interrupt, 0, 389fd3040b9SWells Lu dev_name(&pdev->dev), comm); 390fd3040b9SWells Lu if (ret) { 391fd3040b9SWells Lu dev_err(&pdev->dev, "Failed to request irq #%d!\n", irq); 392fd3040b9SWells Lu goto out_clk_disable; 393fd3040b9SWells Lu } 394fd3040b9SWells Lu 395fd3040b9SWells Lu /* Initialize TX and RX descriptors. */ 396fd3040b9SWells Lu ret = spl2sw_descs_init(comm); 397fd3040b9SWells Lu if (ret) { 398fd3040b9SWells Lu dev_err(&pdev->dev, "Fail to initialize mac descriptors!\n"); 399fd3040b9SWells Lu spl2sw_descs_free(comm); 400fd3040b9SWells Lu goto out_clk_disable; 401fd3040b9SWells Lu } 402fd3040b9SWells Lu 403fd3040b9SWells Lu /* Initialize MAC. */ 404fd3040b9SWells Lu spl2sw_mac_init(comm); 405fd3040b9SWells Lu 406fd3040b9SWells Lu /* Initialize mdio bus */ 407fd3040b9SWells Lu ret = spl2sw_mdio_init(comm); 408fd3040b9SWells Lu if (ret) { 409fd3040b9SWells Lu dev_err(&pdev->dev, "Failed to initialize mdio bus!\n"); 410fd3040b9SWells Lu goto out_clk_disable; 411fd3040b9SWells Lu } 412fd3040b9SWells Lu 413fd3040b9SWells Lu /* Get child node ethernet-ports. */ 414fd3040b9SWells Lu eth_ports_np = of_get_child_by_name(pdev->dev.of_node, "ethernet-ports"); 415fd3040b9SWells Lu if (!eth_ports_np) { 416fd3040b9SWells Lu dev_err(&pdev->dev, "No ethernet-ports child node found!\n"); 417fd3040b9SWells Lu ret = -ENODEV; 418fd3040b9SWells Lu goto out_free_mdio; 419fd3040b9SWells Lu } 420fd3040b9SWells Lu 421fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) { 422fd3040b9SWells Lu /* Get port@i of node ethernet-ports. */ 423fd3040b9SWells Lu port_np = spl2sw_get_eth_child_node(eth_ports_np, i); 424fd3040b9SWells Lu if (!port_np) 425fd3040b9SWells Lu continue; 426fd3040b9SWells Lu 427fd3040b9SWells Lu /* Get phy-mode. */ 428fd3040b9SWells Lu if (of_get_phy_mode(port_np, &phy_mode)) { 429fd3040b9SWells Lu dev_err(&pdev->dev, "Failed to get phy-mode property of port@%d!\n", 430fd3040b9SWells Lu i); 431fd3040b9SWells Lu continue; 432fd3040b9SWells Lu } 433fd3040b9SWells Lu 434fd3040b9SWells Lu /* Get phy-handle. */ 435fd3040b9SWells Lu phy_np = of_parse_phandle(port_np, "phy-handle", 0); 436fd3040b9SWells Lu if (!phy_np) { 437fd3040b9SWells Lu dev_err(&pdev->dev, "Failed to get phy-handle property of port@%d!\n", 438fd3040b9SWells Lu i); 439fd3040b9SWells Lu continue; 440fd3040b9SWells Lu } 441fd3040b9SWells Lu 442fd3040b9SWells Lu /* Get mac-address from nvmem. */ 443fd3040b9SWells Lu ret = spl2sw_nvmem_get_mac_address(&pdev->dev, port_np, mac_addr); 444fd3040b9SWells Lu if (ret == -EPROBE_DEFER) { 445fd3040b9SWells Lu goto out_unregister_dev; 446fd3040b9SWells Lu } else if (ret) { 447fd3040b9SWells Lu dev_info(&pdev->dev, "Generate a random mac address!\n"); 448fd3040b9SWells Lu eth_random_addr(mac_addr); 449fd3040b9SWells Lu } 450fd3040b9SWells Lu 451fd3040b9SWells Lu /* Initialize the net device. */ 452fd3040b9SWells Lu ret = spl2sw_init_netdev(pdev, mac_addr, &ndev); 453fd3040b9SWells Lu if (ret) 454fd3040b9SWells Lu goto out_unregister_dev; 455fd3040b9SWells Lu 456fd3040b9SWells Lu ndev->irq = irq; 457fd3040b9SWells Lu comm->ndev[i] = ndev; 458fd3040b9SWells Lu mac = netdev_priv(ndev); 459fd3040b9SWells Lu mac->phy_node = phy_np; 460fd3040b9SWells Lu mac->phy_mode = phy_mode; 461fd3040b9SWells Lu mac->comm = comm; 462fd3040b9SWells Lu 463fd3040b9SWells Lu mac->lan_port = 0x1 << i; /* forward to port i */ 464fd3040b9SWells Lu mac->to_vlan = 0x1 << i; /* vlan group: i */ 465fd3040b9SWells Lu mac->vlan_id = i; /* vlan group: i */ 466fd3040b9SWells Lu 467fd3040b9SWells Lu /* Set MAC address */ 468fd3040b9SWells Lu ret = spl2sw_mac_addr_add(mac); 469fd3040b9SWells Lu if (ret) 470fd3040b9SWells Lu goto out_unregister_dev; 471fd3040b9SWells Lu 472fd3040b9SWells Lu spl2sw_mac_rx_mode_set(mac); 473fd3040b9SWells Lu } 474fd3040b9SWells Lu 475fd3040b9SWells Lu /* Find first valid net device. */ 476fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) { 477fd3040b9SWells Lu if (comm->ndev[i]) 478fd3040b9SWells Lu break; 479fd3040b9SWells Lu } 480fd3040b9SWells Lu if (i >= MAX_NETDEV_NUM) { 481fd3040b9SWells Lu dev_err(&pdev->dev, "No valid ethernet port!\n"); 482fd3040b9SWells Lu ret = -ENODEV; 483fd3040b9SWells Lu goto out_free_mdio; 484fd3040b9SWells Lu } 485fd3040b9SWells Lu 486fd3040b9SWells Lu /* Save first valid net device */ 487fd3040b9SWells Lu ndev = comm->ndev[i]; 488fd3040b9SWells Lu 489fd3040b9SWells Lu ret = spl2sw_phy_connect(comm); 490fd3040b9SWells Lu if (ret) { 491fd3040b9SWells Lu netdev_err(ndev, "Failed to connect phy!\n"); 492fd3040b9SWells Lu goto out_unregister_dev; 493fd3040b9SWells Lu } 494fd3040b9SWells Lu 495fd3040b9SWells Lu /* Add and enable napi. */ 496*b48b89f9SJakub Kicinski netif_napi_add(ndev, &comm->rx_napi, spl2sw_rx_poll); 497fd3040b9SWells Lu napi_enable(&comm->rx_napi); 4989157533aSJakub Kicinski netif_napi_add_tx(ndev, &comm->tx_napi, spl2sw_tx_poll); 499fd3040b9SWells Lu napi_enable(&comm->tx_napi); 500fd3040b9SWells Lu return 0; 501fd3040b9SWells Lu 502fd3040b9SWells Lu out_unregister_dev: 503fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) 504fd3040b9SWells Lu if (comm->ndev[i]) 505fd3040b9SWells Lu unregister_netdev(comm->ndev[i]); 506fd3040b9SWells Lu 507fd3040b9SWells Lu out_free_mdio: 508fd3040b9SWells Lu spl2sw_mdio_remove(comm); 509fd3040b9SWells Lu 510fd3040b9SWells Lu out_clk_disable: 511fd3040b9SWells Lu clk_disable_unprepare(comm->clk); 512fd3040b9SWells Lu return ret; 513fd3040b9SWells Lu } 514fd3040b9SWells Lu 515fd3040b9SWells Lu static int spl2sw_remove(struct platform_device *pdev) 516fd3040b9SWells Lu { 517fd3040b9SWells Lu struct spl2sw_common *comm; 518fd3040b9SWells Lu int i; 519fd3040b9SWells Lu 520fd3040b9SWells Lu comm = platform_get_drvdata(pdev); 521fd3040b9SWells Lu 522fd3040b9SWells Lu spl2sw_phy_remove(comm); 523fd3040b9SWells Lu 524fd3040b9SWells Lu /* Unregister and free net device. */ 525fd3040b9SWells Lu for (i = 0; i < MAX_NETDEV_NUM; i++) 526fd3040b9SWells Lu if (comm->ndev[i]) 527fd3040b9SWells Lu unregister_netdev(comm->ndev[i]); 528fd3040b9SWells Lu 529fd3040b9SWells Lu comm->enable = 0; 530fd3040b9SWells Lu spl2sw_mac_hw_stop(comm); 531fd3040b9SWells Lu spl2sw_descs_free(comm); 532fd3040b9SWells Lu 533fd3040b9SWells Lu /* Disable and delete napi. */ 534fd3040b9SWells Lu napi_disable(&comm->rx_napi); 535fd3040b9SWells Lu netif_napi_del(&comm->rx_napi); 536fd3040b9SWells Lu napi_disable(&comm->tx_napi); 537fd3040b9SWells Lu netif_napi_del(&comm->tx_napi); 538fd3040b9SWells Lu 539fd3040b9SWells Lu spl2sw_mdio_remove(comm); 540fd3040b9SWells Lu 541fd3040b9SWells Lu clk_disable_unprepare(comm->clk); 542fd3040b9SWells Lu 543fd3040b9SWells Lu return 0; 544fd3040b9SWells Lu } 545fd3040b9SWells Lu 546fd3040b9SWells Lu static const struct of_device_id spl2sw_of_match[] = { 547fd3040b9SWells Lu {.compatible = "sunplus,sp7021-emac"}, 548fd3040b9SWells Lu { /* sentinel */ } 549fd3040b9SWells Lu }; 550fd3040b9SWells Lu 551fd3040b9SWells Lu MODULE_DEVICE_TABLE(of, spl2sw_of_match); 552fd3040b9SWells Lu 553fd3040b9SWells Lu static struct platform_driver spl2sw_driver = { 554fd3040b9SWells Lu .probe = spl2sw_probe, 555fd3040b9SWells Lu .remove = spl2sw_remove, 556fd3040b9SWells Lu .driver = { 557fd3040b9SWells Lu .name = "sp7021_emac", 558fd3040b9SWells Lu .of_match_table = spl2sw_of_match, 559fd3040b9SWells Lu }, 560fd3040b9SWells Lu }; 561fd3040b9SWells Lu 562fd3040b9SWells Lu module_platform_driver(spl2sw_driver); 563fd3040b9SWells Lu 564fd3040b9SWells Lu MODULE_AUTHOR("Wells Lu <wellslutw@gmail.com>"); 565fd3040b9SWells Lu MODULE_DESCRIPTION("Sunplus Dual 10M/100M Ethernet driver"); 566fd3040b9SWells Lu MODULE_LICENSE("GPL"); 567