Merge tag 'for-5.19-rc3-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[platform/kernel/linux-starfive.git] / drivers / net / ethernet / aquantia / atlantic / aq_phy.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Atlantic Network Driver
3  *
4  * Copyright (C) 2018-2019 aQuantia Corporation
5  * Copyright (C) 2019-2020 Marvell International Ltd.
6  */
7
8 #include "aq_phy.h"
9
10 #define HW_ATL_PTP_DISABLE_MSK  BIT(10)
11
12 bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw)
13 {
14         int err = 0;
15         u32 val;
16
17         err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw,
18                                         val, val == 0U, 10U, 100000U);
19
20         if (err < 0)
21                 return false;
22
23         return true;
24 }
25
26 u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr)
27 {
28         u16 phy_addr = aq_hw->phy_id << 5 | mmd;
29
30         /* Set Address register. */
31         hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
32                                    HW_ATL_MDIO_ADDRESS_SHIFT);
33         /* Send Address command. */
34         hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
35                                    (3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
36                                    ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
37                                     HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
38
39         aq_mdio_busy_wait(aq_hw);
40
41         /* Send Read command. */
42         hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
43                                    (1 << HW_ATL_MDIO_OP_MODE_SHIFT) |
44                                    ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
45                                     HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
46         /* Read result. */
47         aq_mdio_busy_wait(aq_hw);
48
49         return (u16)hw_atl_glb_mdio_iface5_get(aq_hw);
50 }
51
52 void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data)
53 {
54         u16 phy_addr = aq_hw->phy_id << 5 | mmd;
55
56         /* Set Address register. */
57         hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
58                                    HW_ATL_MDIO_ADDRESS_SHIFT);
59         /* Send Address command. */
60         hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
61                                    (3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
62                                    ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
63                                     HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
64
65         aq_mdio_busy_wait(aq_hw);
66
67         hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) <<
68                                    HW_ATL_MDIO_WRITE_DATA_SHIFT);
69         /* Send Write command. */
70         hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
71                                    (2 << HW_ATL_MDIO_OP_MODE_SHIFT) |
72                                    ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
73                                     HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
74
75         aq_mdio_busy_wait(aq_hw);
76 }
77
78 u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address)
79 {
80         int err = 0;
81         u32 val;
82
83         err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
84                                         val, val == 1U, 10U, 100000U);
85
86         if (err < 0) {
87                 err = 0xffff;
88                 goto err_exit;
89         }
90
91         err = aq_mdio_read_word(aq_hw, mmd, address);
92
93         hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
94
95 err_exit:
96         return err;
97 }
98
99 void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data)
100 {
101         int err = 0;
102         u32 val;
103
104         err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
105                                         val, val == 1U, 10U, 100000U);
106         if (err < 0)
107                 return;
108
109         aq_mdio_write_word(aq_hw, mmd, address, data);
110         hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
111 }
112
113 bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw)
114 {
115         u16 val;
116
117         for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX;
118              ++aq_hw->phy_id) {
119                 /* PMA Standard Device Identifier 2: Address 1.3 */
120                 val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
121
122                 if (val != 0xffff)
123                         return true;
124         }
125
126         return false;
127 }
128
129 bool aq_phy_init(struct aq_hw_s *aq_hw)
130 {
131         u32 dev_id;
132
133         if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX)
134                 if (!aq_phy_init_phy_id(aq_hw))
135                         return false;
136
137         /* PMA Standard Device Identifier:
138          * Address 1.2 = MSW,
139          * Address 1.3 = LSW
140          */
141         dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2);
142         dev_id <<= 16;
143         dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
144
145         if (dev_id == 0xffffffff) {
146                 aq_hw->phy_id = HW_ATL_PHY_ID_MAX;
147                 return false;
148         }
149
150         return true;
151 }
152
153 void aq_phy_disable_ptp(struct aq_hw_s *aq_hw)
154 {
155         static const u16 ptp_registers[] = {
156                 0x031e,
157                 0x031d,
158                 0x031c,
159                 0x031b,
160         };
161         u16 val;
162         int i;
163
164         for (i = 0; i < ARRAY_SIZE(ptp_registers); i++) {
165                 val = aq_phy_read_reg(aq_hw, MDIO_MMD_VEND1,
166                                       ptp_registers[i]);
167
168                 aq_phy_write_reg(aq_hw, MDIO_MMD_VEND1,
169                                  ptp_registers[i],
170                                  val & ~HW_ATL_PTP_DISABLE_MSK);
171         }
172 }