Skip to content

Commit

Permalink
Merge branch 'remotes/lorenzo/pci/dwc'
Browse files Browse the repository at this point in the history
  - Support 100MHz/200MHz refclocks for i.MX6 (Lucas Stach)

  - Add initial power management for i.MX7 (Leonard Crestez)

  - Add PME_Turn_Off support for i.MX7 (Leonard Crestez)

  - Fix qcom runtime power management error handling (Bjorn Andersson)

  - Update TI dra7xx unaligned access errata workaround for host mode as
    well as endpoint mode (Vignesh R)

  - Fix kirin section mismatch warning (Nathan Chancellor)

* remotes/lorenzo/pci/dwc:
  PCI: imx: Add PME_Turn_Off support
  ARM: dts: imx7d: Add turnoff reset
  dt-bindings: imx6q-pcie: Add turnoff reset for imx7d
  reset: imx7: Add PCIE_CTRL_APPS_TURNOFF
  PCI: kirin: Fix section mismatch warning
  PCI: dwc: pci-dra7xx: Enable errata i870 for both EP and RC mode
  dt-bindings: PCI: dra7xx: Add bindings for unaligned access in host mode
  PCI: qcom: Fix error handling in runtime PM support
  PCI: imx: Initial imx7d pm support
  PCI: imx6: Support MPLL reconfiguration for 100MHz and 200MHz refclock
  • Loading branch information
Bjorn Helgaas committed Oct 20, 2018
2 parents b7c18dc + f4e833b commit 525fde0
Show file tree
Hide file tree
Showing 9 changed files with 233 additions and 30 deletions.
1 change: 1 addition & 0 deletions Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Additional required properties for imx7d-pcie:
- reset-names: Must contain the following entires:
- "pciephy"
- "apps"
- "turnoff"

Example:

Expand Down
5 changes: 5 additions & 0 deletions Documentation/devicetree/bindings/pci/ti-pci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ HOST MODE
ranges,
interrupt-map-mask,
interrupt-map : as specified in ../designware-pcie.txt
- ti,syscon-unaligned-access: phandle to the syscon DT node. The 1st argument
should contain the register offset within syscon
and the 2nd argument should contain the bit field
for setting the bit to enable unaligned
access.

DEVICE MODE
===========
Expand Down
5 changes: 3 additions & 2 deletions arch/arm/boot/dts/imx7d.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,9 @@
fsl,max-link-speed = <2>;
power-domains = <&pgc_pcie_phy>;
resets = <&src IMX7_RESET_PCIEPHY>,
<&src IMX7_RESET_PCIE_CTRL_APPS_EN>;
reset-names = "pciephy", "apps";
<&src IMX7_RESET_PCIE_CTRL_APPS_EN>,
<&src IMX7_RESET_PCIE_CTRL_APPS_TURNOFF>;
reset-names = "pciephy", "apps", "turnoff";
status = "disabled";
};
};
Expand Down
11 changes: 8 additions & 3 deletions drivers/pci/controller/dwc/pci-dra7xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
};

/*
* dra7xx_pcie_ep_unaligned_memaccess: workaround for AM572x/AM571x Errata i870
* dra7xx_pcie_unaligned_memaccess: workaround for AM572x/AM571x Errata i870
* @dra7xx: the dra7xx device where the workaround should be applied
*
* Access to the PCIe slave port that are not 32-bit aligned will result
Expand All @@ -552,7 +552,7 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
*
* To avoid this issue set PCIE_SS1_AXI2OCP_LEGACY_MODE_ENABLE to 1.
*/
static int dra7xx_pcie_ep_unaligned_memaccess(struct device *dev)
static int dra7xx_pcie_unaligned_memaccess(struct device *dev)
{
int ret;
struct device_node *np = dev->of_node;
Expand Down Expand Up @@ -704,6 +704,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)

dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
DEVICE_TYPE_RC);

ret = dra7xx_pcie_unaligned_memaccess(dev);
if (ret)
dev_err(dev, "WA for Errata i870 not applied\n");

ret = dra7xx_add_pcie_port(dra7xx, pdev);
if (ret < 0)
goto err_gpio;
Expand All @@ -717,7 +722,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
DEVICE_TYPE_EP);

