../src/lowrisc_ip_usbdev_0.1/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, single-ended signaling
   9: // and swaps D+/D- if configured. The incomming signals are also muxed and synchronized to the
  10: // corresponding clock domain.
  11: 
  12: module usbdev_iomux
  13:   import usbdev_reg_pkg::*;
  14: (
  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_48mhz_ni,
  19: 
  20:   // Register interface (system clk, quasi-static)
  21:   input  usbdev_reg2hw_phy_config_reg_t sys_reg2hw_config_i,
  22:   output logic                          sys_usb_sense_o,
  23: 
  24:   // External USB Interface(s) (async)
  25:   input  logic                          cio_usb_d_i,
  26:   input  logic                          cio_usb_dp_i,
  27:   input  logic                          cio_usb_dn_i,
  28: 
  29:   output logic                          cio_usb_d_o,
  30:   output logic                          cio_usb_se0_o,
  31:   output logic                          cio_usb_dp_o,
  32:   output logic                          cio_usb_dn_o,
  33:   output logic                          cio_usb_oe_o,
  34: 
  35:   output logic                          cio_usb_tx_mode_se_o,
  36:   input  logic                          cio_usb_sense_i,
  37:   output logic                          cio_usb_dp_pullup_en_o,
  38:   output logic                          cio_usb_dn_pullup_en_o,
  39:   output logic                          cio_usb_suspend_o,
  40: 
  41:   // Internal USB Interface (usb clk)
  42:   output logic                          usb_rx_d_o,
  43:   output logic                          usb_rx_se0_o,
  44: 
  45:   input  logic                          usb_tx_d_i,
  46:   input  logic                          usb_tx_se0_i,
  47:   input  logic                          usb_tx_oe_i,
  48: 
  49:   output logic                          usb_pwr_sense_o,
  50:   input  logic                          usb_pullup_en_i,
  51:   input  logic                          usb_suspend_i
  52: );
  53: 
  54:   logic async_pwr_sense, sys_usb_sense;
  55:   logic cio_usb_dp, cio_usb_dn, cio_usb_d;
  56:   logic usb_rx_dp, usb_rx_dn, usb_rx_d;
  57:   logic pinflip;
  58:   logic unused_eop_single_bit;
  59:   logic unused_usb_ref_disable;
  60: 
  61:   assign unused_eop_single_bit  = sys_reg2hw_config_i.eop_single_bit.q;
  62:   assign unused_usb_ref_disable = sys_reg2hw_config_i.usb_ref_disable.q;
  63: 
  64:   //////////
  65:   // CDCs //
  66:   //////////
  67: 
  68:   // USB sense pin (to sysclk)
  69:   prim_flop_2sync #(
  70:     .Width (1)
  71:   ) cdc_io_to_sys (
  72:     .clk_i  (clk_i),
  73:     .rst_ni (rst_ni),
  74:     .d      ({cio_usb_sense_i}),
  75:     .q      ({sys_usb_sense})
  76:   );
  77: 
  78:   assign sys_usb_sense_o = sys_usb_sense;
  79: 
  80:   // USB input pins (to usbclk)
  81:   prim_flop_2sync #(
  82:     .Width (4)
  83:   ) cdc_io_to_usb (
  84:     .clk_i  (clk_usb_48mhz_i),
  85:     .rst_ni (rst_usb_48mhz_ni),
  86:     .d      ({cio_usb_dp_i,
  87:               cio_usb_dn_i,
  88:               cio_usb_d_i,
  89:               async_pwr_sense}),
  90:     .q      ({cio_usb_dp,
  91:               cio_usb_dn,
  92:               cio_usb_d,
  93:               usb_pwr_sense_o})
  94:   );
  95: 
  96:   ////////////////////////
  97:   // USB output pin mux //
  98:   ////////////////////////
  99: 
 100:   // D+/D- can be swapped based on a config register.
 101:   assign pinflip = sys_reg2hw_config_i.pinflip.q;
 102: 
 103:   assign cio_usb_d_o            = pinflip ? ~usb_tx_d_i     : usb_tx_d_i;
 104:   assign cio_usb_dp_pullup_en_o = pinflip ? 1'b0            : usb_pullup_en_i;
 105:   assign cio_usb_dn_pullup_en_o = pinflip ? usb_pullup_en_i : 1'b0;
 106: 
 107:   always_comb begin : proc_diff_se_mux_out
 108:     // Defaults
 109:     cio_usb_dn_o           = 1'b0;
 110:     cio_usb_dp_o           = 1'b0;
 111: 
 112:     // The single-ended signals are only driven in single-ended mode.
 113:     if (sys_reg2hw_config_i.tx_differential_mode.q) begin
 114:       // Differential TX mode
 115:       cio_usb_tx_mode_se_o   = 1'b0;
 116: 
 117:     end else begin
 118:       // Single-ended TX mode
 119:       cio_usb_tx_mode_se_o   = 1'b1;
 120:       if (usb_tx_se0_i) begin
 121:         cio_usb_dp_o = 1'b0;
 122:         cio_usb_dn_o = 1'b0;
 123:       end else begin
 124:         cio_usb_dp_o = pinflip ? ~usb_tx_d_i :  usb_tx_d_i;
 125:         cio_usb_dn_o = pinflip ?  usb_tx_d_i : ~usb_tx_d_i;
 126:       end
 127:     end
 128:   end
 129: 
 130:   // It would be possible to insert explicit controllability muxes here.
 131:   // For now, we just pass the signal through
 132:   assign cio_usb_oe_o      = usb_tx_oe_i;
 133:   assign cio_usb_se0_o     = usb_tx_se0_i;
 134:   assign cio_usb_suspend_o = usb_suspend_i;
 135: 
 136:   ///////////////////////
 137:   // USB input pin mux //
 138:   ///////////////////////
 139: 
 140:   // Note that while transmitting, we fix the receive line to 1. If the receive line isn't fixed,
 141:   // we are trying to regenerate the bit clock from the bit clock we are regenerating, rather than
 142:   // just holding the phase.
 143:   // D+/D- can be swapped based on a config register.
 144:   assign usb_rx_dp = usb_tx_oe_i ? 1'b1 : (pinflip ?  cio_usb_dn : cio_usb_dp);
 145:   assign usb_rx_dn = usb_tx_oe_i ? 1'b0 : (pinflip ?  cio_usb_dp : cio_usb_dn);
 146:   assign usb_rx_d  = usb_tx_oe_i ? 1'b1 : (pinflip ? ~cio_usb_d  : cio_usb_d);
 147: 
 148:   always_comb begin : proc_diff_se_mux_in
 149:     usb_rx_se0_o = ~usb_rx_dp & ~usb_rx_dn;
 150: 
 151:     if (sys_reg2hw_config_i.rx_differential_mode.q) begin
 152:       // Differential RX mode
 153:       usb_rx_d_o = usb_rx_d;
 154: 
 155:     end else begin
 156:       // Single-ended RX mode
 157:       usb_rx_d_o = usb_rx_dp; // SE1 is interpreted as differential 1
 158:     end
 159:   end
 160: 
 161:   // Power sense mux
 162:   always_comb begin : proc_mux_pwr_sense
 163:     if (sys_reg2hw_config_i.override_pwr_sense_en.q) begin
 164:       async_pwr_sense = sys_reg2hw_config_i.override_pwr_sense_val.q;
 165:     end else begin
 166:       async_pwr_sense = cio_usb_sense_i;
 167:     end
 168:   end
 169: 
 170: endmodule
 171: