usb_phy.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <esp_types.h>
  7. #include <string.h>
  8. #include "freertos/FreeRTOS.h"
  9. #include "esp_log.h"
  10. #include "esp_check.h"
  11. #include "esp_private/periph_ctrl.h"
  12. #include "esp_private/usb_phy.h"
  13. #include "soc/usb_otg_periph.h"
  14. #include "hal/usb_phy_hal.h"
  15. #include "hal/usb_phy_ll.h"
  16. #include "esp_rom_gpio.h"
  17. #include "driver/gpio.h"
  18. #include "hal/gpio_ll.h"
  19. #include "soc/soc_caps.h"
  20. #include "soc/usb_pins.h"
  21. #if !SOC_RCC_IS_INDEPENDENT
  22. #define USB_WRAP_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
  23. #else
  24. #define USB_WRAP_RCC_ATOMIC()
  25. #endif
  26. static const char *USBPHY_TAG = "usb_phy";
  27. #define USBPHY_NOT_INIT_ERR_STR "USB_PHY is not initialized"
  28. typedef struct phy_context_t phy_context_t;
  29. struct phy_context_t {
  30. usb_phy_target_t target; /**< PHY target */
  31. usb_phy_controller_t controller; /**< PHY controller */
  32. usb_phy_status_t status; /**< PHY status */
  33. usb_otg_mode_t otg_mode; /**< USB OTG mode */
  34. usb_phy_speed_t otg_speed; /**< USB speed */
  35. usb_phy_ext_io_conf_t *iopins; /**< external PHY I/O pins */
  36. usb_phy_hal_context_t hal_context; /**< USB_PHY hal context */
  37. };
  38. typedef struct {
  39. phy_context_t *internal_phy; /**< internal PHY context */
  40. phy_context_t *external_phy; /**< external PHY context */
  41. uint32_t ref_count; /**< reference count used to protect p_phy_ctrl_obj */
  42. } phy_ctrl_obj_t;
  43. /**
  44. * @brief A pin descriptor for initialize external PHY I/O pins
  45. */
  46. typedef struct {
  47. int pin; /**< GPIO pin num */
  48. const int func; /**< GPIO matrix signal */
  49. const bool is_output; /**< input/output signal */
  50. } usb_iopin_dsc_t;
  51. static phy_ctrl_obj_t *p_phy_ctrl_obj = NULL;
  52. static portMUX_TYPE phy_spinlock = portMUX_INITIALIZER_UNLOCKED;
  53. static esp_err_t phy_iopins_configure(const usb_iopin_dsc_t *usb_periph_iopins, int iopins_num)
  54. {
  55. for (int i = 0; i < iopins_num; i++) {
  56. const usb_iopin_dsc_t iopin = usb_periph_iopins[i];
  57. if (iopin.pin != GPIO_NUM_NC) {
  58. ESP_RETURN_ON_FALSE((iopin.is_output && GPIO_IS_VALID_OUTPUT_GPIO(iopin.pin)) ||
  59. (!iopin.is_output && GPIO_IS_VALID_GPIO(iopin.pin)),
  60. ESP_ERR_INVALID_ARG, USBPHY_TAG, "io_num argument is invalid");
  61. esp_rom_gpio_pad_select_gpio(iopin.pin);
  62. if (iopin.is_output) {
  63. esp_rom_gpio_connect_out_signal(iopin.pin, iopin.func, false, false);
  64. } else {
  65. esp_rom_gpio_connect_in_signal(iopin.pin, iopin.func, false);
  66. gpio_ll_input_enable(&GPIO, iopin.pin);
  67. }
  68. esp_rom_gpio_pad_unhold(iopin.pin);
  69. }
  70. }
  71. return ESP_OK;
  72. }
  73. static esp_err_t phy_external_iopins_configure(const usb_phy_ext_io_conf_t *ext_io_conf)
  74. {
  75. const usb_iopin_dsc_t usb_periph_iopins[] = {
  76. {ext_io_conf->vp_io_num, usb_otg_periph_signal.extphy_vp_in, false},
  77. {ext_io_conf->vm_io_num, usb_otg_periph_signal.extphy_vm_in, false},
  78. {ext_io_conf->rcv_io_num, usb_otg_periph_signal.extphy_rcv_in, false},
  79. {ext_io_conf->oen_io_num, usb_otg_periph_signal.extphy_oen_out, true},
  80. {ext_io_conf->vpo_io_num, usb_otg_periph_signal.extphy_vpo_out, true},
  81. {ext_io_conf->vmo_io_num, usb_otg_periph_signal.extphy_vmo_out, true},
  82. };
  83. return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t));
  84. }
  85. static esp_err_t phy_otg_iopins_configure(const usb_phy_otg_io_conf_t *otg_io_conf)
  86. {
  87. const usb_iopin_dsc_t usb_periph_iopins[] = {
  88. {otg_io_conf->iddig_io_num, usb_otg_periph_signal.otg_iddig_in, false},
  89. {otg_io_conf->avalid_io_num, usb_otg_periph_signal.otg_avalid_in, false},
  90. {otg_io_conf->vbusvalid_io_num, usb_otg_periph_signal.otg_vbusvalid_in, false},
  91. {otg_io_conf->idpullup_io_num, usb_otg_periph_signal.otg_idpullup_out, true},
  92. {otg_io_conf->dppulldown_io_num, usb_otg_periph_signal.otg_dppulldown_out, true},
  93. {otg_io_conf->dmpulldown_io_num, usb_otg_periph_signal.otg_dmpulldown_out, true},
  94. {otg_io_conf->drvvbus_io_num, usb_otg_periph_signal.otg_drvvbus_out, true},
  95. {otg_io_conf->bvalid_io_num, usb_otg_periph_signal.srp_bvalid_in, false},
  96. {otg_io_conf->sessend_io_num, usb_otg_periph_signal.srp_sessend_in, false},
  97. {otg_io_conf->chrgvbus_io_num, usb_otg_periph_signal.srp_chrgvbus_out, true},
  98. {otg_io_conf->dischrgvbus_io_num, usb_otg_periph_signal.srp_dischrgvbus_out, true},
  99. };
  100. return phy_iopins_configure(usb_periph_iopins, sizeof(usb_periph_iopins) / sizeof(usb_iopin_dsc_t));
  101. }
  102. esp_err_t usb_phy_otg_set_mode(usb_phy_handle_t handle, usb_otg_mode_t mode)
  103. {
  104. ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, USBPHY_TAG, "handle argument is invalid");
  105. ESP_RETURN_ON_FALSE(mode < USB_OTG_MODE_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "mode argument is invalid");
  106. ESP_RETURN_ON_FALSE(handle->controller == USB_PHY_CTRL_OTG, ESP_FAIL, USBPHY_TAG, "phy source is not USB_OTG");
  107. handle->otg_mode = mode;
  108. if (mode == USB_OTG_MODE_HOST) {
  109. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is A side
  110. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_SRP_BVALID_IN_IDX, false);
  111. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from host
  112. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_AVALID_IN_IDX, false); // HIGH to force USB host mode
  113. if (handle->target == USB_PHY_TARGET_INT) {
  114. usb_phy_hal_int_load_conf_host(&(handle->hal_context));
  115. }
  116. } else if (mode == USB_OTG_MODE_DEVICE) {
  117. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_IDDIG_IN_IDX, false); // connected connector is mini-B side
  118. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_SRP_BVALID_IN_IDX, false); // HIGH to force USB device mode
  119. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, USB_OTG_VBUSVALID_IN_IDX, false); // receiving a valid Vbus from device
  120. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_OTG_AVALID_IN_IDX, false);
  121. }
  122. return ESP_OK;
  123. }
  124. esp_err_t usb_phy_otg_dev_set_speed(usb_phy_handle_t handle, usb_phy_speed_t speed)
  125. {
  126. ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, USBPHY_TAG, "handle argument is invalid");
  127. ESP_RETURN_ON_FALSE(speed < USB_PHY_SPEED_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "speed argument is invalid");
  128. ESP_RETURN_ON_FALSE(handle->controller == USB_PHY_CTRL_OTG, ESP_FAIL, USBPHY_TAG, "phy source is not USB_OTG");
  129. ESP_RETURN_ON_FALSE((handle->target == USB_PHY_TARGET_INT && handle->otg_mode == USB_OTG_MODE_DEVICE), ESP_FAIL,
  130. USBPHY_TAG, "set speed not supported");
  131. handle->otg_speed = speed;
  132. usb_priv_speed_t hal_speed = 0;
  133. if (speed == USB_PHY_SPEED_LOW) {
  134. hal_speed = USB_PRIV_SPEED_LOW;
  135. } else if (speed == USB_PHY_SPEED_FULL) {
  136. hal_speed = USB_PRIV_SPEED_FULL;
  137. }
  138. usb_phy_hal_int_load_conf_dev(&(handle->hal_context), hal_speed);
  139. return ESP_OK;
  140. }
  141. esp_err_t usb_phy_action(usb_phy_handle_t handle, usb_phy_action_t action)
  142. {
  143. ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, USBPHY_TAG, "handle argument is invalid");
  144. ESP_RETURN_ON_FALSE(action < USB_PHY_ACTION_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "action argument is invalid");
  145. ESP_RETURN_ON_FALSE((action == USB_PHY_ACTION_HOST_ALLOW_CONN && handle->controller == USB_PHY_CTRL_OTG) ||
  146. (action == USB_PHY_ACTION_HOST_FORCE_DISCONN && handle->controller == USB_PHY_CTRL_OTG),
  147. ESP_ERR_INVALID_ARG, USBPHY_TAG, "wrong target for the action");
  148. esp_err_t ret = ESP_OK;
  149. switch (action) {
  150. case USB_PHY_ACTION_HOST_ALLOW_CONN:
  151. if (handle->target == USB_PHY_TARGET_INT) {
  152. usb_phy_hal_int_mimick_disconn(&(handle->hal_context), false);
  153. } else {
  154. if (!handle->iopins) {
  155. ret = ESP_FAIL;
  156. ESP_LOGE(USBPHY_TAG, "no I/O pins provided for connection");
  157. break;
  158. }
  159. /*
  160. Allow for connections on the external PHY by connecting the VP and VM signals to the external PHY.
  161. */
  162. esp_rom_gpio_connect_in_signal(handle->iopins->vp_io_num, USB_EXTPHY_VP_IDX, false);
  163. esp_rom_gpio_connect_in_signal(handle->iopins->vm_io_num, USB_EXTPHY_VM_IDX, false);
  164. }
  165. break;
  166. case USB_PHY_ACTION_HOST_FORCE_DISCONN:
  167. if (handle->target == USB_PHY_TARGET_INT) {
  168. usb_phy_hal_int_mimick_disconn(&(handle->hal_context), true);
  169. } else {
  170. /*
  171. Disable connections on the external PHY by connecting the VP and VM signals to the constant LOW signal.
  172. */
  173. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VP_IDX, false);
  174. esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, USB_EXTPHY_VM_IDX, false);
  175. }
  176. break;
  177. default:
  178. break;
  179. }
  180. return ret;
  181. }
  182. static esp_err_t usb_phy_install(void)
  183. {
  184. portENTER_CRITICAL(&phy_spinlock);
  185. if (p_phy_ctrl_obj) {
  186. // p_phy_ctrl_obj already installed, return immediately
  187. portEXIT_CRITICAL(&phy_spinlock);
  188. return ESP_OK;
  189. }
  190. portEXIT_CRITICAL(&phy_spinlock);
  191. esp_err_t ret = ESP_OK;
  192. phy_ctrl_obj_t *phy_ctrl_obj = (phy_ctrl_obj_t *) calloc(1, sizeof(phy_ctrl_obj_t));
  193. ESP_GOTO_ON_FALSE(phy_ctrl_obj, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for USB_PHY driver");
  194. portENTER_CRITICAL(&phy_spinlock);
  195. if (!p_phy_ctrl_obj) {
  196. p_phy_ctrl_obj = phy_ctrl_obj;
  197. p_phy_ctrl_obj->ref_count = 0;
  198. } else {
  199. // p_phy_ctrl_obj already installed, need to free resource
  200. portEXIT_CRITICAL(&phy_spinlock);
  201. goto cleanup;
  202. }
  203. // Enable USB peripheral and reset the register
  204. portEXIT_CRITICAL(&phy_spinlock);
  205. USB_WRAP_RCC_ATOMIC() {
  206. usb_phy_ll_usb_wrap_enable_bus_clock(true);
  207. usb_phy_ll_usb_wrap_reset_register();
  208. }
  209. return ESP_OK;
  210. cleanup:
  211. free(phy_ctrl_obj);
  212. return ret;
  213. }
  214. esp_err_t usb_new_phy(const usb_phy_config_t *config, usb_phy_handle_t *handle_ret)
  215. {
  216. ESP_RETURN_ON_FALSE(config, ESP_ERR_INVALID_ARG, USBPHY_TAG, "config argument is invalid");
  217. ESP_RETURN_ON_FALSE(config->target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified PHY argument is invalid");
  218. ESP_RETURN_ON_FALSE(config->controller < USB_PHY_CTRL_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "specified source argument is invalid");
  219. ESP_RETURN_ON_ERROR(usb_phy_install(), USBPHY_TAG, "usb_phy driver installation failed");
  220. esp_err_t ret = ESP_OK;
  221. bool new_phy = false;
  222. phy_context_t *phy_context = (phy_context_t *) calloc(1, sizeof(phy_context_t));
  223. ESP_GOTO_ON_FALSE(phy_context, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for phy context");
  224. portENTER_CRITICAL(&phy_spinlock);
  225. usb_phy_get_phy_status(config->target, &phy_context->status);
  226. if (phy_context->status == USB_PHY_STATUS_FREE) {
  227. new_phy = true;
  228. p_phy_ctrl_obj->ref_count++;
  229. if (config->target == USB_PHY_TARGET_EXT) {
  230. p_phy_ctrl_obj->external_phy = phy_context;
  231. } else {
  232. p_phy_ctrl_obj->internal_phy = phy_context;
  233. }
  234. }
  235. portEXIT_CRITICAL(&phy_spinlock);
  236. ESP_GOTO_ON_FALSE(new_phy, ESP_ERR_INVALID_STATE, cleanup, USBPHY_TAG, "selected PHY is in use");
  237. phy_context->target = config->target;
  238. phy_context->controller = config->controller;
  239. phy_context->status = USB_PHY_STATUS_IN_USE;
  240. usb_phy_hal_init(&(phy_context->hal_context));
  241. if (config->controller == USB_PHY_CTRL_OTG) {
  242. usb_phy_hal_otg_conf(&(phy_context->hal_context), config->target == USB_PHY_TARGET_EXT);
  243. }
  244. #if SOC_USB_SERIAL_JTAG_SUPPORTED
  245. else if (config->controller == USB_PHY_CTRL_SERIAL_JTAG) {
  246. usb_phy_hal_jtag_conf(&(phy_context->hal_context), config->target == USB_PHY_TARGET_EXT);
  247. phy_context->otg_mode = USB_OTG_MODE_DEVICE;
  248. phy_context->otg_speed = USB_PHY_SPEED_FULL;
  249. }
  250. #endif
  251. if (config->target == USB_PHY_TARGET_INT) {
  252. gpio_set_drive_capability(USBPHY_DM_NUM, GPIO_DRIVE_CAP_3);
  253. gpio_set_drive_capability(USBPHY_DP_NUM, GPIO_DRIVE_CAP_3);
  254. }
  255. *handle_ret = (usb_phy_handle_t) phy_context;
  256. if (config->ext_io_conf && config->target == USB_PHY_TARGET_EXT) {
  257. phy_context->iopins = (usb_phy_ext_io_conf_t *) calloc(1, sizeof(usb_phy_ext_io_conf_t));
  258. ESP_GOTO_ON_FALSE(phy_context->iopins, ESP_ERR_NO_MEM, cleanup, USBPHY_TAG, "no mem for storing I/O pins");
  259. memcpy(phy_context->iopins, config->ext_io_conf, sizeof(usb_phy_ext_io_conf_t));
  260. ESP_ERROR_CHECK(phy_external_iopins_configure(phy_context->iopins));
  261. }
  262. if (config->otg_mode != USB_PHY_MODE_DEFAULT) {
  263. ESP_ERROR_CHECK(usb_phy_otg_set_mode(*handle_ret, config->otg_mode));
  264. }
  265. if (config->otg_speed != USB_PHY_SPEED_UNDEFINED) {
  266. ESP_ERROR_CHECK(usb_phy_otg_dev_set_speed(*handle_ret, config->otg_speed));
  267. }
  268. if (config->otg_io_conf && (phy_context->controller == USB_PHY_CTRL_OTG)) {
  269. ESP_ERROR_CHECK(phy_otg_iopins_configure(config->otg_io_conf));
  270. }
  271. return ESP_OK;
  272. cleanup:
  273. free(phy_context->iopins);
  274. free(phy_context);
  275. if (p_phy_ctrl_obj->ref_count == 0) {
  276. free(p_phy_ctrl_obj);
  277. p_phy_ctrl_obj = NULL;
  278. }
  279. return ret;
  280. }
  281. static void phy_uninstall(void)
  282. {
  283. phy_ctrl_obj_t *p_phy_ctrl_obj_free = NULL;
  284. portENTER_CRITICAL(&phy_spinlock);
  285. if (p_phy_ctrl_obj->ref_count == 0) {
  286. p_phy_ctrl_obj_free = p_phy_ctrl_obj;
  287. p_phy_ctrl_obj = NULL;
  288. USB_WRAP_RCC_ATOMIC() {
  289. // Disable USB peripheral without reset the module
  290. usb_phy_ll_usb_wrap_enable_bus_clock(false);
  291. }
  292. }
  293. portEXIT_CRITICAL(&phy_spinlock);
  294. free(p_phy_ctrl_obj_free);
  295. }
  296. esp_err_t usb_del_phy(usb_phy_handle_t handle)
  297. {
  298. ESP_RETURN_ON_FALSE(handle, ESP_ERR_INVALID_ARG, USBPHY_TAG, "handle argument is invalid");
  299. portENTER_CRITICAL(&phy_spinlock);
  300. p_phy_ctrl_obj->ref_count--;
  301. if (handle->target == USB_PHY_TARGET_EXT) {
  302. p_phy_ctrl_obj->external_phy = NULL;
  303. } else {
  304. // Clear pullup and pulldown loads on D+ / D-, and disable the pads
  305. usb_phy_ll_int_load_conf(handle->hal_context.wrap_dev, false, false, false, false);
  306. usb_phy_ll_usb_wrap_pad_enable(handle->hal_context.wrap_dev, false);
  307. p_phy_ctrl_obj->internal_phy = NULL;
  308. }
  309. portEXIT_CRITICAL(&phy_spinlock);
  310. free(handle->iopins);
  311. free(handle);
  312. phy_uninstall();
  313. return ESP_OK;
  314. }
  315. esp_err_t usb_phy_get_phy_status(usb_phy_target_t target, usb_phy_status_t *status)
  316. {
  317. ESP_RETURN_ON_FALSE(target < USB_PHY_TARGET_MAX, ESP_ERR_INVALID_ARG, USBPHY_TAG, "argument is invalid");
  318. ESP_RETURN_ON_FALSE(p_phy_ctrl_obj, ESP_ERR_INVALID_STATE, USBPHY_TAG, USBPHY_NOT_INIT_ERR_STR);
  319. if (target == USB_PHY_TARGET_EXT && p_phy_ctrl_obj->external_phy) {
  320. *status = p_phy_ctrl_obj->external_phy->status;
  321. } else if (target == USB_PHY_TARGET_INT && p_phy_ctrl_obj->internal_phy) {
  322. *status = p_phy_ctrl_obj->internal_phy->status;
  323. } else {
  324. *status = USB_PHY_STATUS_FREE;
  325. }
  326. return ESP_OK;
  327. }