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 3

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 3 ultra_embe
    // Register access (Wishbone pipelined access type)
52
    // NOTE: Tie inputs to 0 if unused
53
    input [7:0]       reg_addr_i,
54
    input             reg_stb_i,
55
    input             reg_we_i,
56
    input [7:0]       reg_data_i,
57
    output [7:0]      reg_data_o,
58
    output            reg_ack_o,
59
 
60 2 ultra_embe
    // UTMI Interface (SIE)
61
    input             utmi_txvalid_i,
62
    output            utmi_txready_o,
63
    output            utmi_rxvalid_o,
64
    output            utmi_rxactive_o,
65
    output            utmi_rxerror_o,
66
    output [7:0]      utmi_data_o,
67
    input  [7:0]      utmi_data_i,
68
    input  [1:0]      utmi_xcvrselect_i,
69
    input             utmi_termselect_i,
70
    input  [1:0]      utmi_opmode_i,
71
    input             utmi_dppulldown_i,
72
    input             utmi_dmpulldown_i,
73
    output [1:0]      utmi_linestate_o
74
);
75
 
76
//-----------------------------------------------------------------
77
// States
78
//-----------------------------------------------------------------
79
localparam STATE_W          = 2;
80
localparam STATE_IDLE       = 2'd0;
81
localparam STATE_CMD        = 2'd1;
82
localparam STATE_DATA       = 2'd2;
83 3 ultra_embe
localparam STATE_REG        = 2'd3;
84 2 ultra_embe
 
85
reg [STATE_W-1:0]   state_q;
86
 
87
//-----------------------------------------------------------------
88 3 ultra_embe
// Local Params
89
//-----------------------------------------------------------------
90
localparam REG_FUNC_CTRL = 8'h84;
91
localparam REG_OTG_CTRL  = 8'h8a;
92
localparam REG_TRANSMIT  = 8'h40;
93
localparam REG_WRITE     = 8'h80;
94
localparam REG_READ      = 8'hC0;
95
 
96
//-----------------------------------------------------------------
97 2 ultra_embe
// UTMI Mode Select
98
//-----------------------------------------------------------------
99
reg         mode_update_q;
100
reg [1:0]   xcvrselect_q;
101
reg         termselect_q;
102
reg [1:0]   opmode_q;
103
reg         phy_reset_q;
104 3 ultra_embe
reg         auto_wr_q;
105
reg         reg_wr_q;
106 2 ultra_embe
 
107
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
108
if (ulpi_rst_i)
109
begin
110
    mode_update_q   <= 1'b0;
111
    xcvrselect_q    <= 2'b0;
112
    termselect_q    <= 1'b0;
113
    opmode_q        <= 2'b11;
114
    phy_reset_q     <= 1'b1;
115
end
116
else
117
begin
118
    xcvrselect_q    <= utmi_xcvrselect_i;
119
    termselect_q    <= utmi_termselect_i;
120
    opmode_q        <= utmi_opmode_i;
121
 
122 3 ultra_embe
    if (mode_update_q && (state_q == STATE_CMD) && (ulpi_data_o == REG_FUNC_CTRL))
123 2 ultra_embe
    begin
124
        mode_update_q <= 1'b0;
125
        phy_reset_q   <= 1'b0;
126
    end
127
    else if (opmode_q     != utmi_opmode_i     ||
128
             termselect_q != utmi_termselect_i ||
129
             xcvrselect_q != utmi_xcvrselect_i)
130
        mode_update_q <= 1'b1;
131
end
132
 
133
//-----------------------------------------------------------------
134
// UTMI OTG Control
135
//-----------------------------------------------------------------
136
reg otg_update_q;
137
reg dppulldown_q;
138
reg dmpulldown_q;
139
 
140
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
141
if (ulpi_rst_i)
142
begin
143
    otg_update_q    <= 1'b0;
144
    dppulldown_q    <= 1'b1;
145
    dmpulldown_q    <= 1'b1;
146
end
147
else
148
begin
149
    dppulldown_q    <= utmi_dppulldown_i;
150
    dmpulldown_q    <= utmi_dmpulldown_i;
151
 
152 3 ultra_embe
    if (otg_update_q && (state_q == STATE_CMD) && (ulpi_data_o == REG_OTG_CTRL))
153 2 ultra_embe
        otg_update_q <= 1'b0;
154
    else if (dppulldown_q != utmi_dppulldown_i ||
155
             dmpulldown_q != utmi_dmpulldown_i)
156
        otg_update_q <= 1'b1;
157
end
158
 
159
//-----------------------------------------------------------------
160
// Bus turnaround detect
161
//-----------------------------------------------------------------
162
reg ulpi_dir_q;
163
 
