Browse Source

usb: change multiplex to allow more than one endpoint/bus

An upstream device might want to handle more than one endpoint using
the same bus "channel". Allow that to be configured instead of forcing
a multiplex that isn't wanted.
H. Peter Anvin 3 years ago
parent
commit
983dccd91f

BIN
fpga/output_files/max80.jic


BIN
fpga/output_files/max80.pof


+ 38 - 25
fpga/usb/usb_serial/src_v/usb_cdc_core.sv

@@ -47,7 +47,7 @@ module usb_cdc_core
    ,input inport_valid_i
    ,input [ 7:0] inport_data_i
    ,input outport_accept_i
-     
+
    // Outputs
    ,output [ 7:0] utmi_data_out_o
    ,output utmi_txvalid_o
@@ -174,9 +174,9 @@ module usb_cdc_core
    wire  usb_reset_w;
    reg [6:0] device_addr_q;
 
-   localparam endpoints = 4;
-   usb_endpoint usb_ep [0:endpoints-1] ();
-   
+   localparam endpoint_channels = 4;
+   usb_endpoint usb_ep [0:endpoint_channels-1] ();
+
    wire       utmi_chirp_en_w;
    wire       usb_hs_w;
 
@@ -200,8 +200,8 @@ module usb_cdc_core
 	   // 60MHz clock rate
 `define USB_RST_W  20
 	   reg [`USB_RST_W-1:0] usb_rst_time_q;
-	   reg [7:0] 		chirp_count_q;
-	   reg [1:0] 		last_linestate_q;
+	   reg [7:0]		chirp_count_q;
+	   reg [1:0]		last_linestate_q;
 
 	   localparam DETACH_TIME    = 20'd60000;  // 1ms -> T0
 	   localparam ATTACH_FS_TIME = 20'd180000; // T0 + 3ms = T1
@@ -209,11 +209,11 @@ module usb_cdc_core
 	   localparam HS_RESET_TIME  = 20'd600000; // T0 + 10ms = T9
 	   localparam HS_CHIRP_COUNT = 8'd5;
 
-	   reg [  1:0] 		utmi_op_mode_r;
-	   reg [  1:0] 		utmi_xcvrselect_r;
-	   reg 			utmi_termselect_r;
-	   reg 			utmi_dppulldown_r;
-	   reg 			utmi_dmpulldown_r;
+	   reg [  1:0]		utmi_op_mode_r;
+	   reg [  1:0]		utmi_xcvrselect_r;
+	   reg			utmi_termselect_r;
+	   reg			utmi_dppulldown_r;
+	   reg			utmi_dmpulldown_r;
 
 	   always @ *
 	     begin
@@ -357,7 +357,7 @@ module usb_cdc_core
 	   // Transceiver Control
 	   //-----------------------------------------------------------------
 	   reg [  1:0]  utmi_op_mode_r;
-	   reg [  1:0] 	utmi_xcvrselect_r;
+	   reg [  1:0]	utmi_xcvrselect_r;
 	   reg          utmi_termselect_r;
 	   reg          utmi_dppulldown_r;
 	   reg          utmi_dmpulldown_r;
@@ -397,7 +397,7 @@ module usb_cdc_core
    //-----------------------------------------------------------------
    // Core
    //-----------------------------------------------------------------
