blob: c21d8e233b5eae0b2f38be8c826b52f369f95974 [file] [log] [blame]
// 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,
input logic clk_usb_48mhz_i, // use usb_ prefix for signals in this clk
input logic rst_usb_48mhz_ni,
// Register interface (system clk)
output usbdev_hw2reg_phy_pins_sense_reg_t sys_hw2reg_sense_o,
input usbdev_reg2hw_phy_pins_drive_reg_t sys_reg2hw_drive_i,
output logic sys_usb_sense_o,
// External USB Interface(s) (async)
input logic usb_rx_d_i,
input logic usb_rx_dp_i,
input logic usb_rx_dn_i,
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,
input logic cio_usb_sense_i,
output logic usb_dp_pullup_en_o,
output logic usb_dn_pullup_en_o,
output logic usb_suspend_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_suspend_i,
input logic usb_rx_enable_i,
output logic usb_pwr_sense_o
);
logic sys_usb_sense;
//////////
// CDCs //
//////////
// USB pins sense (to sysclk)
prim_flop_2sync #(
.Width (10)
) cdc_io_to_sys (
.clk_i (clk_i),
.rst_ni (rst_ni),
.d_i ({usb_rx_dp_i,
usb_rx_dn_i,
usb_rx_d_i,
usb_tx_dp_i,
usb_tx_dn_i,
usb_tx_d_i,
usb_tx_se0_i,
usb_tx_oe_i,
usb_suspend_i,
cio_usb_sense_i}),
.q_o ({sys_hw2reg_sense_o.rx_dp_i.d,
sys_hw2reg_sense_o.rx_dn_i.d,
sys_hw2reg_sense_o.rx_d_i.d,
sys_hw2reg_sense_o.tx_dp_o.d,
sys_hw2reg_sense_o.tx_dn_o.d,
sys_hw2reg_sense_o.tx_d_o.d,
sys_hw2reg_sense_o.tx_se0_o.d,
sys_hw2reg_sense_o.tx_oe_o.d,
sys_hw2reg_sense_o.suspend_o.d,
sys_usb_sense})
);
assign sys_usb_sense_o = sys_usb_sense;
assign sys_hw2reg_sense_o.pwr_sense.d = sys_usb_sense;
// USB input pins (to usbclk)
prim_flop_2sync #(
.Width (4)
) cdc_io_to_usb (
.clk_i (clk_usb_48mhz_i),
.rst_ni (rst_usb_48mhz_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 output pin mux //
////////////////////////
always_comb begin : proc_drive_out
if (sys_reg2hw_drive_i.en.q) begin
// Override from registers
usb_dp_pullup_en_o = sys_reg2hw_drive_i.dp_pullup_en_o.q;
usb_dn_pullup_en_o = sys_reg2hw_drive_i.dn_pullup_en_o.q;
usb_suspend_o = sys_reg2hw_drive_i.suspend_o.q;
usb_rx_enable_o = sys_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_suspend_o = usb_suspend_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 (sys_reg2hw_drive_i.dp_o.q),
.sel_i (sys_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 (sys_reg2hw_drive_i.dn_o.q),
.sel_i (sys_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 (sys_reg2hw_drive_i.d_o.q),
.sel_i (sys_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 (sys_reg2hw_drive_i.se0_o.q),
.sel_i (sys_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 (sys_reg2hw_drive_i.oe_o.q),
.sel_i (sys_reg2hw_drive_i.en.q),
.clk_o (usb_tx_oe_o)
);
endmodule