[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <SJ2PR11MB8452414E4F138EE7B34C2B4C9B22A@SJ2PR11MB8452.namprd11.prod.outlook.com>
Date: Tue, 5 Aug 2025 14:30:04 +0000
From: "Kubalewski, Arkadiusz" <arkadiusz.kubalewski@...el.com>
To: "Nitka, Grzegorz" <grzegorz.nitka@...el.com>,
"intel-wired-lan@...ts.osuosl.org" <intel-wired-lan@...ts.osuosl.org>
CC: "netdev@...r.kernel.org" <netdev@...r.kernel.org>, "Nguyen, Anthony L"
<anthony.l.nguyen@...el.com>, "Kitszel, Przemyslaw"
<przemyslaw.kitszel@...el.com>, "Korba, Przemyslaw"
<przemyslaw.korba@...el.com>, "Olech, Milena" <milena.olech@...el.com>
Subject: RE: [PATCH v8 iwl-next] ice: add recovery clock and clock 1588
control for E825c
>From: Nitka, Grzegorz <grzegorz.nitka@...el.com>
>Sent: Thursday, July 24, 2025 2:28 PM
>
>From: Przemyslaw Korba <przemyslaw.korba@...el.com>
>
>Add control for E825 input pins: phy clock recovery and clock 1588.
>E825 does not provide control over platform level DPLL but it
>provides control over PHY clock recovery, and PTP/timestamp driven
>inputs for platform level DPLL.
>
>Introduce a software controlled layer of abstraction to:
>- create a DPLL of type EEC for E825c,
>- create recovered clock pin for each PF, and control them through
>writing to registers,
>- create pin to control clock 1588 for PF0, and control it through
>writing to registers.
>
>Usage example:
>- to get EEC PLL info
>$ ynl --family dpll --dump device-get
>[{'clock-id': 0,
> 'id': 6,
> 'lock-status': 'locked',
> 'mode': 'manual',
> 'mode-supported': ['manual'],
> 'module-name': 'ice',
> 'type': 'eec'},
>...
> ]
>
>- to get 1588 and rclk pins info
>(note: in the output below, pin id=31 is a representor for 1588 input,
>while pins 32..35 corresponds to PHY clock inputs to SyncE module)
>$ ynl --family dpll --dump pin-get
>[{'board-label': 'CLK_IN_0',
> 'capabilities': set(),
> 'clock-id': 0,
> 'id': 27,
> 'module-name': 'ice',
> 'parent-device': [{'direction': 'input',
> 'parent-id': 6,
> 'state': 'connected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'mux'},
> {'board-label': 'CLK_IN_1',
> 'capabilities': set(),
> 'clock-id': 0,
> 'id': 28,
> 'module-name': 'ice',
> 'parent-device': [{'direction': 'input',
> 'parent-id': 6,
> 'state': 'connected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'mux'},
> {'board-label': 'pin_1588',
> 'capabilities': {'state-can-change'},
> 'clock-id': 0,
> 'id': 31,
> 'module-name': 'ice',
> 'parent-pin': [{'parent-id': 27, 'state': 'disconnected'},
> {'parent-id': 28, 'state': 'disconnected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'synce-eth-port'},
> {'capabilities': {'state-can-change'},
> 'clock-id': 0,
> 'id': 32,
> 'module-name': 'ice',
> 'parent-pin': [{'parent-id': 27, 'state': 'disconnected'},
> {'parent-id': 28, 'state': 'disconnected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'synce-eth-port'},
> {'capabilities': {'state-can-change'},
> 'clock-id': 0,
> 'id': 33,
> 'module-name': 'ice',
> 'parent-pin': [{'parent-id': 27, 'state': 'disconnected'},
> {'parent-id': 28, 'state': 'disconnected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'synce-eth-port'},
> {'capabilities': {'state-can-change'},
> 'clock-id': 0,
> 'id': 34,
> 'module-name': 'ice',
> 'parent-pin': [{'parent-id': 27, 'state': 'disconnected'},
> {'parent-id': 28, 'state': 'disconnected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'synce-eth-port'},
> {'capabilities': {'state-can-change'},
> 'clock-id': 0,
> 'id': 35,
> 'module-name': 'ice',
> 'parent-pin': [{'parent-id': 27, 'state': 'disconnected'},
> {'parent-id': 28, 'state': 'disconnected'}],
> 'phase-adjust-max': 0,
> 'phase-adjust-min': 0,
> 'type': 'synce-eth-port'}]
>
>- to set PHY0 clock as SyncE module input
>$ ynl --family dpll --do pin-set --json '{"id":32,"parent-pin":\
> {"parent-id":27, "state":"connected"}}'
>
>- to set 1588 Main Timer as source into SyncE module
>$ ynl --family dpll --do pin-set --json '{"id":31,"parent-pin":\
> {"parent-id":27, "state":"connected"}}'
>
>Reviewed-by: Milena Olech <milena.olech@...el.com>
>Co-developed-by: Grzegorz Nitka <grzegorz.nitka@...el.com>
>Signed-off-by: Grzegorz Nitka <grzegorz.nitka@...el.com>
>Signed-off-by: Przemyslaw Korba <przemyslaw.korba@...el.com>
>---
>v7->v8:
>- rebased
>- removed unrelated changes
>- change pin_1588 type to DPLL_PIN_TYPE_EXT
>- use ICE_SYNCE_CLK_NUM to determine the number of rclk pins
>---
> drivers/net/ethernet/intel/ice/ice_dpll.c | 852 ++++++++++++++++++--
> drivers/net/ethernet/intel/ice/ice_dpll.h | 24 +
> drivers/net/ethernet/intel/ice/ice_lib.c | 3 +
> drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 34 +-
> drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 +
> drivers/net/ethernet/intel/ice/ice_tspll.h | 7 +
> drivers/net/ethernet/intel/ice/ice_type.h | 6 +
> 7 files changed, 869 insertions(+), 58 deletions(-)
>
>diff --git a/drivers/net/ethernet/intel/ice/ice_dpll.c
>b/drivers/net/ethernet/intel/ice/ice_dpll.c
>index 53b54e395a2e..f89dec5e532e 100644
>--- a/drivers/net/ethernet/intel/ice/ice_dpll.c
>+++ b/drivers/net/ethernet/intel/ice/ice_dpll.c
>@@ -9,6 +9,7 @@
> #define ICE_CGU_STATE_ACQ_ERR_THRESHOLD 50
> #define ICE_DPLL_PIN_IDX_INVALID 0xff
> #define ICE_DPLL_RCLK_NUM_PER_PF 1
>+#define ICE_DPLL_PIN_1588_NUM 1
> #define ICE_DPLL_PIN_ESYNC_PULSE_HIGH_PERCENT 25
> #define ICE_DPLL_PIN_GEN_RCLK_FREQ 1953125
> #define ICE_DPLL_PIN_PRIO_OUTPUT 0xff
>@@ -74,6 +75,7 @@ static const char * const pin_type_name[] = {
>
> static const char * const ice_dpll_sw_pin_sma[] = { "SMA1", "SMA2" };
> static const char * const ice_dpll_sw_pin_ufl[] = { "U.FL1", "U.FL2" };
>+static const char ice_dpll_pin_1588[] = "pin_1588";
>
> static const struct dpll_pin_frequency ice_esync_range[] = {
> DPLL_PIN_FREQUENCY_RANGE(0, DPLL_PIN_FREQUENCY_1_HZ),
>@@ -528,6 +530,117 @@ ice_dpll_pin_disable(struct ice_hw *hw, struct
>ice_dpll_pin *pin,
> return ret;
> }
>
>+/**
>+ * ice_dpll_rclk_update_e825c - updates the state of rclk pin on e825c
>device
>+ * @pf: private board struct
>+ * @pin: pointer to a pin
>+ *
>+ * Update struct holding pin states info, states are separate for each
>parent
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - OK
>+ * * negative - error
>+ */
>+static int ice_dpll_rclk_update_e825c(struct ice_pf *pf,
>+ struct ice_dpll_pin *pin)
>+{
>+ u8 rclk_bits;
>+ int err;
>+ u32 reg;
>+
>+ if (pf->dplls.rclk.num_parents > ICE_SYNCE_CLK_NUM)
>+ return -EINVAL;
>+
>+ err = ice_read_cgu_reg(&pf->hw, ICE_CGU_R10, ®);
>+ if (err)
>+ return err;
>+ rclk_bits = FIELD_GET(ICE_CGU_R10_SYNCE_S_REF_CLK, reg);
>+ SET_PIN_STATE(pin, ICE_SYNCE_CLK0, rclk_bits ==
>+ (pf->ptp.port.port_num +
>ICE_CGU_BYPASS_MUX_OFFSET_E825C));
>+
>+ err = ice_read_cgu_reg(&pf->hw, ICE_CGU_R11, ®);
>+ if (err)
>+ return err;
>+ rclk_bits = FIELD_GET(ICE_CGU_R11_SYNCE_S_BYP_CLK, reg);
>+ SET_PIN_STATE(pin, ICE_SYNCE_CLK1, rclk_bits ==
>+ (pf->ptp.port.port_num +
>ICE_CGU_BYPASS_MUX_OFFSET_E825C));
>+ return 0;
>+}
>+
>+/**
>+ * ice_dpll_rclk_update - updates the state of rclk pin on a device
>+ * @pf: private board struct
>+ * @pin: pointer to a pin
>+ * @port_num: port number
>+ *
>+ * Update struct holding pin states info, states are separate for each
>parent
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - OK
>+ * * negative - error
>+ */
>+static int ice_dpll_rclk_update(struct ice_pf *pf, struct ice_dpll_pin
>*pin,
>+ u8 port_num)
>+{
>+ int ret;
>+
>+ for (u8 parent = 0; parent < pf->dplls.rclk.num_parents; parent++) {
>+ ret = ice_aq_get_phy_rec_clk_out(&pf->hw, &parent, &port_num,
>+ &pin->flags[parent], NULL);
>+ if (ret)
>+ return ret;
>+ SET_PIN_STATE(pin, parent,
>+ ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN &
>+ pin->flags[parent]);
>+ }
>+
>+ return 0;
>+}
>+
>+/**
>+ * ice_dpll_update_pin_1588_e825c - updates the state of clock 1588 pin
>+ * @hw: board private hw structure
>+ * @pin: pointer to a pin
>+ * @parent: clock source identifier
>+ *
>+ * Update struct holding pin states info, states are separate for each
>parent
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - OK
>+ * * negative - error
>+ */
>+static int ice_dpll_update_pin_1588_e825c(struct ice_hw *hw,
>+ struct ice_dpll_pin *pin,
>+ enum ice_synce_clk parent)
>+{
>+ u8 bits_clk;
>+ int err;
>+ u32 reg;
>+
>+ switch (parent) {
>+ case ICE_SYNCE_CLK0:
>+ err = ice_read_cgu_reg(hw, ICE_CGU_R10, ®);
>+ if (err)
>+ return err;
>+ bits_clk = FIELD_GET(ICE_CGU_R10_SYNCE_S_REF_CLK, reg);
>+ break;
>+ case ICE_SYNCE_CLK1:
>+ err = ice_read_cgu_reg(hw, ICE_CGU_R11, ®);
>+ if (err)
>+ return err;
>+ bits_clk = FIELD_GET(ICE_CGU_R11_SYNCE_S_BYP_CLK, reg);
>+ break;
>+ default:
>+ return -EINVAL;
>+ }
>+ SET_PIN_STATE(pin, parent, bits_clk == ICE_CGU_NCOCLK);
>+
>+ return 0;
>+}
>+
> /**
> * ice_dpll_sw_pins_update - update status of all SW pins
> * @pf: private board struct
>@@ -668,22 +781,14 @@ ice_dpll_pin_state_update(struct ice_pf *pf, struct
>ice_dpll_pin *pin,
> }
> break;
> case ICE_DPLL_PIN_TYPE_RCLK_INPUT:
>- for (parent = 0; parent < pf->dplls.rclk.num_parents;
>- parent++) {
>- u8 p = parent;
>-
>- ret = ice_aq_get_phy_rec_clk_out(&pf->hw, &p,
>- &port_num,
>- &pin->flags[parent],
>- NULL);
>+ if (pf->hw.mac_type == ICE_MAC_GENERIC_3K_E825) {
>+ ret = ice_dpll_rclk_update_e825c(pf, pin);
>+ if (ret)
>+ goto err;
>+ } else {
>+ ret = ice_dpll_rclk_update(pf, pin, port_num);
> if (ret)
> goto err;
>- if (ICE_AQC_GET_PHY_REC_CLK_OUT_OUT_EN &
>- pin->flags[parent])
>- pin->state[parent] = DPLL_PIN_STATE_CONNECTED;
>- else
>- pin->state[parent] =
>- DPLL_PIN_STATE_DISCONNECTED;
> }
> break;
> case ICE_DPLL_PIN_TYPE_SOFTWARE:
>@@ -1021,6 +1126,33 @@ ice_dpll_pin_state_get(const struct dpll_pin *pin,
>void *pin_priv,
> return ret;
> }
>
>+/**
>+ * ice_dpll_pin_state_get_e825c - update e825c device pin's state on dpll
>+ * @pin: pointer to a pin
>+ * @pin_priv: private data pointer passed on pin registration
>+ * @dpll: registered dpll pointer
>+ * @dpll_priv: private data pointer passed on dpll registration
>+ * @state: on success holds state of the pin
>+ * @extack: error reporting
>+ *
>+ * Set pin state of e825c device to connected.
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - success
>+ */
>+static int ice_dpll_pin_state_get_e825c(const struct dpll_pin *pin,
>+ void *pin_priv,
>+ const struct dpll_device *dpll,
>+ void *dpll_priv,
>+ enum dpll_pin_state *state,
>+ struct netlink_ext_ack *extack)
>+{
>+ *state = DPLL_PIN_STATE_CONNECTED;
>+
>+ return 0;
>+}
>+
> /**
> * ice_dpll_output_state_get - get output pin state on dpll device
> * @pin: pointer to a pin
>@@ -1842,6 +1974,228 @@ ice_dpll_phase_offset_get(const struct dpll_pin
>*pin, void *pin_priv,
> return 0;
> }
>
>+/**
>+ * ice_dpll_cfg_bypass_mux_e825c - check if the given port recovered clock
>+ * or clock 1588 is set active
>+ * @hw: Pointer to the HW struct
>+ * @ena: true to enable the reference, false if disable
>+ * @port_num: Number of the port
>+ * @output: Output pin, we have two in E825C
>+ * @clock_1588: true to enable 1588 reference, false to recover from port
>+ *
>+ * Dpll subsystem callback. Handler for setting the correct registers to
>+ * enable a functionality on e825c device.
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - success
>+ * * negative - error
>+ */
>+static int
>+ice_dpll_cfg_bypass_mux_e825c(struct ice_hw *hw, bool ena,
>+ u32 port_num, enum ice_synce_clk output,
>+ bool clock_1588)
There is now new file ice_tspll.c, where this code could belong, then just
provide interface for this code.
>+{
>+ u8 first_mux;
>+ int err;
>+ u32 r10;
>+
>+ err = ice_read_cgu_reg(hw, ICE_CGU_R10, &r10);
>+ if (err)
>+ return err;
>+
>+ if (!ena)
>+ first_mux = ICE_CGU_NET_REF_CLK0;
>+ else if (clock_1588)
>+ first_mux = ICE_CGU_NCOCLK;
>+ else
>+ first_mux = port_num + ICE_CGU_BYPASS_MUX_OFFSET_E825C;
>+
>+ r10 &= ~(ICE_CGU_R10_SYNCE_DCK_RST | ICE_CGU_R10_SYNCE_DCK2_RST);
>+
>+ switch (output) {
>+ case ICE_SYNCE_CLK0:
>+ r10 &= ~(ICE_CGU_R10_SYNCE_ETHCLKO_SEL |
>+ ICE_CGU_R10_SYNCE_ETHDIV_LOAD |
>+ ICE_CGU_R10_SYNCE_S_REF_CLK);
>+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_S_REF_CLK, first_mux);
>+ if (clock_1588)
>+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHCLKO_SEL,
>+ ICE_CGU_REF_CLK_BYP0);
>+ else
>+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_ETHCLKO_SEL,
>+ ICE_CGU_REF_CLK_BYP0_DIV);
>+ break;
>+ case ICE_SYNCE_CLK1:
>+ {
>+ u32 val;
>+
>+ err = ice_read_cgu_reg(hw, ICE_CGU_R11, &val);
>+ if (err)
>+ return err;
>+ val &= ~ICE_CGU_R11_SYNCE_S_BYP_CLK;
>+ val |= FIELD_PREP(ICE_CGU_R11_SYNCE_S_BYP_CLK, first_mux);
>+ err = ice_write_cgu_reg(hw, ICE_CGU_R11, val);
>+ if (err)
>+ return err;
>+ r10 &= ~(ICE_CGU_R10_SYNCE_CLKODIV_LOAD |
>+ ICE_CGU_R10_SYNCE_CLKO_SEL);
>+ if (clock_1588)
>+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKO_SEL,
>+ ICE_CGU_REF_CLK_BYP1);
>+ else
>+ r10 |= FIELD_PREP(ICE_CGU_R10_SYNCE_CLKO_SEL,
>+ ICE_CGU_REF_CLK_BYP1_DIV);
>+ break;
>+ }
>+ default:
>+ return -EINVAL;
>+ }
>+
>+ err = ice_write_cgu_reg(hw, ICE_CGU_R10, r10);
>+ if (err)
>+ return err;
>+
>+ return 0;
>+}
>+
>+/**
>+ * ice_dpll_get_div_e825c - get the divider for the given speed
>+ * @link_speed: link speed of the port
>+ * @divider: output value, calculated divider
>+ *
>+ * Dpll subsystem callback. Handler for setting the divider on e825c
>device.
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - success
>+ * * negative - error
>+ */
>+static int ice_dpll_get_div_e825c(u16 link_speed, u8 *divider)
>+{
>+ switch (link_speed) {
>+ case ICE_AQ_LINK_SPEED_100GB:
>+ case ICE_AQ_LINK_SPEED_50GB:
>+ case ICE_AQ_LINK_SPEED_25GB:
>+ *divider = 10;
>+ break;
>+ case ICE_AQ_LINK_SPEED_40GB:
>+ case ICE_AQ_LINK_SPEED_10GB:
>+ *divider = 4;
>+ break;
>+ case ICE_AQ_LINK_SPEED_5GB:
>+ case ICE_AQ_LINK_SPEED_2500MB:
>+ case ICE_AQ_LINK_SPEED_1000MB:
>+ *divider = 2;
>+ break;
>+ case ICE_AQ_LINK_SPEED_100MB:
>+ *divider = 1;
>+ break;
>+ default:
>+ return -EOPNOTSUPP;
>+ }
>+
>+ return 0;
>+}
>+
>+/**
>+ * ice_dpll_cfg_synce_ethdiv_e825c - set the divider on the mux
>+ * @hw: Pointer to the HW struct
>+ * @output: Output pin, we have two in E825C
>+ *
>+ * Dpll subsystem callback. Set the correct divider for RCLKA or RCLKB.
>+ *
>+ * Context: Called under pf->dplls.lock
>+ * Return:
>+ * * 0 - success
>+ * * negative - error
>+ */
>+static int ice_dpll_cfg_synce_ethdiv_e825c(struct ice_hw *hw,
>+ enum ice_synce_clk output)
Ditto.
Thank you!
[..]
Powered by blists - more mailing lists