diff --git a/msm/dp/dp_catalog.c b/msm/dp/dp_catalog.c index a2782461b3..4144942c48 100644 --- a/msm/dp/dp_catalog.c +++ b/msm/dp/dp_catalog.c @@ -3091,6 +3091,22 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser) strlcpy(catalog->exe_mode, "hw", sizeof(catalog->exe_mode)); + if (parser->valid_lt_params) { + ctrl.swing_hbr2_3 = parser->swing_hbr2_3; + ctrl.pre_emp_hbr2_3 = parser->pre_emp_hbr2_3; + + ctrl.swing_hbr_rbr = parser->swing_hbr_rbr; + ctrl.pre_emp_hbr_rbr = parser->pre_emp_hbr_rbr; + ctrl.valid_lt_params = true; + } else { + ctrl.swing_hbr2_3 = NULL; + ctrl.pre_emp_hbr2_3 = NULL; + + ctrl.swing_hbr_rbr = NULL; + ctrl.pre_emp_hbr_rbr = NULL; + ctrl.valid_lt_params = false; + } + dp_catalog = &catalog->dp_catalog; dp_catalog->aux = aux; diff --git a/msm/dp/dp_catalog.h b/msm/dp/dp_catalog.h index 16b60ae403..adbaa8981c 100644 --- a/msm/dp/dp_catalog.h +++ b/msm/dp/dp_catalog.h @@ -93,6 +93,12 @@ struct dp_catalog_ctrl { u32 isr5; u32 isr6; + u8 *swing_hbr2_3; + u8 *pre_emp_hbr2_3; + u8 *swing_hbr_rbr; + u8 *pre_emp_hbr_rbr; + bool valid_lt_params; + void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state); void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u8 ln_cnt); void (*lane_mapping)(struct dp_catalog_ctrl *ctrl, bool flipped, diff --git a/msm/dp/dp_catalog_v420.c b/msm/dp/dp_catalog_v420.c index 60b004d5ee..cbadd92519 100644 --- a/msm/dp/dp_catalog_v420.c +++ b/msm/dp/dp_catalog_v420.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. */ @@ -45,41 +45,6 @@ static u8 const vm_voltage_swing[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ }; -static u8 const dp_pre_emp_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x00, 0x0C, 0x15, 0x1B}, /* pe0, 0 db */ - {0x02, 0x0E, 0x16, 0xFF}, /* pe1, 3.5 db */ - {0x02, 0x11, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0x04, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ -}; - -static u8 const dp_swing_hbr2_hbr3[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x02, 0x12, 0x16, 0x1A}, /* sw0, 0.4v */ - {0x09, 0x19, 0x1F, 0xFF}, /* sw1, 0.6v */ - {0x10, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */ - {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */ -}; - -static u8 const dp_pre_emp_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x00, 0x0D, 0x14, 0x1A}, /* pe0, 0 db */ - {0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */ - {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ -}; - -static u8 const dp_swing_hbr_rbr[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x08, 0x0F, 0x16, 0x1F}, /* sw0, 0.4v */ - {0x11, 0x1E, 0x1F, 0xFF}, /* sw1, 0.6v */ - {0x16, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8v */ - {0x1F, 0xFF, 0xFF, 0xFF} /* sw1, 1.2v */ -}; - -static const u8 dp_pre_emp_hbr_rbr_v600[MAX_VOLTAGE_LEVELS][MAX_PRE_EMP_LEVELS] = { - {0x00, 0x0D, 0x14, 0x1A}, /* pe0, 0 db */ - {0x00, 0x0E, 0x15, 0xFF}, /* pe1, 3.5 db */ - {0x00, 0x0E, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0x02, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ -}; - struct dp_catalog_private_v420 { struct device *dev; struct dp_catalog_sub sub; @@ -249,6 +214,7 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl, u8 value0, value1; u32 version; u32 phy_version; + int idx; if (!ctrl || !((v_level < MAX_VOLTAGE_LEVELS) && (p_level < MAX_PRE_EMP_LEVELS))) { @@ -268,16 +234,14 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl, /* * For DP controller versions >= 1.2.3 */ - if (version >= 0x10020003) { + if (version >= 0x10020003 && ctrl->valid_lt_params) { + idx = v_level * MAX_VOLTAGE_LEVELS + p_level; if (high) { - value0 = dp_swing_hbr2_hbr3[v_level][p_level]; - value1 = dp_pre_emp_hbr2_hbr3[v_level][p_level]; + value0 = ctrl->swing_hbr2_3[idx]; + value1 = ctrl->pre_emp_hbr2_3[idx]; } else { - value0 = dp_swing_hbr_rbr[v_level][p_level]; - if (phy_version >= 0x60000000) - value1 = dp_pre_emp_hbr_rbr_v600[v_level][p_level]; - else - value1 = dp_pre_emp_hbr_rbr[v_level][p_level]; + value0 = ctrl->swing_hbr_rbr[idx]; + value1 = ctrl->pre_emp_hbr_rbr[idx]; } } else { value0 = vm_voltage_swing[v_level][p_level]; diff --git a/msm/dp/dp_parser.c b/msm/dp/dp_parser.c index 4ce53a7c5a..48c76dc804 100644 --- a/msm/dp/dp_parser.c +++ b/msm/dp/dp_parser.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -761,6 +761,90 @@ static void dp_parser_widebus(struct dp_parser *parser) parser->has_widebus); } +static int parse_lt_param(struct device *dev, u8 **ptr, char *property) { + int ret = 0, i = 0, j = 0, index = 0; + u32 out_val = 0; + u32 expected_elems = MAX_SWING_LEVELS * MAX_PRE_EMP_LEVELS; + u8 parsed_val = 0; + + ret = of_property_count_u32_elems(dev->of_node, property); + if (ret != expected_elems) { + return ret; + } + + *ptr = devm_kzalloc(dev, sizeof(u8) * expected_elems, GFP_KERNEL); + if (!*ptr) + return -ENOMEM; + + for (i = 0; i < MAX_SWING_LEVELS; i++) { + for (j = 0; j < MAX_PRE_EMP_LEVELS; j++) { + index = i * MAX_SWING_LEVELS + j; + + ret = of_property_read_u32_index(dev->of_node, property, index, &out_val); + if (ret) + return ret; + + parsed_val = out_val & 0xFF; + + ((u8 *)*ptr)[index] = parsed_val; + } + } + + return ret; +} + +static void dp_parser_clear_link_training_params(struct dp_parser *dp_parser) +{ + devm_kfree(&dp_parser->pdev->dev, dp_parser->swing_hbr2_3); + devm_kfree(&dp_parser->pdev->dev, dp_parser->pre_emp_hbr2_3); + devm_kfree(&dp_parser->pdev->dev, dp_parser->swing_hbr_rbr); + devm_kfree(&dp_parser->pdev->dev, dp_parser->pre_emp_hbr_rbr); + + dp_parser->swing_hbr2_3 = NULL; + dp_parser->pre_emp_hbr2_3 = NULL; + dp_parser->swing_hbr_rbr = NULL; + dp_parser->pre_emp_hbr_rbr = NULL; + + dp_parser->valid_lt_params = false; +} + +static void dp_parser_link_training_params(struct dp_parser *parser) +{ + struct device *dev = &parser->pdev->dev; + int ret = 0; + + ret = parse_lt_param(dev, &parser->swing_hbr2_3, "qcom,hbr2-3-voltage-swing"); + if (ret) + goto early_exit; + + ret = parse_lt_param(dev, &parser->pre_emp_hbr2_3, "qcom,hbr2-3-pre-emphasis"); + if (ret) + goto early_exit; + + ret = parse_lt_param(dev, &parser->swing_hbr_rbr, "qcom,hbr-rbr-voltage-swing"); + if (ret) + goto early_exit; + + ret = parse_lt_param(dev, &parser->pre_emp_hbr_rbr, "qcom,hbr-rbr-pre-emphasis"); + if (ret) + goto early_exit; + + parser->valid_lt_params = true; + + DP_DEBUG("link training parameters parsing success\n"); + goto end; + +early_exit: + if(ret == -EINVAL) + DP_WARN("link training parameters not found - using default values\n"); + else + DP_ERR("link training parameters parsing failure ret: %d\n", ret); + + dp_parser_clear_link_training_params(parser); +end: + return; +} + static int dp_parser_parse(struct dp_parser *parser) { int rc = 0; @@ -815,6 +899,7 @@ static int dp_parser_parse(struct dp_parser *parser) dp_parser_fec(parser); dp_parser_widebus(parser); dp_parser_qos(parser); + dp_parser_link_training_params(parser); err: return rc; } @@ -922,6 +1007,7 @@ void dp_parser_put(struct dp_parser *parser) dp_parser_put_gpio_data(&parser->pdev->dev, &power[i]); } + dp_parser_clear_link_training_params(parser); dp_parser_clear_io_buf(parser); devm_kfree(&parser->pdev->dev, parser->io.data); devm_kfree(&parser->pdev->dev, parser); diff --git a/msm/dp/dp_parser.h b/msm/dp/dp_parser.h index 722f75b402..1ddd2af45f 100644 --- a/msm/dp/dp_parser.h +++ b/msm/dp/dp_parser.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -14,6 +14,8 @@ #define DP_MAX_PIXEL_CLK_KHZ 675000 #define DP_MAX_LINK_CLK_KHZ 810000 #define MAX_DP_MST_STREAMS 2 +#define MAX_SWING_LEVELS 4 +#define MAX_PRE_EMP_LEVELS 4 enum dp_pm_type { DP_CORE_PM, @@ -202,6 +204,11 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) *@mst_fixed_port: mst port_num reserved for fixed topology * @qos_cpu_mask: CPU mask for QOS * @qos_cpu_latency: CPU Latency setting for QOS + * @swing_hbr2_3: Voltage swing levels for HBR2 and HBR3 rates + * @pre_emp_hbr2_3: Pre-emphasis for HBR2 and HBR3 rates + * @swing_hbr_rbr: Voltage swing levels for HBR and RBR rates + * @pre_emp_hbr_rbr: Pre-emphasis for HBR and RBR rates + * @valid_lt_params: valid lt params * @parse: function to be called by client to parse device tree. * @get_io: function to be called by client to get io data. * @get_io_buf: function to be called by client to get io buffers. @@ -232,6 +239,13 @@ struct dp_parser { u32 qos_cpu_mask; unsigned long qos_cpu_latency; + u8 *swing_hbr2_3; + u8 *pre_emp_hbr2_3; + + u8 *swing_hbr_rbr; + u8 *pre_emp_hbr_rbr; + bool valid_lt_params; + int (*parse)(struct dp_parser *parser); struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name); void (*get_io_buf)(struct dp_parser *parser, char *name);