mipi_dsi_bridge_fpga/FPGA/Source/mipi_dsi_bridge.v

375 lines
9.5 KiB
Verilog

/*
* File: MIPI_DSI_BRIDGE.v
* Copyright: Gaurav Singh
* website: www.circuitvalley.com
* Created on Jan 19, 2020, 1:33 AM
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Email: gauravsingh@circuitvalley.com
************************************************************************/
module mipi_dsi_bridge(nsys_reset, clk,
hs_clock_o,
hs_data_o ,
buf_clkout_lp_n_o,
buf_clkout_lp_p_o,
buf_dout_lp_n_o,
buf_dout_lp_p_o,
reg_1v8_en,
reg_3v0_en,
lcd_rst,
bl_en,
spi_mosi_i,
spi_csn_i,
spi_clk_i,
lcd_test_i);
output reg reg_1v8_en;
output reg reg_3v0_en;
output reg lcd_rst;
output reg bl_en;
output hs_clock_o;
output hs_data_o;
output wire buf_clkout_lp_n_o ;
output wire buf_clkout_lp_p_o ;
output wire buf_dout_lp_n_o ;
output wire buf_dout_lp_p_o ;
input wire nsys_reset;
input clk; //clock input
input spi_mosi_i;
input spi_csn_i;
input spi_clk_i;
input lcd_test_i;
reg spi_csn_reg1;
reg spi_csn_reg2;
reg spi_csn_reg3;
reg write_cmd;
reg fifo_reset;
reg [7:0]command_r;
reg [2:0] controller_state;
reg [3:0] reset_state;
reg [7:0] spi_cmd;
reg [7:0] line_counter;
reg [32:0] delay_counter;
wire [7:0]fifo_out;
wire pll_clk_spi;
wire reset_i;
wire pll_clk_p;
wire pll_clk_s;
wire pll_clk_s2;
wire ready;
wire sclk;
wire lock;
wire fifo_full;
wire fifo_empty_w;
wire fifo_almost_full;
wire almost_empty;
wire fifo_read_en_w;
wire spi_byte_clock;
wire fifo_write_en_r;
wire [7:0]spi_rxdata;
wire tx_finish_w;
assign reset_i = !nsys_reset;
assign pll_clk_spi = pll_clk_s2;
PLL pll_i1 (.CLKI(clk ), .CLKOP(pll_clk_p), .CLKOS(pll_clk_s), .CLKOS2(pll_clk_s2));
FIFo fifo_module( .Reset(fifo_reset),
.RPReset(1'b0),
.Data(spi_rxdata),
.Q(fifo_out),
.WrEn(fifo_write_en_r),
.RdEn(fifo_read_en_w),
.WrClock(spi_byte_clock),
.RdClock(byte_clock_o),
.Full(fifo_full),
.AlmostFull(fifo_almost_full),
.AlmostEmpty(almost_empty),
.Empty(fifo_empty_w)
);
DPHY_TX_FRAME dphy_tx_frame(
.reset_i(reset_i), //reset active high
.command_i(command_r),
.write_cmd_i(write_cmd),
.clockp_fast_data_i(pll_clk_p), //fast clokc input for mipi data
.clocks_fast_clk_i(pll_clk_s), //fast clock input for mipi clok
.clock_slow_sync_i(pll_clk_s2), //slow clock for sync
.lock_chk_i(1'b1), //pll lock check
.fifo_almost_empty(almost_empty),
.fifo_empty(fifo_empty_w),
.data_i(fifo_out), //mipi data input from FIFO
.finish_o(tx_finish_w),
.fifo_read_en(fifo_read_en_w),
.buf_clkout_lp_p_o(buf_clkout_lp_p_o), //mipi clock lp0 out
.buf_clkout_lp_n_o(buf_clkout_lp_n_o), //mipi clock lp1 out
.buf_dout_lp_p_o(buf_dout_lp_p_o), //data lp0 out
.buf_dout_lp_n_o(buf_dout_lp_n_o), //data lp1 out
.byte_clock_o(byte_clock_o), //byte clock out
.hs_data_o(hs_data_o), //mipi data out
.hs_clock_o(hs_clock_o)); //mipi clock out
SPI_SLAVE spi_slave_inst1 ( .clk_i(pll_clk_spi),
.rst_i(reset_i),
.rx_data_o(spi_rxdata),
.byte_clock_o(spi_byte_clock),
.spi_clk_i(spi_clk_i),
.spi_mosi_i(spi_mosi_i),
.spi_csn_i(spi_csn_i)
);
parameter controller_state_reset_lcd = 3'h0;
parameter controller_state_idle = 3'h1;
parameter controller_state_cmd_received = 3'h2;
parameter controller_state_cmd_busy = 3'h3;
parameter controller_state_wait_cs = 3'h4;
parameter state_lcd_activate_vee = 4'h0;
parameter state_lcd_reset_active = 4'h1;
parameter state_lcd_reset_wait = 4'h2;
parameter state_lcd_reset_wait_for_vdd = 4'h3;
parameter state_lcd_reset_send_cmd_init = 4'h4;
parameter state_lcd_reset_wait_cmd = 4'h5;
parameter state_lcd_reset_wait_init = 4'h6;
parameter state_lcd_reset_tp_write = 4'h7;
parameter state_lcd_reset_tp_wait = 4'h8;
//reset sequence delay timing as per mipi specs
parameter delay_reset_deactivated = 32'h1071B00; //250ms @ 46Mhz
parameter delay_reset_ativated = 32'h6A980; //5ms @ 12Mhz
parameter delay_reset_wait_vdd = 32'h10B80; //1ms
parameter delay_wait_for_vdd = 32'h6A980; //5ms
parameter delay_wait_init = 32'h6A980; //5ms
parameter CMD_LCD_INIT = 8'h89; //from ROM 13th line
parameter CMD_LCD_TP_FIRST = 8'hCF; //line 17
parameter CMD_LCD_TP_NEXT = 8'hD9; //line 18
parameter DISPLAY_LINE_MAX = 8'd240;
always @(posedge reset_i or posedge byte_clock_o) //must be slower than ddr_byte_clock
begin
if (reset_i)
begin
controller_state <= controller_state_reset_lcd;
reset_state <= state_lcd_activate_vee;
lcd_rst <= 1'h0; //reset active
reg_1v8_en <= 1'h0; //reg inactive
reg_3v0_en <= 1'h0; //reg inactive
line_counter <= 8'h0;
end
else
begin
case (controller_state)
controller_state_reset_lcd: begin
if (delay_counter)
begin
delay_counter <= delay_counter - 1'b1;
end
else
begin
case (reset_state)
state_lcd_activate_vee:begin
reg_1v8_en <= 1'h1; //activate 1v8
lcd_rst <= 1'h1; //reset inactive
bl_en <= 1'h1; //enable BL
fifo_reset <= 1;
write_cmd <= 1'b0;
delay_counter <= delay_reset_deactivated;
reset_state <= state_lcd_reset_active;
end
state_lcd_reset_active:begin
fifo_reset <= 1'b0;
lcd_rst <= 1'h0; //reset active
delay_counter <= delay_reset_ativated;
reset_state <= state_lcd_reset_wait;
end
state_lcd_reset_wait:begin
fifo_reset <= 1'b1;
lcd_rst <= 1'h1; //reset inactive
delay_counter <= delay_reset_wait_vdd;
reset_state <= state_lcd_reset_wait_for_vdd;
end
state_lcd_reset_wait_for_vdd:begin
fifo_reset <= 1'b0;
reg_3v0_en <= 1'h1; //reg acitve
delay_counter <= delay_wait_for_vdd;
reset_state <= state_lcd_reset_send_cmd_init;
end
state_lcd_reset_send_cmd_init:begin
write_cmd <= 1'b1;
command_r <= CMD_LCD_INIT;
delay_counter <= 0;
reset_state <= state_lcd_reset_wait_cmd;
end
state_lcd_reset_wait_cmd:begin //lcd take quite some time to process some commands
if(tx_finish_w)
begin
delay_counter <= delay_wait_init;
reset_state <= state_lcd_reset_wait_init;
end
else
begin
write_cmd <= 1'b0;
end
end
state_lcd_reset_wait_init:begin
reset_state <= state_lcd_activate_vee; //reset, reset state machine
if (lcd_test_i)
begin
reset_state <= state_lcd_reset_tp_write;
line_counter <= 8'h0;
end
else
begin
controller_state <= controller_state_idle;
end
end
state_lcd_reset_tp_write:begin
write_cmd <= 1'b1;
line_counter <= line_counter + 1'b1;
if (line_counter == 8'h0)
begin
command_r <= CMD_LCD_TP_FIRST;
end
else
begin
command_r <= CMD_LCD_TP_NEXT;
end
delay_counter <= 0;
reset_state <= state_lcd_reset_tp_wait;
end
state_lcd_reset_tp_wait:begin
if (tx_finish_w)
begin
if (line_counter < DISPLAY_LINE_MAX)
begin
reset_state <= state_lcd_reset_tp_write;
end
else
begin
reset_state <= state_lcd_activate_vee; //reset reset_state
controller_state <= controller_state_wait_cs;
end
end
else
begin
write_cmd <= 1'b0;
end
end
default:begin
reset_state <= state_lcd_activate_vee;
end
endcase
end
end
controller_state_idle: begin
spi_csn_reg1 <= spi_csn_i;
spi_csn_reg2 <= spi_csn_reg1;
spi_csn_reg3 <= spi_csn_reg2;
if (!spi_csn_reg3 & spi_csn_reg2)
begin
write_cmd <= spi_csn_i;
command_r <= spi_cmd;
controller_state <= controller_state_cmd_received;
end
end
controller_state_cmd_received: begin
controller_state <= controller_state_cmd_busy;
end
controller_state_cmd_busy: begin
if(tx_finish_w)
begin
controller_state <= controller_state_wait_cs;
end
else
begin
write_cmd <= 1'b0;
end
end
controller_state_wait_cs: begin
if (!spi_csn_i) //wait till spi_csn_i goes idle
begin
controller_state <= controller_state_idle;
end
end
default: begin
controller_state <= controller_state_idle;
end
endcase
end
end
reg first_byte;
assign fifo_write_en_r = !spi_csn_i;
always @(posedge reset_i or posedge spi_byte_clock or posedge spi_csn_i)
begin
if (reset_i)
begin
first_byte <= 1'b0;
spi_cmd <= 8'b0;
end
else
begin
if (spi_csn_i)
begin
first_byte <= 1'b0;
end
else
begin
if (first_byte == 1'b0)
begin
first_byte <= 1'b1;
spi_cmd <= spi_rxdata;
end
end
end
end
endmodule