164
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
165
if (ulpi_rst_i)
166
    ulpi_dir_q <= 1'b0;
167
else
168
    ulpi_dir_q <= ulpi_dir_i;
169
 
170
wire turnaround_w = ulpi_dir_q ^ ulpi_dir_i;
171
 
172 3 ultra_embe
reg ulpi_rxcmd_q;
173
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
174
if (ulpi_rst_i)
175
    ulpi_rxcmd_q <= 1'b0;
176
// Switch to input with NXT asserted in turnaround cycle
177
else if (!ulpi_dir_q && ulpi_dir_i && ulpi_nxt_i)
178
    ulpi_rxcmd_q <= 1'b1;
179
// Switch to output (turnaround cycle)
180
else if (ulpi_dir_q && !ulpi_dir_i)
181
    ulpi_rxcmd_q <= 1'b0;
182
 
183 2 ultra_embe
//-----------------------------------------------------------------
184 3 ultra_embe
// Register Access
185
//-----------------------------------------------------------------
186
reg       reg_wr_pending_q;
187
reg       reg_rd_pending_q;
188
reg [7:0] reg_addr_q;
189
reg [7:0] reg_data_q;
190
reg       reg_ack_q;
191
 
192
wire reg_ready_w = (reg_wr_pending_q && state_q == STATE_REG && ulpi_nxt_i && reg_wr_q) ||
193
                   (reg_rd_pending_q && !turnaround_w && ulpi_dir_i && !ulpi_rxcmd_q);
194
 
195
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
196
if (ulpi_rst_i)
197
begin
198
    reg_wr_pending_q    <= 1'b0;
199
    reg_rd_pending_q    <= 1'b0;
200
    reg_addr_q          <= 8'b0;
201
end
202
else if (reg_stb_i)
203
begin
204
    reg_addr_q          <= reg_addr_i;
205
    reg_wr_pending_q    <= reg_we_i;
206
    reg_rd_pending_q    <= ~reg_we_i;
207
end
208
else if (reg_ready_w)
209
begin
210
    reg_wr_pending_q    <= 1'b0;
211
    reg_rd_pending_q    <= 1'b0;
212
end
213
 
214
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
215
if (ulpi_rst_i)
216
    reg_data_q  <= 8'b0;
217
else if (reg_stb_i && reg_we_i)
218
    reg_data_q  <= reg_data_i;
219
 
220
assign reg_data_o = utmi_data_o;
221
 
222
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
223
if (ulpi_rst_i)
224
    reg_ack_q  <= 1'b0;
225
else
226
    reg_ack_q  <= reg_ready_w;
227
 
228
assign reg_ack_o = reg_ack_q;
229
 
230
//-----------------------------------------------------------------
231 2 ultra_embe
// Rx - Tx delay
232
//-----------------------------------------------------------------
233
localparam TX_DELAY_W       = 3;
234
localparam TX_START_DELAY   = 3'd7;
235
 
236
reg [TX_DELAY_W-1:0] tx_delay_q;
237
 
