Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /* aQuantia Corporation Network Driver
3 : : * Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved
4 : : */
5 : :
6 : : #include "aq_phy.h"
7 : :
8 : 136 : bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw)
9 : : {
10 : 136 : int err = 0;
11 : 136 : u32 val;
12 : :
13 [ + + - + ]: 280 : err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw,
14 : : val, val == 0U, 10U, 100000U);
15 : :
16 : 0 : if (err < 0)
17 : 0 : return false;
18 : :
19 : : return true;
20 : : }
21 : :
22 : 68 : u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr)
23 : : {
24 : 68 : u16 phy_addr = aq_hw->phy_id << 5 | mmd;
25 : :
26 : : /* Set Address register. */
27 : 68 : hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
28 : : HW_ATL_MDIO_ADDRESS_SHIFT);
29 : : /* Send Address command. */
30 : 68 : hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
31 : : (3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
32 : : ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
33 : : HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
34 : :
35 : 68 : aq_mdio_busy_wait(aq_hw);
36 : :
37 : : /* Send Read command. */
38 : 68 : hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
39 : : (1 << HW_ATL_MDIO_OP_MODE_SHIFT) |
40 : : ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
41 : : HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
42 : : /* Read result. */
43 : 68 : aq_mdio_busy_wait(aq_hw);
44 : :
45 : 68 : return (u16)hw_atl_glb_mdio_iface5_get(aq_hw);
46 : : }
47 : :
48 : 0 : void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data)
49 : : {
50 : 0 : u16 phy_addr = aq_hw->phy_id << 5 | mmd;
51 : :
52 : : /* Set Address register. */
53 : 0 : hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) <<
54 : : HW_ATL_MDIO_ADDRESS_SHIFT);
55 : : /* Send Address command. */
56 : 0 : hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
57 : : (3 << HW_ATL_MDIO_OP_MODE_SHIFT) |
58 : : ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
59 : : HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
60 : :
61 : 0 : aq_mdio_busy_wait(aq_hw);
62 : :
63 : 0 : hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) <<
64 : : HW_ATL_MDIO_WRITE_DATA_SHIFT);
65 : : /* Send Write command. */
66 : 0 : hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK |
67 : : (2 << HW_ATL_MDIO_OP_MODE_SHIFT) |
68 : : ((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) <<
69 : : HW_ATL_MDIO_PHY_ADDRESS_SHIFT));
70 : :
71 : 0 : aq_mdio_busy_wait(aq_hw);
72 : 0 : }
73 : :
74 : 307 : u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address)
75 : : {
76 : 307 : int err = 0;
77 : 307 : u32 val;
78 : :
79 [ + + + + ]: 605639 : err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
80 : : val, val == 1U, 10U, 100000U);
81 : :
82 : 307 : if (err < 0) {
83 : 239 : err = 0xffff;
84 : 239 : goto err_exit;
85 : : }
86 : :
87 : 68 : err = aq_mdio_read_word(aq_hw, mmd, address);
88 : :
89 : 68 : hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
90 : :
91 : 307 : err_exit:
92 : 307 : return err;
93 : : }
94 : :
95 : 0 : void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data)
96 : : {
97 : 0 : int err = 0;
98 : 0 : u32 val;
99 : :
100 [ # # # # ]: 0 : err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw,
101 : : val, val == 1U, 10U, 100000U);
102 : 0 : if (err < 0)
103 : : return;
104 : :
105 : 0 : aq_mdio_write_word(aq_hw, mmd, address, data);
106 : 0 : hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO);
107 : : }
108 : :
109 : 33 : bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw)
110 : : {
111 : 33 : u16 val;
112 : :
113 [ + + ]: 256 : for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX;
114 : 223 : ++aq_hw->phy_id) {
115 : : /* PMA Standard Device Identifier 2: Address 1.3 */
116 : 251 : val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
117 : :
118 [ + + ]: 251 : if (val != 0xffff)
119 : : return true;
120 : : }
121 : :
122 : : return false;
123 : : }
124 : :
125 : 33 : bool aq_phy_init(struct aq_hw_s *aq_hw)
126 : : {
127 : 33 : u32 dev_id;
128 : :
129 [ + - ]: 33 : if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX)
130 [ + + ]: 33 : if (!aq_phy_init_phy_id(aq_hw))
131 : : return false;
132 : :
133 : : /* PMA Standard Device Identifier:
134 : : * Address 1.2 = MSW,
135 : : * Address 1.3 = LSW
136 : : */
137 : 28 : dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2);
138 : 28 : dev_id <<= 16;
139 : 28 : dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3);
140 : :
141 [ + + ]: 28 : if (dev_id == 0xffffffff) {
142 : 3 : aq_hw->phy_id = HW_ATL_PHY_ID_MAX;
143 : 3 : return false;
144 : : }
145 : :
146 : : return true;
147 : : }
|