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>
This commit is contained in:
Dmitry Bezrukov 2019-10-22 09:53:45 +00:00 committed by David S. Miller
parent 84989af046
commit dbcd6806af
8 changed files with 399 additions and 0 deletions

View File

@ -25,6 +25,7 @@ atlantic-objs := aq_main.o \
aq_drvinfo.o \
aq_filters.o \
aq_ptp.o \
aq_phy.o \
hw_atl/hw_atl_a0.o \
hw_atl/hw_atl_b0.o \
hw_atl/hw_atl_utils.o \

View File

@ -140,6 +140,7 @@ struct aq_hw_s {
u32 rpc_tid;
struct hw_atl_utils_fw_rpc rpc;
s64 ptp_clk_offset;
u16 phy_id;
};
struct aq_ring_s;

View File

@ -12,6 +12,7 @@
#include "aq_hw.h"
#include "aq_pci_func.h"
#include "aq_main.h"
#include "aq_phy.h"
#include "aq_ptp.h"
#include "aq_filters.h"
@ -337,6 +338,11 @@ int aq_nic_init(struct aq_nic_s *self)
if (err < 0)
goto err_exit;
if (self->aq_nic_cfg.aq_hw_caps->media_type == AQ_HW_MEDIA_TYPE_TP) {
self->aq_hw->phy_id = HW_ATL_PHY_ID_MAX;
err = aq_phy_init(self->aq_hw);
}
for (i = 0U, aq_vec = self->aq_vec[0];
self->aq_vecs > i; ++i, aq_vec = self->aq_vec[i])
aq_vec_init(aq_vec, self->aq_hw_ops, self->aq_hw);

View File

@ -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;
}

View File

@ -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 */

View File

@ -1644,6 +1644,11 @@ u32 hw_atl_sem_ram_get(struct aq_hw_s *self)
return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_RAM);
}
u32 hw_atl_sem_mdio_get(struct aq_hw_s *self)
{
return hw_atl_reg_glb_cpu_sem_get(self, HW_ATL_FW_SM_MDIO);
}
u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp)
{
return aq_hw_read_reg(aq_hw,
@ -1659,3 +1664,60 @@ u32 hw_atl_scrpad25_get(struct aq_hw_s *self)
{
return hw_atl_scrpad_get(self, 0x18);
}
void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *aq_hw, u32 value)
{
aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1), value);
}
u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(1));
}
void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *aq_hw, u32 value)
{
aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2), value);
}
u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(2));
}
void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *aq_hw, u32 value)
{
aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3), value);
}
u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(3));
}
void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *aq_hw, u32 value)
{
aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4), value);
}
u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(4));
}
void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *aq_hw, u32 value)
{
aq_hw_write_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5), value);
}
u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg(aq_hw, HW_ATL_GLB_MDIO_IFACE_N_ADR(5));
}
u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw)
{
return aq_hw_read_reg_bit(aq_hw, HW_ATL_MDIO_BUSY_ADR,
HW_ATL_MDIO_BUSY_MSK,
HW_ATL_MDIO_BUSY_SHIFT);
}

View File

@ -767,9 +767,44 @@ void hw_atl_rpfl3l4_ipv6_src_addr_set(struct aq_hw_s *aq_hw, u8 location,
void hw_atl_rpfl3l4_ipv6_dest_addr_set(struct aq_hw_s *aq_hw, u8 location,
u32 *ipv6_dest);
/* set Global MDIO Interface 1 */
void hw_atl_glb_mdio_iface1_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 1 */
u32 hw_atl_glb_mdio_iface1_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 2 */
void hw_atl_glb_mdio_iface2_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 2 */
u32 hw_atl_glb_mdio_iface2_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 3 */
void hw_atl_glb_mdio_iface3_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 3 */
u32 hw_atl_glb_mdio_iface3_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 4 */
void hw_atl_glb_mdio_iface4_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 4 */
u32 hw_atl_glb_mdio_iface4_get(struct aq_hw_s *hw);
/* set Global MDIO Interface 5 */
void hw_atl_glb_mdio_iface5_set(struct aq_hw_s *hw, u32 value);
/* get Global MDIO Interface 5 */
u32 hw_atl_glb_mdio_iface5_get(struct aq_hw_s *hw);
u32 hw_atl_mdio_busy_get(struct aq_hw_s *aq_hw);
/* get global microprocessor ram semaphore */
u32 hw_atl_sem_ram_get(struct aq_hw_s *self);
/* get global microprocessor mdio semaphore */
u32 hw_atl_sem_mdio_get(struct aq_hw_s *self);
/* get global microprocessor scratch pad register */
u32 hw_atl_scrpad_get(struct aq_hw_s *aq_hw, u32 scratch_scp);

View File

@ -2594,6 +2594,121 @@
/* default value of bitfield uP Force Interrupt */
#define HW_ATL_MCP_UP_FORCE_INTERRUPT_DEFAULT 0x0
/* Preprocessor definitions for Global MDIO Interfaces
* Address: 0x00000280 + 0x4 * Number of interface
*/
#define HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN 0x00000280u
#define HW_ATL_GLB_MDIO_IFACE_N_ADR(number) \
(HW_ATL_GLB_MDIO_IFACE_ADDR_BEGIN + (((number) - 1) * 0x4))
/* MIF MDIO Busy Bitfield Definitions
* Preprocessor definitions for the bitfield "MDIO Busy".
* PORT="mdio_pif_busy_o"
*/
/* Register address for bitfield MDIO Busy */
#define HW_ATL_MDIO_BUSY_ADR 0x00000284
/* Bitmask for bitfield MDIO Busy */
#define HW_ATL_MDIO_BUSY_MSK 0x80000000
/* Inverted bitmask for bitfield MDIO Busy */
#define HW_ATL_MDIO_BUSY_MSKN 0x7FFFFFFF
/* Lower bit position of bitfield MDIO Busy */
#define HW_ATL_MDIO_BUSY_SHIFT 31
/* Width of bitfield MDIO Busy */
#define HW_ATL_MDIO_BUSY_WIDTH 1
/* MIF MDIO Execute Operation Bitfield Definitions
* Preprocessor definitions for the bitfield "MDIO Execute Operation".
* PORT="pif_mdio_op_start_i"
*/
/* Register address for bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_ADR 0x00000284
/* Bitmask for bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_MSK 0x00008000
/* Inverted bitmask for bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_MSKN 0xFFFF7FFF
/* Lower bit position of bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_SHIFT 15
/* Width of bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_WIDTH 1
/* Default value of bitfield MDIO Execute Operation */
#define HW_ATL_MDIO_EXECUTE_OPERATION_DEFAULT 0x0
/* MIF Op Mode [1:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "Op Mode [1:0]".
* PORT="pif_mdio_mode_i[1:0]"
*/
/* Register address for bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_ADR 0x00000284
/* Bitmask for bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_MSK 0x00003000
/* Inverted bitmask for bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_MSKN 0xFFFFCFFF
/* Lower bit position of bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_SHIFT 12
/* Width of bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_WIDTH 2
/* Default value of bitfield Op Mode [1:0] */
#define HW_ATL_MDIO_OP_MODE_DEFAULT 0x0
/* MIF PHY address Bitfield Definitions
* Preprocessor definitions for the bitfield "PHY address".
* PORT="pif_mdio_phy_addr_i[9:0]"
*/
/* Register address for bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_ADR 0x00000284
/* Bitmask for bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_MSK 0x000003FF
/* Inverted bitmask for bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_MSKN 0xFFFFFC00
/* Lower bit position of bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_SHIFT 0
/* Width of bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_WIDTH 10
/* Default value of bitfield PHY address */
#define HW_ATL_MDIO_PHY_ADDRESS_DEFAULT 0x0
/* MIF MDIO WriteData [F:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "MDIO WriteData [F:0]".
* PORT="pif_mdio_wdata_i[15:0]"
*/
/* Register address for bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_ADR 0x00000288
/* Bitmask for bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_MSK 0x0000FFFF
/* Inverted bitmask for bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_MSKN 0xFFFF0000
/* Lower bit position of bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_SHIFT 0
/* Width of bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_WIDTH 16
/* Default value of bitfield MDIO WriteData [F:0] */
#define HW_ATL_MDIO_WRITE_DATA_DEFAULT 0x0
/* MIF MDIO Address [F:0] Bitfield Definitions
* Preprocessor definitions for the bitfield "MDIO Address [F:0]".
* PORT="pif_mdio_addr_i[15:0]"
*/
/* Register address for bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_ADR 0x0000028C
/* Bitmask for bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_MSK 0x0000FFFF
/* Inverted bitmask for bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_MSKN 0xFFFF0000
/* Lower bit position of bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_SHIFT 0
/* Width of bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_WIDTH 16
/* Default value of bitfield MDIO Address [F:0] */
#define HW_ATL_MDIO_ADDRESS_DEFAULT 0x0
#define HW_ATL_FW_SM_MDIO 0x0U
#define HW_ATL_FW_SM_RAM 0x2U
#endif /* HW_ATL_LLH_INTERNAL_H */