Implement the DMA control interface for allowing direct control of DMA operations from inside peripheral models embedding (and reusing) the Xilinx CSU DMA.
Signed-off-by: Francisco Iglesias <francisco.igles...@xilinx.com> --- hw/dma/xlnx_csu_dma.c | 32 ++++++++++++++++++++++++++++++++ include/hw/dma/xlnx_csu_dma.h | 4 ++++ 2 files changed, 36 insertions(+) diff --git a/hw/dma/xlnx_csu_dma.c b/hw/dma/xlnx_csu_dma.c index 896bb3574d..e3eb0e9d52 100644 --- a/hw/dma/xlnx_csu_dma.c +++ b/hw/dma/xlnx_csu_dma.c @@ -277,6 +277,11 @@ static uint32_t xlnx_csu_dma_advance(XlnxCSUDMA *s, uint32_t len) s->regs[R_ADDR_MSB] = dst >> 32; } + /* Notify dma-ctrl-if clients when the transfer has been completed */ + if (size == 0 && s->dmactrlif_notify) { + s->dmactrlif_notify(s->dmactrlif_opaque); + } + if (size == 0) { xlnx_csu_dma_done(s); } @@ -472,6 +477,29 @@ static uint64_t addr_msb_pre_write(RegisterInfo *reg, uint64_t val) return val & R_ADDR_MSB_ADDR_MSB_MASK; } +static void xlnx_csu_dma_dma_ctrl_if_read(DmaCtrlIf *dma, hwaddr addr, + uint32_t len, DmaCtrlIfNotify *notify, + bool start_dma) +{ + XlnxCSUDMA *s = XLNX_CSU_DMA(dma); + RegisterInfo *reg = &s->regs_info[R_SIZE]; + uint64_t we = MAKE_64BIT_MASK(0, 4 * 8); + + s->regs[R_ADDR] = addr; + s->regs[R_ADDR_MSB] = (uint64_t)addr >> 32; + + if (notify) { + s->dmactrlif_notify = notify->cb; + s->dmactrlif_opaque = notify->opaque; + } + + if (start_dma) { + register_write(reg, len, we, object_get_typename(OBJECT(s)), false); + } else { + s->regs[R_SIZE] = len; + } +} + static const RegisterAccessInfo *xlnx_csu_dma_regs_info[] = { #define DMACH_REGINFO(NAME, snd) \ (const RegisterAccessInfo []) { \ @@ -696,6 +724,7 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); StreamSinkClass *ssc = STREAM_SINK_CLASS(klass); + DmaCtrlIfClass *dcic = DMA_CTRL_IF_CLASS(klass); dc->reset = xlnx_csu_dma_reset; dc->realize = xlnx_csu_dma_realize; @@ -704,6 +733,8 @@ static void xlnx_csu_dma_class_init(ObjectClass *klass, void *data) ssc->push = xlnx_csu_dma_stream_push; ssc->can_push = xlnx_csu_dma_stream_can_push; + + dcic->read = xlnx_csu_dma_dma_ctrl_if_read; } static void xlnx_csu_dma_init(Object *obj) @@ -731,6 +762,7 @@ static const TypeInfo xlnx_csu_dma_info = { .instance_init = xlnx_csu_dma_init, .interfaces = (InterfaceInfo[]) { { TYPE_STREAM_SINK }, + { TYPE_DMA_CTRL_IF }, { } } }; diff --git a/include/hw/dma/xlnx_csu_dma.h b/include/hw/dma/xlnx_csu_dma.h index 28806628b1..b1b7772250 100644 --- a/include/hw/dma/xlnx_csu_dma.h +++ b/include/hw/dma/xlnx_csu_dma.h @@ -25,6 +25,7 @@ #include "hw/register.h" #include "hw/ptimer.h" #include "hw/stream.h" +#include "hw/dma/dma-ctrl-if.h" #define TYPE_XLNX_CSU_DMA "xlnx.csu_dma" @@ -47,6 +48,9 @@ typedef struct XlnxCSUDMA { StreamCanPushNotifyFn notify; void *notify_opaque; + dmactrlif_notify_fn dmactrlif_notify; + void *dmactrlif_opaque; + uint32_t regs[XLNX_CSU_DMA_R_MAX]; RegisterInfo regs_info[XLNX_CSU_DMA_R_MAX]; } XlnxCSUDMA; -- 2.11.0