From aa2041c012d91b86f9a247a8c9425e0441e900d4 Mon Sep 17 00:00:00 2001 From: hanwckf Date: Sat, 21 Sep 2024 20:17:53 +0800 Subject: [PATCH] mediatek: add mt7981 internal gphy cal support --- .../files-5.4/drivers/net/phy/mediatek-ge.c | 1730 ++++++++++------- .../files-5.4/drivers/net/phy/mtk-phy-lib.c | 452 +++++ .../mediatek/files-5.4/drivers/net/phy/mtk.h | 119 ++ target/linux/mediatek/mt7981/config-5.4 | 2 +- .../patches-5.4/746-mxl-gpy-phy-support.patch | 31 - .../patches-5.4/753-add-mtk-phy-lib.patch | 7 + ...l-introduce-read_poll_timeout-macro.patch} | 171 +- ...d-concept-of-shared-storage-for-PHYs.patch | 311 +++ ...d-concept-of-shared-storage-for-PHYs.patch | 55 + 9 files changed, 2061 insertions(+), 817 deletions(-) create mode 100644 target/linux/mediatek/files-5.4/drivers/net/phy/mtk-phy-lib.c create mode 100644 target/linux/mediatek/files-5.4/drivers/net/phy/mtk.h create mode 100644 target/linux/mediatek/patches-5.4/753-add-mtk-phy-lib.patch rename target/linux/mediatek/patches-5.4/{0030-introduce_read_poll_timeout_macro.patch => 999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch} (50%) create mode 100644 target/linux/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch create mode 100644 target/linux/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c index ac06bf769b..2c2a879937 100644 --- a/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c +++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mediatek-ge.c @@ -1,337 +1,415 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include +#include #include #include -#include +#include #include +#include -#define ANALOG_INTERNAL_OPERATION_MAX_US (20) -#define ZCAL_CTRL_MIN (0) -#define ZCAL_CTRL_MAX (63) -#define TXRESERVE_MIN (0) -#define TXRESERVE_MAX (7) +#include "mtk.h" + +#define MTK_GPHY_ID_MT7981 0x03a29461 +#define MTK_GPHY_ID_MT7988 0x03a29481 + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_3 0x0003 + +#define MTK_PHY_LPI_REG_14 0x14 +#define MTK_PHY_LPI_WAKE_TIMER_1000_MASK GENMASK(8, 0) + +#define MTK_PHY_LPI_REG_1c 0x1c +#define MTK_PHY_SMI_DET_ON_THRESH_MASK GENMASK(13, 8) + +#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 + +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0x7, data_addr = 0x15 */ +/* NormMseLoThresh */ +#define NORMAL_MSE_LO_THRESH_MASK GENMASK(15, 8) + +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +/* RemAckCntLimitCtrl */ +#define REMOTE_ACK_COUNT_LIMIT_CTRL_MASK GENMASK(2, 1) + +/* ch_addr = 0x1, node_addr = 0xd, data_addr = 0x20 */ +/* VcoSlicerThreshBitsHigh */ +#define VCO_SLICER_THRESH_HIGH_MASK GENMASK(23, 0) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x0 */ +/* DfeTailEnableVgaThresh1000 */ +#define DFE_TAIL_EANBLE_VGA_TRHESH_1000 GENMASK(5, 1) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x1 */ +/* MrvlTrFix100Kp */ +#define MRVL_TR_FIX_100KP_MASK GENMASK(22, 20) +/* MrvlTrFix100Kf */ +#define MRVL_TR_FIX_100KF_MASK GENMASK(19, 17) +/* MrvlTrFix1000Kp */ +#define MRVL_TR_FIX_1000KP_MASK GENMASK(16, 14) +/* MrvlTrFix1000Kf */ +#define MRVL_TR_FIX_1000KF_MASK GENMASK(13, 11) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x12 */ +/* VgaDecRate */ +#define VGA_DECIMATION_RATE_MASK GENMASK(8, 5) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x17 */ +/* SlvDSPreadyTime */ +#define SLAVE_DSP_READY_TIME_MASK GENMASK(22, 15) +/* MasDSPreadyTime */ +#define MASTER_DSP_READY_TIME_MASK GENMASK(14, 7) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x18 */ +/* EnabRandUpdTrig */ +#define ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER BIT(8) + +/* ch_addr = 0x1, node_addr = 0xf, data_addr = 0x20 */ +/* ResetSyncOffset */ +#define RESET_SYNC_OFFSET_MASK GENMASK(11, 8) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x0 */ +/* FfeUpdGainForceVal */ +#define FFE_UPDATE_GAIN_FORCE_VAL_MASK GENMASK(9, 7) +/* FfeUpdGainForce */ +#define FFE_UPDATE_GAIN_FORCE BIT(6) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x3 */ +/* TrFreeze */ +#define TR_FREEZE_MASK GENMASK(11, 0) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x6 */ +/* SS: Steady-state, KP: Proportional Gain */ +/* SSTrKp100 */ +#define SS_TR_KP100_MASK GENMASK(21, 19) +/* SSTrKf100 */ +#define SS_TR_KF100_MASK GENMASK(18, 16) +/* SSTrKp1000Mas */ +#define SS_TR_KP1000_MASTER_MASK GENMASK(15, 13) +/* SSTrKf1000Mas */ +#define SS_TR_KF1000_MASTER_MASK GENMASK(12, 10) +/* SSTrKp1000Slv */ +#define SS_TR_KP1000_SLAVE_MASK GENMASK(9, 7) +/* SSTrKf1000Slv */ +#define SS_TR_KF1000_SLAVE_MASK GENMASK(6, 4) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x8 */ +/* clear this bit if wanna select from AFE */ +/* Regsigdet_sel_1000 */ +#define EEE1000_SELECT_SIGNAL_DETECTION_FROM_DFE BIT(4) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xd */ +/* RegEEE_st2TrKf1000 */ +#define EEE1000_STAGE2_TR_KF_MASK GENMASK(13, 11) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0xf */ +/* RegEEE_slv_waketr_timer_tar */ +#define SLAVE_WAKETR_TIMER_MASK GENMASK(20, 11) +/* RegEEE_slv_remtx_timer_tar */ +#define SLAVE_REMTX_TIMER_MASK GENMASK(10, 1) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x10 */ +/* RegEEE_slv_wake_int_timer_tar */ +#define SLAVE_WAKEINT_TIMER_MASK GENMASK(10, 1) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x14 */ +/* RegEEE_trfreeze_timer2 */ +#define TR_FREEZE_TIMER2_MASK GENMASK(9, 0) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x1c */ +/* RegEEE100Stg1_tar */ +#define EEE100_LPSYNC_STAGE1_UPDATE_TIMER_MASK GENMASK(8, 0) + +/* ch_addr = 0x2, node_addr = 0xd, data_addr = 0x25 */ +/* REGEEE_wake_slv_tr_wait_dfesigdet_en */ +#define WAKE_SLAVE_TR_WAIT_DFE_DETECTION_EN BIT(11) -#define MTK_EXT_PAGE_ACCESS 0x1f -#define MTK_PHY_PAGE_STANDARD 0x0000 -#define MTK_PHY_PAGE_EXTENDED 0x0001 -#define MTK_PHY_PAGE_EXTENDED_2 0x0002 -#define MTK_PHY_PAGE_EXTENDED_3 0x0003 -#define MTK_PHY_PAGE_EXTENDED_2A30 0x2a30 -#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 +#define ANALOG_INTERNAL_OPERATION_MAX_US 20 +#define TXRESERVE_MIN 0 +#define TXRESERVE_MAX 7 + +#define MTK_PHY_ANARG_RG 0x10 +#define MTK_PHY_TCLKOFFSET_MASK GENMASK(12, 8) /* Registers on MDIO_MMD_VEND1 */ -enum { - MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TO1 = 0, - MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, - MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, - MTK_PHY_MIDDLE_LEVEL_SHAPPER_1TO0, - MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, - MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, - MTK_PHY_MIDDLE_LEVEL_SHAPPER_0TON1, /* N means negative */ - MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, - MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, - MTK_PHY_MIDDLE_LEVEL_SHAPPER_N1TO0, - MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, - MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, - MTK_PHY_TX_MLT3_END, -}; - -#define MTK_PHY_TXVLD_DA_RG (0x12) +#define MTK_PHY_TXVLD_DA_RG 0x12 #define MTK_PHY_DA_TX_I2MPB_A_GBE_MASK GENMASK(15, 10) #define MTK_PHY_DA_TX_I2MPB_A_TBT_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 (0x16) +#define MTK_PHY_TX_I2MPB_TEST_MODE_A2 0x16 #define MTK_PHY_DA_TX_I2MPB_A_HBT_MASK GENMASK(15, 10) #define MTK_PHY_DA_TX_I2MPB_A_TST_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 (0x17) +#define MTK_PHY_TX_I2MPB_TEST_MODE_B1 0x17 #define MTK_PHY_DA_TX_I2MPB_B_GBE_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_B_TBT_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 (0x18) +#define MTK_PHY_TX_I2MPB_TEST_MODE_B2 0x18 #define MTK_PHY_DA_TX_I2MPB_B_HBT_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_B_TST_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 (0x19) +#define MTK_PHY_TX_I2MPB_TEST_MODE_C1 0x19 #define MTK_PHY_DA_TX_I2MPB_C_GBE_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_C_TBT_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 (0x20) +#define MTK_PHY_TX_I2MPB_TEST_MODE_C2 0x20 #define MTK_PHY_DA_TX_I2MPB_C_HBT_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_C_TST_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 (0x21) +#define MTK_PHY_TX_I2MPB_TEST_MODE_D1 0x21 #define MTK_PHY_DA_TX_I2MPB_D_GBE_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_D_TBT_MASK GENMASK(5, 0) -#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 (0x22) +#define MTK_PHY_TX_I2MPB_TEST_MODE_D2 0x22 #define MTK_PHY_DA_TX_I2MPB_D_HBT_MASK GENMASK(13, 8) #define MTK_PHY_DA_TX_I2MPB_D_TST_MASK GENMASK(5, 0) - -#define MTK_PHY_RESERVE_RG_0 (0x27) -#define MTK_PHY_RESERVE_RG_1 (0x28) - -#define MTK_PHY_RG_ANA_TEST_POWERUP_TX (0x3b) -#define MTK_PHY_TANA_CAL_MODE (0xc1) -#define MTK_PHY_TANA_CAL_MODE_SHIFT (8) - -#define MTK_PHY_RXADC_CTRL_RG7 (0xc6) +#define MTK_PHY_RXADC_CTRL_RG7 0xc6 #define MTK_PHY_DA_AD_BUF_BIAS_LP_MASK GENMASK(9, 8) -#define MTK_PHY_RXADC_CTRL_RG9 (0xc8) -#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) -#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) -#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) -#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) +#define MTK_PHY_RXADC_CTRL_RG9 0xc8 +#define MTK_PHY_DA_RX_PSBN_TBT_MASK GENMASK(14, 12) +#define MTK_PHY_DA_RX_PSBN_HBT_MASK GENMASK(10, 8) +#define MTK_PHY_DA_RX_PSBN_GBE_MASK GENMASK(6, 4) +#define MTK_PHY_DA_RX_PSBN_LP_MASK GENMASK(2, 0) -#define MTK_PHY_RG_ANA_CAL_RG0 (0xdb) -#define MTK_PHY_RG_CAL_CKINV BIT(12) -#define MTK_PHY_RG_ANA_CALEN BIT(8) -#define MTK_PHY_RG_REXT_CALEN BIT(4) -#define MTK_PHY_RG_ZCALEN_A BIT(0) +#define MTK_PHY_LDO_OUTPUT_V 0xd7 -#define MTK_PHY_RG_ANA_CAL_RG1 (0xdc) -#define MTK_PHY_RG_ZCALEN_B BIT(12) -#define MTK_PHY_RG_ZCALEN_C BIT(8) -#define MTK_PHY_RG_ZCALEN_D BIT(4) -#define MTK_PHY_RG_TXVOS_CALEN BIT(0) +#define MTK_PHY_RG_ANA_CAL_RG0 0xdb +#define MTK_PHY_RG_CAL_CKINV BIT(12) +#define MTK_PHY_RG_ANA_CALEN BIT(8) +#define MTK_PHY_RG_ZCALEN_A BIT(0) -#define MTK_PHY_RG_ANA_CAL_RG2 (0xdd) -#define MTK_PHY_RG_TXG_CALEN_A BIT(12) -#define MTK_PHY_RG_TXG_CALEN_B BIT(8) -#define MTK_PHY_RG_TXG_CALEN_C BIT(4) -#define MTK_PHY_RG_TXG_CALEN_D BIT(0) +#define MTK_PHY_RG_ANA_CAL_RG1 0xdc +#define MTK_PHY_RG_ZCALEN_B BIT(12) +#define MTK_PHY_RG_ZCALEN_C BIT(8) +#define MTK_PHY_RG_ZCALEN_D BIT(4) +#define MTK_PHY_RG_TXVOS_CALEN BIT(0) -#define MTK_PHY_RG_ANA_CAL_RG5 (0xe0) -#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) -#define MTK_PHY_RG_ZCAL_CTRL_MASK GENMASK(5, 0) +#define MTK_PHY_RG_ANA_CAL_RG5 0xe0 +#define MTK_PHY_RG_REXT_TRIM_MASK GENMASK(13, 8) -#define MTK_PHY_RG_TX_FILTER (0xfe) +#define MTK_PHY_RG_TX_FILTER 0xfe -#define MTK_PHY_RG_DEV1E_REG172 (0x172) +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG120 0x120 +#define MTK_PHY_LPI_SIG_EN_LO_THRESH1000_MASK GENMASK(12, 8) +#define MTK_PHY_LPI_SIG_EN_HI_THRESH1000_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_LPI_PCS_DSP_CTRL_REG122 0x122 +#define MTK_PHY_LPI_NORM_MSE_HI_THRESH1000_MASK GENMASK(7, 0) + +#define MTK_PHY_RG_TESTMUX_ADC_CTRL 0x144 +#define MTK_PHY_RG_TXEN_DIG_MASK GENMASK(5, 5) + +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B 0x172 #define MTK_PHY_CR_TX_AMP_OFFSET_A_MASK GENMASK(13, 8) #define MTK_PHY_CR_TX_AMP_OFFSET_B_MASK GENMASK(6, 0) -#define MTK_PHY_RG_DEV1E_REG173 (0x173) +#define MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D 0x173 #define MTK_PHY_CR_TX_AMP_OFFSET_C_MASK GENMASK(13, 8) #define MTK_PHY_CR_TX_AMP_OFFSET_D_MASK GENMASK(6, 0) -#define MTK_PHY_RG_DEV1E_REG174 (0x174) -#define MTK_PHY_RSEL_TX_A_MASK GENMASK(14, 8) -#define MTK_PHY_RSEL_TX_B_MASK GENMASK(6, 0) +#define MTK_PHY_RG_AD_CAL_COMP 0x17a +#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) -#define MTK_PHY_RG_DEV1E_REG175 (0x175) -#define MTK_PHY_RSEL_TX_C_MASK GENMASK(14, 8) -#define MTK_PHY_RSEL_TX_D_MASK GENMASK(6, 0) +#define MTK_PHY_RG_AD_CAL_CLK 0x17b +#define MTK_PHY_DA_CAL_CLK BIT(0) -#define MTK_PHY_RG_DEV1E_REG17A (0x17a) -#define MTK_PHY_AD_CAL_COMP_OUT_SHIFT (8) +#define MTK_PHY_RG_AD_CALIN 0x17c +#define MTK_PHY_DA_CALIN_FLAG BIT(0) -#define MTK_PHY_RG_DEV1E_REG17B (0x17b) -#define MTK_PHY_DA_CAL_CLK BIT(0) +#define MTK_PHY_RG_DASN_DAC_IN0_A 0x17d +#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG17C (0x17c) -#define MTK_PHY_DA_CALIN_FLAG BIT(0) +#define MTK_PHY_RG_DASN_DAC_IN0_B 0x17e +#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG17D (0x17d) -#define MTK_PHY_DASN_DAC_IN0_A_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN0_C 0x17f +#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG17E (0x17e) -#define MTK_PHY_DASN_DAC_IN0_B_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN0_D 0x180 +#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG17F (0x17f) -#define MTK_PHY_DASN_DAC_IN0_C_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN1_A 0x181 +#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG180 (0x180) -#define MTK_PHY_DASN_DAC_IN0_D_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN1_B 0x182 +#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG181 (0x181) -#define MTK_PHY_DASN_DAC_IN1_A_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN1_C 0x183 +#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG182 (0x182) -#define MTK_PHY_DASN_DAC_IN1_B_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DASN_DAC_IN1_D 0x184 +#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) -#define MTK_PHY_RG_DEV1E_REG183 (0x183) -#define MTK_PHY_DASN_DAC_IN1_C_MASK GENMASK(9, 0) +#define MTK_PHY_RG_DEV1E_REG19b 0x19b +#define MTK_PHY_BYPASS_DSP_LPI_READY BIT(8) -#define MTK_PHY_RG_DEV1E_REG184 (0x180) -#define MTK_PHY_DASN_DAC_IN1_D_MASK GENMASK(9, 0) +#define MTK_PHY_RG_LP_IIR2_K1_L 0x22a +#define MTK_PHY_RG_LP_IIR2_K1_U 0x22b +#define MTK_PHY_RG_LP_IIR2_K2_L 0x22c +#define MTK_PHY_RG_LP_IIR2_K2_U 0x22d +#define MTK_PHY_RG_LP_IIR2_K3_L 0x22e +#define MTK_PHY_RG_LP_IIR2_K3_U 0x22f +#define MTK_PHY_RG_LP_IIR2_K4_L 0x230 +#define MTK_PHY_RG_LP_IIR2_K4_U 0x231 +#define MTK_PHY_RG_LP_IIR2_K5_L 0x232 +#define MTK_PHY_RG_LP_IIR2_K5_U 0x233 -#define MTK_PHY_RG_DEV1E_REG53D (0x53d) -#define MTK_PHY_DA_TX_R50_A_NORMAL_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_R50_A_TBT_MASK GENMASK(5, 0) +#define MTK_PHY_RG_DEV1E_REG234 0x234 +#define MTK_PHY_TR_OPEN_LOOP_EN_MASK GENMASK(0, 0) +#define MTK_PHY_LPF_X_AVERAGE_MASK GENMASK(7, 4) +#define MTK_PHY_TR_LP_IIR_EEE_EN BIT(12) -#define MTK_PHY_RG_DEV1E_REG53E (0x53e) -#define MTK_PHY_DA_TX_R50_B_NORMAL_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_R50_B_TBT_MASK GENMASK(5, 0) +#define MTK_PHY_RG_LPF_CNT_VAL 0x235 -#define MTK_PHY_RG_DEV1E_REG53F (0x53f) -#define MTK_PHY_DA_TX_R50_C_NORMAL_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_R50_C_TBT_MASK GENMASK(5, 0) +#define MTK_PHY_RG_DEV1E_REG238 0x238 +#define MTK_PHY_LPI_SLV_SEND_TX_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_SLV_SEND_TX_EN BIT(12) -#define MTK_PHY_RG_DEV1E_REG540 (0x540) -#define MTK_PHY_DA_TX_R50_D_NORMAL_MASK GENMASK(13, 8) -#define MTK_PHY_DA_TX_R50_D_TBT_MASK GENMASK(5, 0) +#define MTK_PHY_RG_DEV1E_REG239 0x239 +#define MTK_PHY_LPI_SEND_LOC_TIMER_MASK GENMASK(8, 0) +#define MTK_PHY_LPI_TXPCS_LOC_RCV BIT(12) +#define MTK_PHY_RG_DEV1E_REG27C 0x27c +#define MTK_PHY_VGASTATE_FFE_THR_ST1_MASK GENMASK(12, 8) +#define MTK_PHY_RG_DEV1E_REG27D 0x27d +#define MTK_PHY_VGASTATE_FFE_THR_ST2_MASK GENMASK(4, 0) + +#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 +#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) +#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) + +#define MTK_PHY_RG_DEV1E_REG2D1 0x2d1 +#define MTK_PHY_VCO_SLICER_THRESH_BITS_HIGH_EEE_MASK GENMASK(7, 0) +#define MTK_PHY_LPI_SKIP_SD_SLV_TR BIT(8) +#define MTK_PHY_LPI_TR_READY BIT(9) +#define MTK_PHY_LPI_VCO_EEE_STG0_EN BIT(10) + +#define MTK_PHY_RG_DEV1E_REG323 0x323 +#define MTK_PHY_EEE_WAKE_MAS_INT_DC BIT(0) +#define MTK_PHY_EEE_WAKE_SLV_INT_DC BIT(4) + +#define MTK_PHY_RG_DEV1E_REG324 0x324 +#define MTK_PHY_SMI_DETCNT_MAX_MASK GENMASK(5, 0) +#define MTK_PHY_SMI_DET_MAX_EN BIT(8) + +#define MTK_PHY_RG_DEV1E_REG326 0x326 +#define MTK_PHY_LPI_MODE_SD_ON BIT(0) +#define MTK_PHY_RESET_RANDUPD_CNT BIT(1) +#define MTK_PHY_TREC_UPDATE_ENAB_CLR BIT(2) +#define MTK_PHY_LPI_QUIT_WAIT_DFE_SIG_DET_OFF BIT(4) +#define MTK_PHY_TR_READY_SKIP_AFE_WAKEUP BIT(5) + +#define MTK_PHY_LDO_PUMP_EN_PAIRAB 0x502 +#define MTK_PHY_LDO_PUMP_EN_PAIRCD 0x503 + +#define MTK_PHY_DA_TX_R50_PAIR_A 0x53d +#define MTK_PHY_DA_TX_R50_PAIR_B 0x53e +#define MTK_PHY_DA_TX_R50_PAIR_C 0x53f +#define MTK_PHY_DA_TX_R50_PAIR_D 0x540 /* Registers on MDIO_MMD_VEND2 */ -#define MTK_PHY_ANA_TEST_BUS_CTRL_RG (0x100) -#define MTK_PHY_ANA_TEST_MODE_MASK GENMASK(15, 8) +#define MTK_PHY_LED1_DEFAULT_POLARITIES BIT(1) -#define MTK_PHY_RG_DEV1F_REG110 (0x110) -#define MTK_PHY_RG_TST_DMY2_MASK GENMASK(5, 0) -#define MTK_PHY_RG_TANA_RESERVE_MASK GENMASK(13, 8) +#define MTK_PHY_RG_BG_RASEL 0x115 +#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) -#define MTK_PHY_RG_DEV1F_REG115 (0x115) -#define MTK_PHY_RG_BG_RASEL_MASK GENMASK(2, 0) +/* 'boottrap' register reflecting the configuration of the 4 PHY LEDs */ +#define RG_GPIO_MISC_TPBANK0 0x6f0 +#define RG_GPIO_MISC_TPBANK0_BOOTMODE GENMASK(11, 8) -/* - * These macro privides efuse parsing for internal phy. - */ -#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) -#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) +/* These macro privides efuse parsing for internal phy. */ +#define EFS_DA_TX_I2MPB_A(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_B(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_C(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_I2MPB_D(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_A(x) (((x) >> 24) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_B(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_C(x) (((x) >> 6) & GENMASK(5, 0)) +#define EFS_DA_TX_AMP_OFFSET_D(x) (((x) >> 12) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_A(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_B(x) (((x) >> 24) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_A_10M(x) (((x) >> 12) & GENMASK(5, 0)) -#define EFS_DA_TX_R50_B_10M(x) (((x) >> 18) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_C(x) (((x) >> 0) & GENMASK(5, 0)) +#define EFS_DA_TX_R50_D(x) (((x) >> 6) & GENMASK(5, 0)) -#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) -#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) +#define EFS_RG_BG_RASEL(x) (((x) >> 4) & GENMASK(2, 0)) +#define EFS_RG_REXT_TRIM(x) (((x) >> 7) & GENMASK(5, 0)) -typedef enum { +enum { + NO_PAIR, PAIR_A, PAIR_B, PAIR_C, PAIR_D, -} phy_cal_pair_t; - -const u8 mt798x_zcal_to_r50[64] = { - 7, 8, 9, 9, 10, 10, 11, 11, - 12, 13, 13, 14, 14, 15, 16, 16, - 17, 18, 18, 19, 20, 21, 21, 22, - 23, 24, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, - 38, 40, 41, 42, 43, 45, 46, 48, - 49, 51, 52, 54, 55, 57, 59, 61, - 62, 63, 63, 63, 63, 63, 63, 63 }; -const char pair[4] = {'A', 'B', 'C', 'D'}; +enum { + GPHY_PORT0, + GPHY_PORT1, + GPHY_PORT2, + GPHY_PORT3, +}; -#define CAL_NO_PAIR(cal_item, cal_mode, ...) \ - cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__); +enum calibration_mode { + EFUSE_K, + SW_K +}; -#define CAL_PAIR_A_TO_A(cal_item, cal_mode, ...) \ - for(i=PAIR_A; i<=PAIR_A; i++) { \ - cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__, i);\ - if(cal_ret) break; \ - } +enum CAL_ITEM { + REXT, + TX_OFFSET, + TX_AMP, + TX_R50, + TX_VCM +}; -#define CAL_PAIR_A_TO_D(cal_item, cal_mode, ...) \ - for(i=PAIR_A; i<=PAIR_D; i++) { \ - cal_ret = cal_item##_cal_##cal_mode(phydev, ##__VA_ARGS__, i);\ - if(cal_ret) break; \ - } +enum CAL_MODE { + EFUSE_M, + SW_M +}; -#define SW_CAL(cal_item, cal_mode_get, pair_mode) \ - if(ret || (!ret && strcmp("sw", cal_mode_get) == 0)) { \ - CAL_##pair_mode(cal_item, sw) \ - } +struct mtk_socphy_shared { + u32 boottrap; +}; -#define SW_EFUSE_CAL(cal_item, cal_mode_get, pair_mode,...) \ - if ((efs_valid && ret) || \ - (efs_valid && !ret && strcmp("efuse", cal_mode_get) == 0)) { \ - CAL_##pair_mode(cal_item, efuse, ##__VA_ARGS__) \ - } else if ((!efs_valid && ret) || \ - (!ret && strcmp("sw", cal_mode_get) == 0)) { \ - CAL_##pair_mode(cal_item, sw) \ - } - -#define EFUSE_CAL(cal_item, cal_mode_get, pair_mode, ...) \ - if ((efs_valid && ret) || \ - (efs_valid && !ret && strcmp("efuse", cal_mode_get) == 0)) {\ - CAL_##pair_mode(cal_item, efuse, ##__VA_ARGS__) \ - } - -#define CAL_FLOW(cal_item, cal_mode, cal_mode_get, pair_mode,...) \ - ret = of_property_read_string(phydev->mdio.dev.of_node, \ - #cal_item, &cal_mode_get); \ - cal_mode##_CAL(cal_item, cal_mode_get, pair_mode, ##__VA_ARGS__)\ - else { \ - dev_info(&phydev->mdio.dev, "%s cal mode %s%s," \ - " use default value," \ - " efs-valid: %s", \ - #cal_item, \ - ret? "" : cal_mode_get, \ - ret? "not specified" : " not supported", \ - efs_valid? "yes" : "no"); \ - } \ - if(cal_ret) { \ - dev_err(&phydev->mdio.dev, "%s cal failed\n", #cal_item);\ - ret = -EIO; \ - goto out; \ - } - -#define MTK_PHY_RG_DEV1E_REG2C7 0x2c7 -#define MTK_PHY_MAX_GAIN_MASK GENMASK(4, 0) -#define MTK_PHY_MIN_GAIN_MASK GENMASK(12, 8) - -static int mtk_gephy_read_page(struct phy_device *phydev) -{ - return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); -} - -static int mtk_gephy_write_page(struct phy_device *phydev, int page) -{ - return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); -} - -/* - * One calibration cycle consists of: +/* One calibration cycle consists of: * 1.Set DA_CALIN_FLAG high to start calibration. Keep it high * until AD_CAL_COMP is ready to output calibration result. * 2.Wait until DA_CAL_CLK is available. * 3.Fetch AD_CAL_COMP_OUT. */ static int cal_cycle(struct phy_device *phydev, int devad, - u32 regnum, u16 mask, u16 cal_val) + u32 regnum, u16 mask, u16 cal_val) { - unsigned long timeout; int reg_val; int ret; phy_modify_mmd(phydev, devad, regnum, - mask, cal_val); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17C, - MTK_PHY_DA_CALIN_FLAG); + mask, cal_val); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); - timeout = jiffies + usecs_to_jiffies(ANALOG_INTERNAL_OPERATION_MAX_US); - do{ - reg_val = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17B); - } while(time_before(jiffies, timeout) && !(reg_val & BIT(0))); - - if(!(reg_val & BIT(0))) { - dev_err(&phydev->mdio.dev, "Calibration cycle timeout\n"); - return -ETIMEDOUT; + ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_AD_CAL_CLK, reg_val, + reg_val & MTK_PHY_DA_CAL_CLK, 500, + ANALOG_INTERNAL_OPERATION_MAX_US, + false); + if (ret) { + phydev_err(phydev, "Calibration cycle timeout\n"); + return ret; } - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17C, - MTK_PHY_DA_CALIN_FLAG); - ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17A) >> - MTK_PHY_AD_CAL_COMP_OUT_SHIFT; - dev_dbg(&phydev->mdio.dev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CALIN, + MTK_PHY_DA_CALIN_FLAG); + ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_AD_CAL_COMP) >> + MTK_PHY_AD_CAL_COMP_OUT_SHIFT; + phydev_dbg(phydev, "cal_val: 0x%x, ret: %d\n", cal_val, ret); return ret; } @@ -339,9 +417,9 @@ static int cal_cycle(struct phy_device *phydev, int devad, static int rext_fill_result(struct phy_device *phydev, u16 *buf) { phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG115, - MTK_PHY_RG_BG_RASEL_MASK, buf[1]); + MTK_PHY_RG_REXT_TRIM_MASK, buf[0] << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_BG_RASEL, + MTK_PHY_RG_BG_RASEL_MASK, buf[1]); return 0; } @@ -357,85 +435,15 @@ static int rext_cal_efuse(struct phy_device *phydev, u32 *buf) return 0; } -static int rext_cal_sw(struct phy_device *phydev) -{ - u8 rg_zcal_ctrl_def; - u8 zcal_lower, zcal_upper, rg_zcal_ctrl; - u8 lower_ret, upper_ret; - u16 rext_cal_val[2]; - int ret; - - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, - MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | MTK_PHY_RG_REXT_CALEN); - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110, - MTK_PHY_RG_TST_DMY2_MASK, 0x1); - - rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5) & - MTK_PHY_RG_ZCAL_CTRL_MASK; - zcal_lower = ZCAL_CTRL_MIN; - zcal_upper = ZCAL_CTRL_MAX; - - dev_dbg(&phydev->mdio.dev, "Start REXT SW cal.\n"); - while((zcal_upper-zcal_lower) > 1) { - rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower+zcal_upper, 2); - ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); - if(ret == 1) { - zcal_upper = rg_zcal_ctrl; - upper_ret = ret; - } else if(ret == 0) { - zcal_lower = rg_zcal_ctrl; - lower_ret = ret; - } else - goto restore; - } - - if(zcal_lower == ZCAL_CTRL_MIN) { - ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); - } else if(zcal_upper == ZCAL_CTRL_MAX) { - ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); - } - if (ret < 0) - goto restore; - - ret = upper_ret-lower_ret; - if (ret == 1) { - rext_cal_val[0] = zcal_upper; - rext_cal_val[1] = zcal_upper >> 3; - rext_fill_result(phydev, rext_cal_val); - dev_info(&phydev->mdio.dev, "REXT SW cal result: 0x%x\n", zcal_upper); - ret = 0; - } else - ret = -EINVAL; - -restore: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, - MTK_PHY_ANA_TEST_MODE_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN | MTK_PHY_RG_REXT_CALEN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110, - MTK_PHY_RG_TST_DMY2_MASK); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); - - return ret; -} - static int tx_offset_fill_result(struct phy_device *phydev, u16 *buf) { - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG172, + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, MTK_PHY_CR_TX_AMP_OFFSET_A_MASK, buf[0] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG172, + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_A_B, MTK_PHY_CR_TX_AMP_OFFSET_B_MASK, buf[1]); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG173, + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, MTK_PHY_CR_TX_AMP_OFFSET_C_MASK, buf[2] << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG173, + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_CR_TX_AMP_OFFSET_C_D, MTK_PHY_CR_TX_AMP_OFFSET_D_MASK, buf[3]); return 0; @@ -457,65 +465,79 @@ static int tx_offset_cal_efuse(struct phy_device *phydev, u32 *buf) static int tx_amp_fill_result(struct phy_device *phydev, u16 *buf) { - int bias[16] = {0}; - switch(phydev->drv->phy_id) { - case 0x03a29461: - { - /* We add some calibration to efuse values: - * GBE: +7, TBT: +1, HBT: +4, TST: +7 - */ - int tmp[16] = { 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7, - 7, 1, 4, 7 }; - memcpy(bias, (const void *)tmp, sizeof(bias)); - break; - } - case 0x03a29481: - { - int tmp[16] = { 10, 6, 6, 10, - 10, 6, 6, 10, - 10, 6, 6, 10, - 10, 6, 6, 10 }; - memcpy(bias, (const void *)tmp, sizeof(bias)); - break; - } - default: - break; + const int vals_9481[16] = { 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10, + 10, 6, 6, 10 }; + const int vals_9461[16] = { 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7, + 7, 1, 4, 7 }; + int bias[16] = {}; + int i; + + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + /* We add some calibration to efuse values + * due to board level influence. + * GBE: +7, TBT: +1, HBT: +4, TST: +7 + */ + memcpy(bias, (const void *)vals_9461, sizeof(bias)); + break; + case MTK_GPHY_ID_MT7988: + memcpy(bias, (const void *)vals_9481, sizeof(bias)); + break; } + + /* Prevent overflow */ + for (i = 0; i < 12; i++) { + if (buf[i >> 2] + bias[i] > 63) { + buf[i >> 2] = 63; + bias[i] = 0; + } + } + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, - MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, (buf[0] + bias[0]) << 10); + MTK_PHY_DA_TX_I2MPB_A_GBE_MASK, + (buf[0] + bias[0]) << 10); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, MTK_PHY_DA_TX_I2MPB_A_TBT_MASK, buf[0] + bias[1]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, - MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, (buf[0] + bias[2]) << 10); + MTK_PHY_DA_TX_I2MPB_A_HBT_MASK, + (buf[0] + bias[2]) << 10); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, MTK_PHY_DA_TX_I2MPB_A_TST_MASK, buf[0] + bias[3]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, - MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, (buf[1] + bias[4]) << 8); + MTK_PHY_DA_TX_I2MPB_B_GBE_MASK, + (buf[1] + bias[4]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, MTK_PHY_DA_TX_I2MPB_B_TBT_MASK, buf[1] + bias[5]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, - MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, (buf[1] + bias[6]) << 8); + MTK_PHY_DA_TX_I2MPB_B_HBT_MASK, + (buf[1] + bias[6]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, MTK_PHY_DA_TX_I2MPB_B_TST_MASK, buf[1] + bias[7]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, - MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, (buf[2] + bias[8]) << 8); + MTK_PHY_DA_TX_I2MPB_C_GBE_MASK, + (buf[2] + bias[8]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, MTK_PHY_DA_TX_I2MPB_C_TBT_MASK, buf[2] + bias[9]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, - MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, (buf[2] + bias[10]) << 8); + MTK_PHY_DA_TX_I2MPB_C_HBT_MASK, + (buf[2] + bias[10]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, MTK_PHY_DA_TX_I2MPB_C_TST_MASK, buf[2] + bias[11]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, - MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, (buf[3] + bias[12]) << 8); + MTK_PHY_DA_TX_I2MPB_D_GBE_MASK, + (buf[3] + bias[12]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, MTK_PHY_DA_TX_I2MPB_D_TBT_MASK, buf[3] + bias[13]); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, - MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, (buf[3] + bias[14]) << 8); + MTK_PHY_DA_TX_I2MPB_D_HBT_MASK, + (buf[3] + bias[14]) << 8); phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, MTK_PHY_DA_TX_I2MPB_D_TST_MASK, buf[3] + bias[15]); @@ -535,388 +557,582 @@ static int tx_amp_cal_efuse(struct phy_device *phydev, u32 *buf) return 0; } -static int tx_r50_fill_result(struct phy_device *phydev, u16 *buf, - phy_cal_pair_t txg_calen_x) +static int tx_r50_fill_result(struct phy_device *phydev, u16 tx_r50_cal_val, + u8 txg_calen_x) { - int bias[4] = {0}; - switch(phydev->drv->phy_id) { - case 0x03a29481: - { - int tmp[16] = { 1, 1, 1, 1 }; - memcpy(bias, (const void *)tmp, sizeof(bias)); - break; - } - /* 0x03a29461 enters default case */ - default: - break; + int bias = 0; + u16 reg, val; + + if (phydev->drv->phy_id == MTK_GPHY_ID_MT7988) + bias = -1; + + val = clamp_val(bias + tx_r50_cal_val, 0, 63); + + switch (txg_calen_x) { + case PAIR_A: + reg = MTK_PHY_DA_TX_R50_PAIR_A; + break; + case PAIR_B: + reg = MTK_PHY_DA_TX_R50_PAIR_B; + break; + case PAIR_C: + reg = MTK_PHY_DA_TX_R50_PAIR_C; + break; + case PAIR_D: + reg = MTK_PHY_DA_TX_R50_PAIR_D; + break; + default: + return -EINVAL; } - switch(txg_calen_x) { - case PAIR_A: - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53D, - MTK_PHY_DA_TX_R50_A_NORMAL_MASK, (buf[0] + bias[0]) << 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53D, - MTK_PHY_DA_TX_R50_A_TBT_MASK, (buf[0]) + bias[0]); - break; - case PAIR_B: - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53E, - MTK_PHY_DA_TX_R50_B_NORMAL_MASK, (buf[0] + bias[1])<< 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53E, - MTK_PHY_DA_TX_R50_B_TBT_MASK, (buf[0] + bias[1])); - break; - case PAIR_C: - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53F, - MTK_PHY_DA_TX_R50_C_NORMAL_MASK, (buf[0] + bias[2])<< 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG53F, - MTK_PHY_DA_TX_R50_C_TBT_MASK, (buf[0] + bias[2])); - break; - case PAIR_D: - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG540, - MTK_PHY_DA_TX_R50_D_NORMAL_MASK, (buf[0] + bias[3])<< 8); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG540, - MTK_PHY_DA_TX_R50_D_TBT_MASK, (buf[0] + bias[3])); - break; - } + phy_write_mmd(phydev, MDIO_MMD_VEND1, reg, val | val << 8); + return 0; } static int tx_r50_cal_efuse(struct phy_device *phydev, u32 *buf, - phy_cal_pair_t txg_calen_x) + u8 txg_calen_x) { - u16 tx_r50_cal_val[1]; + u16 tx_r50_cal_val; - switch(txg_calen_x) { - case PAIR_A: - tx_r50_cal_val[0] = EFS_DA_TX_R50_A(buf[1]); - break; - case PAIR_B: - tx_r50_cal_val[0] = EFS_DA_TX_R50_B(buf[1]); - break; - case PAIR_C: - tx_r50_cal_val[0] = EFS_DA_TX_R50_C(buf[2]); - break; - case PAIR_D: - tx_r50_cal_val[0] = EFS_DA_TX_R50_D(buf[2]); - break; + switch (txg_calen_x) { + case PAIR_A: + tx_r50_cal_val = EFS_DA_TX_R50_A(buf[1]); + break; + case PAIR_B: + tx_r50_cal_val = EFS_DA_TX_R50_B(buf[1]); + break; + case PAIR_C: + tx_r50_cal_val = EFS_DA_TX_R50_C(buf[2]); + break; + case PAIR_D: + tx_r50_cal_val = EFS_DA_TX_R50_D(buf[2]); + break; + default: + return -EINVAL; } tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); return 0; } -static int tx_r50_cal_sw(struct phy_device *phydev, phy_cal_pair_t txg_calen_x) -{ - u8 rg_zcal_ctrl_def; - u8 zcal_lower, zcal_upper, rg_zcal_ctrl; - u8 lower_ret, upper_ret; - u16 tx_r50_cal_val[1]; - int ret; - - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, - MTK_PHY_ANA_TEST_MODE_MASK, MTK_PHY_TANA_CAL_MODE << 8); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, - BIT(txg_calen_x * 4)); - phy_modify_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110, - MTK_PHY_RG_TST_DMY2_MASK, 0x1); - - rg_zcal_ctrl_def = phy_read_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5) & - MTK_PHY_RG_ZCAL_CTRL_MASK; - zcal_lower = ZCAL_CTRL_MIN; - zcal_upper = ZCAL_CTRL_MAX; - - dev_dbg(&phydev->mdio.dev, "Start TX-R50 Pair%c SW cal.\n", pair[txg_calen_x]); - while((zcal_upper-zcal_lower) > 1) { - rg_zcal_ctrl = DIV_ROUND_CLOSEST(zcal_lower+zcal_upper, 2); - ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl); - if(ret==1) { - zcal_upper = rg_zcal_ctrl; - upper_ret = ret; - } else if(ret==0) { - zcal_lower = rg_zcal_ctrl; - lower_ret = ret; - } else - goto restore; - } - - if(zcal_lower == ZCAL_CTRL_MIN) { - ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_lower); - } else if(zcal_upper == ZCAL_CTRL_MAX) { - ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, zcal_upper); - } - if (ret < 0) - goto restore; - - ret = upper_ret-lower_ret; - if (ret == 1) { - tx_r50_cal_val[0] = mt798x_zcal_to_r50[zcal_upper]; - tx_r50_fill_result(phydev, tx_r50_cal_val, txg_calen_x); - dev_info(&phydev->mdio.dev, "TX-R50 Pair%c SW cal result: 0x%x\n", - pair[txg_calen_x], zcal_lower); - ret = 0; - } else - ret = -EINVAL; - -restore: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_ANA_TEST_BUS_CTRL_RG, - MTK_PHY_ANA_TEST_MODE_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV | MTK_PHY_RG_ANA_CALEN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG2, - BIT(txg_calen_x * 4)); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_RG_DEV1F_REG110, - MTK_PHY_RG_TST_DMY2_MASK); - phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG5, - MTK_PHY_RG_ZCAL_CTRL_MASK, rg_zcal_ctrl_def); - - return ret; -} - -static int tx_vcm_cal_sw(struct phy_device *phydev, phy_cal_pair_t rg_txreserve_x) +static int tx_vcm_cal_sw(struct phy_device *phydev, u8 rg_txreserve_x) { u8 lower_idx, upper_idx, txreserve_val; u8 lower_ret, upper_ret; int ret; phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ANA_CALEN); + MTK_PHY_RG_ANA_CALEN); phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_CAL_CKINV); + MTK_PHY_RG_CAL_CKINV); phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); + MTK_PHY_RG_TXVOS_CALEN); - switch(rg_txreserve_x) { - case PAIR_A: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17D, - MTK_PHY_DASN_DAC_IN0_A_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG181, - MTK_PHY_DASN_DAC_IN1_A_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ZCALEN_A); - break; - case PAIR_B: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17E, - MTK_PHY_DASN_DAC_IN0_B_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG182, - MTK_PHY_DASN_DAC_IN1_B_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_B); - break; - case PAIR_C: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG17F, - MTK_PHY_DASN_DAC_IN0_C_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG183, - MTK_PHY_DASN_DAC_IN1_C_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_C); - break; - case PAIR_D: - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG180, - MTK_PHY_DASN_DAC_IN0_D_MASK); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG184, - MTK_PHY_DASN_DAC_IN1_D_MASK); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_D); - break; - default: - ret = -EINVAL; - goto restore; + switch (rg_txreserve_x) { + case PAIR_A: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_A, + MTK_PHY_DASN_DAC_IN0_A_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_A, + MTK_PHY_DASN_DAC_IN1_A_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG0, + MTK_PHY_RG_ZCALEN_A); + break; + case PAIR_B: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_B, + MTK_PHY_DASN_DAC_IN0_B_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_B, + MTK_PHY_DASN_DAC_IN1_B_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_B); + break; + case PAIR_C: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_C, + MTK_PHY_DASN_DAC_IN0_C_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_C, + MTK_PHY_DASN_DAC_IN1_C_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_C); + break; + case PAIR_D: + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN0_D, + MTK_PHY_DASN_DAC_IN0_D_MASK); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_DASN_DAC_IN1_D, + MTK_PHY_DASN_DAC_IN1_D_MASK); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + MTK_PHY_RG_ANA_CAL_RG1, + MTK_PHY_RG_ZCALEN_D); + break; + default: + ret = -EINVAL; + goto restore; } lower_idx = TXRESERVE_MIN; upper_idx = TXRESERVE_MAX; - dev_dbg(&phydev->mdio.dev, "Start TX-VCM SW cal.\n"); - while((upper_idx-lower_idx) > 1) { - txreserve_val = DIV_ROUND_CLOSEST(lower_idx+upper_idx, 2); + phydev_dbg(phydev, "Start TX-VCM SW cal.\n"); + while ((upper_idx - lower_idx) > 1) { + txreserve_val = DIV_ROUND_CLOSEST(lower_idx + upper_idx, 2); ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, txreserve_val << 12 | txreserve_val << 8 | txreserve_val << 4 | txreserve_val); - if(ret==1) { + if (ret == 1) { upper_idx = txreserve_val; upper_ret = ret; - } else if(ret==0) { + } else if (ret == 0) { lower_idx = txreserve_val; lower_ret = ret; - } else + } else { goto restore; + } } - if(lower_idx == TXRESERVE_MIN) { - ret = lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK, - lower_idx << 12 | lower_idx << 8 | lower_idx << 4 | lower_idx); - } else if(upper_idx == TXRESERVE_MAX) { - ret = upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK, - upper_idx << 12 | upper_idx << 8 | upper_idx << 4 | upper_idx); + if (lower_idx == TXRESERVE_MIN) { + lower_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + ret = lower_ret; + } else if (upper_idx == TXRESERVE_MAX) { + upper_ret = cal_cycle(phydev, MDIO_MMD_VEND1, + MTK_PHY_RXADC_CTRL_RG9, + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + ret = upper_ret; } if (ret < 0) goto restore; /* We calibrate TX-VCM in different logic. Check upper index and then - * lower index. If this calibration is valid, apply lower index's result. + * lower index. If this calibration is valid, apply lower index's + * result. */ - ret = upper_ret-lower_ret; + ret = upper_ret - lower_ret; if (ret == 1) { ret = 0; /* Make sure we use upper_idx in our calibration system */ cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK, - upper_idx << 12 | upper_idx << 8 | upper_idx << 4 | upper_idx); - dev_info(&phydev->mdio.dev, "TX-VCM SW cal result: 0x%x\n", upper_idx); - } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && lower_ret == 1) { + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + upper_idx << 12 | upper_idx << 8 | + upper_idx << 4 | upper_idx); + phydev_dbg(phydev, "TX-VCM SW cal result: 0x%x\n", upper_idx); + } else if (lower_idx == TXRESERVE_MIN && upper_ret == 1 && + lower_ret == 1) { ret = 0; cal_cycle(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG9, - MTK_PHY_DA_RX_PSBN_TBT_MASK | MTK_PHY_DA_RX_PSBN_HBT_MASK | - MTK_PHY_DA_RX_PSBN_GBE_MASK | MTK_PHY_DA_RX_PSBN_LP_MASK, - lower_idx << 12 | lower_idx << 8 | lower_idx << 4 | lower_idx); - dev_warn(&phydev->mdio.dev, "TX-VCM SW cal result at low margin 0x%x\n", lower_idx); - } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && lower_ret == 0) { + MTK_PHY_DA_RX_PSBN_TBT_MASK | + MTK_PHY_DA_RX_PSBN_HBT_MASK | + MTK_PHY_DA_RX_PSBN_GBE_MASK | + MTK_PHY_DA_RX_PSBN_LP_MASK, + lower_idx << 12 | lower_idx << 8 | + lower_idx << 4 | lower_idx); + phydev_warn(phydev, "TX-VCM SW cal result at low margin 0x%x\n", + lower_idx); + } else if (upper_idx == TXRESERVE_MAX && upper_ret == 0 && + lower_ret == 0) { ret = 0; - dev_warn(&phydev->mdio.dev, "TX-VCM SW cal result at high margin 0x%x\n", upper_idx); - } else + phydev_warn(phydev, + "TX-VCM SW cal result at high margin 0x%x\n", + upper_idx); + } else { ret = -EINVAL; + } restore: phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ANA_CALEN); + MTK_PHY_RG_ANA_CALEN); phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_TXVOS_CALEN); + MTK_PHY_RG_TXVOS_CALEN); phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG0, - MTK_PHY_RG_ZCALEN_A); + MTK_PHY_RG_ZCALEN_A); phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_ANA_CAL_RG1, - MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | MTK_PHY_RG_ZCALEN_D); + MTK_PHY_RG_ZCALEN_B | MTK_PHY_RG_ZCALEN_C | + MTK_PHY_RG_ZCALEN_D); return ret; } -static void mtk_gephy_config_init(struct phy_device *phydev) +static void mt798x_phy_common_finetune(struct phy_device *phydev) { - /* Disable EEE */ - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0); - - /* Enable HW auto downshift */ - phy_modify_paged(phydev, MTK_PHY_PAGE_EXTENDED, 0x14, 0, BIT(4)); - - /* Increase SlvDPSready time */ phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); - __phy_write(phydev, 0x10, 0xafae); - __phy_write(phydev, 0x12, 0x2f); - __phy_write(phydev, 0x10, 0x8fae); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x17, + SLAVE_DSP_READY_TIME_MASK | MASTER_DSP_READY_TIME_MASK, + FIELD_PREP(SLAVE_DSP_READY_TIME_MASK, 0x18) | + FIELD_PREP(MASTER_DSP_READY_TIME_MASK, 0x18)); + + __mtk_tr_set_bits(phydev, 0x1, 0xf, 0x18, + ENABLE_RANDOM_UPDOWN_COUNTER_TRIGGER); + + __mtk_tr_modify(phydev, 0x0, 0x7, 0x15, + NORMAL_MSE_LO_THRESH_MASK, + FIELD_PREP(NORMAL_MSE_LO_THRESH_MASK, 0x55)); + + __mtk_tr_modify(phydev, 0x2, 0xd, 0x0, + FFE_UPDATE_GAIN_FORCE_VAL_MASK, + FIELD_PREP(FFE_UPDATE_GAIN_FORCE_VAL_MASK, 0x4) | + FFE_UPDATE_GAIN_FORCE); + + __mtk_tr_clr_bits(phydev, 0x2, 0xd, 0x3, TR_FREEZE_MASK); + + __mtk_tr_modify(phydev, 0x2, 0xd, 0x6, + SS_TR_KP100_MASK | SS_TR_KF100_MASK | + SS_TR_KP1000_MASTER_MASK | SS_TR_KF1000_MASTER_MASK | + SS_TR_KP1000_SLAVE_MASK | SS_TR_KF1000_SLAVE_MASK, + FIELD_PREP(SS_TR_KP100_MASK, 0x5) | + FIELD_PREP(SS_TR_KF100_MASK, 0x6) | + FIELD_PREP(SS_TR_KP1000_MASTER_MASK, 0x5) | + FIELD_PREP(SS_TR_KF1000_MASTER_MASK, 0x6) | + FIELD_PREP(SS_TR_KP1000_SLAVE_MASK, 0x5) | + FIELD_PREP(SS_TR_KF1000_SLAVE_MASK, 0x6)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); - - /* Adjust 100_mse_threshold */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x123, 0xffff); - - /* Disable mcc */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xa6, 0x300); } -static int mt7530_phy_config_init(struct phy_device *phydev) +static void mt7981_phy_finetune(struct phy_device *phydev) { - mtk_gephy_config_init(phydev); + u16 val[8] = { 0x01ce, 0x01c1, + 0x020f, 0x0202, + 0x03d0, 0x03c0, + 0x0013, 0x0005 }; + int i, k; - /* Increase post_update_timer */ - phy_write_paged(phydev, MTK_PHY_PAGE_EXTENDED_3, 0x11, 0x4b); - - return 0; -} - -static int mt7531_phy_config_init(struct phy_device *phydev) -{ - if (phydev->interface != PHY_INTERFACE_MODE_INTERNAL) - return -EINVAL; - - mtk_gephy_config_init(phydev); - - /* PHY link down power saving enable */ - phy_set_bits(phydev, 0x17, BIT(4)); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, 0xc6, 0x300); - - /* Set TX Pair delay selection */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x13, 0x404); - phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x14, 0x404); - - /* Adjust RX min/max gain to fix CH395 100Mbps link up fail */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG2C7, - FIELD_PREP(MTK_PHY_MAX_GAIN_MASK, 0x8) | - FIELD_PREP(MTK_PHY_MIN_GAIN_MASK, 0x13)); - - return 0; -} - -static inline void mt7981_phy_finetune(struct phy_device *phydev) -{ /* 100M eye finetune: * Keep middle level of TX MLT3 shapper as default. * Only change TX MLT3 overshoot level here. */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TO1, 0x1ce); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TO1, 0x1c1); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_1TO0, 0x20f); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_1TO0, 0x202); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_0TON1, 0x3d0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_0TON1, 0x3c0); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_1st_OVERSHOOT_LEVEL_N1TO0, 0x13); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_2nd_OVERSHOOT_LEVEL_N1TO0, 0x5); + for (k = 0, i = 1; i < 12; i++) { + if (i % 3 == 0) + continue; + phy_write_mmd(phydev, MDIO_MMD_VEND1, i, val[k++]); + } - /* TX-AMP finetune: - * 100M +4, 1000M +6 to default value. - * If efuse values aren't valid, TX-AMP uses the below values. + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x20, + RESET_SYNC_OFFSET_MASK, + FIELD_PREP(RESET_SYNC_OFFSET_MASK, 0x6)); + + __mtk_tr_modify(phydev, 0x1, 0xf, 0x12, + VGA_DECIMATION_RATE_MASK, + FIELD_PREP(VGA_DECIMATION_RATE_MASK, 0x1)); + + /* MrvlTrFix100Kp = 3, MrvlTrFix100Kf = 2, + * MrvlTrFix1000Kp = 3, MrvlTrFix1000Kf = 2 */ - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TXVLD_DA_RG, 0x9824); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_A2, 0x9026); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B1, 0x2624); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_B2, 0x2426); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C1, 0x2624); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_C2, 0x2426); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D1, 0x2624); - phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_TX_I2MPB_TEST_MODE_D2, 0x2426); + __mtk_tr_modify(phydev, 0x1, 0xf, 0x1, + MRVL_TR_FIX_100KP_MASK | MRVL_TR_FIX_100KF_MASK | + MRVL_TR_FIX_1000KP_MASK | MRVL_TR_FIX_1000KF_MASK, + FIELD_PREP(MRVL_TR_FIX_100KP_MASK, 0x3) | + FIELD_PREP(MRVL_TR_FIX_100KF_MASK, 0x2) | + FIELD_PREP(MRVL_TR_FIX_1000KP_MASK, 0x3) | + FIELD_PREP(MRVL_TR_FIX_1000KF_MASK, 0x2)); + + /* VcoSlicerThreshBitsHigh */ + __mtk_tr_modify(phydev, 0x1, 0xd, 0x20, + VCO_SLICER_THRESH_HIGH_MASK, + FIELD_PREP(VCO_SLICER_THRESH_HIGH_MASK, 0x555555)); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + /* TR_OPEN_LOOP_EN = 1, lpf_x_average = 9 */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG234, + MTK_PHY_TR_OPEN_LOOP_EN_MASK | + MTK_PHY_LPF_X_AVERAGE_MASK, + BIT(0) | FIELD_PREP(MTK_PHY_LPF_X_AVERAGE_MASK, 0x9)); + + /* rg_tr_lpf_cnt_val = 512 */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LPF_CNT_VAL, 0x200); + + /* IIR2 related */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K1_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_L, 0x103); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K2_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_L, 0x82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K3_U, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_L, 0xd177); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K4_U, 0x3); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_L, 0x2c82); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_LP_IIR2_K5_U, 0xe); + + /* FFE peaking */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27C, + MTK_PHY_VGASTATE_FFE_THR_ST1_MASK, 0x1b << 8); + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RG_DEV1E_REG27D, + MTK_PHY_VGASTATE_FFE_THR_ST2_MASK, 0x1e); + + /* Disable LDO pump */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRAB, 0x0); + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_PUMP_EN_PAIRCD, 0x0); + /* Adjust LDO output voltage */ + phy_write_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_LDO_OUTPUT_V, 0x2222); } -static inline void mt7988_phy_finetune(struct phy_device *phydev) +static void mt7988_phy_finetune(struct phy_device *phydev) { + u16 val[12] = { 0x0187, 0x01cd, 0x01c8, 0x0182, + 0x020d, 0x0206, 0x0384, 0x03d0, + 0x03c6, 0x030a, 0x0011, 0x0005 }; int i; - u16 val[12] = {0x0187, 0x01cd, 0x01c8, 0x0182, - 0x020d, 0x0206, 0x0384, 0x03d0, - 0x03c6, 0x030a, 0x0011, 0x0005}; - for(i=0; iinterface != PHY_INTERFACE_MODE_GMII) - return -EINVAL; + int ret = 0; + size_t len; + u32 *buf; cell = nvmem_cell_get(&phydev->mdio.dev, "phy-cal-data"); if (IS_ERR(cell)) { @@ -930,117 +1146,205 @@ static int mt798x_phy_calibration(struct phy_device *phydev) return PTR_ERR(buf); nvmem_cell_put(cell); - if(!buf[0] && !buf[1] && !buf[2] && !buf[3]) - efs_valid = false; - - if (len < 4 * sizeof(u32)) { - dev_err(&phydev->mdio.dev, "invalid calibration data\n"); + if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { + phydev_err(phydev, "invalid efuse data\n"); ret = -EINVAL; goto out; } - CAL_FLOW(rext, SW_EFUSE, cal_mode_from_dts, NO_PAIR, buf) - CAL_FLOW(tx_offset, EFUSE, cal_mode_from_dts, NO_PAIR, buf) - CAL_FLOW(tx_amp, EFUSE, cal_mode_from_dts, NO_PAIR, buf) - CAL_FLOW(tx_r50, SW_EFUSE, cal_mode_from_dts, PAIR_A_TO_D, buf) - CAL_FLOW(tx_vcm, SW, cal_mode_from_dts, PAIR_A_TO_A) - ret = 0; + ret = start_cal(phydev, REXT, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_OFFSET, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_AMP, EFUSE_M, NO_PAIR, NO_PAIR, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_R50, EFUSE_M, PAIR_A, PAIR_D, buf); + if (ret) + goto out; + ret = start_cal(phydev, TX_VCM, SW_M, PAIR_A, PAIR_A, buf); + if (ret) + goto out; out: kfree(buf); return ret; } -static int mt7981_phy_config_init(struct phy_device *phydev) +static int mt798x_phy_config_init(struct phy_device *phydev) { - mt7981_phy_finetune(phydev); + switch (phydev->drv->phy_id) { + case MTK_GPHY_ID_MT7981: + mt7981_phy_finetune(phydev); + break; + case MTK_GPHY_ID_MT7988: + mt7988_phy_finetune(phydev); + break; + } + + mt798x_phy_common_finetune(phydev); + mt798x_phy_eee(phydev); return mt798x_phy_calibration(phydev); } -static int mt7988_phy_config_init(struct phy_device *phydev) +static int mt7988_phy_setup_led(struct phy_device *phydev) { - mt7988_phy_finetune(phydev); + struct mtk_socphy_shared *shared = phydev->shared->priv; + int port = phydev->mdio.addr; + u32 reg = shared->boottrap; + struct pinctrl *pinctrl; - return mt798x_phy_calibration(phydev); + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_ENABLE | MTK_PHY_LED_ON_POLARITY | + MTK_PHY_LED_ON_LINK10 | + MTK_PHY_LED_ON_LINK100 | + MTK_PHY_LED_ON_LINK1000); + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED_ON_ENABLE | MTK_PHY_LED_ON_POLARITY | + MTK_PHY_LED_ON_LINK10 | + MTK_PHY_LED_ON_LINK100 | + MTK_PHY_LED_ON_LINK1000); + + if ((port == GPHY_PORT0 && reg & BIT(0)) || + (port == GPHY_PORT1 && reg & BIT(1)) || + (port == GPHY_PORT2 && reg & BIT(2)) || + (port == GPHY_PORT3 && reg & BIT(3))) { + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_POLARITY); + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_ON_CTRL, + MTK_PHY_LED_ON_POLARITY); + } + + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED0_BLINK_CTRL, + MTK_PHY_LED_BLINK_1000TX | MTK_PHY_LED_BLINK_1000RX | + MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_100RX | + MTK_PHY_LED_BLINK_10TX | MTK_PHY_LED_BLINK_10RX); + phy_write_mmd(phydev, MDIO_MMD_VEND2, MTK_PHY_LED1_BLINK_CTRL, + MTK_PHY_LED_BLINK_1000TX | MTK_PHY_LED_BLINK_1000RX | + MTK_PHY_LED_BLINK_100TX | MTK_PHY_LED_BLINK_100RX | + MTK_PHY_LED_BLINK_10TX | MTK_PHY_LED_BLINK_10RX); + + pinctrl = devm_pinctrl_get_select(&phydev->mdio.dev, "gbe-led"); + if (IS_ERR(pinctrl)) { + dev_err(&phydev->mdio.bus->dev, "Failed to setup LED pins\n"); + return PTR_ERR(pinctrl); + } + + return 0; +} + +static int mt7988_phy_probe_shared(struct phy_device *phydev) +{ + struct device_node *np = dev_of_node(&phydev->mdio.bus->dev); + struct mtk_socphy_shared *shared = phydev->shared->priv; + struct regmap *regmap; + u32 reg; + int ret; + + /* The LED0 of the 4 PHYs in MT7988 are wired to SoC pins LED_A, LED_B, + * LED_C and LED_D respectively. At the same time those pins are used to + * bootstrap configuration of the reference clock source (LED_A), + * DRAM DDRx16b x2/x1 (LED_B) and boot device (LED_C, LED_D). + * In practice this is done using a LED and a resistor pulling the pin + * either to GND or to VIO. + * The detected value at boot time is accessible at run-time using the + * TPBANK0 register located in the gpio base of the pinctrl, in order + * to read it here it needs to be referenced by a phandle called + * 'mediatek,pio' in the MDIO bus hosting the PHY. + * The 4 bits in TPBANK0 are kept as package shared data and are used to + * set LED polarity for each of the LED0. + */ + regmap = syscon_regmap_lookup_by_phandle(np, "mediatek,pio"); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regmap_read(regmap, RG_GPIO_MISC_TPBANK0, ®); + if (ret) + return ret; + + shared->boottrap = FIELD_GET(RG_GPIO_MISC_TPBANK0_BOOTMODE, reg); + + return 0; } static int mt7988_phy_probe(struct phy_device *phydev) { - return mt7988_phy_config_init(phydev); + int err; + + if (phydev->mdio.addr > 3) + return -EINVAL; + + err = devm_phy_package_join(&phydev->mdio.dev, phydev, 0, + sizeof(struct mtk_socphy_shared)); + if (err) + return err; + + if (phy_package_probe_once(phydev)) { + err = mt7988_phy_probe_shared(phydev); + if (err) + return err; + } + + /* Disable TX power saving at probing to: + * 1. Meet common mode compliance test criteria + * 2. Make sure that TX-VCM calibration works fine + */ + phy_modify_mmd(phydev, MDIO_MMD_VEND1, MTK_PHY_RXADC_CTRL_RG7, + MTK_PHY_DA_AD_BUF_BIAS_LP_MASK, 0x3 << 8); + + mt7988_phy_setup_led(phydev); + + return mt798x_phy_calibration(phydev); } -static struct phy_driver mtk_gephy_driver[] = { -#if 0 +static int mt7981_phy_probe(struct phy_device *phydev) +{ + return mt798x_phy_calibration(phydev); +} + +static struct phy_driver mtk_socphy_driver[] = { { - PHY_ID_MATCH_EXACT(0x03a29412), - .name = "MediaTek MT7530 PHY", - .config_init = mt7530_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981), + .name = "MediaTek MT7981 PHY", + .config_init = mt798x_phy_config_init, + .read_status = mtk_gphy_cl22_read_status, + .config_intr = genphy_no_config_intr, .handle_interrupt = genphy_no_ack_interrupt, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, + .probe = mt7981_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, }, { - PHY_ID_MATCH_EXACT(0x03a29441), - .name = "MediaTek MT7531 PHY", - .config_init = mt7531_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, + PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988), + .name = "MediaTek MT7988 PHY", + .config_init = mt798x_phy_config_init, + .read_status = mtk_gphy_cl22_read_status, + .config_intr = genphy_no_config_intr, .handle_interrupt = genphy_no_ack_interrupt, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, - }, -#endif - { - PHY_ID_MATCH_EXACT(0x03a29461), - .name = "MediaTek MT7981 PHY", - .config_init = mt7981_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_no_ack_interrupt, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, - }, - { - PHY_ID_MATCH_EXACT(0x03a29481), - .name = "MediaTek MT7988 PHY", - .probe = mt7988_phy_probe, - .config_init = mt7988_phy_config_init, - /* Interrupts are handled by the switch, not the PHY - * itself. - */ - .config_intr = genphy_no_config_intr, - .handle_interrupt = genphy_no_ack_interrupt, - .suspend = genphy_suspend, - .resume = genphy_resume, - .read_page = mtk_gephy_read_page, - .write_page = mtk_gephy_write_page, + .probe = mt7988_phy_probe, + .suspend = genphy_suspend, + .resume = genphy_resume, + .read_page = mtk_phy_read_page, + .write_page = mtk_phy_write_page, }, }; -module_phy_driver(mtk_gephy_driver); +module_phy_driver(mtk_socphy_driver); -static struct mdio_device_id __maybe_unused mtk_gephy_tbl[] = { - { PHY_ID_MATCH_VENDOR(0x03a29400) }, +static struct mdio_device_id __maybe_unused mtk_socphy_tbl[] = { + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7981) }, + { PHY_ID_MATCH_EXACT(MTK_GPHY_ID_MT7988) }, { } }; -MODULE_DESCRIPTION("MediaTek Gigabit Ethernet PHY driver"); -MODULE_AUTHOR("DENG, Qingfang "); +MODULE_DESCRIPTION("MediaTek SoC Gigabit Ethernet PHY driver"); +MODULE_AUTHOR("Daniel Golle "); +MODULE_AUTHOR("SkyLake Huang "); MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(mdio, mtk_gephy_tbl); +MODULE_DEVICE_TABLE(mdio, mtk_socphy_tbl); diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk-phy-lib.c b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk-phy-lib.c new file mode 100644 index 0000000000..9b85c8b1cd --- /dev/null +++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk-phy-lib.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +#include + +#include "mtk.h" + +/* Difference between functions with mtk_tr* and __mtk_tr* prefixes is + * mtk_tr* functions: wrapped by page switching operations + * __mtk_tr* functions: no page switching operations + */ + +static void __mtk_tr_access(struct phy_device *phydev, bool read, u8 ch_addr, + u8 node_addr, u8 data_addr) +{ + u16 tr_cmd = BIT(15); /* bit 14 & 0 are reserved */ + + if (read) + tr_cmd |= BIT(13); + + tr_cmd |= (((ch_addr & 0x3) << 11) | + ((node_addr & 0xf) << 7) | + ((data_addr & 0x3f) << 1)); + dev_dbg(&phydev->mdio.dev, "tr_cmd: 0x%x\n", tr_cmd); + __phy_write(phydev, 0x10, tr_cmd); +} + +static void __mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u16 *tr_high, u16 *tr_low) +{ + __mtk_tr_access(phydev, true, ch_addr, node_addr, data_addr); + *tr_low = __phy_read(phydev, 0x11); + *tr_high = __phy_read(phydev, 0x12); + dev_dbg(&phydev->mdio.dev, "tr_high read: 0x%x, tr_low read: 0x%x\n", + *tr_high, *tr_low); +} + +u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr) +{ + u16 tr_high; + u16 tr_low; + + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); + + return (tr_high << 16) | tr_low; +} +EXPORT_SYMBOL_GPL(mtk_tr_read); + +static void __mtk_tr_write(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 tr_data) +{ + __phy_write(phydev, 0x11, tr_data & 0xffff); + __phy_write(phydev, 0x12, tr_data >> 16); + dev_dbg(&phydev->mdio.dev, "tr_high write: 0x%x, tr_low write: 0x%x\n", + tr_data >> 16, tr_data & 0xffff); + __mtk_tr_access(phydev, false, ch_addr, node_addr, data_addr); +} + +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + u32 tr_data; + u16 tr_high; + u16 tr_low; + + __mtk_tr_read(phydev, ch_addr, node_addr, data_addr, &tr_high, &tr_low); + tr_data = (tr_high << 16) | tr_low; + tr_data = (tr_data & ~mask) | set; + __mtk_tr_write(phydev, ch_addr, node_addr, data_addr, tr_data); +} +EXPORT_SYMBOL_GPL(__mtk_tr_modify); + +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set) +{ + phy_select_page(phydev, MTK_PHY_PAGE_EXTENDED_52B5); + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, mask, set); + phy_restore_page(phydev, MTK_PHY_PAGE_STANDARD, 0); +} +EXPORT_SYMBOL_GPL(mtk_tr_modify); + +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, 0, set); +} +EXPORT_SYMBOL_GPL(__mtk_tr_set_bits); + +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr) +{ + __mtk_tr_modify(phydev, ch_addr, node_addr, data_addr, clr, 0); +} +EXPORT_SYMBOL_GPL(__mtk_tr_clr_bits); + +int mtk_phy_read_page(struct phy_device *phydev) +{ + return __phy_read(phydev, MTK_EXT_PAGE_ACCESS); +} +EXPORT_SYMBOL_GPL(mtk_phy_read_page); + +int mtk_phy_write_page(struct phy_device *phydev, int page) +{ + return __phy_write(phydev, MTK_EXT_PAGE_ACCESS, page); +} +EXPORT_SYMBOL_GPL(mtk_phy_write_page); + +/* This function deals with the case that 1G AN starts but isn't completed. We + * set AN_NEW_LP_CNT_LIMIT with different values time after time to let our + * 1G->100Mbps hardware automatic downshift to fit more partner devices. + */ +static int extend_an_new_lp_cnt_limit(struct phy_device *phydev) +{ + int mmd_read_ret; + u32 reg_val; + int timeout; + + /* According to table 28-9 & Figure 28-18 in IEEE 802.3, + * link_fail_inhibit_timer of 10/100/1000 Mbps devices ranges from 750 + * to "1000ms". Once MTK_PHY_FINAL_SPEED_1000 is set, it means that we + * enter "FLP LINK GOOD CHECK" state, link_fail_inhibit_timer starts and + * this PHY's 1G training starts. If 1G training never starts, we do + * nothing but leave. + */ + timeout = read_poll_timeout(mmd_read_ret = phy_read_mmd, reg_val, + (mmd_read_ret < 0) || + reg_val & MTK_PHY_FINAL_SPEED_1000, + 10000, 1000000, false, phydev, + MDIO_MMD_VEND1, MTK_PHY_LINK_STATUS_MISC); + if (mmd_read_ret < 0) + return mmd_read_ret; + + if (!timeout) { + /* Once we found MTK_PHY_FINAL_SPEED_1000 is set, no matter 1G + * AN is completed or not, we'll set AN_NEW_LP_CNT_LIMIT again + * and again. + */ + mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, AN_NEW_LP_CNT_LIMIT_MASK, + FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, 0xf)); + mdelay(1500); + + timeout = read_poll_timeout(mtk_tr_read, reg_val, + (reg_val & AN_STATE_MASK) != + (AN_STATE_TX_DISABLE << + AN_STATE_SHIFT), + 10000, 1000000, false, phydev, + 0x0, 0xf, 0x2); + if (!timeout) { + mdelay(625); + mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, + AN_NEW_LP_CNT_LIMIT_MASK, + FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, + 0x8)); + mdelay(500); + mtk_tr_modify(phydev, 0x0, 0xf, 0x3c, + AN_NEW_LP_CNT_LIMIT_MASK, + FIELD_PREP(AN_NEW_LP_CNT_LIMIT_MASK, + 0xf)); + } else { + return -ETIMEDOUT; + } + } + + return 0; +} + +int mtk_gphy_cl22_read_status(struct phy_device *phydev) +{ + int ret; + + ret = genphy_read_status(phydev); + if (ret) + return ret; + + if (phydev->autoneg == AUTONEG_ENABLE && !phydev->autoneg_complete) { + ret = phy_read_paged(phydev, MTK_PHY_PAGE_EXTENDED_1, + MTK_PHY_AUX_CTRL_AND_STATUS); + if (ret < 0) + return ret; + + /* Once LP_DETECTED is set, it means that"ability_match" in + * IEEE 802.3 Figure 28-18 is set. This happens after we plug in + * cable. Also, LP_DETECTED will be cleared after AN complete. + */ + if (!FIELD_GET(MTK_PHY_LP_DETECTED_MASK, ret)) + return 0; + + ret = phy_read(phydev, MII_CTRL1000); + if (ret & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) { + ret = extend_an_new_lp_cnt_limit(phydev); + if (ret < 0) + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_gphy_cl22_read_status); + +#if 0 +int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers) +{ + if (index > 1) + return -EINVAL; + + /* All combinations of the supported triggers are allowed */ + if (rules & ~supported_triggers) + return -EOPNOTSUPP; + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_is_supported); + +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, unsigned long *led_state, + u16 on_set, u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + int on, blink; + + if (index > 1) + return -EINVAL; + + on = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL); + + if (on < 0) + return -EIO; + + blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, + index ? MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL); + if (blink < 0) + return -EIO; + + if ((on & (on_set | MTK_PHY_LED_ON_FDX | + MTK_PHY_LED_ON_HDX | MTK_PHY_LED_ON_LINKDOWN)) || + (blink & (rx_blink_set | tx_blink_set))) + set_bit(bit_netdev, led_state); + else + clear_bit(bit_netdev, led_state); + + if (on & MTK_PHY_LED_ON_FORCE_ON) + set_bit(bit_on, led_state); + else + clear_bit(bit_on, led_state); + + if (blink & MTK_PHY_LED_BLINK_FORCE_BLINK) + set_bit(bit_blink, led_state); + else + clear_bit(bit_blink, led_state); + + if (!rules) + return 0; + + if (on & on_set) + *rules |= BIT(TRIGGER_NETDEV_LINK); + + if (on & MTK_PHY_LED_ON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); + + if (on & MTK_PHY_LED_ON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); + + if (on & MTK_PHY_LED_ON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); + + if (on & MTK_PHY_LED_ON_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + + if (on & MTK_PHY_LED_ON_FDX) + *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); + + if (on & MTK_PHY_LED_ON_HDX) + *rules |= BIT(TRIGGER_NETDEV_HALF_DUPLEX); + + if (blink & rx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_RX); + + if (blink & tx_blink_set) + *rules |= BIT(TRIGGER_NETDEV_TX); + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_get); + +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, unsigned long *led_state, + u16 on_set, u16 rx_blink_set, u16 tx_blink_set) +{ + unsigned int bit_netdev = MTK_PHY_LED_STATE_NETDEV + (index ? 16 : 0); + u16 on = 0, blink = 0; + int ret; + + if (index > 1) + return -EINVAL; + + if (rules & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) + on |= MTK_PHY_LED_ON_FDX; + + if (rules & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) + on |= MTK_PHY_LED_ON_HDX; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK10; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK100; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK1000; + + if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK))) + on |= MTK_PHY_LED_ON_LINK2500; + + if (rules & BIT(TRIGGER_NETDEV_RX)) { + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10RX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100RX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000RX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500RX; + } else { + blink |= rx_blink_set; + } + } + + if (rules & BIT(TRIGGER_NETDEV_TX)) { + if (on & on_set) { + if (on & MTK_PHY_LED_ON_LINK10) + blink |= MTK_PHY_LED_BLINK_10TX; + if (on & MTK_PHY_LED_ON_LINK100) + blink |= MTK_PHY_LED_BLINK_100TX; + if (on & MTK_PHY_LED_ON_LINK1000) + blink |= MTK_PHY_LED_BLINK_1000TX; + if (on & MTK_PHY_LED_ON_LINK2500) + blink |= MTK_PHY_LED_BLINK_2500TX; + } else { + blink |= tx_blink_set; + } + } + + if (blink || on) + set_bit(bit_netdev, led_state); + else + clear_bit(bit_netdev, led_state); + + ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : MTK_PHY_LED0_ON_CTRL, + MTK_PHY_LED_ON_FDX | MTK_PHY_LED_ON_HDX | on_set, + on); + + if (ret) + return ret; + + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, blink); +} +EXPORT_SYMBOL_GPL(mtk_phy_led_hw_ctrl_set); + +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking) +{ + if (index > 1) + return -EINVAL; + + if (delay_on && delay_off && (*delay_on > 0) && (*delay_off > 0)) { + *blinking = true; + *delay_on = 50; + *delay_off = 50; + } + + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_led_num_dly_cfg); + +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + unsigned long *led_state, u16 led_on_mask, bool on) +{ + unsigned int bit_on = MTK_PHY_LED_STATE_FORCE_ON + (index ? 16 : 0); + bool changed; + + if (on) + changed = !test_and_set_bit(bit_on, led_state); + else + changed = !!test_and_clear_bit(bit_on, led_state); + + changed |= !!test_and_clear_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), led_state); + if (changed) + return phy_modify_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_ON_CTRL : + MTK_PHY_LED0_ON_CTRL, + led_on_mask, + on ? MTK_PHY_LED_ON_FORCE_ON : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_on_set); + +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *led_state, bool blinking) +{ + unsigned int bit_blink = MTK_PHY_LED_STATE_FORCE_BLINK + + (index ? 16 : 0); + bool changed; + + if (blinking) + changed = !test_and_set_bit(bit_blink, led_state); + else + changed = !!test_and_clear_bit(bit_blink, led_state); + + changed |= !!test_bit(MTK_PHY_LED_STATE_NETDEV + + (index ? 16 : 0), led_state); + if (changed) + return phy_write_mmd(phydev, MDIO_MMD_VEND2, index ? + MTK_PHY_LED1_BLINK_CTRL : + MTK_PHY_LED0_BLINK_CTRL, + blinking ? + MTK_PHY_LED_BLINK_FORCE_BLINK : 0); + else + return 0; +} +EXPORT_SYMBOL_GPL(mtk_phy_hw_led_blink_set); + +void mtk_phy_leds_state_init(struct phy_device *phydev) +{ + int i; + + for (i = 0; i < 2; ++i) + phydev->drv->led_hw_control_get(phydev, i, NULL); +} +EXPORT_SYMBOL_GPL(mtk_phy_leds_state_init); +#endif + +MODULE_DESCRIPTION("MediaTek Ethernet PHY driver common"); +MODULE_AUTHOR("Sky Huang "); +MODULE_AUTHOR("Daniel Golle "); +MODULE_LICENSE("GPL"); diff --git a/target/linux/mediatek/files-5.4/drivers/net/phy/mtk.h b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk.h new file mode 100644 index 0000000000..2a50bf2a16 --- /dev/null +++ b/target/linux/mediatek/files-5.4/drivers/net/phy/mtk.h @@ -0,0 +1,119 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Common definition for Mediatek Ethernet PHYs + * Author: SkyLake Huang + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef _MTK_EPHY_H_ +#define _MTK_EPHY_H_ + +#define MTK_EXT_PAGE_ACCESS 0x1f +#define MTK_PHY_PAGE_STANDARD 0x0000 +#define MTK_PHY_PAGE_EXTENDED_1 0x0001 +#define MTK_PHY_AUX_CTRL_AND_STATUS 0x14 +/* suprv_media_select_RefClk */ +#define MTK_PHY_LP_DETECTED_MASK GENMASK(7, 6) +#define MTK_PHY_ENABLE_DOWNSHIFT BIT(4) + +#define MTK_PHY_PAGE_EXTENDED_52B5 0x52b5 + +/* Registers on Token Ring debug nodes */ +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x2 */ +#define AN_STATE_MASK GENMASK(22, 19) +#define AN_STATE_SHIFT 19 +#define AN_STATE_TX_DISABLE 1 + +/* ch_addr = 0x0, node_addr = 0xf, data_addr = 0x3c */ +#define AN_NEW_LP_CNT_LIMIT_MASK GENMASK(23, 20) +#define AUTO_NP_10XEN BIT(6) + +/* Registers on MDIO_MMD_VEND1 */ +#define MTK_PHY_LINK_STATUS_MISC (0xa2) +#define MTK_PHY_FINAL_SPEED_1000 BIT(3) + +/* Registers on MDIO_MMD_VEND2 */ +#define MTK_PHY_LED0_ON_CTRL 0x24 +#define MTK_PHY_LED1_ON_CTRL 0x26 +#define MTK_GPHY_LED_ON_MASK GENMASK(6, 0) +#define MTK_2P5GPHY_LED_ON_MASK GENMASK(7, 0) +#define MTK_PHY_LED_ON_LINK1000 BIT(0) +#define MTK_PHY_LED_ON_LINK100 BIT(1) +#define MTK_PHY_LED_ON_LINK10 BIT(2) +#define MTK_PHY_LED_ON_LINKDOWN BIT(3) +#define MTK_PHY_LED_ON_FDX BIT(4) /* Full duplex */ +#define MTK_PHY_LED_ON_HDX BIT(5) /* Half duplex */ +#define MTK_PHY_LED_ON_FORCE_ON BIT(6) +#define MTK_PHY_LED_ON_LINK2500 BIT(7) +#define MTK_PHY_LED_ON_POLARITY BIT(14) +#define MTK_PHY_LED_ON_ENABLE BIT(15) + +#define MTK_PHY_LED0_BLINK_CTRL 0x25 +#define MTK_PHY_LED1_BLINK_CTRL 0x27 +#define MTK_PHY_LED_BLINK_1000TX BIT(0) +#define MTK_PHY_LED_BLINK_1000RX BIT(1) +#define MTK_PHY_LED_BLINK_100TX BIT(2) +#define MTK_PHY_LED_BLINK_100RX BIT(3) +#define MTK_PHY_LED_BLINK_10TX BIT(4) +#define MTK_PHY_LED_BLINK_10RX BIT(5) +#define MTK_PHY_LED_BLINK_COLLISION BIT(6) +#define MTK_PHY_LED_BLINK_RX_CRC_ERR BIT(7) +#define MTK_PHY_LED_BLINK_RX_IDLE_ERR BIT(8) +#define MTK_PHY_LED_BLINK_FORCE_BLINK BIT(9) +#define MTK_PHY_LED_BLINK_2500TX BIT(10) +#define MTK_PHY_LED_BLINK_2500RX BIT(11) + +#define MTK_GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK1000 | \ + MTK_PHY_LED_ON_LINK100 | \ + MTK_PHY_LED_ON_LINK10) +#define MTK_GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) +#define MTK_GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_1000RX | \ + MTK_PHY_LED_BLINK_100RX | \ + MTK_PHY_LED_BLINK_10RX) + +#define MTK_2P5GPHY_LED_ON_SET (MTK_PHY_LED_ON_LINK2500 | \ + MTK_GPHY_LED_ON_SET) +#define MTK_2P5GPHY_LED_RX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_RX_BLINK_SET) +#define MTK_2P5GPHY_LED_TX_BLINK_SET (MTK_PHY_LED_BLINK_2500RX | \ + MTK_GPHY_LED_TX_BLINK_SET) + +#define MTK_PHY_LED_STATE_FORCE_ON 0 +#define MTK_PHY_LED_STATE_FORCE_BLINK 1 +#define MTK_PHY_LED_STATE_NETDEV 2 + +u32 mtk_tr_read(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr); +void __mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); +void mtk_tr_modify(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 mask, u32 set); +void __mtk_tr_set_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 set); +void __mtk_tr_clr_bits(struct phy_device *phydev, u8 ch_addr, u8 node_addr, + u8 data_addr, u32 clr); + +int mtk_phy_read_page(struct phy_device *phydev); +int mtk_phy_write_page(struct phy_device *phydev, int page); + +int mtk_gphy_cl22_read_status(struct phy_device *phydev); +/*int mtk_phy_led_hw_is_supported(struct phy_device *phydev, u8 index, + unsigned long rules, + unsigned long supported_triggers); +int mtk_phy_led_hw_ctrl_set(struct phy_device *phydev, u8 index, + unsigned long rules, unsigned long *led_state, + u16 on_set, u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, + unsigned long *rules, unsigned long *led_state, + u16 on_set, u16 rx_blink_set, u16 tx_blink_set); +int mtk_phy_led_num_dly_cfg(u8 index, unsigned long *delay_on, + unsigned long *delay_off, bool *blinking); +int mtk_phy_hw_led_on_set(struct phy_device *phydev, u8 index, + unsigned long *led_state, u16 led_on_mask, bool on); +int mtk_phy_hw_led_blink_set(struct phy_device *phydev, u8 index, + unsigned long *led_state, bool blinking); +void mtk_phy_leds_state_init(struct phy_device *phydev);*/ + +#endif /* _MTK_EPHY_H_ */ diff --git a/target/linux/mediatek/mt7981/config-5.4 b/target/linux/mediatek/mt7981/config-5.4 index 3024f6965e..75b470eae3 100644 --- a/target/linux/mediatek/mt7981/config-5.4 +++ b/target/linux/mediatek/mt7981/config-5.4 @@ -284,7 +284,7 @@ CONFIG_MD=y CONFIG_MDIO_BUS=y CONFIG_MDIO_DEVICE=y # CONFIG_MEDIATEK_2P5GE_PHY is not set -# CONFIG_MEDIATEK_GE_PHY is not set +CONFIG_MEDIATEK_GE_PHY=y CONFIG_MEDIATEK_MT6577_AUXADC=y # CONFIG_MEDIATEK_NETSYS_RX_V2 is not set CONFIG_MEDIATEK_NETSYS_V2=y diff --git a/target/linux/mediatek/patches-5.4/746-mxl-gpy-phy-support.patch b/target/linux/mediatek/patches-5.4/746-mxl-gpy-phy-support.patch index 26bef5fb65..691c4d45f8 100644 --- a/target/linux/mediatek/patches-5.4/746-mxl-gpy-phy-support.patch +++ b/target/linux/mediatek/patches-5.4/746-mxl-gpy-phy-support.patch @@ -771,34 +771,3 @@ index 0000000..7304278 +MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver"); +MODULE_AUTHOR("Xu Liang"); +MODULE_LICENSE("GPL"); -diff --git a/include/linux/phy.h b/include/linux/phy.h -index 19444cd..34bdd16 100644 ---- a/include/linux/phy.h -+++ b/include/linux/phy.h -@@ -21,6 +21,7 @@ - #include - #include - #include -+#include - - #include - -@@ -711,6 +712,18 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) - return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum); - } - -+#define phy_read_poll_timeout(phydev, regnum, val, cond, sleep_us, \ -+ timeout_us, sleep_before_read) \ -+({ \ -+ int __ret = read_poll_timeout(phy_read, val, (cond) || val < 0, \ -+ sleep_us, timeout_us, sleep_before_read, phydev, regnum); \ -+ if (val < 0) \ -+ __ret = val; \ -+ if (__ret) \ -+ phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ -+ __ret; \ -+}) -+ - /** - * __phy_read - convenience function for reading a given PHY register - * @phydev: the phy_device struct diff --git a/target/linux/mediatek/patches-5.4/753-add-mtk-phy-lib.patch b/target/linux/mediatek/patches-5.4/753-add-mtk-phy-lib.patch new file mode 100644 index 0000000000..8ebb4a6ba4 --- /dev/null +++ b/target/linux/mediatek/patches-5.4/753-add-mtk-phy-lib.patch @@ -0,0 +1,7 @@ +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -119,3 +119,4 @@ obj-$(CONFIG_AIR_EN8811H_PHY) += air_e + obj-$(CONFIG_MT753X_GSW) += mtk/mt753x/ + obj-$(CONFIG_RTL8367S_GSW) += rtk/ + ++obj-$(CONFIG_MEDIATEK_GE_PHY) += mtk-phy-lib.o diff --git a/target/linux/mediatek/patches-5.4/0030-introduce_read_poll_timeout_macro.patch b/target/linux/mediatek/patches-5.4/999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch similarity index 50% rename from target/linux/mediatek/patches-5.4/0030-introduce_read_poll_timeout_macro.patch rename to target/linux/mediatek/patches-5.4/999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch index e22703785d..d7fc25cdb7 100644 --- a/target/linux/mediatek/patches-5.4/0030-introduce_read_poll_timeout_macro.patch +++ b/target/linux/mediatek/patches-5.4/999-1021-v5.7-iopoll-introduce-read_poll_timeout-macro.patch @@ -1,5 +1,45 @@ +From bc97a676615bd0ec66bb2a2a42c939455bf5bed6 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Fri, 2 Jun 2023 13:06:27 +0800 +Subject: [PATCH] + [networking][999-2700-v5.7-iopoll-introduce-read_poll_timeout-macro.patch] + +--- + drivers/net/phy/phy_device.c | 16 +++++---------- + include/linux/iopoll.h | 40 +++++++++++++++++++++++++++++------- + include/linux/phy.h | 27 ++++++++++++++++++++++++ + 3 files changed, 65 insertions(+), 18 deletions(-) + +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 76a68bb02..0349801df 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1056,18 +1056,12 @@ EXPORT_SYMBOL(phy_disconnect); + static int phy_poll_reset(struct phy_device *phydev) + { + /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ +- unsigned int retries = 12; +- int ret; +- +- do { +- msleep(50); +- ret = phy_read(phydev, MII_BMCR); +- if (ret < 0) +- return ret; +- } while (ret & BMCR_RESET && --retries); +- if (ret & BMCR_RESET) +- return -ETIMEDOUT; ++ int ret, val; + ++ ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET), ++ 50000, 600000, true); ++ if (ret) ++ return ret; + /* Some chips (smsc911x) may still need up to another 1ms after the + * BMCR_RESET bit is cleared before they are usable. + */ diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h -index 35e15df..2c8860e 100644 +index 35e15dfd4..cb20c733b 100644 --- a/include/linux/iopoll.h +++ b/include/linux/iopoll.h @@ -14,36 +14,41 @@ @@ -51,56 +91,7 @@ index 35e15df..2c8860e 100644 break; \ } \ if (__sleep_us) \ -@@ -53,42 +58,87 @@ - }) - - /** -- * readx_poll_timeout_atomic - Periodically poll an address until a condition is met or a timeout occurs -- * @op: accessor function (takes @addr as its only argument) -- * @addr: Address to poll -+ * read_poll_timeout_atomic - Periodically poll an address until a condition is -+ * met or a timeout occurs -+ * @op: accessor function (takes @args as its arguments) - * @val: Variable to read the value into - * @cond: Break condition (usually involving @val) - * @delay_us: Time to udelay between reads in us (0 tight-loops). Should - * be less than ~10us since udelay is used (see - * Documentation/timers/timers-howto.rst). - * @timeout_us: Timeout in us, 0 means never timeout -+ * @delay_before_read: if it is true, delay @delay_us before read. -+ * @args: arguments for @op poll - * - * Returns 0 on success and -ETIMEDOUT upon a timeout. In either -- * case, the last read value at @addr is stored in @val. -+ * case, the last read value at @args is stored in @val. - * - * When available, you'll probably want to use one of the specialized - * macros defined below rather than this macro directly. - */ --#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \ -+#define read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, \ -+ delay_before_read, args...) \ - ({ \ - u64 __timeout_us = (timeout_us); \ - unsigned long __delay_us = (delay_us); \ - ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \ -+ if (delay_before_read && __delay_us) \ -+ udelay(__delay_us); \ - for (;;) { \ -- (val) = op(addr); \ -+ (val) = op(args); \ - if (cond) \ - break; \ - if (__timeout_us && \ - ktime_compare(ktime_get(), __timeout) > 0) { \ -- (val) = op(addr); \ -+ (val) = op(args); \ - break; \ - } \ - if (__delay_us) \ -- udelay(__delay_us); \ -+ udelay(__delay_us); \ - } \ +@@ -52,6 +57,27 @@ (cond) ? 0 : -ETIMEDOUT; \ }) @@ -125,25 +116,61 @@ index 35e15df..2c8860e 100644 +#define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \ + read_poll_timeout(op, val, cond, sleep_us, timeout_us, false, addr) + -+/** -+ * readx_poll_timeout_atomic - Periodically poll an address until a condition is met or a timeout occurs -+ * @op: accessor function (takes @addr as its only argument) -+ * @addr: Address to poll -+ * @val: Variable to read the value into -+ * @cond: Break condition (usually involving @val) -+ * @delay_us: Time to udelay between reads in us (0 tight-loops). Should -+ * be less than ~10us since udelay is used (see -+ * Documentation/timers/timers-howto.rst). -+ * @timeout_us: Timeout in us, 0 means never timeout -+ * -+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either -+ * case, the last read value at @addr is stored in @val. -+ * -+ * When available, you'll probably want to use one of the specialized -+ * macros defined below rather than this macro directly. -+ */ -+#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \ -+ read_poll_timeout_atomic(op, val, cond, delay_us, timeout_us, false, addr) + /** + * readx_poll_timeout_atomic - Periodically poll an address until a condition is met or a timeout occurs + * @op: accessor function (takes @addr as its only argument) +diff --git a/include/linux/phy.h b/include/linux/phy.h +index a1070d60e..107dcbea4 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include - #define readb_poll_timeout(addr, val, cond, delay_us, timeout_us) \ - readx_poll_timeout(readb, addr, val, cond, delay_us, timeout_us) + #include + +@@ -714,6 +715,19 @@ static inline int phy_read(struct phy_device *phydev, u32 regnum) + return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum); + } + ++#define phy_read_poll_timeout(phydev, regnum, val, cond, sleep_us, \ ++ timeout_us, sleep_before_read) \ ++({ \ ++ int __ret = read_poll_timeout(phy_read, val, (cond) || val < 0, \ ++ sleep_us, timeout_us, sleep_before_read, phydev, regnum); \ ++ if (val < 0) \ ++ __ret = val; \ ++ if (__ret) \ ++ phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ ++ __ret; \ ++}) ++ ++ + /** + * __phy_read - convenience function for reading a given PHY register + * @phydev: the phy_device struct +@@ -766,6 +780,19 @@ static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val) + */ + int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum); + ++#define phy_read_mmd_poll_timeout(phydev, devaddr, regnum, val, cond, \ ++ sleep_us, timeout_us, sleep_before_read) \ ++({ \ ++ int __ret = read_poll_timeout(phy_read_mmd, val, (cond) || val < 0, \ ++ sleep_us, timeout_us, sleep_before_read, \ ++ phydev, devaddr, regnum); \ ++ if (val < 0) \ ++ __ret = val; \ ++ if (__ret) \ ++ phydev_err(phydev, "%s failed: %d\n", __func__, __ret); \ ++ __ret; \ ++}) ++ + /** + * __phy_read_mmd - Convenience function for reading a register + * from an MMD on a given PHY. +-- +2.34.1 + diff --git a/target/linux/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch b/target/linux/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch new file mode 100644 index 0000000000..e74f20b7bb --- /dev/null +++ b/target/linux/mediatek/patches-5.4/999-1700-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch @@ -0,0 +1,311 @@ +From 2dca4de7282d3003f3703f707d773f4dbbc0f28e Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Fri, 2 Jun 2023 13:06:27 +0800 +Subject: [PATCH] + [networking][999-2701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch] + +--- + drivers/net/phy/mdio_bus.c | 1 + + drivers/net/phy/phy_device.c | 138 +++++++++++++++++++++++++++++++++++ + include/linux/phy.h | 89 ++++++++++++++++++++++ + 3 files changed, 228 insertions(+) + +diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c +index fdf8221f4..d9f2cee33 100644 +--- a/drivers/net/phy/mdio_bus.c ++++ b/drivers/net/phy/mdio_bus.c +@@ -404,6 +404,7 @@ int __mdiobus_register(struct mii_bus *bus, struct module *owner) + } + + mutex_init(&bus->mdio_lock); ++ mutex_init(&bus->shared_lock); + + /* de-assert bus level PHY GPIO reset */ + gpiod = devm_gpiod_get_optional(&bus->dev, "reset", GPIOD_OUT_LOW); +diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c +index 0349801df..99f265a1c 100644 +--- a/drivers/net/phy/phy_device.c ++++ b/drivers/net/phy/phy_device.c +@@ -1447,6 +1447,144 @@ bool phy_driver_is_genphy_10g(struct phy_device *phydev) + } + EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g); + ++/** ++ * phy_package_join - join a common PHY group ++ * @phydev: target phy_device struct ++ * @addr: cookie and PHY address for global register access ++ * @priv_size: if non-zero allocate this amount of bytes for private data ++ * ++ * This joins a PHY group and provides a shared storage for all phydevs in ++ * this group. This is intended to be used for packages which contain ++ * more than one PHY, for example a quad PHY transceiver. ++ * ++ * The addr parameter serves as a cookie which has to have the same value ++ * for all members of one group and as a PHY address to access generic ++ * registers of a PHY package. Usually, one of the PHY addresses of the ++ * different PHYs in the package provides access to these global registers. ++ * The address which is given here, will be used in the phy_package_read() ++ * and phy_package_write() convenience functions. If your PHY doesn't have ++ * global registers you can just pick any of the PHY addresses. ++ * ++ * This will set the shared pointer of the phydev to the shared storage. ++ * If this is the first call for a this cookie the shared storage will be ++ * allocated. If priv_size is non-zero, the given amount of bytes are ++ * allocated for the priv member. ++ * ++ * Returns < 1 on error, 0 on success. Esp. calling phy_package_join() ++ * with the same cookie but a different priv_size is an error. ++ */ ++int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size) ++{ ++ struct mii_bus *bus = phydev->mdio.bus; ++ struct phy_package_shared *shared; ++ int ret; ++ ++ if (addr < 0 || addr >= PHY_MAX_ADDR) ++ return -EINVAL; ++ ++ mutex_lock(&bus->shared_lock); ++ shared = bus->shared[addr]; ++ if (!shared) { ++ ret = -ENOMEM; ++ shared = kzalloc(sizeof(*shared), GFP_KERNEL); ++ if (!shared) ++ goto err_unlock; ++ if (priv_size) { ++ shared->priv = kzalloc(priv_size, GFP_KERNEL); ++ if (!shared->priv) ++ goto err_free; ++ shared->priv_size = priv_size; ++ } ++ shared->addr = addr; ++ refcount_set(&shared->refcnt, 1); ++ bus->shared[addr] = shared; ++ } else { ++ ret = -EINVAL; ++ if (priv_size && priv_size != shared->priv_size) ++ goto err_unlock; ++ refcount_inc(&shared->refcnt); ++ } ++ mutex_unlock(&bus->shared_lock); ++ ++ phydev->shared = shared; ++ ++ return 0; ++ ++err_free: ++ kfree(shared); ++err_unlock: ++ mutex_unlock(&bus->shared_lock); ++ return ret; ++} ++EXPORT_SYMBOL_GPL(phy_package_join); ++ ++/** ++ * phy_package_leave - leave a common PHY group ++ * @phydev: target phy_device struct ++ * ++ * This leaves a PHY group created by phy_package_join(). If this phydev ++ * was the last user of the shared data between the group, this data is ++ * freed. Resets the phydev->shared pointer to NULL. ++ */ ++void phy_package_leave(struct phy_device *phydev) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ struct mii_bus *bus = phydev->mdio.bus; ++ ++ if (!shared) ++ return; ++ ++ if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { ++ bus->shared[shared->addr] = NULL; ++ mutex_unlock(&bus->shared_lock); ++ kfree(shared->priv); ++ kfree(shared); ++ } ++ ++ phydev->shared = NULL; ++} ++EXPORT_SYMBOL_GPL(phy_package_leave); ++ ++static void devm_phy_package_leave(struct device *dev, void *res) ++{ ++ phy_package_leave(*(struct phy_device **)res); ++} ++ ++/** ++ * devm_phy_package_join - resource managed phy_package_join() ++ * @dev: device that is registering this PHY package ++ * @phydev: target phy_device struct ++ * @addr: cookie and PHY address for global register access ++ * @priv_size: if non-zero allocate this amount of bytes for private data ++ * ++ * Managed phy_package_join(). Shared storage fetched by this function, ++ * phy_package_leave() is automatically called on driver detach. See ++ * phy_package_join() for more information. ++ */ ++int devm_phy_package_join(struct device *dev, struct phy_device *phydev, ++ int addr, size_t priv_size) ++{ ++ struct phy_device **ptr; ++ int ret; ++ ++ ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr), ++ GFP_KERNEL); ++ if (!ptr) ++ return -ENOMEM; ++ ++ ret = phy_package_join(phydev, addr, priv_size); ++ ++ if (!ret) { ++ *ptr = phydev; ++ devres_add(dev, ptr); ++ } else { ++ devres_free(ptr); ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(devm_phy_package_join); ++ + /** + * phy_detach - detach a PHY device from its network device + * @phydev: target phy_device struct +diff --git a/include/linux/phy.h b/include/linux/phy.h +index 107dcbea4..d26dba255 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + + #include + +@@ -211,6 +212,28 @@ struct sfp_bus; + struct sfp_upstream_ops; + struct sk_buff; + ++/* Represents a shared structure between different phydev's in the same ++ * package, for example a quad PHY. See phy_package_join() and ++ * phy_package_leave(). ++ */ ++struct phy_package_shared { ++ int addr; ++ refcount_t refcnt; ++ unsigned long flags; ++ size_t priv_size; ++ ++ /* private data pointer */ ++ /* note that this pointer is shared between different phydevs and ++ * the user has to take care of appropriate locking. It is allocated ++ * and freed automatically by phy_package_join() and ++ * phy_package_leave(). ++ */ ++ void *priv; ++}; ++ ++/* used as bit number in atomic bitops */ ++#define PHY_SHARED_F_INIT_DONE 0 ++ + /* + * The Bus class for PHYs. Devices which provide access to + * PHYs should register using this structure +@@ -258,6 +281,12 @@ struct mii_bus { + int reset_delay_us; + /* RESET GPIO descriptor pointer */ + struct gpio_desc *reset_gpiod; ++ ++ /* protect access to the shared element */ ++ struct mutex shared_lock; ++ ++ /* shared state across different PHYs */ ++ struct phy_package_shared *shared[PHY_MAX_ADDR]; + }; + #define to_mii_bus(d) container_of(d, struct mii_bus, dev) + +@@ -437,6 +466,10 @@ struct phy_device { + /* For use by PHYs to maintain extra state */ + void *priv; + ++ /* shared data pointer */ ++ /* For use by PHYs inside the same package that need a shared state. */ ++ struct phy_package_shared *shared; ++ + /* Interrupt and Polling infrastructure */ + struct delayed_work state_queue; + +@@ -1242,6 +1275,10 @@ int phy_ethtool_get_link_ksettings(struct net_device *ndev, + int phy_ethtool_set_link_ksettings(struct net_device *ndev, + const struct ethtool_link_ksettings *cmd); + int phy_ethtool_nway_reset(struct net_device *ndev); ++int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size); ++void phy_package_leave(struct phy_device *phydev); ++int devm_phy_package_join(struct device *dev, struct phy_device *phydev, ++ int addr, size_t priv_size); + + #if IS_ENABLED(CONFIG_PHYLIB) + int __init mdio_bus_init(void); +@@ -1294,6 +1331,58 @@ static inline int phy_ethtool_get_stats(struct phy_device *phydev, + return 0; + } + ++static inline int phy_package_read(struct phy_device *phydev, u32 regnum) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ ++ if (!shared) ++ return -EIO; ++ ++ return mdiobus_read(phydev->mdio.bus, shared->addr, regnum); ++} ++ ++static inline int __phy_package_read(struct phy_device *phydev, u32 regnum) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ ++ if (!shared) ++ return -EIO; ++ ++ return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum); ++} ++ ++static inline int phy_package_write(struct phy_device *phydev, ++ u32 regnum, u16 val) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ ++ if (!shared) ++ return -EIO; ++ ++ return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); ++} ++ ++static inline int __phy_package_write(struct phy_device *phydev, ++ u32 regnum, u16 val) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ ++ if (!shared) ++ return -EIO; ++ ++ return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); ++} ++ ++static inline bool phy_package_init_once(struct phy_device *phydev) ++{ ++ struct phy_package_shared *shared = phydev->shared; ++ ++ if (!shared) ++ return false; ++ ++ return !test_and_set_bit(PHY_SHARED_F_INIT_DONE, &shared->flags); ++} ++ + extern struct bus_type mdio_bus_type; + + struct mdio_board_info { +-- +2.34.1 + diff --git a/target/linux/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch b/target/linux/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch new file mode 100644 index 0000000000..c2f2c108ec --- /dev/null +++ b/target/linux/mediatek/patches-5.4/999-1701-v5.8-net-phy-add-concept-of-shared-storage-for-PHYs.patch @@ -0,0 +1,55 @@ +From 3fc10755d5f6a5618519f2b5b3a68febfc5984b0 Mon Sep 17 00:00:00 2001 +From: Sam Shih +Date: Fri, 2 Jun 2023 13:06:27 +0800 +Subject: [PATCH] + [networking][999-2702-v5.9-net-phy-add-support-for-a-common-probe-between-shared-PHYs.patch] + +--- + include/linux/phy.h | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/include/linux/phy.h b/include/linux/phy.h +index d26dba255..4f2c105f5 100644 +--- a/include/linux/phy.h ++++ b/include/linux/phy.h +@@ -232,7 +232,8 @@ struct phy_package_shared { + }; + + /* used as bit number in atomic bitops */ +-#define PHY_SHARED_F_INIT_DONE 0 ++#define PHY_SHARED_F_INIT_DONE 0 ++#define PHY_SHARED_F_PROBE_DONE 1 + + /* + * The Bus class for PHYs. Devices which provide access to +@@ -1373,14 +1374,25 @@ static inline int __phy_package_write(struct phy_device *phydev, + return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); + } + +-static inline bool phy_package_init_once(struct phy_device *phydev) ++static inline bool __phy_package_set_once(struct phy_device *phydev, ++ unsigned int b) + { + struct phy_package_shared *shared = phydev->shared; + + if (!shared) + return false; + +- return !test_and_set_bit(PHY_SHARED_F_INIT_DONE, &shared->flags); ++ return !test_and_set_bit(b, &shared->flags); ++} ++ ++static inline bool phy_package_init_once(struct phy_device *phydev) ++{ ++ return __phy_package_set_once(phydev, PHY_SHARED_F_INIT_DONE); ++} ++ ++static inline bool phy_package_probe_once(struct phy_device *phydev) ++{ ++ return __phy_package_set_once(phydev, PHY_SHARED_F_PROBE_DONE); + } + + extern struct bus_type mdio_bus_type; +-- +2.34.1 +