aboutsummaryrefslogtreecommitdiff
path: root/sys/arm/nvidia/tegra_pcie.c
diff options
context:
space:
mode:
authorMichal Meloun <strejda@users.noreply.github.com>2018-01-04 11:50:12 +0000
committerMichal Meloun <mmel@FreeBSD.org>2020-12-26 18:13:10 +0000
commitb9cbd68d1cbbb21eade18182a797d5fa7d0dc110 (patch)
treea1c3742f0eadfb4587e352a93af0fdb5cee66a2e /sys/arm/nvidia/tegra_pcie.c
parent9bc6c7219a376f905f2ecd1f7fbfb42d17b93b49 (diff)
downloadsrc-b9cbd68d1cbbb21eade18182a797d5fa7d0dc110.tar.gz
src-b9cbd68d1cbbb21eade18182a797d5fa7d0dc110.zip
ARM: Enhance common Nvidia Tegra drivers by support for Tegra210 SoC.
MFC after: 4 weeks
Diffstat (limited to 'sys/arm/nvidia/tegra_pcie.c')
-rw-r--r--sys/arm/nvidia/tegra_pcie.c258
1 files changed, 132 insertions, 126 deletions
diff --git a/sys/arm/nvidia/tegra_pcie.c b/sys/arm/nvidia/tegra_pcie.c
index 710480c146cf..44eb682a40b4 100644
--- a/sys/arm/nvidia/tegra_pcie.c
+++ b/sys/arm/nvidia/tegra_pcie.c
@@ -179,28 +179,36 @@ __FBSDID("$FreeBSD$");
#define AFI_PEXBIAS_CTRL 0x168
-/* FPCI Address space */
-#define FPCI_MAP_IO 0xfdfc000000ULL
-#define FPCI_MAP_TYPE0_CONFIG 0xfdfc000000ULL
-#define FPCI_MAP_TYPE1_CONFIG 0xfdff000000ULL
-#define FPCI_MAP_EXT_TYPE0_CONFIG 0xfe00000000ULL
-#define FPCI_MAP_EXT_TYPE1_CONFIG 0xfe10000000ULL
-
/* Configuration space */
-#define RP_VEND_XP 0x00000F00
-#define RP_VEND_XP_DL_UP (1 << 30)
+#define RP_VEND_XP 0x0F00
+#define RP_VEND_XP_DL_UP (1 << 30)
+
+#define RP_VEND_CTL2 0x0fa8
+#define RP_VEND_CTL2_PCA_ENABLE (1 << 7)
+
+#define RP_PRIV_MISC 0x0FE0
+#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
+#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
-#define RP_PRIV_MISC 0x00000FE0
-#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
-#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
+#define RP_LINK_CONTROL_STATUS 0x0090
+#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
+#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
+
+/* PADS space */
+#define PADS_REFCLK_CFG0 0x000c8
+#define PADS_REFCLK_CFG1 0x000cc
-#define RP_LINK_CONTROL_STATUS 0x00000090
-#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
-#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
/* Wait 50 ms (per port) for link. */
#define TEGRA_PCIE_LINKUP_TIMEOUT 50000
+/* FPCI Address space */
+#define FPCI_MAP_IO 0xFDFC000000ULL
+#define FPCI_MAP_TYPE0_CONFIG 0xFDFC000000ULL
+#define FPCI_MAP_TYPE1_CONFIG 0xFDFF000000ULL
+#define FPCI_MAP_EXT_TYPE0_CONFIG 0xFE00000000ULL
+#define FPCI_MAP_EXT_TYPE1_CONFIG 0xFE10000000ULL
+
#define TEGRA_PCIB_MSI_ENABLE
#define DEBUG
@@ -224,7 +232,7 @@ __FBSDID("$FreeBSD$");
#define PCI_CFG_FUN(fun) (((fun) & 0x07) << 8)
#define PCI_CFG_BASE_REG(reg) ((reg) & 0xff)
-#define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)-pads_mem_res, (_r), (_v))
+#define PADS_WR4(_sc, _r, _v) bus_write_4((_sc)->pads_mem_res, (_r), (_v))
#define PADS_RD4(_sc, _r) bus_read_4((_sc)->pads_mem_res, (_r))
#define AFI_WR4(_sc, _r, _v) bus_write_4((_sc)->afi_mem_res, (_r), (_v))
#define AFI_RD4(_sc, _r) bus_read_4((_sc)->afi_mem_res, (_r))
@@ -246,10 +254,57 @@ static struct {
{AFI_MSI_AXI_BAR_ST, AFI_MSI_FPCI_BAR_ST, AFI_MSI_BAR_SZ}, /* MSI 9 */
};
+
+struct pcie_soc {
+ char **regulator_names;
+ bool cml_clk;
+ bool pca_enable;
+ uint32_t pads_refclk_cfg0;
+ uint32_t pads_refclk_cfg1;
+};
+
+/* Tegra 124 config. */
+static char *tegra124_reg_names[] = {
+ "avddio-pex-supply",
+ "dvddio-pex-supply",
+ "avdd-pex-pll-supply",
+ "hvdd-pex-supply",
+ "hvdd-pex-pll-e-supply",
+ "vddio-pex-ctl-supply",
+ "avdd-pll-erefe-supply",
+ NULL
+};
+
+static struct pcie_soc tegra124_soc = {
+ .regulator_names = tegra124_reg_names,
+ .cml_clk = true,
+ .pca_enable = false,
+ .pads_refclk_cfg0 = 0x44ac44ac,
+};
+
+/* Tegra 210 config. */
+static char *tegra210_reg_names[] = {
+ "avdd-pll-uerefe-supply",
+ "hvddio-pex-supply",
+ "dvddio-pex-supply",
+ "dvdd-pex-pll-supply",
+ "hvdd-pex-pll-e-supply",
+ "vddio-pex-ctl-supply",
+ NULL
+};
+
+static struct pcie_soc tegra210_soc = {
+ .regulator_names = tegra210_reg_names,
+ .cml_clk = true,
+ .pca_enable = true,
+ .pads_refclk_cfg0 = 0x90b890b8,
+};
+
/* Compatible devices. */
static struct ofw_compat_data compat_data[] = {
- {"nvidia,tegra124-pcie", 1},
- {NULL, 0},
+ {"nvidia,tegra124-pcie", (uintptr_t)&tegra124_soc},
+ {"nvidia,tegra210-pcie", (uintptr_t)&tegra210_soc},
+ {NULL, 0},
};
#define TEGRA_FLAG_MSI_USED 0x0001
@@ -277,6 +332,7 @@ struct tegra_pcib_port {
struct tegra_pcib_softc {
struct ofw_pci_softc ofw_pci;
device_t dev;
+ struct pcie_soc *soc;
struct mtx mtx;
struct resource *pads_mem_res;
struct resource *afi_mem_res;
@@ -297,13 +353,7 @@ struct tegra_pcib_softc {
hwreset_t hwreset_pex;
hwreset_t hwreset_afi;
hwreset_t hwreset_pcie_x;
- regulator_t supply_avddio_pex;
- regulator_t supply_dvddio_pex;
- regulator_t supply_avdd_pex_pll;
- regulator_t supply_hvdd_pex;
- regulator_t supply_hvdd_pex_pll_e;
- regulator_t supply_vddio_pex_ctl;
- regulator_t supply_avdd_pll_erefe;
+ regulator_t regulators[16]; /* Safe maximum */
vm_offset_t msi_page; /* VA of MSI page */
bus_addr_t cfg_base_addr; /* base address of config */
@@ -801,7 +851,7 @@ tegra_pcib_pex_ctrl(struct tegra_pcib_softc *sc, int port)
static int
tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc)
{
- int rv;
+ int i, rv;
rv = hwreset_assert(sc->hwreset_pcie_x);
if (rv != 0) {
@@ -821,48 +871,17 @@ tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc)
tegra_powergate_power_off(TEGRA_POWERGATE_PCX);
- /* Power supplies. */
- rv = regulator_enable(sc->supply_avddio_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'avddio_pex' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_dvddio_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'dvddio_pex' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_avdd_pex_pll);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'avdd-pex-pll' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_hvdd_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'hvdd-pex-supply' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_hvdd_pex_pll_e);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'hvdd-pex-pll-e-supply' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_vddio_pex_ctl);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'vddio-pex-ctl' regulator\n");
- return (rv);
- }
- rv = regulator_enable(sc->supply_avdd_pll_erefe);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot enable 'avdd-pll-erefe-supply' regulator\n");
- return (rv);
+ /* Regulators. */
+ for (i = 0; i < nitems(sc->regulators); i++) {
+ if (sc->regulators[i] == NULL)
+ continue;
+ rv = regulator_enable(sc->regulators[i]);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot enable '%s' regulator\n",
+ sc->soc->regulator_names[i]);
+ return (rv);
+ }
}
rv = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCX,
@@ -883,16 +902,19 @@ tegra_pcib_enable_fdt_resources(struct tegra_pcib_softc *sc)
device_printf(sc->dev, "Cannot enable 'afi' clock\n");
return (rv);
}
- rv = clk_enable(sc->clk_cml);
- if (rv != 0) {
- device_printf(sc->dev, "Cannot enable 'cml' clock\n");
- return (rv);
+ if (sc->soc->cml_clk) {
+ rv = clk_enable(sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot enable 'cml' clock\n");
+ return (rv);
+ }
}
rv = clk_enable(sc->clk_pll_e);
if (rv != 0) {
device_printf(sc->dev, "Cannot enable 'pll_e' clock\n");
return (rv);
}
+
return (0);
}
@@ -975,57 +997,23 @@ tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node)
{
phandle_t child;
struct tegra_pcib_port *port;
- int rv;
+ int i, rv;
- /* Power supplies. */
- rv = regulator_get_by_ofw_property(sc->dev, 0, "avddio-pex-supply",
- &sc->supply_avddio_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'avddio-pex' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "dvddio-pex-supply",
- &sc->supply_dvddio_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'dvddio-pex' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "avdd-pex-pll-supply",
- &sc->supply_avdd_pex_pll);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'avdd-pex-pll' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "hvdd-pex-supply",
- &sc->supply_hvdd_pex);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'hvdd-pex' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "hvdd-pex-pll-e-supply",
- &sc->supply_hvdd_pex_pll_e);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'hvdd-pex-pll-e' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "vddio-pex-ctl-supply",
- &sc->supply_vddio_pex_ctl);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'vddio-pex-ctl' regulator\n");
- return (ENXIO);
- }
- rv = regulator_get_by_ofw_property(sc->dev, 0, "avdd-pll-erefe-supply",
- &sc->supply_avdd_pll_erefe);
- if (rv != 0) {
- device_printf(sc->dev,
- "Cannot get 'avdd-pll-erefe' regulator\n");
- return (ENXIO);
+ /* Regulators. */
+ for (i = 0; sc->soc->regulator_names[i] != NULL; i++) {
+ if (i >= nitems(sc->regulators)) {
+ device_printf(sc->dev,
+ "Too many regulators present in DT.\n");
+ return (EOVERFLOW);
+ }
+ rv = regulator_get_by_ofw_property(sc->dev, 0,
+ sc->soc->regulator_names[i], sc->regulators + i);
+ if (rv != 0) {
+ device_printf(sc->dev,
+ "Cannot get '%s' regulator\n",
+ sc->soc->regulator_names[i]);
+ return (ENXIO);
+ }
}
/* Resets. */
@@ -1061,10 +1049,12 @@ tegra_pcib_parse_fdt_resources(struct tegra_pcib_softc *sc, phandle_t node)
device_printf(sc->dev, "Cannot get 'pll_e' clock\n");
return (ENXIO);
}
- rv = clk_get_by_ofw_name(sc->dev, 0, "cml", &sc->clk_cml);
- if (rv != 0) {
- device_printf(sc->dev, "Cannot get 'cml' clock\n");
- return (ENXIO);
+ if (sc->soc->cml_clk) {
+ rv = clk_get_by_ofw_name(sc->dev, 0, "cml", &sc->clk_cml);
+ if (rv != 0) {
+ device_printf(sc->dev, "Cannot get 'cml' clock\n");
+ return (ENXIO);
+ }
}
/* Ports */
@@ -1196,6 +1186,14 @@ tegra_pcib_port_enable(struct tegra_pcib_softc *sc, int port_num)
reg |= AFI_PEX_CTRL_RST_L;
AFI_WR4(sc, port->afi_pex_ctrl, reg);
+ if (sc->soc->pca_enable) {
+ reg = tegra_pcib_read_config(sc->dev, 0, port->port_idx, 0,
+ RP_VEND_CTL2, 4);
+ reg |= RP_VEND_CTL2_PCA_ENABLE;
+ tegra_pcib_write_config(sc->dev, 0, port->port_idx, 0,
+ RP_VEND_CTL2, reg, 4);
+ }
+
rv = tegra_pcib_wait_for_link(sc, port);
if (bootverbose)
device_printf(sc->dev, " port %d (%d lane%s): Link is %s\n",
@@ -1259,6 +1257,7 @@ tegra_pcib_enable(struct tegra_pcib_softc *sc)
device_printf(sc->dev, "Cannot enable FDT resources\n");
return (rv);
}
+
/* Enable PLLE control. */
reg = AFI_RD4(sc, AFI_PLLE_CONTROL);
reg &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
@@ -1310,6 +1309,11 @@ tegra_pcib_enable(struct tegra_pcib_softc *sc)
}
}
+ /* Configure PCIe reference clock */
+ PADS_WR4(sc, PADS_REFCLK_CFG0, sc->soc->pads_refclk_cfg0);
+ if (sc->num_ports > 2)
+ PADS_WR4(sc, PADS_REFCLK_CFG1, sc->soc->pads_refclk_cfg1);
+
rv = hwreset_deassert(sc->hwreset_pcie_x);
if (rv != 0) {
device_printf(sc->dev, "Cannot unreset 'pci_x' reset\n");
@@ -1449,6 +1453,8 @@ tegra_pcib_attach(device_t dev)
mtx_init(&sc->mtx, "msi_mtx", NULL, MTX_DEF);
node = ofw_bus_get_node(dev);
+ sc->soc = (struct pcie_soc *)ofw_bus_search_compatible(dev,
+ compat_data)->ocd_data;
rv = tegra_pcib_parse_fdt_resources(sc, node);
if (rv != 0) {