Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions arch/arm/boot/dts/zynq-zed-adv7511.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
67 changes: 53 additions & 14 deletions drivers/gpu/drm/adi_axi_hdmi/axi_hdmi_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}

Expand All @@ -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;
Expand Down