1// SPDX-License-Identifier: GPL-2.0
2/* Copyright Sunplus Technology Co., Ltd.
3 * All rights reserved.
4 */
5
6#include <linux/netdevice.h>
7#include <linux/bitfield.h>
8#include <linux/of_mdio.h>
9
10#include "spl2sw_register.h"
11#include "spl2sw_define.h"
12#include "spl2sw_phy.h"
13
14static void spl2sw_mii_link_change(struct net_device *ndev)
15{
16 struct spl2sw_mac *mac = netdev_priv(dev: ndev);
17 struct phy_device *phydev = ndev->phydev;
18 struct spl2sw_common *comm = mac->comm;
19 u32 reg;
20
21 reg = readl(addr: comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE);
22
23 if (phydev->link) {
24 reg |= FIELD_PREP(MAC_FORCE_RMII_LINK, mac->lan_port);
25
26 if (phydev->speed == 100) {
27 reg |= FIELD_PREP(MAC_FORCE_RMII_SPD, mac->lan_port);
28 } else {
29 reg &= FIELD_PREP(MAC_FORCE_RMII_SPD, ~mac->lan_port) |
30 ~MAC_FORCE_RMII_SPD;
31 }
32
33 if (phydev->duplex) {
34 reg |= FIELD_PREP(MAC_FORCE_RMII_DPX, mac->lan_port);
35 } else {
36 reg &= FIELD_PREP(MAC_FORCE_RMII_DPX, ~mac->lan_port) |
37 ~MAC_FORCE_RMII_DPX;
38 }
39
40 if (phydev->pause) {
41 reg |= FIELD_PREP(MAC_FORCE_RMII_FC, mac->lan_port);
42 } else {
43 reg &= FIELD_PREP(MAC_FORCE_RMII_FC, ~mac->lan_port) |
44 ~MAC_FORCE_RMII_FC;
45 }
46 } else {
47 reg &= FIELD_PREP(MAC_FORCE_RMII_LINK, ~mac->lan_port) |
48 ~MAC_FORCE_RMII_LINK;
49 }
50
51 writel(val: reg, addr: comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE);
52
53 phy_print_status(phydev);
54}
55
56int spl2sw_phy_connect(struct spl2sw_common *comm)
57{
58 struct phy_device *phydev;
59 struct net_device *ndev;
60 struct spl2sw_mac *mac;
61 int i;
62
63 for (i = 0; i < MAX_NETDEV_NUM; i++)
64 if (comm->ndev[i]) {
65 ndev = comm->ndev[i];
66 mac = netdev_priv(dev: ndev);
67 phydev = of_phy_connect(dev: ndev, phy_np: mac->phy_node, hndlr: spl2sw_mii_link_change,
68 flags: 0, iface: mac->phy_mode);
69 if (!phydev)
70 return -ENODEV;
71
72 phy_support_asym_pause(phydev);
73 phy_attached_info(phydev);
74 }
75
76 return 0;
77}
78
79void spl2sw_phy_remove(struct spl2sw_common *comm)
80{
81 struct net_device *ndev;
82 int i;
83
84 for (i = 0; i < MAX_NETDEV_NUM; i++)
85 if (comm->ndev[i]) {
86 ndev = comm->ndev[i];
87 if (ndev)
88 phy_disconnect(phydev: ndev->phydev);
89 }
90}
91

source code of linux/drivers/net/ethernet/sunplus/spl2sw_phy.c