-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: aquantia: add support for Phy access
GPIO PIN control and access is done by direct phy manipulation. Here we add an aq_phy module which is able to access phy registers via MDIO access mailbox. Access is controlled via HW semaphore. Co-developed-by: Nikita Danilov <nikita.danilov@aquantia.com> Signed-off-by: Nikita Danilov <nikita.danilov@aquantia.com> Signed-off-by: Dmitry Bezrukov <dmitry.bezrukov@aquantia.com> Signed-off-by: Igor Russkikh <igor.russkikh@aquantia.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Dmitry Bezrukov
authored and
David S. Miller
committed
Oct 24, 2019
1 parent
84989af
commit dbcd680
Showing
8 changed files
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
/* aQuantia Corporation Network Driver | ||
* Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved | ||
*/ | ||
|
||
#include "aq_phy.h" | ||
|
||
bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw) | ||
{ | ||
int err = 0; | ||
u32 val; | ||
|
||
err = readx_poll_timeout_atomic(hw_atl_mdio_busy_get, aq_hw, | ||
val, val == 0U, 10U, 100000U); | ||
|
||
if (err < 0) | ||
return false; | ||
|
||
return true; | ||
} | ||
|
||
u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr) | ||
{ | ||
u16 phy_addr = aq_hw->phy_id << 5 | mmd; | ||
|
||
/* Set Address register. */ | ||
hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << | ||
HW_ATL_MDIO_ADDRESS_SHIFT); | ||
/* Send Address command. */ | ||
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | | ||
(3 << HW_ATL_MDIO_OP_MODE_SHIFT) | | ||
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << | ||
HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); | ||
|
||
aq_mdio_busy_wait(aq_hw); | ||
|
||
/* Send Read command. */ | ||
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | | ||
(1 << HW_ATL_MDIO_OP_MODE_SHIFT) | | ||
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << | ||
HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); | ||
/* Read result. */ | ||
aq_mdio_busy_wait(aq_hw); | ||
|
||
return (u16)hw_atl_glb_mdio_iface5_get(aq_hw); | ||
} | ||
|
||
void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data) | ||
{ | ||
u16 phy_addr = aq_hw->phy_id << 5 | mmd; | ||
|
||
/* Set Address register. */ | ||
hw_atl_glb_mdio_iface4_set(aq_hw, (addr & HW_ATL_MDIO_ADDRESS_MSK) << | ||
HW_ATL_MDIO_ADDRESS_SHIFT); | ||
/* Send Address command. */ | ||
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | | ||
(3 << HW_ATL_MDIO_OP_MODE_SHIFT) | | ||
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << | ||
HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); | ||
|
||
aq_mdio_busy_wait(aq_hw); | ||
|
||
hw_atl_glb_mdio_iface3_set(aq_hw, (data & HW_ATL_MDIO_WRITE_DATA_MSK) << | ||
HW_ATL_MDIO_WRITE_DATA_SHIFT); | ||
/* Send Write command. */ | ||
hw_atl_glb_mdio_iface2_set(aq_hw, HW_ATL_MDIO_EXECUTE_OPERATION_MSK | | ||
(2 << HW_ATL_MDIO_OP_MODE_SHIFT) | | ||
((phy_addr & HW_ATL_MDIO_PHY_ADDRESS_MSK) << | ||
HW_ATL_MDIO_PHY_ADDRESS_SHIFT)); | ||
|
||
aq_mdio_busy_wait(aq_hw); | ||
} | ||
|
||
u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address) | ||
{ | ||
int err = 0; | ||
u32 val; | ||
|
||
err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, | ||
val, val == 1U, 10U, 100000U); | ||
|
||
if (err < 0) { | ||
err = 0xffff; | ||
goto err_exit; | ||
} | ||
|
||
err = aq_mdio_read_word(aq_hw, mmd, address); | ||
|
||
hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); | ||
|
||
err_exit: | ||
return err; | ||
} | ||
|
||
void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data) | ||
{ | ||
int err = 0; | ||
u32 val; | ||
|
||
err = readx_poll_timeout_atomic(hw_atl_sem_mdio_get, aq_hw, | ||
val, val == 1U, 10U, 100000U); | ||
if (err < 0) | ||
return; | ||
|
||
aq_mdio_write_word(aq_hw, mmd, address, data); | ||
hw_atl_reg_glb_cpu_sem_set(aq_hw, 1U, HW_ATL_FW_SM_MDIO); | ||
} | ||
|
||
bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw) | ||
{ | ||
u16 val; | ||
|
||
for (aq_hw->phy_id = 0; aq_hw->phy_id < HW_ATL_PHY_ID_MAX; | ||
++aq_hw->phy_id) { | ||
/* PMA Standard Device Identifier 2: Address 1.3 */ | ||
val = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); | ||
|
||
if (val != 0xffff) | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool aq_phy_init(struct aq_hw_s *aq_hw) | ||
{ | ||
u32 dev_id; | ||
|
||
if (aq_hw->phy_id == HW_ATL_PHY_ID_MAX) | ||
if (!aq_phy_init_phy_id(aq_hw)) | ||
return false; | ||
|
||
/* PMA Standard Device Identifier: | ||
* Address 1.2 = MSW, | ||
* Address 1.3 = LSW | ||
*/ | ||
dev_id = aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 2); | ||
dev_id <<= 16; | ||
dev_id |= aq_phy_read_reg(aq_hw, MDIO_MMD_PMAPMD, 3); | ||
|
||
if (dev_id == 0xffffffff) { | ||
aq_hw->phy_id = HW_ATL_PHY_ID_MAX; | ||
return false; | ||
} | ||
|
||
return true; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
/* aQuantia Corporation Network Driver | ||
* Copyright (C) 2018-2019 aQuantia Corporation. All rights reserved | ||
*/ | ||
|
||
#ifndef AQ_PHY_H | ||
#define AQ_PHY_H | ||
|
||
#include <linux/mdio.h> | ||
|
||
#include "hw_atl/hw_atl_llh.h" | ||
#include "hw_atl/hw_atl_llh_internal.h" | ||
#include "aq_hw_utils.h" | ||
#include "aq_hw.h" | ||
|
||
#define HW_ATL_PHY_ID_MAX 32U | ||
|
||
bool aq_mdio_busy_wait(struct aq_hw_s *aq_hw); | ||
|
||
u16 aq_mdio_read_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr); | ||
|
||
void aq_mdio_write_word(struct aq_hw_s *aq_hw, u16 mmd, u16 addr, u16 data); | ||
|
||
u16 aq_phy_read_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address); | ||
|
||
void aq_phy_write_reg(struct aq_hw_s *aq_hw, u16 mmd, u16 address, u16 data); | ||
|
||
bool aq_phy_init_phy_id(struct aq_hw_s *aq_hw); | ||
|
||
bool aq_phy_init(struct aq_hw_s *aq_hw); | ||
|
||
#endif /* AQ_PHY_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.