ret = dra7xx_pcie_ep_unaligned_memaccess(dev);
ret = dra7xx_pcie_unaligned_memaccess(dev);
if (ret)
goto err_gpio;

Expand Down
176 changes: 171 additions & 5 deletions drivers/pci/controller/dwc/pci-imx6.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ struct imx6_pcie {
struct regmap *iomuxc_gpr;
struct reset_control *pciephy_reset;
struct reset_control *apps_reset;
struct reset_control *turnoff_reset;
enum imx6_pcie_variants variant;
u32 tx_deemph_gen1;
u32 tx_deemph_gen2_3p5db;
Expand Down Expand Up @@ -97,6 +98,16 @@ struct imx6_pcie {
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)

/* PHY registers (not memory-mapped) */
#define PCIE_PHY_ATEOVRD 0x10
#define PCIE_PHY_ATEOVRD_EN (0x1 << 2)
#define PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT 0
#define PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK 0x1

#define PCIE_PHY_MPLL_OVRD_IN_LO 0x11
#define PCIE_PHY_MPLL_MULTIPLIER_SHIFT 2
#define PCIE_PHY_MPLL_MULTIPLIER_MASK 0x7f
#define PCIE_PHY_MPLL_MULTIPLIER_OVRD (0x1 << 9)

#define PCIE_PHY_RX_ASIC_OUT 0x100D
#define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0)

Expand Down Expand Up @@ -508,6 +519,50 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
}

static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
{
unsigned long phy_rate = clk_get_rate(imx6_pcie->pcie_phy);
int mult, div;
u32 val;

switch (phy_rate) {
case 125000000:
/*
* The default settings of the MPLL are for a 125MHz input
* clock, so no need to reconfigure anything in that case.
*/
return 0;
case 100000000:
mult = 25;
div = 0;
break;
case 200000000:
mult = 25;
div = 1;
break;
default:
dev_err(imx6_pcie->pci->dev,
"Unsupported PHY reference clock rate %lu\n", phy_rate);
return -EINVAL;
}

pcie_phy_read(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, &val);
val &= ~(PCIE_PHY_MPLL_MULTIPLIER_MASK <<
PCIE_PHY_MPLL_MULTIPLIER_SHIFT);
val |= mult << PCIE_PHY_MPLL_MULTIPLIER_SHIFT;
val |= PCIE_PHY_MPLL_MULTIPLIER_OVRD;
pcie_phy_write(imx6_pcie, PCIE_PHY_MPLL_OVRD_IN_LO, val);

pcie_phy_read(imx6_pcie, PCIE_PHY_ATEOVRD, &val);
val &= ~(PCIE_PHY_ATEOVRD_REF_CLKDIV_MASK <<
PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT);
val |= div << PCIE_PHY_ATEOVRD_REF_CLKDIV_SHIFT;
val |= PCIE_PHY_ATEOVRD_EN;
pcie_phy_write(imx6_pcie, PCIE_PHY_ATEOVRD, val);

return 0;
}

static int imx6_pcie_wait_for_link(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
Expand Down Expand Up @@ -542,6 +597,24 @@ static int imx6_pcie_wait_for_speed_change(struct imx6_pcie *imx6_pcie)
return -EINVAL;
}

static void imx6_pcie_ltssm_enable(struct device *dev)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);

switch (imx6_pcie->variant) {
case IMX6Q:
case IMX6SX:
case IMX6QP:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2,
IMX6Q_GPR12_PCIE_CTL_2);
break;
case IMX7D:
reset_control_deassert(imx6_pcie->apps_reset);
break;
}
}

static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
{
struct dw_pcie *pci = imx6_pcie->pci;
Expand All @@ -560,11 +633,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);

/* Start LTSSM. */
if (imx6_pcie->variant == IMX7D)
reset_control_deassert(imx6_pcie->apps_reset);
else
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 1 << 10);
imx6_pcie_ltssm_enable(dev);

ret = imx6_pcie_wait_for_link(imx6_pcie);
if (ret)
Expand Down Expand Up @@ -632,6 +701,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie);
imx6_setup_phy_mpll(imx6_pcie);
dw_pcie_setup_rc(pp);
imx6_pcie_establish_link(imx6_pcie);

