mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
Merge branch 'remotes/lorenzo/pci/dwc'
- Fix designware-ep Header Type check (Hou Zhiqiang) - Use DBI accessors instead of own config accessors (Rob Herring) - Allow overriding bridge pci_ops (Rob Herring) - Allow root and child buses to have different pci_ops (Rob Herring) - Add default dwc pci_ops.map_bus (Rob Herring) - Use pci_ops for root config space accessors in al, exynos, histb, keystone, kirin, meson, tegra (Rob Herring) - Remove dwc own/other config accessor ops (Rob Herring) - Use generic config accessors in dwc (Rob Herring) - Also call .add_bus() callback for root bus (Rob Herring) - Convert keystone .scan_bus() callback to use pci_ops.add_bus (Rob Herring) - Convert dwc to use pci_host_probe() (Rob Herring) - Remove dwc root_bus pointer (Rob Herring) - Remove storing of PCI resources in dwc-specific structs (Rob Herring) - Simplify config space handling (Rob Herring) - Drop keystone duplicated DT num-viewport handling (Rob Herring) - Check CONFIG_PCI_MSI in dw_pcie_msi_init() instead of duplicating it in all the drivers (Rob Herring) - Remove imx6 duplicate PCIE_LINK_WIDTH_SPEED_CONTROL definition (Rob Herring) - Add dwc num_lanes for use when it's lacking from DT (Rob Herring) - Ensure "Fast Link Mode" simulation environment setting is cleared (Rob Herring) - Drop meson duplicate number of lanes setup (Rob Herring) - Drop meson unnecessary RC config space init (Rob Herring) - Rework meson config and dwc port logic register accesses (Rob Herring) - Use common PCI register definitions in imx6 and qcom (Rob Herring) - Search for DesignWare PCIe Capability instead of hard-coding its location (Rob Herring) - Use common DesignWare register definitions in tegra (Rob Herring) - Drop keystone unused DBI2 code (Rob Herring) - Make dwc ATU accessors private (Rob Herring) - Centralize link gen setting in dwc (Rob Herring) - Set PORT_LINK_DLL_LINK_EN in common dwc setup code (Rob Herring) - Drop intel-gw unnecessary DT 'device_type' checking (Rob Herring) - Move intel-gw PCI_CAP_ID_EXP discovery to the single place it's used (Rob Herring) - Drop intel-gw unused max_width (Rob Herring) - Move N_FTS (fast training sequence) setup to common dwc setup (Rob Herring) - Convert spear13xx, tegra194 to use DBI accessors (Rob Herring) - Add multiple PFs support for DWC (Xiaowei Bao) - Add MSI-X doorbell mode for endpoint mode (Xiaowei Bao) - Update MSI/MSI-X capability management for endpoints (Xiaowei Bao) - Add layerscape ls1088a and ls2088a compatible strings (Xiaowei Bao) - Update layerscape MSI/MSI-X management (Xiaowei Bao) - Use doorbell to support MSI-X on layerscape (Xiaowei Bao) - Add layerscape endpoint mode support for ls1088a and ls2088a (Xiaowei Bao) - Add layerscape ls1088a node to DT (Xiaowei Bao) - Add Freescale/Layerscape ls1088a to endpoint test (Xiaowei Bao) - Add endpoint test driver data for Layerscape PCIe controllers (Hou Zhiqiang) - Fix 'cast truncates bits from constant value' warning (Gustavo Pimentel) - Add uniphier iATU register description (Kunihiko Hayashi) - Add common iATU register support (Kunihiko Hayashi) - Remove keystone iATU register mapping in favor of generic dwc support (Kunihiko Hayashi) - Skip PCIE_MSI_INTR0* programming if MSI is disabled (Jisheng Zhang) - Fix MSI page leakage in suspend/resume (Jisheng Zhang) - Check whether link is up before attempting config access (best-effort fix even though it's racy) (Hou Zhiqiang) * remotes/lorenzo/pci/dwc: PCI: dwc: Add link up check in dw_child_pcie_ops.map_bus() PCI: dwc: Fix MSI page leakage in suspend/resume PCI: dwc: Skip PCIE_MSI_INTR0* programming if MSI is disabled PCI: keystone: Remove iATU register mapping PCI: dwc: Add common iATU register support dt-bindings: PCI: uniphier-ep: Add iATU register description dt-bindings: PCI: uniphier: Add iATU register description PCI: dwc: Fix 'cast truncates bits from constant value' misc: pci_endpoint_test: Add driver data for Layerscape PCIe controllers misc: pci_endpoint_test: Add LS1088a in pci_device_id table PCI: layerscape: Add EP mode support for ls1088a and ls2088a PCI: layerscape: Modify the MSIX to the doorbell mode PCI: layerscape: Modify the way of getting capability with different PEX PCI: layerscape: Fix some format issue of the code dt-bindings: pci: layerscape-pci: Add compatible strings for ls1088a and ls2088a PCI: designware-ep: Modify MSI and MSIX CAP way of finding PCI: designware-ep: Move the function of getting MSI capability forward PCI: designware-ep: Add the doorbell mode of MSI-X in EP mode PCI: designware-ep: Add multiple PFs support for DWC PCI: dwc: Use DBI accessors PCI: dwc: Move N_FTS setup to common setup PCI: dwc/intel-gw: Drop unused max_width PCI: dwc/intel-gw: Move getting PCI_CAP_ID_EXP offset to intel_pcie_link_setup() PCI: dwc/intel-gw: Drop unnecessary checking of DT 'device_type' property PCI: dwc: Set PORT_LINK_DLL_LINK_EN in common setup code PCI: dwc: Centralize link gen setting PCI: dwc: Make ATU accessors private PCI: dwc: Remove read_dbi2 code PCI: dwc/tegra: Use common Designware port logic register definitions PCI: dwc: Remove hardcoded PCI_CAP_ID_EXP offset PCI: dwc/qcom: Use common PCI register definitions PCI: dwc/imx6: Use common PCI register definitions PCI: dwc/meson: Rework PCI config and DW port logic register accesses PCI: dwc/meson: Drop unnecessary RC config space initialization PCI: dwc/meson: Drop the duplicate number of lanes setup PCI: dwc: Ensure FAST_LINK_MODE is cleared PCI: dwc: Add a 'num_lanes' field to struct dw_pcie PCI: dwc/imx6: Remove duplicate define PCIE_LINK_WIDTH_SPEED_CONTROL PCI: dwc: Check CONFIG_PCI_MSI inside dw_pcie_msi_init() PCI: dwc/keystone: Drop duplicated 'num-viewport' PCI: dwc: Simplify config space handling PCI: dwc: Remove storing of PCI resources PCI: dwc: Remove root_bus pointer PCI: dwc: Convert to use pci_host_probe() PCI: dwc: keystone: Convert .scan_bus() callback to use add_bus PCI: Also call .add_bus() callback for root bus PCI: dwc: Use generic config accessors PCI: dwc: Remove dwc specific config accessor ops PCI: dwc: histb: Use pci_ops for root config space accessors PCI: dwc: exynos: Use pci_ops for root config space accessors PCI: dwc: kirin: Use pci_ops for root config space accessors PCI: dwc: meson: Use pci_ops for root config space accessors PCI: dwc: tegra: Use pci_ops for root config space accessors PCI: dwc: keystone: Use pci_ops for config space accessors PCI: dwc: al: Use pci_ops for child config space accessors PCI: dwc: Add a default pci_ops.map_bus for root port PCI: dwc: Allow overriding bridge pci_ops PCI: dwc: Use DBI accessors instead of own config accessors PCI: Allow root and child buses to have different pci_ops PCI: designware-ep: Fix the Header Type check
This commit is contained in:
commit
924bb1f9b0
@ -24,6 +24,8 @@ Required properties:
|
||||
"fsl,ls1028a-pcie"
|
||||
EP mode:
|
||||
"fsl,ls1046a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
"fsl,ls1088a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
"fsl,ls2088a-pcie-ep", "fsl,ls-pcie-ep"
|
||||
- reg: base addresses and lengths of the PCIe controller register blocks.
|
||||
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||
entry for each entry in the interrupt-names property.
|
||||
|
@ -23,14 +23,22 @@ properties:
|
||||
const: socionext,uniphier-pro5-pcie-ep
|
||||
|
||||
reg:
|
||||
maxItems: 4
|
||||
minItems: 4
|
||||
maxItems: 5
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
oneOf:
|
||||
- items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
- items:
|
||||
- const: dbi
|
||||
- const: dbi2
|
||||
- const: link
|
||||
- const: addr_space
|
||||
- const: atu
|
||||
|
||||
clocks:
|
||||
maxItems: 2
|
||||
|
@ -16,6 +16,7 @@ Required properties:
|
||||
"dbi" - controller configuration registers
|
||||
"link" - SoC-specific glue layer registers
|
||||
"config" - PCIe configuration space
|
||||
"atu" - iATU registers for DWC version 4.80 or later
|
||||
- clocks: A phandle to the clock gate for PCIe glue layer including
|
||||
the host controller.
|
||||
- resets: A phandle to the reset line for PCIe glue layer including
|
||||
|
@ -70,6 +70,7 @@
|
||||
|
||||
#define PCI_DEVICE_ID_TI_J721E 0xb00d
|
||||
#define PCI_DEVICE_ID_TI_AM654 0xb00c
|
||||
#define PCI_DEVICE_ID_LS1088A 0x80c0
|
||||
|
||||
#define is_am654_pci_dev(pdev) \
|
||||
((pdev)->device == PCI_DEVICE_ID_TI_AM654)
|
||||
@ -945,7 +946,12 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA72x),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, 0x81c0),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, PCI_DEVICE_ID_LS1088A),
|
||||
.driver_data = (kernel_ulong_t)&default_data,
|
||||
},
|
||||
{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, NULL) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
|
||||
.driver_data = (kernel_ulong_t)&am654_data
|
||||
|
@ -73,8 +73,6 @@
|
||||
#define LINK_UP BIT(16)
|
||||
#define DRA7XX_CPU_TO_BUS_ADDR 0x0FFFFFFF
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define PCIECTRL_TI_CONF_INTX_ASSERT 0x0124
|
||||
#define PCIECTRL_TI_CONF_INTX_DEASSERT 0x0128
|
||||
|
||||
@ -91,7 +89,6 @@ struct dra7xx_pcie {
|
||||
void __iomem *base; /* DT ti_conf */
|
||||
int phy_count; /* DT phy-names count */
|
||||
struct phy **phy;
|
||||
int link_gen;
|
||||
struct irq_domain *irq_domain;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
@ -142,33 +139,12 @@ static int dra7xx_pcie_establish_link(struct dw_pcie *pci)
|
||||
struct dra7xx_pcie *dra7xx = to_dra7xx_pcie(pci);
|
||||
struct device *dev = pci->dev;
|
||||
u32 reg;
|
||||
u32 exp_cap_off = EXP_CAP_ID_OFFSET;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(dev, "link is already up\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dra7xx->link_gen == 1) {
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
|
||||
4, ®);
|
||||
if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCAP, 4, reg);
|
||||
}
|
||||
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
|
||||
2, ®);
|
||||
if ((reg & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
reg &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
reg |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCTL2, 2, reg);
|
||||
}
|
||||
}
|
||||
|
||||
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
|
||||
reg |= LTSSM_EN;
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
|
||||
@ -490,7 +466,9 @@ static struct irq_chip dra7xx_pci_msi_bottom_irq_chip = {
|
||||
static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
u32 ctrl, num_ctrls;
|
||||
int ret;
|
||||
|
||||
pp->msi_irq_chip = &dra7xx_pci_msi_bottom_irq_chip;
|
||||
|
||||
@ -506,7 +484,21 @@ static int dra7xx_pcie_msi_host_init(struct pcie_port *pp)
|
||||
~0);
|
||||
}
|
||||
|
||||
return dw_pcie_allocate_domains(pp);
|
||||
ret = dw_pcie_allocate_domains(pp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
ret = dma_mapping_error(dev, pp->msi_data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to map MSI data\n");
|
||||
pp->msi_data = 0;
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops dra7xx_pcie_host_ops = {
|
||||
@ -937,10 +929,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
reg &= ~LTSSM_EN;
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);
|
||||
|
||||
dra7xx->link_gen = of_pci_get_max_link_speed(np);
|
||||
if (dra7xx->link_gen < 0 || dra7xx->link_gen > 2)
|
||||
dra7xx->link_gen = 2;
|
||||
|
||||
switch (mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) {
|
||||
|
@ -336,32 +336,37 @@ static void exynos_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, false);
|
||||
}
|
||||
|
||||
static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
static int exynos_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
exynos_pcie_sideband_dbi_r_mode(ep, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
exynos_pcie_sideband_dbi_r_mode(ep, false);
|
||||
return ret;
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int exynos_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
static int exynos_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
exynos_pcie_sideband_dbi_w_mode(ep, false);
|
||||
return ret;
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops exynos_pci_ops = {
|
||||
.read = exynos_pcie_rd_own_conf,
|
||||
.write = exynos_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static int exynos_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
@ -379,6 +384,8 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct exynos_pcie *ep = to_exynos_pcie(pci);
|
||||
|
||||
pp->bridge->ops = &exynos_pci_ops;
|
||||
|
||||
exynos_pcie_establish_link(ep);
|
||||
exynos_pcie_enable_interrupts(ep);
|
||||
|
||||
@ -386,8 +393,6 @@ static int exynos_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops exynos_pcie_host_ops = {
|
||||
.rd_own_conf = exynos_pcie_rd_own_conf,
|
||||
.wr_own_conf = exynos_pcie_wr_own_conf,
|
||||
.host_init = exynos_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -79,7 +79,6 @@ struct imx6_pcie {
|
||||
u32 tx_deemph_gen2_6db;
|
||||
u32 tx_swing_full;
|
||||
u32 tx_swing_low;
|
||||
int link_gen;
|
||||
struct regulator *vpcie;
|
||||
void __iomem *phy_base;
|
||||
|
||||
@ -94,15 +93,6 @@ struct imx6_pcie {
|
||||
#define PHY_PLL_LOCK_WAIT_USLEEP_MAX 200
|
||||
#define PHY_PLL_LOCK_WAIT_TIMEOUT (2000 * PHY_PLL_LOCK_WAIT_USLEEP_MAX)
|
||||
|
||||
/* PCIe Root Complex registers (memory-mapped) */
|
||||
#define PCIE_RC_IMX6_MSI_CAP 0x50
|
||||
#define PCIE_RC_LCR 0x7c
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1 0x1
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2 0x2
|
||||
#define PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK 0xf
|
||||
|
||||
#define PCIE_RC_LCSR 0x80
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
|
||||
@ -116,8 +106,6 @@ struct imx6_pcie {
|
||||
#define PCIE_PHY_STAT (PL_OFFSET + 0x110)
|
||||
#define PCIE_PHY_STAT_ACK BIT(16)
|
||||
|
||||
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
|
||||
|
||||
/* PHY registers (not memory-mapped) */
|
||||
#define PCIE_PHY_ATEOVRD 0x10
|
||||
#define PCIE_PHY_ATEOVRD_EN BIT(2)
|
||||
@ -761,6 +749,7 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = imx6_pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
@ -769,10 +758,10 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
* started in Gen2 mode, there is a possibility the devices on the
|
||||
* bus will not be detected at all. This happens with PCIe switches.
|
||||
*/
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
|
||||
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
|
||||
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
|
||||
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
|
||||
tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
tmp &= ~PCI_EXP_LNKCAP_SLS;
|
||||
tmp |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
|
||||
|
||||
/* Start LTSSM. */
|
||||
imx6_pcie_ltssm_enable(dev);
|
||||
@ -781,12 +770,12 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
if (ret)
|
||||
goto err_reset_phy;
|
||||
|
||||
if (imx6_pcie->link_gen == 2) {
|
||||
if (pci->link_gen == 2) {
|
||||
/* Allow Gen2 mode after the link is up. */
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCR);
|
||||
tmp &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
|
||||
tmp |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
|
||||
dw_pcie_writel_dbi(pci, PCIE_RC_LCR, tmp);
|
||||
tmp = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
tmp &= ~PCI_EXP_LNKCAP_SLS;
|
||||
tmp |= PCI_EXP_LNKCAP_SLS_5_0GB;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, tmp);
|
||||
|
||||
/*
|
||||
* Start Directed Speed Change so the best possible
|
||||
@ -824,8 +813,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
dev_info(dev, "Link: Gen2 disabled\n");
|
||||
}
|
||||
|
||||
tmp = dw_pcie_readl_dbi(pci, PCIE_RC_LCSR);
|
||||
dev_info(dev, "Link up, Gen%i\n", (tmp >> 16) & 0xf);
|
||||
tmp = dw_pcie_readw_dbi(pci, offset + PCI_EXP_LNKSTA);
|
||||
dev_info(dev, "Link up, Gen%i\n", tmp & PCI_EXP_LNKSTA_CLS);
|
||||
return 0;
|
||||
|
||||
err_reset_phy:
|
||||
@ -847,9 +836,7 @@ static int imx6_pcie_host_init(struct pcie_port *pp)
|
||||
imx6_setup_phy_mpll(imx6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
imx6_pcie_establish_link(imx6_pcie);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1165,10 +1152,8 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
imx6_pcie->tx_swing_low = 127;
|
||||
|
||||
/* Limit link speed */
|
||||
ret = of_property_read_u32(node, "fsl,max-link-speed",
|
||||
&imx6_pcie->link_gen);
|
||||
if (ret)
|
||||
imx6_pcie->link_gen = 1;
|
||||
pci->link_gen = 1;
|
||||
ret = of_property_read_u32(node, "fsl,max-link-speed", &pci->link_gen);
|
||||
|
||||
imx6_pcie->vpcie = devm_regulator_get_optional(&pdev->dev, "vpcie");
|
||||
if (IS_ERR(imx6_pcie->vpcie)) {
|
||||
@ -1188,11 +1173,10 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
val = dw_pcie_readw_dbi(pci, PCIE_RC_IMX6_MSI_CAP +
|
||||
PCI_MSI_FLAGS);
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
val = dw_pcie_readw_dbi(pci, offset + PCI_MSI_FLAGS);
|
||||
val |= PCI_MSI_FLAGS_ENABLE;
|
||||
dw_pcie_writew_dbi(pci, PCIE_RC_IMX6_MSI_CAP + PCI_MSI_FLAGS,
|
||||
val);
|
||||
dw_pcie_writew_dbi(pci, offset + PCI_MSI_FLAGS, val);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -96,8 +96,6 @@
|
||||
#define LEG_EP 0x1
|
||||
#define RC 0x2
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define KS_PCIE_SYSCLOCKOUTEN BIT(0)
|
||||
|
||||
#define AM654_PCIE_DEV_TYPE_MASK 0x3
|
||||
@ -123,7 +121,6 @@ struct keystone_pcie {
|
||||
|
||||
int msi_host_irq;
|
||||
int num_lanes;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
struct device_link **link;
|
||||
struct device_node *msi_intc_np;
|
||||
@ -397,13 +394,17 @@ static void ks_pcie_clear_dbi_mode(struct keystone_pcie *ks_pcie)
|
||||
static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
||||
{
|
||||
u32 val;
|
||||
u32 num_viewport = ks_pcie->num_viewport;
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u64 start = pp->mem->start;
|
||||
u64 end = pp->mem->end;
|
||||
u32 num_viewport = pci->num_viewport;
|
||||
u64 start, end;
|
||||
struct resource *mem;
|
||||
int i;
|
||||
|
||||
mem = resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM)->res;
|
||||
start = mem->start;
|
||||
end = mem->end;
|
||||
|
||||
/* Disable BARs for inbound access */
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
@ -430,10 +431,10 @@ static void ks_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
|
||||
ks_pcie_app_writel(ks_pcie, CMD_STATUS, val);
|
||||
}
|
||||
|
||||
static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 *val)
|
||||
static void __iomem *ks_pcie_other_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 reg;
|
||||
@ -444,36 +445,29 @@ static int ks_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
return dw_pcie_read(pp->va_cfg0_base + where, size, val);
|
||||
return pp->va_cfg0_base + where;
|
||||
}
|
||||
|
||||
static int ks_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 reg;
|
||||
|
||||
reg = CFG_BUS(bus->number) | CFG_DEVICE(PCI_SLOT(devfn)) |
|
||||
CFG_FUNC(PCI_FUNC(devfn));
|
||||
if (!pci_is_root_bus(bus->parent))
|
||||
reg |= CFG_TYPE1;
|
||||
ks_pcie_app_writel(ks_pcie, CFG_SETUP, reg);
|
||||
|
||||
return dw_pcie_write(pp->va_cfg0_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops ks_child_pcie_ops = {
|
||||
.map_bus = ks_pcie_other_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
/**
|
||||
* ks_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
|
||||
* ks_pcie_v3_65_add_bus() - keystone add_bus post initialization
|
||||
*
|
||||
* This sets BAR0 to enable inbound access for MSI_IRQ register
|
||||
*/
|
||||
static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
|
||||
static int ks_pcie_v3_65_add_bus(struct pci_bus *bus)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
|
||||
if (!pci_is_root_bus(bus))
|
||||
return 0;
|
||||
|
||||
/* Configure and set up BAR0 */
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
|
||||
@ -488,8 +482,17 @@ static void ks_pcie_v3_65_scan_bus(struct pcie_port *pp)
|
||||
* be sufficient. Use physical address to avoid any conflicts.
|
||||
*/
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, ks_pcie->app.start);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pci_ops ks_pcie_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
.add_bus = ks_pcie_v3_65_add_bus,
|
||||
};
|
||||
|
||||
/**
|
||||
* ks_pcie_link_up() - Check if link up
|
||||
*/
|
||||
@ -807,6 +810,9 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
int ret;
|
||||
|
||||
pp->bridge->ops = &ks_pcie_ops;
|
||||
pp->bridge->child_ops = &ks_child_pcie_ops;
|
||||
|
||||
ret = ks_pcie_config_legacy_irq(ks_pcie);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -842,11 +848,8 @@ static int __init ks_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops ks_pcie_host_ops = {
|
||||
.rd_other_conf = ks_pcie_rd_other_conf,
|
||||
.wr_other_conf = ks_pcie_wr_other_conf,
|
||||
.host_init = ks_pcie_host_init,
|
||||
.msi_host_init = ks_pcie_msi_host_init,
|
||||
.scan_bus = ks_pcie_v3_65_scan_bus,
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops ks_pcie_am654_host_ops = {
|
||||
@ -867,16 +870,8 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
|
||||
struct dw_pcie *pci = ks_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(pp->va_cfg0_base))
|
||||
return PTR_ERR(pp->va_cfg0_base);
|
||||
|
||||
pp->va_cfg1_base = pp->va_cfg0_base;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
@ -886,18 +881,6 @@ static int __init ks_pcie_add_pcie_port(struct keystone_pcie *ks_pcie,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 ks_pcie_am654_read_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size)
|
||||
{
|
||||
struct keystone_pcie *ks_pcie = to_keystone_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
ks_pcie_set_dbi_mode(ks_pcie);
|
||||
dw_pcie_read(base + reg, size, &val);
|
||||
ks_pcie_clear_dbi_mode(ks_pcie);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ks_pcie_am654_write_dbi2(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size, u32 val)
|
||||
{
|
||||
@ -912,7 +895,6 @@ static const struct dw_pcie_ops ks_pcie_dw_pcie_ops = {
|
||||
.start_link = ks_pcie_start_link,
|
||||
.stop_link = ks_pcie_stop_link,
|
||||
.link_up = ks_pcie_link_up,
|
||||
.read_dbi2 = ks_pcie_am654_read_dbi2,
|
||||
.write_dbi2 = ks_pcie_am654_write_dbi2,
|
||||
};
|
||||
|
||||
@ -1125,31 +1107,6 @@ static int ks_pcie_am654_set_mode(struct device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ks_pcie_set_link_speed(struct dw_pcie *pci, int link_speed)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= link_speed;
|
||||
dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != link_speed) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= link_speed;
|
||||
dw_pcie_writel_dbi(pci, EXP_CAP_ID_OFFSET + PCI_EXP_LNKCTL2,
|
||||
val);
|
||||
}
|
||||
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
static const struct ks_pcie_of_data ks_pcie_rc_of_data = {
|
||||
.host_ops = &ks_pcie_host_ops,
|
||||
.version = 0x365A,
|
||||
@ -1197,13 +1154,10 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
struct keystone_pcie *ks_pcie;
|
||||
struct device_link **link;
|
||||
struct gpio_desc *gpiod;
|
||||
void __iomem *atu_base;
|
||||
struct resource *res;
|
||||
unsigned int version;
|
||||
void __iomem *base;
|
||||
u32 num_viewport;
|
||||
struct phy **phy;
|
||||
int link_speed;
|
||||
u32 num_lanes;
|
||||
char name[10];
|
||||
int ret;
|
||||
@ -1320,29 +1274,12 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
if (pci->version >= 0x480A) {
|
||||
atu_base = devm_platform_ioremap_resource_byname(pdev, "atu");
|
||||
if (IS_ERR(atu_base)) {
|
||||
ret = PTR_ERR(atu_base);
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
pci->atu_base = atu_base;
|
||||
|
||||
if (pci->version >= 0x480A)
|
||||
ret = ks_pcie_am654_set_mode(dev, mode);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
} else {
|
||||
else
|
||||
ret = ks_pcie_set_mode(dev);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
link_speed = of_pci_get_max_link_speed(np);
|
||||
if (link_speed < 0)
|
||||
link_speed = 2;
|
||||
|
||||
ks_pcie_set_link_speed(pci, link_speed);
|
||||
if (ret < 0)
|
||||
goto err_get_sync;
|
||||
|
||||
switch (mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
@ -1351,12 +1288,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &num_viewport);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to read *num-viewport* property\n");
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
/*
|
||||
* "Power Sequencing and Reset Signal Timings" table in
|
||||
* PCI EXPRESS CARD ELECTROMECHANICAL SPECIFICATION, REV. 2.0
|
||||
@ -1370,7 +1301,6 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
|
||||
gpiod_set_value_cansleep(gpiod, 1);
|
||||
}
|
||||
|
||||
ks_pcie->num_viewport = num_viewport;
|
||||
pci->pp.ops = host_ops;
|
||||
ret = ks_pcie_add_pcie_port(ks_pcie, pdev);
|
||||
if (ret < 0)
|
||||
|
@ -20,50 +20,58 @@
|
||||
|
||||
#define PCIE_DBI2_OFFSET 0x1000 /* DBI2 base address*/
|
||||
|
||||
struct ls_pcie_ep {
|
||||
struct dw_pcie *pci;
|
||||
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
struct ls_pcie_ep_drvdata {
|
||||
u32 func_offset;
|
||||
const struct dw_pcie_ep_ops *ops;
|
||||
const struct dw_pcie_ops *dw_pcie_ops;
|
||||
};
|
||||
|
||||
#define to_ls_pcie_ep(x) dev_get_drvdata((x)->dev)
|
||||
struct ls_pcie_ep {
|
||||
struct dw_pcie *pci;
|
||||
struct pci_epc_features *ls_epc;
|
||||
const struct ls_pcie_ep_drvdata *drvdata;
|
||||
};
|
||||
|
||||
static int ls_pcie_establish_link(struct dw_pcie *pci)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops ls_pcie_ep_ops = {
|
||||
static const struct dw_pcie_ops dw_ls_pcie_ep_ops = {
|
||||
.start_link = ls_pcie_establish_link,
|
||||
};
|
||||
|
||||
static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||
{ .compatible = "fsl,ls-pcie-ep",},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct pci_epc_features ls_pcie_epc_features = {
|
||||
.linkup_notifier = false,
|
||||
.msi_capable = true,
|
||||
.msix_capable = false,
|
||||
.bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
|
||||
};
|
||||
|
||||
static const struct pci_epc_features*
|
||||
ls_pcie_ep_get_features(struct dw_pcie_ep *ep)
|
||||
{
|
||||
return &ls_pcie_epc_features;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
|
||||
return pcie->ls_epc;
|
||||
}
|
||||
|
||||
static void ls_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
enum pci_barno bar;
|
||||
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, 0);
|
||||
if (!ep_func)
|
||||
return;
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
||||
pcie->ls_epc->msi_capable = ep_func->msi_cap ? true : false;
|
||||
pcie->ls_epc->msix_capable = ep_func->msix_cap ? true : false;
|
||||
}
|
||||
|
||||
static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num)
|
||||
enum pci_epc_irq_type type, u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
@ -73,21 +81,51 @@ static int ls_pcie_ep_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||
case PCI_EPC_IRQ_MSIX:
|
||||
return dw_pcie_ep_raise_msix_irq(ep, func_no, interrupt_num);
|
||||
return dw_pcie_ep_raise_msix_irq_doorbell(ep, func_no,
|
||||
interrupt_num);
|
||||
default:
|
||||
dev_err(pci->dev, "UNKNOWN IRQ type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
static unsigned int ls_pcie_ep_func_conf_select(struct dw_pcie_ep *ep,
|
||||
u8 func_no)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct ls_pcie_ep *pcie = to_ls_pcie_ep(pci);
|
||||
|
||||
WARN_ON(func_no && !pcie->drvdata->func_offset);
|
||||
return pcie->drvdata->func_offset * func_no;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ep_ops ls_pcie_ep_ops = {
|
||||
.ep_init = ls_pcie_ep_init,
|
||||
.raise_irq = ls_pcie_ep_raise_irq,
|
||||
.get_features = ls_pcie_ep_get_features,
|
||||
.func_conf_select = ls_pcie_ep_func_conf_select,
|
||||
};
|
||||
|
||||
static const struct ls_pcie_ep_drvdata ls1_ep_drvdata = {
|
||||
.ops = &ls_pcie_ep_ops,
|
||||
.dw_pcie_ops = &dw_ls_pcie_ep_ops,
|
||||
};
|
||||
|
||||
static const struct ls_pcie_ep_drvdata ls2_ep_drvdata = {
|
||||
.func_offset = 0x20000,
|
||||
.ops = &ls_pcie_ep_ops,
|
||||
.dw_pcie_ops = &dw_ls_pcie_ep_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id ls_pcie_ep_of_match[] = {
|
||||
{ .compatible = "fsl,ls1046a-pcie-ep", .data = &ls1_ep_drvdata },
|
||||
{ .compatible = "fsl,ls1088a-pcie-ep", .data = &ls2_ep_drvdata },
|
||||
{ .compatible = "fsl,ls2088a-pcie-ep", .data = &ls2_ep_drvdata },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||
struct platform_device *pdev)
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
@ -96,7 +134,7 @@ static int __init ls_add_pcie_ep(struct ls_pcie_ep *pcie,
|
||||
int ret;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
ep->ops = pcie->drvdata->ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
@ -119,6 +157,7 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci;
|
||||
struct ls_pcie_ep *pcie;
|
||||
struct pci_epc_features *ls_epc;
|
||||
struct resource *dbi_base;
|
||||
int ret;
|
||||
|
||||
@ -130,15 +169,26 @@ static int __init ls_pcie_ep_probe(struct platform_device *pdev)
|
||||
if (!pci)
|
||||
return -ENOMEM;
|
||||
|
||||
ls_epc = devm_kzalloc(dev, sizeof(*ls_epc), GFP_KERNEL);
|
||||
if (!ls_epc)
|
||||
return -ENOMEM;
|
||||
|
||||
pcie->drvdata = of_device_get_match_data(dev);
|
||||
|
||||
pci->dev = dev;
|
||||
pci->ops = pcie->drvdata->dw_pcie_ops;
|
||||
|
||||
ls_epc->bar_fixed_64bit = (1 << BAR_2) | (1 << BAR_4),
|
||||
|
||||
pcie->pci = pci;
|
||||
pcie->ls_epc = ls_epc;
|
||||
|
||||
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
|
||||
pci->dbi_base = devm_pci_remap_cfg_resource(dev, dbi_base);
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
pci->dbi_base2 = pci->dbi_base + PCIE_DBI2_OFFSET;
|
||||
pci->dev = dev;
|
||||
pci->ops = &ls_pcie_ep_ops;
|
||||
pcie->pci = pci;
|
||||
|
||||
platform_set_drvdata(pdev, pcie);
|
||||
|
||||
|
@ -22,32 +22,7 @@
|
||||
|
||||
#define to_meson_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
/* External local bus interface registers */
|
||||
#define PLR_OFFSET 0x700
|
||||
#define PCIE_PORT_LINK_CTRL_OFF (PLR_OFFSET + 0x10)
|
||||
#define FAST_LINK_MODE BIT(7)
|
||||
#define LINK_CAPABLE_MASK GENMASK(21, 16)
|
||||
#define LINK_CAPABLE_X1 BIT(16)
|
||||
|
||||
#define PCIE_GEN2_CTRL_OFF (PLR_OFFSET + 0x10c)
|
||||
#define NUM_OF_LANES_MASK GENMASK(12, 8)
|
||||
#define NUM_OF_LANES_X1 BIT(8)
|
||||
#define DIRECT_SPEED_CHANGE BIT(17)
|
||||
|
||||
#define TYPE1_HDR_OFFSET 0x0
|
||||
#define PCIE_STATUS_COMMAND (TYPE1_HDR_OFFSET + 0x04)
|
||||
#define PCI_IO_EN BIT(0)
|
||||
#define PCI_MEM_SPACE_EN BIT(1)
|
||||
#define PCI_BUS_MASTER_EN BIT(2)
|
||||
|
||||
#define PCIE_BASE_ADDR0 (TYPE1_HDR_OFFSET + 0x10)
|
||||
#define PCIE_BASE_ADDR1 (TYPE1_HDR_OFFSET + 0x14)
|
||||
|
||||
#define PCIE_CAP_OFFSET 0x70
|
||||
#define PCIE_DEV_CTRL_DEV_STUS (PCIE_CAP_OFFSET + 0x08)
|
||||
#define PCIE_CAP_MAX_PAYLOAD_MASK GENMASK(7, 5)
|
||||
#define PCIE_CAP_MAX_PAYLOAD_SIZE(x) ((x) << 5)
|
||||
#define PCIE_CAP_MAX_READ_REQ_MASK GENMASK(14, 12)
|
||||
#define PCIE_CAP_MAX_READ_REQ_SIZE(x) ((x) << 12)
|
||||
|
||||
/* PCIe specific config registers */
|
||||
@ -77,11 +52,6 @@ enum pcie_data_rate {
|
||||
PCIE_GEN4
|
||||
};
|
||||
|
||||
struct meson_pcie_mem_res {
|
||||
void __iomem *elbi_base;
|
||||
void __iomem *cfg_base;
|
||||
};
|
||||
|
||||
struct meson_pcie_clk_res {
|
||||
struct clk *clk;
|
||||
struct clk *port_clk;
|
||||
@ -95,7 +65,7 @@ struct meson_pcie_rc_reset {
|
||||
|
||||
struct meson_pcie {
|
||||
struct dw_pcie pci;
|
||||
struct meson_pcie_mem_res mem_res;
|
||||
void __iomem *cfg_base;
|
||||
struct meson_pcie_clk_res clk_res;
|
||||
struct meson_pcie_rc_reset mrst;
|
||||
struct gpio_desc *reset_gpio;
|
||||
@ -134,28 +104,18 @@ static int meson_pcie_get_resets(struct meson_pcie *mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __iomem *meson_pcie_get_mem(struct platform_device *pdev,
|
||||
struct meson_pcie *mp,
|
||||
const char *id)
|
||||
{
|
||||
struct device *dev = mp->pci.dev;
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, id);
|
||||
|
||||
return devm_ioremap_resource(dev, res);
|
||||
}
|
||||
|
||||
static int meson_pcie_get_mems(struct platform_device *pdev,
|
||||
struct meson_pcie *mp)
|
||||
{
|
||||
mp->mem_res.elbi_base = meson_pcie_get_mem(pdev, mp, "elbi");
|
||||
if (IS_ERR(mp->mem_res.elbi_base))
|
||||
return PTR_ERR(mp->mem_res.elbi_base);
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
|
||||
mp->mem_res.cfg_base = meson_pcie_get_mem(pdev, mp, "cfg");
|
||||
if (IS_ERR(mp->mem_res.cfg_base))
|
||||
return PTR_ERR(mp->mem_res.cfg_base);
|
||||
pci->dbi_base = devm_platform_ioremap_resource_byname(pdev, "elbi");
|
||||
if (IS_ERR(pci->dbi_base))
|
||||
return PTR_ERR(pci->dbi_base);
|
||||
|
||||
mp->cfg_base = devm_platform_ioremap_resource_byname(pdev, "cfg");
|
||||
if (IS_ERR(mp->cfg_base))
|
||||
return PTR_ERR(mp->cfg_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -253,24 +213,14 @@ static int meson_pcie_probe_clocks(struct meson_pcie *mp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void meson_elb_writel(struct meson_pcie *mp, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, mp->mem_res.elbi_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 meson_elb_readl(struct meson_pcie *mp, u32 reg)
|
||||
{
|
||||
return readl(mp->mem_res.elbi_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 meson_cfg_readl(struct meson_pcie *mp, u32 reg)
|
||||
{
|
||||
return readl(mp->mem_res.cfg_base + reg);
|
||||
return readl(mp->cfg_base + reg);
|
||||
}
|
||||
|
||||
static inline void meson_cfg_writel(struct meson_pcie *mp, u32 val, u32 reg)
|
||||
{
|
||||
writel(val, mp->mem_res.cfg_base + reg);
|
||||
writel(val, mp->cfg_base + reg);
|
||||
}
|
||||
|
||||
static void meson_pcie_assert_reset(struct meson_pcie *mp)
|
||||
@ -287,25 +237,6 @@ static void meson_pcie_init_dw(struct meson_pcie *mp)
|
||||
val = meson_cfg_readl(mp, PCIE_CFG0);
|
||||
val |= APP_LTSSM_ENABLE;
|
||||
meson_cfg_writel(mp, val, PCIE_CFG0);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
|
||||
val &= ~(LINK_CAPABLE_MASK | FAST_LINK_MODE);
|
||||
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_PORT_LINK_CTRL_OFF);
|
||||
val |= LINK_CAPABLE_X1;
|
||||
meson_elb_writel(mp, val, PCIE_PORT_LINK_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
|
||||
val &= ~NUM_OF_LANES_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_GEN2_CTRL_OFF);
|
||||
val |= NUM_OF_LANES_X1 | DIRECT_SPEED_CHANGE;
|
||||
meson_elb_writel(mp, val, PCIE_GEN2_CTRL_OFF);
|
||||
|
||||
meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR0);
|
||||
meson_elb_writel(mp, 0x0, PCIE_BASE_ADDR1);
|
||||
}
|
||||
|
||||
static int meson_size_to_payload(struct meson_pcie *mp, int size)
|
||||
@ -327,37 +258,34 @@ static int meson_size_to_payload(struct meson_pcie *mp, int size)
|
||||
|
||||
static void meson_set_max_payload(struct meson_pcie *mp, int size)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
u32 val;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int max_payload_size = meson_size_to_payload(mp, size);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val &= ~PCIE_CAP_MAX_PAYLOAD_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_PAYLOAD;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val |= PCIE_CAP_MAX_PAYLOAD_SIZE(max_payload_size);
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
}
|
||||
|
||||
static void meson_set_max_rd_req_size(struct meson_pcie *mp, int size)
|
||||
{
|
||||
struct dw_pcie *pci = &mp->pci;
|
||||
u32 val;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int max_rd_req_size = meson_size_to_payload(mp, size);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val &= ~PCIE_CAP_MAX_READ_REQ_MASK;
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
|
||||
val = meson_elb_readl(mp, PCIE_DEV_CTRL_DEV_STUS);
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_DEVCTL);
|
||||
val |= PCIE_CAP_MAX_READ_REQ_SIZE(max_rd_req_size);
|
||||
meson_elb_writel(mp, val, PCIE_DEV_CTRL_DEV_STUS);
|
||||
}
|
||||
|
||||
static inline void meson_enable_memory_space(struct meson_pcie *mp)
|
||||
{
|
||||
/* Set the RC Bus Master, Memory Space and I/O Space enables */
|
||||
meson_elb_writel(mp, PCI_IO_EN | PCI_MEM_SPACE_EN | PCI_BUS_MASTER_EN,
|
||||
PCIE_STATUS_COMMAND);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_DEVCTL, val);
|
||||
}
|
||||
|
||||
static int meson_pcie_establish_link(struct meson_pcie *mp)
|
||||
@ -370,26 +298,18 @@ static int meson_pcie_establish_link(struct meson_pcie *mp)
|
||||
meson_set_max_rd_req_size(mp, MAX_READ_REQ_SIZE);
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
meson_enable_memory_space(mp);
|
||||
|
||||
meson_pcie_assert_reset(mp);
|
||||
|
||||
return dw_pcie_wait_for_link(pci);
|
||||
}
|
||||
|
||||
static void meson_pcie_enable_interrupts(struct meson_pcie *mp)
|
||||
static int meson_pcie_rd_own_conf(struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(&mp->pci.pp);
|
||||
}
|
||||
|
||||
static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
if (ret != PCIBIOS_SUCCESSFUL)
|
||||
return ret;
|
||||
|
||||
@ -410,13 +330,11 @@ static int meson_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int meson_pcie_wr_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops meson_pci_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = meson_pcie_rd_own_conf,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static int meson_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
@ -463,18 +381,18 @@ static int meson_pcie_host_init(struct pcie_port *pp)
|
||||
struct meson_pcie *mp = to_meson_pcie(pci);
|
||||
int ret;
|
||||
|
||||
pp->bridge->ops = &meson_pci_ops;
|
||||
|
||||
ret = meson_pcie_establish_link(mp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
meson_pcie_enable_interrupts(mp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops meson_pcie_host_ops = {
|
||||
.rd_own_conf = meson_pcie_rd_own_conf,
|
||||
.wr_own_conf = meson_pcie_wr_own_conf,
|
||||
.host_init = meson_pcie_host_init,
|
||||
};
|
||||
|
||||
@ -493,7 +411,6 @@ static int meson_add_pcie_port(struct meson_pcie *mp,
|
||||
}
|
||||
|
||||
pp->ops = &meson_pcie_host_ops;
|
||||
pci->dbi_base = mp->mem_res.elbi_base;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
@ -522,6 +439,7 @@ static int meson_pcie_probe(struct platform_device *pdev)
|
||||
pci = &mp->pci;
|
||||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
pci->num_lanes = 1;
|
||||
|
||||
mp->phy = devm_phy_get(dev, "pcie");
|
||||
if (IS_ERR(mp->phy)) {
|
||||
|
@ -217,14 +217,15 @@ static inline void al_pcie_target_bus_set(struct al_pcie *pcie,
|
||||
reg);
|
||||
}
|
||||
|
||||
static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
|
||||
unsigned int busnr,
|
||||
unsigned int devfn)
|
||||
static void __iomem *al_pcie_conf_addr_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct al_pcie *pcie = to_al_pcie(to_dw_pcie_from_pp(pp));
|
||||
unsigned int busnr = bus->number;
|
||||
struct al_pcie_target_bus_cfg *target_bus_cfg = &pcie->target_bus_cfg;
|
||||
unsigned int busnr_ecam = busnr & target_bus_cfg->ecam_mask;
|
||||
unsigned int busnr_reg = busnr & target_bus_cfg->reg_mask;
|
||||
struct pcie_port *pp = &pcie->pci->pp;
|
||||
void __iomem *pci_base_addr;
|
||||
|
||||
pci_base_addr = (void __iomem *)((uintptr_t)pp->va_cfg0_base +
|
||||
@ -240,52 +241,14 @@ static void __iomem *al_pcie_conf_addr_map(struct al_pcie *pcie,
|
||||
target_bus_cfg->reg_mask);
|
||||
}
|
||||
|
||||
return pci_base_addr;
|
||||
return pci_base_addr + where;
|
||||
}
|
||||
|
||||
static int al_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
unsigned int busnr = bus->number;
|
||||
void __iomem *pci_addr;
|
||||
int rc;
|
||||
|
||||
pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
|
||||
|
||||
rc = dw_pcie_read(pci_addr + where, size, val);
|
||||
|
||||
dev_dbg(pci->dev, "%d-byte config read from %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
|
||||
size, pci_domain_nr(bus), bus->number,
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn), where,
|
||||
(pci_addr + where), *val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int al_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
unsigned int busnr = bus->number;
|
||||
void __iomem *pci_addr;
|
||||
int rc;
|
||||
|
||||
pci_addr = al_pcie_conf_addr_map(pcie, busnr, devfn);
|
||||
|
||||
rc = dw_pcie_write(pci_addr + where, size, val);
|
||||
|
||||
dev_dbg(pci->dev, "%d-byte config write to %04x:%02x:%02x.%d offset 0x%x (pci_addr: 0x%px) - val:0x%x\n",
|
||||
size, pci_domain_nr(bus), bus->number,
|
||||
PCI_SLOT(devfn), PCI_FUNC(devfn), where,
|
||||
(pci_addr + where), val);
|
||||
|
||||
return rc;
|
||||
}
|
||||
static struct pci_ops al_child_pci_ops = {
|
||||
.map_bus = al_pcie_conf_addr_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
{
|
||||
@ -297,6 +260,7 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
u8 secondary_bus;
|
||||
u32 cfg_control;
|
||||
u32 reg;
|
||||
struct resource *bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS)->res;
|
||||
|
||||
target_bus_cfg = &pcie->target_bus_cfg;
|
||||
|
||||
@ -310,13 +274,13 @@ static void al_pcie_config_prepare(struct al_pcie *pcie)
|
||||
target_bus_cfg->ecam_mask = ecam_bus_mask;
|
||||
/* This portion is taken from the cfg_target_bus reg */
|
||||
target_bus_cfg->reg_mask = ~target_bus_cfg->ecam_mask;
|
||||
target_bus_cfg->reg_val = pp->busn->start & target_bus_cfg->reg_mask;
|
||||
target_bus_cfg->reg_val = bus->start & target_bus_cfg->reg_mask;
|
||||
|
||||
al_pcie_target_bus_set(pcie, target_bus_cfg->reg_val,
|
||||
target_bus_cfg->reg_mask);
|
||||
|
||||
secondary_bus = pp->busn->start + 1;
|
||||
subordinate_bus = pp->busn->end;
|
||||
secondary_bus = bus->start + 1;
|
||||
subordinate_bus = bus->end;
|
||||
|
||||
/* Set the valid values of secondary and subordinate buses */
|
||||
cfg_control_offset = AXI_BASE_OFFSET + pcie->reg_offsets.ob_ctrl +
|
||||
@ -339,6 +303,8 @@ static int al_pcie_host_init(struct pcie_port *pp)
|
||||
struct al_pcie *pcie = to_al_pcie(pci);
|
||||
int rc;
|
||||
|
||||
pp->bridge->child_ops = &al_child_pci_ops;
|
||||
|
||||
rc = al_pcie_rev_id_get(pcie, &pcie->controller_rev_id);
|
||||
if (rc)
|
||||
return rc;
|
||||
@ -353,8 +319,6 @@ static int al_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
static const struct dw_pcie_host_ops al_pcie_host_ops = {
|
||||
.rd_other_conf = al_pcie_rd_other_conf,
|
||||
.wr_other_conf = al_pcie_wr_other_conf,
|
||||
.host_init = al_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -44,13 +44,6 @@ struct artpec_pcie_of_data {
|
||||
|
||||
static const struct of_device_id artpec6_pcie_of_match[];
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
|
||||
#define ACK_F_ASPM_CTRL_OFF (PL_OFFSET + 0xc)
|
||||
#define ACK_N_FTS_MASK GENMASK(15, 8)
|
||||
#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK)
|
||||
|
||||
/* ARTPEC-6 specific registers */
|
||||
#define PCIECFG 0x18
|
||||
#define PCIECFG_DBG_OEN BIT(24)
|
||||
@ -289,30 +282,6 @@ static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie)
|
||||
}
|
||||
}
|
||||
|
||||
static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
u32 val;
|
||||
|
||||
if (artpec6_pcie->variant != ARTPEC7)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Increase the N_FTS (Number of Fast Training Sequences)
|
||||
* to be transmitted when transitioning from L0s to L0.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF);
|
||||
val &= ~ACK_N_FTS_MASK;
|
||||
val |= ACK_N_FTS(180);
|
||||
dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val);
|
||||
|
||||
/*
|
||||
* Set the Number of Fast Training Sequences that the core
|
||||
* advertises as its N_FTS during Gen2 or Gen3 link training.
|
||||
*/
|
||||
dw_pcie_link_set_n_fts(pci, 180);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
u32 val;
|
||||
@ -346,29 +315,23 @@ static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
usleep_range(100, 200);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
}
|
||||
|
||||
static int artpec6_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
|
||||
if (artpec6_pcie->variant == ARTPEC7) {
|
||||
pci->n_fts[0] = 180;
|
||||
pci->n_fts[1] = 180;
|
||||
}
|
||||
artpec6_pcie_assert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
artpec6_pcie_establish_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
artpec6_pcie_enable_interrupts(artpec6_pcie);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -412,7 +375,6 @@ static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
|
||||
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <linux/pci-epc.h>
|
||||
#include <linux/pci-epf.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
|
||||
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct pci_epc *epc = ep->epc;
|
||||
@ -28,12 +30,39 @@ void dw_pcie_ep_init_notify(struct dw_pcie_ep *ep)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_ep_init_notify);
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
|
||||
int flags)
|
||||
struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
list_for_each_entry(ep_func, &ep->func_list, list) {
|
||||
if (ep_func->func_no == func_no)
|
||||
return ep_func;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static unsigned int dw_pcie_ep_func_select(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
if (ep->ops->func_conf_select)
|
||||
func_offset = ep->ops->func_conf_select(ep, func_no);
|
||||
|
||||
return func_offset;
|
||||
}
|
||||
|
||||
static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, u8 func_no,
|
||||
enum pci_barno bar, int flags)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = func_offset + PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
@ -46,7 +75,53 @@ static void __dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar,
|
||||
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
__dw_pcie_ep_reset_bar(pci, bar, 0);
|
||||
u8 func_no, funcs;
|
||||
|
||||
funcs = pci->ep.epc->max_functions;
|
||||
|
||||
for (func_no = 0; func_no < funcs; func_no++)
|
||||
__dw_pcie_ep_reset_bar(pci, func_no, bar, 0);
|
||||
}
|
||||
|
||||
static u8 __dw_pcie_ep_find_next_cap(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 cap_ptr, u8 cap)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
u8 cap_id, next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
if (!cap_ptr)
|
||||
return 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, func_offset + cap_ptr);
|
||||
cap_id = (reg & 0x00ff);
|
||||
|
||||
if (cap_id > PCI_CAP_ID_MAX)
|
||||
return 0;
|
||||
|
||||
if (cap_id == cap)
|
||||
return cap_ptr;
|
||||
|
||||
next_cap_ptr = (reg & 0xff00) >> 8;
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
static u8 dw_pcie_ep_find_capability(struct dw_pcie_ep *ep, u8 func_no, u8 cap)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
u8 next_cap_ptr;
|
||||
u16 reg;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = dw_pcie_readw_dbi(pci, func_offset + PCI_CAPABILITY_LIST);
|
||||
next_cap_ptr = (reg & 0x00ff);
|
||||
|
||||
return __dw_pcie_ep_find_next_cap(ep, func_no, next_cap_ptr, cap);
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||
@ -54,28 +129,31 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid);
|
||||
dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid);
|
||||
dw_pcie_writeb_dbi(pci, PCI_CLASS_PROG, hdr->progif_code);
|
||||
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_VENDOR_ID, hdr->vendorid);
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_DEVICE_ID, hdr->deviceid);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_REVISION_ID, hdr->revid);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_CLASS_PROG, hdr->progif_code);
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_CLASS_DEVICE,
|
||||
hdr->subclass_code | hdr->baseclass_code << 8);
|
||||
dw_pcie_writeb_dbi(pci, PCI_CACHE_LINE_SIZE,
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_CACHE_LINE_SIZE,
|
||||
hdr->cache_line_size);
|
||||
dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_VENDOR_ID,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_VENDOR_ID,
|
||||
hdr->subsys_vendor_id);
|
||||
dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN,
|
||||
dw_pcie_writew_dbi(pci, func_offset + PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
dw_pcie_writeb_dbi(pci, func_offset + PCI_INTERRUPT_PIN,
|
||||
hdr->interrupt_pin);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
dma_addr_t cpu_addr,
|
||||
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_barno bar, dma_addr_t cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int ret;
|
||||
@ -88,7 +166,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = dw_pcie_prog_inbound_atu(pci, free_win, bar, cpu_addr,
|
||||
ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr,
|
||||
as_type);
|
||||
if (ret < 0) {
|
||||
dev_err(pci->dev, "Failed to program IB window\n");
|
||||
@ -101,7 +179,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
||||
static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no,
|
||||
phys_addr_t phys_addr,
|
||||
u64 pci_addr, size_t size)
|
||||
{
|
||||
u32 free_win;
|
||||
@ -113,8 +192,8 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM,
|
||||
phys_addr, pci_addr, size);
|
||||
dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM,
|
||||
phys_addr, pci_addr, size);
|
||||
|
||||
set_bit(free_win, ep->ob_window_map);
|
||||
ep->outbound_addr[free_win] = phys_addr;
|
||||
@ -130,7 +209,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_barno bar = epf_bar->barno;
|
||||
u32 atu_index = ep->bar_to_atu[bar];
|
||||
|
||||
__dw_pcie_ep_reset_bar(pci, bar, epf_bar->flags);
|
||||
__dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags);
|
||||
|
||||
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
|
||||
clear_bit(atu_index, ep->ib_window_map);
|
||||
@ -147,14 +226,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
|
||||
size_t size = epf_bar->size;
|
||||
int flags = epf_bar->flags;
|
||||
enum dw_pcie_as_type as_type;
|
||||
u32 reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
u32 reg;
|
||||
unsigned int func_offset = 0;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset;
|
||||
|
||||
if (!(flags & PCI_BASE_ADDRESS_SPACE))
|
||||
as_type = DW_PCIE_AS_MEM;
|
||||
else
|
||||
as_type = DW_PCIE_AS_IO;
|
||||
|
||||
ret = dw_pcie_ep_inbound_atu(ep, bar, epf_bar->phys_addr, as_type);
|
||||
ret = dw_pcie_ep_inbound_atu(ep, func_no, bar,
|
||||
epf_bar->phys_addr, as_type);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -213,7 +298,7 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
ret = dw_pcie_ep_outbound_atu(ep, addr, pci_addr, size);
|
||||
ret = dw_pcie_ep_outbound_atu(ep, func_no, addr, pci_addr, size);
|
||||
if (ret) {
|
||||
dev_err(pci->dev, "Failed to enable address\n");
|
||||
return ret;
|
||||
@ -227,11 +312,16 @@ static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
if (!(val & PCI_MSI_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
@ -246,11 +336,16 @@ static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSI_FLAGS_QMASK;
|
||||
val |= (interrupts << 1) & PCI_MSI_FLAGS_QMASK;
|
||||
@ -266,11 +361,16 @@ static int dw_pcie_ep_get_msix(struct pci_epc *epc, u8 func_no)
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msix_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
if (!(val & PCI_MSIX_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
@ -286,23 +386,28 @@ static int dw_pcie_ep_set_msix(struct pci_epc *epc, u8 func_no, u16 interrupts,
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
u32 val, reg;
|
||||
unsigned int func_offset = 0;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
if (!ep->msix_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_FLAGS;
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_FLAGS;
|
||||
val = dw_pcie_readw_dbi(pci, reg);
|
||||
val &= ~PCI_MSIX_FLAGS_QSIZE;
|
||||
val |= interrupts;
|
||||
dw_pcie_writew_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_TABLE;
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
|
||||
val = offset | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_PBA;
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_PBA;
|
||||
val = (offset + (interrupts * PCI_MSIX_ENTRY_SIZE)) | bir;
|
||||
dw_pcie_writel_dbi(pci, reg, val);
|
||||
|
||||
@ -385,31 +490,36 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
struct pci_epc *epc = ep->epc;
|
||||
unsigned int aligned_offset;
|
||||
unsigned int func_offset = 0;
|
||||
u16 msg_ctrl, msg_data;
|
||||
u32 msg_addr_lower, msg_addr_upper, reg;
|
||||
u64 msg_addr;
|
||||
bool has_upper;
|
||||
int ret;
|
||||
|
||||
if (!ep->msi_cap)
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msi_cap)
|
||||
return -EINVAL;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
/* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
|
||||
reg = ep->msi_cap + PCI_MSI_FLAGS;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_FLAGS;
|
||||
msg_ctrl = dw_pcie_readw_dbi(pci, reg);
|
||||
has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
|
||||
reg = ep->msi_cap + PCI_MSI_ADDRESS_LO;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_LO;
|
||||
msg_addr_lower = dw_pcie_readl_dbi(pci, reg);
|
||||
if (has_upper) {
|
||||
reg = ep->msi_cap + PCI_MSI_ADDRESS_HI;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_ADDRESS_HI;
|
||||
msg_addr_upper = dw_pcie_readl_dbi(pci, reg);
|
||||
reg = ep->msi_cap + PCI_MSI_DATA_64;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_64;
|
||||
msg_data = dw_pcie_readw_dbi(pci, reg);
|
||||
} else {
|
||||
msg_addr_upper = 0;
|
||||
reg = ep->msi_cap + PCI_MSI_DATA_32;
|
||||
reg = ep_func->msi_cap + func_offset + PCI_MSI_DATA_32;
|
||||
msg_data = dw_pcie_readw_dbi(pci, reg);
|
||||
}
|
||||
aligned_offset = msg_addr_lower & (epc->mem->window.page_size - 1);
|
||||
@ -427,12 +537,33 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
u32 msg_data;
|
||||
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
msg_data = (func_no << PCIE_MSIX_DOORBELL_PF_SHIFT) |
|
||||
(interrupt_num - 1);
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSIX_DOORBELL, msg_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
struct pci_epf_msix_tbl *msix_tbl;
|
||||
struct pci_epc *epc = ep->epc;
|
||||
unsigned int func_offset = 0;
|
||||
u32 reg, msg_data, vec_ctrl;
|
||||
unsigned int aligned_offset;
|
||||
u32 tbl_offset;
|
||||
@ -440,7 +571,13 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
int ret;
|
||||
u8 bir;
|
||||
|
||||
reg = ep->msix_cap + PCI_MSIX_TABLE;
|
||||
ep_func = dw_pcie_ep_get_func_from_ep(ep, func_no);
|
||||
if (!ep_func || !ep_func->msix_cap)
|
||||
return -EINVAL;
|
||||
|
||||
func_offset = dw_pcie_ep_func_select(ep, func_no);
|
||||
|
||||
reg = ep_func->msix_cap + func_offset + PCI_MSIX_TABLE;
|
||||
tbl_offset = dw_pcie_readl_dbi(pci, reg);
|
||||
bir = (tbl_offset & PCI_MSIX_TABLE_BIR);
|
||||
tbl_offset &= PCI_MSIX_TABLE_OFFSET;
|
||||
@ -505,7 +642,8 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
|
||||
u32 reg;
|
||||
int i;
|
||||
|
||||
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE);
|
||||
hdr_type = dw_pcie_readb_dbi(pci, PCI_HEADER_TYPE) &
|
||||
PCI_HEADER_TYPE_MASK;
|
||||
if (hdr_type != PCI_HEADER_TYPE_NORMAL) {
|
||||
dev_err(pci->dev,
|
||||
"PCIe controller is not set to EP mode (hdr_type:0x%x)!\n",
|
||||
@ -513,23 +651,21 @@ int dw_pcie_ep_init_complete(struct dw_pcie_ep *ep)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ep->msi_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSI);
|
||||
|
||||
ep->msix_cap = dw_pcie_find_capability(pci, PCI_CAP_ID_MSIX);
|
||||
|
||||
offset = dw_pcie_ep_find_ext_capability(pci, PCI_EXT_CAP_ID_REBAR);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
|
||||
if (offset) {
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_REBAR_CTRL);
|
||||
nbars = (reg & PCI_REBAR_CTRL_NBAR_MASK) >>
|
||||
PCI_REBAR_CTRL_NBAR_SHIFT;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
for (i = 0; i < nbars; i++, offset += PCI_REBAR_CTRL)
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_REBAR_CAP, 0x0);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -539,11 +675,15 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
int ret;
|
||||
void *addr;
|
||||
u8 func_no;
|
||||
struct pci_epc *epc;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
const struct pci_epc_features *epc_features;
|
||||
struct dw_pcie_ep_func *ep_func;
|
||||
|
||||
INIT_LIST_HEAD(&ep->func_list);
|
||||
|
||||
if (!pci->dbi_base || !pci->dbi_base2) {
|
||||
dev_err(dev, "dbi_base/dbi_base2 is not populated\n");
|
||||
@ -590,6 +730,9 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
return -ENOMEM;
|
||||
ep->outbound_addr = addr;
|
||||
|
||||
if (pci->link_gen < 1)
|
||||
pci->link_gen = of_pci_get_max_link_speed(np);
|
||||
|
||||
epc = devm_pci_epc_create(dev, &epc_ops);
|
||||
if (IS_ERR(epc)) {
|
||||
dev_err(dev, "Failed to create epc device\n");
|
||||
@ -599,13 +742,27 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
ep->epc = epc;
|
||||
epc_set_drvdata(epc, ep);
|
||||
|
||||
if (ep->ops->ep_init)
|
||||
ep->ops->ep_init(ep);
|
||||
|
||||
ret = of_property_read_u8(np, "max-functions", &epc->max_functions);
|
||||
if (ret < 0)
|
||||
epc->max_functions = 1;
|
||||
|
||||
for (func_no = 0; func_no < epc->max_functions; func_no++) {
|
||||
ep_func = devm_kzalloc(dev, sizeof(*ep_func), GFP_KERNEL);
|
||||
if (!ep_func)
|
||||
return -ENOMEM;
|
||||
|
||||
ep_func->func_no = func_no;
|
||||
ep_func->msi_cap = dw_pcie_ep_find_capability(ep, func_no,
|
||||
PCI_CAP_ID_MSI);
|
||||
ep_func->msix_cap = dw_pcie_ep_find_capability(ep, func_no,
|
||||
PCI_CAP_ID_MSIX);
|
||||
|
||||
list_add_tail(&ep_func->list, &ep->func_list);
|
||||
}
|
||||
|
||||
if (ep->ops->ep_init)
|
||||
ep->ops->ep_init(ep);
|
||||
|
||||
ret = pci_epc_mem_init(epc, ep->phys_base, ep->addr_size,
|
||||
ep->page_size);
|
||||
if (ret < 0) {
|
||||
|
@ -20,30 +20,7 @@
|
||||
#include "pcie-designware.h"
|
||||
|
||||
static struct pci_ops dw_pcie_ops;
|
||||
|
||||
static int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci;
|
||||
|
||||
if (pp->ops->rd_own_conf)
|
||||
return pp->ops->rd_own_conf(pp, where, size, val);
|
||||
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
return dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
{
|
||||
struct dw_pcie *pci;
|
||||
|
||||
if (pp->ops->wr_own_conf)
|
||||
return pp->ops->wr_own_conf(pp, where, size, val);
|
||||
|
||||
pci = to_dw_pcie_from_pp(pp);
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
}
|
||||
static struct pci_ops dw_child_pcie_ops;
|
||||
|
||||
static void dw_msi_ack_irq(struct irq_data *d)
|
||||
{
|
||||
@ -82,13 +59,13 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
||||
unsigned long val;
|
||||
u32 status, num_ctrls;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
for (i = 0; i < num_ctrls; i++) {
|
||||
dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS +
|
||||
(i * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, &status);
|
||||
status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
|
||||
(i * MSI_REG_CTRL_BLOCK_SIZE));
|
||||
if (!status)
|
||||
continue;
|
||||
|
||||
@ -148,6 +125,7 @@ static int dw_pci_msi_set_affinity(struct irq_data *d,
|
||||
static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
@ -158,8 +136,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -167,6 +144,7 @@ static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
@ -177,8 +155,7 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK + res, pp->irq_mask[ctrl]);
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
@ -186,13 +163,14 @@ static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
static void dw_pci_bottom_ack(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
unsigned int res, bit, ctrl;
|
||||
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_STATUS + res, BIT(bit));
|
||||
}
|
||||
|
||||
static struct irq_chip dw_pci_msi_bottom_irq_chip = {
|
||||
@ -288,32 +266,26 @@ void dw_pcie_free_msi(struct pcie_port *pp)
|
||||
irq_domain_remove(pp->msi_domain);
|
||||
irq_domain_remove(pp->irq_domain);
|
||||
|
||||
if (pp->msi_page)
|
||||
__free_page(pp->msi_page);
|
||||
if (pp->msi_data) {
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
|
||||
dma_unmap_single_attrs(dev, pp->msi_data, sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
|
||||
}
|
||||
}
|
||||
|
||||
void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
u64 msi_target;
|
||||
u64 msi_target = (u64)pp->msi_data;
|
||||
|
||||
pp->msi_page = alloc_page(GFP_KERNEL);
|
||||
pp->msi_data = dma_map_page(dev, pp->msi_page, 0, PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, pp->msi_data)) {
|
||||
dev_err(dev, "Failed to map MSI data\n");
|
||||
__free_page(pp->msi_page);
|
||||
pp->msi_page = NULL;
|
||||
if (!IS_ENABLED(CONFIG_PCI_MSI))
|
||||
return;
|
||||
}
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
/* Program the msi_data */
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
|
||||
lower_32_bits(msi_target));
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4,
|
||||
upper_32_bits(msi_target));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
|
||||
|
||||
@ -324,20 +296,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource_entry *win;
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct resource *cfg_res;
|
||||
u32 hdr_type;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_init(&pci->pp.lock);
|
||||
|
||||
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
|
||||
if (cfg_res) {
|
||||
pp->cfg0_size = resource_size(cfg_res) >> 1;
|
||||
pp->cfg1_size = resource_size(cfg_res) >> 1;
|
||||
pp->cfg0_size = resource_size(cfg_res);
|
||||
pp->cfg0_base = cfg_res->start;
|
||||
pp->cfg1_base = cfg_res->start + pp->cfg0_size;
|
||||
} else if (!pp->va_cfg0_base) {
|
||||
dev_err(dev, "Missing *config* reg space\n");
|
||||
}
|
||||
@ -346,47 +314,33 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
pp->bridge = bridge;
|
||||
|
||||
/* Get the I/O and memory ranges from DT */
|
||||
resource_list_for_each_entry(win, &bridge->windows) {
|
||||
switch (resource_type(win->res)) {
|
||||
case IORESOURCE_IO:
|
||||
pp->io = win->res;
|
||||
pp->io->name = "I/O";
|
||||
pp->io_size = resource_size(pp->io);
|
||||
pp->io_bus_addr = pp->io->start - win->offset;
|
||||
pp->io_base = pci_pio_to_address(pp->io->start);
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
pp->mem = win->res;
|
||||
pp->mem->name = "MEM";
|
||||
pp->mem_size = resource_size(pp->mem);
|
||||
pp->mem_bus_addr = pp->mem->start - win->offset;
|
||||
pp->io_size = resource_size(win->res);
|
||||
pp->io_bus_addr = win->res->start - win->offset;
|
||||
pp->io_base = pci_pio_to_address(win->res->start);
|
||||
break;
|
||||
case 0:
|
||||
pp->cfg = win->res;
|
||||
pp->cfg0_size = resource_size(pp->cfg) >> 1;
|
||||
pp->cfg1_size = resource_size(pp->cfg) >> 1;
|
||||
pp->cfg0_base = pp->cfg->start;
|
||||
pp->cfg1_base = pp->cfg->start + pp->cfg0_size;
|
||||
break;
|
||||
case IORESOURCE_BUS:
|
||||
pp->busn = win->res;
|
||||
dev_err(dev, "Missing *config* reg space\n");
|
||||
pp->cfg0_size = resource_size(win->res);
|
||||
pp->cfg0_base = win->res->start;
|
||||
if (!pci->dbi_base) {
|
||||
pci->dbi_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg0_base,
|
||||
pp->cfg0_size);
|
||||
if (!pci->dbi_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pci->dbi_base) {
|
||||
pci->dbi_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg->start,
|
||||
resource_size(pp->cfg));
|
||||
if (!pci->dbi_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
pp->mem_base = pp->mem->start;
|
||||
|
||||
if (!pp->va_cfg0_base) {
|
||||
pp->va_cfg0_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg0_base, pp->cfg0_size);
|
||||
@ -396,20 +350,13 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
if (!pp->va_cfg1_base) {
|
||||
pp->va_cfg1_base = devm_pci_remap_cfgspace(dev,
|
||||
pp->cfg1_base,
|
||||
pp->cfg1_size);
|
||||
if (!pp->va_cfg1_base) {
|
||||
dev_err(dev, "Error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-viewport", &pci->num_viewport);
|
||||
if (ret)
|
||||
pci->num_viewport = 2;
|
||||
|
||||
if (pci->link_gen < 1)
|
||||
pci->link_gen = of_pci_get_max_link_speed(np);
|
||||
|
||||
if (pci_msi_enabled()) {
|
||||
/*
|
||||
* If a specific SoC driver needs to change the
|
||||
@ -440,6 +387,16 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
irq_set_chained_handler_and_data(pp->msi_irq,
|
||||
dw_chained_msi_isr,
|
||||
pp);
|
||||
|
||||
pp->msi_data = dma_map_single_attrs(pci->dev, &pp->msi_msg,
|
||||
sizeof(pp->msi_msg),
|
||||
DMA_FROM_DEVICE,
|
||||
DMA_ATTR_SKIP_CPU_SYNC);
|
||||
if (dma_mapping_error(pci->dev, pp->msi_data)) {
|
||||
dev_err(pci->dev, "Failed to map MSI data\n");
|
||||
pp->msi_data = 0;
|
||||
goto err_free_msi;
|
||||
}
|
||||
} else {
|
||||
ret = pp->ops->msi_host_init(pp);
|
||||
if (ret < 0)
|
||||
@ -447,47 +404,21 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
}
|
||||
|
||||
/* Set default bus ops */
|
||||
bridge->ops = &dw_pcie_ops;
|
||||
bridge->child_ops = &dw_child_pcie_ops;
|
||||
|
||||
if (pp->ops->host_init) {
|
||||
ret = pp->ops->host_init(pp);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
ret = dw_pcie_rd_own_conf(pp, PCI_HEADER_TYPE, 1, &hdr_type);
|
||||
if (ret != PCIBIOS_SUCCESSFUL) {
|
||||
dev_err(pci->dev, "Failed reading PCI_HEADER_TYPE cfg space reg (ret: 0x%x)\n",
|
||||
ret);
|
||||
ret = pcibios_err_to_errno(ret);
|
||||
goto err_free_msi;
|
||||
}
|
||||
if (hdr_type != PCI_HEADER_TYPE_BRIDGE) {
|
||||
dev_err(pci->dev,
|
||||
"PCIe controller is not set to bridge type (hdr_type: 0x%x)!\n",
|
||||
hdr_type);
|
||||
ret = -EIO;
|
||||
goto err_free_msi;
|
||||
}
|
||||
|
||||
bridge->sysdata = pp;
|
||||
bridge->ops = &dw_pcie_ops;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
if (ret)
|
||||
goto err_free_msi;
|
||||
|
||||
pp->root_bus = bridge->bus;
|
||||
|
||||
if (pp->ops->scan_bus)
|
||||
pp->ops->scan_bus(pp);
|
||||
|
||||
pci_bus_size_bridges(pp->root_bus);
|
||||
pci_bus_assign_resources(pp->root_bus);
|
||||
|
||||
list_for_each_entry(child, &pp->root_bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
||||
pci_bus_add_devices(pp->root_bus);
|
||||
return 0;
|
||||
ret = pci_host_probe(bridge);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
err_free_msi:
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
@ -498,47 +429,58 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_init);
|
||||
|
||||
void dw_pcie_host_deinit(struct pcie_port *pp)
|
||||
{
|
||||
pci_stop_root_bus(pp->root_bus);
|
||||
pci_remove_root_bus(pp->root_bus);
|
||||
pci_stop_root_bus(pp->bridge->bus);
|
||||
pci_remove_root_bus(pp->bridge->bus);
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init)
|
||||
dw_pcie_free_msi(pp);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_host_deinit);
|
||||
|
||||
static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 *val,
|
||||
bool write)
|
||||
static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn, int where)
|
||||
{
|
||||
int ret, type;
|
||||
u32 busdev, cfg_size;
|
||||
u64 cpu_addr;
|
||||
void __iomem *va_cfg_base;
|
||||
int type;
|
||||
u32 busdev;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* Checking whether the link is up here is a last line of defense
|
||||
* against platforms that forward errors on the system bus as
|
||||
* SError upon PCI configuration transactions issued when the link
|
||||
* is down. This check is racy by definition and does not stop
|
||||
* the system from triggering an SError if the link goes down
|
||||
* after this check is performed.
|
||||
*/
|
||||
if (!dw_pcie_link_up(pci))
|
||||
return NULL;
|
||||
|
||||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||
|
||||
if (pci_is_root_bus(bus->parent)) {
|
||||
if (pci_is_root_bus(bus->parent))
|
||||
type = PCIE_ATU_TYPE_CFG0;
|
||||
cpu_addr = pp->cfg0_base;
|
||||
cfg_size = pp->cfg0_size;
|
||||
va_cfg_base = pp->va_cfg0_base;
|
||||
} else {
|
||||
else
|
||||
type = PCIE_ATU_TYPE_CFG1;
|
||||
cpu_addr = pp->cfg1_base;
|
||||
cfg_size = pp->cfg1_size;
|
||||
va_cfg_base = pp->va_cfg1_base;
|
||||
}
|
||||
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
type, cpu_addr,
|
||||
busdev, cfg_size);
|
||||
if (write)
|
||||
ret = dw_pcie_write(va_cfg_base + where, size, *val);
|
||||
else
|
||||
ret = dw_pcie_read(va_cfg_base + where, size, val);
|
||||
type, pp->cfg0_base,
|
||||
busdev, pp->cfg0_size);
|
||||
|
||||
if (pci->num_viewport <= 2)
|
||||
return pp->va_cfg0_base + where;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
int ret;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
@ -546,77 +488,45 @@ static int dw_pcie_access_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 *val)
|
||||
{
|
||||
if (pp->ops->rd_other_conf)
|
||||
return pp->ops->rd_other_conf(pp, bus, devfn, where,
|
||||
size, val);
|
||||
|
||||
return dw_pcie_access_other_conf(pp, bus, devfn, where, size, val,
|
||||
false);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
u32 devfn, int where, int size, u32 val)
|
||||
{
|
||||
if (pp->ops->wr_other_conf)
|
||||
return pp->ops->wr_other_conf(pp, bus, devfn, where,
|
||||
size, val);
|
||||
|
||||
return dw_pcie_access_other_conf(pp, bus, devfn, where, size, &val,
|
||||
true);
|
||||
}
|
||||
|
||||
static int dw_pcie_valid_device(struct pcie_port *pp, struct pci_bus *bus,
|
||||
int dev)
|
||||
static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
int ret;
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/* If there is no link, then there is no device */
|
||||
if (!pci_is_root_bus(bus)) {
|
||||
if (!dw_pcie_link_up(pci))
|
||||
return 0;
|
||||
} else if (dev > 0)
|
||||
/* Access only one slot on each root port */
|
||||
return 0;
|
||||
ret = pci_generic_config_write(bus, devfn, where, size, val);
|
||||
|
||||
return 1;
|
||||
if (!ret && pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 *val)
|
||||
static struct pci_ops dw_child_pcie_ops = {
|
||||
.map_bus = dw_pcie_other_conf_map_bus,
|
||||
.read = dw_pcie_rd_other_conf,
|
||||
.write = dw_pcie_wr_other_conf,
|
||||
};
|
||||
|
||||
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn))) {
|
||||
*val = 0xffffffff;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
if (PCI_SLOT(devfn) > 0)
|
||||
return NULL;
|
||||
|
||||
if (pci_is_root_bus(bus))
|
||||
return dw_pcie_rd_own_conf(pp, where, size, val);
|
||||
|
||||
return dw_pcie_rd_other_conf(pp, bus, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct pcie_port *pp = bus->sysdata;
|
||||
|
||||
if (!dw_pcie_valid_device(pp, bus, PCI_SLOT(devfn)))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
if (pci_is_root_bus(bus))
|
||||
return dw_pcie_wr_own_conf(pp, where, size, val);
|
||||
|
||||
return dw_pcie_wr_other_conf(pp, bus, devfn, where, size, val);
|
||||
return pci->dbi_base + where;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus);
|
||||
|
||||
static struct pci_ops dw_pcie_ops = {
|
||||
.read = dw_pcie_rd_conf,
|
||||
.write = dw_pcie_wr_conf,
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
@ -632,18 +542,18 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup(pci);
|
||||
|
||||
if (!pp->ops->msi_host_init) {
|
||||
if (pci_msi_enabled() && !pp->ops->msi_host_init) {
|
||||
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
/* Initialize IRQ Status array */
|
||||
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
|
||||
pp->irq_mask[ctrl] = ~0;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK +
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, pp->irq_mask[ctrl]);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
|
||||
pp->irq_mask[ctrl]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
~0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -671,28 +581,32 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
|
||||
|
||||
/*
|
||||
* If the platform provides ->rd_other_conf, it means the platform
|
||||
* uses its own address translation component rather than ATU, so
|
||||
* we should not program the ATU here.
|
||||
* If the platform provides its own child bus config accesses, it means
|
||||
* the platform uses its own address translation component rather than
|
||||
* ATU, so we should not program the ATU here.
|
||||
*/
|
||||
if (!pp->ops->rd_other_conf) {
|
||||
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
|
||||
struct resource_entry *entry =
|
||||
resource_list_first_type(&pp->bridge->windows, IORESOURCE_MEM);
|
||||
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX0,
|
||||
PCIE_ATU_TYPE_MEM, pp->mem_base,
|
||||
pp->mem_bus_addr, pp->mem_size);
|
||||
PCIE_ATU_TYPE_MEM, entry->res->start,
|
||||
entry->res->start - entry->offset,
|
||||
resource_size(entry->res));
|
||||
if (pci->num_viewport > 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX2,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
pp->io_bus_addr, pp->io_size);
|
||||
}
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCI_BASE_ADDRESS_0, 4, 0);
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
|
||||
/* Program correct class for RC */
|
||||
dw_pcie_wr_own_conf(pp, PCI_CLASS_DEVICE, 2, PCI_CLASS_BRIDGE_PCI);
|
||||
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
|
||||
|
||||
dw_pcie_rd_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, &val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
@ -39,9 +39,7 @@ static int dw_plat_pcie_host_init(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "../../pci.h"
|
||||
@ -166,21 +167,6 @@ void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_write_dbi);
|
||||
|
||||
u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pci->ops->read_dbi2)
|
||||
return pci->ops->read_dbi2(pci, pci->dbi_base2, reg, size);
|
||||
|
||||
ret = dw_pcie_read(pci->dbi_base2 + reg, size, &val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "read DBI address failed\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
{
|
||||
int ret;
|
||||
@ -195,31 +181,31 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
dev_err(pci->dev, "write DBI address failed\n");
|
||||
}
|
||||
|
||||
u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size)
|
||||
static u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
if (pci->ops->read_dbi)
|
||||
return pci->ops->read_dbi(pci, pci->atu_base, reg, size);
|
||||
return pci->ops->read_dbi(pci, pci->atu_base, reg, 4);
|
||||
|
||||
ret = dw_pcie_read(pci->atu_base + reg, size, &val);
|
||||
ret = dw_pcie_read(pci->atu_base + reg, 4, &val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "Read ATU address failed\n");
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val)
|
||||
static void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (pci->ops->write_dbi) {
|
||||
pci->ops->write_dbi(pci, pci->atu_base, reg, size, val);
|
||||
pci->ops->write_dbi(pci, pci->atu_base, reg, 4, val);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = dw_pcie_write(pci->atu_base + reg, size, val);
|
||||
ret = dw_pcie_write(pci->atu_base + reg, 4, val);
|
||||
if (ret)
|
||||
dev_err(pci->dev, "Write ATU address failed\n");
|
||||
}
|
||||
@ -239,9 +225,10 @@ static void dw_pcie_writel_ob_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr,
|
||||
u32 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
u64 limit_addr = cpu_addr + size - 1;
|
||||
@ -259,7 +246,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
|
||||
upper_32_bits(pci_addr));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1,
|
||||
type);
|
||||
type | PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
|
||||
PCIE_ATU_ENABLE);
|
||||
|
||||
@ -278,8 +265,9 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int type, u64 cpu_addr,
|
||||
u64 pci_addr, u32 size)
|
||||
{
|
||||
u32 retries, val;
|
||||
|
||||
@ -287,8 +275,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
|
||||
|
||||
if (pci->iatu_unroll_enabled) {
|
||||
dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr,
|
||||
pci_addr, size);
|
||||
dw_pcie_prog_outbound_atu_unroll(pci, func_no, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -304,7 +292,8 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
lower_32_bits(pci_addr));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET,
|
||||
upper_32_bits(pci_addr));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE);
|
||||
|
||||
/*
|
||||
@ -321,6 +310,21 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
|
||||
}
|
||||
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
||||
u64 cpu_addr, u64 pci_addr, u32 size)
|
||||
{
|
||||
__dw_pcie_prog_outbound_atu(pci, 0, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
}
|
||||
|
||||
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size)
|
||||
{
|
||||
__dw_pcie_prog_outbound_atu(pci, func_no, index, type,
|
||||
cpu_addr, pci_addr, size);
|
||||
}
|
||||
|
||||
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);
|
||||
@ -336,8 +340,8 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg,
|
||||
dw_pcie_writel_atu(pci, offset + reg, val);
|
||||
}
|
||||
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no,
|
||||
int index, int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int type;
|
||||
@ -359,8 +363,10 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type);
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2,
|
||||
PCIE_ATU_FUNC_NUM_MATCH_EN |
|
||||
PCIE_ATU_ENABLE |
|
||||
PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
|
||||
@ -381,14 +387,15 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, int index,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
u64 cpu_addr, enum dw_pcie_as_type as_type)
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type)
|
||||
{
|
||||
int type;
|
||||
u32 retries, val;
|
||||
|
||||
if (pci->iatu_unroll_enabled)
|
||||
return dw_pcie_prog_inbound_atu_unroll(pci, index, bar,
|
||||
return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar,
|
||||
cpu_addr, as_type);
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND |
|
||||
@ -407,9 +414,11 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE
|
||||
| PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type |
|
||||
PCIE_ATU_FUNC_NUM(func_no));
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE |
|
||||
PCIE_ATU_FUNC_NUM_MATCH_EN |
|
||||
PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
|
||||
|
||||
/*
|
||||
* Make sure ATU enable takes effect before any subsequent config
|
||||
@ -444,7 +453,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, (u32)~PCIE_ATU_ENABLE);
|
||||
dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE);
|
||||
}
|
||||
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci)
|
||||
@ -488,50 +497,41 @@ void dw_pcie_upconfig_setup(struct dw_pcie *pci)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_upconfig_setup);
|
||||
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
static void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen)
|
||||
{
|
||||
u32 reg, val;
|
||||
u32 cap, ctrl2, link_speed;
|
||||
u8 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
reg = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
|
||||
reg &= ~PCI_EXP_LNKCTL2_TLS;
|
||||
cap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
ctrl2 = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCTL2);
|
||||
ctrl2 &= ~PCI_EXP_LNKCTL2_TLS;
|
||||
|
||||
switch (pcie_link_speed[link_gen]) {
|
||||
case PCIE_SPEED_2_5GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_2_5GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_2_5GT;
|
||||
break;
|
||||
case PCIE_SPEED_5_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_5_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_5_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_8_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_8_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_8_0GT;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
reg |= PCI_EXP_LNKCTL2_TLS_16_0GT;
|
||||
link_speed = PCI_EXP_LNKCTL2_TLS_16_0GT;
|
||||
break;
|
||||
default:
|
||||
/* Use hardware capability */
|
||||
val = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP);
|
||||
val = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
reg &= ~PCI_EXP_LNKCTL2_HASD;
|
||||
reg |= FIELD_PREP(PCI_EXP_LNKCTL2_TLS, val);
|
||||
link_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, cap);
|
||||
ctrl2 &= ~PCI_EXP_LNKCTL2_HASD;
|
||||
break;
|
||||
}
|
||||
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, reg);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_max_speed);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCTL2, ctrl2 | link_speed);
|
||||
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts)
|
||||
{
|
||||
u32 val;
|
||||
cap &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
dw_pcie_writel_dbi(pci, offset + PCI_EXP_LNKCAP, cap | link_speed);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_N_FTS_MASK;
|
||||
val |= n_fts & PORT_LOGIC_N_FTS_MASK;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dw_pcie_link_set_n_fts);
|
||||
|
||||
static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
{
|
||||
@ -546,32 +546,58 @@ static u8 dw_pcie_iatu_unroll_enabled(struct dw_pcie *pci)
|
||||
|
||||
void dw_pcie_setup(struct dw_pcie *pci)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
u32 lanes;
|
||||
struct device *dev = pci->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
|
||||
if (pci->version >= 0x480A || (!pci->version &&
|
||||
dw_pcie_iatu_unroll_enabled(pci))) {
|
||||
pci->iatu_unroll_enabled = true;
|
||||
if (!pci->atu_base)
|
||||
pci->atu_base =
|
||||
devm_platform_ioremap_resource_byname(pdev, "atu");
|
||||
if (IS_ERR(pci->atu_base))
|
||||
pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET;
|
||||
}
|
||||
dev_dbg(pci->dev, "iATU unroll: %s\n", pci->iatu_unroll_enabled ?
|
||||
"enabled" : "disabled");
|
||||
|
||||
if (pci->link_gen > 0)
|
||||
dw_pcie_link_set_max_speed(pci, pci->link_gen);
|
||||
|
||||
ret = of_property_read_u32(np, "num-lanes", &lanes);
|
||||
if (ret) {
|
||||
dev_dbg(pci->dev, "property num-lanes isn't found\n");
|
||||
/* Configure Gen1 N_FTS */
|
||||
if (pci->n_fts[0]) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
|
||||
val |= PORT_AFR_N_FTS(pci->n_fts[0]);
|
||||
val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
|
||||
}
|
||||
|
||||
/* Configure Gen2+ N_FTS */
|
||||
if (pci->n_fts[1]) {
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_N_FTS_MASK;
|
||||
val |= pci->n_fts[pci->link_gen - 1];
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val |= PORT_LINK_DLL_LINK_EN;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
|
||||
of_property_read_u32(np, "num-lanes", &pci->num_lanes);
|
||||
if (!pci->num_lanes) {
|
||||
dev_dbg(pci->dev, "Using h/w default number of lanes\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set the number of lanes */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
|
||||
val &= ~PORT_LINK_FAST_LINK_MODE;
|
||||
val &= ~PORT_LINK_MODE_MASK;
|
||||
switch (lanes) {
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LINK_MODE_1_LANES;
|
||||
break;
|
||||
@ -585,7 +611,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
val |= PORT_LINK_MODE_8_LANES;
|
||||
break;
|
||||
default:
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", lanes);
|
||||
dev_err(pci->dev, "num-lanes %u: invalid value\n", pci->num_lanes);
|
||||
return;
|
||||
}
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
|
||||
@ -593,7 +619,7 @@ void dw_pcie_setup(struct dw_pcie *pci)
|
||||
/* Set link width speed control register */
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~PORT_LOGIC_LINK_WIDTH_MASK;
|
||||
switch (lanes) {
|
||||
switch (pci->num_lanes) {
|
||||
case 1:
|
||||
val |= PORT_LOGIC_LINK_WIDTH_1_LANES;
|
||||
break;
|
||||
|
@ -32,10 +32,18 @@
|
||||
/* Synopsys-specific PCIe configuration registers */
|
||||
#define PCIE_PORT_AFR 0x70C
|
||||
#define PORT_AFR_N_FTS_MASK GENMASK(15, 8)
|
||||
#define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
|
||||
#define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16)
|
||||
#define PORT_AFR_CC_N_FTS(n) FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n)
|
||||
#define PORT_AFR_ENTER_ASPM BIT(30)
|
||||
#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24
|
||||
#define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)
|
||||
#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27
|
||||
#define PORT_AFR_L1_ENTRANCE_LAT_MASK GENMASK(29, 27)
|
||||
|
||||
#define PCIE_PORT_LINK_CONTROL 0x710
|
||||
#define PORT_LINK_DLL_LINK_EN BIT(5)
|
||||
#define PORT_LINK_FAST_LINK_MODE BIT(7)
|
||||
#define PORT_LINK_MODE_MASK GENMASK(21, 16)
|
||||
#define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)
|
||||
#define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)
|
||||
@ -80,9 +88,11 @@
|
||||
#define PCIE_ATU_TYPE_IO 0x2
|
||||
#define PCIE_ATU_TYPE_CFG0 0x4
|
||||
#define PCIE_ATU_TYPE_CFG1 0x5
|
||||
#define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20)
|
||||
#define PCIE_ATU_CR2 0x908
|
||||
#define PCIE_ATU_ENABLE BIT(31)
|
||||
#define PCIE_ATU_BAR_MODE_ENABLE BIT(30)
|
||||
#define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19)
|
||||
#define PCIE_ATU_LOWER_BASE 0x90C
|
||||
#define PCIE_ATU_UPPER_BASE 0x910
|
||||
#define PCIE_ATU_LIMIT 0x914
|
||||
@ -95,6 +105,9 @@
|
||||
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
||||
#define PCIE_DBI_RO_WR_EN BIT(0)
|
||||
|
||||
#define PCIE_MSIX_DOORBELL 0x948
|
||||
#define PCIE_MSIX_DOORBELL_PF_SHIFT 24
|
||||
|
||||
#define PCIE_PL_CHK_REG_CONTROL_STATUS 0xB20
|
||||
#define PCIE_PL_CHK_REG_CHK_REG_START BIT(0)
|
||||
#define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS BIT(1)
|
||||
@ -160,14 +173,7 @@ enum dw_pcie_device_mode {
|
||||
};
|
||||
|
||||
struct dw_pcie_host_ops {
|
||||
int (*rd_own_conf)(struct pcie_port *pp, int where, int size, u32 *val);
|
||||
int (*wr_own_conf)(struct pcie_port *pp, int where, int size, u32 val);
|
||||
int (*rd_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 *val);
|
||||
int (*wr_other_conf)(struct pcie_port *pp, struct pci_bus *bus,
|
||||
unsigned int devfn, int where, int size, u32 val);
|
||||
int (*host_init)(struct pcie_port *pp);
|
||||
void (*scan_bus)(struct pcie_port *pp);
|
||||
void (*set_num_vectors)(struct pcie_port *pp);
|
||||
int (*msi_host_init)(struct pcie_port *pp);
|
||||
};
|
||||
@ -176,30 +182,20 @@ struct pcie_port {
|
||||
u64 cfg0_base;
|
||||
void __iomem *va_cfg0_base;
|
||||
u32 cfg0_size;
|
||||
u64 cfg1_base;
|
||||
void __iomem *va_cfg1_base;
|
||||
u32 cfg1_size;
|
||||
resource_size_t io_base;
|
||||
phys_addr_t io_bus_addr;
|
||||
u32 io_size;
|
||||
u64 mem_base;
|
||||
phys_addr_t mem_bus_addr;
|
||||
u32 mem_size;
|
||||
struct resource *cfg;
|
||||
struct resource *io;
|
||||
struct resource *mem;
|
||||
struct resource *busn;
|
||||
int irq;
|
||||
const struct dw_pcie_host_ops *ops;
|
||||
int msi_irq;
|
||||
struct irq_domain *irq_domain;
|
||||
struct irq_domain *msi_domain;
|
||||
u16 msi_msg;
|
||||
dma_addr_t msi_data;
|
||||
struct page *msi_page;
|
||||
struct irq_chip *msi_irq_chip;
|
||||
u32 num_vectors;
|
||||
u32 irq_mask[MAX_MSI_CTRLS];
|
||||
struct pci_bus *root_bus;
|
||||
struct pci_host_bridge *bridge;
|
||||
raw_spinlock_t lock;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
|
||||
};
|
||||
@ -215,10 +211,26 @@ struct dw_pcie_ep_ops {
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u16 interrupt_num);
|
||||
const struct pci_epc_features* (*get_features)(struct dw_pcie_ep *ep);
|
||||
/*
|
||||
* Provide a method to implement the different func config space
|
||||
* access for different platform, if different func have different
|
||||
* offset, return the offset of func. if use write a register way
|
||||
* return a 0, and implement code in callback function of platform
|
||||
* driver.
|
||||
*/
|
||||
unsigned int (*func_conf_select)(struct dw_pcie_ep *ep, u8 func_no);
|
||||
};
|
||||
|
||||
struct dw_pcie_ep_func {
|
||||
struct list_head list;
|
||||
u8 func_no;
|
||||
u8 msi_cap; /* MSI capability offset */
|
||||
u8 msix_cap; /* MSI-X capability offset */
|
||||
};
|
||||
|
||||
struct dw_pcie_ep {
|
||||
struct pci_epc *epc;
|
||||
struct list_head func_list;
|
||||
const struct dw_pcie_ep_ops *ops;
|
||||
phys_addr_t phys_base;
|
||||
size_t addr_size;
|
||||
@ -231,8 +243,6 @@ struct dw_pcie_ep {
|
||||
u32 num_ob_windows;
|
||||
void __iomem *msi_mem;
|
||||
phys_addr_t msi_mem_phys;
|
||||
u8 msi_cap; /* MSI capability offset */
|
||||
u8 msix_cap; /* MSI-X capability offset */
|
||||
struct pci_epf_bar *epf_bar[PCI_STD_NUM_BARS];
|
||||
};
|
||||
|
||||
@ -242,8 +252,6 @@ struct dw_pcie_ops {
|
||||
size_t size);
|
||||
void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
u32 (*read_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void (*write_dbi2)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size, u32 val);
|
||||
int (*link_up)(struct dw_pcie *pcie);
|
||||
@ -263,6 +271,9 @@ struct dw_pcie {
|
||||
struct dw_pcie_ep ep;
|
||||
const struct dw_pcie_ops *ops;
|
||||
unsigned int version;
|
||||
int num_lanes;
|
||||
int link_gen;
|
||||
u8 n_fts[2];
|
||||
};
|
||||
|
||||
#define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)
|
||||
@ -278,20 +289,19 @@ int dw_pcie_write(void __iomem *addr, int size, u32 val);
|
||||
|
||||
u32 dw_pcie_read_dbi(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_dbi(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
u32 dw_pcie_read_dbi2(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
u32 dw_pcie_read_atu(struct dw_pcie *pci, u32 reg, size_t size);
|
||||
void dw_pcie_write_atu(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
|
||||
int dw_pcie_link_up(struct dw_pcie *pci);
|
||||
void dw_pcie_upconfig_setup(struct dw_pcie *pci);
|
||||
void dw_pcie_link_set_max_speed(struct dw_pcie *pci, u32 link_gen);
|
||||
void dw_pcie_link_set_n_fts(struct dw_pcie *pci, u32 n_fts);
|
||||
int dw_pcie_wait_for_link(struct dw_pcie *pci);
|
||||
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int bar,
|
||||
u64 cpu_addr, enum dw_pcie_as_type as_type);
|
||||
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int type, u64 cpu_addr, u64 pci_addr,
|
||||
u32 size);
|
||||
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
|
||||
int bar, u64 cpu_addr,
|
||||
enum dw_pcie_as_type as_type);
|
||||
void dw_pcie_disable_atu(struct dw_pcie *pci, int index,
|
||||
enum dw_pcie_region_type type);
|
||||
void dw_pcie_setup(struct dw_pcie *pci);
|
||||
@ -331,21 +341,6 @@ static inline void dw_pcie_writel_dbi2(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
dw_pcie_write_dbi2(pci, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_dbi2(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return dw_pcie_read_dbi2(pci, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_writel_atu(struct dw_pcie *pci, u32 reg, u32 val)
|
||||
{
|
||||
dw_pcie_write_atu(pci, reg, 0x4, val);
|
||||
}
|
||||
|
||||
static inline u32 dw_pcie_readl_atu(struct dw_pcie *pci, u32 reg)
|
||||
{
|
||||
return dw_pcie_read_atu(pci, reg, 0x4);
|
||||
}
|
||||
|
||||
static inline void dw_pcie_dbi_ro_wr_en(struct dw_pcie *pci)
|
||||
{
|
||||
u32 reg;
|
||||
@ -376,6 +371,8 @@ void dw_pcie_setup_rc(struct pcie_port *pp);
|
||||
int dw_pcie_host_init(struct pcie_port *pp);
|
||||
void dw_pcie_host_deinit(struct pcie_port *pp);
|
||||
int dw_pcie_allocate_domains(struct pcie_port *pp);
|
||||
void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int where);
|
||||
#else
|
||||
static inline irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
||||
{
|
||||
@ -407,6 +404,12 @@ static inline int dw_pcie_allocate_domains(struct pcie_port *pp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIE_DW_EP
|
||||
@ -420,7 +423,11 @@ int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num);
|
||||
int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num);
|
||||
int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u16 interrupt_num);
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
|
||||
struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no);
|
||||
#else
|
||||
static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
{
|
||||
@ -461,8 +468,21 @@ static inline int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_raise_msix_irq_doorbell(struct dw_pcie_ep *ep,
|
||||
u8 func_no,
|
||||
u16 interrupt_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline struct dw_pcie_ep_func *
|
||||
dw_pcie_ep_get_func_from_ep(struct dw_pcie_ep *ep, u8 func_no)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
#endif /* _PCIE_DESIGNWARE_H */
|
||||
|
@ -122,32 +122,37 @@ static void histb_pcie_write_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
histb_pcie_dbi_w_mode(&pci->pp, false);
|
||||
}
|
||||
|
||||
static int histb_pcie_rd_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 *val)
|
||||
static int histb_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
histb_pcie_dbi_r_mode(pp, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
histb_pcie_dbi_r_mode(pp, false);
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ret;
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int histb_pcie_wr_own_conf(struct pcie_port *pp, int where,
|
||||
int size, u32 val)
|
||||
static int histb_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
histb_pcie_dbi_w_mode(pp, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
histb_pcie_dbi_w_mode(pp, false);
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return ret;
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops histb_pci_ops = {
|
||||
.read = histb_pcie_rd_own_conf,
|
||||
.write = histb_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static int histb_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
struct histb_pcie *hipcie = to_histb_pcie(pci);
|
||||
@ -194,17 +199,15 @@ static int histb_pcie_establish_link(struct pcie_port *pp)
|
||||
|
||||
static int histb_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
histb_pcie_establish_link(pp);
|
||||
pp->bridge->ops = &histb_pci_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
histb_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
|
||||
|
@ -67,14 +67,9 @@ struct intel_pcie_port {
|
||||
void __iomem *app_base;
|
||||
struct gpio_desc *reset_gpio;
|
||||
u32 rst_intrvl;
|
||||
u32 max_speed;
|
||||
u32 link_gen;
|
||||
u32 max_width;
|
||||
u32 n_fts;
|
||||
struct clk *core_clk;
|
||||
struct reset_control *core_rst;
|
||||
struct phy *phy;
|
||||
u8 pcie_cap_ofst;
|
||||
};
|
||||
|
||||
static void pcie_update_bits(void __iomem *base, u32 ofs, u32 mask, u32 val)
|
||||
@ -134,11 +129,7 @@ static void intel_pcie_ltssm_disable(struct intel_pcie_port *lpp)
|
||||
static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 val;
|
||||
u8 offset = lpp->pcie_cap_ofst;
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCAP);
|
||||
lpp->max_speed = FIELD_GET(PCI_EXP_LNKCAP_SLS, val);
|
||||
lpp->max_width = FIELD_GET(PCI_EXP_LNKCAP_MLW, val);
|
||||
u8 offset = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
|
||||
|
||||
val = pcie_rc_cfg_rd(lpp, offset + PCI_EXP_LNKCTL);
|
||||
|
||||
@ -146,41 +137,29 @@ static void intel_pcie_link_setup(struct intel_pcie_port *lpp)
|
||||
pcie_rc_cfg_wr(lpp, offset + PCI_EXP_LNKCTL, val);
|
||||
}
|
||||
|
||||
static void intel_pcie_port_logic_setup(struct intel_pcie_port *lpp)
|
||||
static void intel_pcie_init_n_fts(struct dw_pcie *pci)
|
||||
{
|
||||
u32 val, mask;
|
||||
|
||||
switch (pcie_link_speed[lpp->max_speed]) {
|
||||
case PCIE_SPEED_8_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN3;
|
||||
switch (pci->link_gen) {
|
||||
case 3:
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN3;
|
||||
break;
|
||||
case PCIE_SPEED_16_0GT:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN4;
|
||||
case 4:
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN4;
|
||||
break;
|
||||
default:
|
||||
lpp->n_fts = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
pci->n_fts[1] = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
break;
|
||||
}
|
||||
|
||||
mask = PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK;
|
||||
val = FIELD_PREP(PORT_AFR_N_FTS_MASK, lpp->n_fts) |
|
||||
FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, lpp->n_fts);
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_AFR, mask, val);
|
||||
|
||||
/* Port Link Control Register */
|
||||
pcie_rc_cfg_wr_mask(lpp, PCIE_PORT_LINK_CONTROL, PORT_LINK_DLL_LINK_EN,
|
||||
PORT_LINK_DLL_LINK_EN);
|
||||
pci->n_fts[0] = PORT_AFR_N_FTS_GEN12_DFT;
|
||||
}
|
||||
|
||||
static void intel_pcie_rc_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
intel_pcie_ltssm_disable(lpp);
|
||||
intel_pcie_link_setup(lpp);
|
||||
intel_pcie_init_n_fts(&lpp->pci);
|
||||
dw_pcie_setup_rc(&lpp->pci.pp);
|
||||
dw_pcie_upconfig_setup(&lpp->pci);
|
||||
intel_pcie_port_logic_setup(lpp);
|
||||
dw_pcie_link_set_max_speed(&lpp->pci, lpp->link_gen);
|
||||
dw_pcie_link_set_n_fts(&lpp->pci, lpp->n_fts);
|
||||
}
|
||||
|
||||
static int intel_pcie_ep_rst_init(struct intel_pcie_port *lpp)
|
||||
@ -275,20 +254,11 @@ static int intel_pcie_get_resources(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_match_string(dev, "device_type", "pci");
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to find pci device type: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = device_property_read_u32(dev, "reset-assert-ms",
|
||||
&lpp->rst_intrvl);
|
||||
if (ret)
|
||||
lpp->rst_intrvl = RESET_INTERVAL_MS;
|
||||
|
||||
ret = of_pci_get_max_link_speed(dev->of_node);
|
||||
lpp->link_gen = ret < 0 ? 0 : ret;
|
||||
|
||||
lpp->app_base = devm_platform_ioremap_resource_byname(pdev, "app");
|
||||
if (IS_ERR(lpp->app_base))
|
||||
return PTR_ERR(lpp->app_base);
|
||||
@ -313,8 +283,9 @@ static int intel_pcie_wait_l2(struct intel_pcie_port *lpp)
|
||||
{
|
||||
u32 value;
|
||||
int ret;
|
||||
struct dw_pcie *pci = &lpp->pci;
|
||||
|
||||
if (pcie_link_speed[lpp->max_speed] < PCIE_SPEED_8_0GT)
|
||||
if (pci->link_gen < 3)
|
||||
return 0;
|
||||
|
||||
/* Send PME_TURN_OFF message */
|
||||
@ -343,7 +314,6 @@ static void intel_pcie_turn_off(struct intel_pcie_port *lpp)
|
||||
|
||||
static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
{
|
||||
struct device *dev = lpp->pci.dev;
|
||||
int ret;
|
||||
|
||||
intel_pcie_core_rst_assert(lpp);
|
||||
@ -361,17 +331,6 @@ static int intel_pcie_host_setup(struct intel_pcie_port *lpp)
|
||||
goto clk_err;
|
||||
}
|
||||
|
||||
if (!lpp->pcie_cap_ofst) {
|
||||
ret = dw_pcie_find_capability(&lpp->pci, PCI_CAP_ID_EXP);
|
||||
if (!ret) {
|
||||
ret = -ENXIO;
|
||||
dev_err(dev, "Invalid PCIe capability offset\n");
|
||||
goto app_init_err;
|
||||
}
|
||||
|
||||
lpp->pcie_cap_ofst = ret;
|
||||
}
|
||||
|
||||
intel_pcie_rc_setup(lpp);
|
||||
ret = intel_pcie_app_logic_setup(lpp);
|
||||
if (ret)
|
||||
|
@ -330,34 +330,37 @@ static void kirin_pcie_sideband_dbi_r_mode(struct kirin_pcie *kirin_pcie,
|
||||
kirin_apb_ctrl_writel(kirin_pcie, val, SOC_PCIECTRL_CTRL1_ADDR);
|
||||
}
|
||||
|
||||
static int kirin_pcie_rd_own_conf(struct pcie_port *pp,
|
||||
static int kirin_pcie_rd_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
kirin_pcie_sideband_dbi_r_mode(kirin_pcie, true);
|
||||
ret = dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
kirin_pcie_sideband_dbi_r_mode(kirin_pcie, false);
|
||||
if (PCI_SLOT(devfn)) {
|
||||
*val = ~0;
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
}
|
||||
|
||||
return ret;
|
||||
*val = dw_pcie_read_dbi(pci, where, size);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static int kirin_pcie_wr_own_conf(struct pcie_port *pp,
|
||||
static int kirin_pcie_wr_own_conf(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct kirin_pcie *kirin_pcie = to_kirin_pcie(pci);
|
||||
int ret;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(bus->sysdata);
|
||||
|
||||
kirin_pcie_sideband_dbi_w_mode(kirin_pcie, true);
|
||||
ret = dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
kirin_pcie_sideband_dbi_w_mode(kirin_pcie, false);
|
||||
if (PCI_SLOT(devfn))
|
||||
return PCIBIOS_DEVICE_NOT_FOUND;
|
||||
|
||||
return ret;
|
||||
dw_pcie_write_dbi(pci, where, size, val);
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
static struct pci_ops kirin_pci_ops = {
|
||||
.read = kirin_pcie_rd_own_conf,
|
||||
.write = kirin_pcie_wr_own_conf,
|
||||
};
|
||||
|
||||
static u32 kirin_pcie_read_dbi(struct dw_pcie *pci, void __iomem *base,
|
||||
u32 reg, size_t size)
|
||||
{
|
||||
@ -423,10 +426,10 @@ static int kirin_pcie_establish_link(struct pcie_port *pp)
|
||||
|
||||
static int kirin_pcie_host_init(struct pcie_port *pp)
|
||||
{
|
||||
kirin_pcie_establish_link(pp);
|
||||
pp->bridge->ops = &kirin_pci_ops;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
kirin_pcie_establish_link(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -438,8 +441,6 @@ static const struct dw_pcie_ops kirin_dw_pcie_ops = {
|
||||
};
|
||||
|
||||
static const struct dw_pcie_host_ops kirin_pcie_host_ops = {
|
||||
.rd_own_conf = kirin_pcie_rd_own_conf,
|
||||
.wr_own_conf = kirin_pcie_wr_own_conf,
|
||||
.host_init = kirin_pcie_host_init,
|
||||
};
|
||||
|
||||
|
@ -67,10 +67,6 @@
|
||||
#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c
|
||||
#define CFG_BRIDGE_SB_INIT BIT(0)
|
||||
|
||||
#define PCIE20_CAP 0x70
|
||||
#define PCIE20_DEVICE_CONTROL2_STATUS2 (PCIE20_CAP + PCI_EXP_DEVCTL2)
|
||||
#define PCIE20_CAP_LINK_CAPABILITIES (PCIE20_CAP + PCI_EXP_LNKCAP)
|
||||
#define PCIE20_CAP_LINK_1 (PCIE20_CAP + 0x14)
|
||||
#define PCIE_CAP_LINK1_VAL 0x2FD7F
|
||||
|
||||
#define PCIE20_PARF_Q2A_FLUSH 0x1AC
|
||||
@ -193,7 +189,6 @@ struct qcom_pcie {
|
||||
struct phy *phy;
|
||||
struct gpio_desc *reset;
|
||||
const struct qcom_pcie_ops *ops;
|
||||
int gen;
|
||||
};
|
||||
|
||||
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
|
||||
@ -394,12 +389,6 @@ static int qcom_pcie_init_2_1_0(struct qcom_pcie *pcie)
|
||||
/* wait for clock acquisition */
|
||||
usleep_range(1000, 1500);
|
||||
|
||||
if (pcie->gen == 1) {
|
||||
val = readl(pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
|
||||
val |= PCI_EXP_LNKSTA_CLS_2_5GB;
|
||||
writel(val, pci->dbi_base + PCIE20_LNK_CONTROL2_LINK_STATUS2);
|
||||
}
|
||||
|
||||
/* Set the Max TLP size to 2K, instead of using default of 4K */
|
||||
writel(CFG_REMOTE_RD_REQ_BRIDGE_SIZE_2K,
|
||||
pci->dbi_base + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
|
||||
@ -1017,6 +1006,7 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
|
||||
struct qcom_pcie_resources_2_3_3 *res = &pcie->res.v2_3_3;
|
||||
struct dw_pcie *pci = pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
int i, ret;
|
||||
u32 val;
|
||||
|
||||
@ -1092,14 +1082,14 @@ static int qcom_pcie_init_2_3_3(struct qcom_pcie *pcie)
|
||||
|
||||
writel(PCI_COMMAND_MASTER, pci->dbi_base + PCI_COMMAND);
|
||||
writel(DBI_RO_WR_EN, pci->dbi_base + PCIE20_MISC_CONTROL_1_REG);
|
||||
writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + PCIE20_CAP_LINK_1);
|
||||
writel(PCIE_CAP_LINK1_VAL, pci->dbi_base + offset + PCI_EXP_SLTCAP);
|
||||
|
||||
val = readl(pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
val = readl(pci->dbi_base + offset + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_ASPMS;
|
||||
writel(val, pci->dbi_base + PCIE20_CAP_LINK_CAPABILITIES);
|
||||
writel(val, pci->dbi_base + offset + PCI_EXP_LNKCAP);
|
||||
|
||||
writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base +
|
||||
PCIE20_DEVICE_CONTROL2_STATUS2);
|
||||
writel(PCI_EXP_DEVCTL2_COMP_TMOUT_DIS, pci->dbi_base + offset +
|
||||
PCI_EXP_DEVCTL2);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1252,7 +1242,8 @@ static void qcom_pcie_post_deinit_2_7_0(struct qcom_pcie *pcie)
|
||||
|
||||
static int qcom_pcie_link_up(struct dw_pcie *pci)
|
||||
{
|
||||
u16 val = readw(pci->dbi_base + PCIE20_CAP + PCI_EXP_LNKSTA);
|
||||
u16 offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
u16 val = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
|
||||
|
||||
return !!(val & PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
@ -1280,9 +1271,7 @@ static int qcom_pcie_host_init(struct pcie_port *pp)
|
||||
}
|
||||
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
qcom_ep_reset_deassert(pcie);
|
||||
|
||||
@ -1399,10 +1388,6 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
goto err_pm_runtime_put;
|
||||
}
|
||||
|
||||
pcie->gen = of_pci_get_max_link_speed(pdev->dev.of_node);
|
||||
if (pcie->gen < 0)
|
||||
pcie->gen = 2;
|
||||
|
||||
pcie->parf = devm_platform_ioremap_resource_byname(pdev, "parf");
|
||||
if (IS_ERR(pcie->parf)) {
|
||||
ret = PTR_ERR(pcie->parf);
|
||||
|
@ -26,7 +26,6 @@ struct spear13xx_pcie {
|
||||
void __iomem *app_base;
|
||||
struct phy *phy;
|
||||
struct clk *clk;
|
||||
bool is_gen1;
|
||||
};
|
||||
|
||||
struct pcie_app_reg {
|
||||
@ -65,8 +64,6 @@ struct pcie_app_reg {
|
||||
/* CR6 */
|
||||
#define MSI_CTRL_INT (1 << 26)
|
||||
|
||||
#define EXP_CAP_ID_OFFSET 0x70
|
||||
|
||||
#define to_spear13xx_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
@ -75,7 +72,7 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct pcie_app_reg *app_reg = spear13xx_pcie->app_base;
|
||||
u32 val;
|
||||
u32 exp_cap_off = EXP_CAP_ID_OFFSET;
|
||||
u32 exp_cap_off = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(pci->dev, "link already up\n");
|
||||
@ -89,36 +86,12 @@ static int spear13xx_pcie_establish_link(struct spear13xx_pcie *spear13xx_pcie)
|
||||
* default value in capability register is 512 bytes. So force
|
||||
* it to 128 here.
|
||||
*/
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, &val);
|
||||
val = dw_pcie_readw_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL);
|
||||
val &= ~PCI_EXP_DEVCTL_READRQ;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off + PCI_EXP_DEVCTL, 2, val);
|
||||
dw_pcie_writew_dbi(pci, exp_cap_off + PCI_EXP_DEVCTL, val);
|
||||
|
||||
dw_pcie_write(pci->dbi_base + PCI_VENDOR_ID, 2, 0x104A);
|
||||
dw_pcie_write(pci->dbi_base + PCI_DEVICE_ID, 2, 0xCD80);
|
||||
|
||||
/*
|
||||
* if is_gen1 is set then handle it, so that some buggy card
|
||||
* also works
|
||||
*/
|
||||
if (spear13xx_pcie->is_gen1) {
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCAP,
|
||||
4, &val);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCAP, 4, val);
|
||||
}
|
||||
|
||||
dw_pcie_read(pci->dbi_base + exp_cap_off + PCI_EXP_LNKCTL2,
|
||||
2, &val);
|
||||
if ((val & PCI_EXP_LNKCAP_SLS) != PCI_EXP_LNKCAP_SLS_2_5GB) {
|
||||
val &= ~((u32)PCI_EXP_LNKCAP_SLS);
|
||||
val |= PCI_EXP_LNKCAP_SLS_2_5GB;
|
||||
dw_pcie_write(pci->dbi_base + exp_cap_off +
|
||||
PCI_EXP_LNKCTL2, 2, val);
|
||||
}
|
||||
}
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, 0x104A);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, 0xCD80);
|
||||
|
||||
/* enable ltssm */
|
||||
writel(DEVICE_TYPE_RC | (1 << MISCTRL_EN_ID)
|
||||
@ -278,7 +251,7 @@ static int spear13xx_pcie_probe(struct platform_device *pdev)
|
||||
spear13xx_pcie->app_base = pci->dbi_base + 0x2000;
|
||||
|
||||
if (of_property_read_bool(np, "st,pcie-is-gen1"))
|
||||
spear13xx_pcie->is_gen1 = true;
|
||||
pci->link_gen = 1;
|
||||
|
||||
platform_set_drvdata(pdev, spear13xx_pcie);
|
||||
|
||||
|
@ -183,19 +183,7 @@
|
||||
#define EVENT_COUNTER_GROUP_SEL_SHIFT 24
|
||||
#define EVENT_COUNTER_GROUP_5 0x5
|
||||
|
||||
#define PORT_LOGIC_ACK_F_ASPM_CTRL 0x70C
|
||||
#define ENTER_ASPM BIT(30)
|
||||
#define L0S_ENTRANCE_LAT_SHIFT 24
|
||||
#define L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)
|
||||
#define L1_ENTRANCE_LAT_SHIFT 27
|
||||
#define L1_ENTRANCE_LAT_MASK GENMASK(29, 27)
|
||||
#define N_FTS_SHIFT 8
|
||||
#define N_FTS_MASK GENMASK(7, 0)
|
||||
#define N_FTS_VAL 52
|
||||
|
||||
#define PORT_LOGIC_GEN2_CTRL 0x80C
|
||||
#define PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE BIT(17)
|
||||
#define FTS_MASK GENMASK(7, 0)
|
||||
#define FTS_VAL 52
|
||||
|
||||
#define PORT_LOGIC_MSI_CTRL_INT_0_EN 0x828
|
||||
@ -296,7 +284,6 @@ struct tegra_pcie_dw {
|
||||
u8 init_link_width;
|
||||
u32 msi_ctrl_int;
|
||||
u32 num_lanes;
|
||||
u32 max_speed;
|
||||
u32 cid;
|
||||
u32 cfg_link_cap_l1sub;
|
||||
u32 pcie_cap_base;
|
||||
@ -401,9 +388,9 @@ static irqreturn_t tegra_pcie_rp_irq_handler(int irq, void *arg)
|
||||
val |= APPL_CAR_RESET_OVRD_CYA_OVERRIDE_CORE_RST_N;
|
||||
appl_writel(pcie, val, APPL_CAR_RESET_OVRD);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val |= PORT_LOGIC_GEN2_CTRL_DIRECT_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -568,42 +555,44 @@ static irqreturn_t tegra_pcie_ep_hard_irq(int irq, void *arg)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_rd_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 *val)
|
||||
static int tegra_pcie_dw_rd_own_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 *val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* This is an endpoint mode specific register happen to appear even
|
||||
* when controller is operating in root port mode and system hangs
|
||||
* when it is accessed with link being in ASPM-L1 state.
|
||||
* So skip accessing it altogether
|
||||
*/
|
||||
if (where == PORT_LOGIC_MSIX_DOORBELL) {
|
||||
if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL) {
|
||||
*val = 0x00000000;
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
return dw_pcie_read(pci->dbi_base + where, size, val);
|
||||
return pci_generic_config_read(bus, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static int tegra_pcie_dw_wr_own_conf(struct pcie_port *pp, int where, int size,
|
||||
u32 val)
|
||||
static int tegra_pcie_dw_wr_own_conf(struct pci_bus *bus, u32 devfn, int where,
|
||||
int size, u32 val)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
/*
|
||||
* This is an endpoint mode specific register happen to appear even
|
||||
* when controller is operating in root port mode and system hangs
|
||||
* when it is accessed with link being in ASPM-L1 state.
|
||||
* So skip accessing it altogether
|
||||
*/
|
||||
if (where == PORT_LOGIC_MSIX_DOORBELL)
|
||||
if (!PCI_SLOT(devfn) && where == PORT_LOGIC_MSIX_DOORBELL)
|
||||
return PCIBIOS_SUCCESSFUL;
|
||||
|
||||
return dw_pcie_write(pci->dbi_base + where, size, val);
|
||||
return pci_generic_config_write(bus, devfn, where, size, val);
|
||||
}
|
||||
|
||||
static struct pci_ops tegra_pci_ops = {
|
||||
.map_bus = dw_pcie_own_conf_map_bus,
|
||||
.read = tegra_pcie_dw_rd_own_conf,
|
||||
.write = tegra_pcie_dw_wr_own_conf,
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PCIEASPM)
|
||||
static void disable_aspm_l11(struct tegra_pcie_dw *pcie)
|
||||
{
|
||||
@ -692,11 +681,11 @@ static void init_host_aspm(struct tegra_pcie_dw *pcie)
|
||||
dw_pcie_writel_dbi(pci, pcie->cfg_link_cap_l1sub, val);
|
||||
|
||||
/* Program L0s and L1 entrance latencies */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~L0S_ENTRANCE_LAT_MASK;
|
||||
val |= (pcie->aspm_l0s_enter_lat << L0S_ENTRANCE_LAT_SHIFT);
|
||||
val |= ENTER_ASPM;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
|
||||
val &= ~PORT_AFR_L0S_ENTRANCE_LAT_MASK;
|
||||
val |= (pcie->aspm_l0s_enter_lat << PORT_AFR_L0S_ENTRANCE_LAT_SHIFT);
|
||||
val |= PORT_AFR_ENTER_ASPM;
|
||||
dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
|
||||
}
|
||||
|
||||
static int init_debugfs(struct tegra_pcie_dw *pcie)
|
||||
@ -827,26 +816,24 @@ static void config_gen3_gen4_eq_presets(struct tegra_pcie_dw *pcie)
|
||||
|
||||
/* Program init preset */
|
||||
for (i = 0; i < pcie->num_lanes; i++) {
|
||||
dw_pcie_read(pci->dbi_base + CAP_SPCIE_CAP_OFF
|
||||
+ (i * 2), 2, &val);
|
||||
val = dw_pcie_readw_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2));
|
||||
val &= ~CAP_SPCIE_CAP_OFF_DSP_TX_PRESET0_MASK;
|
||||
val |= GEN3_GEN4_EQ_PRESET_INIT;
|
||||
val &= ~CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_MASK;
|
||||
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
|
||||
CAP_SPCIE_CAP_OFF_USP_TX_PRESET0_SHIFT);
|
||||
dw_pcie_write(pci->dbi_base + CAP_SPCIE_CAP_OFF
|
||||
+ (i * 2), 2, val);
|
||||
dw_pcie_writew_dbi(pci, CAP_SPCIE_CAP_OFF + (i * 2), val);
|
||||
|
||||
offset = dw_pcie_find_ext_capability(pci,
|
||||
PCI_EXT_CAP_ID_PL_16GT) +
|
||||
PCI_PL_16GT_LE_CTRL;
|
||||
dw_pcie_read(pci->dbi_base + offset + i, 1, &val);
|
||||
val = dw_pcie_readb_dbi(pci, offset + i);
|
||||
val &= ~PCI_PL_16GT_LE_CTRL_DSP_TX_PRESET_MASK;
|
||||
val |= GEN3_GEN4_EQ_PRESET_INIT;
|
||||
val &= ~PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_MASK;
|
||||
val |= (GEN3_GEN4_EQ_PRESET_INIT <<
|
||||
PCI_PL_16GT_LE_CTRL_USP_TX_PRESET_SHIFT);
|
||||
dw_pcie_write(pci->dbi_base + offset + i, 1, val);
|
||||
dw_pcie_writeb_dbi(pci, offset + i, val);
|
||||
}
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, GEN3_RELATED_OFF);
|
||||
@ -892,17 +879,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
|
||||
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
|
||||
|
||||
/* Configure FTS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~(N_FTS_MASK << N_FTS_SHIFT);
|
||||
val |= N_FTS_VAL << N_FTS_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val &= ~FTS_MASK;
|
||||
val |= FTS_VAL;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
|
||||
/* Enable as 0xFFFF0001 response for CRS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT);
|
||||
val &= ~(AMBA_ERROR_RESPONSE_CRS_MASK << AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
@ -910,16 +886,6 @@ static void tegra_pcie_prepare_host(struct pcie_port *pp)
|
||||
AMBA_ERROR_RESPONSE_CRS_SHIFT);
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_AMBA_ERROR_RESPONSE_DEFAULT, val);
|
||||
|
||||
/* Configure Max Speed from DT */
|
||||
if (pcie->max_speed && pcie->max_speed != -EINVAL) {
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_SLS;
|
||||
val |= pcie->max_speed;
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
/* Configure Max lane width from DT */
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_MLW;
|
||||
@ -970,6 +936,8 @@ static int tegra_pcie_dw_host_init(struct pcie_port *pp)
|
||||
struct tegra_pcie_dw *pcie = to_tegra_pcie(pci);
|
||||
u32 val, tmp, offset, speed;
|
||||
|
||||
pp->bridge->ops = &tegra_pci_ops;
|
||||
|
||||
tegra_pcie_prepare_host(pp);
|
||||
|
||||
if (dw_pcie_wait_for_link(pci)) {
|
||||
@ -1057,8 +1025,6 @@ static const struct dw_pcie_ops tegra_dw_pcie_ops = {
|
||||
};
|
||||
|
||||
static struct dw_pcie_host_ops tegra_pcie_dw_host_ops = {
|
||||
.rd_own_conf = tegra_pcie_dw_rd_own_conf,
|
||||
.wr_own_conf = tegra_pcie_dw_wr_own_conf,
|
||||
.host_init = tegra_pcie_dw_host_init,
|
||||
.set_num_vectors = tegra_pcie_set_msi_vec_num,
|
||||
};
|
||||
@ -1129,8 +1095,6 @@ static int tegra_pcie_dw_parse_dt(struct tegra_pcie_dw *pcie)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcie->max_speed = of_pci_get_max_link_speed(np);
|
||||
|
||||
ret = of_property_read_u32_index(np, "nvidia,bpmp", 1, &pcie->cid);
|
||||
if (ret) {
|
||||
dev_err(pcie->dev, "Failed to read Controller-ID: %d\n", ret);
|
||||
@ -1262,9 +1226,9 @@ static void tegra_pcie_downstream_dev_to_D0(struct tegra_pcie_dw *pcie)
|
||||
* 5.2 Link State Power Management (Page #428).
|
||||
*/
|
||||
|
||||
list_for_each_entry(child, &pp->root_bus->children, node) {
|
||||
list_for_each_entry(child, &pp->bridge->bus->children, node) {
|
||||
/* Bring downstream devices to D0 if they are not already in */
|
||||
if (child->parent == pp->root_bus) {
|
||||
if (child->parent == pp->bridge->bus) {
|
||||
root_bus = child;
|
||||
break;
|
||||
}
|
||||
@ -1817,27 +1781,6 @@ static void pex_ep_event_pex_rst_deassert(struct tegra_pcie_dw *pcie)
|
||||
val &= ~GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL;
|
||||
dw_pcie_writel_dbi(pci, GEN3_RELATED_OFF, val);
|
||||
|
||||
/* Configure N_FTS & FTS */
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL);
|
||||
val &= ~(N_FTS_MASK << N_FTS_SHIFT);
|
||||
val |= N_FTS_VAL << N_FTS_SHIFT;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_ACK_F_ASPM_CTRL, val);
|
||||
|
||||
val = dw_pcie_readl_dbi(pci, PORT_LOGIC_GEN2_CTRL);
|
||||
val &= ~FTS_MASK;
|
||||
val |= FTS_VAL;
|
||||
dw_pcie_writel_dbi(pci, PORT_LOGIC_GEN2_CTRL, val);
|
||||
|
||||
/* Configure Max Speed from DT */
|
||||
if (pcie->max_speed && pcie->max_speed != -EINVAL) {
|
||||
val = dw_pcie_readl_dbi(pci, pcie->pcie_cap_base +
|
||||
PCI_EXP_LNKCAP);
|
||||
val &= ~PCI_EXP_LNKCAP_SLS;
|
||||
val |= pcie->max_speed;
|
||||
dw_pcie_writel_dbi(pci, pcie->pcie_cap_base + PCI_EXP_LNKCAP,
|
||||
val);
|
||||
}
|
||||
|
||||
pcie->pcie_cap_base = dw_pcie_find_capability(&pcie->pci,
|
||||
PCI_CAP_ID_EXP);
|
||||
clk_set_rate(pcie->core_clk, GEN4_CORE_CLK_FREQ);
|
||||
@ -2066,6 +2009,9 @@ static int tegra_pcie_dw_probe(struct platform_device *pdev)
|
||||
pci = &pcie->pci;
|
||||
pci->dev = &pdev->dev;
|
||||
pci->ops = &tegra_dw_pcie_ops;
|
||||
pci->n_fts[0] = N_FTS_VAL;
|
||||
pci->n_fts[1] = FTS_VAL;
|
||||
|
||||
pp = &pci->pp;
|
||||
pcie->dev = &pdev->dev;
|
||||
pcie->mode = (enum dw_pcie_device_mode)data->mode;
|
||||
|
@ -322,8 +322,7 @@ static int uniphier_pcie_host_init(struct pcie_port *pp)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI))
|
||||
dw_pcie_msi_init(pp);
|
||||
dw_pcie_msi_init(pp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -941,6 +941,12 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
|
||||
|
||||
pcibios_add_bus(bus);
|
||||
|
||||
if (bus->ops->add_bus) {
|
||||
err = bus->ops->add_bus(bus);
|
||||
if (WARN_ON(err < 0))
|
||||
dev_err(&bus->dev, "failed to add bus: %d\n", err);
|
||||
}
|
||||
|
||||
/* Create legacy_io and legacy_mem files for this bus */
|
||||
pci_create_legacy_files(bus);
|
||||
|
||||
@ -1036,6 +1042,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
struct pci_dev *bridge, int busnr)
|
||||
{
|
||||
struct pci_bus *child;
|
||||
struct pci_host_bridge *host;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
@ -1045,11 +1052,16 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
|
||||
return NULL;
|
||||
|
||||
child->parent = parent;
|
||||
child->ops = parent->ops;
|
||||
child->msi = parent->msi;
|
||||
child->sysdata = parent->sysdata;
|
||||
child->bus_flags = parent->bus_flags;
|
||||
|
||||
host = pci_find_host_bridge(parent);
|
||||
if (host->child_ops)
|
||||
child->ops = host->child_ops;
|
||||
else
|
||||
child->ops = parent->ops;
|
||||
|
||||
/*
|
||||
* Initialize some portions of the bus device, but don't register
|
||||
* it now as the parent is not properly set up yet.
|
||||
|
@ -524,6 +524,7 @@ struct pci_host_bridge {
|
||||
struct device dev;
|
||||
struct pci_bus *bus; /* Root bus */
|
||||
struct pci_ops *ops;
|
||||
struct pci_ops *child_ops;
|
||||
void *sysdata;
|
||||
int busnr;
|
||||
struct list_head windows; /* resource_entry */
|
||||
|
@ -76,6 +76,7 @@
|
||||
#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
|
||||
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
|
||||
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
|
||||
#define PCI_HEADER_TYPE_MASK 0x7f
|
||||
#define PCI_HEADER_TYPE_NORMAL 0
|
||||
#define PCI_HEADER_TYPE_BRIDGE 1
|
||||
#define PCI_HEADER_TYPE_CARDBUS 2
|
||||
|
Loading…
Reference in New Issue
Block a user