Commit 05cf00aa authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

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
parents c7b9c591 3e512746
Loading
Loading
Loading
Loading
+50 −0
Original line number Diff line number Diff line
@@ -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
+79 −0
Original line number Diff line number Diff line
@@ -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
+8 −0
Original line number Diff line number Diff line
@@ -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;
+4 −0
Original line number Diff line number Diff line
@@ -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,
+1 −0
Original line number Diff line number Diff line
@@ -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 },
Loading