mirror of
https://github.com/torvalds/linux.git
synced 2026-05-21 05:18:45 +02:00
Merge branch 'pci/controller/qcom'
- Add OF support for parsing DT 'eq-presets-<N>gts' property for lane equalization presets (Krishna Chaitanya Chundru) - Read Maximum Link Width from the Link Capabilities register if DT lacks 'num-lanes' property (Krishna Chaitanya Chundru) - Add Physical Layer 64 GT/s Capability ID and register offsets for 8, 32, and 64 GT/s lane equalization registers (Krishna Chaitanya Chundru) - Add generic dwc support for configuring lane equalization presets (Krishna Chaitanya Chundru) - Add DT and driver support for PCIe on IPQ5018 SoC (Nitheesh Sekar) * pci/controller/qcom: PCI: qcom: Add support for IPQ5018 dt-bindings: PCI: qcom: Add IPQ5018 SoC PCI: dwc: Add support for configuring lane equalization presets PCI: Add lane equalization register offsets PCI: dwc: Update pci->num_lanes to maximum supported link width PCI: of: Add of_pci_get_equalization_presets() API
This commit is contained in:
commit
05cf00aa05
|
|
@ -21,6 +21,7 @@ properties:
|
|||
- qcom,pcie-apq8064
|
||||
- qcom,pcie-apq8084
|
||||
- qcom,pcie-ipq4019
|
||||
- qcom,pcie-ipq5018
|
||||
- qcom,pcie-ipq6018
|
||||
- qcom,pcie-ipq8064
|
||||
- qcom,pcie-ipq8064-v2
|
||||
|
|
@ -168,6 +169,7 @@ allOf:
|
|||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,pcie-ipq5018
|
||||
- qcom,pcie-ipq6018
|
||||
- qcom,pcie-ipq8074-gen3
|
||||
- qcom,pcie-ipq9574
|
||||
|
|
@ -322,6 +324,53 @@ allOf:
|
|||
- const: ahb # AHB reset
|
||||
- const: phy_ahb # PHY AHB reset
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,pcie-ipq5018
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 6
|
||||
maxItems: 6
|
||||
clock-names:
|
||||
items:
|
||||
- const: iface # PCIe to SysNOC BIU clock
|
||||
- const: axi_m # AXI Master clock
|
||||
- const: axi_s # AXI Slave clock
|
||||
- const: ahb # AHB clock
|
||||
- const: aux # Auxiliary clock
|
||||
- const: axi_bridge # AXI bridge clock
|
||||
resets:
|
||||
minItems: 8
|
||||
maxItems: 8
|
||||
reset-names:
|
||||
items:
|
||||
- const: pipe # PIPE reset
|
||||
- const: sleep # Sleep reset
|
||||
- const: sticky # Core sticky reset
|
||||
- const: axi_m # AXI master reset
|
||||
- const: axi_s # AXI slave reset
|
||||
- const: ahb # AHB reset
|
||||
- const: axi_m_sticky # AXI master sticky reset
|
||||
- const: axi_s_sticky # AXI slave sticky reset
|
||||
interrupts:
|
||||
minItems: 9
|
||||
maxItems: 9
|
||||
interrupt-names:
|
||||
items:
|
||||
- const: msi0
|
||||
- const: msi1
|
||||
- const: msi2
|
||||
- const: msi3
|
||||
- const: msi4
|
||||
- const: msi5
|
||||
- const: msi6
|
||||
- const: msi7
|
||||
- const: global
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
|
@ -562,6 +611,7 @@ allOf:
|
|||
enum:
|
||||
- qcom,pcie-apq8064
|
||||
- qcom,pcie-ipq4019
|
||||
- qcom,pcie-ipq5018
|
||||
- qcom,pcie-ipq8064
|
||||
- qcom,pcie-ipq8064v2
|
||||
- qcom,pcie-ipq8074
|
||||
|
|
|
|||
|
|
@ -523,6 +523,13 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
|
|||
|
||||
dw_pcie_iatu_detect(pci);
|
||||
|
||||
if (pci->num_lanes < 1)
|
||||
pci->num_lanes = dw_pcie_link_get_max_link_width(pci);
|
||||
|
||||
ret = of_pci_get_equalization_presets(dev, &pp->presets, pci->num_lanes);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
|
||||
/*
|
||||
* Allocate the resource for MSG TLP before programming the iATU
|
||||
* outbound window in dw_pcie_setup_rc(). Since the allocation depends
|
||||
|
|
@ -828,6 +835,77 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dw_pcie_program_presets(struct dw_pcie_rp *pp, enum pci_bus_speed speed)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
u8 lane_eq_offset, lane_reg_size, cap_id;
|
||||
u8 *presets;
|
||||
u32 cap;
|
||||
int i;
|
||||
|
||||
if (speed == PCIE_SPEED_8_0GT) {
|
||||
presets = (u8 *)pp->presets.eq_presets_8gts;
|
||||
lane_eq_offset = PCI_SECPCI_LE_CTRL;
|
||||
cap_id = PCI_EXT_CAP_ID_SECPCI;
|
||||
/* For data rate of 8 GT/S each lane equalization control is 16bits wide*/
|
||||
lane_reg_size = 0x2;
|
||||
} else if (speed == PCIE_SPEED_16_0GT) {
|
||||
presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_16GTS - 1];
|
||||
lane_eq_offset = PCI_PL_16GT_LE_CTRL;
|
||||
cap_id = PCI_EXT_CAP_ID_PL_16GT;
|
||||
lane_reg_size = 0x1;
|
||||
} else if (speed == PCIE_SPEED_32_0GT) {
|
||||
presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_32GTS - 1];
|
||||
lane_eq_offset = PCI_PL_32GT_LE_CTRL;
|
||||
cap_id = PCI_EXT_CAP_ID_PL_32GT;
|
||||
lane_reg_size = 0x1;
|
||||
} else if (speed == PCIE_SPEED_64_0GT) {
|
||||
presets = pp->presets.eq_presets_Ngts[EQ_PRESET_TYPE_64GTS - 1];
|
||||
lane_eq_offset = PCI_PL_64GT_LE_CTRL;
|
||||
cap_id = PCI_EXT_CAP_ID_PL_64GT;
|
||||
lane_reg_size = 0x1;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (presets[0] == PCI_EQ_RESV)
|
||||
return;
|
||||
|
||||
cap = dw_pcie_find_ext_capability(pci, cap_id);
|
||||
if (!cap)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Write preset values to the registers byte-by-byte for the given
|
||||
* number of lanes and register size.
|
||||
*/
|
||||
for (i = 0; i < pci->num_lanes * lane_reg_size; i++)
|
||||
dw_pcie_writeb_dbi(pci, cap + lane_eq_offset + i, presets[i]);
|
||||
}
|
||||
|
||||
static void dw_pcie_config_presets(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
enum pci_bus_speed speed = pcie_link_speed[pci->max_link_speed];
|
||||
|
||||
/*
|
||||
* Lane equalization settings need to be applied for all data rates the
|
||||
* controller supports and for all supported lanes.
|
||||
*/
|
||||
|
||||
if (speed >= PCIE_SPEED_8_0GT)
|
||||
dw_pcie_program_presets(pp, PCIE_SPEED_8_0GT);
|
||||
|
||||
if (speed >= PCIE_SPEED_16_0GT)
|
||||
dw_pcie_program_presets(pp, PCIE_SPEED_16_0GT);
|
||||
|
||||
if (speed >= PCIE_SPEED_32_0GT)
|
||||
dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT);
|
||||
|
||||
if (speed >= PCIE_SPEED_64_0GT)
|
||||
dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT);
|
||||
}
|
||||
|
||||
int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
|
@ -881,6 +959,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
|
|||
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
|
||||
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
|
||||
|
||||
dw_pcie_config_presets(pp);
|
||||
/*
|
||||
* If the platform provides its own child bus config accesses, it means
|
||||
* the platform uses its own address translation component rather than
|
||||
|
|
|
|||
|
|
@ -781,6 +781,14 @@ static void dw_pcie_link_set_max_speed(struct dw_pcie *pci)
|
|||
|
||||
}
|
||||
|
||||
int dw_pcie_link_get_max_link_width(struct dw_pcie *pci)
|
||||
{
|
||||
u8 cap = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u32 lnkcap = dw_pcie_readl_dbi(pci, cap + PCI_EXP_LNKCAP);
|
||||
|
||||
return FIELD_GET(PCI_EXP_LNKCAP_MLW, lnkcap);
|
||||
}
|
||||
|
||||
static void dw_pcie_link_set_max_link_width(struct dw_pcie *pci, u32 num_lanes)
|
||||
{
|
||||
u32 lnkcap, lwsc, plc;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include <linux/pci-epc.h>
|
||||
#include <linux/pci-epf.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
|
||||
/* DWC PCIe IP-core versions (native support since v4.70a) */
|
||||
#define DW_PCIE_VER_365A 0x3336352a
|
||||
#define DW_PCIE_VER_460A 0x3436302a
|
||||
|
|
@ -412,6 +414,7 @@ struct dw_pcie_rp {
|
|||
int msg_atu_index;
|
||||
struct resource *msg_res;
|
||||
bool use_linkup_irq;
|
||||
struct pci_eq_presets presets;
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_ops {
|
||||
|
|
@ -540,6 +543,7 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
|||
bool dw_pcie_link_up(struct dw_pcie *pci);
|
||||
void dw_pcie_upconfig_setup(struct dw_pcie *pci);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
int dw_pcie_link_get_max_link_width(struct dw_pcie *pci);
|
||||
int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
|
||||
const struct dw_pcie_ob_atu_cfg *atu);
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
|
|
|
|||
|
|
@ -1840,6 +1840,7 @@ static const struct of_device_id qcom_pcie_match[] = {
|
|||
{ .compatible = "qcom,pcie-apq8064", .data = &cfg_2_1_0 },
|
||||
{ .compatible = "qcom,pcie-apq8084", .data = &cfg_1_0_0 },
|
||||
{ .compatible = "qcom,pcie-ipq4019", .data = &cfg_2_4_0 },
|
||||
{ .compatible = "qcom,pcie-ipq5018", .data = &cfg_2_9_0 },
|
||||
{ .compatible = "qcom,pcie-ipq6018", .data = &cfg_2_9_0 },
|
||||
{ .compatible = "qcom,pcie-ipq8064", .data = &cfg_2_1_0 },
|
||||
{ .compatible = "qcom,pcie-ipq8064-v2", .data = &cfg_2_1_0 },
|
||||
|
|
|
|||
|
|
@ -966,3 +966,47 @@ 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 @presets structure.
|
||||
* Else, assign a default value of PCI_EQ_RESV.
|
||||
*
|
||||
* Return: 0 if the property is not available or successfully parsed else
|
||||
* 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 - 1; 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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -891,6 +893,21 @@ 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_8GTS,
|
||||
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 - 1][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);
|
||||
|
|
@ -905,7 +922,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)
|
||||
|
|
@ -950,6 +969,17 @@ 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)
|
||||
{
|
||||
presets->eq_presets_8gts[0] = PCI_EQ_RESV;
|
||||
for (int i = 0; i < EQ_PRESET_TYPE_MAX - 1; i++)
|
||||
presets->eq_presets_Ngts[i][0] = PCI_EQ_RESV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
struct of_changeset;
|
||||
|
|
|
|||
|
|
@ -750,7 +750,8 @@
|
|||
#define PCI_EXT_CAP_ID_NPEM 0x29 /* Native PCIe Enclosure Management */
|
||||
#define PCI_EXT_CAP_ID_PL_32GT 0x2A /* Physical Layer 32.0 GT/s */
|
||||
#define PCI_EXT_CAP_ID_DOE 0x2E /* Data Object Exchange */
|
||||
#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DOE
|
||||
#define PCI_EXT_CAP_ID_PL_64GT 0x31 /* Physical Layer 64.0 GT/s */
|
||||
#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PL_64GT
|
||||
|
||||
#define PCI_EXT_CAP_DSN_SIZEOF 12
|
||||
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
|
||||
|
|
@ -1144,12 +1145,21 @@
|
|||
#define PCI_DLF_CAP 0x04 /* Capabilities Register */
|
||||
#define PCI_DLF_EXCHANGE_ENABLE 0x80000000 /* Data Link Feature Exchange Enable */
|
||||
|
||||
/* Secondary PCIe Capability 8.0 GT/s */
|
||||
#define PCI_SECPCI_LE_CTRL 0x0c /* Lane Equalization Control Register */
|
||||
|
||||
/* Physical Layer 16.0 GT/s */
|
||||
#define PCI_PL_16GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
|
||||
#define PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK 0x0000000F
|
||||
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK 0x000000F0
|
||||
#define PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT 4
|
||||
|
||||
/* Physical Layer 32.0 GT/s */
|
||||
#define PCI_PL_32GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
|
||||
|
||||
/* Physical Layer 64.0 GT/s */
|
||||
#define PCI_PL_64GT_LE_CTRL 0x20 /* Lane Equalization Control Register */
|
||||
|
||||
/* Native PCIe Enclosure Management */
|
||||
#define PCI_NPEM_CAP 0x04 /* NPEM capability register */
|
||||
#define PCI_NPEM_CAP_CAPABLE 0x00000001 /* NPEM Capable */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user