]> Git Repo - linux.git/blob - drivers/net/ethernet/mediatek/mtk_sgmii.c
zstd: import usptream v1.5.2
[linux.git] / drivers / net / ethernet / mediatek / mtk_sgmii.c
1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018-2019 MediaTek Inc.
3
4 /* A library for MediaTek SGMII circuit
5  *
6  * Author: Sean Wang <[email protected]>
7  *
8  */
9
10 #include <linux/mfd/syscon.h>
11 #include <linux/of.h>
12 #include <linux/phylink.h>
13 #include <linux/regmap.h>
14
15 #include "mtk_eth_soc.h"
16
17 static struct mtk_pcs *pcs_to_mtk_pcs(struct phylink_pcs *pcs)
18 {
19         return container_of(pcs, struct mtk_pcs, pcs);
20 }
21
22 /* For SGMII interface mode */
23 static int mtk_pcs_setup_mode_an(struct mtk_pcs *mpcs)
24 {
25         unsigned int val;
26
27         /* Setup the link timer and QPHY power up inside SGMIISYS */
28         regmap_write(mpcs->regmap, SGMSYS_PCS_LINK_TIMER,
29                      SGMII_LINK_TIMER_DEFAULT);
30
31         regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
32         val |= SGMII_REMOTE_FAULT_DIS;
33         regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
34
35         regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
36         val |= SGMII_AN_RESTART;
37         regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
38
39         regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
40         val &= ~SGMII_PHYA_PWD;
41         regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
42
43         return 0;
44
45 }
46
47 /* For 1000BASE-X and 2500BASE-X interface modes, which operate at a
48  * fixed speed.
49  */
50 static int mtk_pcs_setup_mode_force(struct mtk_pcs *mpcs,
51                                     phy_interface_t interface)
52 {
53         unsigned int val;
54
55         regmap_read(mpcs->regmap, mpcs->ana_rgc3, &val);
56         val &= ~RG_PHY_SPEED_MASK;
57         if (interface == PHY_INTERFACE_MODE_2500BASEX)
58                 val |= RG_PHY_SPEED_3_125G;
59         regmap_write(mpcs->regmap, mpcs->ana_rgc3, val);
60
61         /* Disable SGMII AN */
62         regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
63         val &= ~SGMII_AN_ENABLE;
64         regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
65
66         /* Set the speed etc but leave the duplex unchanged */
67         regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
68         val &= SGMII_DUPLEX_FULL | ~SGMII_IF_MODE_MASK;
69         val |= SGMII_SPEED_1000;
70         regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
71
72         /* Release PHYA power down state */
73         regmap_read(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, &val);
74         val &= ~SGMII_PHYA_PWD;
75         regmap_write(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, val);
76
77         return 0;
78 }
79
80 static int mtk_pcs_config(struct phylink_pcs *pcs, unsigned int mode,
81                           phy_interface_t interface,
82                           const unsigned long *advertising,
83                           bool permit_pause_to_mac)
84 {
85         struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
86         int err = 0;
87
88         /* Setup SGMIISYS with the determined property */
89         if (interface != PHY_INTERFACE_MODE_SGMII)
90                 err = mtk_pcs_setup_mode_force(mpcs, interface);
91         else if (phylink_autoneg_inband(mode))
92                 err = mtk_pcs_setup_mode_an(mpcs);
93
94         return err;
95 }
96
97 static void mtk_pcs_restart_an(struct phylink_pcs *pcs)
98 {
99         struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
100         unsigned int val;
101
102         regmap_read(mpcs->regmap, SGMSYS_PCS_CONTROL_1, &val);
103         val |= SGMII_AN_RESTART;
104         regmap_write(mpcs->regmap, SGMSYS_PCS_CONTROL_1, val);
105 }
106
107 static void mtk_pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
108                             phy_interface_t interface, int speed, int duplex)
109 {
110         struct mtk_pcs *mpcs = pcs_to_mtk_pcs(pcs);
111         unsigned int val;
112
113         if (!phy_interface_mode_is_8023z(interface))
114                 return;
115
116         /* SGMII force duplex setting */
117         regmap_read(mpcs->regmap, SGMSYS_SGMII_MODE, &val);
118         val &= ~SGMII_DUPLEX_FULL;
119         if (duplex == DUPLEX_FULL)
120                 val |= SGMII_DUPLEX_FULL;
121
122         regmap_write(mpcs->regmap, SGMSYS_SGMII_MODE, val);
123 }
124
125 static const struct phylink_pcs_ops mtk_pcs_ops = {
126         .pcs_config = mtk_pcs_config,
127         .pcs_an_restart = mtk_pcs_restart_an,
128         .pcs_link_up = mtk_pcs_link_up,
129 };
130
131 int mtk_sgmii_init(struct mtk_sgmii *ss, struct device_node *r, u32 ana_rgc3)
132 {
133         struct device_node *np;
134         int i;
135
136         for (i = 0; i < MTK_MAX_DEVS; i++) {
137                 np = of_parse_phandle(r, "mediatek,sgmiisys", i);
138                 if (!np)
139                         break;
140
141                 ss->pcs[i].ana_rgc3 = ana_rgc3;
142                 ss->pcs[i].regmap = syscon_node_to_regmap(np);
143                 of_node_put(np);
144                 if (IS_ERR(ss->pcs[i].regmap))
145                         return PTR_ERR(ss->pcs[i].regmap);
146
147                 ss->pcs[i].pcs.ops = &mtk_pcs_ops;
148         }
149
150         return 0;
151 }
152
153 struct phylink_pcs *mtk_sgmii_select_pcs(struct mtk_sgmii *ss, int id)
154 {
155         if (!ss->pcs[id].regmap)
156                 return NULL;
157
158         return &ss->pcs[id].pcs;
159 }
This page took 0.041974 seconds and 4 git commands to generate.