mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
Merge branch 'pci/host-tegra' into next
* pci/host-tegra: PCI: tegra: Add Tegra186 PCIe support dt-bindings: pci: tegra: Document Tegra186 PCIe DT PCI: tegra: Use generic accessors where possible
This commit is contained in:
commit
d238be6957
@ -1,10 +1,15 @@
|
||||
NVIDIA Tegra PCIe controller
|
||||
|
||||
Required properties:
|
||||
- compatible: For Tegra20, must contain "nvidia,tegra20-pcie". For Tegra30,
|
||||
"nvidia,tegra30-pcie". For Tegra124, must contain "nvidia,tegra124-pcie".
|
||||
Otherwise, must contain "nvidia,<chip>-pcie", plus one of the above, where
|
||||
<chip> is tegra132 or tegra210.
|
||||
- compatible: Must be:
|
||||
- "nvidia,tegra20-pcie": for Tegra20
|
||||
- "nvidia,tegra30-pcie": for Tegra30
|
||||
- "nvidia,tegra124-pcie": for Tegra124 and Tegra132
|
||||
- "nvidia,tegra210-pcie": for Tegra210
|
||||
- "nvidia,tegra186-pcie": for Tegra186
|
||||
- power-domains: To ungate power partition by BPMP powergate driver. Must
|
||||
contain BPMP phandle and PCIe power partition ID. This is required only
|
||||
for Tegra186.
|
||||
- device_type: Must be "pci"
|
||||
- reg: A list of physical base address and length for each set of controller
|
||||
registers. Must contain an entry for each entry in the reg-names property.
|
||||
@ -124,6 +129,16 @@ Power supplies for Tegra210:
|
||||
- vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
|
||||
supply 1.8 V.
|
||||
|
||||
Power supplies for Tegra186:
|
||||
- Required:
|
||||
- dvdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
|
||||
- hvdd-pex-pll-supply: High-voltage supply for PLLE (shared with USB3). Must
|
||||
supply 1.8 V.
|
||||
- hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks.
|
||||
Must supply 1.8 V.
|
||||
- vddio-pexctl-aud-supply: Power supply for PCIe side band signals. Must
|
||||
supply 1.8 V.
|
||||
|
||||
Root ports are defined as subnodes of the PCIe controller node.
|
||||
|
||||
Required properties:
|
||||
@ -546,3 +561,114 @@ Board DTS:
|
||||
status = "okay";
|
||||
};
|
||||
};
|
||||
|
||||
Tegra186:
|
||||
---------
|
||||
|
||||
SoC DTSI:
|
||||
|
||||
pcie@10003000 {
|
||||
compatible = "nvidia,tegra186-pcie";
|
||||
power-domains = <&bpmp TEGRA186_POWER_DOMAIN_PCX>;
|
||||
device_type = "pci";
|
||||
reg = <0x0 0x10003000 0x0 0x00000800 /* PADS registers */
|
||||
0x0 0x10003800 0x0 0x00000800 /* AFI registers */
|
||||
0x0 0x40000000 0x0 0x10000000>; /* configuration space */
|
||||
reg-names = "pads", "afi", "cs";
|
||||
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>, /* controller interrupt */
|
||||
<GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; /* MSI interrupt */
|
||||
interrupt-names = "intr", "msi";
|
||||
|
||||
#interrupt-cells = <1>;
|
||||
interrupt-map-mask = <0 0 0 0>;
|
||||
interrupt-map = <0 0 0 0 &gic GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
||||
bus-range = <0x00 0xff>;
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
|
||||
ranges = <0x82000000 0 0x10000000 0x0 0x10000000 0 0x00001000 /* port 0 configuration space */
|
||||
0x82000000 0 0x10001000 0x0 0x10001000 0 0x00001000 /* port 1 configuration space */
|
||||
0x82000000 0 0x10004000 0x0 0x10004000 0 0x00001000 /* port 2 configuration space */
|
||||
0x81000000 0 0x0 0x0 0x50000000 0 0x00010000 /* downstream I/O (64 KiB) */
|
||||
0x82000000 0 0x50100000 0x0 0x50100000 0 0x07F00000 /* non-prefetchable memory (127 MiB) */
|
||||
0xc2000000 0 0x58000000 0x0 0x58000000 0 0x28000000>; /* prefetchable memory (640 MiB) */
|
||||
|
||||
clocks = <&bpmp TEGRA186_CLK_AFI>,
|
||||
<&bpmp TEGRA186_CLK_PCIE>,
|
||||
<&bpmp TEGRA186_CLK_PLLE>;
|
||||
clock-names = "afi", "pex", "pll_e";
|
||||
|
||||
resets = <&bpmp TEGRA186_RESET_AFI>,
|
||||
<&bpmp TEGRA186_RESET_PCIE>,
|
||||
<&bpmp TEGRA186_RESET_PCIEXCLK>;
|
||||
reset-names = "afi", "pex", "pcie_x";
|
||||
|
||||
status = "disabled";
|
||||
|
||||
pci@1,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82000800 0 0x10000000 0 0x1000>;
|
||||
reg = <0x000800 0 0 0 0>;
|
||||
status = "disabled";
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
nvidia,num-lanes = <2>;
|
||||
};
|
||||
|
||||
pci@2,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82001000 0 0x10001000 0 0x1000>;
|
||||
reg = <0x001000 0 0 0 0>;
|
||||
status = "disabled";
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
nvidia,num-lanes = <1>;
|
||||
};
|
||||
|
||||
pci@3,0 {
|
||||
device_type = "pci";
|
||||
assigned-addresses = <0x82001800 0 0x10004000 0 0x1000>;
|
||||
reg = <0x001800 0 0 0 0>;
|
||||
status = "disabled";
|
||||
|
||||
#address-cells = <3>;
|
||||
#size-cells = <2>;
|
||||
ranges;
|
||||
|
||||
nvidia,num-lanes = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
Board DTS:
|
||||
|
||||
pcie@10003000 {
|
||||
status = "okay";
|
||||
|
||||
dvdd-pex-supply = <&vdd_pex>;
|
||||
hvdd-pex-pll-supply = <&vdd_1v8>;
|
||||
hvdd-pex-supply = <&vdd_1v8>;
|
||||
vddio-pexctl-aud-supply = <&vdd_1v8>;
|
||||
|
||||
pci@1,0 {
|
||||
nvidia,num-lanes = <4>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
pci@2,0 {
|
||||
nvidia,num-lanes = <0>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
pci@3,0 {
|
||||
nvidia,num-lanes = <1>;
|
||||
status = "disabled";
|
||||
};
|
||||
};
|
||||
|
@ -159,10 +159,13 @@
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401 (0x0 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211 (0x1 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
|
||||
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111 (0x2 << 20)
|
||||
|
||||
#define AFI_FUSE 0x104
|
||||
#define AFI_FUSE_PCIE_T0_GEN2_DIS (1 << 2)
|
||||
@ -252,6 +255,7 @@ struct tegra_pcie_soc {
|
||||
bool has_cml_clk;
|
||||
bool has_gen2;
|
||||
bool force_pca_enable;
|
||||
bool program_uphy;
|
||||
};
|
||||
|
||||
static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
|
||||
@ -491,12 +495,32 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int tegra_pcie_config_read(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 *value)
|
||||
{
|
||||
if (bus->number == 0)
|
||||
return pci_generic_config_read32(bus, devfn, where, size,
|
||||
value);
|
||||
|
||||
return pci_generic_config_read(bus, devfn, where, size, value);
|
||||
}
|
||||
|
||||
static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
|
||||
int where, int size, u32 value)
|
||||
{
|
||||
if (bus->number == 0)
|
||||
return pci_generic_config_write32(bus, devfn, where, size,
|
||||
value);
|
||||
|
||||
return pci_generic_config_write(bus, devfn, where, size, value);
|
||||
}
|
||||
|
||||
static struct pci_ops tegra_pcie_ops = {
|
||||
.add_bus = tegra_pcie_add_bus,
|
||||
.remove_bus = tegra_pcie_remove_bus,
|
||||
.map_bus = tegra_pcie_map_bus,
|
||||
.read = pci_generic_config_read32,
|
||||
.write = pci_generic_config_write32,
|
||||
.read = tegra_pcie_config_read,
|
||||
.write = tegra_pcie_config_write,
|
||||
};
|
||||
|
||||
static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
|
||||
@ -1012,10 +1036,12 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
|
||||
afi_writel(pcie, value, AFI_FUSE);
|
||||
}
|
||||
|
||||
err = tegra_pcie_phy_power_on(pcie);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to power on PHY(s): %d\n", err);
|
||||
return err;
|
||||
if (soc->program_uphy) {
|
||||
err = tegra_pcie_phy_power_on(pcie);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to power on PHY(s): %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* take the PCIe interface module out of reset */
|
||||
@ -1048,19 +1074,23 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
|
||||
static void tegra_pcie_power_off(struct tegra_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
const struct tegra_pcie_soc *soc = pcie->soc;
|
||||
int err;
|
||||
|
||||
/* TODO: disable and unprepare clocks? */
|
||||
|
||||
err = tegra_pcie_phy_power_off(pcie);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to power off PHY(s): %d\n", err);
|
||||
if (soc->program_uphy) {
|
||||
err = tegra_pcie_phy_power_off(pcie);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to power off PHY(s): %d\n", err);
|
||||
}
|
||||
|
||||
reset_control_assert(pcie->pcie_xrst);
|
||||
reset_control_assert(pcie->afi_rst);
|
||||
reset_control_assert(pcie->pex_rst);
|
||||
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
|
||||
if (!dev->pm_domain)
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
|
||||
|
||||
err = regulator_bulk_disable(pcie->num_supplies, pcie->supplies);
|
||||
if (err < 0)
|
||||
@ -1077,19 +1107,29 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie)
|
||||
reset_control_assert(pcie->afi_rst);
|
||||
reset_control_assert(pcie->pex_rst);
|
||||
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
|
||||
if (!dev->pm_domain)
|
||||
tegra_powergate_power_off(TEGRA_POWERGATE_PCIE);
|
||||
|
||||
/* enable regulators */
|
||||
err = regulator_bulk_enable(pcie->num_supplies, pcie->supplies);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to enable regulators: %d\n", err);
|
||||
|
||||
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
|
||||
pcie->pex_clk,
|
||||
pcie->pex_rst);
|
||||
if (err) {
|
||||
dev_err(dev, "powerup sequence failed: %d\n", err);
|
||||
return err;
|
||||
if (dev->pm_domain) {
|
||||
err = clk_prepare_enable(pcie->pex_clk);
|
||||
if (err) {
|
||||
dev_err(dev, "failed to enable PEX clock: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
reset_control_deassert(pcie->pex_rst);
|
||||
} else {
|
||||
err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE,
|
||||
pcie->pex_clk,
|
||||
pcie->pex_rst);
|
||||
if (err) {
|
||||
dev_err(dev, "powerup sequence failed: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
reset_control_deassert(pcie->afi_rst);
|
||||
@ -1262,6 +1302,7 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
||||
struct device *dev = pcie->dev;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct resource *pads, *afi, *res;
|
||||
const struct tegra_pcie_soc *soc = pcie->soc;
|
||||
int err;
|
||||
|
||||
err = tegra_pcie_clocks_get(pcie);
|
||||
@ -1276,10 +1317,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = tegra_pcie_phys_get(pcie);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to get PHYs: %d\n", err);
|
||||
return err;
|
||||
if (soc->program_uphy) {
|
||||
err = tegra_pcie_phys_get(pcie);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to get PHYs: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = tegra_pcie_power_on(pcie);
|
||||
@ -1341,6 +1384,7 @@ poweroff:
|
||||
static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
const struct tegra_pcie_soc *soc = pcie->soc;
|
||||
int err;
|
||||
|
||||
if (pcie->irq > 0)
|
||||
@ -1348,9 +1392,11 @@ static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
|
||||
|
||||
tegra_pcie_power_off(pcie);
|
||||
|
||||
err = phy_exit(pcie->phy);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to teardown PHY: %d\n", err);
|
||||
if (soc->program_uphy) {
|
||||
err = phy_exit(pcie->phy);
|
||||
if (err < 0)
|
||||
dev_err(dev, "failed to teardown PHY: %d\n", err);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1616,8 +1662,32 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
|
||||
struct device *dev = pcie->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
|
||||
of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
|
||||
if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
|
||||
switch (lanes) {
|
||||
case 0x010004:
|
||||
dev_info(dev, "4x1, 1x1 configuration\n");
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_401;
|
||||
return 0;
|
||||
|
||||
case 0x010102:
|
||||
dev_info(dev, "2x1, 1X1, 1x1 configuration\n");
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
|
||||
return 0;
|
||||
|
||||
case 0x010101:
|
||||
dev_info(dev, "1x1, 1x1, 1x1 configuration\n");
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_111;
|
||||
return 0;
|
||||
|
||||
default:
|
||||
dev_info(dev, "wrong configuration updated in DT, "
|
||||
"switching to default 2x1, 1x1, 1x1 "
|
||||
"configuration\n");
|
||||
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_211;
|
||||
return 0;
|
||||
}
|
||||
} else if (of_device_is_compatible(np, "nvidia,tegra124-pcie") ||
|
||||
of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
|
||||
switch (lanes) {
|
||||
case 0x0000104:
|
||||
dev_info(dev, "4x1, 1x1 configuration\n");
|
||||
@ -1737,7 +1807,20 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
|
||||
struct device_node *np = dev->of_node;
|
||||
unsigned int i = 0;
|
||||
|
||||
if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
|
||||
if (of_device_is_compatible(np, "nvidia,tegra186-pcie")) {
|
||||
pcie->num_supplies = 4;
|
||||
|
||||
pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
|
||||
sizeof(*pcie->supplies),
|
||||
GFP_KERNEL);
|
||||
if (!pcie->supplies)
|
||||
return -ENOMEM;
|
||||
|
||||
pcie->supplies[i++].supply = "dvdd-pex";
|
||||
pcie->supplies[i++].supply = "hvdd-pex-pll";
|
||||
pcie->supplies[i++].supply = "hvdd-pex";
|
||||
pcie->supplies[i++].supply = "vddio-pexctl-aud";
|
||||
} else if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) {
|
||||
pcie->num_supplies = 6;
|
||||
|
||||
pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
|
||||
@ -2076,6 +2159,7 @@ static const struct tegra_pcie_soc tegra20_pcie = {
|
||||
.has_cml_clk = false,
|
||||
.has_gen2 = false,
|
||||
.force_pca_enable = false,
|
||||
.program_uphy = true,
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_soc tegra30_pcie = {
|
||||
@ -2091,6 +2175,7 @@ static const struct tegra_pcie_soc tegra30_pcie = {
|
||||
.has_cml_clk = true,
|
||||
.has_gen2 = false,
|
||||
.force_pca_enable = false,
|
||||
.program_uphy = true,
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_soc tegra124_pcie = {
|
||||
@ -2105,6 +2190,7 @@ static const struct tegra_pcie_soc tegra124_pcie = {
|
||||
.has_cml_clk = true,
|
||||
.has_gen2 = true,
|
||||
.force_pca_enable = false,
|
||||
.program_uphy = true,
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_soc tegra210_pcie = {
|
||||
@ -2119,9 +2205,27 @@ static const struct tegra_pcie_soc tegra210_pcie = {
|
||||
.has_cml_clk = true,
|
||||
.has_gen2 = true,
|
||||
.force_pca_enable = true,
|
||||
.program_uphy = true,
|
||||
};
|
||||
|
||||
static const struct tegra_pcie_soc tegra186_pcie = {
|
||||
.num_ports = 3,
|
||||
.msi_base_shift = 8,
|
||||
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
|
||||
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
|
||||
.pads_refclk_cfg0 = 0x80b880b8,
|
||||
.pads_refclk_cfg1 = 0x000480b8,
|
||||
.has_pex_clkreq_en = true,
|
||||
.has_pex_bias_ctrl = true,
|
||||
.has_intr_prsnt_sense = true,
|
||||
.has_cml_clk = false,
|
||||
.has_gen2 = true,
|
||||
.force_pca_enable = false,
|
||||
.program_uphy = false,
|
||||
};
|
||||
|
||||
static const struct of_device_id tegra_pcie_of_match[] = {
|
||||
{ .compatible = "nvidia,tegra186-pcie", .data = &tegra186_pcie },
|
||||
{ .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie },
|
||||
{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie },
|
||||
{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie },
|
||||
|
Loading…
Reference in New Issue
Block a user