usb_phy.c 14 KB

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