summaryrefslogtreecommitdiff
path: root/sys/dev/fdt/dwpcie.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/fdt/dwpcie.c')
-rw-r--r--sys/dev/fdt/dwpcie.c504
1 files changed, 427 insertions, 77 deletions
diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c
index 9509b49787f..cd4ed5c4714 100644
--- a/sys/dev/fdt/dwpcie.c
+++ b/sys/dev/fdt/dwpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dwpcie.c,v 1.11 2018/08/22 21:15:53 kettenis Exp $ */
+/* $OpenBSD: dwpcie.c,v 1.12 2019/01/11 08:03:24 patrick Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -32,24 +32,50 @@
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
+#include <dev/ofw/ofw_gpio.h>
+#include <dev/ofw/ofw_misc.h>
#include <dev/ofw/ofw_pinctrl.h>
+#include <dev/ofw/ofw_power.h>
#include <dev/ofw/fdt.h>
/* Registers */
+#define PCIE_PORT_LINK_CTRL 0x710
+#define PCIE_PORT_LINK_CTRL_LANES_MASK (0x3f << 16)
+#define PCIE_PORT_LINK_CTRL_LANES_1 (0x1 << 16)
+#define PCIE_PORT_LINK_CTRL_LANES_2 (0x3 << 16)
+#define PCIE_PORT_LINK_CTRL_LANES_4 (0x7 << 16)
+#define PCIE_PORT_LINK_CTRL_LANES_8 (0xf << 16)
+#define PCIE_PHY_DEBUG_R1 0x72c
+#define PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING (1 << 29)
+#define PCIE_PHY_DEBUG_R1_XMLH_LINK_UP (1 << 4)
+#define PCIE_LINK_WIDTH_SPEED_CTRL 0x80c
+#define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK (0x1f << 8)
+#define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1 (0x1 << 8)
+#define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2 (0x2 << 8)
+#define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4 (0x4 << 8)
+#define PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8 (0x8 << 8)
+#define PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE (1 << 17)
+
#define MISC_CONTROL_1 0x8bc
#define MISC_CONTROL_1_DBI_RO_WR_EN (1 << 0)
#define IATU_VIEWPORT 0x900
-#define IATU_REGION_CTRL_1 0x904
+#define IATU_VIEWPORT_INDEX0 0
+#define IATU_VIEWPORT_INDEX1 1
+#define IATU_VIEWPORT_INDEX2 2
+#define IATU_OFFSET_VIEWPORT 0x904
+#define IATU_OFFSET_UNROLL(x) (0x200 * (x))
+#define IATU_REGION_CTRL_1 0x000
+#define IATU_REGION_CTRL_1_TYPE_MEM 0
#define IATU_REGION_CTRL_1_TYPE_IO 2
#define IATU_REGION_CTRL_1_TYPE_CFG0 4
#define IATU_REGION_CTRL_1_TYPE_CFG1 5
-#define IATU_REGION_CTRL_2 0x908
+#define IATU_REGION_CTRL_2 0x004
#define IATU_REGION_CTRL_2_REGION_EN (1U << 31)
-#define IATU_LWR_BASE_ADDR 0x90c
-#define IATU_UPPER_BASE_ADDR 0x910
-#define IATU_LIMIT_ADDR 0x914
-#define IATU_LWR_TARGET_ADDR 0x918
-#define IATU_UPPER_TARGET_ADDR 0x91c
+#define IATU_LWR_BASE_ADDR 0x08
+#define IATU_UPPER_BASE_ADDR 0x0c
+#define IATU_LIMIT_ADDR 0x10
+#define IATU_LWR_TARGET_ADDR 0x14
+#define IATU_UPPER_TARGET_ADDR 0x18
#define PCIE_GLOBAL_CTRL 0x8000
#define PCIE_GLOBAL_CTRL_APP_LTSSM_EN (1 << 2)
@@ -75,6 +101,32 @@
#define PCIE_AXUSER_DOMAIN_INNER_SHARABLE (0x1 << 4)
#define PCIE_AXUSER_DOMAIN_OUTER_SHARABLE (0x2 << 4)
+/* i.MX8MQ registers */
+#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_LCR_L1EL_MASK (0x7 << 15)
+#define PCIE_RC_LCR_L1EL_64US (0x6 << 15)
+
+#define IOMUXC_GPR12 0x30
+#define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK (0xf << 8)
+#define IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC (0x4 << 8)
+#define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK (0xf << 12)
+#define IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC (0x4 << 12)
+#define IOMUXC_GPR14 0x38
+#define IOMUXC_GPR16 0x40
+#define IMX8MQ_GPR_PCIE_REF_USE_PAD (1 << 9)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE_EN (1 << 10)
+#define IMX8MQ_GPR_PCIE_CLK_REQ_OVERRIDE (1 << 11)
+
+#define ANATOP_PLLOUT_CTL 0x74
+#define ANATOP_PLLOUT_CTL_CKE (1 << 4)
+#define ANATOP_PLLOUT_CTL_SEL_SYSPLL1 0xb
+#define ANATOP_PLLOUT_CTL_SEL_MASK 0xf
+#define ANATOP_PLLOUT_DIV 0x7c
+#define ANATOP_PLLOUT_DIV_SYSPLL1 0x7
+
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
@@ -95,9 +147,19 @@ struct dwpcie_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
- bus_space_handle_t sc_cfg_ioh;
- bus_addr_t sc_cfg_addr;
- bus_size_t sc_cfg_size;
+ bus_space_handle_t sc_cfg0_ioh;
+ bus_space_handle_t sc_cfg1_ioh;
+
+ bus_addr_t sc_cfg0_base;
+ bus_size_t sc_cfg0_size;
+ bus_addr_t sc_cfg1_base;
+ bus_size_t sc_cfg1_size;
+ bus_addr_t sc_io_base;
+ bus_addr_t sc_io_bus_addr;
+ bus_size_t sc_io_size;
+ bus_addr_t sc_mem_base;
+ bus_addr_t sc_mem_bus_addr;
+ bus_size_t sc_mem_size;
int sc_node;
int sc_acells;
@@ -113,6 +175,10 @@ struct dwpcie_softc {
struct arm64_pci_chipset sc_pc;
int sc_bus;
+ int sc_num_viewport;
+ bus_addr_t sc_atu_base;
+ int sc_atu_unroll;
+
void *sc_ih;
};
@@ -132,13 +198,22 @@ dwpcie_match(struct device *parent, void *match, void *aux)
{
struct fdt_attach_args *faa = aux;
- return OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie");
+ return (OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie") ||
+ OF_is_compatible(faa->fa_node, "fsl,imx8mq-pcie"));
}
+void dwpcie_atu_config(struct dwpcie_softc *, int, int,
+ uint64_t, uint64_t, uint64_t);
+void dwpcie_link_config(struct dwpcie_softc *);
+int dwpcie_link_up(struct dwpcie_softc *);
+
void dwpcie_armada8k_init(struct dwpcie_softc *);
int dwpcie_armada8k_link_up(struct dwpcie_softc *);
int dwpcie_armada8k_intr(void *);
+void dwpcie_imx8mq_init(struct dwpcie_softc *);
+int dwpcie_imx8mq_intr(void *);
+
void dwpcie_attach_hook(struct device *, struct device *,
struct pcibus_attach_args *);
int dwpcie_bus_maxdevs(void *, int);
@@ -238,23 +313,68 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
return;
}
- if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
- faa->fa_reg[1].size, 0, &sc->sc_cfg_ioh)) {
+ sc->sc_cfg0_base = faa->fa_reg[1].addr;
+ sc->sc_cfg0_size = faa->fa_reg[1].size / 2;
+ sc->sc_cfg0_base = faa->fa_reg[1].addr + sc->sc_cfg0_size;
+ sc->sc_cfg1_size = sc->sc_cfg0_size;
+
+ if (bus_space_map(sc->sc_iot, sc->sc_cfg0_base,
+ sc->sc_cfg1_size, 0, &sc->sc_cfg0_ioh)) {
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
+ printf(": can't map config registers\n");
+ return;
+ }
+
+ if (bus_space_map(sc->sc_iot, sc->sc_cfg1_base,
+ sc->sc_cfg1_size, 0, &sc->sc_cfg1_ioh)) {
+ bus_space_unmap(sc->sc_iot, sc->sc_cfg0_ioh, sc->sc_cfg0_size);
bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
printf(": can't map config registers\n");
return;
}
- sc->sc_cfg_addr = faa->fa_reg[1].addr;
- sc->sc_cfg_size = faa->fa_reg[1].size;
+
+ sc->sc_num_viewport = OF_getpropint(sc->sc_node, "num-viewport", 2);
printf("\n");
pinctrl_byname(sc->sc_node, "default");
- clock_enable_all(sc->sc_node);
+ clock_set_assigned(sc->sc_node);
if (OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie"))
dwpcie_armada8k_init(sc);
+ if (OF_is_compatible(sc->sc_node, "fsl,imx8mq-pcie"))
+ dwpcie_imx8mq_init(sc);
+
+ if (HREAD4(sc, IATU_VIEWPORT) == 0xffffffff) {
+ sc->sc_atu_base = 0x300000;
+ sc->sc_atu_unroll = 1;
+ }
+
+ /* Set up address translation for I/O space. */
+ sc->sc_io_bus_addr = sc->sc_mem_bus_addr = -1;
+ for (i = 0; i < sc->sc_nranges; i++) {
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
+ sc->sc_ranges[i].size > 0) {
+ sc->sc_io_base = sc->sc_ranges[i].phys_base;
+ sc->sc_io_bus_addr = sc->sc_ranges[i].pci_base;
+ sc->sc_io_size = sc->sc_ranges[i].size;
+ }
+ if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
+ sc->sc_ranges[i].size > 0) {
+ sc->sc_mem_base = sc->sc_ranges[i].phys_base;
+ sc->sc_mem_bus_addr = sc->sc_ranges[i].pci_base;
+ sc->sc_mem_size = sc->sc_ranges[i].size;
+ }
+ }
+
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX0,
+ IATU_REGION_CTRL_1_TYPE_MEM, sc->sc_mem_base,
+ sc->sc_mem_bus_addr, sc->sc_mem_size);
+ if (sc->sc_num_viewport > 2)
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX2,
+ IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
+ sc->sc_io_bus_addr, sc->sc_io_size);
/* Enable modification of read-only bits. */
HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
@@ -286,23 +406,9 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
bir |= (bus_range[1] << 16);
HWRITE4(sc, PPB_REG_BUSINFO, bir);
- /* Set up I/O and memory mapped I/O ranges. */
- iobase = 0xffff; iolimit = 0;
- membase = 0xffffffff; memlimit = 0;
- for (i = 0; i < sc->sc_nranges; i++) {
- if ((sc->sc_ranges[i].flags & 0x03000000) == 0x01000000 &&
- sc->sc_ranges[i].size > 0) {
- iobase = sc->sc_ranges[i].pci_base;
- iolimit = iobase + sc->sc_ranges[i].size - 1;
- }
- if ((sc->sc_ranges[i].flags & 0x03000000) == 0x02000000 &&
- sc->sc_ranges[i].size > 0) {
- membase = sc->sc_ranges[i].pci_base;
- memlimit = membase + sc->sc_ranges[i].size - 1;
- }
- }
-
/* Initialize I/O window. */
+ iobase = sc->sc_io_bus_addr;
+ iolimit = iobase + sc->sc_io_size - 1;
blr = iolimit & PPB_IO_MASK;
blr |= (iobase >> PPB_IO_SHIFT);
HWRITE4(sc, PPB_REG_IOSTATUS, blr);
@@ -311,6 +417,8 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
HWRITE4(sc, PPB_REG_IO_HI, blr);
/* Initialize memory mapped I/O window. */
+ membase = sc->sc_mem_bus_addr;
+ memlimit = membase + sc->sc_mem_size - 1;
blr = memlimit & PPB_MEM_MASK;
blr |= (membase >> PPB_MEM_SHIFT);
HWRITE4(sc, PPB_REG_MEM, blr);
@@ -359,16 +467,66 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
pba.pba_pc = &sc->sc_pc;
pba.pba_domain = pci_ndomains++;
pba.pba_bus = sc->sc_bus;
- pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
+ if (OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie"))
+ pba.pba_flags |= PCI_FLAGS_MSI_ENABLED;
config_found(self, &pba, NULL);
}
void
+dwpcie_link_config(struct dwpcie_softc *sc)
+{
+ uint32_t mode, width, reg;
+ int lanes;
+
+ lanes = OF_getpropint(sc->sc_node, "num-lanes", 0);
+
+ switch (lanes) {
+ case 1:
+ mode = PCIE_PORT_LINK_CTRL_LANES_1;
+ width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_1;
+ break;
+ case 2:
+ mode = PCIE_PORT_LINK_CTRL_LANES_2;
+ width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_2;
+ break;
+ case 4:
+ mode = PCIE_PORT_LINK_CTRL_LANES_4;
+ width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_4;
+ break;
+ case 8:
+ mode = PCIE_PORT_LINK_CTRL_LANES_8;
+ width = PCIE_LINK_WIDTH_SPEED_CTRL_LANES_8;
+ break;
+ default:
+ printf("%s: %d lanes not supported\n", __func__, lanes);
+ return;
+ }
+
+ reg = HREAD4(sc, PCIE_PORT_LINK_CTRL);
+ reg &= ~PCIE_PORT_LINK_CTRL_LANES_MASK;
+ reg |= mode;
+ HWRITE4(sc, PCIE_PORT_LINK_CTRL, reg);
+
+ reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL);
+ reg &= ~PCIE_LINK_WIDTH_SPEED_CTRL_LANES_MASK;
+ reg |= width;
+ HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg);
+
+ reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL);
+ reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE;
+ HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg);
+}
+
+void
dwpcie_armada8k_init(struct dwpcie_softc *sc)
{
- int i, timo, viewport = 0;
uint32_t reg;
+ int timo;
+
+ clock_enable_all(sc->sc_node);
+
+ dwpcie_link_config(sc);
if (!dwpcie_armada8k_link_up(sc)) {
reg = HREAD4(sc, PCIE_GLOBAL_CTRL);
@@ -393,34 +551,6 @@ dwpcie_armada8k_init(struct dwpcie_softc *sc)
reg |= PCIE_AXUSER_DOMAIN_OUTER_SHARABLE;
HWRITE4(sc, PCIE_AWUSER, reg);
- /* Set up addres translation for PCI confg space. */
- HWRITE4(sc, IATU_VIEWPORT, viewport++);
- HWRITE4(sc, IATU_LWR_BASE_ADDR, sc->sc_cfg_addr);
- HWRITE4(sc, IATU_UPPER_BASE_ADDR, sc->sc_cfg_addr >> 32);
- HWRITE4(sc, IATU_LIMIT_ADDR, sc->sc_cfg_addr + sc->sc_cfg_size - 1);
- HWRITE4(sc, IATU_LWR_TARGET_ADDR, 0);
- HWRITE4(sc, IATU_UPPER_TARGET_ADDR, 0);
- HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN);
-
- /* Set up address translation for I/O space. */
- for (i = 0; i < sc->sc_nranges; i++) {
- if ((sc->sc_ranges[i].flags & 0x03000000) != 0x01000000)
- continue;
- HWRITE4(sc, IATU_VIEWPORT, viewport++);
- HWRITE4(sc, IATU_LWR_BASE_ADDR,
- sc->sc_ranges[i].phys_base);
- HWRITE4(sc, IATU_UPPER_BASE_ADDR,
- sc->sc_ranges[i].phys_base >> 32);
- HWRITE4(sc, IATU_LIMIT_ADDR,
- sc->sc_ranges[i].phys_base + sc->sc_ranges[i].size - 1);
- HWRITE4(sc, IATU_LWR_TARGET_ADDR,
- sc->sc_ranges[i].pci_base);
- HWRITE4(sc, IATU_UPPER_TARGET_ADDR,
- sc->sc_ranges[i].pci_base >> 32);
- HWRITE4(sc, IATU_REGION_CTRL_1, IATU_REGION_CTRL_1_TYPE_IO);
- HWRITE4(sc, IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN);
- }
-
if (!dwpcie_armada8k_link_up(sc)) {
reg = HREAD4(sc, PCIE_GLOBAL_CTRL);
reg |= PCIE_GLOBAL_CTRL_APP_LTSSM_EN;
@@ -468,11 +598,208 @@ dwpcie_armada8k_intr(void *arg)
}
void
-dwpcie_atu_config(struct dwpcie_softc *sc, pcitag_t tag, int type)
+dwpcie_imx8mq_init(struct dwpcie_softc *sc)
{
- HWRITE4(sc, IATU_VIEWPORT, 0);
- HWRITE4(sc, IATU_REGION_CTRL_1, type);
- HWRITE4(sc, IATU_LWR_TARGET_ADDR, tag);
+ uint32_t *clkreq_gpio, *disable_gpio, *reset_gpio;
+ ssize_t clkreq_gpiolen, disable_gpiolen, reset_gpiolen;
+ struct regmap *anatop, *gpc, *gpr;
+ uint32_t off, reg;
+ int timo;
+
+ anatop = regmap_bycompatible("fsl,imx8mq-anatop");
+ gpc = regmap_bycompatible("fsl,imx8mq-gpc");
+ gpr = regmap_bycompatible("fsl,imx8mq-iomuxc-gpr");
+ KASSERT(anatop != NULL);
+ KASSERT(gpc != NULL);
+ KASSERT(gpr != NULL);
+
+ clkreq_gpiolen = OF_getproplen(sc->sc_node, "clkreq-gpio");
+ disable_gpiolen = OF_getproplen(sc->sc_node, "disable-gpio");
+ reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpio");
+
+ if (clkreq_gpiolen > 0) {
+ clkreq_gpio = malloc(clkreq_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "clkreq-gpio", clkreq_gpio,
+ clkreq_gpiolen);
+ gpio_controller_config_pin(clkreq_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(clkreq_gpio, 1);
+ }
+
+ if (disable_gpiolen > 0) {
+ disable_gpio = malloc(disable_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "disable-gpio", disable_gpio,
+ disable_gpiolen);
+ gpio_controller_config_pin(disable_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(disable_gpio, 0);
+ }
+
+ if (reset_gpiolen > 0) {
+ reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "reset-gpio", reset_gpio,
+ reset_gpiolen);
+ gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(reset_gpio, 1);
+ }
+
+ power_domain_enable(sc->sc_node);
+ reset_assert(sc->sc_node, "pciephy");
+ reset_assert(sc->sc_node, "apps");
+
+ reg = regmap_read_4(gpr, IOMUXC_GPR12);
+ if (OF_getpropint(sc->sc_node, "ctrl-id", 0) == 0) {
+ off = IOMUXC_GPR14;
+ reg &= ~IMX8MQ_GPR_PCIE1_DEVICE_TYPE_MASK;
+ reg |= IMX8MQ_GPR_PCIE1_DEVICE_TYPE_RC;
+ } else {
+ off = IOMUXC_GPR16;
+ reg &= ~IMX8MQ_GPR_PCIE2_DEVICE_TYPE_MASK;
+ reg |= IMX8MQ_GPR_PCIE2_DEVICE_TYPE_RC;
+ }
+ regmap_write_4(gpr, IOMUXC_GPR12, reg);
+
+ if (OF_getproplen(sc->sc_node, "ext_osc") == 0) {
+ reg = regmap_read_4(gpr, off);
+ reg |= IMX8MQ_GPR_PCIE_REF_USE_PAD;
+ regmap_write_4(gpr, off, reg);
+ } else {
+ reg = regmap_read_4(gpr, off);
+ reg &= ~IMX8MQ_GPR_PCIE_REF_USE_PAD;
+ regmap_write_4(gpr, off, reg);
+
+ regmap_write_4(anatop, ANATOP_PLLOUT_CTL,
+ ANATOP_PLLOUT_CTL_CKE | ANATOP_PLLOUT_CTL_SEL_SYSPLL1);
+ regmap_write_4(anatop, ANATOP_PLLOUT_DIV,
+ ANATOP_PLLOUT_DIV_SYSPLL1);
+ }
+
+ clock_enable(sc->sc_node, "pcie_phy");
+ clock_enable(sc->sc_node, "pcie_bus");
+ clock_enable(sc->sc_node, "pcie");
+
+ /* Allow clocks to stabilize. */
+ delay(200);
+
+ if (reset_gpiolen > 0) {
+ gpio_controller_set_pin(reset_gpio, 1);
+ delay(20000);
+ gpio_controller_set_pin(reset_gpio, 0);
+ delay(20000);
+ }
+
+ reset_deassert(sc->sc_node, "pciephy");
+
+ reg = HREAD4(sc, 0x100000 + PCIE_RC_LCR);
+ reg &= ~PCIE_RC_LCR_L1EL_MASK;
+ reg |= PCIE_RC_LCR_L1EL_64US;
+ HWRITE4(sc, 0x100000 + PCIE_RC_LCR, reg);
+
+ dwpcie_link_config(sc);
+
+ reg = HREAD4(sc, PCIE_RC_LCR);
+ reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
+ reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN1;
+ HWRITE4(sc, PCIE_RC_LCR, reg);
+
+ reset_deassert(sc->sc_node, "apps");
+
+ for (timo = 20000; timo > 0; timo--) {
+ if (dwpcie_link_up(sc))
+ break;
+ delay(10);
+ }
+ if (timo == 0)
+ printf("%s:%d: timeout\n", __func__, __LINE__);
+
+ if (OF_getpropint(sc->sc_node, "fsl,max-link-speed", 1) >= 2) {
+ reg = HREAD4(sc, PCIE_RC_LCR);
+ reg &= ~PCIE_RC_LCR_MAX_LINK_SPEEDS_MASK;
+ reg |= PCIE_RC_LCR_MAX_LINK_SPEEDS_GEN2;
+ HWRITE4(sc, PCIE_RC_LCR, reg);
+
+ reg = HREAD4(sc, PCIE_LINK_WIDTH_SPEED_CTRL);
+ reg |= PCIE_LINK_WIDTH_SPEED_CTRL_CHANGE;
+ HWRITE4(sc, PCIE_LINK_WIDTH_SPEED_CTRL, reg);
+
+ for (timo = 20000; timo > 0; timo--) {
+ if (dwpcie_link_up(sc))
+ break;
+ delay(10);
+ }
+ if (timo == 0)
+ printf("%s:%d: timeout\n", __func__, __LINE__);
+ }
+
+ sc->sc_ih = fdt_intr_establish(sc->sc_node, IPL_AUDIO | IPL_MPSAFE,
+ dwpcie_imx8mq_intr, sc, sc->sc_dev.dv_xname);
+
+ /* Unmask INTx interrupts. */
+ HWRITE4(sc, PCIE_GLOBAL_INT_MASK,
+ PCIE_GLOBAL_INT_MASK_INT_A | PCIE_GLOBAL_INT_MASK_INT_B |
+ PCIE_GLOBAL_INT_MASK_INT_C | PCIE_GLOBAL_INT_MASK_INT_D);
+
+ if (clkreq_gpiolen > 0)
+ free(clkreq_gpio, M_TEMP, clkreq_gpiolen);
+ if (disable_gpiolen > 0)
+ free(disable_gpio, M_TEMP, disable_gpiolen);
+ if (reset_gpiolen > 0)
+ free(reset_gpio, M_TEMP, reset_gpiolen);
+}
+
+int
+dwpcie_imx8mq_intr(void *arg)
+{
+ struct dwpcie_softc *sc = arg;
+ uint32_t cause;
+
+ /* Acknowledge interrupts. */
+ cause = HREAD4(sc, PCIE_GLOBAL_INT_CAUSE);
+ HWRITE4(sc, PCIE_GLOBAL_INT_CAUSE, cause);
+
+ /* INTx interrupt, so not really ours. */
+ return 0;
+}
+
+void
+dwpcie_atu_config(struct dwpcie_softc *sc, int index, int type,
+ uint64_t cpu_addr, uint64_t pci_addr, uint64_t size)
+{
+ uint32_t reg, off;
+ int timo;
+
+ off = sc->sc_atu_base + IATU_OFFSET_UNROLL(index);
+ if (!sc->sc_atu_unroll) {
+ off = IATU_OFFSET_VIEWPORT;
+ HWRITE4(sc, IATU_VIEWPORT, index);
+ }
+
+ HWRITE4(sc, off + IATU_LWR_BASE_ADDR, cpu_addr);
+ HWRITE4(sc, off + IATU_UPPER_BASE_ADDR, cpu_addr >> 32);
+ HWRITE4(sc, off + IATU_LIMIT_ADDR, cpu_addr + size - 1);
+ HWRITE4(sc, off + IATU_LWR_TARGET_ADDR, pci_addr);
+ HWRITE4(sc, off + IATU_UPPER_TARGET_ADDR, pci_addr >> 32);
+ HWRITE4(sc, off + IATU_REGION_CTRL_1, type);
+ HWRITE4(sc, off + IATU_REGION_CTRL_2, IATU_REGION_CTRL_2_REGION_EN);
+
+ for (timo = 5; timo > 0; timo--) {
+ reg = HREAD4(sc, off + IATU_REGION_CTRL_2);
+ if (reg & IATU_REGION_CTRL_2_REGION_EN)
+ break;
+ delay(9000);
+ }
+ if (timo == 0)
+ printf("%s:%d: timeout\n", __func__, __LINE__);
+}
+
+int
+dwpcie_link_up(struct dwpcie_softc *sc)
+{
+ uint32_t reg;
+
+ reg = HREAD4(sc, PCIE_PHY_DEBUG_R1);
+ if ((reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_UP) != 0 &&
+ (reg & PCIE_PHY_DEBUG_R1_XMLH_LINK_IN_TRAINING) == 0)
+ return 1;
+ return 0;
}
void
@@ -519,6 +846,7 @@ dwpcie_conf_read(void *v, pcitag_t tag, int reg)
{
struct dwpcie_softc *sc = v;
int bus, dev, fn;
+ uint32_t ret;
dwpcie_decompose_tag(sc, tag, &bus, &dev, &fn);
if (bus == sc->sc_bus) {
@@ -526,11 +854,23 @@ dwpcie_conf_read(void *v, pcitag_t tag, int reg)
return HREAD4(sc, tag | reg);
}
- if (bus == sc->sc_bus + 1)
- dwpcie_atu_config(sc, tag, IATU_REGION_CTRL_1_TYPE_CFG0);
- else
- dwpcie_atu_config(sc, tag, IATU_REGION_CTRL_1_TYPE_CFG1);
- return bus_space_read_4(sc->sc_iot, sc->sc_cfg_ioh, reg);
+ if (bus == sc->sc_bus + 1) {
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_CFG0,
+ sc->sc_cfg0_base, tag, sc->sc_cfg0_size);
+ ret = bus_space_read_4(sc->sc_iot, sc->sc_cfg0_ioh, reg);
+ } else {
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_CFG1,
+ sc->sc_cfg1_base, tag, sc->sc_cfg1_size);
+ ret = bus_space_read_4(sc->sc_iot, sc->sc_cfg1_ioh, reg);
+ }
+ if (sc->sc_num_viewport <= 2)
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
+ sc->sc_io_bus_addr, sc->sc_io_size);
+
+ return ret;
}
void
@@ -546,11 +886,21 @@ dwpcie_conf_write(void *v, pcitag_t tag, int reg, pcireg_t data)
return;
}
- if (bus == sc->sc_bus + 1)
- dwpcie_atu_config(sc, tag, IATU_REGION_CTRL_1_TYPE_CFG0);
- else
- dwpcie_atu_config(sc, tag, IATU_REGION_CTRL_1_TYPE_CFG1);
- bus_space_write_4(sc->sc_iot, sc->sc_cfg_ioh, reg, data);
+ if (bus == sc->sc_bus + 1) {
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_CFG0,
+ sc->sc_cfg0_base, tag, sc->sc_cfg0_size);
+ bus_space_write_4(sc->sc_iot, sc->sc_cfg0_ioh, reg, data);
+ } else {
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_CFG1,
+ sc->sc_cfg1_base, tag, sc->sc_cfg1_size);
+ bus_space_write_4(sc->sc_iot, sc->sc_cfg1_ioh, reg, data);
+ }
+ if (sc->sc_num_viewport <= 2)
+ dwpcie_atu_config(sc, IATU_VIEWPORT_INDEX1,
+ IATU_REGION_CTRL_1_TYPE_IO, sc->sc_io_base,
+ sc->sc_io_bus_addr, sc->sc_io_size);
}
struct dwpcie_intr_handle {