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
spl2sw_mii_link_change(struct net_device * ndev)14 static void spl2sw_mii_link_change(struct net_device *ndev)
15 {
16 struct spl2sw_mac *mac = netdev_priv(ndev);
17 struct phy_device *phydev = ndev->phydev;
18 struct spl2sw_common *comm = mac->comm;
19 u32 reg;
20
21 reg = readl(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(reg, comm->l2sw_reg_base + L2SW_MAC_FORCE_MODE);
52
53 phy_print_status(phydev);
54 }
55
spl2sw_phy_connect(struct spl2sw_common * comm)56 int 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(ndev);
67 phydev = of_phy_connect(ndev, mac->phy_node, spl2sw_mii_link_change,
68 0, 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
spl2sw_phy_remove(struct spl2sw_common * comm)79 void 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(ndev->phydev);
89 ndev->phydev = NULL;
90 }
91 }
92 }
93