mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-05-05 12:46:14 +02:00
Merge tag 'net-20260312' of https://source.denx.de/u-boot/custodians/u-boot-net into next
Pull request net-20260312.
net:
- Move network PHY under NETDEVICES
- s/DM_CLK/CLK/ in HIFEMAC_{ETH,MDIO}
- Add support for Airoha AN8811HB PHY
- airoha: PCS and MDIO support for Airoha AN7581 SoC
net-lwip:
- Fix issue when TFTP blocksize is >8192
- Adjust PBUF_POOL_SIZE/IP_REASS_MAX_PBUFS for better performance and
resource usage.
- Enable mii command for NET_LWIP
This commit is contained in:
commit
6dc75d440d
@ -35,6 +35,48 @@
|
||||
reg = <0x0 0x1fa20000 0x0 0x388>;
|
||||
};
|
||||
|
||||
pon_pcs: pcs@1fa08000 {
|
||||
compatible = "airoha,an7581-pcs-pon";
|
||||
reg = <0x0 0x1fa08000 0x0 0x1000>,
|
||||
<0x0 0x1fa80000 0x0 0x60>,
|
||||
<0x0 0x1fa80a00 0x0 0x164>,
|
||||
<0x0 0x1fa84000 0x0 0x450>,
|
||||
<0x0 0x1fa85900 0x0 0x338>,
|
||||
<0x0 0x1fa86000 0x0 0x300>,
|
||||
<0x0 0x1fa8a000 0x0 0x1000>,
|
||||
<0x0 0x1fa8b000 0x0 0x1000>;
|
||||
reg-names = "xfi_mac", "hsgmii_an", "hsgmii_pcs",
|
||||
"multi_sgmii", "usxgmii",
|
||||
"hsgmii_rate_adp", "xfi_ana", "xfi_pma";
|
||||
|
||||
resets = <&scuclk EN7581_XPON_MAC_RST>,
|
||||
<&scuclk EN7581_XPON_PHY_RST>;
|
||||
reset-names = "mac", "phy";
|
||||
|
||||
airoha,scu = <&scuclk>;
|
||||
};
|
||||
|
||||
eth_pcs: pcs@1fa09000 {
|
||||
compatible = "airoha,an7581-pcs-eth";
|
||||
reg = <0x0 0x1fa09000 0x0 0x1000>,
|
||||
<0x0 0x1fa70000 0x0 0x60>,
|
||||
<0x0 0x1fa70a00 0x0 0x164>,
|
||||
<0x0 0x1fa74000 0x0 0x450>,
|
||||
<0x0 0x1fa75900 0x0 0x338>,
|
||||
<0x0 0x1fa76000 0x0 0x300>,
|
||||
<0x0 0x1fa7a000 0x0 0x1000>,
|
||||
<0x0 0x1fa7b000 0x0 0x1000>;
|
||||
reg-names = "xfi_mac", "hsgmii_an", "hsgmii_pcs",
|
||||
"multi_sgmii", "usxgmii",
|
||||
"hsgmii_rate_adp", "xfi_ana", "xfi_pma";
|
||||
|
||||
resets = <&scuclk EN7581_XSI_MAC_RST>,
|
||||
<&scuclk EN7581_XSI_PHY_RST>;
|
||||
reset-names = "mac", "phy";
|
||||
|
||||
airoha,scu = <&scuclk>;
|
||||
};
|
||||
|
||||
eth: ethernet@1fb50000 {
|
||||
compatible = "airoha,en7581-eth";
|
||||
reg = <0 0x1fb50000 0 0x2600>,
|
||||
@ -52,6 +94,35 @@
|
||||
reset-names = "fe", "pdma", "qdma",
|
||||
"hsi0-mac", "hsi1-mac", "hsi-mac",
|
||||
"xfp-mac";
|
||||
|
||||
gdm1: ethernet@1 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <1>;
|
||||
phy-mode = "internal";
|
||||
status = "disabled";
|
||||
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
pause;
|
||||
};
|
||||
};
|
||||
|
||||
gdm2: ethernet@2 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <2>;
|
||||
pcs = <&pon_pcs>;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
gdm4: ethernet@4 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <4>;
|
||||
pcs = <ð_pcs>;
|
||||
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
switch: switch@1fb58000 {
|
||||
|
||||
@ -9,3 +9,7 @@
|
||||
};
|
||||
|
||||
#include "en7523-u-boot.dtsi"
|
||||
|
||||
&gdm1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
@ -37,6 +37,19 @@
|
||||
<&scu EN7523_HSI_MAC_RST>;
|
||||
reset-names = "fe", "pdma", "qdma",
|
||||
"hsi0-mac", "hsi1-mac", "hsi-mac";
|
||||
|
||||
gdm1: ethernet@1 {
|
||||
compatible = "airoha,eth-mac";
|
||||
reg = <1>;
|
||||
phy-mode = "internal";
|
||||
status = "disabled";
|
||||
|
||||
fixed-link {
|
||||
speed = <10000>;
|
||||
full-duplex;
|
||||
pause;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
switch: switch@1fb58000 {
|
||||
|
||||
@ -9,3 +9,21 @@
|
||||
};
|
||||
|
||||
#include "an7581-u-boot.dtsi"
|
||||
|
||||
&gdm1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&gdm2 {
|
||||
status = "okay";
|
||||
|
||||
managed = "in-band-status";
|
||||
phy-mode = "10gbase-r";
|
||||
};
|
||||
|
||||
&gdm4 {
|
||||
status = "okay";
|
||||
|
||||
managed = "in-band-status";
|
||||
phy-mode = "usxgmii";
|
||||
};
|
||||
|
||||
@ -434,7 +434,7 @@ config BOOT_DEFAULTS_CMDS
|
||||
select CMD_PXE if CMD_NET
|
||||
select CMD_BOOTI if ARM64
|
||||
select CMD_BOOTZ if ARM && !ARM64
|
||||
imply CMD_MII if NET
|
||||
imply CMD_MII if NET || NET_LWIP
|
||||
|
||||
config BOOT_DEFAULTS
|
||||
bool # Common defaults for standard boot and distroboot
|
||||
|
||||
@ -68,6 +68,8 @@ CONFIG_SPI_FLASH_WINBOND=y
|
||||
CONFIG_SPI_FLASH_MTD=y
|
||||
CONFIG_DM_MDIO=y
|
||||
CONFIG_AIROHA_ETH=y
|
||||
CONFIG_PCS_AIROHA_AN7581=y
|
||||
CONFIG_PHYLIB=y
|
||||
CONFIG_PHY=y
|
||||
CONFIG_PINCTRL=y
|
||||
CONFIG_PINCONF=y
|
||||
|
||||
@ -1,7 +1,3 @@
|
||||
source "drivers/net/phy/Kconfig"
|
||||
source "drivers/net/pfe_eth/Kconfig"
|
||||
source "drivers/net/fsl-mc/Kconfig"
|
||||
|
||||
config ETH
|
||||
def_bool y
|
||||
|
||||
@ -121,11 +117,15 @@ config AG7XXX
|
||||
This driver supports the Atheros AG7xxx Ethernet MAC. This MAC is
|
||||
present in the Atheros AR7xxx, AR9xxx and QCA9xxx MIPS chips.
|
||||
|
||||
source "drivers/net/airoha/Kconfig"
|
||||
|
||||
config AIROHA_ETH
|
||||
bool "Airoha Ethernet QDMA Driver"
|
||||
depends on ARCH_AIROHA
|
||||
select MISC
|
||||
select PHYLIB
|
||||
select DEVRES
|
||||
select DM_ETH_PHY
|
||||
select DM_RESET
|
||||
select MDIO_MT7531_MMIO
|
||||
help
|
||||
@ -979,7 +979,7 @@ source "drivers/net/mtk_eth/Kconfig"
|
||||
|
||||
config HIFEMAC_ETH
|
||||
bool "HiSilicon Fast Ethernet Controller"
|
||||
select DM_CLK
|
||||
select CLK
|
||||
select DM_RESET
|
||||
select PHYLIB
|
||||
help
|
||||
@ -989,7 +989,7 @@ config HIFEMAC_ETH
|
||||
config HIFEMAC_MDIO
|
||||
bool "HiSilicon Fast Ethernet Controller MDIO interface"
|
||||
depends on DM_MDIO
|
||||
select DM_CLK
|
||||
select CLK
|
||||
help
|
||||
This driver supports the internal MDIO interface of HIFEMAC
|
||||
Ethernet controller.
|
||||
@ -1098,4 +1098,8 @@ config MDIO_MUX_MESON_GXL
|
||||
This driver is used for the MDIO mux found on the Amlogic GXL & compatible
|
||||
SoCs.
|
||||
|
||||
source "drivers/net/phy/Kconfig"
|
||||
source "drivers/net/pfe_eth/Kconfig"
|
||||
source "drivers/net/fsl-mc/Kconfig"
|
||||
|
||||
endif # NETDEVICES
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
|
||||
|
||||
obj-$(CONFIG_AG7XXX) += ag7xxx.o
|
||||
obj-y += airoha/
|
||||
obj-$(CONFIG_AIROHA_ETH) += airoha_eth.o
|
||||
obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
|
||||
obj-$(CONFIG_ASPEED_MDIO) += aspeed_mdio.o
|
||||
|
||||
12
drivers/net/airoha/Kconfig
Normal file
12
drivers/net/airoha/Kconfig
Normal file
@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
config PCS_AIROHA
|
||||
bool
|
||||
select MISC
|
||||
|
||||
config PCS_AIROHA_AN7581
|
||||
bool "Airoha AN7581 PCS driver"
|
||||
select PCS_AIROHA
|
||||
help
|
||||
This module provides helper to phylink for managing the Airoha
|
||||
AN7581 PCS for SoC Ethernet and PON SERDES.
|
||||
4
drivers/net/airoha/Makefile
Normal file
4
drivers/net/airoha/Makefile
Normal file
@ -0,0 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
obj-$(CONFIG_PCS_AIROHA) += pcs-airoha-common.o
|
||||
obj-$(CONFIG_PCS_AIROHA_AN7581) += pcs-an7581.o
|
||||
827
drivers/net/airoha/pcs-airoha-common.c
Normal file
827
drivers/net/airoha/pcs-airoha-common.c
Normal file
@ -0,0 +1,827 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 AIROHA Inc
|
||||
* Author: Christian Marangi <ansuelsmth@gmail.com>
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <dm/devres.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <net.h>
|
||||
#include <regmap.h>
|
||||
#include <reset.h>
|
||||
#include <syscon.h>
|
||||
|
||||
#include "pcs-airoha.h"
|
||||
|
||||
static void airoha_pcs_setup_scu_eth(struct airoha_pcs_priv *priv,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
u32 xsi_sel;
|
||||
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
xsi_sel = AIROHA_SCU_ETH_XSI_HSGMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
default:
|
||||
xsi_sel = AIROHA_SCU_ETH_XSI_USXGMII;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->scu, AIROHA_SCU_SSR3,
|
||||
AIROHA_SCU_ETH_XSI_SEL,
|
||||
xsi_sel);
|
||||
}
|
||||
|
||||
static void airoha_pcs_setup_scu_pon(struct airoha_pcs_priv *priv,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
u32 xsi_sel, wan_sel;
|
||||
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
wan_sel = AIROHA_SCU_WAN_SEL_SGMII;
|
||||
xsi_sel = AIROHA_SCU_PON_XSI_HSGMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
wan_sel = AIROHA_SCU_WAN_SEL_HSGMII;
|
||||
xsi_sel = AIROHA_SCU_PON_XSI_HSGMII;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
default:
|
||||
wan_sel = AIROHA_SCU_WAN_SEL_USXGMII;
|
||||
xsi_sel = AIROHA_SCU_PON_XSI_USXGMII;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->scu, AIROHA_SCU_SSTR,
|
||||
AIROHA_SCU_PON_XSI_SEL,
|
||||
xsi_sel);
|
||||
|
||||
regmap_update_bits(priv->scu, AIROHA_SCU_WAN_CONF,
|
||||
AIROHA_SCU_WAN_SEL,
|
||||
wan_sel);
|
||||
}
|
||||
|
||||
static int airoha_pcs_setup_scu(struct airoha_pcs_priv *priv,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
const struct airoha_pcs_match_data *data = priv->data;
|
||||
int ret;
|
||||
|
||||
if (priv->xfi_rst) {
|
||||
ret = reset_assert(priv->xfi_rst);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (data->port_type) {
|
||||
case AIROHA_PCS_ETH:
|
||||
airoha_pcs_setup_scu_eth(priv, interface);
|
||||
break;
|
||||
case AIROHA_PCS_PON:
|
||||
airoha_pcs_setup_scu_pon(priv, interface);
|
||||
break;
|
||||
}
|
||||
|
||||
if (priv->xfi_rst) {
|
||||
ret = reset_deassert(priv->xfi_rst);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* TODO better handle reset from MAC */
|
||||
ret = reset_assert_bulk(&priv->rsts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_deassert_bulk(&priv->rsts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void airoha_pcs_init_usxgmii(struct airoha_pcs_priv *priv)
|
||||
{
|
||||
const struct airoha_pcs_match_data *data = priv->data;
|
||||
|
||||
regmap_set_bits(priv->multi_sgmii, AIROHA_PCS_MULTI_SGMII_MSG_RX_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_XFI_SEL);
|
||||
|
||||
/* Disable Hibernation */
|
||||
if (data->hibernation_workaround)
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTROL_1,
|
||||
AIROHA_PCS_USXGMII_SPEED_SEL_H);
|
||||
|
||||
/* FIXME: wait Airoha */
|
||||
/* Avoid PCS sending garbage to MAC in some HW revision (E0) */
|
||||
if (data->usxgmii_ber_time_fixup)
|
||||
regmap_write(priv->usxgmii_pcs, AIROHA_PCS_USGMII_VENDOR_DEFINE_116, 0);
|
||||
|
||||
if (data->usxgmii_rx_gb_out_vld_tweak)
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AN7583_PCS_USXGMII_RTL_MODIFIED,
|
||||
AIROHA_PCS_USXGMII_MODIFIED_RX_GB_OUT_VLD);
|
||||
}
|
||||
|
||||
static void airoha_pcs_init_hsgmii(struct airoha_pcs_priv *priv)
|
||||
{
|
||||
regmap_clear_bits(priv->multi_sgmii, AIROHA_PCS_MULTI_SGMII_MSG_RX_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_XFI_SEL);
|
||||
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_1,
|
||||
AIROHA_PCS_TBI_10B_MODE);
|
||||
}
|
||||
|
||||
static void airoha_pcs_init_sgmii(struct airoha_pcs_priv *priv)
|
||||
{
|
||||
regmap_clear_bits(priv->multi_sgmii, AIROHA_PCS_MULTI_SGMII_MSG_RX_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_XFI_SEL);
|
||||
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_1,
|
||||
AIROHA_PCS_TBI_10B_MODE);
|
||||
|
||||
regmap_update_bits(priv->hsgmii_rate_adp, AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_6,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_DOUT_L,
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_DOUT_L, 0x07070707));
|
||||
|
||||
regmap_update_bits(priv->hsgmii_rate_adp, AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_8,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_DOUT_C,
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_DOUT_C, 0xff));
|
||||
}
|
||||
|
||||
static void airoha_pcs_init(struct airoha_pcs_priv *priv,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
airoha_pcs_init_sgmii(priv);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
airoha_pcs_init_hsgmii(priv);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
airoha_pcs_init_usxgmii(priv);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void airoha_pcs_interrupt_init_sgmii(struct airoha_pcs_priv *priv)
|
||||
{
|
||||
/* Disable every interrupt */
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_HSGMII_PCS_HSGMII_MODE_INTERRUPT,
|
||||
AIROHA_PCS_HSGMII_MODE2_REMOVE_FAULT_OCCUR_INT |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_CL37_TIMERDONE_INT |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_MIS_INT |
|
||||
AIROHA_PCS_HSGMII_MODE2_RX_SYN_DONE_INT |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_DONE_INT);
|
||||
|
||||
/* Clear interrupt */
|
||||
regmap_set_bits(priv->usxgmii_pcs, AIROHA_PCS_HSGMII_PCS_HSGMII_MODE_INTERRUPT,
|
||||
AIROHA_PCS_HSGMII_MODE2_REMOVE_FAULT_OCCUR_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_CL37_TIMERDONE_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_MIS_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_RX_SYN_DONE_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_DONE_INT_CLEAR);
|
||||
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_HSGMII_PCS_HSGMII_MODE_INTERRUPT,
|
||||
AIROHA_PCS_HSGMII_MODE2_REMOVE_FAULT_OCCUR_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_CL37_TIMERDONE_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_MIS_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_RX_SYN_DONE_INT_CLEAR |
|
||||
AIROHA_PCS_HSGMII_MODE2_AN_DONE_INT_CLEAR);
|
||||
}
|
||||
|
||||
static void airoha_pcs_interrupt_init_usxgmii(struct airoha_pcs_priv *priv)
|
||||
{
|
||||
/* Disable every Interrupt */
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTRL_0,
|
||||
AIROHA_PCS_USXGMII_T_TYPE_T_INT_EN |
|
||||
AIROHA_PCS_USXGMII_T_TYPE_D_INT_EN |
|
||||
AIROHA_PCS_USXGMII_T_TYPE_C_INT_EN |
|
||||
AIROHA_PCS_USXGMII_T_TYPE_S_INT_EN);
|
||||
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTRL_1,
|
||||
AIROHA_PCS_USXGMII_R_TYPE_C_INT_EN |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_S_INT_EN |
|
||||
AIROHA_PCS_USXGMII_TXPCS_FSM_ENC_ERR_INT_EN |
|
||||
AIROHA_PCS_USXGMII_T_TYPE_E_INT_EN);
|
||||
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTRL_2,
|
||||
AIROHA_PCS_USXGMII_RPCS_FSM_DEC_ERR_INT_EN |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_E_INT_EN |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_T_INT_EN |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_D_INT_EN);
|
||||
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTRL_3,
|
||||
AIROHA_PCS_USXGMII_FAIL_SYNC_XOR_ST_INT_EN |
|
||||
AIROHA_PCS_USXGMII_RX_BLOCK_LOCK_ST_INT_EN |
|
||||
AIROHA_PCS_USXGMII_LINK_UP_ST_INT_EN |
|
||||
AIROHA_PCS_USXGMII_HI_BER_ST_INT_EN);
|
||||
|
||||
regmap_clear_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_CTRL_4,
|
||||
AIROHA_PCS_USXGMII_LINK_DOWN_ST_INT_EN);
|
||||
|
||||
/* Clear any pending interrupt */
|
||||
regmap_set_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_INT_STA_2,
|
||||
AIROHA_PCS_USXGMII_RPCS_FSM_DEC_ERR_INT |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_E_INT |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_T_INT |
|
||||
AIROHA_PCS_USXGMII_R_TYPE_D_INT);
|
||||
|
||||
regmap_set_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_INT_STA_3,
|
||||
AIROHA_PCS_USXGMII_FAIL_SYNC_XOR_ST_INT |
|
||||
AIROHA_PCS_USXGMII_RX_BLOCK_LOCK_ST_INT |
|
||||
AIROHA_PCS_USXGMII_LINK_UP_ST_INT |
|
||||
AIROHA_PCS_USXGMII_HI_BER_ST_INT);
|
||||
|
||||
regmap_set_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_INT_STA_4,
|
||||
AIROHA_PCS_USXGMII_LINK_DOWN_ST_INT);
|
||||
|
||||
/* Interrupt saddly seems to be not weel supported for Link Down.
|
||||
* PCS Poll is a must to correctly read and react on Cable Deatch
|
||||
* as only cable attach interrupt are fired and Link Down interrupt
|
||||
* are fired only in special case like AN restart.
|
||||
*/
|
||||
}
|
||||
|
||||
static void airoha_pcs_interrupt_init(struct airoha_pcs_priv *priv,
|
||||
phy_interface_t interface)
|
||||
{
|
||||
switch (interface) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
return airoha_pcs_interrupt_init_sgmii(priv);
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
return airoha_pcs_interrupt_init_usxgmii(priv);
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int airoha_pcs_config(struct udevice *dev, bool neg_mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
bool permit_pause_to_mac)
|
||||
{
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
const struct airoha_pcs_match_data *data;
|
||||
u32 rate_adapt;
|
||||
int ret;
|
||||
|
||||
priv->interface = interface;
|
||||
data = priv->data;
|
||||
|
||||
/* Apply Analog and Digital configuration for PCS */
|
||||
if (data->bringup) {
|
||||
ret = data->bringup(priv, interface);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Set final configuration for various modes */
|
||||
airoha_pcs_init(priv, interface);
|
||||
|
||||
/* Configure Interrupt for various modes */
|
||||
airoha_pcs_interrupt_init(priv, interface);
|
||||
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADAPT_RX_EN |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_TX_EN;
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII)
|
||||
rate_adapt |= AIROHA_PCS_HSGMII_RATE_ADAPT_RX_BYPASS |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_TX_BYPASS;
|
||||
|
||||
/* AN Auto Settings (Rate Adaptation) */
|
||||
regmap_update_bits(priv->hsgmii_rate_adp, AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_BYPASS |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_TX_BYPASS |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_EN |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_TX_EN, rate_adapt);
|
||||
|
||||
/* FIXME: With an attached Aeonsemi PHY, AN is needed
|
||||
* even with no inband.
|
||||
*/
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII ||
|
||||
interface == PHY_INTERFACE_MODE_10GBASER) {
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII)
|
||||
regmap_set_bits(priv->usxgmii_pcs,
|
||||
AIROHA_PCS_USXGMII_PCS_AN_CONTROL_0,
|
||||
AIROHA_PCS_USXGMII_AN_ENABLE);
|
||||
else
|
||||
regmap_clear_bits(priv->usxgmii_pcs,
|
||||
AIROHA_PCS_USXGMII_PCS_AN_CONTROL_0,
|
||||
AIROHA_PCS_USXGMII_AN_ENABLE);
|
||||
|
||||
if (data->usxgmii_xfi_mode_sel && neg_mode)
|
||||
regmap_set_bits(priv->usxgmii_pcs,
|
||||
AIROHA_PCS_USXGMII_PCS_AN_CONTROL_7,
|
||||
AIROHA_PCS_USXGMII_XFI_MODE_TX_SEL |
|
||||
AIROHA_PCS_USXGMII_XFI_MODE_RX_SEL);
|
||||
}
|
||||
|
||||
/* Clear any force bit that my be set by bootloader */
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII ||
|
||||
interface == PHY_INTERFACE_MODE_1000BASEX ||
|
||||
interface == PHY_INTERFACE_MODE_2500BASEX) {
|
||||
regmap_clear_bits(priv->multi_sgmii, AIROHA_PCS_MULTI_SGMII_SGMII_STS_CTRL_0,
|
||||
AIROHA_PCS_LINK_MODE_P0 |
|
||||
AIROHA_PCS_FORCE_SPD_MODE_P0 |
|
||||
AIROHA_PCS_FORCE_LINKDOWN_P0 |
|
||||
AIROHA_PCS_FORCE_LINKUP_P0);
|
||||
}
|
||||
|
||||
/* Toggle Rate Adaption for SGMII/HSGMII mode */ /* TODO */
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII ||
|
||||
interface == PHY_INTERFACE_MODE_1000BASEX ||
|
||||
interface == PHY_INTERFACE_MODE_2500BASEX) {
|
||||
if (neg_mode)
|
||||
regmap_clear_bits(priv->hsgmii_rate_adp,
|
||||
AIROHA_PCS_HSGMII_RATE_ADP_P0_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_P0_DIS_MII_MODE);
|
||||
else
|
||||
regmap_set_bits(priv->hsgmii_rate_adp,
|
||||
AIROHA_PCS_HSGMII_RATE_ADP_P0_CTRL_0,
|
||||
AIROHA_PCS_HSGMII_P0_DIS_MII_MODE);
|
||||
}
|
||||
|
||||
/* Setup SGMII AN and advertisement in DEV_ABILITY */ /* TODO */
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
if (neg_mode) {
|
||||
int advertise = 0x1;
|
||||
|
||||
regmap_update_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_4,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_DEV_ABILITY,
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_AN_SGMII_DEV_ABILITY,
|
||||
advertise));
|
||||
|
||||
regmap_set_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_0,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_RA_ENABLE);
|
||||
} else {
|
||||
regmap_clear_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_0,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_RA_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_2500BASEX) {
|
||||
regmap_clear_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_0,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_RA_ENABLE);
|
||||
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_6,
|
||||
AIROHA_PCS_HSGMII_PCS_TX_ENABLE);
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII ||
|
||||
interface == PHY_INTERFACE_MODE_1000BASEX) {
|
||||
u32 if_mode = AIROHA_PCS_HSGMII_AN_SIDEBAND_EN;
|
||||
|
||||
/* Toggle SGMII or 1000base-x mode */
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII)
|
||||
if_mode |= AIROHA_PCS_HSGMII_AN_SGMII_EN;
|
||||
|
||||
if (neg_mode)
|
||||
regmap_set_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_13,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_REMOTE_FAULT_DIS);
|
||||
else
|
||||
regmap_clear_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_13,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_REMOTE_FAULT_DIS);
|
||||
|
||||
if (neg_mode) {
|
||||
/* Clear force speed bits and MAC mode */
|
||||
regmap_clear_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_6,
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_10 |
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_100 |
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_1000 |
|
||||
AIROHA_PCS_HSGMII_PCS_MAC_MODE |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT_VAL |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT);
|
||||
} else {
|
||||
/* Enable compatibility with MAC PCS Layer */
|
||||
if_mode |= AIROHA_PCS_HSGMII_AN_SGMII_COMPAT_EN;
|
||||
|
||||
/* AN off force rate adaption, speed is set later in Link Up */
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_6,
|
||||
AIROHA_PCS_HSGMII_PCS_MAC_MODE |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT);
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_13,
|
||||
AIROHA_PCS_HSGMII_AN_SGMII_IF_MODE_5_0, if_mode);
|
||||
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_6,
|
||||
AIROHA_PCS_HSGMII_PCS_TX_ENABLE |
|
||||
AIROHA_PCS_HSGMII_PCS_MODE2_EN);
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_1000BASEX &&
|
||||
!neg_mode) {
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_1,
|
||||
AIROHA_PCS_SGMII_SEND_AN_ERR_EN);
|
||||
|
||||
regmap_set_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_FORCE_CL37,
|
||||
AIROHA_PCS_HSGMII_AN_FORCE_AN_DONE);
|
||||
}
|
||||
|
||||
/* Configure Flow Control on XFI */
|
||||
regmap_update_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_TX_FC_EN | AIROHA_PCS_XFI_RX_FC_EN,
|
||||
permit_pause_to_mac ?
|
||||
AIROHA_PCS_XFI_TX_FC_EN | AIROHA_PCS_XFI_RX_FC_EN :
|
||||
0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void airoha_pcs_link_up(struct udevice *dev, unsigned int neg_mode,
|
||||
phy_interface_t interface, int speed, int duplex)
|
||||
{
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
const struct airoha_pcs_match_data *data;
|
||||
|
||||
data = priv->data;
|
||||
|
||||
if (neg_mode) {
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
regmap_update_bits(priv->hsgmii_rate_adp,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_1,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_WR_THR |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_RD_THR,
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_WR_THR, 0x0) |
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_RD_THR, 0x0));
|
||||
udelay(1);
|
||||
regmap_update_bits(priv->hsgmii_rate_adp,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_1,
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_WR_THR |
|
||||
AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_RD_THR,
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_WR_THR, 0xf) |
|
||||
FIELD_PREP(AIROHA_PCS_HSGMII_RATE_ADAPT_RX_AFIFO_RD_THR, 0x5));
|
||||
}
|
||||
} else {
|
||||
if (interface == PHY_INTERFACE_MODE_USXGMII ||
|
||||
interface == PHY_INTERFACE_MODE_10GBASER) {
|
||||
u32 mode;
|
||||
u32 rate_adapt;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_10000:
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_10000;
|
||||
mode = AIROHA_PCS_USXGMII_MODE_10000;
|
||||
break;
|
||||
/* case SPEED_5000: not supported in U-Boot
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_5000;
|
||||
mode = AIROHA_PCS_USXGMII_MODE_5000;
|
||||
break; */
|
||||
case SPEED_2500:
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_2500;
|
||||
mode = AIROHA_PCS_USXGMII_MODE_2500;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_1000;
|
||||
mode = AIROHA_PCS_USXGMII_MODE_1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
rate_adapt = AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_100;
|
||||
mode = AIROHA_PCS_USXGMII_MODE_100;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Trigger USXGMII change mode and force selected speed */
|
||||
regmap_update_bits(priv->usxgmii_pcs, AIROHA_PCS_USXGMII_PCS_AN_CONTROL_7,
|
||||
AIROHA_PCS_USXGMII_RATE_UPDATE_MODE |
|
||||
AIROHA_PCS_USXGMII_MODE,
|
||||
AIROHA_PCS_USXGMII_RATE_UPDATE_MODE | mode);
|
||||
|
||||
regmap_update_bits(priv->hsgmii_rate_adp, AIROHA_PCS_HSGMII_RATE_ADAPT_CTRL_11,
|
||||
AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_EN |
|
||||
AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE,
|
||||
AIROHA_PCS_HSGMII_RATE_ADPT_FORCE_RATE_ADAPT_MODE_EN |
|
||||
rate_adapt);
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII ||
|
||||
interface == PHY_INTERFACE_MODE_1000BASEX) {
|
||||
u32 force_speed;
|
||||
u32 rate_adapt;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_1000:
|
||||
force_speed = AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_1000;
|
||||
rate_adapt = AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT_VAL_1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
force_speed = AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_100;
|
||||
rate_adapt = AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT_VAL_100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
force_speed = AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_10;
|
||||
rate_adapt = AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT_VAL_10;
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_CTROL_6,
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_10 |
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_100 |
|
||||
AIROHA_PCS_HSGMII_PCS_SGMII_SPD_FORCE_1000 |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_RATEADAPT_VAL,
|
||||
force_speed | rate_adapt);
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII ||
|
||||
interface == PHY_INTERFACE_MODE_2500BASEX) {
|
||||
u32 ck_gen_mode;
|
||||
u32 speed_reg;
|
||||
u32 if_mode;
|
||||
|
||||
switch (speed) {
|
||||
case SPEED_2500:
|
||||
speed_reg = AIROHA_PCS_LINK_MODE_P0_2_5G;
|
||||
break;
|
||||
case SPEED_1000:
|
||||
speed_reg = AIROHA_PCS_LINK_MODE_P0_1G;
|
||||
if_mode = AIROHA_PCS_HSGMII_AN_SPEED_FORCE_MODE_1000;
|
||||
ck_gen_mode = AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE_1000;
|
||||
break;
|
||||
case SPEED_100:
|
||||
speed_reg = AIROHA_PCS_LINK_MODE_P0_100M;
|
||||
if_mode = AIROHA_PCS_HSGMII_AN_SPEED_FORCE_MODE_100;
|
||||
ck_gen_mode = AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE_100;
|
||||
break;
|
||||
case SPEED_10:
|
||||
speed_reg = AIROHA_PCS_LINK_MODE_P0_100M;
|
||||
if_mode = AIROHA_PCS_HSGMII_AN_SPEED_FORCE_MODE_10;
|
||||
ck_gen_mode = AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE_10;
|
||||
break;
|
||||
}
|
||||
|
||||
if (interface == PHY_INTERFACE_MODE_SGMII) {
|
||||
regmap_update_bits(priv->hsgmii_an, AIROHA_PCS_HSGMII_AN_SGMII_REG_AN_13,
|
||||
AIROHA_PCS_HSGMII_AN_SPEED_FORCE_MODE,
|
||||
if_mode);
|
||||
|
||||
regmap_update_bits(priv->hsgmii_pcs, AIROHA_PCS_HSGMII_PCS_AN_SGMII_MODE_FORCE,
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE_SEL,
|
||||
ck_gen_mode |
|
||||
AIROHA_PCS_HSGMII_PCS_FORCE_CUR_SGMII_MODE_SEL);
|
||||
}
|
||||
|
||||
regmap_update_bits(priv->multi_sgmii, AIROHA_PCS_MULTI_SGMII_SGMII_STS_CTRL_0,
|
||||
AIROHA_PCS_LINK_MODE_P0 |
|
||||
AIROHA_PCS_FORCE_SPD_MODE_P0,
|
||||
speed_reg |
|
||||
AIROHA_PCS_FORCE_SPD_MODE_P0);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->link_up)
|
||||
data->link_up(priv);
|
||||
|
||||
/* BPI BMI enable */
|
||||
regmap_clear_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_RXMPI_STOP |
|
||||
AIROHA_PCS_XFI_RXMBI_STOP |
|
||||
AIROHA_PCS_XFI_TXMPI_STOP |
|
||||
AIROHA_PCS_XFI_TXMBI_STOP);
|
||||
}
|
||||
|
||||
void airoha_pcs_link_down(struct udevice *dev)
|
||||
{
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* MPI MBI disable */
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_RXMPI_STOP |
|
||||
AIROHA_PCS_XFI_RXMBI_STOP |
|
||||
AIROHA_PCS_XFI_TXMPI_STOP |
|
||||
AIROHA_PCS_XFI_TXMBI_STOP);
|
||||
}
|
||||
|
||||
void airoha_pcs_pre_config(struct udevice *dev, phy_interface_t interface)
|
||||
{
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Select HSGMII or USXGMII in SCU regs */
|
||||
airoha_pcs_setup_scu(priv, interface);
|
||||
|
||||
/* MPI MBI disable */
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_RXMPI_STOP |
|
||||
AIROHA_PCS_XFI_RXMBI_STOP |
|
||||
AIROHA_PCS_XFI_TXMPI_STOP |
|
||||
AIROHA_PCS_XFI_TXMBI_STOP);
|
||||
|
||||
/* Write 1 to trigger reset and clear */
|
||||
regmap_clear_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_LOGIC_RST,
|
||||
AIROHA_PCS_XFI_MAC_LOGIC_RST);
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_LOGIC_RST,
|
||||
AIROHA_PCS_XFI_MAC_LOGIC_RST);
|
||||
|
||||
udelay(1000);
|
||||
|
||||
/* Clear XFI MAC counter */
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_CNT_CLR,
|
||||
AIROHA_PCS_XFI_GLB_CNT_CLR);
|
||||
}
|
||||
|
||||
int airoha_pcs_post_config(struct udevice *dev, phy_interface_t interface)
|
||||
{
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Frag disable */
|
||||
regmap_update_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_RX_FRAG_LEN,
|
||||
FIELD_PREP(AIROHA_PCS_XFI_RX_FRAG_LEN, 31));
|
||||
regmap_update_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_TX_FRAG_LEN,
|
||||
FIELD_PREP(AIROHA_PCS_XFI_TX_FRAG_LEN, 31));
|
||||
|
||||
/* IPG NUM */
|
||||
regmap_update_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_IPG_NUM,
|
||||
FIELD_PREP(AIROHA_PCS_XFI_IPG_NUM, 10));
|
||||
|
||||
/* Enable TX/RX flow control */
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_TX_FC_EN);
|
||||
regmap_set_bits(priv->xfi_mac, AIROHA_PCS_XFI_MAC_XFI_GIB_CFG,
|
||||
AIROHA_PCS_XFI_RX_FC_EN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct regmap_config airoha_pcs_regmap_config = {
|
||||
.width = REGMAP_SIZE_32,
|
||||
};
|
||||
|
||||
static int airoha_pcs_probe(struct udevice *dev)
|
||||
{
|
||||
struct regmap_config syscon_config = airoha_pcs_regmap_config;
|
||||
struct airoha_pcs_priv *priv = dev_get_priv(dev);
|
||||
fdt_addr_t base;
|
||||
fdt_size_t size;
|
||||
int ret;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->data = (void *)dev_get_driver_data(dev);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "xfi_mac", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->xfi_mac = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->xfi_mac))
|
||||
return PTR_ERR(priv->xfi_mac);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "hsgmii_an", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->hsgmii_an = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->hsgmii_an))
|
||||
return PTR_ERR(priv->hsgmii_an);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "hsgmii_pcs", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->hsgmii_pcs = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->hsgmii_pcs))
|
||||
return PTR_ERR(priv->hsgmii_pcs);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "hsgmii_rate_adp", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->hsgmii_rate_adp = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->hsgmii_rate_adp))
|
||||
return PTR_ERR(priv->hsgmii_rate_adp);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "multi_sgmii", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->multi_sgmii = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->multi_sgmii))
|
||||
return PTR_ERR(priv->multi_sgmii);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "usxgmii", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->usxgmii_pcs = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->usxgmii_pcs))
|
||||
return PTR_ERR(priv->usxgmii_pcs);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "xfi_pma", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->xfi_pma = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->xfi_pma))
|
||||
return PTR_ERR(priv->xfi_pma);
|
||||
|
||||
base = dev_read_addr_size_name(dev, "xfi_ana", &size);
|
||||
if (base == FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
syscon_config.r_start = base;
|
||||
syscon_config.r_size = size;
|
||||
priv->xfi_ana = devm_regmap_init(dev, NULL, NULL, &syscon_config);
|
||||
if (IS_ERR(priv->xfi_ana))
|
||||
return PTR_ERR(priv->xfi_ana);
|
||||
|
||||
/* SCU is used to toggle XFI or HSGMII in global SoC registers */
|
||||
priv->scu = syscon_regmap_lookup_by_phandle(dev, "airoha,scu");
|
||||
if (IS_ERR(priv->scu))
|
||||
return PTR_ERR(priv->scu);
|
||||
|
||||
priv->rsts.resets = devm_kcalloc(dev, AIROHA_PCS_MAX_NUM_RSTS,
|
||||
sizeof(struct reset_ctl), GFP_KERNEL);
|
||||
if (!priv->rsts.resets)
|
||||
return -ENOMEM;
|
||||
priv->rsts.count = AIROHA_PCS_MAX_NUM_RSTS;
|
||||
|
||||
ret = reset_get_by_name(dev, "mac", &priv->rsts.resets[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_get_by_name(dev, "phy", &priv->rsts.resets[1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
priv->xfi_rst = devm_reset_control_get_optional(dev, "xfi");
|
||||
|
||||
/* For Ethernet PCS, read the AN7581 SoC revision to check if
|
||||
* manual rx calibration is needed. This is only limited to
|
||||
* any SoC revision before E2.
|
||||
*/
|
||||
if (device_is_compatible(dev, "airoha,an7581-pcs-eth") &&
|
||||
priv->data->port_type == AIROHA_PCS_ETH) {
|
||||
u32 val;
|
||||
|
||||
ret = regmap_read(priv->scu, AIROHA_SCU_PDIDR, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (FIELD_GET(AIROHA_SCU_PRODUCT_ID, val) < 0x2)
|
||||
priv->manual_rx_calib = true;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct airoha_pcs_match_data an7581_pcs_eth = {
|
||||
.port_type = AIROHA_PCS_ETH,
|
||||
.hibernation_workaround = true,
|
||||
.usxgmii_ber_time_fixup = true,
|
||||
.bringup = an7581_pcs_bringup,
|
||||
.link_up = an7581_pcs_phya_link_up,
|
||||
};
|
||||
|
||||
static const struct airoha_pcs_match_data an7581_pcs_pon = {
|
||||
.port_type = AIROHA_PCS_PON,
|
||||
.hibernation_workaround = true,
|
||||
.usxgmii_ber_time_fixup = true,
|
||||
.bringup = an7581_pcs_bringup,
|
||||
.link_up = an7581_pcs_phya_link_up,
|
||||
};
|
||||
|
||||
static const struct udevice_id airoha_pcs_of_table[] = {
|
||||
{ .compatible = "airoha,an7581-pcs-eth",
|
||||
.data = (ulong)&an7581_pcs_eth },
|
||||
{ .compatible = "airoha,an7581-pcs-pon",
|
||||
.data = (ulong)&an7581_pcs_pon },
|
||||
{ },
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(airoha_pcs) = {
|
||||
.name = "airoha-pcs",
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = airoha_pcs_of_table,
|
||||
.probe = airoha_pcs_probe,
|
||||
.priv_auto = sizeof(struct airoha_pcs_priv),
|
||||
};
|
||||
1220
drivers/net/airoha/pcs-airoha.h
Normal file
1220
drivers/net/airoha/pcs-airoha.h
Normal file
File diff suppressed because it is too large
Load Diff
1375
drivers/net/airoha/pcs-an7581.c
Normal file
1375
drivers/net/airoha/pcs-an7581.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,9 +9,12 @@
|
||||
*/
|
||||
|
||||
#include <dm.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/devres.h>
|
||||
#include <dm/lists.h>
|
||||
#include <eth_phy.h>
|
||||
#include <mapmem.h>
|
||||
#include <miiphy.h>
|
||||
#include <net.h>
|
||||
#include <regmap.h>
|
||||
#include <reset.h>
|
||||
@ -19,12 +22,15 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/time.h>
|
||||
#include <asm/arch/scu-regmap.h>
|
||||
|
||||
#define AIROHA_MAX_NUM_GDM_PORTS 1
|
||||
#include "airoha/pcs-airoha.h"
|
||||
|
||||
#define AIROHA_MAX_NUM_GDM_PORTS 4
|
||||
#define AIROHA_MAX_NUM_QDMA 1
|
||||
#define AIROHA_MAX_NUM_RSTS 3
|
||||
#define AIROHA_MAX_NUM_XSI_RSTS 4
|
||||
@ -38,6 +44,8 @@
|
||||
#define TX_DSCP_NUM 16
|
||||
#define RX_DSCP_NUM PKTBUFSRX
|
||||
|
||||
#define AIROHA_GDM_PORT_STRING_LEN sizeof("airoha-gdmX")
|
||||
|
||||
/* SCU */
|
||||
#define SCU_SHARE_FEMEM_SEL 0x958
|
||||
|
||||
@ -246,6 +254,21 @@
|
||||
#define QDMA_ETH_RXMSG_CRSN_MASK GENMASK(20, 16)
|
||||
#define QDMA_ETH_RXMSG_PPE_ENTRY_MASK GENMASK(15, 0)
|
||||
|
||||
enum {
|
||||
FE_PSE_PORT_CDM1,
|
||||
FE_PSE_PORT_GDM1,
|
||||
FE_PSE_PORT_GDM2,
|
||||
FE_PSE_PORT_GDM3,
|
||||
FE_PSE_PORT_PPE1,
|
||||
FE_PSE_PORT_CDM2,
|
||||
FE_PSE_PORT_CDM3,
|
||||
FE_PSE_PORT_CDM4,
|
||||
FE_PSE_PORT_PPE2,
|
||||
FE_PSE_PORT_GDM4,
|
||||
FE_PSE_PORT_CDM5,
|
||||
FE_PSE_PORT_DROP = 0xf,
|
||||
};
|
||||
|
||||
struct airoha_qdma_desc {
|
||||
__le32 rsv;
|
||||
__le32 ctrl;
|
||||
@ -301,20 +324,30 @@ struct airoha_qdma {
|
||||
struct airoha_gdm_port {
|
||||
struct airoha_qdma *qdma;
|
||||
int id;
|
||||
|
||||
struct udevice *pcs_dev;
|
||||
phy_interface_t mode;
|
||||
bool neg_mode;
|
||||
|
||||
struct phy_device *phydev;
|
||||
};
|
||||
|
||||
struct airoha_eth {
|
||||
void __iomem *fe_regs;
|
||||
void __iomem *switch_regs;
|
||||
struct udevice *switch_mdio_dev;
|
||||
|
||||
struct reset_ctl_bulk rsts;
|
||||
struct reset_ctl_bulk xsi_rsts;
|
||||
|
||||
struct airoha_eth_soc_data *soc;
|
||||
|
||||
struct airoha_qdma qdma[AIROHA_MAX_NUM_QDMA];
|
||||
struct airoha_gdm_port *ports[AIROHA_MAX_NUM_GDM_PORTS];
|
||||
char gdm_port_str[AIROHA_MAX_NUM_GDM_PORTS + 1][AIROHA_GDM_PORT_STRING_LEN];
|
||||
};
|
||||
|
||||
struct airoha_eth_soc_data {
|
||||
u32 version;
|
||||
int num_xsi_rsts;
|
||||
const char * const *xsi_rsts_names;
|
||||
const char *switch_compatible;
|
||||
@ -397,22 +430,33 @@ static inline void dma_unmap_unaligned(dma_addr_t addr, size_t len,
|
||||
dma_unmap_single(start, end - start, dir);
|
||||
}
|
||||
|
||||
static void airoha_fe_maccr_init(struct airoha_eth *eth)
|
||||
static int airoha_get_fe_port(struct airoha_gdm_port *port)
|
||||
{
|
||||
int p;
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
struct airoha_eth *eth = qdma->eth;
|
||||
|
||||
for (p = 1; p <= ARRAY_SIZE(eth->ports); p++) {
|
||||
/*
|
||||
* Disable any kind of CRC drop or offload.
|
||||
* Enable padding of short TX packets to 60 bytes.
|
||||
*/
|
||||
airoha_fe_wr(eth, REG_GDM_FWD_CFG(p), GDM_PAD_EN);
|
||||
switch (eth->soc->version) {
|
||||
case 0x7523:
|
||||
/* FIXME: GDM1 is the only supported port */
|
||||
return FE_PSE_PORT_GDM1;
|
||||
case 0x7581:
|
||||
default:
|
||||
return port->id == 4 ? FE_PSE_PORT_GDM4 : port->id;
|
||||
}
|
||||
}
|
||||
|
||||
static int airoha_fe_init(struct airoha_eth *eth)
|
||||
static void airoha_fe_maccr_init(struct airoha_gdm_port *port)
|
||||
{
|
||||
airoha_fe_maccr_init(eth);
|
||||
/*
|
||||
* Disable any kind of CRC drop or offload.
|
||||
* Enable padding of short TX packets to 60 bytes.
|
||||
*/
|
||||
airoha_fe_wr(port->qdma->eth, REG_GDM_FWD_CFG(port->id), GDM_PAD_EN);
|
||||
}
|
||||
|
||||
static int airoha_fe_init(struct airoha_gdm_port *port)
|
||||
{
|
||||
airoha_fe_maccr_init(port);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -662,6 +706,36 @@ static int airoha_qdma_init(struct udevice *dev,
|
||||
return airoha_qdma_hw_init(qdma);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PCS_AIROHA)
|
||||
static int airoha_pcs_init(struct udevice *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct udevice *pcs_dev;
|
||||
const char *managed;
|
||||
int ret;
|
||||
|
||||
ret = uclass_get_device_by_phandle(UCLASS_MISC, dev, "pcs",
|
||||
&pcs_dev);
|
||||
if (ret || !pcs_dev)
|
||||
return ret;
|
||||
|
||||
port->pcs_dev = pcs_dev;
|
||||
port->mode = dev_read_phy_mode(dev);
|
||||
managed = dev_read_string(dev, "managed");
|
||||
port->neg_mode = !strncmp(managed, "in-band-status",
|
||||
sizeof("in-band-status"));
|
||||
|
||||
airoha_pcs_pre_config(pcs_dev, port->mode);
|
||||
|
||||
ret = airoha_pcs_post_config(pcs_dev, port->mode);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return airoha_pcs_config(pcs_dev, port->neg_mode,
|
||||
port->mode, NULL, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int airoha_hw_init(struct udevice *dev,
|
||||
struct airoha_eth *eth)
|
||||
{
|
||||
@ -682,12 +756,12 @@ static int airoha_hw_init(struct udevice *dev,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
ret = airoha_fe_init(eth);
|
||||
ret = reset_deassert_bulk(ð->xsi_rsts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdelay(20);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(eth->qdma); i++) {
|
||||
ret = airoha_qdma_init(dev, eth, ð->qdma[i]);
|
||||
if (ret)
|
||||
@ -739,11 +813,45 @@ static int airoha_switch_init(struct udevice *dev, struct airoha_eth *eth)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_alloc_gdm_port(struct udevice *dev, ofnode node)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct udevice *gdm_dev;
|
||||
struct driver *gdm_drv;
|
||||
char *str;
|
||||
int ret;
|
||||
u32 id;
|
||||
|
||||
gdm_drv = lists_driver_lookup_name("airoha-eth-port");
|
||||
if (!gdm_drv)
|
||||
return -ENOENT;
|
||||
|
||||
ret = ofnode_read_u32(node, "reg", &id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id > AIROHA_MAX_NUM_GDM_PORTS)
|
||||
return -EINVAL;
|
||||
|
||||
#if !defined(CONFIG_PCS_AIROHA)
|
||||
if (id != 1)
|
||||
return -ENOTSUPP;
|
||||
#endif
|
||||
|
||||
str = eth->gdm_port_str[id];
|
||||
snprintf(str, AIROHA_GDM_PORT_STRING_LEN,
|
||||
"airoha-gdm%d", id);
|
||||
|
||||
return device_bind_with_driver_data(dev, gdm_drv, str,
|
||||
(ulong)eth, node, &gdm_dev);
|
||||
}
|
||||
|
||||
static int airoha_eth_probe(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct regmap *scu_regmap;
|
||||
ofnode node;
|
||||
int i, ret;
|
||||
|
||||
scu_regmap = airoha_get_scu_regmap();
|
||||
@ -756,6 +864,8 @@ static int airoha_eth_probe(struct udevice *dev)
|
||||
*/
|
||||
regmap_write(scu_regmap, SCU_SHARE_FEMEM_SEL, 0x0);
|
||||
|
||||
eth->soc = data;
|
||||
|
||||
eth->fe_regs = dev_remap_addr_name(dev, "fe");
|
||||
if (!eth->fe_regs)
|
||||
return -ENOMEM;
|
||||
@ -795,13 +905,79 @@ static int airoha_eth_probe(struct udevice *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return airoha_switch_init(dev, eth);
|
||||
ret = airoha_switch_init(dev, eth);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ofnode_for_each_subnode(node, dev_ofnode(dev)) {
|
||||
if (!ofnode_device_is_compatible(node, "airoha,eth-mac"))
|
||||
continue;
|
||||
|
||||
if (!ofnode_is_enabled(node))
|
||||
continue;
|
||||
|
||||
ret = airoha_alloc_gdm_port(dev, node);
|
||||
if (ret && ret != -ENOTSUPP)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_eth_port_of_to_plat(struct udevice *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
|
||||
return dev_read_u32(dev, "reg", &port->id);
|
||||
}
|
||||
|
||||
static int airoha_eth_port_probe(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth *eth = (void *)dev_get_driver_data(dev);
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct mdio_perdev_priv *pdata;
|
||||
struct mii_dev *mdio_bus;
|
||||
int ret;
|
||||
|
||||
port->qdma = ð->qdma[0];
|
||||
|
||||
ret = airoha_fe_init(port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mdio_bus = NULL;
|
||||
if (port->id > 1) {
|
||||
#if defined(CONFIG_PCS_AIROHA)
|
||||
ret = airoha_pcs_init(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
port->phydev = dm_eth_phy_connect(dev);
|
||||
if (port->phydev)
|
||||
mdio_bus = port->phydev->bus;
|
||||
#else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
} else {
|
||||
if (eth->switch_mdio_dev &&
|
||||
!device_probe(eth->switch_mdio_dev)) {
|
||||
pdata = dev_get_uclass_priv(eth->switch_mdio_dev);
|
||||
mdio_bus = pdata->mii_bus;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DM_ETH_PHY
|
||||
if (!IS_ERR_OR_NULL(mdio_bus))
|
||||
eth_phy_set_mdio_bus(dev, mdio_bus);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int airoha_eth_init(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = ð->qdma[0];
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
struct airoha_queue *q;
|
||||
int qid;
|
||||
|
||||
@ -814,13 +990,65 @@ static int airoha_eth_init(struct udevice *dev)
|
||||
GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
GLOBAL_CFG_RX_DMA_EN_MASK);
|
||||
|
||||
#if defined(CONFIG_PCS_AIROHA)
|
||||
if (port->id > 1) {
|
||||
struct phy_device *phydev = port->phydev;
|
||||
int speed, duplex;
|
||||
int ret;
|
||||
|
||||
if (phydev) {
|
||||
ret = phy_config(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = phy_startup(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
speed = phydev->speed;
|
||||
duplex = phydev->duplex;
|
||||
} else {
|
||||
duplex = DUPLEX_FULL;
|
||||
|
||||
/* Hardcode speed for linkup */
|
||||
switch (port->mode) {
|
||||
case PHY_INTERFACE_MODE_USXGMII:
|
||||
case PHY_INTERFACE_MODE_10GBASER:
|
||||
speed = SPEED_10000;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
speed = SPEED_2500;
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
case PHY_INTERFACE_MODE_1000BASEX:
|
||||
speed = SPEED_1000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
airoha_pcs_link_up(port->pcs_dev, port->neg_mode, port->mode,
|
||||
speed, duplex);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void airoha_eth_stop(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = ð->qdma[0];
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
|
||||
#if defined(CONFIG_PCS_AIROHA)
|
||||
if (port->id > 1) {
|
||||
if (port->phydev)
|
||||
phy_shutdown(port->phydev);
|
||||
|
||||
airoha_pcs_link_down(port->pcs_dev);
|
||||
}
|
||||
#endif
|
||||
|
||||
airoha_qdma_clear(qdma, REG_QDMA_GLOBAL_CFG,
|
||||
GLOBAL_CFG_TX_DMA_EN_MASK |
|
||||
@ -829,8 +1057,8 @@ static void airoha_eth_stop(struct udevice *dev)
|
||||
|
||||
static int airoha_eth_send(struct udevice *dev, void *packet, int length)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = ð->qdma[0];
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
struct airoha_qdma_desc *desc;
|
||||
struct airoha_queue *q;
|
||||
dma_addr_t dma_addr;
|
||||
@ -852,7 +1080,7 @@ static int airoha_eth_send(struct udevice *dev, void *packet, int length)
|
||||
desc = &q->desc[q->head];
|
||||
index = (q->head + 1) % q->ndesc;
|
||||
|
||||
fport = 1;
|
||||
fport = airoha_get_fe_port(port);
|
||||
|
||||
msg0 = 0;
|
||||
msg1 = FIELD_PREP(QDMA_ETH_TXMSG_FPORT_MASK, fport) |
|
||||
@ -894,8 +1122,8 @@ static int airoha_eth_send(struct udevice *dev, void *packet, int length)
|
||||
|
||||
static int airoha_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = ð->qdma[0];
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
struct airoha_qdma_desc *desc;
|
||||
struct airoha_queue *q;
|
||||
u16 length;
|
||||
@ -922,8 +1150,8 @@ static int airoha_eth_recv(struct udevice *dev, int flags, uchar **packetp)
|
||||
|
||||
static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
||||
{
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = ð->qdma[0];
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
struct airoha_queue *q;
|
||||
int qid;
|
||||
|
||||
@ -964,8 +1192,9 @@ static int arht_eth_free_pkt(struct udevice *dev, uchar *packet, int length)
|
||||
|
||||
static int arht_eth_write_hwaddr(struct udevice *dev)
|
||||
{
|
||||
struct airoha_gdm_port *port = dev_get_priv(dev);
|
||||
struct eth_pdata *pdata = dev_get_plat(dev);
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
struct airoha_qdma *qdma = port->qdma;
|
||||
unsigned char *mac = pdata->enetaddr;
|
||||
u32 macaddr_lsb, macaddr_msb;
|
||||
|
||||
@ -977,8 +1206,8 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
|
||||
FIELD_PREP(SMACCR1_MAC0, mac[0]);
|
||||
|
||||
/* Set MAC for Switch */
|
||||
airoha_switch_wr(eth, SWITCH_SMACCR0, macaddr_lsb);
|
||||
airoha_switch_wr(eth, SWITCH_SMACCR1, macaddr_msb);
|
||||
airoha_switch_wr(qdma->eth, SWITCH_SMACCR0, macaddr_lsb);
|
||||
airoha_switch_wr(qdma->eth, SWITCH_SMACCR1, macaddr_msb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -986,9 +1215,15 @@ static int arht_eth_write_hwaddr(struct udevice *dev)
|
||||
static int airoha_eth_bind(struct udevice *dev)
|
||||
{
|
||||
struct airoha_eth_soc_data *data = (void *)dev_get_driver_data(dev);
|
||||
struct airoha_eth *eth = dev_get_priv(dev);
|
||||
ofnode switch_node, mdio_node;
|
||||
struct udevice *mdio_dev;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Force Probe as we set the Main ETH driver as misc
|
||||
* to register multiple eth port for each GDM
|
||||
*/
|
||||
dev_or_flags(dev, DM_FLAG_PROBE_AFTER_BIND);
|
||||
|
||||
if (!CONFIG_IS_ENABLED(MDIO_MT7531_MMIO))
|
||||
return 0;
|
||||
@ -1006,8 +1241,8 @@ static int airoha_eth_bind(struct udevice *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mdio",
|
||||
mdio_node, &mdio_dev);
|
||||
ret = device_bind_driver_to_node(dev, "mt7531-mdio-mmio", "mt7531-mdio",
|
||||
mdio_node, ð->switch_mdio_dev);
|
||||
if (ret)
|
||||
debug("Warning: failed to bind mdio controller\n");
|
||||
|
||||
@ -1015,12 +1250,14 @@ static int airoha_eth_bind(struct udevice *dev)
|
||||
}
|
||||
|
||||
static const struct airoha_eth_soc_data en7523_data = {
|
||||
.version = 0x7523,
|
||||
.xsi_rsts_names = en7523_xsi_rsts_names,
|
||||
.num_xsi_rsts = ARRAY_SIZE(en7523_xsi_rsts_names),
|
||||
.switch_compatible = "airoha,en7523-switch",
|
||||
};
|
||||
|
||||
static const struct airoha_eth_soc_data en7581_data = {
|
||||
.version = 0x7581,
|
||||
.xsi_rsts_names = en7581_xsi_rsts_names,
|
||||
.num_xsi_rsts = ARRAY_SIZE(en7581_xsi_rsts_names),
|
||||
.switch_compatible = "airoha,en7581-switch",
|
||||
@ -1045,13 +1282,21 @@ static const struct eth_ops airoha_eth_ops = {
|
||||
.write_hwaddr = arht_eth_write_hwaddr,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(airoha_eth_port) = {
|
||||
.name = "airoha-eth-port",
|
||||
.id = UCLASS_ETH,
|
||||
.of_to_plat = airoha_eth_port_of_to_plat,
|
||||
.probe = airoha_eth_port_probe,
|
||||
.ops = &airoha_eth_ops,
|
||||
.priv_auto = sizeof(struct airoha_gdm_port),
|
||||
.plat_auto = sizeof(struct eth_pdata),
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(airoha_eth) = {
|
||||
.name = "airoha-eth",
|
||||
.id = UCLASS_ETH,
|
||||
.id = UCLASS_MISC,
|
||||
.of_match = airoha_eth_ids,
|
||||
.probe = airoha_eth_probe,
|
||||
.bind = airoha_eth_bind,
|
||||
.ops = &airoha_eth_ops,
|
||||
.priv_auto = sizeof(struct airoha_eth),
|
||||
.plat_auto = sizeof(struct eth_pdata),
|
||||
};
|
||||
|
||||
@ -8,4 +8,4 @@ config PHY_AIROHA_EN8811
|
||||
select FW_LOADER
|
||||
help
|
||||
AIROHA EN8811H supported.
|
||||
|
||||
AIROHA AN8811HB supported.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Driver for the Airoha EN8811H 2.5 Gigabit PHY.
|
||||
* Driver for the Airoha EN8811H and AN8811HB 2.5 Gigabit PHY.
|
||||
*
|
||||
* Limitations of the EN8811H:
|
||||
* - Only full duplex supported
|
||||
@ -8,9 +8,8 @@
|
||||
*
|
||||
* Source originated from linux air_en8811h.c
|
||||
*
|
||||
* Copyright (C) 2025 Airoha Technology Corp.
|
||||
* Copyright (C) 2025, 2026 Airoha Technology Corp.
|
||||
*/
|
||||
|
||||
#include <phy.h>
|
||||
#include <errno.h>
|
||||
#include <log.h>
|
||||
@ -20,27 +19,15 @@
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/compat.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <u-boot/crc.h>
|
||||
|
||||
#define EN8811H_PHY_ID 0x03a2a411
|
||||
|
||||
#define AIR_FW_ADDR_DM 0x00000000
|
||||
#define AIR_FW_ADDR_DSP 0x00100000
|
||||
|
||||
#define EN8811H_MD32_DM_SIZE 0x4000
|
||||
#define EN8811H_MD32_DSP_SIZE 0x20000
|
||||
|
||||
#define EN8811H_FW_CTRL_1 0x0f0018
|
||||
#define EN8811H_FW_CTRL_1_START 0x0
|
||||
#define EN8811H_FW_CTRL_1_FINISH 0x1
|
||||
#define EN8811H_FW_CTRL_2 0x800000
|
||||
#define EN8811H_FW_CTRL_2_LOADING BIT(11)
|
||||
|
||||
/* MII Registers */
|
||||
#define AIR_AUX_CTRL_STATUS 0x1d
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_MASK GENMASK(4, 2)
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_10 0x0
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_100 0x4
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
|
||||
#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
|
||||
@ -49,6 +36,7 @@
|
||||
#define AIR_PHY_PAGE_STANDARD 0x0000
|
||||
#define AIR_PHY_PAGE_EXTENDED_4 0x0004
|
||||
|
||||
#define AIR_PBUS_MODE_ADDR_HIGH 0x1c
|
||||
/* MII Registers Page 4 */
|
||||
#define AIR_BPBUS_MODE 0x10
|
||||
#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
|
||||
@ -63,8 +51,16 @@
|
||||
#define AIR_BPBUS_RD_DATA_LOW 0x18
|
||||
|
||||
/* Registers on MDIO_MMD_VEND1 */
|
||||
#define EN8811H_PHY_FW_STATUS 0x8009
|
||||
#define EN8811H_PHY_READY 0x02
|
||||
#define AIR_PHY_MCU_CMD_1 0x800c
|
||||
#define AIR_PHY_MCU_CMD_1_MODE1 0x0
|
||||
#define AIR_PHY_MCU_CMD_2 0x800d
|
||||
#define AIR_PHY_MCU_CMD_2_MODE1 0x0
|
||||
#define AIR_PHY_MCU_CMD_3 0x800e
|
||||
#define AIR_PHY_MCU_CMD_3_MODE1 0x1101
|
||||
#define AIR_PHY_MCU_CMD_3_DOCMD 0x1100
|
||||
#define AIR_PHY_MCU_CMD_4 0x800f
|
||||
#define AIR_PHY_MCU_CMD_4_MODE1 0x0002
|
||||
#define AIR_PHY_MCU_CMD_4_INTCLR 0x00e4
|
||||
|
||||
/* Registers on MDIO_MMD_VEND2 */
|
||||
#define AIR_PHY_LED_BCR 0x021
|
||||
@ -77,7 +73,7 @@
|
||||
|
||||
#define AIR_PHY_LED_DUR_BLINK 0x023
|
||||
|
||||
#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
|
||||
#define AIR_PHY_LED_ON(i) (0x024 + ((i) * 2))
|
||||
#define AIR_PHY_LED_ON_MASK (GENMASK(6, 0) | BIT(8))
|
||||
#define AIR_PHY_LED_ON_LINK1000 BIT(0)
|
||||
#define AIR_PHY_LED_ON_LINK100 BIT(1)
|
||||
@ -90,7 +86,7 @@
|
||||
#define AIR_PHY_LED_ON_POLARITY BIT(14)
|
||||
#define AIR_PHY_LED_ON_ENABLE BIT(15)
|
||||
|
||||
#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
|
||||
#define AIR_PHY_LED_BLINK(i) (0x025 + ((i) * 2))
|
||||
#define AIR_PHY_LED_BLINK_1000TX BIT(0)
|
||||
#define AIR_PHY_LED_BLINK_1000RX BIT(1)
|
||||
#define AIR_PHY_LED_BLINK_100TX BIT(2)
|
||||
@ -104,21 +100,101 @@
|
||||
#define AIR_PHY_LED_BLINK_2500TX BIT(10)
|
||||
#define AIR_PHY_LED_BLINK_2500RX BIT(11)
|
||||
|
||||
/* Registers on BUCKPBUS */
|
||||
#define AIR_PHY_CONTROL 0x3a9c
|
||||
#define AIR_PHY_CONTROL_SURGE_5R BIT(3)
|
||||
#define AIR_PHY_CONTROL_INTERNAL BIT(11)
|
||||
|
||||
/* Led definitions */
|
||||
#define EN8811H_LED_COUNT 3
|
||||
|
||||
/* Firmware registers */
|
||||
#define AIR_FW_ADDR_DM 0x00000000
|
||||
#define AIR_FW_ADDR_DSP 0x00100000
|
||||
#define EN8811H_FW_CTRL_1 0x0f0018
|
||||
#define EN8811H_FW_CTRL_1_START 0x0
|
||||
#define EN8811H_FW_CTRL_1_FINISH 0x1
|
||||
#define EN8811H_FW_CTRL_2 0x800000
|
||||
#define EN8811H_FW_CTRL_2_LOADING BIT(11)
|
||||
#define EN8811H_PHY_FW_STATUS 0x8009
|
||||
#define EN8811H_PHY_READY 0x02
|
||||
#define AIR_PHY_FW_STATUS 0x8009
|
||||
#define AIR_PHY_READY 0x02
|
||||
|
||||
#define AIR_PHY_FW_CTRL_1 0x0f0018
|
||||
#define AIR_PHY_FW_CTRL_1_START 0x0
|
||||
#define AIR_PHY_FW_CTRL_1_FINISH 0x1
|
||||
|
||||
/* EN8811H */
|
||||
#define EN8811H_PHY_ID 0x03a2a411
|
||||
#define EN8811H_MD32_DM_SIZE 0x4000
|
||||
#define EN8811H_MD32_DSP_SIZE 0x20000
|
||||
#define EN8811H_FW_VERSION 0x3b3c
|
||||
|
||||
#define EN8811H_POLARITY 0xca0f8
|
||||
#define EN8811H_POLARITY_TX_NORMAL BIT(0)
|
||||
#define EN8811H_POLARITY_RX_REVERSE BIT(1)
|
||||
|
||||
#define EN8811H_CLK_CGM 0xcf958
|
||||
#define EN8811H_CLK_CGM_CKO BIT(26)
|
||||
#define EN8811H_HWTRAP1 0xcf914
|
||||
#define EN8811H_HWTRAP1_CKO BIT(12)
|
||||
|
||||
#define clear_bit(bit, bitmap) __clear_bit(bit, bitmap)
|
||||
/* AN8811HB */
|
||||
#define AN8811HB_PHY_ID 0xc0ff04a0
|
||||
#define AIR_MD32_DM_SIZE 0x8000
|
||||
#define AIR_MD32_DSP_SIZE 0x20000
|
||||
#define AIR_PHY_MD32FW_VERSION 0x3b3c
|
||||
|
||||
/* Led definitions */
|
||||
#define EN8811H_LED_COUNT 3
|
||||
#define AN8811HB_GPIO_OUTPUT 0x5cf8b8
|
||||
#define AN8811HB_GPIO_OUTPUT_MASK GENMASK(15, 0)
|
||||
#define AN8811HB_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5))
|
||||
#define AN8811HB_GPIO_OUTPUT_0115 (BIT(0) | BIT(1) | BIT(15))
|
||||
#define AN8811HB_GPIO_SEL_1 0x5cf8bc
|
||||
#define AN8811HB_GPIO_SEL_1_0_MASK GENMASK(2, 0)
|
||||
#define AN8811HB_GPIO_SEL_1_1_MASK GENMASK(6, 4)
|
||||
#define AN8811HB_GPIO_SEL_1_0 FIELD_PREP(AN8811HB_GPIO_SEL_1_0_MASK, 1)
|
||||
#define AN8811HB_GPIO_SEL_1_1 FIELD_PREP(AN8811HB_GPIO_SEL_1_1_MASK, 0)
|
||||
#define AN8811HB_GPIO_SEL_2 0x5cf8c0
|
||||
#define AN8811HB_GPIO_SEL_2_15_MASK GENMASK(30, 28)
|
||||
#define AN8811HB_GPIO_SEL_2_15 FIELD_PREP(AN8811HB_GPIO_SEL_2_15_MASK, 2)
|
||||
|
||||
#define AN8811HB_CRC_PM_SET1 0xf020c
|
||||
#define AN8811HB_CRC_PM_MON2 0xf0218
|
||||
#define AN8811HB_CRC_PM_MON3 0xf021c
|
||||
#define AN8811HB_CRC_DM_SET1 0xf0224
|
||||
#define AN8811HB_CRC_DM_MON2 0xf0230
|
||||
#define AN8811HB_CRC_DM_MON3 0xf0234
|
||||
#define AN8811HB_CRC_RD_EN BIT(0)
|
||||
#define AN8811HB_CRC_ST (BIT(0) | BIT(1))
|
||||
#define AN8811HB_CRC_CHECK_PASS BIT(0)
|
||||
|
||||
#define AN8811HB_TX_POLARITY 0x5ce004
|
||||
#define AN8811HB_TX_POLARITY_NORMAL BIT(7)
|
||||
#define AN8811HB_RX_POLARITY 0x5ce61c
|
||||
#define AN8811HB_RX_POLARITY_NORMAL BIT(7)
|
||||
|
||||
#define AN8811HB_HWTRAP1 0x5cf910
|
||||
#define AN8811HB_HWTRAP2 0x5cf914
|
||||
#define AN8811HB_HWTRAP2_CKO BIT(28)
|
||||
#define AN8811HB_HWTRAP2_PKG (BIT(12) | BIT(13) | BIT(14))
|
||||
#define AN8811HB_PRO_ID 0x5cf920
|
||||
#define AN8811HB_PRO_ID_VERSION GENMASK(3, 0)
|
||||
|
||||
#define AN8811HB_CLK_DRV 0x5cf9e4
|
||||
#define AN8811HB_CLK_DRV_CKO_MASK GENMASK(14, 12)
|
||||
#define AN8811HB_CLK_DRV_CKOPWD BIT(12)
|
||||
#define AN8811HB_CLK_DRV_CKO_LDPWD BIT(13)
|
||||
#define AN8811HB_CLK_DRV_CKO_LPPWD BIT(14)
|
||||
|
||||
#define AN8811HB_MCU_SW_RST 0x5cf9f8
|
||||
#define AN8811HB_MCU_SW_RST_HOLD BIT(16)
|
||||
#define AN8811HB_MCU_SW_RST_RUN (BIT(16) | BIT(0))
|
||||
#define AN8811HB_MCU_SW_START 0x5cf9fc
|
||||
#define AN8811HB_MCU_SW_START_EN BIT(16)
|
||||
|
||||
#define clear_bit(bit, bitmap) __clear_bit(bit, bitmap)
|
||||
|
||||
#define SCRIPT_NAME(name) #name "_load_firmware"
|
||||
|
||||
struct led {
|
||||
unsigned long rules;
|
||||
@ -191,11 +267,48 @@ enum air_led_trigger_netdev_modes {
|
||||
#define AIR_PHY_LED_DUR (AIR_PHY_LED_DUR_UNIT << AIR_PHY_LED_DUR_BLINK_64MS)
|
||||
|
||||
struct en8811h_priv {
|
||||
int firmware_version;
|
||||
u32 firmware_version;
|
||||
bool mcu_needs_restart;
|
||||
struct led led[EN8811H_LED_COUNT];
|
||||
u32 pro_id;
|
||||
u32 pkg_sel;
|
||||
u32 mem_size;
|
||||
const char *script_name;
|
||||
};
|
||||
|
||||
static int air_pbus_reg_write(struct phy_device *phydev,
|
||||
u32 pbus_reg, u32 pbus_data)
|
||||
{
|
||||
int pbus_addr = (phydev->addr) + 8;
|
||||
struct mii_dev *bus = phydev->bus;
|
||||
int ret;
|
||||
|
||||
ret = bus->write(bus, pbus_addr, MDIO_DEVAD_NONE,
|
||||
AIR_EXT_PAGE_ACCESS,
|
||||
(pbus_reg >> 16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bus->write(bus, pbus_addr, MDIO_DEVAD_NONE,
|
||||
AIR_PBUS_MODE_ADDR_HIGH,
|
||||
((pbus_reg & GENMASK(15, 6)) >> 6));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bus->write(bus, pbus_addr, MDIO_DEVAD_NONE,
|
||||
((pbus_reg & GENMASK(5, 2)) >> 2),
|
||||
(pbus_data & GENMASK(15, 0)));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = bus->write(bus, pbus_addr, MDIO_DEVAD_NONE, 0x10,
|
||||
((pbus_data & GENMASK(31, 16)) >> 16));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int air_buckpbus_reg_write(struct phy_device *phydev,
|
||||
u32 pbus_address, u32 pbus_data)
|
||||
{
|
||||
@ -359,8 +472,8 @@ restore_page:
|
||||
static int air_write_buf(struct phy_device *phydev, unsigned long address,
|
||||
unsigned long array_size, const unsigned char *buffer)
|
||||
{
|
||||
unsigned int offset;
|
||||
int ret, saved_page;
|
||||
u32 offset;
|
||||
u16 val;
|
||||
|
||||
saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
|
||||
@ -419,18 +532,144 @@ static int en8811h_wait_mcu_ready(struct phy_device *phydev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int en8811h_read_fw(void **fw, size_t *fwsize)
|
||||
static int an8811hb_check_crc(struct phy_device *phydev,
|
||||
u32 set1, u32 mon2, u32 mon3)
|
||||
{
|
||||
int ret, retry = 10;
|
||||
u32 pbus_value;
|
||||
|
||||
/* Configure CRC */
|
||||
ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN,
|
||||
AN8811HB_CRC_RD_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, set1, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("%d: reg 0x%x val 0x%x!\n", __LINE__, set1, pbus_value);
|
||||
|
||||
do {
|
||||
mdelay(300);
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, mon2, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("%d: reg 0x%x val 0x%x!\n", __LINE__, mon2, pbus_value);
|
||||
|
||||
if (pbus_value & AN8811HB_CRC_ST) {
|
||||
ret = air_buckpbus_reg_read(phydev, mon3, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("%d: reg 0x%x val 0x%x!\n", __LINE__, mon3,
|
||||
pbus_value);
|
||||
|
||||
if (pbus_value & AN8811HB_CRC_CHECK_PASS)
|
||||
debug("CRC Check PASS!\n");
|
||||
else
|
||||
dev_err(phydev->dev, "CRC Check FAIL!(0x%lx)\n",
|
||||
pbus_value & AN8811HB_CRC_CHECK_PASS);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!retry) {
|
||||
dev_err(phydev->dev,
|
||||
"CRC Check is not ready.(Status %u)\n",
|
||||
pbus_value);
|
||||
return -ENODEV;
|
||||
}
|
||||
} while (--retry);
|
||||
|
||||
ret = air_buckpbus_reg_modify(phydev, set1, AN8811HB_CRC_RD_EN, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, set1, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("%d: reg 0x%x val 0x%x!\n", __LINE__, set1, pbus_value);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int an8811hb_mcu_assert(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = air_pbus_reg_write(phydev, AN8811HB_MCU_SW_RST,
|
||||
AN8811HB_MCU_SW_RST_HOLD);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = air_pbus_reg_write(phydev, AN8811HB_MCU_SW_START, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("MCU asserted\n");
|
||||
mdelay(50);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int an8811hb_mcu_deassert(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = air_pbus_reg_write(phydev, AN8811HB_MCU_SW_START,
|
||||
AN8811HB_MCU_SW_START_EN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = air_pbus_reg_write(phydev, AN8811HB_MCU_SW_RST,
|
||||
AN8811HB_MCU_SW_RST_RUN);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("MCU deasserted\n");
|
||||
mdelay(50);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int an8811hb_surge_protect_cfg(struct phy_device *phydev)
|
||||
{
|
||||
ofnode node = phy_get_ofnode(phydev);
|
||||
int ret = 0;
|
||||
|
||||
if (!ofnode_read_bool(node, "airoha,surge-5r")) {
|
||||
debug("Surge Protection mode - 0R\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = air_buckpbus_reg_modify(phydev, AIR_PHY_CONTROL,
|
||||
AIR_PHY_CONTROL_SURGE_5R,
|
||||
AIR_PHY_CONTROL_SURGE_5R);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("Surge Protection mode - 5R\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8811h_read_fw(void **fw, size_t *fwsize, struct en8811h_priv *priv)
|
||||
{
|
||||
const char *script_name = priv->script_name;
|
||||
u32 mem_size = priv->mem_size;
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
buffer = malloc(EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE);
|
||||
buffer = malloc(mem_size);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = request_firmware_into_buf_via_script(buffer,
|
||||
EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE,
|
||||
"en8811h_load_firmware", fwsize);
|
||||
ret = request_firmware_into_buf_via_script(buffer, mem_size,
|
||||
script_name, fwsize);
|
||||
if (ret) {
|
||||
free(buffer);
|
||||
return ret;
|
||||
@ -450,7 +689,10 @@ static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
void *buffer;
|
||||
int ret;
|
||||
|
||||
ret = en8811h_read_fw(&buffer, &fw_size);
|
||||
priv->script_name = SCRIPT_NAME(en8811h);
|
||||
priv->mem_size = EN8811H_MD32_DM_SIZE + EN8811H_MD32_DSP_SIZE;
|
||||
|
||||
ret = en8811h_read_fw(&buffer, &fw_size, priv);
|
||||
if (ret < 0) {
|
||||
dev_err(phydev->dev, "Failed to get firmware data\n");
|
||||
return -EINVAL;
|
||||
@ -496,9 +738,12 @@ static int en8811h_load_firmware(struct phy_device *phydev)
|
||||
goto en8811h_load_firmware_out;
|
||||
|
||||
ret = en8811h_wait_mcu_ready(phydev);
|
||||
if (ret < 0)
|
||||
goto en8811h_load_firmware_out;
|
||||
|
||||
air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
|
||||
&priv->firmware_version);
|
||||
|
||||
dev_info(phydev->dev, "MD32 firmware version: %08x\n",
|
||||
priv->firmware_version);
|
||||
|
||||
@ -510,6 +755,130 @@ en8811h_load_firmware_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int an8811hb_load_firmware(struct phy_device *phydev)
|
||||
{
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
int ret, retry = 10;
|
||||
size_t fw_size;
|
||||
void *buffer;
|
||||
u32 reg_val;
|
||||
|
||||
ret = an8811hb_mcu_assert(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = an8811hb_mcu_deassert(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
priv->script_name = SCRIPT_NAME(an8811hb);
|
||||
priv->mem_size = AIR_MD32_DM_SIZE + AIR_MD32_DSP_SIZE;
|
||||
|
||||
ret = en8811h_read_fw(&buffer, &fw_size, priv);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1,
|
||||
AIR_PHY_FW_CTRL_1_START);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = air_write_buf(phydev, AIR_FW_ADDR_DM, AIR_MD32_DM_SIZE,
|
||||
(unsigned char *)buffer);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = an8811hb_check_crc(phydev, AN8811HB_CRC_DM_SET1,
|
||||
AN8811HB_CRC_DM_MON2, AN8811HB_CRC_DM_MON3);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = air_write_buf(phydev, AIR_FW_ADDR_DSP, AIR_MD32_DSP_SIZE,
|
||||
(unsigned char *)buffer + AIR_MD32_DM_SIZE);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = an8811hb_check_crc(phydev, AN8811HB_CRC_PM_SET1,
|
||||
AN8811HB_CRC_PM_MON2, AN8811HB_CRC_PM_MON3);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1,
|
||||
AIR_PHY_FW_CTRL_1_FINISH);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
ret = an8811hb_surge_protect_cfg(phydev);
|
||||
if (ret < 0) {
|
||||
dev_err(phydev->dev, "an8811hb_surge_protect_cfg fail. (ret=%d)\n", ret);
|
||||
goto an8811hb_load_firmware_out;
|
||||
}
|
||||
|
||||
do {
|
||||
mdelay(300);
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, AIR_PHY_FW_CTRL_1, ®_val);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
if (reg_val == AIR_PHY_FW_CTRL_1_FINISH)
|
||||
break;
|
||||
|
||||
debug("%d: reg 0x%x val 0x%x!\n", __LINE__, AIR_PHY_FW_CTRL_1,
|
||||
reg_val);
|
||||
|
||||
ret = air_buckpbus_reg_write(phydev, AIR_PHY_FW_CTRL_1,
|
||||
AIR_PHY_FW_CTRL_1_FINISH);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
} while (--retry);
|
||||
|
||||
ret = en8811h_wait_mcu_ready(phydev);
|
||||
if (ret < 0)
|
||||
goto an8811hb_load_firmware_out;
|
||||
|
||||
air_buckpbus_reg_read(phydev, AIR_PHY_MD32FW_VERSION,
|
||||
&priv->firmware_version);
|
||||
|
||||
debug("MD32 firmware version: %08x\n", priv->firmware_version);
|
||||
|
||||
an8811hb_load_firmware_out:
|
||||
free(buffer);
|
||||
if (ret < 0)
|
||||
dev_err(phydev->dev, "Firmware loading failed: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int an8811hb_cko_cfg(struct phy_device *phydev)
|
||||
{
|
||||
ofnode node = phy_get_ofnode(phydev);
|
||||
u32 pbus_value;
|
||||
int ret = 0;
|
||||
|
||||
if (!ofnode_read_bool(node, "airoha,phy-output-clock")) {
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV,
|
||||
AN8811HB_CLK_DRV_CKO_MASK,
|
||||
AN8811HB_CLK_DRV_CKOPWD |
|
||||
AN8811HB_CLK_DRV_CKO_LDPWD |
|
||||
AN8811HB_CLK_DRV_CKO_LPPWD);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("CKO Output mode - Disabled\n");
|
||||
} else {
|
||||
ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("CKO Output %dMHz - Enabled\n",
|
||||
(pbus_value & AN8811HB_HWTRAP2_CKO) ? 50 : 25);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8811h_restart_mcu(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
@ -613,13 +982,30 @@ static int air_led_init(struct phy_device *phydev, u8 index, u8 state, u8 pol)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* air_leds_init - Initialize and configure LEDs for a phy device.
|
||||
*
|
||||
* @phydev: Pointer to the phy_device structure.
|
||||
* @num: Number of LEDs to initialize.
|
||||
* @dur: Duration for LED blink in milliseconds. It sets the duration
|
||||
* for both the ON and OFF periods (OFF period will be half of `dur`).
|
||||
* @mode: LED operation mode. Supported modes are:
|
||||
* - AIR_LED_MODE_DISABLE: Disables LED control.
|
||||
* - AIR_LED_MODE_USER_DEFINE: Enables user-defined LED control.
|
||||
*
|
||||
* Initializes and configures LEDs on a phy device with a specified blink duration
|
||||
* and mode. Supports disabling or enabling user-defined control.
|
||||
* Return:
|
||||
* On success, returns 0. On error, it returns a negative value that denotes
|
||||
* the error code.
|
||||
*/
|
||||
|
||||
static int air_leds_init(struct phy_device *phydev, int num, u16 dur, int mode)
|
||||
{
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
int ret, i;
|
||||
|
||||
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK,
|
||||
dur);
|
||||
ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AIR_PHY_LED_DUR_BLINK, dur);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -707,7 +1093,8 @@ static int en8811h_config(struct phy_device *phydev)
|
||||
pbus_value |= EN8811H_POLARITY_TX_NORMAL;
|
||||
ret = air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
|
||||
EN8811H_POLARITY_RX_REVERSE |
|
||||
EN8811H_POLARITY_TX_NORMAL, pbus_value);
|
||||
EN8811H_POLARITY_TX_NORMAL,
|
||||
pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -721,6 +1108,198 @@ static int en8811h_config(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8811hb_config(struct phy_device *phydev)
|
||||
{
|
||||
struct en8811h_priv *priv = phydev->priv;
|
||||
u32 pbus_value = 0;
|
||||
ofnode node;
|
||||
int ret = 0;
|
||||
|
||||
node = phy_get_ofnode(phydev);
|
||||
if (!ofnode_valid(node))
|
||||
return 0;
|
||||
|
||||
/* If restart happened in .probe(), no need to restart now */
|
||||
if (priv->mcu_needs_restart) {
|
||||
ret = an8811hb_mcu_assert(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = an8811hb_mcu_deassert(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = en8811h_restart_mcu(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = an8811hb_load_firmware(phydev);
|
||||
if (ret) {
|
||||
dev_err(phydev->dev, "Load firmware fail.\n");
|
||||
return ret;
|
||||
}
|
||||
/* Next calls to .config() mcu needs to restart */
|
||||
priv->mcu_needs_restart = true;
|
||||
}
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, AN8811HB_PRO_ID, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->pro_id = (pbus_value & AN8811HB_PRO_ID_VERSION) + 1;
|
||||
|
||||
ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
priv->pkg_sel = (pbus_value & AN8811HB_HWTRAP2_PKG) >> 12;
|
||||
debug("%s(%d) Version: E%d\n",
|
||||
priv->pkg_sel ? "AN8811HBCN" : "AN8811HBN", priv->pkg_sel,
|
||||
priv->pro_id);
|
||||
|
||||
/* Serdes polarity */
|
||||
pbus_value = 0;
|
||||
if (ofnode_read_bool(node, "airoha,pnswap-rx"))
|
||||
pbus_value &= ~AN8811HB_RX_POLARITY_NORMAL;
|
||||
else
|
||||
pbus_value |= AN8811HB_RX_POLARITY_NORMAL;
|
||||
|
||||
debug("1 pbus_value 0x%x\n", pbus_value);
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY,
|
||||
AN8811HB_RX_POLARITY_NORMAL, pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
pbus_value = 0;
|
||||
if (ofnode_read_bool(node, "airoha,pnswap-tx"))
|
||||
pbus_value &= ~AN8811HB_TX_POLARITY_NORMAL;
|
||||
else
|
||||
pbus_value |= AN8811HB_TX_POLARITY_NORMAL;
|
||||
|
||||
debug("2 pbus_value 0x%x\n", pbus_value);
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY,
|
||||
AN8811HB_TX_POLARITY_NORMAL, pbus_value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Configure led gpio pins as output */
|
||||
if (priv->pkg_sel) {
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT,
|
||||
AN8811HB_GPIO_OUTPUT_MASK,
|
||||
AN8811HB_GPIO_OUTPUT_0115);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_1,
|
||||
AN8811HB_GPIO_SEL_1_0_MASK |
|
||||
AN8811HB_GPIO_SEL_1_1_MASK,
|
||||
AN8811HB_GPIO_SEL_1_0 |
|
||||
AN8811HB_GPIO_SEL_1_1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_SEL_2,
|
||||
AN8811HB_GPIO_SEL_2_15_MASK,
|
||||
AN8811HB_GPIO_SEL_2_15);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT,
|
||||
AN8811HB_GPIO_OUTPUT_345,
|
||||
AN8811HB_GPIO_OUTPUT_345);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = air_leds_init(phydev, EN8811H_LED_COUNT, AIR_PHY_LED_DUR,
|
||||
AIR_LED_MODE_USER_DEFINE);
|
||||
if (ret < 0) {
|
||||
dev_err(phydev->dev, "Failed to disable leds: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Co-Clock Output */
|
||||
ret = an8811hb_cko_cfg(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
printf("AN8811HB initialize OK !\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8811hb_update_duplex(struct phy_device *phydev)
|
||||
{
|
||||
int lpa;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
|
||||
if (lpa < 0)
|
||||
return lpa;
|
||||
|
||||
switch (phydev->speed) {
|
||||
case SPEED_2500:
|
||||
case SPEED_1000:
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
break;
|
||||
case SPEED_100:
|
||||
phydev->duplex = (lpa & LPA_100FULL) ? DUPLEX_FULL :
|
||||
DUPLEX_HALF;
|
||||
break;
|
||||
case SPEED_10:
|
||||
phydev->duplex = (lpa & LPA_10FULL) ? DUPLEX_FULL :
|
||||
DUPLEX_HALF;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
|
||||
|
||||
if (phydev->speed == SPEED_2500)
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
else
|
||||
phydev->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL :
|
||||
DUPLEX_HALF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int an8811hb_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0, reg_value;
|
||||
|
||||
reg_value = phy_read(phydev, MDIO_DEVAD_NONE, AIR_AUX_CTRL_STATUS);
|
||||
if (reg_value < 0)
|
||||
return reg_value;
|
||||
|
||||
switch (reg_value & AIR_AUX_CTRL_STATUS_SPEED_MASK) {
|
||||
case AIR_AUX_CTRL_STATUS_SPEED_2500:
|
||||
phydev->speed = SPEED_2500;
|
||||
break;
|
||||
case AIR_AUX_CTRL_STATUS_SPEED_1000:
|
||||
phydev->speed = SPEED_1000;
|
||||
break;
|
||||
case AIR_AUX_CTRL_STATUS_SPEED_100:
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
case AIR_AUX_CTRL_STATUS_SPEED_10:
|
||||
phydev->speed = SPEED_10;
|
||||
break;
|
||||
default:
|
||||
dev_err(phydev->dev,
|
||||
"Auto-neg error, defaulting to 2500M/FD\n");
|
||||
phydev->speed = SPEED_2500;
|
||||
phydev->duplex = DUPLEX_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update duplex mode based on speed and negotiation status */
|
||||
ret = an8811hb_update_duplex(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
debug("Speed: %d, %s duplex\n", phydev->speed,
|
||||
(phydev->duplex) ? "full" : "half");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8811h_parse_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0, reg_value;
|
||||
@ -742,7 +1321,8 @@ static int en8811h_parse_status(struct phy_device *phydev)
|
||||
phydev->speed = SPEED_100;
|
||||
break;
|
||||
default:
|
||||
dev_err(phydev->dev, "Auto-neg error, defaulting to 2500M/FD\n");
|
||||
dev_err(phydev->dev,
|
||||
"Auto-neg error, defaulting to 2500M/FD\n");
|
||||
phydev->speed = SPEED_2500;
|
||||
break;
|
||||
}
|
||||
@ -752,24 +1332,35 @@ static int en8811h_parse_status(struct phy_device *phydev)
|
||||
|
||||
static int en8811h_startup(struct phy_device *phydev)
|
||||
{
|
||||
u32 phy_id = phydev->phy_id;
|
||||
int ret = 0;
|
||||
|
||||
ret = genphy_update_link(phydev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return en8811h_parse_status(phydev);
|
||||
if (phy_id == EN8811H_PHY_ID)
|
||||
ret = en8811h_parse_status(phydev);
|
||||
else if (phy_id == AN8811HB_PHY_ID)
|
||||
ret = an8811hb_parse_status(phydev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int en8811h_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct en8811h_priv *priv;
|
||||
int phy_id;
|
||||
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
memset(priv, 0, sizeof(*priv));
|
||||
|
||||
debug("%s driver is probed.\n", phydev->drv->name);
|
||||
get_phy_id(phydev->bus, phydev->addr, MDIO_DEVAD_NONE, &phy_id);
|
||||
debug("phy id is 0x%x.\n", phy_id);
|
||||
|
||||
priv->led[0].rules = AIR_DEFAULT_TRIGGER_LED0;
|
||||
priv->led[1].rules = AIR_DEFAULT_TRIGGER_LED1;
|
||||
priv->led[2].rules = AIR_DEFAULT_TRIGGER_LED2;
|
||||
@ -782,12 +1373,12 @@ static int en8811h_probe(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int en8811h_read_page(struct phy_device *phydev)
|
||||
static int air_phy_read_page(struct phy_device *phydev)
|
||||
{
|
||||
return phy_read(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS);
|
||||
}
|
||||
|
||||
static int en8811h_write_page(struct phy_device *phydev, int page)
|
||||
static int air_phy_write_page(struct phy_device *phydev, int page)
|
||||
{
|
||||
return phy_write(phydev, MDIO_DEVAD_NONE, AIR_EXT_PAGE_ACCESS, page);
|
||||
}
|
||||
@ -798,8 +1389,20 @@ U_BOOT_PHY_DRIVER(en8811h) = {
|
||||
.mask = 0x0ffffff0,
|
||||
.config = &en8811h_config,
|
||||
.probe = &en8811h_probe,
|
||||
.read_page = &en8811h_read_page,
|
||||
.write_page = &en8811h_write_page,
|
||||
.read_page = &air_phy_read_page,
|
||||
.write_page = &air_phy_write_page,
|
||||
.startup = &en8811h_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
U_BOOT_PHY_DRIVER(an8811hb) = {
|
||||
.name = "Airoha AN8811HB",
|
||||
.uid = AN8811HB_PHY_ID,
|
||||
.mask = 0x0ffffff0,
|
||||
.config = &an8811hb_config,
|
||||
.probe = &en8811h_probe,
|
||||
.read_page = &air_phy_read_page,
|
||||
.write_page = &air_phy_write_page,
|
||||
.startup = &en8811h_startup,
|
||||
.shutdown = &genphy_shutdown,
|
||||
};
|
||||
|
||||
@ -65,7 +65,21 @@
|
||||
#define MEM_ALIGNMENT 8
|
||||
|
||||
#define MEMP_NUM_TCP_SEG 16
|
||||
|
||||
/* IP fragmentation parameters for TFTP reassembly */
|
||||
#define IP_FRAG_MTU_USABLE 1480
|
||||
#define PBUF_POOL_HEADROOM 6
|
||||
#define PBUF_POOL_RESERVE 4
|
||||
#define TFTP_BLOCKSIZE_THRESHOLD 4096
|
||||
|
||||
#if defined(CONFIG_TFTP_BLOCKSIZE) && (CONFIG_TFTP_BLOCKSIZE > TFTP_BLOCKSIZE_THRESHOLD)
|
||||
#define PBUF_POOL_SIZE (((CONFIG_TFTP_BLOCKSIZE + (IP_FRAG_MTU_USABLE - 1)) / \
|
||||
IP_FRAG_MTU_USABLE) + PBUF_POOL_HEADROOM)
|
||||
#define IP_REASS_MAX_PBUFS (PBUF_POOL_SIZE - PBUF_POOL_RESERVE)
|
||||
#else
|
||||
#define PBUF_POOL_SIZE 8
|
||||
#define IP_REASS_MAX_PBUFS 4
|
||||
#endif
|
||||
|
||||
#define LWIP_ARP 1
|
||||
#define ARP_TABLE_SIZE 4
|
||||
@ -76,7 +90,7 @@
|
||||
#define IP_REASSEMBLY 1
|
||||
#define IP_FRAG 1
|
||||
#define IP_REASS_MAXAGE 3
|
||||
#define IP_REASS_MAX_PBUFS 4
|
||||
|
||||
#define IP_FRAG_USES_STATIC_BUF 0
|
||||
|
||||
#define IP_DEFAULT_TTL 255
|
||||
@ -121,9 +135,13 @@
|
||||
#define LWIP_UDP 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* PBUF_POOL_BUFSIZE is derived from TCP_MSS even when
|
||||
* CONFIG_PROT_TCP_LWIP is not defined
|
||||
*/
|
||||
#define TCP_MSS 1460
|
||||
#if defined(CONFIG_PROT_TCP_LWIP)
|
||||
#define LWIP_TCP 1
|
||||
#define TCP_MSS 1460
|
||||
#define TCP_WND CONFIG_LWIP_TCP_WND
|
||||
#define LWIP_WND_SCALE 1
|
||||
#define TCP_RCV_SCALE 0x7
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user