mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 14:12:06 +00:00
Merge branch 'remotes/lorenzo/pci/dwc'
- Constify histb dw_pcie_host_ops structure (Julia Lawall) - Support multiple power domains for imx6 (Leonard Crestez) - Constify layerscape driver data (Stefan Agner) - Update imx6 Kconfig to allow imx6 PCIe in imx7 kernel (Trent Piepho) - Support armada8k GPIO reset (Baruch Siach) - Support suspend/resume support on imx6 (Leonard Crestez) - Don't hard-code DesignWare DBI/ATU offst (Stephen Warren) - Skip i.MX6 PHY setup on i.MX7D (Andrey Smirnov) - Remove Jianguo Sun from HiSilicon STB maintainers (Lorenzo Pieralisi) * remotes/lorenzo/pci/dwc: MAINTAINERS: Remove Jianguo Sun from HiSilicon STB DWC entry PCI: dwc: Don't hard-code DBI/ATU offset PCI: imx: Add imx6sx suspend/resume support PCI: armada8k: Add support for gpio controlled reset signal PCI: dwc: Adjust Kconfig to allow IMX6 PCIe host on IMX7 PCI: dwc: layerscape: Constify driver data PCI: imx: Add multi-pd support dt-bindings: imx6q-pcie: Add multi-pd bindings for imx6sx PCI: histb: Constify dw_pcie_host_ops structure
This commit is contained in:
commit
6a790bf0ea
@ -41,7 +41,9 @@ Optional properties:
|
||||
Additional required properties for imx6sx-pcie:
|
||||
- clock names: Must include the following additional entries:
|
||||
- "pcie_inbound_axi"
|
||||
- power-domains: Must be set to a phandle pointing to the PCIE_PHY power domain
|
||||
- power-domains: Must be set to phandles pointing to the DISPLAY and
|
||||
PCIE_PHY power domains
|
||||
- power-domain-names: Must be "pcie", "pcie_phy"
|
||||
|
||||
Additional required properties for imx7d-pcie:
|
||||
- power-domains: Must be set to a phandle pointing to PCIE_PHY power domain
|
||||
|
@ -11549,7 +11549,6 @@ F: Documentation/devicetree/bindings/pci/kirin-pcie.txt
|
||||
F: drivers/pci/controller/dwc/pcie-kirin.c
|
||||
|
||||
PCIE DRIVER FOR HISILICON STB
|
||||
M: Jianguo Sun <sunjianguo1@huawei.com>
|
||||
M: Shawn Guo <shawn.guo@linaro.org>
|
||||
L: linux-pci@vger.kernel.org
|
||||
S: Maintained
|
||||
|
@ -89,8 +89,8 @@ config PCI_EXYNOS
|
||||
select PCIE_DW_HOST
|
||||
|
||||
config PCI_IMX6
|
||||
bool "Freescale i.MX6 PCIe controller"
|
||||
depends on SOC_IMX6Q || (ARM && COMPILE_TEST)
|
||||
bool "Freescale i.MX6/7 PCIe controller"
|
||||
depends on SOC_IMX6Q || SOC_IMX7D || (ARM && COMPILE_TEST)
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
@ -59,6 +61,11 @@ struct imx6_pcie {
|
||||
u32 tx_swing_low;
|
||||
int link_gen;
|
||||
struct regulator *vpcie;
|
||||
|
||||
/* power domain for pcie */
|
||||
struct device *pd_pcie;
|
||||
/* power domain for pcie phy */
|
||||
struct device *pd_pcie_phy;
|
||||
};
|
||||
|
||||
/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
|
||||
@ -292,6 +299,43 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int imx6_pcie_attach_pd(struct device *dev)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
|
||||
struct device_link *link;
|
||||
|
||||
/* Do nothing when in a single power domain */
|
||||
if (dev->pm_domain)
|
||||
return 0;
|
||||
|
||||
imx6_pcie->pd_pcie = dev_pm_domain_attach_by_name(dev, "pcie");
|
||||
if (IS_ERR(imx6_pcie->pd_pcie))
|
||||
return PTR_ERR(imx6_pcie->pd_pcie);
|
||||
link = device_link_add(dev, imx6_pcie->pd_pcie,
|
||||
DL_FLAG_STATELESS |
|
||||
DL_FLAG_PM_RUNTIME |
|
||||
DL_FLAG_RPM_ACTIVE);
|
||||
if (!link) {
|
||||
dev_err(dev, "Failed to add device_link to pcie pd.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
imx6_pcie->pd_pcie_phy = dev_pm_domain_attach_by_name(dev, "pcie_phy");
|
||||
if (IS_ERR(imx6_pcie->pd_pcie_phy))
|
||||
return PTR_ERR(imx6_pcie->pd_pcie_phy);
|
||||
|
||||
device_link_add(dev, imx6_pcie->pd_pcie_phy,
|
||||
DL_FLAG_STATELESS |
|
||||
DL_FLAG_PM_RUNTIME |
|
||||
DL_FLAG_RPM_ACTIVE);
|
||||
if (IS_ERR(link)) {
|
||||
dev_err(dev, "Failed to add device_link to pcie_phy pd: %ld\n", PTR_ERR(link));
|
||||
return PTR_ERR(link);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct device *dev = imx6_pcie->pci->dev;
|
||||
@ -773,8 +817,28 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
|
||||
|
||||
static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct device *dev = imx6_pcie->pci->dev;
|
||||
|
||||
/* Some variants have a turnoff reset in DT */
|
||||
if (imx6_pcie->turnoff_reset) {
|
||||
reset_control_assert(imx6_pcie->turnoff_reset);
|
||||
reset_control_deassert(imx6_pcie->turnoff_reset);
|
||||
goto pm_turnoff_sleep;
|
||||
}
|
||||
|
||||
/* Others poke directly at IOMUXC registers */
|
||||
switch (imx6_pcie->variant) {
|
||||
case IMX6SX:
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6SX_GPR12_PCIE_PM_TURN_OFF,
|
||||
IMX6SX_GPR12_PCIE_PM_TURN_OFF);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6SX_GPR12_PCIE_PM_TURN_OFF, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(dev, "PME_Turn_Off not implemented\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Components with an upstream port must respond to
|
||||
@ -783,6 +847,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
|
||||
* The standard recommends a 1-10ms timeout after which to
|
||||
* proceed anyway as if acks were received.
|
||||
*/
|
||||
pm_turnoff_sleep:
|
||||
usleep_range(1000, 10000);
|
||||
}
|
||||
|
||||
@ -792,18 +857,31 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
|
||||
clk_disable_unprepare(imx6_pcie->pcie_phy);
|
||||
clk_disable_unprepare(imx6_pcie->pcie_bus);
|
||||
|
||||
if (imx6_pcie->variant == IMX7D) {
|
||||
switch (imx6_pcie->variant) {
|
||||
case IMX6SX:
|
||||
clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
|
||||
break;
|
||||
case IMX7D:
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
|
||||
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
return (imx6_pcie->variant == IMX7D ||
|
||||
imx6_pcie->variant == IMX6SX);
|
||||
}
|
||||
|
||||
static int imx6_pcie_suspend_noirq(struct device *dev)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
|
||||
|
||||
if (imx6_pcie->variant != IMX7D)
|
||||
if (!imx6_pcie_supports_suspend(imx6_pcie))
|
||||
return 0;
|
||||
|
||||
imx6_pcie_pm_turnoff(imx6_pcie);
|
||||
@ -819,7 +897,7 @@ static int imx6_pcie_resume_noirq(struct device *dev)
|
||||
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
|
||||
struct pcie_port *pp = &imx6_pcie->pci->pp;
|
||||
|
||||
if (imx6_pcie->variant != IMX7D)
|
||||
if (!imx6_pcie_supports_suspend(imx6_pcie))
|
||||
return 0;
|
||||
|
||||
imx6_pcie_assert_core_reset(imx6_pcie);
|
||||
@ -985,6 +1063,10 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, imx6_pcie);
|
||||
|
||||
ret = imx6_pcie_attach_pd(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = imx6_add_pcie_port(imx6_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -222,12 +222,12 @@ static const struct dw_pcie_ops dw_ls_pcie_ops = {
|
||||
.link_up = ls_pcie_link_up,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls1021_drvdata = {
|
||||
static const struct ls_pcie_drvdata ls1021_drvdata = {
|
||||
.ops = &ls1021_pcie_host_ops,
|
||||
.dw_pcie_ops = &dw_ls1021_pcie_ops,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls1043_drvdata = {
|
||||
static const struct ls_pcie_drvdata ls1043_drvdata = {
|
||||
.lut_offset = 0x10000,
|
||||
.ltssm_shift = 24,
|
||||
.lut_dbg = 0x7fc,
|
||||
@ -235,7 +235,7 @@ static struct ls_pcie_drvdata ls1043_drvdata = {
|
||||
.dw_pcie_ops = &dw_ls_pcie_ops,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls1046_drvdata = {
|
||||
static const struct ls_pcie_drvdata ls1046_drvdata = {
|
||||
.lut_offset = 0x80000,
|
||||
.ltssm_shift = 24,
|
||||
.lut_dbg = 0x407fc,
|
||||
@ -243,7 +243,7 @@ static struct ls_pcie_drvdata ls1046_drvdata = {
|
||||
.dw_pcie_ops = &dw_ls_pcie_ops,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls2080_drvdata = {
|
||||
static const struct ls_pcie_drvdata ls2080_drvdata = {
|
||||
.lut_offset = 0x80000,
|
||||
.ltssm_shift = 0,
|
||||
.lut_dbg = 0x7fc,
|
||||
@ -251,7 +251,7 @@ static struct ls_pcie_drvdata ls2080_drvdata = {
|
||||
.dw_pcie_ops = &dw_ls_pcie_ops,
|
||||
};
|
||||
|
||||
static struct ls_pcie_drvdata ls2088_drvdata = {
|
||||
static const struct ls_pcie_drvdata ls2088_drvdata = {
|
||||
.lut_offset = 0x80000,
|
||||
.ltssm_shift = 0,
|
||||
.lut_dbg = 0x407fc,
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/resource.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
@ -29,6 +30,7 @@ struct armada8k_pcie {
|
||||
struct dw_pcie *pci;
|
||||
struct clk *clk;
|
||||
struct clk *clk_reg;
|
||||
struct gpio_desc *reset_gpio;
|
||||
};
|
||||
|
||||
#define PCIE_VENDOR_REGS_OFFSET 0x8000
|
||||
@ -137,6 +139,12 @@ static int armada8k_pcie_host_init(struct pcie_port *pp)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct armada8k_pcie *pcie = to_armada8k_pcie(pci);
|
||||
|
||||
if (pcie->reset_gpio) {
|
||||
/* assert and then deassert the reset signal */
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 1);
|
||||
msleep(100);
|
||||
gpiod_set_value_cansleep(pcie->reset_gpio, 0);
|
||||
}
|
||||
dw_pcie_setup_rc(pp);
|
||||
armada8k_pcie_establish_link(pcie);
|
||||
|
||||
@ -249,6 +257,14 @@ static int armada8k_pcie_probe(struct platform_device *pdev)
|
||||
goto fail_clkreg;
|
||||
}
|
||||
|
||||
/* Get reset gpio signal and hold asserted (logically high) */
|
||||
pcie->reset_gpio = devm_gpiod_get_optional(dev, "reset",
|
||||
GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pcie->reset_gpio)) {
|
||||
ret = PTR_ERR(pcie->reset_gpio);
|
||||
goto fail_clkreg;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
ret = armada8k_add_pcie_port(pcie, pdev);
|
||||
|
@ -504,6 +504,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (pci->iatu_unroll_enabled && !pci->atu_base) {
|
||||
dev_err(dev, "atu_base is not populated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-ib-windows", &ep->num_ib_windows);
|
||||
if (ret < 0) {
|
||||
|
@ -699,6 +699,9 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n",
|
||||
pci->iatu_unroll_enabled ? "enabled" : "disabled");
|
||||
|
||||
if (pci->iatu_unroll_enabled && !pci->atu_base)
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, pp->mem_base,
|
||||
pp->mem_bus_addr, pp->mem_size);
|
||||
|
@ -93,7 +93,7 @@ static u32 dw_pcie_readl_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg)
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
||||
|
||||
return dw_pcie_readl_dbi(pci, offset + reg);
|
||||
return dw_pcie_readl_atu(pci, offset + reg);
|
||||
}
|
||||
|
||||
static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
@ -101,7 +101,7 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(index);
|
||||
|
||||
dw_pcie_writel_dbi(pci, offset + reg, val);
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
@ -187,7 +187,7 @@ static u32 dw_pcie_readl_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg)
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
|
||||
|
||||
return dw_pcie_readl_dbi(pci, offset + reg);
|
||||
return dw_pcie_readl_atu(pci, offset + reg);
|
||||
}
|
||||
|
||||
static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
@ -195,7 +195,7 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
{
|
||||
u32 offset = PCIE_GET_ATU_INB_UNR_REG_OFFSET(index);
|
||||
|
||||
dw_pcie_writel_dbi(pci, offset + reg, val);
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
|
@ -92,12 +92,20 @@
|
||||
#define PCIE_ATU_UNR_LOWER_TARGET 0x14
|
||||
#define PCIE_ATU_UNR_UPPER_TARGET 0x18
|
||||
|
||||
/*
|
||||
* The default address offset between dbi_base and atu_base. Root controller
|
||||
* drivers are not required to initialize atu_base if the offset matches this
|
||||
* default; the driver core automatically derives atu_base from dbi_base using
|
||||
* this offset, if atu_base not set.
|
||||
*/
|
||||
#define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
|
||||
|
||||
/* Register address builder */
|
||||
#define PCIE_GET_ATU_OUTB_UNR_REG_OFFSET(region) \
|
||||
((0x3 << 20) | ((region) << 9))
|
||||
((region) << 9)
|
||||
|
||||
#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
|
||||
((0x3 << 20) | ((region) << 9) | (0x1 << 8))
|
||||
(((region) << 9) | (0x1 << 8))
|
||||
|
||||
#define MAX_MSI_IRQS 256
|
||||
#define MAX_MSI_IRQS_PER_CTRL 32
|
||||
@ -219,6 +227,8 @@ struct dw_pcie {
|
||||
struct device *dev;
|
||||
void __iomem *dbi_base;
|
||||
void __iomem *dbi_base2;
|
||||
/* Used when iatu_unroll_enabled is true */
|
||||
void __iomem *atu_base;
|
||||
u32 num_viewport;
|
||||
u8 iatu_unroll_enabled;
|
||||
struct pcie_port pp;
|
||||
@ -289,6 +299,16 @@ static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
|
||||
return __dw_pcie_read_dbi(pci, pci->dbi_base2, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
__dw_pcie_write_dbi(pci, pci->atu_base, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return __dw_pcie_read_dbi(pci, pci->atu_base, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
|
||||
{
|
||||
u32 reg;
|
||||
|
@ -202,7 +202,7 @@ static int histb_pcie_host_init(struct pcie_port *pp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dw_pcie_host_ops histb_pcie_host_ops = {
|
||||
static const struct dw_pcie_host_ops histb_pcie_host_ops = {
|
||||
.rd_own_conf = histb_pcie_rd_own_conf,
|
||||
.wr_own_conf = histb_pcie_wr_own_conf,
|
||||
.host_init = histb_pcie_host_init,
|
||||
|
@ -440,6 +440,7 @@
|
||||
#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1)
|
||||
|
||||
#define IMX6SX_GPR12_PCIE_TEST_POWERDOWN BIT(30)
|
||||
#define IMX6SX_GPR12_PCIE_PM_TURN_OFF BIT(16)
|
||||
#define IMX6SX_GPR12_PCIE_RX_EQ_MASK (0x7 << 0)
|
||||
#define IMX6SX_GPR12_PCIE_RX_EQ_2 (0x2 << 0)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user