OpenCores
URL https://opencores.org/ocsvn/ulpi_wrapper/ulpi_wrapper/trunk

Subversion Repositories ulpi_wrapper

[/] [ulpi_wrapper/] [trunk/] [rtl/] [ulpi_wrapper.v] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 ultra_embe
//-----------------------------------------------------------------
2
//                        ULPI (Link) Wrapper
3
//                              V0.1
4
//                        Ultra-Embedded.com
5
//                          Copyright 2015
6
//
7
//                 Email: admin@ultra-embedded.com
8
//
9
//                         License: GPL
10
// If you would like a version with a more permissive license for
11
// use in closed source commercial applications please contact me
12
// for details.
13
//-----------------------------------------------------------------
14
//
15
// This file is open source HDL; you can redistribute it and/or 
16
// modify it under the terms of the GNU General Public License as 
17
// published by the Free Software Foundation; either version 2 of 
18
// the License, or (at your option) any later version.
19
//
20
// This file is distributed in the hope that it will be useful,
21
// but WITHOUT ANY WARRANTY; without even the implied warranty of
22
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23
// GNU General Public License for more details.
24
//
25
// You should have received a copy of the GNU General Public 
26
// License along with this file; if not, write to the Free Software
27
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28
// USA
29
//-----------------------------------------------------------------
30
 
31
//-----------------------------------------------------------------
32
// Module: UTMI+ to ULPI Wrapper
33
//
34
// Description:
35
//   - Converts from UTMI interface to reduced pin count ULPI.
36
//   - No support for low power mode.
37
//   - I/O synchronous to 60MHz ULPI clock input (from PHY)
38
//   - Tested against SMSC/Microchip USB3300 in device mode.
39
//-----------------------------------------------------------------
40
module ulpi_wrapper
41
(
42
    // ULPI Interface (PHY)
43
    input             ulpi_clk60_i,
44
    input             ulpi_rst_i,
45
    input  [7:0]      ulpi_data_i,
46
    output [7:0]      ulpi_data_o,
47
    input             ulpi_dir_i,
48
    input             ulpi_nxt_i,
49
    output            ulpi_stp_o,
50
 
51
    // UTMI Interface (SIE)
52
    input             utmi_txvalid_i,
53
    output            utmi_txready_o,
54
    output            utmi_rxvalid_o,
55
    output            utmi_rxactive_o,
56
    output            utmi_rxerror_o,
57
    output [7:0]      utmi_data_o,
58
    input  [7:0]      utmi_data_i,
59
    input  [1:0]      utmi_xcvrselect_i,
60
    input             utmi_termselect_i,
61
    input  [1:0]      utmi_opmode_i,
62
    input             utmi_dppulldown_i,
63
    input             utmi_dmpulldown_i,
64
    output [1:0]      utmi_linestate_o
65
);
66
 
67
//-----------------------------------------------------------------
68
// States
69
//-----------------------------------------------------------------
70
localparam STATE_W          = 2;
71
localparam STATE_IDLE       = 2'd0;
72
localparam STATE_CMD        = 2'd1;
73
localparam STATE_DATA       = 2'd2;
74
localparam STATE_WAIT       = 2'd3;
75
 
76
reg [STATE_W-1:0]   state_q;
77
 
78
//-----------------------------------------------------------------
79
// UTMI Mode Select
80
//-----------------------------------------------------------------
81
reg         mode_update_q;
82
reg [1:0]   xcvrselect_q;
83
reg         termselect_q;
84
reg [1:0]   opmode_q;
85
reg         phy_reset_q;
86
 
87
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
88
if (ulpi_rst_i)
89
begin
90
    mode_update_q   <= 1'b0;
91
    xcvrselect_q    <= 2'b0;
92
    termselect_q    <= 1'b0;
93
    opmode_q        <= 2'b11;
94
    phy_reset_q     <= 1'b1;
95
end
96
else
97
begin
98
    xcvrselect_q    <= utmi_xcvrselect_i;
99
    termselect_q    <= utmi_termselect_i;
100
    opmode_q        <= utmi_opmode_i;
101
 
102
    if (mode_update_q && (state_q == STATE_IDLE) && !ulpi_dir_i)
103
    begin
104
        mode_update_q <= 1'b0;
105
        phy_reset_q   <= 1'b0;
106
    end
107
    else if (opmode_q     != utmi_opmode_i     ||
108
             termselect_q != utmi_termselect_i ||
109
             xcvrselect_q != utmi_xcvrselect_i)
110
        mode_update_q <= 1'b1;
111
end
112
 
113
//-----------------------------------------------------------------
114
// UTMI OTG Control
115
//-----------------------------------------------------------------
116
reg otg_update_q;
117
reg dppulldown_q;
118
reg dmpulldown_q;
119
 
120
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
121
if (ulpi_rst_i)
122
begin
123
    otg_update_q    <= 1'b0;
124
    dppulldown_q    <= 1'b1;
125
    dmpulldown_q    <= 1'b1;
126
end
127
else
128
begin
129
    dppulldown_q    <= utmi_dppulldown_i;
130
    dmpulldown_q    <= utmi_dmpulldown_i;
131
 
132
    if (otg_update_q && !mode_update_q && (state_q == STATE_IDLE) && !ulpi_dir_i)
133
        otg_update_q <= 1'b0;
134
    else if (dppulldown_q != utmi_dppulldown_i ||
135
             dmpulldown_q != utmi_dmpulldown_i)
136
        otg_update_q <= 1'b1;
137
end
138
 
139
//-----------------------------------------------------------------
140
// Bus turnaround detect
141
//-----------------------------------------------------------------
142
reg ulpi_dir_q;
143
 
144
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
145
if (ulpi_rst_i)
146
    ulpi_dir_q <= 1'b0;
147
else
148
    ulpi_dir_q <= ulpi_dir_i;
149
 
150
wire turnaround_w = ulpi_dir_q ^ ulpi_dir_i;
151
 
152
//-----------------------------------------------------------------
153
// Rx - Tx delay
154
//-----------------------------------------------------------------
155
localparam TX_DELAY_W       = 3;
156
localparam TX_START_DELAY   = 3'd7;
157
 
158
reg [TX_DELAY_W-1:0] tx_delay_q;
159
 
160
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
161
if (ulpi_rst_i)
162
    tx_delay_q <= {TX_DELAY_W{1'b0}};
163
else if (utmi_rxactive_o)
164
    tx_delay_q <= TX_START_DELAY;
165
else if (tx_delay_q != {TX_DELAY_W{1'b0}})
166
    tx_delay_q <= tx_delay_q - 1;
167
 
168
wire tx_delay_complete_w = (tx_delay_q == {TX_DELAY_W{1'b0}});
169
 
170
//-----------------------------------------------------------------
171
// Tx Buffer - decouple UTMI Tx from PHY I/O
172
//-----------------------------------------------------------------
173
reg [7:0] tx_buffer_q[0:1];
174
reg       tx_valid_q[0:1];
175
reg       tx_wr_idx_q;
176
reg       tx_rd_idx_q;
177
 
178
wire      utmi_tx_ready_w;
179
wire      utmi_tx_accept_w;
180
 
181
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
182
if (ulpi_rst_i)
183
begin
184
    tx_buffer_q[0] <= 8'b0;
185
    tx_buffer_q[1] <= 8'b0;
186
    tx_valid_q[0]  <= 1'b0;
187
    tx_valid_q[1]  <= 1'b0;
188
    tx_wr_idx_q    <= 1'b0;
189
    tx_rd_idx_q    <= 1'b0;
190
end
191
else
192
begin
193
    // Push
194
    if (utmi_txvalid_i && utmi_txready_o)
195
    begin
196
        tx_buffer_q[tx_wr_idx_q] <= utmi_data_i;
197
        tx_valid_q[tx_wr_idx_q]  <= 1'b1;
198
 
199
        tx_wr_idx_q <= tx_wr_idx_q + 1'b1;
200
    end
201
 
202
    // Pop
203
    if (utmi_tx_ready_w && utmi_tx_accept_w)
204
    begin
205
        tx_valid_q[tx_rd_idx_q]  <= 1'b0;
206
        tx_rd_idx_q <= tx_rd_idx_q + 1'b1;
207
    end
208
end
209
 
210
// Tx buffer space (only accept after Rx->Tx turnaround delay)
211
assign utmi_txready_o  = ~tx_valid_q[tx_wr_idx_q] & tx_delay_complete_w;
212
 
213
assign utmi_tx_ready_w = tx_valid_q[tx_rd_idx_q];
214
 
215
wire [7:0] utmi_tx_data_w = tx_buffer_q[tx_rd_idx_q];
216
 
217
//-----------------------------------------------------------------
218
// Implementation
219
//-----------------------------------------------------------------
220
 
221
// Xilinx placement pragmas:
222
//synthesis attribute IOB of ulpi_data_q is "TRUE"
223
//synthesis attribute IOB of ulpi_stp_q is "TRUE"
224
 
225
reg [7:0]           ulpi_data_q;
226
reg                 ulpi_stp_q;
227
reg [7:0]           data_q;
228
 
229
reg                 utmi_rxvalid_q;
230
reg                 utmi_rxerror_q;
231
reg                 utmi_rxactive_q;
232
reg [1:0]           utmi_linestate_q;
233
reg [7:0]           utmi_data_q;
234
 
235
reg                 cmd_wr_q;
236
 
237
localparam REG_FUNC_CTRL = 8'h84;
238
localparam REG_OTG_CTRL  = 8'h8a;
239
localparam REG_TRANSMIT  = 8'h40;
240
localparam REG_WRITE     = 8'h80;
241
localparam REG_READ      = 8'hC0;
242
 
243
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
244
begin
245
    if (ulpi_rst_i)
246
    begin
247
        state_q             <= STATE_IDLE;
248
        ulpi_data_q         <= 8'b0;
249
        data_q              <= 8'b0;
250
        ulpi_stp_q          <= 1'b0;
251
 
252
        utmi_rxvalid_q      <= 1'b0;
253
        utmi_rxerror_q      <= 1'b0;
254
        utmi_rxactive_q     <= 1'b0;
255
        utmi_linestate_q    <= 2'b0;
256
        utmi_data_q         <= 8'b0;
257
        cmd_wr_q            <= 1'b0;
258
    end
259
    else
260
    begin
261
        ulpi_stp_q          <= 1'b0;
262
        utmi_rxvalid_q      <= 1'b0;
263
 
264
        if (!turnaround_w)
265
        begin
266
            //-----------------------------------------------------------------
267
            // Input
268
            //-----------------------------------------------------------------
269
            if (ulpi_dir_i)
270
            begin
271
                utmi_rxvalid_q  <= ulpi_nxt_i;
272
                utmi_data_q     <= ulpi_data_i;
273
 
274
                // No valid data, extract phy status 
275
                if (!ulpi_nxt_i)
276
                begin
277
                    utmi_linestate_q <= ulpi_data_i[1:0];
278
 
279
                    case (ulpi_data_i[5:4])
280
                    2'b00:
281
                    begin
282
                        utmi_rxactive_q <= 1'b0;
283
                        utmi_rxerror_q  <= 1'b0;
284
                    end
285
                    2'b01:
286
                    begin
287
                        utmi_rxactive_q <= 1'b1;
288
                        utmi_rxerror_q  <= 1'b0;
289
                    end
290
                    2'b11:
291
                    begin
292
                        utmi_rxactive_q <= 1'b1;
293
                        utmi_rxerror_q  <= 1'b1;
294
                    end
295
                    default:
296
                        ; // HOST_DISCONNECTED
297
                    endcase
298
                end
299
                // RxValid (so force RxActive)
300
                else
301
                    utmi_rxactive_q <= 1'b1;
302
            end
303
            //-----------------------------------------------------------------
304
            // Output
305
            //-----------------------------------------------------------------
306
            else
307
            begin
308
                // IDLE: Pending mode update
309
                if ((state_q == STATE_IDLE) && mode_update_q)
310
                begin
311
                    data_q      <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q};
312
                    ulpi_data_q <= REG_FUNC_CTRL;
313
 
314
                    state_q     <= STATE_CMD;
315
                    cmd_wr_q    <= 1'b1;
316
                end
317
                // IDLE: Pending OTG control update
318
                else if ((state_q == STATE_IDLE) && otg_update_q)
319
                begin
320
                    data_q      <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0};
321
                    ulpi_data_q <= REG_OTG_CTRL;
322
 
323
                    state_q     <= STATE_CMD;
324
                    cmd_wr_q    <= 1'b1;
325
                end
326
                // IDLE: Pending transmit
327
                else if ((state_q == STATE_IDLE) && utmi_tx_ready_w)
328
                begin
329
                    ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]};
330
                    state_q     <= STATE_DATA;
331
                    cmd_wr_q    <= 1'b0;
332
                end
333
                // Command
334
                else if ((state_q == STATE_CMD) && ulpi_nxt_i)
335
                begin
336
                    state_q     <= STATE_DATA;
337
                    ulpi_data_q <= data_q;
338
                end
339
                // Data
340
                else if (state_q == STATE_DATA && ulpi_nxt_i)
341
                begin
342
                    // End of packet
343
                    if (!utmi_tx_ready_w || cmd_wr_q)
344
                    begin
345
                        state_q       <= STATE_IDLE;
346
                        ulpi_data_q   <= 8'b0;  // IDLE
347
                        ulpi_stp_q    <= 1'b1;
348
                        cmd_wr_q      <= 1'b0;
349
                    end
350
                    else
351
                    begin
352
                        state_q        <= STATE_DATA;
353
                        ulpi_data_q    <= utmi_tx_data_w;
354
                    end
355
                end
356
            end
357
        end
358
    end
359
end
360
 
361
// Accept from buffer
362
assign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w) && !ulpi_dir_i) ||
363
                          (state_q == STATE_DATA && ulpi_nxt_i && !ulpi_dir_i && !cmd_wr_q);
364
 
365
//-----------------------------------------------------------------
366
// Assignments
367
//-----------------------------------------------------------------
368
// ULPI Interface
369
assign ulpi_data_o          = ulpi_data_q;
370
assign ulpi_stp_o           = ulpi_stp_q;
371
 
372
// UTMI Interface
373
assign utmi_linestate_o     = utmi_linestate_q;
374
assign utmi_data_o          = utmi_data_q;
375
assign utmi_rxerror_o       = utmi_rxerror_q;
376
assign utmi_rxactive_o      = utmi_rxactive_q;
377
assign utmi_rxvalid_o       = utmi_rxvalid_q;
378
 
379
endmodule

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.