--- 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 { @@ -156,10 +202,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 +250,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,6 +274,18 @@ 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"); @@ -228,12 +295,18 @@ static int qcom_pcie_enable_resources_v0 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 +402,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 +430,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 +550,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_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); + writel((pp->cfg0_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); + writel((pp->cfg0_mod_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_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR); + writel((pp->mem_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR); + writel(pp->mem_mod_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); + + /* 1K PCIE buffer setting */ + writel(0x3, 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); @@ -476,9 +616,26 @@ static void qcom_pcie_host_init_v0(struc 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 +674,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);