/ src / pio_usb_ll.h
pio_usb_ll.h
  1  /**
  2   * Copyright (c) 2021 sekigon-gonnoc
  3   *                    Ha Thach (thach@tinyusb.org)
  4   */
  5  
  6  #pragma once
  7  
  8  #include "hardware/pio.h"
  9  #include "pio_usb_configuration.h"
 10  #include "usb_definitions.h"
 11  #include <stdint.h>
 12  
 13  enum {
 14    PIO_USB_INTS_CONNECT_POS = 0,
 15    PIO_USB_INTS_DISCONNECT_POS,
 16    PIO_USB_INTS_RESET_END_POS,
 17    PIO_USB_INTS_SETUP_REQ_POS,
 18    PIO_USB_INTS_SOF_POS,
 19  
 20    PIO_USB_INTS_ENDPOINT_COMPLETE_POS,
 21    PIO_USB_INTS_ENDPOINT_ERROR_POS,
 22    PIO_USB_INTS_ENDPOINT_STALLED_POS,
 23    PIO_USB_INTS_ENDPOINT_CONTINUE_POS,
 24  };
 25  
 26  #define PIO_USB_INTS_CONNECT_BITS (1u << PIO_USB_INTS_CONNECT_POS)
 27  #define PIO_USB_INTS_DISCONNECT_BITS (1u << PIO_USB_INTS_DISCONNECT_POS)
 28  #define PIO_USB_INTS_RESET_END_BITS (1u << PIO_USB_INTS_RESET_END_POS)
 29  #define PIO_USB_INTS_SETUP_REQ_BITS (1u << PIO_USB_INTS_SETUP_REQ_POS)
 30  
 31  #define PIO_USB_INTS_SOF_BITS (1u << PIO_USB_INTS_SOF_POS)
 32  
 33  #define PIO_USB_INTS_ENDPOINT_COMPLETE_BITS                                    \
 34    (1u << PIO_USB_INTS_ENDPOINT_COMPLETE_POS)
 35  #define PIO_USB_INTS_ENDPOINT_ERROR_BITS (1u << PIO_USB_INTS_ENDPOINT_ERROR_POS)
 36  #define PIO_USB_INTS_ENDPOINT_STALLED_BITS                                     \
 37    (1u << PIO_USB_INTS_ENDPOINT_STALLED_POS)
 38  #define PIO_USB_INTS_ENDPOINT_CONTINUE_BITS                                     \
 39    (1u << PIO_USB_INTS_ENDPOINT_CONTINUE_POS)
 40  
 41  typedef enum {
 42    PORT_PIN_SE0 = 0b00,
 43    PORT_PIN_FS_IDLE = 0b01,
 44    PORT_PIN_LS_IDLE = 0b10,
 45    PORT_PIN_SE1 = 0b11,
 46  } port_pin_status_t;
 47  
 48  typedef struct {
 49    uint16_t div_int;
 50    uint8_t div_frac;
 51  } pio_clk_div_t;
 52  
 53  typedef struct {
 54    PIO pio_usb_tx; // could not set to volatile
 55    uint sm_tx;
 56    uint offset_tx;
 57    uint tx_ch;
 58  
 59    PIO pio_usb_rx; // could not set to volatile
 60    uint sm_rx;
 61    uint offset_rx;
 62    uint sm_eop;
 63    uint offset_eop;
 64    uint tx_reset_instr;
 65    uint tx_start_instr;
 66    uint rx_reset_instr;
 67    uint rx_reset_instr2;
 68    uint device_rx_irq_num;
 69  
 70    int8_t debug_pin_rx;
 71    int8_t debug_pin_eop;
 72  
 73    const pio_program_t *fs_tx_program;
 74    const pio_program_t *fs_tx_pre_program;
 75    const pio_program_t *ls_tx_program;
 76  
 77    pio_clk_div_t clk_div_fs_tx;
 78    pio_clk_div_t clk_div_fs_rx;
 79    pio_clk_div_t clk_div_ls_tx;
 80    pio_clk_div_t clk_div_ls_rx;
 81  
 82    bool need_pre;
 83  
 84    uint8_t usb_rx_buffer[128];
 85  } pio_port_t;
 86  
 87  //--------------------------------------------------------------------+
 88  //
 89  //--------------------------------------------------------------------+
 90  
 91  enum {
 92    PIO_USB_MODE_INVALID = 0,
 93    PIO_USB_MODE_DEVICE,
 94    PIO_USB_MODE_HOST,
 95  };
 96  
 97  extern usb_device_t pio_usb_device[PIO_USB_DEVICE_CNT];
 98  
 99  extern root_port_t pio_usb_root_port[PIO_USB_ROOT_PORT_CNT];
