mirror of
https://github.com/openbsd/src.git
synced 2026-04-15 01:34:03 +00:00
Add SpacemiT K1 support.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dwpcie.c,v 1.58 2026/01/25 12:09:50 kettenis Exp $ */
|
||||
/* $OpenBSD: dwpcie.c,v 1.59 2026/04/07 20:38:51 kettenis Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
|
||||
*
|
||||
@@ -322,7 +322,8 @@ dwpcie_match(struct device *parent, void *match, void *aux)
|
||||
OF_is_compatible(faa->fa_node, "qcom,pcie-x1e80100") ||
|
||||
OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie") ||
|
||||
OF_is_compatible(faa->fa_node, "rockchip,rk3588-pcie") ||
|
||||
OF_is_compatible(faa->fa_node, "sifive,fu740-pcie"));
|
||||
OF_is_compatible(faa->fa_node, "sifive,fu740-pcie") ||
|
||||
OF_is_compatible(faa->fa_node, "spacemit,k1-pcie"));
|
||||
}
|
||||
|
||||
void dwpcie_attach_deferred(struct device *);
|
||||
@@ -345,6 +346,8 @@ int dwpcie_imx8mq_intr(void *);
|
||||
|
||||
int dwpcie_fu740_init(struct dwpcie_softc *);
|
||||
|
||||
int dwpcie_k1_init(struct dwpcie_softc *);
|
||||
|
||||
int dwpcie_rk3568_init(struct dwpcie_softc *);
|
||||
int dwpcie_rk3568_intr(void *);
|
||||
void *dwpcie_rk3568_intr_establish(void *, int *, int,
|
||||
@@ -443,6 +446,17 @@ dwpcie_attach(struct device *parent, struct device *self, void *aux)
|
||||
sc->sc_glue_size = faa->fa_reg[glue].size;
|
||||
}
|
||||
|
||||
if (OF_is_compatible(faa->fa_node, "spacemit,k1-pcie")) {
|
||||
glue = OF_getindex(faa->fa_node, "link", "reg-names");
|
||||
if (glue < 0 || glue >= faa->fa_nreg) {
|
||||
printf(": no link 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;
|
||||
@@ -548,6 +562,8 @@ dwpcie_attach_deferred(struct device *self)
|
||||
error = dwpcie_rk3568_init(sc);
|
||||
if (OF_is_compatible(sc->sc_node, "sifive,fu740-pcie"))
|
||||
error = dwpcie_fu740_init(sc);
|
||||
if (OF_is_compatible(sc->sc_node, "spacemit,k1-pcie"))
|
||||
error = dwpcie_k1_init(sc);
|
||||
if (error != 0) {
|
||||
bus_space_unmap(sc->sc_iot, sc->sc_conf_ioh, sc->sc_conf_size);
|
||||
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ctrl_size);
|
||||
@@ -754,6 +770,29 @@ dwpcie_attach_deferred(struct device *self)
|
||||
config_found(self, &pba, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
dwpcie_get_capability(struct dwpcie_softc *sc, int capid, int *offset,
|
||||
pcireg_t *value)
|
||||
{
|
||||
pcireg_t reg;
|
||||
unsigned int ofs;
|
||||
|
||||
ofs = PCI_CAPLIST_PTR(HREAD4(sc, PCI_CAPLISTPTR_REG));
|
||||
while (ofs != 0) {
|
||||
reg = HREAD4(sc, ofs);
|
||||
if (PCI_CAPLIST_CAP(reg) == capid) {
|
||||
if (offset)
|
||||
*offset = ofs;
|
||||
if (value)
|
||||
*value = reg;
|
||||
return 1;
|
||||
}
|
||||
ofs = PCI_CAPLIST_NEXT(reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
dwpcie_link_config(struct dwpcie_softc *sc)
|
||||
{
|
||||
@@ -1337,6 +1376,123 @@ dwpcie_fu740_init(struct dwpcie_softc *sc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* SpacemiT K1 registers */
|
||||
#define APMU_PCIE_CLK_RES_CTRL 0x0000
|
||||
#define APMU_PCIE_DEVICE_TYPE_SEL (1U << 31)
|
||||
#define APMU_PCIE_APP_HOLD_PHY_RST (1U << 30)
|
||||
#define APMU_PCIE_RC_PERST (1U << 12)
|
||||
#define APMU_PCIE_SYS_AUX_PWR_DET (1U << 9)
|
||||
#define APMU_PCIE_LTSSM_EN (1U << 6)
|
||||
#define APMU_PCIE_CTRL_LOGIC 0x0004
|
||||
#define APMU_PCIE_SOFT_RESET (1U << 0)
|
||||
|
||||
#define K1_PHY_AHB_IRQ 0x0000
|
||||
#define K1_PHY_AHB_IRQ_EN (1U << 0)
|
||||
#define K1_PHY_AHB_IRQENABLE_MSI 0x0014
|
||||
#define K1_PHY_AHB_IRQENABLE_MSI_EN (1U << 11)
|
||||
|
||||
int
|
||||
dwpcie_k1_init(struct dwpcie_softc *sc)
|
||||
{
|
||||
struct regmap *apmu_rm;
|
||||
uint32_t apmu[2], val;
|
||||
int error, off, timo;
|
||||
|
||||
sc->sc_num_viewport = 8;
|
||||
|
||||
if (bus_space_map(sc->sc_iot, sc->sc_glue_base,
|
||||
sc->sc_glue_size, 0, &sc->sc_glue_ioh))
|
||||
return ENOMEM;
|
||||
|
||||
if (OF_getpropintarray(sc->sc_node, "spacemit,apmu",
|
||||
apmu, sizeof(apmu)) != sizeof(apmu))
|
||||
return EINVAL;
|
||||
|
||||
apmu_rm = regmap_byphandle(apmu[0]);
|
||||
if (apmu_rm == NULL)
|
||||
return ENXIO;
|
||||
|
||||
/* Hold PHY in reset until starting the link. */
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
val |= APMU_PCIE_APP_HOLD_PHY_RST;
|
||||
val &= ~APMU_PCIE_LTSSM_EN;
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL, val);
|
||||
|
||||
/* Soft reset. */
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CTRL_LOGIC);
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CTRL_LOGIC,
|
||||
val | APMU_PCIE_SOFT_RESET);
|
||||
regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CTRL_LOGIC);
|
||||
delay(2000);
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CTRL_LOGIC,
|
||||
val &= ~APMU_PCIE_SOFT_RESET);
|
||||
|
||||
clock_enable_all(sc->sc_node);
|
||||
reset_deassert_all(sc->sc_node);
|
||||
|
||||
/* Set vendor ID and product ID. (*/
|
||||
HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
|
||||
HWRITE4(sc, PCI_ID_REG,
|
||||
PCI_VENDOR_SPACEMIT << PCI_VENDOR_SHIFT |
|
||||
PCI_PRODUCT_SPACEMIT_K1 << PCI_PRODUCT_SHIFT);
|
||||
HCLR4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
|
||||
|
||||
/* Assert PERST#. */
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL,
|
||||
val | APMU_PCIE_RC_PERST);
|
||||
regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
delay(100000);
|
||||
|
||||
/* Set RC mode; indicate Vaux presence. */
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL,
|
||||
val | APMU_PCIE_DEVICE_TYPE_SEL | APMU_PCIE_SYS_AUX_PWR_DET);
|
||||
|
||||
phy_enable_idx(OF_child(sc->sc_node), 0);
|
||||
|
||||
/* Deassert PERST#. */
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL,
|
||||
val & ~APMU_PCIE_RC_PERST);
|
||||
|
||||
/* Disable ASPM L1. */
|
||||
if (!dwpcie_get_capability(sc, PCI_CAP_PCIEXPRESS, &off, NULL))
|
||||
return ENXIO;
|
||||
HSET4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
|
||||
val = HREAD4(sc, off + PCI_PCIE_LCAP);
|
||||
val &= ~PCI_PCIE_LCAP_ASPM_L1;
|
||||
HWRITE4(sc, off + PCI_PCIE_LCAP, val);
|
||||
HCLR4(sc, MISC_CONTROL_1, MISC_CONTROL_1_DBI_RO_WR_EN);
|
||||
|
||||
error = dwpcie_msi_init(sc);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
val = regmap_read_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL);
|
||||
val &= ~APMU_PCIE_APP_HOLD_PHY_RST;
|
||||
val |= APMU_PCIE_LTSSM_EN;
|
||||
regmap_write_4(apmu_rm, apmu[1] + APMU_PCIE_CLK_RES_CTRL, val);
|
||||
|
||||
/* Enable MSIs */
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh,
|
||||
K1_PHY_AHB_IRQENABLE_MSI, K1_PHY_AHB_IRQENABLE_MSI_EN);
|
||||
val = bus_space_read_4(sc->sc_iot, sc->sc_glue_ioh, K1_PHY_AHB_IRQ);
|
||||
bus_space_write_4(sc->sc_iot, sc->sc_glue_ioh, K1_PHY_AHB_IRQ,
|
||||
val | K1_PHY_AHB_IRQ_EN);
|
||||
|
||||
/* Wait for the link to come up. */
|
||||
for (timo = 20000; timo > 0; timo--) {
|
||||
if (dwpcie_link_up(sc))
|
||||
break;
|
||||
delay(10);
|
||||
}
|
||||
if (timo == 0)
|
||||
return ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
dwpcie_rk3568_link_up(struct dwpcie_softc *sc)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user