| // Copyright lowRISC contributors. | |
| // Licensed under the Apache License, Version 2.0, see LICENSE for details. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // | |
| // USB IO Mux | |
| // | |
| // Muxes the USB IO signals between the override CSRs and the USB engine. The | |
| // incoming signals are also synchronized to the corresponding clock domain. | |
| module usbdev_iomux | |
| import usbdev_reg_pkg::*; | |
| ( | |
| input logic clk_i, | |
| input logic rst_ni, | |
| // Register interface | |
| output usbdev_hw2reg_phy_pins_sense_reg_t hw2reg_sense_o, | |
| input usbdev_reg2hw_phy_pins_drive_reg_t reg2hw_drive_i, | |
| // External USB Inputs (async) | |
| input logic usb_rx_d_i, | |
| input logic usb_rx_dp_i, | |
| input logic usb_rx_dn_i, | |
| input logic cio_usb_sense_i, | |
| // External USB outputs (usb clk) | |
| output logic usb_tx_d_o, | |
| output logic usb_tx_se0_o, | |
| output logic usb_tx_dp_o, | |
| output logic usb_tx_dn_o, | |
| output logic usb_tx_oe_o, | |
| output logic usb_dp_pullup_en_o, | |
| output logic usb_dn_pullup_en_o, | |
| output logic usb_rx_enable_o, | |
| // Internal USB Interface (usb clk) | |
| output logic usb_rx_d_o, | |
| output logic usb_rx_dp_o, | |
| output logic usb_rx_dn_o, | |
| input logic usb_tx_d_i, | |
| input logic usb_tx_se0_i, | |
| input logic usb_tx_dp_i, | |
| input logic usb_tx_dn_i, | |
| input logic usb_tx_oe_i, | |
| input logic usb_dp_pullup_en_i, | |
| input logic usb_dn_pullup_en_i, | |
| input logic usb_rx_enable_i, | |
| output logic usb_pwr_sense_o | |
| ); | |
| ////////// | |
| // CDCs // | |
| ////////// | |
| // USB input pins | |
| prim_flop_2sync #( | |
| .Width (4) | |
| ) cdc_io_to_usb ( | |
| .clk_i, | |
| .rst_ni, | |
| .d_i ({usb_rx_dp_i, | |
| usb_rx_dn_i, | |
| usb_rx_d_i, | |
| cio_usb_sense_i}), | |
| .q_o ({usb_rx_dp_o, | |
| usb_rx_dn_o, | |
| usb_rx_d_o, | |
| usb_pwr_sense_o}) | |
| ); | |
| // USB pins sense | |
| assign hw2reg_sense_o.rx_dp_i.d = usb_rx_dp_o; | |
| assign hw2reg_sense_o.rx_dn_i.d = usb_rx_dn_o; | |
| assign hw2reg_sense_o.rx_d_i.d = usb_rx_d_o; | |
| assign hw2reg_sense_o.pwr_sense.d = usb_pwr_sense_o; | |
| assign hw2reg_sense_o.tx_dp_o.d = usb_tx_dp_i; | |
| assign hw2reg_sense_o.tx_dn_o.d = usb_tx_dn_i; | |
| assign hw2reg_sense_o.tx_d_o.d = usb_tx_d_i; | |
| assign hw2reg_sense_o.tx_se0_o.d = usb_tx_se0_i; | |
| assign hw2reg_sense_o.tx_oe_o.d = usb_tx_oe_i; | |
| //////////////////////// | |
| // USB output pin mux // | |
| //////////////////////// | |
| always_comb begin : proc_drive_out | |
| if (reg2hw_drive_i.en.q) begin | |
| // Override from registers | |
| usb_dp_pullup_en_o = reg2hw_drive_i.dp_pullup_en_o.q; | |
| usb_dn_pullup_en_o = reg2hw_drive_i.dn_pullup_en_o.q; | |
| usb_rx_enable_o = reg2hw_drive_i.rx_enable_o.q; | |
| end else begin | |
| // Signals from the peripheral core | |
| usb_dp_pullup_en_o = usb_dp_pullup_en_i; | |
| usb_dn_pullup_en_o = usb_dn_pullup_en_i; | |
| usb_rx_enable_o = usb_rx_enable_i; | |
| end | |
| end | |
| // Use explicit muxes for the critical output signals, we do this | |
| // to avoid glitches from synthesized logic on these signals. | |
| // Clock muxes should be used here to achieve the best match between | |
| // rising and falling edges on an ASIC. This mismatch on the data line | |
| // degrades performance in the JK-KJ jitter test. | |
| prim_clock_mux2 #( | |
| .NoFpgaBufG(1) | |
| ) i_mux_tx_dp ( | |
| .clk0_i (usb_tx_dp_i), | |
| .clk1_i (reg2hw_drive_i.dp_o.q), | |
| .sel_i (reg2hw_drive_i.en.q), | |
| .clk_o (usb_tx_dp_o) | |
| ); | |
| prim_clock_mux2 #( | |
| .NoFpgaBufG(1) | |
| ) i_mux_tx_dn ( | |
| .clk0_i (usb_tx_dn_i), | |
| .clk1_i (reg2hw_drive_i.dn_o.q), | |
| .sel_i (reg2hw_drive_i.en.q), | |
| .clk_o (usb_tx_dn_o) | |
| ); | |
| prim_clock_mux2 #( | |
| .NoFpgaBufG(1) | |
| ) i_mux_tx_d ( | |
| .clk0_i (usb_tx_d_i), | |
| .clk1_i (reg2hw_drive_i.d_o.q), | |
| .sel_i (reg2hw_drive_i.en.q), | |
| .clk_o (usb_tx_d_o) | |
| ); | |
| prim_clock_mux2 #( | |
| .NoFpgaBufG(1) | |
| ) i_mux_tx_se0 ( | |
| .clk0_i (usb_tx_se0_i), | |
| .clk1_i (reg2hw_drive_i.se0_o.q), | |
| .sel_i (reg2hw_drive_i.en.q), | |
| .clk_o (usb_tx_se0_o) | |
| ); | |
| prim_clock_mux2 #( | |
| .NoFpgaBufG(1) | |
| ) i_mux_tx_oe ( | |
| .clk0_i (usb_tx_oe_i), | |
| .clk1_i (reg2hw_drive_i.oe_o.q), | |
| .sel_i (reg2hw_drive_i.en.q), | |
| .clk_o (usb_tx_oe_o) | |
| ); | |
| endmodule |