hw/ip/usbdev/rtl/usbdev_iomux.sv Cov: 100%

   1: // Copyright lowRISC contributors.
   2: // Copyright ETH Zurich.
   3: // Licensed under the Apache License, Version 2.0, see LICENSE for details.
   4: // SPDX-License-Identifier: Apache-2.0
   5: //
   6: //  USB IO Mux
   7: //
   8: //  Muxes the USB IO signals from: register access, differential signaling,
   9: //  single-ended signaling. The incomming signals are also muxed and synchronized
  10: //  to the corresponding clock domain.
  11: 
  12: import usbdev_reg_pkg::*;
  13: 
  14: module usbdev_iomux (
  15:   input  logic                          clk_i,
  16:   input  logic                          rst_ni,
  17:   input  logic                          clk_usb_48mhz_i, // use usb_ prefix for signals in this clk
  18:   input  logic                          rst_usb_ni,
  19: 
  20:   // Configuration (quasi-static)
  21:   input  logic                          rx_differential_mode_i,
  22:   input  logic                          tx_differential_mode_i,
  23: 
  24:   // Register interface (system clk)
  25:   input  usbdev_reg2hw_phy_config_reg_t sys_reg2hw_config_i,
  26:   output logic                          sys_usb_sense_o,
  27: 
  28:   // External USB Interface(s) (async)
  29:   input  logic                          cio_usb_d_i,
  30:   input  logic                          cio_usb_dp_i,
  31:   input  logic                          cio_usb_dn_i,
  32: 
  33:   output logic                          cio_usb_d_o,
  34:   output logic                          cio_usb_se0_o,
  35:   output logic                          cio_usb_dp_o,
  36:   output logic                          cio_usb_dn_o,
  37:   output logic                          cio_usb_oe_o,
  38: 
  39:   output logic                          cio_usb_tx_mode_se_o,
  40:   input  logic                          cio_usb_sense_i,
  41:   output logic                          cio_usb_pullup_en_o,
  42:   output logic                          cio_usb_suspend_o,
  43: 
  44:   // Internal USB Interface (usb clk)
  45:   output logic                          usb_rx_d_o,
  46:   output logic                          usb_rx_se0_o,
  47: 
  48:   input  logic                          usb_tx_d_i,
  49:   input  logic                          usb_tx_se0_i,
  50:   input  logic                          usb_tx_oe_i,
  51: 
  52:   output logic                          usb_pwr_sense_o,
  53:   input  logic                          usb_pullup_en_i,
  54:   input  logic                          usb_suspend_i
  55: );
  56: 
  57:   logic async_pwr_sense;
  58: 
  59:   logic sys_usb_sense;
  60: 
  61:   logic usb_rx_d;
  62:   logic usb_rx_dp;
  63:   logic usb_rx_dn;
  64: 
  65:   //////////
  66:   // CDCs //
  67:   //////////
  68: 
  69:   // USB pins sense (to sysclk)
  70:   prim_flop_2sync #(
  71:     .Width (1)
  72:   ) cdc_io_to_sys (
  73:     .clk_i  (clk_i),
  74:     .rst_ni (rst_ni),
  75:     .d      ({cio_usb_sense_i}),
  76:     .q      ({sys_usb_sense})
  77:   );
  78: 
  79:   assign sys_usb_sense_o                = sys_usb_sense;
  80: 
  81:   // USB input pins (to usbclk)
  82:   prim_flop_2sync #(
  83:     .Width (4)
  84:   ) cdc_io_to_usb (
  85:     .clk_i  (clk_usb_48mhz_i),
  86:     .rst_ni (rst_usb_ni),
  87:     .d      ({cio_usb_dp_i,
  88:               cio_usb_dn_i,
  89:               cio_usb_d_i,
  90:               async_pwr_sense}),
  91:     .q      ({usb_rx_dp,
  92:               usb_rx_dn,
  93:               usb_rx_d,
  94:               usb_pwr_sense_o})
  95:   );
  96: 
  97:   ///////////////////////////////
  98:   // USB output pins drive mux //
  99:   ///////////////////////////////
 100:   always_comb begin : proc_drive_out
 101:     // Defaults
 102:     cio_usb_dn_o           = 1'b0;
 103:     cio_usb_dp_o           = 1'b0;
 104: 
 105:     // Signals from the peripheral core
 106:     cio_usb_pullup_en_o    = usb_pullup_en_i;
 107:     cio_usb_suspend_o      = usb_suspend_i;
 108: 
 109:     if (tx_differential_mode_i) begin
 110:       // Differential mode
 111:       cio_usb_tx_mode_se_o   = 1'b0;
 112: 
 113:     end else begin
 114:       // Single-ended mode
 115:       cio_usb_tx_mode_se_o   = 1'b1;
 116:       if (usb_tx_se0_i) begin
 117:         cio_usb_dp_o = 1'b0;
 118:         cio_usb_dn_o = 1'b0;
 119:       end else begin
 120:         cio_usb_dp_o = usb_tx_d_i;
 121:         cio_usb_dn_o = !usb_tx_d_i;
 122:       end
 123:     end
 124:   end
 125: 
 126:   // It would be possible to insert explicit controllability muxes here.
 127:   // For now, we just pass the signal through
 128:   assign cio_usb_d_o   = usb_tx_d_i;
 129:   assign cio_usb_se0_o = usb_tx_se0_i;
 130:   assign cio_usb_oe_o  = usb_tx_oe_i;
 131: 
 132:   ///////////////////////
 133:   // USB input pin mux //
 134:   ///////////////////////
 135:   always_comb begin : proc_mux_data_input
 136:     usb_rx_se0_o = ~usb_rx_dp & ~usb_rx_dn;
 137: 
 138:     if (rx_differential_mode_i) begin
 139:       // Differential RX mode
 140:       usb_rx_d_o = usb_rx_d;
 141: 
 142:     end else begin
 143:       // Single-ended RX mode
 144:       usb_rx_d_o = usb_rx_dp; // SE1 is interpreted as differential 1
 145:     end
 146:   end
 147: 
 148:   // Power sense mux
 149:   always_comb begin : proc_mux_pwr_input
 150:     if (sys_reg2hw_config_i.override_pwr_sense_en.q) begin
 151:       async_pwr_sense = sys_reg2hw_config_i.override_pwr_sense_val.q;
 152:     end else begin
 153:       async_pwr_sense = cio_usb_sense_i;
 154:     end
 155:   end
 156: 
 157: endmodule
 158: