Merge branch 'remotes/lorenzo/pci/dwc'
- Add dra72x/dra74x/dra76x SoC compatible strings (Kishon Vijay Abraham I) - Enable x2 mode support for dra72x/dra74x/dra76x SoC (Kishon Vijay Abraham I) - Configure dra7xx PHY to PCIe mode (Kishon Vijay Abraham I) - Simplify dwc (remove unnecessary header includes, name variables consistently, reduce inverted logic, etc) (Gustavo Pimentel) - Add i.MX8MQ support (Andrey Smirnov) - Add message to help debug dwc MSI-X mask bit errors (Gustavo Pimentel) - Work around imx7d PCIe PLL erratum (Trent Piepho) - Don't assert qcom reset GPIO during probe (Bjorn Andersson) - Skip dwc MSI init if MSIs have been disabled (Lucas Stach) * remotes/lorenzo/pci/dwc: PCI: dwc: skip MSI init if MSIs have been explicitly disabled PCI: dwc: Remove superfluous shifting in definitions PCI: dwc: Make use of GENMASK/FIELD_PREP PCI: dwc: Make use of BIT() in constant definitions PCI: dwc: Share code for dw_pcie_rd/wr_other_conf() PCI: dwc: Make use of IS_ALIGNED() PCI: imx6: Add code to request/control "pcie_aux" clock for i.MX8MQ dt-bindings: imx6q-pcie: Add "pcie_aux" clock for imx8mq PCI: qcom: Don't deassert reset GPIO during probe PCI: imx: Add workaround for e10728, IMX7d PCIe PLL failure ARM: dts: imx7d: Add node for PCIe PHY dt-bindings: imx6q-pcie: Add description of imx7d pcie phy PCI: dwc: Print debug error message when MSI-X entry control mask bit is set PCI: imx6: Add support for i.MX8MQ PCI: imx6: Convert DIRECT_SPEED_CHANGE quirk code to use a flag PCI: imx6: Mark PHY functions as i.MX6 specific PCI: imx6: Introduce drvdata PCI: dwc: Replace bit rotation operation (1 << bit) with BIT(bit) PCI: dwc: Improve code readability and simplify mask/unmask operations PCI: dwc: Rename variable name from data to d on dw_pcie_irq_domain_free() PCI: dwc: Rename variable name from data to d on dw_pci_msi_set_affinity() PCI: dwc: Rename variable name from data to d on dw_pci_setup_msi_msg() PCI: dwc: Rename variable name from data to d on dw_pci_bottom_mask/unmask() PCI: dwc: Remove unnecessary header include (signal.h) PCI: dwc: Remove unnecessary header include (of_gpio.h) PCI: dwc: dra7xx: Invoke phy_set_mode() API to set PHY mode to PHY_MODE_PCIE PCI: dwc: dra7xx: Enable x2 mode support for dra74x, dra76x and dra72x dt-bindings: PCI: dra7xx: Add properties to enable x2 lane in dra7 dt-bindings: PCI: dra7xx: Add SoC specific compatible strings
This commit is contained in:
commit
2506419e06
@ -9,6 +9,7 @@ Required properties:
|
||||
- "fsl,imx6sx-pcie",
|
||||
- "fsl,imx6qp-pcie"
|
||||
- "fsl,imx7d-pcie"
|
||||
- "fsl,imx8mq-pcie"
|
||||
- reg: base address and length of the PCIe controller
|
||||
- interrupts: A list of interrupt outputs of the controller. Must contain an
|
||||
entry for each entry in the interrupt-names property.
|
||||
@ -45,7 +46,7 @@ Additional required properties for imx6sx-pcie:
|
||||
PCIE_PHY power domains
|
||||
- power-domain-names: Must be "pcie", "pcie_phy"
|
||||
|
||||
Additional required properties for imx7d-pcie:
|
||||
Additional required properties for imx7d-pcie and imx8mq-pcie:
|
||||
- power-domains: Must be set to a phandle pointing to PCIE_PHY power domain
|
||||
- resets: Must contain phandles to PCIe-related reset lines exposed by SRC
|
||||
IP block
|
||||
@ -53,6 +54,11 @@ Additional required properties for imx7d-pcie:
|
||||
- "pciephy"
|
||||
- "apps"
|
||||
- "turnoff"
|
||||
- fsl,imx7d-pcie-phy: A phandle to an fsl,imx7d-pcie-phy node.
|
||||
|
||||
Additional required properties for imx8mq-pcie:
|
||||
- clock-names: Must include the following additional entries:
|
||||
- "pcie_aux"
|
||||
|
||||
Example:
|
||||
|
||||
@ -79,3 +85,13 @@ Example:
|
||||
clocks = <&clks 144>, <&clks 206>, <&clks 189>;
|
||||
clock-names = "pcie", "pcie_bus", "pcie_phy";
|
||||
};
|
||||
|
||||
* Freescale i.MX7d PCIe PHY
|
||||
|
||||
This is the PHY associated with the IMX7d PCIe controller. It's used by the
|
||||
PCI-e controller via the fsl,imx7d-pcie-phy phandle.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
- "fsl,imx7d-pcie-phy"
|
||||
- reg: base address and length of the PCIe PHY controller
|
||||
|
@ -1,14 +1,21 @@
|
||||
TI PCI Controllers
|
||||
|
||||
PCIe DesignWare Controller
|
||||
- compatible: Should be "ti,dra7-pcie" for RC
|
||||
Should be "ti,dra7-pcie-ep" for EP
|
||||
- compatible: Should be "ti,dra7-pcie" for RC (deprecated)
|
||||
Should be "ti,dra7-pcie-ep" for EP (deprecated)
|
||||
Should be "ti,dra746-pcie-rc" for dra74x/dra76 in RC mode
|
||||
Should be "ti,dra746-pcie-ep" for dra74x/dra76 in EP mode
|
||||
Should be "ti,dra726-pcie-rc" for dra72x in RC mode
|
||||
Should be "ti,dra726-pcie-ep" for dra72x in EP mode
|
||||
- phys : list of PHY specifiers (used by generic PHY framework)
|
||||
- phy-names : must be "pcie-phy0", "pcie-phy1", "pcie-phyN".. based on the
|
||||
number of PHYs as specified in *phys* property.
|
||||
- ti,hwmods : Name of the hwmod associated to the pcie, "pcie<X>",
|
||||
where <X> is the instance number of the pcie from the HW spec.
|
||||
- num-lanes as specified in ../designware-pcie.txt
|
||||
- ti,syscon-lane-sel : phandle/offset pair. Phandle to the system control
|
||||
module and the register offset to specify lane
|
||||
selection.
|
||||
|
||||
HOST MODE
|
||||
=========
|
||||
|
@ -96,6 +96,14 @@ intc: interrupt-controller@31001000 {
|
||||
};
|
||||
};
|
||||
|
||||
&aips2 {
|
||||
pcie_phy: pcie-phy@306d0000 {
|
||||
compatible = "fsl,imx7d-pcie-phy";
|
||||
reg = <0x306d0000 0x10000>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
||||
&aips3 {
|
||||
usbotg2: usb@30b20000 {
|
||||
compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
|
||||
@ -173,6 +181,7 @@ pcie: pcie@33800000 {
|
||||
<&src IMX7_RESET_PCIE_CTRL_APPS_EN>,
|
||||
<&src IMX7_RESET_PCIE_CTRL_APPS_TURNOFF>;
|
||||
reset-names = "pciephy", "apps", "turnoff";
|
||||
fsl,imx7d-pcie-phy = <&pcie_phy>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
@ -89,8 +89,8 @@ config PCI_EXYNOS
|
||||
select PCIE_DW_HOST
|
||||
|
||||
config PCI_IMX6
|
||||
bool "Freescale i.MX6/7 PCIe controller"
|
||||
depends on SOC_IMX6Q || SOC_IMX7D || (ARM && COMPILE_TEST)
|
||||
bool "Freescale i.MX6/7/8 PCIe controller"
|
||||
depends on SOC_IMX6Q || SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
select PCIE_DW_HOST
|
||||
|
||||
|
@ -81,6 +81,10 @@
|
||||
#define MSI_REQ_GRANT BIT(0)
|
||||
#define MSI_VECTOR_SHIFT 7
|
||||
|
||||
#define PCIE_1LANE_2LANE_SELECTION BIT(13)
|
||||
#define PCIE_B1C0_MODE_SEL BIT(2)
|
||||
#define PCIE_B0_B1_TSYNCEN BIT(0)
|
||||
|
||||
struct dra7xx_pcie {
|
||||
struct dw_pcie *pci;
|
||||
void __iomem *base; /* DT ti_conf */
|
||||
@ -93,6 +97,7 @@ struct dra7xx_pcie {
|
||||
|
||||
struct dra7xx_pcie_of_data {
|
||||
enum dw_pcie_device_mode mode;
|
||||
u32 b1co_mode_sel_mask;
|
||||
};
|
||||
|
||||
#define to_dra7xx_pcie(x) dev_get_drvdata((x)->dev)
|
||||
@ -499,6 +504,10 @@ static int dra7xx_pcie_enable_phy(struct dra7xx_pcie *dra7xx)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < phy_count; i++) {
|
||||
ret = phy_set_mode(dra7xx->phy[i], PHY_MODE_PCIE);
|
||||
if (ret < 0)
|
||||
goto err_phy;
|
||||
|
||||
ret = phy_init(dra7xx->phy[i]);
|
||||
if (ret < 0)
|
||||
goto err_phy;
|
||||
@ -529,6 +538,26 @@ static const struct dra7xx_pcie_of_data dra7xx_pcie_ep_of_data = {
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct dra7xx_pcie_of_data dra746_pcie_rc_of_data = {
|
||||
.b1co_mode_sel_mask = BIT(2),
|
||||
.mode = DW_PCIE_RC_TYPE,
|
||||
};
|
||||
|
||||
static const struct dra7xx_pcie_of_data dra726_pcie_rc_of_data = {
|
||||
.b1co_mode_sel_mask = GENMASK(3, 2),
|
||||
.mode = DW_PCIE_RC_TYPE,
|
||||
};
|
||||
|
||||
static const struct dra7xx_pcie_of_data dra746_pcie_ep_of_data = {
|
||||
.b1co_mode_sel_mask = BIT(2),
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct dra7xx_pcie_of_data dra726_pcie_ep_of_data = {
|
||||
.b1co_mode_sel_mask = GENMASK(3, 2),
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct of_device_id of_dra7xx_pcie_match[] = {
|
||||
{
|
||||
.compatible = "ti,dra7-pcie",
|
||||
@ -538,6 +567,22 @@ static const struct of_device_id of_dra7xx_pcie_match[] = {
|
||||
.compatible = "ti,dra7-pcie-ep",
|
||||
.data = &dra7xx_pcie_ep_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,dra746-pcie-rc",
|
||||
.data = &dra746_pcie_rc_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,dra726-pcie-rc",
|
||||
.data = &dra726_pcie_rc_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,dra746-pcie-ep",
|
||||
.data = &dra746_pcie_ep_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,dra726-pcie-ep",
|
||||
.data = &dra726_pcie_ep_of_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -583,6 +628,34 @@ static int dra7xx_pcie_unaligned_memaccess(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int dra7xx_pcie_configure_two_lane(struct device *dev,
|
||||
u32 b1co_mode_sel_mask)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
struct regmap *pcie_syscon;
|
||||
unsigned int pcie_reg;
|
||||
u32 mask;
|
||||
u32 val;
|
||||
|
||||
pcie_syscon = syscon_regmap_lookup_by_phandle(np, "ti,syscon-lane-sel");
|
||||
if (IS_ERR(pcie_syscon)) {
|
||||
dev_err(dev, "unable to get ti,syscon-lane-sel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (of_property_read_u32_index(np, "ti,syscon-lane-sel", 1,
|
||||
&pcie_reg)) {
|
||||
dev_err(dev, "couldn't get lane selection reg offset\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mask = b1co_mode_sel_mask | PCIE_B0_B1_TSYNCEN;
|
||||
val = PCIE_B1C0_MODE_SEL | PCIE_B0_B1_TSYNCEN;
|
||||
regmap_update_bits(pcie_syscon, pcie_reg, mask, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 reg;
|
||||
@ -603,6 +676,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
const struct of_device_id *match;
|
||||
const struct dra7xx_pcie_of_data *data;
|
||||
enum dw_pcie_device_mode mode;
|
||||
u32 b1co_mode_sel_mask;
|
||||
|
||||
match = of_match_device(of_match_ptr(of_dra7xx_pcie_match), dev);
|
||||
if (!match)
|
||||
@ -610,6 +684,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
data = (struct dra7xx_pcie_of_data *)match->data;
|
||||
mode = (enum dw_pcie_device_mode)data->mode;
|
||||
b1co_mode_sel_mask = data->b1co_mode_sel_mask;
|
||||
|
||||
dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
|
||||
if (!dra7xx)
|
||||
@ -665,6 +740,12 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
||||
dra7xx->pci = pci;
|
||||
dra7xx->phy_count = phy_count;
|
||||
|
||||
if (phy_count == 2) {
|
||||
ret = dra7xx_pcie_configure_two_lane(dev, b1co_mode_sel_mask);
|
||||
if (ret < 0)
|
||||
dra7xx->phy_count = 1; /* Fallback to x1 lane mode */
|
||||
}
|
||||
|
||||
ret = dra7xx_pcie_enable_phy(dra7xx);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to enable phy\n");
|
||||
|
@ -8,6 +8,7 @@
|
||||
* Author: Sean Cross <xobs@kosagi.com>
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
@ -18,6 +19,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
@ -32,6 +34,12 @@
|
||||
|
||||
#include "pcie-designware.h"
|
||||
|
||||
#define IMX8MQ_GPR_PCIE_REF_USE_PAD BIT(9)
|
||||
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN BIT(10)
|
||||
#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE BIT(11)
|
||||
#define IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE GENMASK(11, 8)
|
||||
#define IMX8MQ_PCIE2_BASE_ADDR 0x33c00000
|
||||
|
||||
#define to_imx6_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
enum imx6_pcie_variants {
|
||||
@ -39,6 +47,15 @@ enum imx6_pcie_variants {
|
||||
IMX6SX,
|
||||
IMX6QP,
|
||||
IMX7D,
|
||||
IMX8MQ,
|
||||
};
|
||||
|
||||
#define IMX6_PCIE_FLAG_IMX6_PHY BIT(0)
|
||||
#define IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE BIT(1)
|
||||
|
||||
struct imx6_pcie_drvdata {
|
||||
enum imx6_pcie_variants variant;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
struct imx6_pcie {
|
||||
@ -49,11 +66,12 @@ struct imx6_pcie {
|
||||
struct clk *pcie_phy;
|
||||
struct clk *pcie_inbound_axi;
|
||||
struct clk *pcie;
|
||||
struct clk *pcie_aux;
|
||||
struct regmap *iomuxc_gpr;
|
||||
u32 controller_id;
|
||||
struct reset_control *pciephy_reset;
|
||||
struct reset_control *apps_reset;
|
||||
struct reset_control *turnoff_reset;
|
||||
enum imx6_pcie_variants variant;
|
||||
u32 tx_deemph_gen1;
|
||||
u32 tx_deemph_gen2_3p5db;
|
||||
u32 tx_deemph_gen2_6db;
|
||||
@ -61,11 +79,13 @@ struct imx6_pcie {
|
||||
u32 tx_swing_low;
|
||||
int link_gen;
|
||||
struct regulator *vpcie;
|
||||
void __iomem *phy_base;
|
||||
|
||||
/* power domain for pcie */
|
||||
struct device *pd_pcie;
|
||||
/* power domain for pcie phy */
|
||||
struct device *pd_pcie_phy;
|
||||
const struct imx6_pcie_drvdata *drvdata;
|
||||
};
|
||||
|
||||
/* Parameters for the waiting for PCIe PHY PLL to lock on i.MX7 */
|
||||
@ -101,7 +121,6 @@ struct imx6_pcie {
|
||||
#define PCIE_PHY_STAT_ACK_LOC 16
|
||||
|
||||
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
|
||||
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
|
||||
|
||||
/* PHY registers (not memory-mapped) */
|
||||
#define PCIE_PHY_ATEOVRD 0x10
|
||||
@ -117,6 +136,23 @@ struct imx6_pcie {
|
||||
#define PCIE_PHY_RX_ASIC_OUT 0x100D
|
||||
#define PCIE_PHY_RX_ASIC_OUT_VALID (1 << 0)
|
||||
|
||||
/* iMX7 PCIe PHY registers */
|
||||
#define PCIE_PHY_CMN_REG4 0x14
|
||||
/* These are probably the bits that *aren't* DCC_FB_EN */
|
||||
#define PCIE_PHY_CMN_REG4_DCC_FB_EN 0x29
|
||||
|
||||
#define PCIE_PHY_CMN_REG15 0x54
|
||||
#define PCIE_PHY_CMN_REG15_DLY_4 BIT(2)
|
||||
#define PCIE_PHY_CMN_REG15_PLL_PD BIT(5)
|
||||
#define PCIE_PHY_CMN_REG15_OVRD_PLL_PD BIT(7)
|
||||
|
||||
#define PCIE_PHY_CMN_REG24 0x90
|
||||
#define PCIE_PHY_CMN_REG24_RX_EQ BIT(6)
|
||||
#define PCIE_PHY_CMN_REG24_RX_EQ_SEL BIT(3)
|
||||
|
||||
#define PCIE_PHY_CMN_REG26 0x98
|
||||
#define PCIE_PHY_CMN_REG26_ATT_MODE 0xBC
|
||||
|
||||
#define PHY_RX_OVRD_IN_LO 0x1005
|
||||
#define PHY_RX_OVRD_IN_LO_RX_DATA_EN (1 << 5)
|
||||
#define PHY_RX_OVRD_IN_LO_RX_PLL_EN (1 << 3)
|
||||
@ -251,6 +287,9 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
u32 tmp;
|
||||
|
||||
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
|
||||
return;
|
||||
|
||||
pcie_phy_read(imx6_pcie, PHY_RX_OVRD_IN_LO, &tmp);
|
||||
tmp |= (PHY_RX_OVRD_IN_LO_RX_DATA_EN |
|
||||
PHY_RX_OVRD_IN_LO_RX_PLL_EN);
|
||||
@ -264,6 +303,7 @@ static void imx6_pcie_reset_phy(struct imx6_pcie *imx6_pcie)
|
||||
pcie_phy_write(imx6_pcie, PHY_RX_OVRD_IN_LO, tmp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
/* Added for PCI abort handling */
|
||||
static int imx6q_pcie_abort_handler(unsigned long addr,
|
||||
unsigned int fsr, struct pt_regs *regs)
|
||||
@ -297,6 +337,7 @@ static int imx6q_pcie_abort_handler(unsigned long addr,
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int imx6_pcie_attach_pd(struct device *dev)
|
||||
{
|
||||
@ -339,8 +380,9 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct device *dev = imx6_pcie->pci->dev;
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX7D:
|
||||
case IMX8MQ:
|
||||
reset_control_assert(imx6_pcie->pciephy_reset);
|
||||
reset_control_assert(imx6_pcie->apps_reset);
|
||||
break;
|
||||
@ -375,13 +417,20 @@ static void imx6_pcie_assert_core_reset(struct imx6_pcie *imx6_pcie)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int imx6_pcie_grp_offset(const struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
WARN_ON(imx6_pcie->drvdata->variant != IMX8MQ);
|
||||
return imx6_pcie->controller_id == 1 ? IOMUXC_GPR16 : IOMUXC_GPR14;
|
||||
}
|
||||
|
||||
static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = imx6_pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
unsigned int offset;
|
||||
int ret = 0;
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
ret = clk_prepare_enable(imx6_pcie->pcie_inbound_axi);
|
||||
if (ret) {
|
||||
@ -409,6 +458,25 @@ static int imx6_pcie_enable_ref_clk(struct imx6_pcie *imx6_pcie)
|
||||
break;
|
||||
case IMX7D:
|
||||
break;
|
||||
case IMX8MQ:
|
||||
ret = clk_prepare_enable(imx6_pcie->pcie_aux);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to enable pcie_aux clock\n");
|
||||
break;
|
||||
}
|
||||
|
||||
offset = imx6_pcie_grp_offset(imx6_pcie);
|
||||
/*
|
||||
* Set the over ride low and enabled
|
||||
* make sure that REF_CLK is turned on.
|
||||
*/
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
|
||||
IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE,
|
||||
0);
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, offset,
|
||||
IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN,
|
||||
IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -484,9 +552,32 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
|
||||
!imx6_pcie->gpio_active_high);
|
||||
}
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX8MQ:
|
||||
reset_control_deassert(imx6_pcie->pciephy_reset);
|
||||
break;
|
||||
case IMX7D:
|
||||
reset_control_deassert(imx6_pcie->pciephy_reset);
|
||||
|
||||
/* Workaround for ERR010728, failure of PCI-e PLL VCO to
|
||||
* oscillate, especially when cold. This turns off "Duty-cycle
|
||||
* Corrector" and other mysterious undocumented things.
|
||||
*/
|
||||
if (likely(imx6_pcie->phy_base)) {
|
||||
/* De-assert DCC_FB_EN */
|
||||
writel(PCIE_PHY_CMN_REG4_DCC_FB_EN,
|
||||
imx6_pcie->phy_base + PCIE_PHY_CMN_REG4);
|
||||
/* Assert RX_EQS and RX_EQS_SEL */
|
||||
writel(PCIE_PHY_CMN_REG24_RX_EQ_SEL
|
||||
| PCIE_PHY_CMN_REG24_RX_EQ,
|
||||
imx6_pcie->phy_base + PCIE_PHY_CMN_REG24);
|
||||
/* Assert ATT_MODE */
|
||||
writel(PCIE_PHY_CMN_REG26_ATT_MODE,
|
||||
imx6_pcie->phy_base + PCIE_PHY_CMN_REG26);
|
||||
} else {
|
||||
dev_warn(dev, "Unable to apply ERR010728 workaround. DT missing fsl,imx7d-pcie-phy phandle ?\n");
|
||||
}
|
||||
|
||||
imx7d_pcie_wait_for_phy_pll_lock(imx6_pcie);
|
||||
break;
|
||||
case IMX6SX:
|
||||
@ -520,9 +611,37 @@ static void imx6_pcie_deassert_core_reset(struct imx6_pcie *imx6_pcie)
|
||||
}
|
||||
}
|
||||
|
||||
static void imx6_pcie_configure_type(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
unsigned int mask, val;
|
||||
|
||||
if (imx6_pcie->drvdata->variant == IMX8MQ &&
|
||||
imx6_pcie->controller_id == 1) {
|
||||
mask = IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE;
|
||||
val = FIELD_PREP(IMX8MQ_GPR12_PCIE2_CTRL_DEVICE_TYPE,
|
||||
PCI_EXP_TYPE_ROOT_PORT);
|
||||
} else {
|
||||
mask = IMX6Q_GPR12_DEVICE_TYPE;
|
||||
val = FIELD_PREP(IMX6Q_GPR12_DEVICE_TYPE,
|
||||
PCI_EXP_TYPE_ROOT_PORT);
|
||||
}
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12, mask, val);
|
||||
}
|
||||
|
||||
static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX8MQ:
|
||||
/*
|
||||
* TODO: Currently this code assumes external
|
||||
* oscillator is being used
|
||||
*/
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr,
|
||||
imx6_pcie_grp_offset(imx6_pcie),
|
||||
IMX8MQ_GPR_PCIE_REF_USE_PAD,
|
||||
IMX8MQ_GPR_PCIE_REF_USE_PAD);
|
||||
break;
|
||||
case IMX7D:
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL, 0);
|
||||
@ -558,8 +677,7 @@ static void imx6_pcie_init_phy(struct imx6_pcie *imx6_pcie)
|
||||
break;
|
||||
}
|
||||
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6Q_GPR12_DEVICE_TYPE, PCI_EXP_TYPE_ROOT_PORT << 12);
|
||||
imx6_pcie_configure_type(imx6_pcie);
|
||||
}
|
||||
|
||||
static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
|
||||
@ -568,6 +686,9 @@ static int imx6_setup_phy_mpll(struct imx6_pcie *imx6_pcie)
|
||||
int mult, div;
|
||||
u32 val;
|
||||
|
||||
if (!(imx6_pcie->drvdata->flags & IMX6_PCIE_FLAG_IMX6_PHY))
|
||||
return 0;
|
||||
|
||||
switch (phy_rate) {
|
||||
case 125000000:
|
||||
/*
|
||||
@ -644,7 +765,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6Q:
|
||||
case IMX6SX:
|
||||
case IMX6QP:
|
||||
@ -653,6 +774,7 @@ static void imx6_pcie_ltssm_enable(struct device *dev)
|
||||
IMX6Q_GPR12_PCIE_CTL_2);
|
||||
break;
|
||||
case IMX7D:
|
||||
case IMX8MQ:
|
||||
reset_control_deassert(imx6_pcie->apps_reset);
|
||||
break;
|
||||
}
|
||||
@ -697,7 +819,8 @@ static int imx6_pcie_establish_link(struct imx6_pcie *imx6_pcie)
|
||||
tmp |= PORT_LOGIC_SPEED_CHANGE;
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, tmp);
|
||||
|
||||
if (imx6_pcie->variant != IMX7D) {
|
||||
if (imx6_pcie->drvdata->flags &
|
||||
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE) {
|
||||
/*
|
||||
* On i.MX7, DIRECT_SPEED_CHANGE behaves differently
|
||||
* from i.MX6 family when no link speed transition
|
||||
@ -794,7 +917,7 @@ static void imx6_pcie_ltssm_disable(struct device *dev)
|
||||
{
|
||||
struct imx6_pcie *imx6_pcie = dev_get_drvdata(dev);
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
case IMX6QP:
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
@ -820,7 +943,7 @@ static void imx6_pcie_pm_turnoff(struct imx6_pcie *imx6_pcie)
|
||||
}
|
||||
|
||||
/* Others poke directly at IOMUXC registers */
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR12,
|
||||
IMX6SX_GPR12_PCIE_PM_TURN_OFF,
|
||||
@ -850,7 +973,7 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
|
||||
clk_disable_unprepare(imx6_pcie->pcie_phy);
|
||||
clk_disable_unprepare(imx6_pcie->pcie_bus);
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
clk_disable_unprepare(imx6_pcie->pcie_inbound_axi);
|
||||
break;
|
||||
@ -859,6 +982,9 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
|
||||
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL,
|
||||
IMX7D_GPR12_PCIE_PHY_REFCLK_SEL);
|
||||
break;
|
||||
case IMX8MQ:
|
||||
clk_disable_unprepare(imx6_pcie->pcie_aux);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -866,8 +992,8 @@ static void imx6_pcie_clk_disable(struct imx6_pcie *imx6_pcie)
|
||||
|
||||
static inline bool imx6_pcie_supports_suspend(struct imx6_pcie *imx6_pcie)
|
||||
{
|
||||
return (imx6_pcie->variant == IMX7D ||
|
||||
imx6_pcie->variant == IMX6SX);
|
||||
return (imx6_pcie->drvdata->variant == IMX7D ||
|
||||
imx6_pcie->drvdata->variant == IMX6SX);
|
||||
}
|
||||
|
||||
static int imx6_pcie_suspend_noirq(struct device *dev)
|
||||
@ -916,6 +1042,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci;
|
||||
struct imx6_pcie *imx6_pcie;
|
||||
struct device_node *np;
|
||||
struct resource *dbi_base;
|
||||
struct device_node *node = dev->of_node;
|
||||
int ret;
|
||||
@ -933,8 +1060,24 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
imx6_pcie->pci = pci;
|
||||
imx6_pcie->variant =
|
||||
(enum imx6_pcie_variants)of_device_get_match_data(dev);
|
||||
imx6_pcie->drvdata = of_device_get_match_data(dev);
|
||||
|
||||
/* Find the PHY if one is defined, only imx7d uses it */
|
||||
np = of_parse_phandle(node, "fsl,imx7d-pcie-phy", 0);
|
||||
if (np) {
|
||||
struct resource res;
|
||||
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to map PCIe PHY\n");
|
||||
return ret;
|
||||
}
|
||||
imx6_pcie->phy_base = devm_ioremap_resource(dev, &res);
|
||||
if (IS_ERR(imx6_pcie->phy_base)) {
|
||||
dev_err(dev, "Unable to map PCIe PHY\n");
|
||||
return PTR_ERR(imx6_pcie->phy_base);
|
||||
}
|
||||
}
|
||||
|
||||
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
|
||||
@ -978,7 +1121,7 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(imx6_pcie->pcie);
|
||||
}
|
||||
|
||||
switch (imx6_pcie->variant) {
|
||||
switch (imx6_pcie->drvdata->variant) {
|
||||
case IMX6SX:
|
||||
imx6_pcie->pcie_inbound_axi = devm_clk_get(dev,
|
||||
"pcie_inbound_axi");
|
||||
@ -987,7 +1130,17 @@ static int imx6_pcie_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(imx6_pcie->pcie_inbound_axi);
|
||||
}
|
||||
break;
|
||||
case IMX8MQ:
|
||||
imx6_pcie->pcie_aux = devm_clk_get(dev, "pcie_aux");
|
||||
if (IS_ERR(imx6_pcie->pcie_aux)) {
|
||||
dev_err(dev, "pcie_aux clock source missing or invalid\n");
|
||||
return PTR_ERR(imx6_pcie->pcie_aux);
|
||||
}
|
||||
/* fall through */
|
||||
case IMX7D:
|
||||
if (dbi_base->start == IMX8MQ_PCIE2_BASE_ADDR)
|
||||
imx6_pcie->controller_id = 1;
|
||||
|
||||
imx6_pcie->pciephy_reset = devm_reset_control_get_exclusive(dev,
|
||||
"pciephy");
|
||||
if (IS_ERR(imx6_pcie->pciephy_reset)) {
|
||||
@ -1084,11 +1237,36 @@ static void imx6_pcie_shutdown(struct platform_device *pdev)
|
||||
imx6_pcie_assert_core_reset(imx6_pcie);
|
||||
}
|
||||
|
||||
static const struct imx6_pcie_drvdata drvdata[] = {
|
||||
[IMX6Q] = {
|
||||
.variant = IMX6Q,
|
||||
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
|
||||
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
|
||||
},
|
||||
[IMX6SX] = {
|
||||
.variant = IMX6SX,
|
||||
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
|
||||
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
|
||||
},
|
||||
[IMX6QP] = {
|
||||
.variant = IMX6QP,
|
||||
.flags = IMX6_PCIE_FLAG_IMX6_PHY |
|
||||
IMX6_PCIE_FLAG_IMX6_SPEED_CHANGE,
|
||||
},
|
||||
[IMX7D] = {
|
||||
.variant = IMX7D,
|
||||
},
|
||||
[IMX8MQ] = {
|
||||
.variant = IMX8MQ,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id imx6_pcie_of_match[] = {
|
||||
{ .compatible = "fsl,imx6q-pcie", .data = (void *)IMX6Q, },
|
||||
{ .compatible = "fsl,imx6sx-pcie", .data = (void *)IMX6SX, },
|
||||
{ .compatible = "fsl,imx6qp-pcie", .data = (void *)IMX6QP, },
|
||||
{ .compatible = "fsl,imx7d-pcie", .data = (void *)IMX7D, },
|
||||
{ .compatible = "fsl,imx6q-pcie", .data = &drvdata[IMX6Q], },
|
||||
{ .compatible = "fsl,imx6sx-pcie", .data = &drvdata[IMX6SX], },
|
||||
{ .compatible = "fsl,imx6qp-pcie", .data = &drvdata[IMX6QP], },
|
||||
{ .compatible = "fsl,imx7d-pcie", .data = &drvdata[IMX7D], },
|
||||
{ .compatible = "fsl,imx8mq-pcie", .data = &drvdata[IMX8MQ], } ,
|
||||
{},
|
||||
};
|
||||
|
||||
@ -1105,6 +1283,7 @@ static struct platform_driver imx6_pcie_driver = {
|
||||
|
||||
static int __init imx6_pcie_init(void)
|
||||
{
|
||||
#ifdef CONFIG_ARM
|
||||
/*
|
||||
* Since probe() can be deferred we need to make sure that
|
||||
* hook_fault_code is not called after __init memory is freed
|
||||
@ -1114,6 +1293,7 @@ static int __init imx6_pcie_init(void)
|
||||
*/
|
||||
hook_fault_code(8, imx6q_pcie_abort_handler, SIGBUS, 0,
|
||||
"external abort on non-linefetch");
|
||||
#endif
|
||||
|
||||
return platform_driver_register(&imx6_pcie_driver);
|
||||
}
|
||||
|
@ -465,8 +465,10 @@ int dw_pcie_ep_raise_msix_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
|
||||
iounmap(msix_tbl);
|
||||
|
||||
if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)
|
||||
if (vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) {
|
||||
dev_dbg(pci->dev, "MSI-X entry ctrl set\n");
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
|
||||
epc->mem->page_size);
|
||||
|
@ -120,9 +120,9 @@ static void dw_chained_msi_isr(struct irq_desc *desc)
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
u64 msi_target;
|
||||
|
||||
@ -135,61 +135,61 @@ static void dw_pci_setup_msi_msg(struct irq_data *data, struct msi_msg *msg)
|
||||
msg->address_hi = upper_32_bits(msi_target);
|
||||
|
||||
if (pp->ops->get_msi_data)
|
||||
msg->data = pp->ops->get_msi_data(pp, data->hwirq);
|
||||
msg->data = pp->ops->get_msi_data(pp, d->hwirq);
|
||||
else
|
||||
msg->data = data->hwirq;
|
||||
msg->data = d->hwirq;
|
||||
|
||||
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
|
||||
(int)data->hwirq, msg->address_hi, msg->address_lo);
|
||||
(int)d->hwirq, msg->address_hi, msg->address_lo);
|
||||
}
|
||||
|
||||
static int dw_pci_msi_set_affinity(struct irq_data *irq_data,
|
||||
static int dw_pci_msi_set_affinity(struct irq_data *d,
|
||||
const struct cpumask *mask, bool force)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dw_pci_bottom_mask(struct irq_data *data)
|
||||
static void dw_pci_bottom_mask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
if (pp->ops->msi_clear_irq) {
|
||||
pp->ops->msi_clear_irq(pp, data->hwirq);
|
||||
pp->ops->msi_clear_irq(pp, d->hwirq);
|
||||
} else {
|
||||
ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_status[ctrl] &= ~(1 << bit);
|
||||
pp->irq_mask[ctrl] |= BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
~pp->irq_status[ctrl]);
|
||||
pp->irq_mask[ctrl]);
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
}
|
||||
|
||||
static void dw_pci_bottom_unmask(struct irq_data *data)
|
||||
static void dw_pci_bottom_unmask(struct irq_data *d)
|
||||
{
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
unsigned int res, bit, ctrl;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
if (pp->ops->msi_set_irq) {
|
||||
pp->ops->msi_set_irq(pp, data->hwirq);
|
||||
pp->ops->msi_set_irq(pp, d->hwirq);
|
||||
} else {
|
||||
ctrl = data->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
ctrl = d->hwirq / MAX_MSI_IRQS_PER_CTRL;
|
||||
res = ctrl * MSI_REG_CTRL_BLOCK_SIZE;
|
||||
bit = data->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
bit = d->hwirq % MAX_MSI_IRQS_PER_CTRL;
|
||||
|
||||
pp->irq_status[ctrl] |= 1 << bit;
|
||||
pp->irq_mask[ctrl] &= ~BIT(bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_MASK + res, 4,
|
||||
~pp->irq_status[ctrl]);
|
||||
pp->irq_mask[ctrl]);
|
||||
}
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
@ -207,7 +207,7 @@ static void dw_pci_bottom_ack(struct irq_data *d)
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, 1 << bit);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + res, 4, BIT(bit));
|
||||
|
||||
if (pp->ops->msi_irq_ack)
|
||||
pp->ops->msi_irq_ack(d->hwirq, pp);
|
||||
@ -255,13 +255,13 @@ static int dw_pcie_irq_domain_alloc(struct irq_domain *domain,
|
||||
static void dw_pcie_irq_domain_free(struct irq_domain *domain,
|
||||
unsigned int virq, unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *data = irq_domain_get_irq_data(domain, virq);
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(data);
|
||||
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
|
||||
struct pcie_port *pp = irq_data_get_irq_chip_data(d);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&pp->lock, flags);
|
||||
|
||||
bitmap_release_region(pp->msi_irq_in_use, data->hwirq,
|
||||
bitmap_release_region(pp->msi_irq_in_use, d->hwirq,
|
||||
order_base_2(nr_irqs));
|
||||
|
||||
raw_spin_unlock_irqrestore(&pp->lock, flags);
|
||||
@ -439,7 +439,7 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
if (ret)
|
||||
pci->num_viewport = 2;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI)) {
|
||||
if (IS_ENABLED(CONFIG_PCI_MSI) && pci_msi_enabled()) {
|
||||
/*
|
||||
* If a specific SoC driver needs to change the
|
||||
* default number of vectors, it needs to implement
|
||||
@ -512,8 +512,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
|
||||
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)
|
||||
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)
|
||||
{
|
||||
int ret, type;
|
||||
u32 busdev, cfg_size;
|
||||
@ -521,9 +522,6 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
void __iomem *va_cfg_base;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
if (pp->ops->rd_other_conf)
|
||||
return pp->ops->rd_other_conf(pp, bus, devfn, where, size, val);
|
||||
|
||||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||
|
||||
@ -542,7 +540,11 @@ static int dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
type, cpu_addr,
|
||||
busdev, cfg_size);
|
||||
ret = dw_pcie_read(va_cfg_base + where, size, val);
|
||||
if (write)
|
||||
ret = dw_pcie_write(va_cfg_base + where, size, *val);
|
||||
else
|
||||
ret = dw_pcie_read(va_cfg_base + where, size, val);
|
||||
|
||||
if (pci->num_viewport <= 2)
|
||||
dw_pcie_prog_outbound_atu(pci, PCIE_ATU_REGION_INDEX1,
|
||||
PCIE_ATU_TYPE_IO, pp->io_base,
|
||||
@ -551,43 +553,26 @@ static int dw_pcie_rd_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)
|
||||
{
|
||||
int ret, type;
|
||||
u32 busdev, cfg_size;
|
||||
u64 cpu_addr;
|
||||
void __iomem *va_cfg_base;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
|
||||
if (pp->ops->wr_other_conf)
|
||||
return pp->ops->wr_other_conf(pp, bus, devfn, where, size, val);
|
||||
return pp->ops->wr_other_conf(pp, bus, devfn, where,
|
||||
size, val);
|
||||
|
||||
busdev = PCIE_ATU_BUS(bus->number) | PCIE_ATU_DEV(PCI_SLOT(devfn)) |
|
||||
PCIE_ATU_FUNC(PCI_FUNC(devfn));
|
||||
|
||||
if (bus->parent->number == pp->root_bus_nr) {
|
||||
type = PCIE_ATU_TYPE_CFG0;
|
||||
cpu_addr = pp->cfg0_base;
|
||||
cfg_size = pp->cfg0_size;
|
||||
va_cfg_base = pp->va_cfg0_base;
|
||||
} 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);
|
||||
ret = dw_pcie_write(va_cfg_base + where, size, val);
|
||||
if (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;
|
||||
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,
|
||||
@ -665,13 +650,13 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
|
||||
|
||||
/* 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 +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
4, pp->irq_mask[ctrl]);
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE +
|
||||
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
|
||||
4, ~0);
|
||||
pp->irq_status[ctrl] = 0;
|
||||
}
|
||||
|
||||
/* Setup RC BARs */
|
||||
|
@ -13,11 +13,9 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/resource.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
int dw_pcie_read(void __iomem *addr, int size, u32 *val)
|
||||
{
|
||||
if ((uintptr_t)addr & (size - 1)) {
|
||||
if (!IS_ALIGNED((uintptr_t)addr, size)) {
|
||||
*val = 0;
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
}
|
||||
@ -43,7 +43,7 @@ int dw_pcie_read(void __iomem *addr, int size, u32 *val)
|
||||
|
||||
int dw_pcie_write(void __iomem *addr, int size, u32 val)
|
||||
{
|
||||
if ((uintptr_t)addr & (size - 1))
|
||||
if (!IS_ALIGNED((uintptr_t)addr, size))
|
||||
return PCIBIOS_BAD_REGISTER_NUMBER;
|
||||
|
||||
if (size == 4)
|
||||
@ -306,7 +306,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, ~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)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#ifndef _PCIE_DESIGNWARE_H
|
||||
#define _PCIE_DESIGNWARE_H
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/msi.h>
|
||||
@ -30,23 +31,25 @@
|
||||
|
||||
/* Synopsys-specific PCIe configuration registers */
|
||||
#define PCIE_PORT_LINK_CONTROL 0x710
|
||||
#define PORT_LINK_MODE_MASK (0x3f << 16)
|
||||
#define PORT_LINK_MODE_1_LANES (0x1 << 16)
|
||||
#define PORT_LINK_MODE_2_LANES (0x3 << 16)
|
||||
#define PORT_LINK_MODE_4_LANES (0x7 << 16)
|
||||
#define PORT_LINK_MODE_8_LANES (0xf << 16)
|
||||
#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)
|
||||
#define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3)
|
||||
#define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)
|
||||
#define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)
|
||||
|
||||
#define PCIE_PORT_DEBUG0 0x728
|
||||
#define PORT_LOGIC_LTSSM_STATE_MASK 0x1f
|
||||
#define PORT_LOGIC_LTSSM_STATE_L0 0x11
|
||||
|
||||
#define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C
|
||||
#define PORT_LOGIC_SPEED_CHANGE (0x1 << 17)
|
||||
#define PORT_LOGIC_LINK_WIDTH_MASK (0x1f << 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH_1_LANES (0x1 << 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH_2_LANES (0x2 << 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH_4_LANES (0x4 << 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH_8_LANES (0x8 << 8)
|
||||
#define PORT_LOGIC_SPEED_CHANGE BIT(17)
|
||||
#define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)
|
||||
#define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
|
||||
#define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1)
|
||||
#define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2)
|
||||
#define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4)
|
||||
#define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8)
|
||||
|
||||
#define PCIE_MSI_ADDR_LO 0x820
|
||||
#define PCIE_MSI_ADDR_HI 0x824
|
||||
@ -55,30 +58,30 @@
|
||||
#define PCIE_MSI_INTR0_STATUS 0x830
|
||||
|
||||
#define PCIE_ATU_VIEWPORT 0x900
|
||||
#define PCIE_ATU_REGION_INBOUND (0x1 << 31)
|
||||
#define PCIE_ATU_REGION_OUTBOUND (0x0 << 31)
|
||||
#define PCIE_ATU_REGION_INDEX2 (0x2 << 0)
|
||||
#define PCIE_ATU_REGION_INDEX1 (0x1 << 0)
|
||||
#define PCIE_ATU_REGION_INDEX0 (0x0 << 0)
|
||||
#define PCIE_ATU_REGION_INBOUND BIT(31)
|
||||
#define PCIE_ATU_REGION_OUTBOUND 0
|
||||
#define PCIE_ATU_REGION_INDEX2 0x2
|
||||
#define PCIE_ATU_REGION_INDEX1 0x1
|
||||
#define PCIE_ATU_REGION_INDEX0 0x0
|
||||
#define PCIE_ATU_CR1 0x904
|
||||
#define PCIE_ATU_TYPE_MEM (0x0 << 0)
|
||||
#define PCIE_ATU_TYPE_IO (0x2 << 0)
|
||||
#define PCIE_ATU_TYPE_CFG0 (0x4 << 0)
|
||||
#define PCIE_ATU_TYPE_CFG1 (0x5 << 0)
|
||||
#define PCIE_ATU_TYPE_MEM 0x0
|
||||
#define PCIE_ATU_TYPE_IO 0x2
|
||||
#define PCIE_ATU_TYPE_CFG0 0x4
|
||||
#define PCIE_ATU_TYPE_CFG1 0x5
|
||||
#define PCIE_ATU_CR2 0x908
|
||||
#define PCIE_ATU_ENABLE (0x1 << 31)
|
||||
#define PCIE_ATU_BAR_MODE_ENABLE (0x1 << 30)
|
||||
#define PCIE_ATU_ENABLE BIT(31)
|
||||
#define PCIE_ATU_BAR_MODE_ENABLE BIT(30)
|
||||
#define PCIE_ATU_LOWER_BASE 0x90C
|
||||
#define PCIE_ATU_UPPER_BASE 0x910
|
||||
#define PCIE_ATU_LIMIT 0x914
|
||||
#define PCIE_ATU_LOWER_TARGET 0x918
|
||||
#define PCIE_ATU_BUS(x) (((x) & 0xff) << 24)
|
||||
#define PCIE_ATU_DEV(x) (((x) & 0x1f) << 19)
|
||||
#define PCIE_ATU_FUNC(x) (((x) & 0x7) << 16)
|
||||
#define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)
|
||||
#define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)
|
||||
#define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)
|
||||
#define PCIE_ATU_UPPER_TARGET 0x91C
|
||||
|
||||
#define PCIE_MISC_CONTROL_1_OFF 0x8BC
|
||||
#define PCIE_DBI_RO_WR_EN (0x1 << 0)
|
||||
#define PCIE_DBI_RO_WR_EN BIT(0)
|
||||
|
||||
/*
|
||||
* iATU Unroll-specific register definitions
|
||||
@ -105,7 +108,7 @@
|
||||
((region) << 9)
|
||||
|
||||
#define PCIE_GET_ATU_INB_UNR_REG_OFFSET(region) \
|
||||
(((region) << 9) | (0x1 << 8))
|
||||
(((region) << 9) | BIT(8))
|
||||
|
||||
#define MAX_MSI_IRQS 256
|
||||
#define MAX_MSI_IRQS_PER_CTRL 32
|
||||
@ -177,7 +180,7 @@ struct pcie_port {
|
||||
struct irq_domain *msi_domain;
|
||||
dma_addr_t msi_data;
|
||||
u32 num_vectors;
|
||||
u32 irq_status[MAX_MSI_CTRLS];
|
||||
u32 irq_mask[MAX_MSI_CTRLS];
|
||||
raw_spinlock_t lock;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
|
||||
};
|
||||
|
@ -1228,7 +1228,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
||||
|
||||
pcie->ops = of_device_get_match_data(dev);
|
||||
|
||||
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
|
||||
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(pcie->reset)) {
|
||||
ret = PTR_ERR(pcie->reset);
|
||||
goto err_pm_runtime_put;
|
||||
|
Loading…
Reference in New Issue
Block a user