diff options
author | Michal Meloun <strejda@users.noreply.github.com> | 2018-01-04 11:50:12 +0000 |
---|---|---|
committer | Michal Meloun <mmel@FreeBSD.org> | 2020-12-26 18:13:10 +0000 |
commit | b9cbd68d1cbbb21eade18182a797d5fa7d0dc110 (patch) | |
tree | a1c3742f0eadfb4587e352a93af0fdb5cee66a2e /sys/arm/nvidia/tegra_pcie.c | |
parent | 9bc6c7219a376f905f2ecd1f7fbfb42d17b93b49 (diff) | |
download | src-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.c | 258 |
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) { |