100  #define PIO_USB_ROOT_PORT(_idx) (pio_usb_root_port + (_idx))
101  
102  extern endpoint_t pio_usb_ep_pool[PIO_USB_EP_POOL_CNT];
103  #define PIO_USB_ENDPOINT(_idx) (pio_usb_ep_pool + (_idx))
104  
105  extern pio_port_t pio_port[1];
106  #define PIO_USB_PIO_PORT(_idx) (pio_port + (_idx))
107  
108  //--------------------------------------------------------------------+
109  // Bus functions
110  //--------------------------------------------------------------------+
111  
112  #define IRQ_TX_EOP_MASK (1 << IRQ_TX_EOP)
113  #define IRQ_TX_ALL_MASK (IRQ_TX_EOP_MASK)
114  #define IRQ_RX_COMP_MASK (1 << IRQ_RX_EOP)
115  #define IRQ_RX_ALL_MASK                                             \
116    ((1 << IRQ_RX_EOP) | (1 << IRQ_RX_BS_ERR) | (1 << IRQ_RX_START) | \
117     (1 << DECODER_TRIGGER))
118  
119  #define SM_SET_CLKDIV(pio, sm, div)                                            \
120    pio_sm_set_clkdiv_int_frac(pio, sm, div.div_int, div.div_frac)
121  #define SM_SET_CLKDIV_MAXSPEED(pio, sm)                                        \
122    pio_sm_set_clkdiv_int_frac(pio, sm, 1, 0)
123  
124  void pio_usb_bus_init(pio_port_t *pp, const pio_usb_configuration_t *c,
125                        root_port_t *root);
126  
127  void pio_usb_bus_start_receive(const pio_port_t *pp);
128  void pio_usb_bus_prepare_receive(const pio_port_t *pp);
129  int pio_usb_bus_receive_packet_and_handshake(pio_port_t *pp, uint8_t handshake);
130  void pio_usb_bus_usb_transfer(const pio_port_t *pp, uint8_t *data,
131                                uint16_t len);
132  
133  uint8_t pio_usb_bus_wait_handshake(pio_port_t *pp);
134  void pio_usb_bus_send_handshake(const pio_port_t *pp, uint8_t pid);
135  void pio_usb_bus_send_token(const pio_port_t *pp, uint8_t token, uint8_t addr,
136                              uint8_t ep_num);
137  
138  static __always_inline port_pin_status_t
139  pio_usb_bus_get_line_state(root_port_t *root) {
140    uint8_t dp = gpio_get(root->pin_dp) ? 0 : 1;
141    uint8_t dm = gpio_get(root->pin_dm) ? 0 : 1;
142  
143    return (dm << 1) | dp;
144  }
145  
146  //--------------------------------------------------------------------+
147  // Low Level functions
148  //--------------------------------------------------------------------+
149  
150  void pio_usb_ll_configure_endpoint(endpoint_t *ep,
151                                     uint8_t const *desc_endpoint);
152  bool pio_usb_ll_transfer_start(endpoint_t *ep, uint8_t *buffer,
153                                 uint16_t buflen);
154  bool pio_usb_ll_transfer_continue(endpoint_t *ep, uint16_t xferred_bytes);
155  void pio_usb_ll_transfer_complete(endpoint_t *ep, uint32_t flag);
156  
157  static inline __force_inline uint16_t
158  pio_usb_ll_get_transaction_len(endpoint_t *ep) {
159    uint16_t remaining = ep->total_len - ep->actual_len;
160    return (remaining < ep->size) ? remaining : ep->size;
161  }
162  
163  enum {
164    PIO_USB_TX_ENCODED_DATA_SE0 = 0,
165    PIO_USB_TX_ENCODED_DATA_K = 1,
166    PIO_USB_TX_ENCODED_DATA_COMP = 2,
167    PIO_USB_TX_ENCODED_DATA_J = 3,
168  };
169  uint8_t pio_usb_ll_encode_tx_data(uint8_t const *buffer, uint8_t buffer_len,
170                                    uint8_t *encoded_data);
171  
172  //--------------------------------------------------------------------
173  // Host Controller functions
174  //--------------------------------------------------------------------
175  
176  // Host IRQ Handler
177  void pio_usb_host_irq_handler(uint8_t root_idx);
178  
179  void pio_usb_host_port_reset_start(uint8_t root_idx);
180  void pio_usb_host_port_reset_end(uint8_t root_idx);
181  
182  void pio_usb_host_close_device(uint8_t root_idx, uint8_t device_address);
183  
184  bool pio_usb_host_endpoint_open(uint8_t root_idx, uint8_t device_address,
185                                  uint8_t const *desc_endpoint, bool need_pre);
186  bool pio_usb_host_send_setup(uint8_t root_idx, uint8_t device_address,
187                               uint8_t const setup_packet[8]);
188  bool pio_usb_host_endpoint_transfer(uint8_t root_idx, uint8_t device_address,
189                                      uint8_t ep_address, uint8_t *buffer,
190                                      uint16_t buflen);
191  bool pio_usb_host_endpoint_abort_transfer(uint8_t root_idx, uint8_t device_address,
192                                            uint8_t ep_address);
193  
194  //--------------------------------------------------------------------
195  // Device Controller functions
196  //--------------------------------------------------------------------
197  
198  // Device IRQ Handler
199  void pio_usb_device_irq_handler(uint8_t root_idx);
200  
201  void pio_usb_device_set_address(uint8_t dev_addr);
202  bool pio_usb_device_endpoint_open(uint8_t const *desc_endpoint);
203  bool pio_usb_device_transfer(uint8_t ep_address, uint8_t *buffer,
204                               uint16_t buflen);
205  
206  static inline __force_inline endpoint_t *
207  pio_usb_device_get_endpoint_by_address(uint8_t ep_address) {
208    // index = 2*num + dir e.g out1, in1, out2, in2
209    uint8_t const ep_idx = ((ep_address & 0x7f) << 1) | (ep_address >> 7);
210    return PIO_USB_ENDPOINT(ep_idx);
211  }