diff options
Diffstat (limited to 'target/linux/ipq806x/patches-4.4/114-pcie-add-ctlr-init.patch')
-rw-r--r-- | target/linux/ipq806x/patches-4.4/114-pcie-add-ctlr-init.patch | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.4/114-pcie-add-ctlr-init.patch b/target/linux/ipq806x/patches-4.4/114-pcie-add-ctlr-init.patch new file mode 100644 index 0000000000..6328113c06 --- /dev/null +++ b/target/linux/ipq806x/patches-4.4/114-pcie-add-ctlr-init.patch @@ -0,0 +1,311 @@ +--- a/drivers/pci/host/pcie-qcom.c ++++ b/drivers/pci/host/pcie-qcom.c +@@ -29,8 +29,53 @@ + + #include "pcie-designware.h" + ++/* DBI registers */ ++#define PCIE20_CAP 0x70 ++#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) ++ ++#define PCIE20_AXI_MSTR_RESP_COMP_CTRL0 0x818 ++#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c ++ ++#define PCIE20_PLR_IATU_VIEWPORT 0x900 ++#define PCIE20_PLR_IATU_REGION_OUTBOUND (0x0 << 31) ++#define PCIE20_PLR_IATU_REGION_INDEX(x) (x << 0) ++ ++#define PCIE20_PLR_IATU_CTRL1 0x904 ++#define PCIE20_PLR_IATU_TYPE_CFG0 (0x4 << 0) ++#define PCIE20_PLR_IATU_TYPE_MEM (0x0 << 0) ++ ++#define PCIE20_PLR_IATU_CTRL2 0x908 ++#define PCIE20_PLR_IATU_ENABLE BIT(31) ++ ++#define PCIE20_PLR_IATU_LBAR 0x90C ++#define PCIE20_PLR_IATU_UBAR 0x910 ++#define PCIE20_PLR_IATU_LAR 0x914 ++#define PCIE20_PLR_IATU_LTAR 0x918 ++#define PCIE20_PLR_IATU_UTAR 0x91c ++ ++#define MSM_PCIE_DEV_CFG_ADDR 0x01000000 ++ ++/* PARF registers */ ++#define PCIE20_PARF_PCS_DEEMPH 0x34 ++#define PCS_DEEMPH_TX_DEEMPH_GEN1(x) (x << 16) ++#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) (x << 8) ++#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) (x << 0) ++ ++#define PCIE20_PARF_PCS_SWING 0x38 ++#define PCS_SWING_TX_SWING_FULL(x) (x << 8) ++#define PCS_SWING_TX_SWING_LOW(x) (x << 0) ++ + #define PCIE20_PARF_PHY_CTRL 0x40 ++#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK (0x1f << 16) ++#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) (x << 16) ++ + #define PCIE20_PARF_PHY_REFCLK 0x4C ++#define REF_SSP_EN BIT(16) ++#define REF_USE_PAD BIT(12) ++ ++#define PCIE20_PARF_CONFIG_BITS 0x50 ++#define PHY_RX0_EQ(x) (x << 24) ++ + #define PCIE20_PARF_DBI_BASE_ADDR 0x168 + #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c + #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178 +@@ -39,9 +84,6 @@ + #define PCIE20_ELBI_SYS_STTS 0x08 + #define XMLH_LINK_UP BIT(10) + +-#define PCIE20_CAP 0x70 +-#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10) +- + #define PERST_DELAY_MIN_US 1000 + #define PERST_DELAY_MAX_US 1005 + +@@ -56,14 +98,18 @@ struct qcom_pcie_resources_v0 { + struct clk *iface_clk; + struct clk *core_clk; + struct clk *phy_clk; ++ struct clk *aux_clk; ++ struct clk *ref_clk; + struct reset_control *pci_reset; + struct reset_control *axi_reset; + struct reset_control *ahb_reset; + struct reset_control *por_reset; + struct reset_control *phy_reset; ++ struct reset_control *ext_reset; + struct regulator *vdda; + struct regulator *vdda_phy; + struct regulator *vdda_refclk; ++ uint8_t phy_tx0_term_offset; + }; + + struct qcom_pcie_resources_v1 { +@@ -106,20 +152,10 @@ writel_masked(void __iomem *addr, u32 cl + + static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert) + { +- int val, active_low; +- + if (IS_ERR_OR_NULL(pcie->reset)) + return; + +- active_low = gpiod_is_active_low(pcie->reset); +- +- if (assert) +- val = !!active_low; +- else +- val = !active_low; +- +- gpiod_set_value(pcie->reset, val); +- ++ gpiod_set_value(pcie->reset, assert); + usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US); + } + +@@ -156,10 +192,13 @@ static void qcom_pcie_disable_resources_ + reset_control_assert(res->axi_reset); + reset_control_assert(res->ahb_reset); + reset_control_assert(res->por_reset); +- reset_control_assert(res->pci_reset); ++ reset_control_assert(res->phy_reset); ++ reset_control_assert(res->ext_reset); + clk_disable_unprepare(res->iface_clk); + clk_disable_unprepare(res->core_clk); + clk_disable_unprepare(res->phy_clk); ++ clk_disable_unprepare(res->aux_clk); ++ clk_disable_unprepare(res->ref_clk); + regulator_disable(res->vdda); + regulator_disable(res->vdda_phy); + regulator_disable(res->vdda_refclk); +@@ -201,6 +240,12 @@ static int qcom_pcie_enable_resources_v0 + goto err_vdda_phy; + } + ++ ret = reset_control_deassert(res->ext_reset); ++ if (ret) { ++ dev_err(dev, "cannot assert ext reset\n"); ++ goto err_reset_ext; ++ } ++ + ret = clk_prepare_enable(res->iface_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable iface clock\n"); +@@ -219,21 +264,40 @@ static int qcom_pcie_enable_resources_v0 + goto err_clk_phy; + } + ++ ret = clk_prepare_enable(res->aux_clk); ++ if (ret) { ++ dev_err(dev, "cannot prepare/enable aux clock\n"); ++ goto err_clk_aux; ++ } ++ ++ ret = clk_prepare_enable(res->ref_clk); ++ if (ret) { ++ dev_err(dev, "cannot prepare/enable ref clock\n"); ++ goto err_clk_ref; ++ } ++ + ret = reset_control_deassert(res->ahb_reset); + if (ret) { + dev_err(dev, "cannot deassert ahb reset\n"); + goto err_reset_ahb; + } ++ udelay(1); + + return 0; + + err_reset_ahb: ++ clk_disable_unprepare(res->ref_clk); ++err_clk_ref: ++ clk_disable_unprepare(res->aux_clk); ++err_clk_aux: + clk_disable_unprepare(res->phy_clk); + err_clk_phy: + clk_disable_unprepare(res->core_clk); + err_clk_core: + clk_disable_unprepare(res->iface_clk); + err_iface: ++ reset_control_assert(res->ext_reset); ++err_reset_ext: + regulator_disable(res->vdda_phy); + err_vdda_phy: + regulator_disable(res->vdda_refclk); +@@ -329,6 +393,14 @@ static int qcom_pcie_get_resources_v0(st + if (IS_ERR(res->phy_clk)) + return PTR_ERR(res->phy_clk); + ++ res->aux_clk = devm_clk_get(dev, "aux"); ++ if (IS_ERR(res->aux_clk)) ++ return PTR_ERR(res->aux_clk); ++ ++ res->ref_clk = devm_clk_get(dev, "ref"); ++ if (IS_ERR(res->ref_clk)) ++ return PTR_ERR(res->ref_clk); ++ + res->pci_reset = devm_reset_control_get(dev, "pci"); + if (IS_ERR(res->pci_reset)) + return PTR_ERR(res->pci_reset); +@@ -349,6 +421,14 @@ static int qcom_pcie_get_resources_v0(st + if (IS_ERR(res->phy_reset)) + return PTR_ERR(res->phy_reset); + ++ res->ext_reset = devm_reset_control_get(dev, "ext"); ++ if (IS_ERR(res->ext_reset)) ++ return PTR_ERR(res->ext_reset); ++ ++ if (of_property_read_u8(dev->of_node, "phy-tx0-term-offset", ++ &res->phy_tx0_term_offset)) ++ res->phy_tx0_term_offset = 0; ++ + return 0; + } + +@@ -461,6 +541,57 @@ err_res: + qcom_pcie_disable_resources_v1(pcie); + } + ++static void qcom_pcie_prog_viewport_cfg0(struct qcom_pcie *pcie, u32 busdev) ++{ ++ struct pcie_port *pp = &pcie->pp; ++ ++ /* ++ * program and enable address translation region 0 (device config ++ * address space); region type config; ++ * axi config address range to device config address range ++ */ ++ writel(PCIE20_PLR_IATU_REGION_OUTBOUND | ++ PCIE20_PLR_IATU_REGION_INDEX(0), ++ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT); ++ ++ writel(PCIE20_PLR_IATU_TYPE_CFG0, pcie->dbi + PCIE20_PLR_IATU_CTRL1); ++ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2); ++ writel(pp->cfg0_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); ++ writel((pp->cfg0_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); ++ writel((pp->cfg0_base + pp->cfg0_size - 1), ++ pcie->dbi + PCIE20_PLR_IATU_LAR); ++ writel(busdev, pcie->dbi + PCIE20_PLR_IATU_LTAR); ++ writel(0, pcie->dbi + PCIE20_PLR_IATU_UTAR); ++} ++ ++static void qcom_pcie_prog_viewport_mem2_outbound(struct qcom_pcie *pcie) ++{ ++ struct pcie_port *pp = &pcie->pp; ++ ++ /* ++ * program and enable address translation region 2 (device resource ++ * address space); region type memory; ++ * axi device bar address range to device bar address range ++ */ ++ writel(PCIE20_PLR_IATU_REGION_OUTBOUND | ++ PCIE20_PLR_IATU_REGION_INDEX(2), ++ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT); ++ ++ writel(PCIE20_PLR_IATU_TYPE_MEM, pcie->dbi + PCIE20_PLR_IATU_CTRL1); ++ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2); ++ writel(pp->mem_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); ++ writel((pp->mem_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); ++ writel(pp->mem_base + pp->mem_size - 1, ++ pcie->dbi + PCIE20_PLR_IATU_LAR); ++ writel(pp->mem_bus_addr, pcie->dbi + PCIE20_PLR_IATU_LTAR); ++ writel(upper_32_bits(pp->mem_bus_addr), ++ pcie->dbi + PCIE20_PLR_IATU_UTAR); ++ ++ /* 256B PCIE buffer setting */ ++ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL0); ++ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL1); ++} ++ + static void qcom_pcie_host_init_v0(struct pcie_port *pp) + { + struct qcom_pcie *pcie = to_qcom_pcie(pp); +@@ -470,15 +601,34 @@ static void qcom_pcie_host_init_v0(struc + + qcom_ep_reset_assert(pcie); + ++ reset_control_assert(res->ahb_reset); ++ + ret = qcom_pcie_enable_resources_v0(pcie); + if (ret) + return; + + writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0); + +- /* enable external reference clock */ +- writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16)); ++ /* Set Tx termination offset */ ++ writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, ++ PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK, ++ PHY_CTRL_PHY_TX0_TERM_OFFSET(res->phy_tx0_term_offset)); ++ ++ /* PARF programming */ ++ writel(PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) | ++ PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) | ++ PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22), ++ pcie->parf + PCIE20_PARF_PCS_DEEMPH); ++ writel(PCS_SWING_TX_SWING_FULL(0x78) | ++ PCS_SWING_TX_SWING_LOW(0x78), ++ pcie->parf + PCIE20_PARF_PCS_SWING); ++ writel(PHY_RX0_EQ(0x4), pcie->parf + PCIE20_PARF_CONFIG_BITS); ++ ++ /* Enable reference clock */ ++ writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, ++ REF_USE_PAD, REF_SSP_EN); + ++ /* De-assert PHY, PCIe, POR and AXI resets */ + ret = reset_control_deassert(res->phy_reset); + if (ret) { + dev_err(dev, "cannot deassert phy reset\n"); +@@ -517,6 +667,9 @@ static void qcom_pcie_host_init_v0(struc + if (ret) + goto err; + ++ qcom_pcie_prog_viewport_cfg0(pcie, MSM_PCIE_DEV_CFG_ADDR); ++ qcom_pcie_prog_viewport_mem2_outbound(pcie); ++ + return; + err: + qcom_ep_reset_assert(pcie); |