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