-   usbf_device_core #(.endpoints(endpoints))
+   usbf_device_core #(.endpoint_channels(endpoint_channels))
      u_core
        (
 	.clk_i(clk_i),
@@ -438,6 +438,9 @@ module usb_cdc_core
    reg       setup_data_q;
    reg       status_ready_q; // STATUS response received
 
+   assign usb_ep[0].c.ep_num   = 4'd0;
+   assign usb_ep[0].c.ep_mask  = 4'b1111;
+
    assign usb_ep[0].d.rx_space = 1'b1;
 
    always @ (posedge clk_i or posedge rst_i)
@@ -515,24 +518,24 @@ module usb_cdc_core
    //-----------------------------------------------------------------
    // Process setup request
    //-----------------------------------------------------------------
-   reg 	       ctrl_stall_r; // Send STALL
-   reg 	       ctrl_ack_r;   // Send STATUS (ZLP)
+   reg	       ctrl_stall_r; // Send STALL
+   reg	       ctrl_ack_r;   // Send STATUS (ZLP)
    reg [15:0]  ctrl_get_len_r;
 
    reg [7:0]   desc_addr_r;
 
-   reg 	       rx_break_q;
-   reg 	       rx_break_r;
+   reg	       rx_break_q;
+   reg	       rx_break_r;
 
-   reg 	       addressed_q;
-   reg 	       addressed_r;
+   reg	       addressed_q;
+   reg	       addressed_r;
    reg [6:0]   device_addr_r;
 
-   reg 	       configured_q;
-   reg 	       configured_r;
+   reg	       configured_q;
+   reg	       configured_r;
 
-   reg 	       set_with_data_q;
-   reg 	       set_with_data_r;
+   reg	       set_with_data_q;
+   reg	       set_with_data_r;
    wire        data_status_zlp_w;
 
    always @ *
@@ -932,14 +935,24 @@ module usb_cdc_core
    assign usb_ep[3].d.tx_data       = 8'bx;
    assign usb_ep[3].d.tx_data_last  = 1'b0;
    assign usb_ep[3].d.rx_space      = 1'b0;
-   
+
+   //-----------------------------------------------------------------
+   // Stream endpoint channel configuration
+   //-----------------------------------------------------------------
+   assign usb_ep[1].c.ep_num        = 4'd1;
+   assign usb_ep[1].c.ep_mask       = 4'b1111;
+   assign usb_ep[2].c.ep_num        = 4'd2;
+   assign usb_ep[2].c.ep_mask       = 4'b1111;
+   assign usb_ep[3].c.ep_num        = 4'd3;
+   assign usb_ep[3].c.ep_mask       = 4'b1111;
+
    //-----------------------------------------------------------------
    // Stream I/O
    //-----------------------------------------------------------------
    reg        inport_valid_q;
    reg [7:0]  inport_data_q;
    reg [10:0] inport_cnt_q;
-   reg 	      outport_break_q;
+   reg	      outport_break_q;
 
    always @ (posedge clk_i or posedge rst_i)
      if (rst_i)

+ 105 - 86
fpga/usb/usb_serial/src_v/usbf_device_core.sv

@@ -9,26 +9,26 @@
 //                         License: LGPL
 //-----------------------------------------------------------------
 //
-// This source file may be used and distributed without         
-// restriction provided that this copyright statement is not    
-// removed from the file and that any derivative work contains  
-// the original copyright notice and the associated disclaimer. 
+// This source file may be used and distributed without
+// restriction provided that this copyright statement is not
+// removed from the file and that any derivative work contains
+// the original copyright notice and the associated disclaimer.
 //
-// This source file is free software; you can redistribute it   
-// and/or modify it under the terms of the GNU Lesser General   
-// Public License as published by the Free Software Foundation; 
-// either version 2.1 of the License, or (at your option) any   
+// This source file is free software; you can redistribute it
+// and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation;
+// either version 2.1 of the License, or (at your option) any
 // later version.
 //
-// This source 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 Lesser General Public License for more 
+// This source 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 Lesser General Public License for more
 // details.
 //
-// You should have received a copy of the GNU Lesser General    
-// Public License along with this source; if not, write to the 
-// Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
+// You should have received a copy of the GNU Lesser General
+// Public License along with this source; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 // Boston, MA  02111-1307  USA
 //-----------------------------------------------------------------
 
@@ -37,6 +37,12 @@
 //-----------------------------------------------------------------
 
 package usb_endpoint_types;
+   // Endpoint channel configuration (normally static)
+   typedef struct {
+      logic [3:0] ep_num;
+      logic [3:0] ep_mask;
+   } usb_ep_c_t;
+
    // Downstream data
    typedef struct {
       logic       ep_stall;
@@ -49,13 +55,15 @@ package usb_endpoint_types;
       logic       tx_data_strb;
       logic [7:0] tx_data;
       logic       tx_data_last;
-   } d_t;
+   } usb_ep_d_t;
 
    // Per-endpoint upstream data
    typedef struct {
+      logic	  ep_selected;
       logic       rx_valid;
       logic       tx_data_accept;
-   } u_t;
+   } usb_ep_u_t;
+
    // Upstream data, shared between all endpoints; included here
    // to make the interface complete. If suitable for the upstream
    // device core, however, they do not need to be multiplexed.
@@ -65,67 +73,80 @@ package usb_endpoint_types;
       logic       rx_strb;
       logic       rx_last;
       logic       rx_crc_err;
-   } uc_t;
+      logic [3:0] ep_select;	  // Currently selected endpoint
+      logic	  ep_select_rx;	  // Selected for read
+   } usb_ep_uc_t;
 endpackage
 
 interface usb_endpoint;
    import usb_endpoint_types::*;
-   
-   d_t d;
-   u_t u;
-   uc_t uc;
+
+   usb_ep_c_t  c;
+   usb_ep_d_t  d;
+   usb_ep_u_t  u;
+   usb_ep_uc_t uc;
 
    // Upstream interface (toward application)
    modport ustr (
-		 input 	      d,
-		 output       u,
-		 output       uc
+		 input  c,
+		 input	d,
+		 output u,
+		 output uc
 		 );
 
    // Downstream interface (toward PHY)
    modport dstr (
-		 output       d,
-		 input 	      u,
-		 input 	      uc
+		 output c,
+		 output d,
+		 input	u,
+		 input	uc
 		 );
 endinterface // usb_endpoint
 
 module usbf_endpoint_mux
-  #(parameter endpoints = 4, epbits = 4)
+  #(parameter endpoint_channels = 4)
    (
-    input 	       valid_i,
-    input [epbits-1:0] ep_select_i,
-    usb_endpoint.ustr  ep_u [0:endpoints-1],
-    usb_endpoint.dstr  ep_d
+    input	      valid_i,
+    input [3:0]       ep_select_i,
+    input	      ep_select_rx_i,
+    usb_endpoint.ustr ep_u [0:endpoint_channels-1],
+    usb_endpoint.dstr ep_d
     );
 
    import usb_endpoint_types::*;
 
-   wire [endpoints-1:0] selected = valid_i << ep_select_i;
-
    // Quartus seems to need these intermediate variables
    // to be able to use structures here.
-   d_t   u_d [0:endpoints-1];
-   u_t   ep_d_u;
-   uc_t  ep_d_uc;
+   usb_ep_d_t   u_d [0:endpoint_channels-1];
+   usb_ep_u_t   ep_d_u;
+   usb_ep_uc_t  ep_d_uc;
+
+   logic [endpoint_channels-1:-1] selected;
+   assign selected[-1] = ~valid_i; // If not valid, prevents selection
 
    always_comb
      begin
-	ep_d_u  = ep_d.u;
-	ep_d_uc = ep_d.uc;
-	
+	ep_d_u             = ep_d.u;
+	ep_d_u.ep_selected = 1'b1;
+	ep_d_uc            = ep_d.uc;
+
+	ep_d.c = '{ default:'bx }; // Irrelevant
 	ep_d.d = '{ default:'b0 };
-	for (int j = 0; j < endpoints; j++)
+	for (int j = 0; j < endpoint_channels; j++)
 	  if (selected[j])
 	    ep_d.d = u_d[j];
      end
-   
+
    generate
-      genvar 	i;
-      for (i = 0; i < endpoints; i++)
+      genvar	i;
+      for (i = 0; i < endpoint_channels; i++)
 	begin : mux
 	   always_comb
 	     begin
+		selected[i] = ~|selected[i-1:-1] &&
+			      ((ep_select_i & ep_u[i].c.ep_mask) ==
+			       ep_u[i].c.ep_num);
+
 		ep_u[i].uc = ep_d_uc;
 		if (selected[i])
 		  ep_u[i].u = ep_d_u;
@@ -139,7 +160,7 @@ module usbf_endpoint_mux
 endmodule
 
 module usbf_device_core
-  #(parameter endpoints = 4)
+  #(parameter endpoint_channels = 1)
   (
    // Inputs
    input clk_i
@@ -155,7 +176,7 @@ module usbf_device_core
    ,input reg_int_en_sof_i
    ,input reg_sts_rst_clr_i
    ,input [ 6:0] reg_dev_addr_i
-     
+
    // Outputs
    ,output intr_o
    ,output [ 7:0] utmi_data_o
@@ -164,11 +185,11 @@ module usbf_device_core
    ,output [ 10:0] reg_sts_frame_num_o
 
    // Endpoint interfaces
-   ,usb_endpoint.ustr ep[0:endpoints-1]
+   ,usb_endpoint.ustr ep[0:endpoint_channels-1]
    );
 
    genvar e;
-   
+
    //-----------------------------------------------------------------
    // Defines:
    //-----------------------------------------------------------------
@@ -199,7 +220,7 @@ module usbf_device_core
        begin
 	  if (!se0_cnt_q[`USB_RESET_CNT_W-1])
             se0_cnt_q <= se0_cnt_q + `USB_RESET_CNT_W'd1;
-       end    
+       end
      else
        se0_cnt_q <= `USB_RESET_CNT_W'b0;
 
@@ -234,17 +255,17 @@ module usbf_device_core
 
    reg                     tx_data_valid_r;
    reg                     tx_data_strb_r;
-   reg [7:0] 		   tx_data_r;
-   reg 			   tx_data_last_r;
+   reg [7:0]		   tx_data_r;
+   reg			   tx_data_last_r;
    wire                    tx_data_accept_w;
-   
-   wire [7:0] 		   rx_data_w;
-   wire 		   rx_strb_w;
-   wire 		   rx_last_w;
+
+   wire [7:0]		   rx_data_w;
+   wire			   rx_strb_w;
+   wire			   rx_last_w;
    wire			   rx_crc_err_w;
 
-   reg 			   tx_valid_q;
-   reg [7:0] 		   tx_pid_q;
+   reg			   tx_valid_q;
+   reg [7:0]		   tx_pid_q;
    wire                    tx_accept_w;
 
    reg                     rx_space_q;
@@ -260,8 +281,8 @@ module usbf_device_core
    reg                     rx_setup_q;
 
    // Note: these registers are forced to zero for invalid endpoints
-   reg [usb_ep_max:0] 	   out_data_bit_q;
-   reg [usb_ep_max:0] 	   in_data_bit_q;
+   reg [usb_ep_max:0]	   out_data_bit_q;
+   reg [usb_ep_max:0]	   in_data_bit_q;
 
    reg [`USB_DEV_W-1:0]    current_addr_q;
 
@@ -270,18 +291,19 @@ module usbf_device_core
    //-----------------------------------------------------------------
    usb_endpoint ept ();		// Endpoint selected by token
 
-   usbf_endpoint_mux #(.endpoints(endpoints), .epbits(`USB_EP_W))
+   usbf_endpoint_mux #(.endpoint_channels(endpoint_channels))
    u_endpoint_mux
      (
       .valid_i     ( ~rst_i & ~usb_rst_w ),
       .ep_select_i ( token_ep_w ),
+      .ep_select_rx_i ( token_pid_w == `PID_IN || token_pid_w == `PID_PING ),
       .ep_u        ( ep ),
       .ep_d        ( ept.dstr )
       );
 
    assign ep_stall_r = ept.d.ep_stall;
    assign ep_iso_r   = ept.d.ep_iso;
-   
+
 //-----------------------------------------------------------------
 // SIE - TX
 //-----------------------------------------------------------------
@@ -290,20 +312,20 @@ module usbf_device_core
        (
 	.clk_i(clk_i),
 	.rst_i(rst_i),
-	
+
 	.enable_i(~usb_rst_w),
 	.chirp_i(reg_chirp_en_i),
-	
+
 	// UTMI Interface
 	.utmi_data_o(utmi_data_o),
 	.utmi_txvalid_o(utmi_txvalid_o),
 	.utmi_txready_i(utmi_txready_i),
-	
+
 	// Request
 	.tx_valid_i(tx_valid_q),
 	.tx_pid_i(tx_pid_q),
 	.tx_accept_o(tx_accept_w),
-	
+
 	// Data
 	.data_valid_i(tx_data_valid_r),
 	.data_strb_i(tx_data_strb_r),
@@ -328,33 +350,33 @@ module usbf_device_core
        (
 	.clk_i(clk_i),
 	.rst_i(rst_i),
-	
+
 	.enable_i(~usb_rst_w && ~reg_chirp_en_i),
-	
+
 	// UTMI Interface
 	.utmi_data_i(utmi_data_i),
 	.utmi_rxvalid_i(utmi_rxvalid_i),
 	.utmi_rxactive_i(utmi_rxactive_i),
-	
+
 	.current_addr_i(current_addr_q),
-	
+
 	.pid_o(token_pid_w),
-	
+
 	.frame_valid_o(frame_valid_w),
 	.frame_number_o(reg_sts_frame_num_o),
-	
+
 	.token_valid_o(token_valid_w),
 	.token_addr_o(token_dev_w),
 	.token_ep_o(token_ep_w),
 	.token_crc_err_o(),
-	
+
 	.handshake_valid_o(rx_handshake_w),
-	
+
 	.data_valid_o(rx_data_valid_w),
 	.data_strb_o(rx_strb_w),
 	.data_o(rx_data_w),
 	.data_last_o(rx_last_w),
-	
+
 	.data_complete_o(rx_data_complete_w),
 	.data_crc_err_o(rx_crc_err_w)
 	);
@@ -374,7 +396,7 @@ module usbf_device_core
    assign ept.uc.rx_strb    = rx_strb_w;
    assign ept.uc.rx_last    = rx_last_w;
    assign ept.uc.rx_crc_err = rx_crc_err_w;
-   
+
    //-----------------------------------------------------------------
    // Next state
    //-----------------------------------------------------------------
@@ -533,7 +555,7 @@ module usbf_device_core
 
 	//-----------------------------------------
 	// USB Bus Reset (HOST->DEVICE)
-	//----------------------------------------- 
+	//-----------------------------------------
 	if (usb_rst_w && !reg_chirp_en_i)
           next_state_r  = STATE_RX_IDLE;
      end
@@ -719,7 +741,7 @@ module usbf_device_core
    wire ep0_tx_zlp_w = ep[0].d.tx_data_valid & ~ep[0].d.tx_data_strb &
 	ep[0].d.tx_data_last & ep[0].u.tx_data_accept;
 
-   reg 	sent_status_zlp_q;
+   reg	sent_status_zlp_q;
 
    always @ (posedge clk_i or posedge rst_i)
      if (rst_i)
@@ -751,8 +773,8 @@ module usbf_device_core
    //-----------------------------------------------------------------
    // Endpoint data bit toggle
    //-----------------------------------------------------------------
-   reg 	new_out_bit_r;
-   reg 	new_in_bit_r;
+   reg	new_out_bit_r;
+   reg	new_in_bit_r;
 
    always @ *
      begin
@@ -829,11 +851,8 @@ module usbf_device_core
 	 end
        else
 	 begin
-	    if ((token_ep_w < endpoints) && ~usb_rst_w)
-	      begin
-		 out_data_bit_q[token_ep_w] <= new_out_bit_r;
-		 in_data_bit_q [token_ep_w] <= new_in_bit_r;
-	      end
+	    out_data_bit_q[token_ep_w] <= new_out_bit_r;
+	    in_data_bit_q [token_ep_w] <= new_in_bit_r;
 	 end // else: !if(rst_i)
 
    assign out_data_bit_r = out_data_bit_q[token_ep_w];
@@ -876,7 +895,7 @@ module usbf_device_core
        intr_q <= 1'b1;
    // Tx complete
      else if (state_q == STATE_TX_DATA_COMPLETE && cfg_int_tx_r)
-       intr_q <= 1'b1;    
+       intr_q <= 1'b1;
      else
        intr_q <= 1'b0;