diff --git a/drivers/net/phy/nxp-c45-tja11xx.c b/drivers/net/phy/nxp-c45-tja11xx.c index f1f15a1b6cfc7..d5981985b320d 100644 --- a/drivers/net/phy/nxp-c45-tja11xx.c +++ b/drivers/net/phy/nxp-c45-tja11xx.c @@ -41,10 +41,8 @@ #define SQI_MASK GENMASK(2, 0) #define MAX_SQI SQI_MASK -#define VEND1_CABLE_TEST 0x8330 #define CABLE_TEST_ENABLE BIT(15) #define CABLE_TEST_START BIT(14) -#define CABLE_TEST_VALID BIT(13) #define CABLE_TEST_OK 0x00 #define CABLE_TEST_SHORTED 0x01 #define CABLE_TEST_OPEN 0x02 @@ -89,59 +87,18 @@ #define VEND1_PTP_CONFIG 0x1102 #define EXT_TRG_EDGE BIT(1) -#define PPS_OUT_POL BIT(2) -#define PPS_OUT_EN BIT(3) -#define VEND1_LTC_LOAD_CTRL 0x1105 -#define READ_LTC BIT(2) -#define LOAD_LTC BIT(0) - -#define VEND1_LTC_WR_NSEC_0 0x1106 -#define VEND1_LTC_WR_NSEC_1 0x1107 -#define VEND1_LTC_WR_SEC_0 0x1108 -#define VEND1_LTC_WR_SEC_1 0x1109 - -#define VEND1_LTC_RD_NSEC_0 0x110A -#define VEND1_LTC_RD_NSEC_1 0x110B -#define VEND1_LTC_RD_SEC_0 0x110C -#define VEND1_LTC_RD_SEC_1 0x110D - -#define VEND1_RATE_ADJ_SUBNS_0 0x110F -#define VEND1_RATE_ADJ_SUBNS_1 0x1110 #define CLK_RATE_ADJ_LD BIT(15) #define CLK_RATE_ADJ_DIR BIT(14) -#define VEND1_HW_LTC_LOCK_CTRL 0x1115 -#define HW_LTC_LOCK_EN BIT(0) - -#define VEND1_PTP_IRQ_EN 0x1131 -#define VEND1_PTP_IRQ_STATUS 0x1132 -#define PTP_IRQ_EGR_TS BIT(0) - #define VEND1_RX_TS_INSRT_CTRL 0x114D -#define RX_TS_INSRT_MODE2 0x02 +#define TJA1103_RX_TS_INSRT_MODE2 0x02 #define VEND1_EGR_RING_DATA_0 0x114E -#define VEND1_EGR_RING_DATA_1_SEQ_ID 0x114F -#define VEND1_EGR_RING_DATA_2_NSEC_15_0 0x1150 -#define VEND1_EGR_RING_DATA_3 0x1151 #define VEND1_EGR_RING_CTRL 0x1154 -#define VEND1_EXT_TRG_TS_DATA_0 0x1121 -#define VEND1_EXT_TRG_TS_DATA_1 0x1122 -#define VEND1_EXT_TRG_TS_DATA_2 0x1123 -#define VEND1_EXT_TRG_TS_DATA_3 0x1124 -#define VEND1_EXT_TRG_TS_DATA_4 0x1125 -#define VEND1_EXT_TRG_TS_CTRL 0x1126 - -#define RING_DATA_0_DOMAIN_NUMBER GENMASK(7, 0) -#define RING_DATA_0_MSG_TYPE GENMASK(11, 8) -#define RING_DATA_0_SEC_4_2 GENMASK(14, 2) #define RING_DATA_0_TS_VALID BIT(15) -#define RING_DATA_3_NSEC_29_16 GENMASK(13, 0) -#define RING_DATA_3_SEC_1_0 GENMASK(15, 14) -#define RING_DATA_5_SEC_16_5 GENMASK(15, 4) #define RING_DONE BIT(0) #define TS_SEC_MASK GENMASK(1, 0) @@ -152,18 +109,11 @@ #define VEND1_PORT_PTP_CONTROL 0x9000 #define PORT_PTP_CONTROL_BYPASS BIT(11) -#define VEND1_PTP_CLK_PERIOD 0x1104 #define PTP_CLK_PERIOD_100BT1 15ULL -#define VEND1_EVENT_MSG_FILT 0x1148 #define EVENT_MSG_FILT_ALL 0x0F #define EVENT_MSG_FILT_NONE 0x00 -#define VEND1_TX_PIPE_DLY_NS 0x1149 -#define VEND1_TX_PIPEDLY_SUBNS 0x114A -#define VEND1_RX_PIPE_DLY_NS 0x114B -#define VEND1_RX_PIPEDLY_SUBNS 0x114C - #define VEND1_GPIO_FUNC_CONFIG_BASE 0x2C40 #define GPIO_FUNC_EN BIT(15) #define GPIO_FUNC_PTP BIT(6) @@ -181,8 +131,8 @@ #define MAX_ID_PS 2260U #define DEFAULT_ID_PS 2000U -#define PPM_TO_SUBNS_INC(ppb) div_u64(GENMASK_ULL(31, 0) * (ppb) * \ - PTP_CLK_PERIOD_100BT1, NSEC_PER_SEC) +#define PPM_TO_SUBNS_INC(ppb, ptp_clk_period) div_u64(GENMASK_ULL(31, 0) * \ + (ppb) * (ptp_clk_period), NSEC_PER_SEC) #define NXP_C45_SKB_CB(skb) ((struct nxp_c45_skb_cb *)(skb)->cb) @@ -191,6 +141,21 @@ struct nxp_c45_skb_cb { unsigned int type; }; +#define NXP_C45_REG_FIELD(_reg, _devad, _offset, _size) \ + ((struct nxp_c45_reg_field) { \ + .reg = _reg, \ + .devad = _devad, \ + .offset = _offset, \ + .size = _size, \ + }) + +struct nxp_c45_reg_field { + u16 reg; + u8 devad; + u8 offset; + u8 size; +}; + struct nxp_c45_hwts { u32 nsec; u32 sec; @@ -199,7 +164,69 @@ struct nxp_c45_hwts { u8 msg_type; }; +struct nxp_c45_regmap { + /* PTP config regs. */ + u16 vend1_ptp_clk_period; + u16 vend1_event_msg_filt; + + /* LTC bits and regs. */ + struct nxp_c45_reg_field ltc_read; + struct nxp_c45_reg_field ltc_write; + struct nxp_c45_reg_field ltc_lock_ctrl; + u16 vend1_ltc_wr_nsec_0; + u16 vend1_ltc_wr_nsec_1; + u16 vend1_ltc_wr_sec_0; + u16 vend1_ltc_wr_sec_1; + u16 vend1_ltc_rd_nsec_0; + u16 vend1_ltc_rd_nsec_1; + u16 vend1_ltc_rd_sec_0; + u16 vend1_ltc_rd_sec_1; + u16 vend1_rate_adj_subns_0; + u16 vend1_rate_adj_subns_1; + + /* External trigger reg fields. */ + struct nxp_c45_reg_field irq_egr_ts_en; + struct nxp_c45_reg_field irq_egr_ts_status; + struct nxp_c45_reg_field domain_number; + struct nxp_c45_reg_field msg_type; + struct nxp_c45_reg_field sequence_id; + struct nxp_c45_reg_field sec_1_0; + struct nxp_c45_reg_field sec_4_2; + struct nxp_c45_reg_field nsec_15_0; + struct nxp_c45_reg_field nsec_29_16; + + /* PPS and EXT Trigger bits and regs. */ + struct nxp_c45_reg_field pps_enable; + struct nxp_c45_reg_field pps_polarity; + u16 vend1_ext_trg_data_0; + u16 vend1_ext_trg_data_1; + u16 vend1_ext_trg_data_2; + u16 vend1_ext_trg_data_3; + u16 vend1_ext_trg_ctrl; + + /* Cable test reg fields. */ + u16 cable_test; + struct nxp_c45_reg_field cable_test_valid; + struct nxp_c45_reg_field cable_test_result; +}; + +struct nxp_c45_phy_stats { + const char *name; + const struct nxp_c45_reg_field counter; +}; + +struct nxp_c45_phy_data { + const struct nxp_c45_regmap *regmap; + const struct nxp_c45_phy_stats *stats; + int n_stats; + u8 ptp_clk_period; + void (*counters_enable)(struct phy_device *phydev); + void (*ptp_init)(struct phy_device *phydev); + void (*ptp_enable)(struct phy_device *phydev, bool enable); +}; + struct nxp_c45_phy { + const struct nxp_c45_phy_data *phy_data; struct phy_device *phydev; struct mii_timestamper mii_ts; struct ptp_clock *ptp_clock; @@ -217,13 +244,86 @@ struct nxp_c45_phy { bool extts; }; -struct nxp_c45_phy_stats { - const char *name; - u8 mmd; - u16 reg; - u8 off; - u16 mask; -}; +static const +struct nxp_c45_phy_data *nxp_c45_get_data(struct phy_device *phydev) +{ + return phydev->drv->driver_data; +} + +static const +struct nxp_c45_regmap *nxp_c45_get_regmap(struct phy_device *phydev) +{ + const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev); + + return phy_data->regmap; +} + +static int nxp_c45_read_reg_field(struct phy_device *phydev, + const struct nxp_c45_reg_field *reg_field) +{ + u16 mask; + int ret; + + if (reg_field->size == 0) { + phydev_err(phydev, "Trying to read a reg field of size 0.\n"); + return -EINVAL; + } + + ret = phy_read_mmd(phydev, reg_field->devad, reg_field->reg); + if (ret < 0) + return ret; + + mask = reg_field->size == 1 ? BIT(reg_field->offset) : + GENMASK(reg_field->offset + reg_field->size - 1, + reg_field->offset); + ret &= mask; + ret >>= reg_field->offset; + + return ret; +} + +static int nxp_c45_write_reg_field(struct phy_device *phydev, + const struct nxp_c45_reg_field *reg_field, + u16 val) +{ + u16 mask; + u16 set; + + if (reg_field->size == 0) { + phydev_err(phydev, "Trying to write a reg field of size 0.\n"); + return -EINVAL; + } + + mask = reg_field->size == 1 ? BIT(reg_field->offset) : + GENMASK(reg_field->offset + reg_field->size - 1, + reg_field->offset); + set = val << reg_field->offset; + + return phy_modify_mmd_changed(phydev, reg_field->devad, + reg_field->reg, mask, set); +} + +static int nxp_c45_set_reg_field(struct phy_device *phydev, + const struct nxp_c45_reg_field *reg_field) +{ + if (reg_field->size != 1) { + phydev_err(phydev, "Trying to set a reg field of size different than 1.\n"); + return -EINVAL; + } + + return nxp_c45_write_reg_field(phydev, reg_field, 1); +} + +static int nxp_c45_clear_reg_field(struct phy_device *phydev, + const struct nxp_c45_reg_field *reg_field) +{ + if (reg_field->size != 1) { + phydev_err(phydev, "Trying to set a reg field of size different than 1.\n"); + return -EINVAL; + } + + return nxp_c45_write_reg_field(phydev, reg_field, 0); +} static bool nxp_c45_poll_txts(struct phy_device *phydev) { @@ -235,17 +335,17 @@ static int _nxp_c45_ptp_gettimex64(struct ptp_clock_info *ptp, struct ptp_system_timestamp *sts) { struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, - READ_LTC); + nxp_c45_set_reg_field(priv->phydev, ®map->ltc_read); ts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_LTC_RD_NSEC_0); + regmap->vend1_ltc_rd_nsec_0); ts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_LTC_RD_NSEC_1) << 16; + regmap->vend1_ltc_rd_nsec_1) << 16; ts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_LTC_RD_SEC_0); + regmap->vend1_ltc_rd_sec_0); ts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_LTC_RD_SEC_1) << 16; + regmap->vend1_ltc_rd_sec_1) << 16; return 0; } @@ -267,17 +367,17 @@ static int _nxp_c45_ptp_settime64(struct ptp_clock_info *ptp, const struct timespec64 *ts) { struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_0, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_nsec_0, ts->tv_nsec); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_NSEC_1, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_nsec_1, ts->tv_nsec >> 16); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_0, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_sec_0, ts->tv_sec); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_WR_SEC_1, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, regmap->vend1_ltc_wr_sec_1, ts->tv_sec >> 16); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_LTC_LOAD_CTRL, - LOAD_LTC); + nxp_c45_set_reg_field(priv->phydev, ®map->ltc_write); return 0; } @@ -297,6 +397,8 @@ static int nxp_c45_ptp_settime64(struct ptp_clock_info *ptp, static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) { struct nxp_c45_phy *priv = container_of(ptp, struct nxp_c45_phy, caps); + const struct nxp_c45_phy_data *data = nxp_c45_get_data(priv->phydev); + const struct nxp_c45_regmap *regmap = data->regmap; s32 ppb = scaled_ppm_to_ppb(scaled_ppm); u64 subns_inc_val; bool inc; @@ -305,16 +407,18 @@ static int nxp_c45_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) inc = ppb >= 0; ppb = abs(ppb); - subns_inc_val = PPM_TO_SUBNS_INC(ppb); + subns_inc_val = PPM_TO_SUBNS_INC(ppb, data->ptp_clk_period); - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_0, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, + regmap->vend1_rate_adj_subns_0, subns_inc_val); subns_inc_val >>= 16; subns_inc_val |= CLK_RATE_ADJ_LD; if (inc) subns_inc_val |= CLK_RATE_ADJ_DIR; - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_RATE_ADJ_SUBNS_1, + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, + regmap->vend1_rate_adj_subns_1, subns_inc_val); mutex_unlock(&priv->ptp_lock); @@ -358,21 +462,25 @@ static bool nxp_c45_match_ts(struct ptp_header *header, static void nxp_c45_get_extts(struct nxp_c45_phy *priv, struct timespec64 *extts) { + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev); + extts->tv_nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EXT_TRG_TS_DATA_0); + regmap->vend1_ext_trg_data_0); extts->tv_nsec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EXT_TRG_TS_DATA_1) << 16; + regmap->vend1_ext_trg_data_1) << 16; extts->tv_sec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EXT_TRG_TS_DATA_2); + regmap->vend1_ext_trg_data_2); extts->tv_sec |= phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EXT_TRG_TS_DATA_3) << 16; - phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EXT_TRG_TS_CTRL, - RING_DONE); + regmap->vend1_ext_trg_data_3) << 16; + phy_write_mmd(priv->phydev, MDIO_MMD_VEND1, + regmap->vend1_ext_trg_ctrl, RING_DONE); } static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv, struct nxp_c45_hwts *hwts) { + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev); + struct phy_device *phydev = priv->phydev; bool valid; u16 reg; @@ -384,16 +492,18 @@ static bool nxp_c45_get_hwtxts(struct nxp_c45_phy *priv, if (!valid) goto nxp_c45_get_hwtxts_out; - hwts->domain_number = reg; - hwts->msg_type = (reg & RING_DATA_0_MSG_TYPE) >> 8; - hwts->sec = (reg & RING_DATA_0_SEC_4_2) >> 10; - hwts->sequence_id = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EGR_RING_DATA_1_SEQ_ID); - hwts->nsec = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, - VEND1_EGR_RING_DATA_2_NSEC_15_0); - reg = phy_read_mmd(priv->phydev, MDIO_MMD_VEND1, VEND1_EGR_RING_DATA_3); - hwts->nsec |= (reg & RING_DATA_3_NSEC_29_16) << 16; - hwts->sec |= (reg & RING_DATA_3_SEC_1_0) >> 14; + hwts->domain_number = + nxp_c45_read_reg_field(phydev, ®map->domain_number); + hwts->msg_type = + nxp_c45_read_reg_field(phydev, ®map->msg_type); + hwts->sequence_id = + nxp_c45_read_reg_field(phydev, ®map->sequence_id); + hwts->nsec = + nxp_c45_read_reg_field(phydev, ®map->nsec_15_0); + hwts->nsec |= + nxp_c45_read_reg_field(phydev, ®map->nsec_29_16) << 16; + hwts->sec = nxp_c45_read_reg_field(phydev, ®map->sec_1_0); + hwts->sec |= nxp_c45_read_reg_field(phydev, ®map->sec_4_2) << 2; nxp_c45_get_hwtxts_out: mutex_unlock(&priv->ptp_lock); @@ -498,6 +608,7 @@ static void nxp_c45_gpio_config(struct nxp_c45_phy *priv, static int nxp_c45_perout_enable(struct nxp_c45_phy *priv, struct ptp_perout_request *perout, int on) { + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(priv->phydev); struct phy_device *phydev = priv->phydev; int pin; @@ -509,10 +620,10 @@ static int nxp_c45_perout_enable(struct nxp_c45_phy *priv, return pin; if (!on) { - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG, - PPS_OUT_EN); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG, - PPS_OUT_POL); + nxp_c45_clear_reg_field(priv->phydev, + ®map->pps_enable); + nxp_c45_clear_reg_field(priv->phydev, + ®map->pps_polarity); nxp_c45_gpio_config(priv, pin, GPIO_DISABLE); @@ -541,16 +652,16 @@ static int nxp_c45_perout_enable(struct nxp_c45_phy *priv, } if (perout->phase.nsec == 0) - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - VEND1_PTP_CONFIG, PPS_OUT_POL); + nxp_c45_clear_reg_field(priv->phydev, + ®map->pps_polarity); else - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - VEND1_PTP_CONFIG, PPS_OUT_POL); + nxp_c45_set_reg_field(priv->phydev, + ®map->pps_polarity); } nxp_c45_gpio_config(priv, pin, GPIO_PPS_OUT_CFG); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CONFIG, PPS_OUT_EN); + nxp_c45_set_reg_field(priv->phydev, ®map->pps_enable); return 0; } @@ -725,6 +836,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, struct nxp_c45_phy *priv = container_of(mii_ts, struct nxp_c45_phy, mii_ts); struct phy_device *phydev = priv->phydev; + const struct nxp_c45_phy_data *data; struct hwtstamp_config cfg; if (copy_from_user(&cfg, ifreq->ifr_data, sizeof(cfg))) @@ -733,6 +845,7 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, if (cfg.tx_type < 0 || cfg.tx_type > HWTSTAMP_TX_ON) return -ERANGE; + data = nxp_c45_get_data(phydev); priv->hwts_tx = cfg.tx_type; switch (cfg.rx_filter) { @@ -750,27 +863,24 @@ static int nxp_c45_hwtstamp(struct mii_timestamper *mii_ts, } if (priv->hwts_rx || priv->hwts_tx) { - phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT, + phy_write_mmd(phydev, MDIO_MMD_VEND1, + data->regmap->vend1_event_msg_filt, EVENT_MSG_FILT_ALL); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - VEND1_PORT_PTP_CONTROL, - PORT_PTP_CONTROL_BYPASS); + data->ptp_enable(phydev, true); } else { - phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_EVENT_MSG_FILT, + phy_write_mmd(phydev, MDIO_MMD_VEND1, + data->regmap->vend1_event_msg_filt, EVENT_MSG_FILT_NONE); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_PTP_CONTROL, - PORT_PTP_CONTROL_BYPASS); + data->ptp_enable(phydev, false); } if (nxp_c45_poll_txts(priv->phydev)) goto nxp_c45_no_ptp_irq; if (priv->hwts_tx) - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, - VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS); + nxp_c45_set_reg_field(phydev, &data->regmap->irq_egr_ts_en); else - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, - VEND1_PTP_IRQ_EN, PTP_IRQ_EGR_TS); + nxp_c45_clear_reg_field(phydev, &data->regmap->irq_egr_ts_en); nxp_c45_no_ptp_irq: return copy_to_user(ifreq->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0; @@ -795,57 +905,79 @@ static int nxp_c45_ts_info(struct mii_timestamper *mii_ts, return 0; } -static const struct nxp_c45_phy_stats nxp_c45_hw_stats[] = { - { "phy_symbol_error_cnt", MDIO_MMD_VEND1, - VEND1_SYMBOL_ERROR_COUNTER, 0, GENMASK(15, 0) }, - { "phy_link_status_drop_cnt", MDIO_MMD_VEND1, - VEND1_LINK_DROP_COUNTER, 8, GENMASK(13, 8) }, - { "phy_link_availability_drop_cnt", MDIO_MMD_VEND1, - VEND1_LINK_DROP_COUNTER, 0, GENMASK(5, 0) }, - { "phy_link_loss_cnt", MDIO_MMD_VEND1, - VEND1_LINK_LOSSES_AND_FAILURES, 10, GENMASK(15, 10) }, - { "phy_link_failure_cnt", MDIO_MMD_VEND1, - VEND1_LINK_LOSSES_AND_FAILURES, 0, GENMASK(9, 0) }, - { "rx_preamble_count", MDIO_MMD_VEND1, - VEND1_RX_PREAMBLE_COUNT, 0, GENMASK(5, 0) }, - { "tx_preamble_count", MDIO_MMD_VEND1, - VEND1_TX_PREAMBLE_COUNT, 0, GENMASK(5, 0) }, - { "rx_ipg_length", MDIO_MMD_VEND1, - VEND1_RX_IPG_LENGTH, 0, GENMASK(8, 0) }, - { "tx_ipg_length", MDIO_MMD_VEND1, - VEND1_TX_IPG_LENGTH, 0, GENMASK(8, 0) }, +static const struct nxp_c45_phy_stats common_hw_stats[] = { + { "phy_link_status_drop_cnt", + NXP_C45_REG_FIELD(0x8352, MDIO_MMD_VEND1, 8, 6), }, + { "phy_link_availability_drop_cnt", + NXP_C45_REG_FIELD(0x8352, MDIO_MMD_VEND1, 0, 6), }, + { "phy_link_loss_cnt", + NXP_C45_REG_FIELD(0x8353, MDIO_MMD_VEND1, 10, 6), }, + { "phy_link_failure_cnt", + NXP_C45_REG_FIELD(0x8353, MDIO_MMD_VEND1, 0, 10), }, + { "phy_symbol_error_cnt", + NXP_C45_REG_FIELD(0x8350, MDIO_MMD_VEND1, 0, 16) }, +}; + +static const struct nxp_c45_phy_stats tja1103_hw_stats[] = { + { "rx_preamble_count", + NXP_C45_REG_FIELD(0xAFCE, MDIO_MMD_VEND1, 0, 6), }, + { "tx_preamble_count", + NXP_C45_REG_FIELD(0xAFCF, MDIO_MMD_VEND1, 0, 6), }, + { "rx_ipg_length", + NXP_C45_REG_FIELD(0xAFD0, MDIO_MMD_VEND1, 0, 9), }, + { "tx_ipg_length", + NXP_C45_REG_FIELD(0xAFD1, MDIO_MMD_VEND1, 0, 9), }, }; static int nxp_c45_get_sset_count(struct phy_device *phydev) { - return ARRAY_SIZE(nxp_c45_hw_stats); + const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev); + + return ARRAY_SIZE(common_hw_stats) + (phy_data ? phy_data->n_stats : 0); } static void nxp_c45_get_strings(struct phy_device *phydev, u8 *data) { + const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev); + size_t count = nxp_c45_get_sset_count(phydev); + size_t idx; size_t i; - for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) { - strncpy(data + i * ETH_GSTRING_LEN, - nxp_c45_hw_stats[i].name, ETH_GSTRING_LEN); + for (i = 0; i < count; i++) { + if (i < ARRAY_SIZE(common_hw_stats)) { + strscpy(data + i * ETH_GSTRING_LEN, + common_hw_stats[i].name, ETH_GSTRING_LEN); + continue; + } + idx = i - ARRAY_SIZE(common_hw_stats); + strscpy(data + i * ETH_GSTRING_LEN, + phy_data->stats[idx].name, ETH_GSTRING_LEN); } } static void nxp_c45_get_stats(struct phy_device *phydev, struct ethtool_stats *stats, u64 *data) { + const struct nxp_c45_phy_data *phy_data = nxp_c45_get_data(phydev); + size_t count = nxp_c45_get_sset_count(phydev); + const struct nxp_c45_reg_field *reg_field; + size_t idx; size_t i; int ret; - for (i = 0; i < ARRAY_SIZE(nxp_c45_hw_stats); i++) { - ret = phy_read_mmd(phydev, nxp_c45_hw_stats[i].mmd, - nxp_c45_hw_stats[i].reg); - if (ret < 0) { - data[i] = U64_MAX; + for (i = 0; i < count; i++) { + if (i < ARRAY_SIZE(common_hw_stats)) { + reg_field = &common_hw_stats[i].counter; } else { - data[i] = ret & nxp_c45_hw_stats[i].mask; - data[i] >>= nxp_c45_hw_stats[i].off; + idx = i - ARRAY_SIZE(common_hw_stats); + reg_field = &phy_data->stats[idx].counter; } + + ret = nxp_c45_read_reg_field(phydev, reg_field); + if (ret < 0) + data[i] = U64_MAX; + else + data[i] = ret; } } @@ -884,6 +1016,7 @@ static int nxp_c45_config_intr(struct phy_device *phydev) static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev) { + const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev); struct nxp_c45_phy *priv = phydev->priv; irqreturn_t ret = IRQ_NONE; struct nxp_c45_hwts hwts; @@ -901,8 +1034,8 @@ static irqreturn_t nxp_c45_handle_interrupt(struct phy_device *phydev) * The irq signal will be asserted until the EGR TS FIFO will be * emptied. */ - irq = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_IRQ_STATUS); - if (irq & PTP_IRQ_EGR_TS) { + irq = nxp_c45_read_reg_field(phydev, &data->regmap->irq_egr_ts_status); + if (irq) { while (nxp_c45_get_hwtxts(priv, &hwts)) nxp_c45_process_txts(priv, &hwts); @@ -929,24 +1062,28 @@ static int nxp_c45_soft_reset(struct phy_device *phydev) static int nxp_c45_cable_test_start(struct phy_device *phydev) { - return phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST, - CABLE_TEST_ENABLE | CABLE_TEST_START); + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(phydev); + + return phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, regmap->cable_test, + CABLE_TEST_ENABLE | CABLE_TEST_START); } static int nxp_c45_cable_test_get_status(struct phy_device *phydev, bool *finished) { + const struct nxp_c45_regmap *regmap = nxp_c45_get_regmap(phydev); int ret; u8 cable_test_result; - ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST); - if (!(ret & CABLE_TEST_VALID)) { + ret = nxp_c45_read_reg_field(phydev, ®map->cable_test_valid); + if (!ret) { *finished = false; return 0; } *finished = true; - cable_test_result = ret & GENMASK(2, 0); + cable_test_result = nxp_c45_read_reg_field(phydev, + ®map->cable_test_result); switch (cable_test_result) { case CABLE_TEST_OK: @@ -966,7 +1103,7 @@ static int nxp_c45_cable_test_get_status(struct phy_device *phydev, ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC); } - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_CABLE_TEST, + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, regmap->cable_test, CABLE_TEST_ENABLE); return nxp_c45_start_op(phydev); @@ -1005,6 +1142,28 @@ static int nxp_c45_check_delay(struct phy_device *phydev, u32 delay) return 0; } +static void nxp_c45_counters_enable(struct phy_device *phydev) +{ + const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev); + + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER, + COUNTER_EN); + + data->counters_enable(phydev); +} + +static void nxp_c45_ptp_init(struct phy_device *phydev) +{ + const struct nxp_c45_phy_data *data = nxp_c45_get_data(phydev); + + phy_write_mmd(phydev, MDIO_MMD_VEND1, + data->regmap->vend1_ptp_clk_period, + data->ptp_clk_period); + nxp_c45_clear_reg_field(phydev, &data->regmap->ltc_lock_ctrl); + + data->ptp_init(phydev); +} + static u64 nxp_c45_get_phase_shift(u64 phase_offset_raw) { /* The delay in degree phase is 73.8 + phase_offset_raw * 0.9. @@ -1182,31 +1341,14 @@ static int nxp_c45_config_init(struct phy_device *phydev) phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PHY_CONFIG, PHY_CONFIG_AUTO); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_LINK_DROP_COUNTER, - COUNTER_EN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT, - COUNTER_EN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT, - COUNTER_EN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH, - COUNTER_EN); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH, - COUNTER_EN); - ret = nxp_c45_set_phy_mode(phydev); if (ret) return ret; phydev->autoneg = AUTONEG_DISABLE; - phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_PTP_CLK_PERIOD, - PTP_CLK_PERIOD_100BT1); - phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_HW_LTC_LOCK_CTRL, - HW_LTC_LOCK_EN); - phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL, - RX_TS_INSRT_MODE2); - phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES, - PTP_ENABLE); + nxp_c45_counters_enable(phydev); + nxp_c45_ptp_init(phydev); return nxp_c45_start_op(phydev); } @@ -1266,11 +1408,107 @@ static void nxp_c45_remove(struct phy_device *phydev) skb_queue_purge(&priv->rx_queue); } +static void tja1103_counters_enable(struct phy_device *phydev) +{ + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_PREAMBLE_COUNT, + COUNTER_EN); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_PREAMBLE_COUNT, + COUNTER_EN); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_IPG_LENGTH, + COUNTER_EN); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_TX_IPG_LENGTH, + COUNTER_EN); +} + +static void tja1103_ptp_init(struct phy_device *phydev) +{ + phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_RX_TS_INSRT_CTRL, + TJA1103_RX_TS_INSRT_MODE2); + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, VEND1_PORT_FUNC_ENABLES, + PTP_ENABLE); +} + +static void tja1103_ptp_enable(struct phy_device *phydev, bool enable) +{ + if (enable) + phy_clear_bits_mmd(phydev, MDIO_MMD_VEND1, + VEND1_PORT_PTP_CONTROL, + PORT_PTP_CONTROL_BYPASS); + else + phy_set_bits_mmd(phydev, MDIO_MMD_VEND1, + VEND1_PORT_PTP_CONTROL, + PORT_PTP_CONTROL_BYPASS); +} + +static const struct nxp_c45_regmap tja1103_regmap = { + .vend1_ptp_clk_period = 0x1104, + .vend1_event_msg_filt = 0x1148, + .pps_enable = + NXP_C45_REG_FIELD(0x1102, MDIO_MMD_VEND1, 3, 1), + .pps_polarity = + NXP_C45_REG_FIELD(0x1102, MDIO_MMD_VEND1, 2, 1), + .ltc_lock_ctrl = + NXP_C45_REG_FIELD(0x1115, MDIO_MMD_VEND1, 0, 1), + .ltc_read = + NXP_C45_REG_FIELD(0x1105, MDIO_MMD_VEND1, 2, 1), + .ltc_write = + NXP_C45_REG_FIELD(0x1105, MDIO_MMD_VEND1, 0, 1), + .vend1_ltc_wr_nsec_0 = 0x1106, + .vend1_ltc_wr_nsec_1 = 0x1107, + .vend1_ltc_wr_sec_0 = 0x1108, + .vend1_ltc_wr_sec_1 = 0x1109, + .vend1_ltc_rd_nsec_0 = 0x110A, + .vend1_ltc_rd_nsec_1 = 0x110B, + .vend1_ltc_rd_sec_0 = 0x110C, + .vend1_ltc_rd_sec_1 = 0x110D, + .vend1_rate_adj_subns_0 = 0x110F, + .vend1_rate_adj_subns_1 = 0x1110, + .irq_egr_ts_en = + NXP_C45_REG_FIELD(0x1131, MDIO_MMD_VEND1, 0, 1), + .irq_egr_ts_status = + NXP_C45_REG_FIELD(0x1132, MDIO_MMD_VEND1, 0, 1), + .domain_number = + NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 0, 8), + .msg_type = + NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 8, 4), + .sequence_id = + NXP_C45_REG_FIELD(0x114F, MDIO_MMD_VEND1, 0, 16), + .sec_1_0 = + NXP_C45_REG_FIELD(0x1151, MDIO_MMD_VEND1, 14, 2), + .sec_4_2 = + NXP_C45_REG_FIELD(0x114E, MDIO_MMD_VEND1, 12, 3), + .nsec_15_0 = + NXP_C45_REG_FIELD(0x1150, MDIO_MMD_VEND1, 0, 16), + .nsec_29_16 = + NXP_C45_REG_FIELD(0x1151, MDIO_MMD_VEND1, 0, 14), + .vend1_ext_trg_data_0 = 0x1121, + .vend1_ext_trg_data_1 = 0x1122, + .vend1_ext_trg_data_2 = 0x1123, + .vend1_ext_trg_data_3 = 0x1124, + .vend1_ext_trg_ctrl = 0x1126, + .cable_test = 0x8330, + .cable_test_valid = + NXP_C45_REG_FIELD(0x8330, MDIO_MMD_VEND1, 13, 1), + .cable_test_result = + NXP_C45_REG_FIELD(0x8330, MDIO_MMD_VEND1, 0, 3), +}; + +static const struct nxp_c45_phy_data tja1103_phy_data = { + .regmap = &tja1103_regmap, + .stats = tja1103_hw_stats, + .n_stats = ARRAY_SIZE(tja1103_hw_stats), + .ptp_clk_period = PTP_CLK_PERIOD_100BT1, + .counters_enable = tja1103_counters_enable, + .ptp_init = tja1103_ptp_init, + .ptp_enable = tja1103_ptp_enable, +}; + static struct phy_driver nxp_c45_driver[] = { { PHY_ID_MATCH_MODEL(PHY_ID_TJA_1103), .name = "NXP C45 TJA1103", .features = PHY_BASIC_T1_FEATURES, + .driver_data = &tja1103_phy_data, .probe = nxp_c45_probe, .soft_reset = nxp_c45_soft_reset, .config_aneg = genphy_c45_config_aneg,