diff --git a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi index 1209b8cf688c9..924fe2f17f190 100644 --- a/arch/arm/boot/dts/zynq-zed-adv7511.dtsi +++ b/arch/arm/boot/dts/zynq-zed-adv7511.dtsi @@ -38,13 +38,12 @@ }; axi_vdma_0: axivdma@43000000 { - compatible = "xlnx,axi-vdma"; + compatible = "xlnx,axi-vdma-1.00.a"; #address-cells = <1>; #size-cells = <1>; #dma-cells = <1>; #dma-channels = <1>; reg = <0x43000000 0x1000>; - xlnx,include-sg = <0x0>; xlnx,num-fstores = <0x3>; dma-channel@43000000 { compatible = "xlnx,axi-vdma-mm2s-channel"; diff --git a/drivers/gpu/drm/adi_axi_hdmi/axi_hdmi_crtc.c b/drivers/gpu/drm/adi_axi_hdmi/axi_hdmi_crtc.c index d8338c7d768a1..1aa5fa39bbd7b 100644 --- a/drivers/gpu/drm/adi_axi_hdmi/axi_hdmi_crtc.c +++ b/drivers/gpu/drm/adi_axi_hdmi/axi_hdmi_crtc.c @@ -23,7 +23,7 @@ struct axi_hdmi_crtc { struct drm_crtc drm_crtc; struct dma_chan *dma; - struct xilinx_dma_config dma_config; + struct dma_interleaved_template *dma_template; int mode; }; @@ -39,7 +39,8 @@ static int axi_hdmi_crtc_update(struct drm_crtc *crtc) struct drm_framebuffer *fb = crtc->primary->fb; struct dma_async_tx_descriptor *desc; struct drm_gem_cma_object *obj; - size_t offset; + struct xilinx_vdma_config vdma_config; + size_t offset, hw_row_size; if (!mode || !fb) return -EINVAL; @@ -51,19 +52,45 @@ static int axi_hdmi_crtc_update(struct drm_crtc *crtc) if (!obj) return -EINVAL; - axi_hdmi_crtc->dma_config.hsize = mode->hdisplay * fb->bits_per_pixel / 8; - axi_hdmi_crtc->dma_config.vsize = mode->vdisplay; - axi_hdmi_crtc->dma_config.stride = fb->pitches[0]; + memset(&vdma_config, 0, sizeof(vdma_config)); + vdma_config.park = 1; + xilinx_vdma_channel_set_config(axi_hdmi_crtc->dma, &vdma_config); + + offset = crtc->x * fb->bits_per_pixel / 8 + + crtc->y * fb->pitches[0]; + + /* Interleaved DMA is used that way: + * Each interleaved frame is a row (hsize) implemented in ONE + * chunk (sgl has len 1). + * The number of interleaved frames is the number of rows (vsize). + * The icg in used to pack data to the HW, so that the buffer len + * is fb->piches[0], but the actual size for the hw is somewhat less + */ + axi_hdmi_crtc->dma_template->dir = DMA_MEM_TO_DEV; + axi_hdmi_crtc->dma_template->src_start = obj->paddr + offset; + /* sgl list have just one entry (each interleaved frame have 1 chunk) */ + axi_hdmi_crtc->dma_template->frame_size = 1; + /* the number of interleaved frame, each has the size specified in sgl */ + axi_hdmi_crtc->dma_template->numf = mode->vdisplay; + axi_hdmi_crtc->dma_template->src_sgl = 1; + axi_hdmi_crtc->dma_template->src_inc = 1; + + /* vdma IP does not provide any addr to the hdmi IP, so dst_inc + * and dst_sgl should make no any difference. + */ + axi_hdmi_crtc->dma_template->dst_inc = 0; + axi_hdmi_crtc->dma_template->dst_sgl = 0; + + hw_row_size = mode->hdisplay * fb->bits_per_pixel / 8; + axi_hdmi_crtc->dma_template->sgl[0].size = hw_row_size; + + /* the vdma driver seems to look at icg, and not src_icg */ + axi_hdmi_crtc->dma_template->sgl[0].icg = + fb->pitches[0] - hw_row_size; + + desc = dmaengine_prep_interleaved_dma(axi_hdmi_crtc->dma, + axi_hdmi_crtc->dma_template, 0); - dmaengine_slave_config(axi_hdmi_crtc->dma, - (struct dma_slave_config *)&axi_hdmi_crtc->dma_config); - - offset = crtc->x * fb->bits_per_pixel / 8 + crtc->y * fb->pitches[0]; - - desc = dmaengine_prep_slave_single(axi_hdmi_crtc->dma, - obj->paddr + offset, - mode->vdisplay * fb->pitches[0], - DMA_MEM_TO_DEV, 0); if (!desc) { pr_err("Failed to prepare DMA descriptor\n"); return -ENOMEM; @@ -141,6 +168,7 @@ static void axi_hdmi_crtc_destroy(struct drm_crtc *crtc) struct axi_hdmi_crtc *axi_hdmi_crtc = to_axi_hdmi_crtc(crtc); drm_crtc_cleanup(crtc); + kfree(axi_hdmi_crtc->dma_template); kfree(axi_hdmi_crtc); } @@ -161,6 +189,17 @@ struct drm_crtc *axi_hdmi_crtc_create(struct drm_device *dev) return ERR_PTR(-ENOMEM); } + /* we know we'll always use only one data chunk */ + axi_hdmi_crtc->dma_template = kzalloc( + sizeof(struct dma_interleaved_template) + + sizeof(struct data_chunk), GFP_KERNEL); + + if (!axi_hdmi_crtc->dma_template) { + kfree(axi_hdmi_crtc); + DRM_ERROR("failed to allocate dma_template crtc\n"); + return ERR_PTR(-ENOMEM); + } + crtc = &axi_hdmi_crtc->drm_crtc; axi_hdmi_crtc->dma = p->dma;