summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/dev/fdt/dwpcie.c130
1 files changed, 119 insertions, 11 deletions
diff --git a/sys/dev/fdt/dwpcie.c b/sys/dev/fdt/dwpcie.c
index bb6f1eb0eb8..07443c41211 100644
--- a/sys/dev/fdt/dwpcie.c
+++ b/sys/dev/fdt/dwpcie.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dwpcie.c,v 1.23 2020/12/22 12:59:05 kettenis Exp $ */
+/* $OpenBSD: dwpcie.c,v 1.24 2020/12/28 12:24:31 kettenis Exp $ */
/*
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -101,7 +101,16 @@
#define PCIE_AXUSER_DOMAIN_INNER_SHARABLE (0x1 << 4)
#define PCIE_AXUSER_DOMAIN_OUTER_SHARABLE (0x2 << 4)
-/* i.MX8MQ registers */
+/* Amlogic G12A registers */
+#define PCIE_CFG0 0x0000
+#define PCIE_CFG0_APP_LTSSM_EN (1 << 7)
+#define PCIE_STATUS12 0x0030
+#define PCIE_STATUS12_RDLH_LINK_UP (1 << 16)
+#define PCIE_STATUS12_LTSSM_MASK (0x1f << 10)
+#define PCIE_STATUS12_LTSSM_UP (0x11 << 10)
+#define PCIE_STATUS12_SMLH_LINK_UP (1 << 6)
+
+/* NXP 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
@@ -175,6 +184,11 @@ struct dwpcie_softc {
bus_size_t sc_cfg0_size;
bus_addr_t sc_cfg1_base;
bus_size_t sc_cfg1_size;
+
+ bus_addr_t sc_glue_base;
+ bus_size_t sc_glue_size;
+ bus_space_handle_t sc_glue_ioh;
+
bus_addr_t sc_io_base;
bus_addr_t sc_io_bus_addr;
bus_size_t sc_io_size;
@@ -219,7 +233,8 @@ 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, "amlogic,g12a-pcie") ||
+ OF_is_compatible(faa->fa_node, "marvell,armada8k-pcie") ||
OF_is_compatible(faa->fa_node, "fsl,imx8mm-pcie") ||
OF_is_compatible(faa->fa_node, "fsl,imx8mq-pcie"));
}
@@ -235,6 +250,9 @@ int dwpcie_armada8k_init(struct dwpcie_softc *);
int dwpcie_armada8k_link_up(struct dwpcie_softc *);
int dwpcie_armada8k_intr(void *);
+int dwpcie_g12a_init(struct dwpcie_softc *);
+int dwpcie_g12a_link_up(struct dwpcie_softc *);
+
int dwpcie_imx8mq_init(struct dwpcie_softc *);
int dwpcie_imx8mq_intr(void *);
@@ -265,12 +283,38 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
struct fdt_attach_args *faa = aux;
uint32_t *ranges;
int i, j, nranges, rangeslen;
+ int config, glue;
if (faa->fa_nreg < 2) {
printf(": no registers\n");
return;
}
+ sc->sc_ctrl_base = faa->fa_reg[0].addr;
+ sc->sc_ctrl_size = faa->fa_reg[0].size;
+
+ config = OF_getindex(faa->fa_node, "config", "reg-names");
+ if (config < 0 || config >= faa->fa_nreg) {
+ printf(": no config registers\n");
+ return;
+ }
+
+ sc->sc_cfg0_base = faa->fa_reg[config].addr;
+ sc->sc_cfg0_size = faa->fa_reg[config].size / 2;
+ sc->sc_cfg0_base = faa->fa_reg[config].addr + sc->sc_cfg0_size;
+ sc->sc_cfg1_size = sc->sc_cfg0_size;
+
+ if (OF_is_compatible(faa->fa_node, "amlogic,g12a-pcie")) {
+ glue = OF_getindex(faa->fa_node, "cfg", "reg-names");
+ if (glue < 0 || glue >= faa->fa_nreg) {
+ printf(": no glue registers\n");
+ return;
+ }
+
+ sc->sc_glue_base = faa->fa_reg[glue].addr;
+ sc->sc_glue_size = faa->fa_reg[glue].size;
+ }
+
sc->sc_iot = faa->fa_iot;
sc->sc_dmat = faa->fa_dmat;
sc->sc_node = faa->fa_node;
@@ -321,9 +365,6 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
free(ranges, M_TEMP, rangeslen);
- sc->sc_ctrl_base = faa->fa_reg[0].addr;
- sc->sc_ctrl_size = faa->fa_reg[0].size;
-
if (bus_space_map(sc->sc_iot, sc->sc_ctrl_base,
sc->sc_ctrl_size, 0, &sc->sc_ioh)) {
free(sc->sc_ranges, M_TEMP, sc->sc_nranges *
@@ -332,11 +373,6 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
return;
}
- 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, sc->sc_ctrl_size);
@@ -379,6 +415,8 @@ dwpcie_attach_deferred(struct device *self)
if (OF_is_compatible(sc->sc_node, "marvell,armada8k-pcie"))
error = dwpcie_armada8k_init(sc);
+ if (OF_is_compatible(sc->sc_node, "amlogic,g12a-pcie"))
+ error = dwpcie_g12a_init(sc);
if (OF_is_compatible(sc->sc_node, "fsl,imx8mm-pcie") ||
OF_is_compatible(sc->sc_node, "fsl,imx8mq-pcie"))
error = dwpcie_imx8mq_init(sc);
@@ -649,6 +687,76 @@ dwpcie_armada8k_intr(void *arg)
}
int
+dwpcie_g12a_init(struct dwpcie_softc *sc)
+{
+ uint32_t *reset_gpio;
+ ssize_t reset_gpiolen;
+ uint32_t reg;
+ int timo;
+
+ reset_gpiolen = OF_getproplen(sc->sc_node, "reset-gpios");
+ if (reset_gpiolen <= 0)
+ return ENXIO;
+
+ if (bus_space_map(sc->sc_iot, sc->sc_glue_base,
+ sc->sc_glue_size, 0, &sc->sc_glue_ioh))
+ return ENOMEM;
+
+ power_domain_enable(sc->sc_node);
+
+ phy_enable(sc->sc_node, "pcie");
+
+ reset_assert_all(sc->sc_node);
+ delay(500);
+ reset_deassert_all(sc->sc_node);
+ delay(500);
+
+ clock_set_frequency(sc->sc_node, "port", 100000000UL);
+ clock_enable_all(sc->sc_node);
+
+ reset_gpio = malloc(reset_gpiolen, M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "reset-gpios", reset_gpio,
+ reset_gpiolen);
+ gpio_controller_config_pin(reset_gpio, GPIO_CONFIG_OUTPUT);
+ gpio_controller_set_pin(reset_gpio, 1);
+
+ dwpcie_link_config(sc);
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CFG0);
+ reg |= PCIE_CFG0_APP_LTSSM_EN;
+ bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_CFG0, reg);
+
+ gpio_controller_set_pin(reset_gpio, 1);
+ delay(500);
+ gpio_controller_set_pin(reset_gpio, 0);
+
+ free(reset_gpio, M_TEMP, reset_gpiolen);
+
+ for (timo = 40; timo > 0; timo--) {
+ if (dwpcie_g12a_link_up(sc))
+ break;
+ delay(1000);
+ }
+ if (timo == 0)
+ return ETIMEDOUT;
+
+ return 0;
+}
+
+int
+dwpcie_g12a_link_up(struct dwpcie_softc *sc)
+{
+ uint32_t reg;
+
+ reg = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, PCIE_STATUS12);
+ if ((reg & PCIE_STATUS12_SMLH_LINK_UP) &&
+ (reg & PCIE_STATUS12_RDLH_LINK_UP) &&
+ (reg & PCIE_STATUS12_LTSSM_MASK) == PCIE_STATUS12_LTSSM_UP)
+ return 1;
+ return 0;
+}
+
+int
dwpcie_imx8mq_init(struct dwpcie_softc *sc)
{
uint32_t *clkreq_gpio, *disable_gpio, *reset_gpio;