Expand Down Expand Up @@ -682,6 +752,94 @@ static const struct dw_pcie_ops dw_pcie_ops = {
.link_up = imx6_pcie_link_up,
};

#ifdef CONFIG_PM_SLEEP
static void imx6_pcie_ltssm_disable(struct device *dev)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);

switch (imx6_pcie->variant) {
case IMX6SX:
case IMX6QP:
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX6Q_GPR12_PCIE_CTL_2, 0);
break;
case IMX7D:
reset_control_assert(imx6_pcie->apps_reset);
break;
default:
dev_err(dev, "ltssm_disable not supported\n");
}
}

static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
{
reset_control_assert(imx6_pcie->turnoff_reset);
reset_control_deassert(imx6_pcie->turnoff_reset);

/*
* Components with an upstream port must respond to
* PME_Turn_Off with PME_TO_Ack but we can't check.
*
* The standard recommends a 1-10ms timeout after which to
* proceed anyway as if acks were received.
*/
usleep_range(1000, 10000);
}

static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
{
clk_disable_unprepare(imx6_pcie->pcie);
clk_disable_unprepare(imx6_pcie->pcie_phy);
clk_disable_unprepare(imx6_pcie->pcie_bus);

if (imx6_pcie->variant == IMX7D) {
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
}
}

static int imx6_pcie_suspend_noirq(struct device *dev)
{
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);

if (imx6_pcie->variant != IMX7D)
return 0;

imx6_pcie_pm_turnoff(imx6_pcie);
imx6_pcie_clk_disable(imx6_pcie);
imx6_pcie_ltssm_disable(dev);

return 0;
}

static int imx6_pcie_resume_noirq(struct device *dev)
{
int ret;
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
struct pcie_port *pp = &imx6_pcie->pci->pp;

if (imx6_pcie->variant != IMX7D)
return 0;

imx6_pcie_assert_core_reset(imx6_pcie);
imx6_pcie_init_phy(imx6_pcie);
imx6_pcie_deassert_core_reset(imx6_pcie);
dw_pcie_setup_rc(pp);

ret = imx6_pcie_establish_link(imx6_pcie);
if (ret < 0)
dev_info(dev, "pcie link is down after resume.\n");

return 0;
}
#endif

static const struct dev_pm_ops imx6_pcie_pm_ops = {
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx6_pcie_suspend_noirq,
imx6_pcie_resume_noirq)
};

static int imx6_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
Expand Down Expand Up @@ -776,6 +934,13 @@ static int imx6_pcie_probe(struct platform_device *pdev)
break;
}

/* Grab turnoff reset */
imx6_pcie->turnoff_reset = devm_reset_control_get_optional_exclusive(dev, "turnoff");
if (IS_ERR(imx6_pcie->turnoff_reset)) {
dev_err(dev, "Failed to get TURNOFF reset control\n");
return PTR_ERR(imx6_pcie->turnoff_reset);
}

/* Grab GPR config register range */
imx6_pcie->iomuxc_gpr =
syscon_regmap_lookup_by_compatible("fsl,imx6q-iomuxc-gpr");
Expand Down Expand Up @@ -848,6 +1013,7 @@ static struct platform_driver imx6_pcie_driver = {
.name = "imx6q-pcie",
.of_match_table = imx6_pcie_of_match,
.suppress_bind_attrs = true,
.pm = &imx6_pcie_pm_ops,
},
.probe = imx6_pcie_probe,
.shutdown = imx6_pcie_shutdown,
Expand Down
4 changes: 2 additions & 2 deletions drivers/pci/controller/dwc/pcie-kirin.c
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,8 @@ static int kirin_pcie_add_msi(struct dw_pcie *pci,
return 0;
}

static int __init kirin_add_pcie_port(struct dw_pcie *pci,
struct platform_device *pdev)
static int kirin_add_pcie_port(struct dw_pcie *pci,
struct platform_device *pdev)
{
int ret;

Expand Down
Loading

0 comments on commit 525fde0

Please sign in to comment.