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 | |
14 | static 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 | |
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(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 | |
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(phydev: ndev->phydev); |
89 | } |
90 | } |
91 | |