238
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
239
if (ulpi_rst_i)
240
    tx_delay_q <= {TX_DELAY_W{1'b0}};
241
else if (utmi_rxactive_o)
242
    tx_delay_q <= TX_START_DELAY;
243
else if (tx_delay_q != {TX_DELAY_W{1'b0}})
244
    tx_delay_q <= tx_delay_q - 1;
245
 
246
wire tx_delay_complete_w = (tx_delay_q == {TX_DELAY_W{1'b0}});
247
 
248
//-----------------------------------------------------------------
249
// Tx Buffer - decouple UTMI Tx from PHY I/O
250
//-----------------------------------------------------------------
251
reg [7:0] tx_buffer_q[0:1];
252
reg       tx_valid_q[0:1];
253
reg       tx_wr_idx_q;
254
reg       tx_rd_idx_q;
255
 
256
wire      utmi_tx_ready_w;
257
wire      utmi_tx_accept_w;
258
 
259
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
260
if (ulpi_rst_i)
261
begin
262
    tx_buffer_q[0] <= 8'b0;
263
    tx_buffer_q[1] <= 8'b0;
264
    tx_valid_q[0]  <= 1'b0;
265
    tx_valid_q[1]  <= 1'b0;
266
    tx_wr_idx_q    <= 1'b0;
267
    tx_rd_idx_q    <= 1'b0;
268
end
269
else
270
begin
271
    // Push
272
    if (utmi_txvalid_i && utmi_txready_o)
273
    begin
274
        tx_buffer_q[tx_wr_idx_q] <= utmi_data_i;
275
        tx_valid_q[tx_wr_idx_q]  <= 1'b1;
276
 
277
        tx_wr_idx_q <= tx_wr_idx_q + 1'b1;
278
    end
279
 
280
    // Pop
281
    if (utmi_tx_ready_w && utmi_tx_accept_w)
282
    begin
283
        tx_valid_q[tx_rd_idx_q]  <= 1'b0;
284
        tx_rd_idx_q <= tx_rd_idx_q + 1'b1;
285
    end
286
end
287
 
288
// Tx buffer space (only accept after Rx->Tx turnaround delay)
289
assign utmi_txready_o  = ~tx_valid_q[tx_wr_idx_q] & tx_delay_complete_w;
290
 
291
assign utmi_tx_ready_w = tx_valid_q[tx_rd_idx_q];
292
 
293
wire [7:0] utmi_tx_data_w = tx_buffer_q[tx_rd_idx_q];
294
 
295
//-----------------------------------------------------------------
296
// Implementation
297
//-----------------------------------------------------------------
298
 
299
// Xilinx placement pragmas:
300
//synthesis attribute IOB of ulpi_data_q is "TRUE"
301
//synthesis attribute IOB of ulpi_stp_q is "TRUE"
302
 
303
reg [7:0]           ulpi_data_q;
304
reg                 ulpi_stp_q;
305
reg [7:0]           data_q;
306
 
307
reg                 utmi_rxvalid_q;
308
reg                 utmi_rxerror_q;
309
reg                 utmi_rxactive_q;
310
reg [1:0]           utmi_linestate_q;
311
reg [7:0]           utmi_data_q;
312
 
313
always @ (posedge ulpi_clk60_i or posedge ulpi_rst_i)
314
begin
315
    if (ulpi_rst_i)
316
    begin
317
        state_q             <= STATE_IDLE;
318
        ulpi_data_q         <= 8'b0;
319
        data_q              <= 8'b0;
320
        ulpi_stp_q          <= 1'b0;
321
 
322
        utmi_rxvalid_q      <= 1'b0;
323
        utmi_rxerror_q      <= 1'b0;
324
        utmi_rxactive_q     <= 1'b0;
325
        utmi_linestate_q    <= 2'b0;
326
        utmi_data_q         <= 8'b0;
327 3 ultra_embe
        auto_wr_q           <= 1'b0;
328
        reg_wr_q            <= 1'b0;
329 2 ultra_embe
    end
330
    else
331
    begin
332
        ulpi_stp_q          <= 1'b0;
333
        utmi_rxvalid_q      <= 1'b0;
334
 
335
        if (!turnaround_w)
336
        begin
337
            //-----------------------------------------------------------------
338 3 ultra_embe
            // Input: RX_DATA
339 2 ultra_embe
            //-----------------------------------------------------------------
340 3 ultra_embe
            if (ulpi_dir_i && ulpi_rxcmd_q)
341 2 ultra_embe
            begin
342
                utmi_rxvalid_q  <= ulpi_nxt_i;
343
                utmi_data_q     <= ulpi_data_i;
344
 
345
                // No valid data, extract phy status 
346
                if (!ulpi_nxt_i)
347
                begin
348
                    utmi_linestate_q <= ulpi_data_i[1:0];
349
 
350
                    case (ulpi_data_i[5:4])
351
                    2'b00:
352
                    begin
353
                        utmi_rxactive_q <= 1'b0;
354
                        utmi_rxerror_q  <= 1'b0;
355
                    end
356
                    2'b01:
357
                    begin
358
                        utmi_rxactive_q <= 1'b1;
359
                        utmi_rxerror_q  <= 1'b0;
360
                    end
361
                    2'b11:
362
                    begin
363
                        utmi_rxactive_q <= 1'b1;
364
                        utmi_rxerror_q  <= 1'b1;
365
                    end
366
                    default:
367
                        ; // HOST_DISCONNECTED
368
                    endcase
369
                end
370
                // RxValid (so force RxActive)
371
                else
372
                    utmi_rxactive_q <= 1'b1;
373
            end
374
            //-----------------------------------------------------------------
375 3 ultra_embe
            // Input: REG_DATA
376
            //-----------------------------------------------------------------
377
            else if (ulpi_dir_i)
378
            begin
379
                utmi_rxvalid_q  <= 1'b0;
380
                utmi_data_q     <= ulpi_data_i;
381
            end
382
            //-----------------------------------------------------------------
383 2 ultra_embe
            // Output
384
            //-----------------------------------------------------------------
385
            else
386
            begin
387
                // IDLE: Pending mode update
388
                if ((state_q == STATE_IDLE) && mode_update_q)
389
                begin
390
                    data_q      <= {1'b0, 1'b1, phy_reset_q, opmode_q, termselect_q, xcvrselect_q};
391
                    ulpi_data_q <= REG_FUNC_CTRL;
392
 
393
                    state_q     <= STATE_CMD;
394 3 ultra_embe
                    auto_wr_q   <= 1'b1;
395
                    reg_wr_q    <= 1'b0;
396 2 ultra_embe
                end
397
                // IDLE: Pending OTG control update
398
                else if ((state_q == STATE_IDLE) && otg_update_q)
399
                begin
400
                    data_q      <= {5'b0, dmpulldown_q, dppulldown_q, 1'b0};
401
                    ulpi_data_q <= REG_OTG_CTRL;
402
 
403
                    state_q     <= STATE_CMD;
404 3 ultra_embe
                    auto_wr_q   <= 1'b1;
405
                    reg_wr_q    <= 1'b0;
406 2 ultra_embe
                end
407 3 ultra_embe
                // IDLE: Pending register access
408
                else if ((state_q == STATE_IDLE) && (reg_wr_pending_q || reg_rd_pending_q))
409
                begin
410
                    data_q      <= reg_data_q;
411
 
412
                    if (reg_wr_pending_q)
413
                        ulpi_data_q <= REG_WRITE | {2'b0, reg_addr_q[5:0]};
414
                    else
415
                        ulpi_data_q <= REG_READ  | {2'b0, reg_addr_q[5:0]};
416
 
417
                    state_q     <= STATE_CMD;
418
                    auto_wr_q   <= 1'b0;
419
                    reg_wr_q    <= reg_wr_pending_q;
420
                end
421 2 ultra_embe
                // IDLE: Pending transmit
422
                else if ((state_q == STATE_IDLE) && utmi_tx_ready_w)
423
                begin
424
                    ulpi_data_q <= REG_TRANSMIT | {4'b0, utmi_tx_data_w[3:0]};
425
                    state_q     <= STATE_DATA;
426 3 ultra_embe
                    auto_wr_q   <= 1'b0;
427
                    reg_wr_q    <= 1'b0;
428 2 ultra_embe
                end
429
                // Command
430
                else if ((state_q == STATE_CMD) && ulpi_nxt_i)
431
                begin
432 3 ultra_embe
                    // Read Register
433
                    if (!reg_wr_q && !auto_wr_q)
434
                    begin
435
                        state_q     <= STATE_IDLE;
436
                        ulpi_data_q <= 8'b0;
437
                    end
438
                    // Write Register
439
                    else
440
                    begin
441
                        state_q     <= STATE_REG;
442
                        ulpi_data_q <= data_q;
443
                    end
444 2 ultra_embe
                end
445 3 ultra_embe
                // Data (register write)
446
                else if (state_q == STATE_REG && ulpi_nxt_i)
447
                begin
448
                    state_q       <= STATE_IDLE;
449
                    ulpi_data_q   <= 8'b0;  // IDLE
450
                    ulpi_stp_q    <= 1'b1;
451
                    auto_wr_q     <= 1'b0;
452
                    reg_wr_q      <= 1'b0;
453
                end
454 2 ultra_embe
                // Data
455
                else if (state_q == STATE_DATA && ulpi_nxt_i)
456
                begin
457
                    // End of packet
458 3 ultra_embe
                    if (!utmi_tx_ready_w)
459 2 ultra_embe
                    begin
460
                        state_q       <= STATE_IDLE;
461
                        ulpi_data_q   <= 8'b0;  // IDLE
462
                        ulpi_stp_q    <= 1'b1;
463
                    end
464
                    else
465
                    begin
466
                        state_q        <= STATE_DATA;
467
                        ulpi_data_q    <= utmi_tx_data_w;
468
                    end
469
                end
470
            end
471
        end
472
    end
473
end
474
 
475
// Accept from buffer
476 3 ultra_embe
assign utmi_tx_accept_w = ((state_q == STATE_IDLE) && !(mode_update_q || otg_update_q || turnaround_w || reg_wr_pending_q || reg_rd_pending_q) && !ulpi_dir_i) ||
477
                          (state_q == STATE_DATA && ulpi_nxt_i && !ulpi_dir_i);
478 2 ultra_embe
 
479
//-----------------------------------------------------------------
480
// Assignments
481
//-----------------------------------------------------------------
482
// ULPI Interface
483
assign ulpi_data_o          = ulpi_data_q;
484
assign ulpi_stp_o           = ulpi_stp_q;
485
 
486
// UTMI Interface
487
assign utmi_linestate_o     = utmi_linestate_q;
488
assign utmi_data_o          = utmi_data_q;
489
assign utmi_rxerror_o       = utmi_rxerror_q;
490
assign utmi_rxactive_o      = utmi_rxactive_q;
491
assign utmi_rxvalid_o       = utmi_rxvalid_q;
492
 
493
endmodule

powered by: WebSVN 2.1.0

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