summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2022-07-27 20:18:47 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2022-07-27 20:18:47 +0000
commitcc0510965190e09229359319e7fea3eff1612eba (patch)
tree3ddb198be9df89bb9868b04ec6f7877ee03fe84d
parent9ae83f2ec6f3addb4d5e9ba9400628fcbe39f334 (diff)
Partially catch up with device tree bindings in mainline Linux.
Initialize the burst size register such that DMA channels that haven't been initialized by Apple's bootloader also work. ok patrick@
-rw-r--r--sys/arch/arm64/dev/apldma.c64
1 files changed, 44 insertions, 20 deletions
diff --git a/sys/arch/arm64/dev/apldma.c b/sys/arch/arm64/dev/apldma.c
index a9a21d4be23..814d055f485 100644
--- a/sys/arch/arm64/dev/apldma.c
+++ b/sys/arch/arm64/dev/apldma.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: apldma.c,v 1.1 2022/02/02 22:55:57 kettenis Exp $ */
+/* $OpenBSD: apldma.c,v 1.2 2022/07/27 20:18:46 kettenis Exp $ */
/*
* Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
*
@@ -38,36 +38,43 @@
* dropped as soon as official bindings are available.
*/
+/*
+ * The device tree bindings for this hardware use separate Tx and Rx
+ * channels with Tx channels using even channel numbers and Rx
+ * channels using odd channel numbers.
+ */
+
#define DMA_TX_EN 0x0000
#define DMA_TX_EN_CLR 0x0004
#define DMA_TX_INTR 0x0034
-#define DMA_TX_CTL(chan) (0x8000 + (chan) * 0x400)
+#define DMA_TX_CTL(chan) (0x8000 + ((chan) / 2) * 0x400)
#define DMA_TX_CTL_RESET_RINGS (1 << 0)
-#define DMA_TX_INTRSTAT(chan) (0x8014 + (chan) * 0x400)
+#define DMA_TX_INTRSTAT(chan) (0x8014 + ((chan) / 2) * 0x400)
#define DMA_TX_INTRSTAT_DESC_DONE (1 << 0)
#define DMA_TX_INTRSTAT_ERR (1 << 6)
-#define DMA_TX_INTRMASK(chan) (0x8024 + (chan) * 0x400)
+#define DMA_TX_INTRMASK(chan) (0x8024 + ((chan) / 2) * 0x400)
#define DMA_TX_INTRMASK_DESC_DONE (1 << 0)
#define DMA_TX_INTRMASK_ERR (1 << 6)
-#define DMA_TX_BUS_WIDTH(chan) (0x8040 + (chan) * 0x400)
+#define DMA_TX_BUS_WIDTH(chan) (0x8040 + ((chan) / 2) * 0x400)
#define DMA_TX_BUS_WIDTH_8BIT (0 << 0)
#define DMA_TX_BUS_WIDTH_16BIT (1 << 0)
#define DMA_TX_BUS_WIDTH_32BIT (2 << 0)
#define DMA_TX_BUS_WIDTH_FRAME_2_WORDS (1 << 4)
#define DMA_TX_BUS_WIDTH_FRAME_4_WORDS (2 << 4)
-#define DMA_TX_BURST_SIZE(chan) (0x8054 + (chan) * 0x400)
-#define DMA_TX_RESIDUE(chan) (0x8064 + (chan) * 0x400)
-#define DMA_TX_DESC_RING(chan) (0x8070 + (chan) * 0x400)
+#define DMA_TX_BURST_SIZE(chan) (0x8054 + ((chan) / 2) * 0x400)
+#define DMA_TX_BURST_SIZE_MAGIC 0x00c00060
+#define DMA_TX_RESIDUE(chan) (0x8064 + ((chan) / 2) * 0x400)
+#define DMA_TX_DESC_RING(chan) (0x8070 + ((chan) / 2) * 0x400)
#define DMA_TX_DESC_RING_FULL (1 << 9)
-#define DMA_TX_REPORT_RING(chan) (0x8074 + (chan) * 0x400)
+#define DMA_TX_REPORT_RING(chan) (0x8074 + ((chan) / 2) * 0x400)
#define DMA_TX_REPORT_RING_EMPTY (1 << 8)
-#define DMA_TX_DESC_WRITE(chan) (0x10000 + (chan) * 4)
-#define DMA_TX_REPORT_READ(chan) (0x10100 + (chan) * 4)
+#define DMA_TX_DESC_WRITE(chan) (0x10000 + ((chan) / 2) * 4)
+#define DMA_TX_REPORT_READ(chan) (0x10100 + ((chan) / 2) * 4)
#define DMA_DESC_NOTIFY (1 << 16)
#define DMA_NUM_DESCRIPTORS 4
-#define DMA_NUM_CHANNELS 4
+#define DMA_NUM_INTERRUPTS 4
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
@@ -101,7 +108,8 @@ struct apldma_softc {
int sc_node;
void *sc_ih;
- struct apldma_channel *sc_ac[DMA_NUM_CHANNELS];
+ int sc_nchannels;
+ struct apldma_channel **sc_ac;
};
struct apldma_softc *apldma_sc;
@@ -145,6 +153,14 @@ apldma_attach(struct device *parent, struct device *self, void *aux)
return;
}
+ sc->sc_nchannels = OF_getpropint(faa->fa_node, "dma-channels", 0);
+ if (sc->sc_nchannels == 0) {
+ printf(": no DMA channels\n");
+ goto unmap;
+ }
+ sc->sc_ac = mallocarray(sc->sc_nchannels,
+ sizeof(struct apldma_channel), M_DEVBUF, M_WAITOK | M_ZERO);
+
sc->sc_dmat = faa->fa_dmat;
sc->sc_node = faa->fa_node;
@@ -154,7 +170,7 @@ apldma_attach(struct device *parent, struct device *self, void *aux)
apldma_intr, sc, sc->sc_dev.dv_xname);
if (sc->sc_ih == NULL) {
printf(": can't establish interrupt\n");
- goto unmap;
+ goto free;
}
printf("\n");
@@ -162,6 +178,9 @@ apldma_attach(struct device *parent, struct device *self, void *aux)
apldma_sc = sc;
return;
+free:
+ free(sc->sc_ac, M_DEVBUF,
+ sc->sc_nchannels * sizeof(struct apldma_channel));
unmap:
bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
}
@@ -199,8 +218,8 @@ apldma_intr(void *arg)
unsigned int chan, i;
intr = HREAD4(sc, DMA_TX_INTR);
- for (chan = 0; chan < DMA_NUM_CHANNELS; chan++) {
- if ((intr & (1 << chan)) == 0)
+ for (chan = 0; chan < sc->sc_nchannels; chan += 2) {
+ if ((intr & (1 << (chan / 2))) == 0)
continue;
intrstat = HREAD4(sc, DMA_TX_INTRSTAT(chan));
@@ -208,7 +227,7 @@ apldma_intr(void *arg)
if ((intrstat & DMA_TX_INTRSTAT_DESC_DONE) == 0)
continue;
-
+
for (i = 0; i < DMA_NUM_DESCRIPTORS; i++) {
uint32_t status;
@@ -240,7 +259,11 @@ apldma_alloc_channel(unsigned int chan)
struct apldma_softc *sc = apldma_sc;
struct apldma_channel *ac;
- if (chan >= DMA_NUM_CHANNELS)
+ if (chan >= sc->sc_nchannels)
+ return NULL;
+
+ /* We only support Tx channels for now. */
+ if ((chan % 2) != 0)
return NULL;
ac = malloc(sizeof(*ac), M_DEVBUF, M_WAITOK);
@@ -337,6 +360,7 @@ apldma_trigger_output(struct apldma_channel *ac, void *start, void *end,
default:
return EINVAL;
}
+ HWRITE4(sc, DMA_TX_BURST_SIZE(ac->ac_chan), DMA_TX_BURST_SIZE_MAGIC);
/* Reset rings. */
HWRITE4(sc, DMA_TX_CTL(ac->ac_chan), DMA_TX_CTL_RESET_RINGS);
@@ -351,7 +375,7 @@ apldma_trigger_output(struct apldma_channel *ac, void *start, void *end,
apldma_fill_descriptors(ac);
/* Start DMA transfer. */
- HWRITE4(sc, DMA_TX_EN, 1 << ac->ac_chan);
+ HWRITE4(sc, DMA_TX_EN, 1 << (ac->ac_chan / 2));
return 0;
}
@@ -362,7 +386,7 @@ apldma_halt_output(struct apldma_channel *ac)
struct apldma_softc *sc = ac->ac_sc;
/* Stop DMA transfer. */
- HWRITE4(sc, DMA_TX_EN_CLR, 1 << ac->ac_chan);
+ HWRITE4(sc, DMA_TX_EN_CLR, 1 << (ac->ac_chan / 2));
/* Mask all interrupts. */
HWRITE4(sc, DMA_TX_INTRMASK(ac->ac_chan), 0);