From e60747189823b78f424f8d26e72356efb8310e54 Mon Sep 17 00:00:00 2001 From: AndreiGrozav Date: Fri, 11 May 2018 18:00:15 +0300 Subject: [PATCH] axi_hdmi_tx: Update to use ADI DMA The frame synchronization between axi_hdmi_tx and axi_dmac is based on the DMA(2D streaming) last signal. The last signal will be used as an end of frame signal marking the beginning of the future frame to be transferred by the DMA. Only after both HDMI and DMA are ready for a "new frame" data will be requested from the DMA. The datarate and CDC between the axi_dmac and axi_hdmi_tx cores will be handled by axi_hdmi_tx's DMA interface based on a backpressure mechanism. --- library/axi_hdmi_tx/axi_hdmi_tx.v | 6 +-- library/axi_hdmi_tx/axi_hdmi_tx_core.v | 35 ++++++------ library/axi_hdmi_tx/axi_hdmi_tx_ip.tcl | 2 +- library/axi_hdmi_tx/axi_hdmi_tx_vdma.v | 74 +++++++++++++++++++------- 4 files changed, 77 insertions(+), 40 deletions(-) diff --git a/library/axi_hdmi_tx/axi_hdmi_tx.v b/library/axi_hdmi_tx/axi_hdmi_tx.v index 5e723fb86..f6d6c05e6 100644 --- a/library/axi_hdmi_tx/axi_hdmi_tx.v +++ b/library/axi_hdmi_tx/axi_hdmi_tx.v @@ -71,8 +71,7 @@ module axi_hdmi_tx #( // vdma interface input vdma_clk, - output vdma_fs, - input vdma_fs_ret, + input vdma_end_of_frame, input vdma_valid, input [63:0] vdma_data, output vdma_ready, @@ -237,11 +236,10 @@ module axi_hdmi_tx #( .hdmi_raddr_g (hdmi_raddr_g_s), .vdma_clk (vdma_clk), .vdma_rst (vdma_rst), - .vdma_fs (vdma_fs), - .vdma_fs_ret (vdma_fs_ret), .vdma_valid (vdma_valid), .vdma_data (vdma_data), .vdma_ready (vdma_ready), + .vdma_end_of_frame (vdma_end_of_frame), .vdma_wr (vdma_wr_s), .vdma_waddr (vdma_waddr_s), .vdma_wdata (vdma_wdata_s), diff --git a/library/axi_hdmi_tx/axi_hdmi_tx_core.v b/library/axi_hdmi_tx/axi_hdmi_tx_core.v index c535934d5..bf4074701 100644 --- a/library/axi_hdmi_tx/axi_hdmi_tx_core.v +++ b/library/axi_hdmi_tx/axi_hdmi_tx_core.v @@ -244,21 +244,26 @@ module axi_hdmi_tx_core #( // hdmi start of frame always @(posedge hdmi_clk) begin - if (EMBEDDED_SYNC == 1) begin - if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_ve_width_s)) begin - hdmi_fs <= hdmi_enable; - end else begin - hdmi_fs <= 1'b0; - end + if (hdmi_rst == 1'b1) begin + hdmi_fs_toggle <= 1'b0; + hdmi_fs <= 1'b0; end else begin - if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_vs_width)) begin - hdmi_fs <= hdmi_enable; + if (EMBEDDED_SYNC == 1) begin + if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_ve_width_s)) begin + hdmi_fs <= hdmi_enable; + end else begin + hdmi_fs <= 1'b0; + end end else begin - hdmi_fs <= 1'b0; + if ((hdmi_hs_count == 1) && (hdmi_vs_count == hdmi_vs_width)) begin + hdmi_fs <= hdmi_enable; + end else begin + hdmi_fs <= 1'b0; + end + end + if (hdmi_fs == 1'b1) begin + hdmi_fs_toggle <= ~hdmi_fs_toggle; end - end - if (hdmi_fs == 1'b1) begin - hdmi_fs_toggle <= ~hdmi_fs_toggle; end end @@ -279,10 +284,8 @@ module axi_hdmi_tx_core #( end always @(posedge hdmi_clk) begin - hdmi_fs_ret <= hdmi_fs_ret_s; - if (hdmi_fs_ret_s == 1'b1) begin + hdmi_fs_ret <= hdmi_fs_ret_s; hdmi_fs_waddr <= vdma_fs_waddr; - end end // hdmi sync signals @@ -332,7 +335,7 @@ module axi_hdmi_tx_core #( always @(posedge hdmi_clk) begin if (hdmi_rst == 1'b1) begin hdmi_raddr <= 10'd0; - end else if (hdmi_fs_ret == 1'b1) begin + end else if (hdmi_fs == 1'b1) begin hdmi_raddr <= {hdmi_fs_waddr, 1'b0}; end else if (hdmi_de_s == 1'b1) begin hdmi_raddr <= hdmi_raddr + 1'b1; diff --git a/library/axi_hdmi_tx/axi_hdmi_tx_ip.tcl b/library/axi_hdmi_tx/axi_hdmi_tx_ip.tcl index 2db4a0cdb..919f08b19 100644 --- a/library/axi_hdmi_tx/axi_hdmi_tx_ip.tcl +++ b/library/axi_hdmi_tx/axi_hdmi_tx_ip.tcl @@ -35,7 +35,7 @@ set_property driver_value 0 [ipx::get_ports *vsync* -of_objects [ipx::current_co set_property driver_value 0 [ipx::get_ports *data* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *es_data* -of_objects [ipx::current_core]] -set_property driver_value 0 [ipx::get_ports *vdma_fs* -of_objects [ipx::current_core]] +set_property driver_value 0 [ipx::get_ports *vdma_end_of_frame* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_valid* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_data* -of_objects [ipx::current_core]] set_property driver_value 0 [ipx::get_ports *vdma_ready* -of_objects [ipx::current_core]] diff --git a/library/axi_hdmi_tx/axi_hdmi_tx_vdma.v b/library/axi_hdmi_tx/axi_hdmi_tx_vdma.v index 930d4395e..0c4bc08d8 100644 --- a/library/axi_hdmi_tx/axi_hdmi_tx_vdma.v +++ b/library/axi_hdmi_tx/axi_hdmi_tx_vdma.v @@ -45,8 +45,7 @@ module axi_hdmi_tx_vdma ( input vdma_clk, input vdma_rst, - output reg vdma_fs, - input vdma_fs_ret, + input vdma_end_of_frame, input vdma_valid, input [63:0] vdma_data, output reg vdma_ready, @@ -66,16 +65,20 @@ module axi_hdmi_tx_vdma ( // internal registers - reg vdma_fs_toggle_m1 = 'd0; - reg vdma_fs_toggle_m2 = 'd0; - reg vdma_fs_toggle_m3 = 'd0; - reg [22:0] vdma_tpm_data = 'd0; - reg [ 8:0] vdma_raddr_g_m1 = 'd0; - reg [ 8:0] vdma_raddr_g_m2 = 'd0; - reg [ 8:0] vdma_raddr = 'd0; - reg [ 8:0] vdma_addr_diff = 'd0; - reg vdma_almost_full = 'd0; - reg vdma_almost_empty = 'd0; + reg vdma_fs_toggle_m1 = 1'd0; + reg vdma_fs_toggle_m2 = 1'd0; + reg vdma_fs_toggle_m3 = 1'd0; + reg [22:0] vdma_tpm_data = 23'd0; + reg [ 8:0] vdma_raddr_g_m1 = 9'd0; + reg [ 8:0] vdma_raddr_g_m2 = 9'd0; + reg [ 8:0] vdma_raddr = 9'd0; + reg [ 8:0] vdma_addr_diff = 9'd0; + reg vdma_almost_full = 1'd0; + reg vdma_almost_empty = 1'd0; + reg hdmi_fs = 1'd0; + reg vdma_fs = 1'd0; + reg vdma_end_of_frame_d = 1'd0; + reg vdma_active_frame = 1'd0; // internal wires @@ -104,7 +107,7 @@ module axi_hdmi_tx_vdma ( end endfunction - // get fs from hdmi side, return fs and sof write address back + // hdmi frame sync always @(posedge vdma_clk or posedge vdma_rst) begin if (vdma_rst == 1'b1) begin @@ -116,13 +119,46 @@ module axi_hdmi_tx_vdma ( vdma_fs_toggle_m2 <= vdma_fs_toggle_m1; vdma_fs_toggle_m3 <= vdma_fs_toggle_m2; end + hdmi_fs <= vdma_fs_toggle_m2 ^ vdma_fs_toggle_m3; end + // dma frame sync + + always @(posedge vdma_clk or posedge vdma_rst) begin + if (vdma_rst == 1'b1) begin + vdma_end_of_frame_d <= 1'b0; + vdma_fs <= 1'b0; + end else begin + vdma_end_of_frame_d <= vdma_end_of_frame; + vdma_fs <= vdma_end_of_frame_d; + end + end + + // sync dma and hdmi frames + always @(posedge vdma_clk) begin - vdma_fs <= vdma_fs_toggle_m2 ^ vdma_fs_toggle_m3; - if (vdma_fs_ret == 1'b1) begin - vdma_fs_waddr <= vdma_waddr; - vdma_fs_ret_toggle <= ~vdma_fs_ret_toggle; + if (vdma_rst == 1'b1) begin + vdma_fs_ret_toggle = 1'b0; + vdma_fs_waddr <= 9'b0; + end else begin + if (vdma_fs) begin + vdma_fs_ret_toggle <= ~vdma_fs_ret_toggle; + vdma_fs_waddr <= vdma_waddr ; + end + end + end + + // accept new frame from dma + + always @(posedge vdma_clk) begin + if (vdma_rst == 1'b1) begin + vdma_active_frame <= 1'b0; + end else begin + if ((vdma_active_frame == 1'b1) && (vdma_end_of_frame == 1'b1)) begin + vdma_active_frame <= 1'b0; + end else if ((vdma_active_frame == 1'b0) && (hdmi_fs == 1'b1)) begin + vdma_active_frame <= 1'b1; + end end end @@ -144,7 +180,7 @@ module axi_hdmi_tx_vdma ( assign vdma_tpm_oos_s = (vdma_wdata == vdma_tpm_data_s) ? 1'b0 : vdma_wr; always @(posedge vdma_clk) begin - if ((vdma_rst == 1'b1) || (vdma_fs_ret == 1'b1)) begin + if ((vdma_rst == 1'b1) || (vdma_fs == 1'b1)) begin vdma_tpm_data <= 23'd0; vdma_tpm_oos <= 1'd0; end else if (vdma_wr == 1'b1) begin @@ -175,7 +211,7 @@ module axi_hdmi_tx_vdma ( if (vdma_addr_diff >= RDY_THRESHOLD_HI) begin vdma_ready <= 1'b0; end else if (vdma_addr_diff <= RDY_THRESHOLD_LO) begin - vdma_ready <= 1'b1; + vdma_ready <= vdma_active_frame; end if (vdma_addr_diff > BUF_THRESHOLD_HI) begin vdma_almost_full <= 1'b1;