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