ulpi_wrapper.v 14 KB

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