PCIe equalization presets are predefined settings used to optimize signal integrity by compensating for signal loss and distortion in high-speed data transmission. As per PCIe spec 6.0.1 revision section 8.3.3.3 & 4.2.4 for data rates of 8.0 GT/s, 16.0 GT/s, 32.0 GT/s, and 64.0 GT/s, there is a way to configure lane equalization presets for each lane to enhance the PCIe link reliability. Each preset value represents a different combination of pre-shoot and de-emphasis values. For each data rate, different registers are defined: for 8.0 GT/s, registers are defined in section 7.7.3.4; for 16.0 GT/s, in section 7.7.5.9, etc. The 8.0 GT/s rate has an extra receiver preset hint, requiring 16 bits per lane, while the remaining data rates use 8 bits per lane. Based on the number of lanes and the supported data rate, this function reads the device tree property and stores in the presets structure. Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx> --- drivers/pci/of.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 27 ++++++++++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/drivers/pci/of.c b/drivers/pci/of.c index 7a806f5c0d20..705d5529fa95 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -851,3 +851,46 @@ u32 of_pci_get_slot_power_limit(struct device_node *node, return slot_power_limit_mw; } EXPORT_SYMBOL_GPL(of_pci_get_slot_power_limit); + +/** + * of_pci_get_equalization_presets - Parses the "eq-presets-ngts" property. + * + * @dev: Device containing the properties. + * @presets: Pointer to store the parsed data. + * @num_lanes: Maximum number of lanes supported. + * + * If the property is present read and store the data in the preset structure + * assign default value 0xff to indicate property is not present. + * + * Return: 0 if the property is not available or successfully parsed; errno otherwise. + */ +int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes) +{ + char name[20]; + int ret; + + presets->eq_presets_8gts[0] = PCI_EQ_RESV; + ret = of_property_read_u16_array(dev->of_node, "eq-presets-8gts", + presets->eq_presets_8gts, num_lanes); + if (ret && ret != -EINVAL) { + dev_err(dev, "Error reading eq-presets-8gts %d\n", ret); + return ret; + } + + for (int i = 0; i < EQ_PRESET_TYPE_MAX; i++) { + presets->eq_presets_Ngts[i][0] = PCI_EQ_RESV; + snprintf(name, sizeof(name), "eq-presets-%dgts", 8 << (i + 1)); + ret = of_property_read_u8_array(dev->of_node, name, + presets->eq_presets_Ngts[i], + num_lanes); + if (ret && ret != -EINVAL) { + dev_err(dev, "Error reading %s %d\n", name, ret); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(of_pci_get_equalization_presets); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 01e51db8d285..e87c2ffd1e85 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -9,6 +9,8 @@ struct pcie_tlp_log; /* Number of possible devfns: 0.0 to 1f.7 inclusive */ #define MAX_NR_DEVFNS 256 +#define MAX_NR_LANES 16 + #define PCI_FIND_CAP_TTL 48 #define PCI_VSEC_ID_INTEL_TBT 0x1234 /* Thunderbolt */ @@ -808,6 +810,20 @@ static inline u64 pci_rebar_size_to_bytes(int size) struct device_node; +#define PCI_EQ_RESV 0xff + +enum equalization_preset_type { + EQ_PRESET_TYPE_16GTS, + EQ_PRESET_TYPE_32GTS, + EQ_PRESET_TYPE_64GTS, + EQ_PRESET_TYPE_MAX +}; + +struct pci_eq_presets { + u16 eq_presets_8gts[MAX_NR_LANES]; + u8 eq_presets_Ngts[EQ_PRESET_TYPE_MAX][MAX_NR_LANES]; +}; + #ifdef CONFIG_OF int of_get_pci_domain_nr(struct device_node *node); int of_pci_get_max_link_speed(struct device_node *node); @@ -822,7 +838,9 @@ void pci_release_bus_of_node(struct pci_bus *bus); int devm_of_pci_bridge_init(struct device *dev, struct pci_host_bridge *bridge); bool of_pci_supply_present(struct device_node *np); - +int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes); #else static inline int of_get_pci_domain_nr(struct device_node *node) @@ -867,6 +885,13 @@ static inline bool of_pci_supply_present(struct device_node *np) { return false; } + +static inline int of_pci_get_equalization_presets(struct device *dev, + struct pci_eq_presets *presets, + int num_lanes) +{ + return 0; +} #endif /* CONFIG_OF */ struct of_changeset; -- 2.34.1