diff options
Diffstat (limited to 'drivers/thunderbolt/usb4.c')
-rw-r--r-- | drivers/thunderbolt/usb4.c | 62 |
1 files changed, 35 insertions, 27 deletions
diff --git a/drivers/thunderbolt/usb4.c b/drivers/thunderbolt/usb4.c index 4d83b65afb5b..0a9b4aeb3fa1 100644 --- a/drivers/thunderbolt/usb4.c +++ b/drivers/thunderbolt/usb4.c @@ -1653,31 +1653,31 @@ int usb4_port_margining_caps(struct tb_port *port, enum usb4_sb_target target, * @port: USB4 port * @target: Sideband target * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER - * @lanes: Which lanes to run (must match the port capabilities). Can be - * %0, %1 or %7. - * @ber_level: BER level contour value - * @timing: Perform timing margining instead of voltage - * @right_high: Use Right/high margin instead of left/low + * @params: Parameters for USB4 hardware margining * @results: Array with at least two elements to hold the results * * Runs hardware lane margining on USB4 port and returns the result in * @results. */ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, - u8 index, unsigned int lanes, unsigned int ber_level, - bool timing, bool right_high, u32 *results) + u8 index, const struct usb4_port_margining_params *params, + u32 *results) { u32 val; int ret; - val = lanes; - if (timing) + if (WARN_ON_ONCE(!params)) + return -EINVAL; + + val = params->lanes; + if (params->time) val |= USB4_MARGIN_HW_TIME; - if (right_high) + if (params->right_high) val |= USB4_MARGIN_HW_RH; - if (ber_level) - val |= (ber_level << USB4_MARGIN_HW_BER_SHIFT) & - USB4_MARGIN_HW_BER_MASK; + if (params->ber_level) + val |= FIELD_PREP(USB4_MARGIN_HW_BER_MASK, params->ber_level); + if (params->optional_voltage_offset_range) + val |= USB4_MARGIN_HW_OPT_VOLTAGE; ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val, sizeof(val)); @@ -1698,38 +1698,46 @@ int usb4_port_hw_margin(struct tb_port *port, enum usb4_sb_target target, * @port: USB4 port * @target: Sideband target * @index: Retimer index if taget is %USB4_SB_TARGET_RETIMER - * @lanes: Which lanes to run (must match the port capabilities). Can be - * %0, %1 or %7. - * @timing: Perform timing margining instead of voltage - * @right_high: Use Right/high margin instead of left/low - * @counter: What to do with the error counter + * @params: Parameters for USB4 software margining + * @results: Data word for the operation completion data * * Runs software lane margining on USB4 port. Read back the error * counters by calling usb4_port_sw_margin_errors(). Returns %0 in * success and negative errno otherwise. */ int usb4_port_sw_margin(struct tb_port *port, enum usb4_sb_target target, - u8 index, unsigned int lanes, bool timing, - bool right_high, u32 counter) + u8 index, const struct usb4_port_margining_params *params, + u32 *results) { u32 val; int ret; - val = lanes; - if (timing) + if (WARN_ON_ONCE(!params)) + return -EINVAL; + + val = params->lanes; + if (params->time) val |= USB4_MARGIN_SW_TIME; - if (right_high) + if (params->optional_voltage_offset_range) + val |= USB4_MARGIN_SW_OPT_VOLTAGE; + if (params->right_high) val |= USB4_MARGIN_SW_RH; - val |= (counter << USB4_MARGIN_SW_COUNTER_SHIFT) & - USB4_MARGIN_SW_COUNTER_MASK; + val |= FIELD_PREP(USB4_MARGIN_SW_COUNTER_MASK, params->error_counter); + val |= FIELD_PREP(USB4_MARGIN_SW_VT_MASK, params->voltage_time_offset); ret = usb4_port_sb_write(port, target, index, USB4_SB_METADATA, &val, sizeof(val)); if (ret) return ret; - return usb4_port_sb_op(port, target, index, - USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500); + ret = usb4_port_sb_op(port, target, index, + USB4_SB_OPCODE_RUN_SW_LANE_MARGINING, 2500); + if (ret) + return ret; + + return usb4_port_sb_read(port, target, index, USB4_SB_DATA, results, + sizeof(*results)); + } /** |