Lines Matching +full:start +full:- +full:from +full:- +full:bottom

4  * SPDX-License-Identifier: Apache-2.0
11 #include <zephyr/dt-bindings/usb/usb.h>
39 /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, required to be 8-byte aligned */
45 * This is to static-allocate EP contexts which can accommodate all instances.
103 * one-shot implementation
131 * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach().
137 * Allocate-only, and de-allocate all on re-initialize in usb_dc_attach().
141 /* Pass Setup packet from ISR to thread */
154 /* Enable interrupt top/bottom halves processing
175 struct numaker_usbd_data *data = dev->data; in numaker_usbd_lock()
177 k_mutex_lock(&data->sync_mutex, K_FOREVER); in numaker_usbd_lock()
182 struct numaker_usbd_data *data = dev->data; in numaker_usbd_unlock()
184 k_mutex_unlock(&data->sync_mutex); in numaker_usbd_unlock()
189 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_sw_connect()
190 USBD_T *const base = config->base; in numaker_usbd_sw_connect()
193 base->INTSTS = base->INTSTS; in numaker_usbd_sw_connect()
196 base->INTEN = USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP | USBD_INT_SOF; in numaker_usbd_sw_connect()
199 base->SE0 &= ~USBD_DRVSE0; in numaker_usbd_sw_connect()
204 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_sw_disconnect()
205 USBD_T *const base = config->base; in numaker_usbd_sw_disconnect()
208 base->SE0 |= USBD_DRVSE0; in numaker_usbd_sw_disconnect()
221 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_reset_addr()
222 struct numaker_usbd_data *data = dev->data; in numaker_usbd_reset_addr()
223 USBD_T *const base = config->base; in numaker_usbd_reset_addr()
225 base->FADDR = 0; in numaker_usbd_reset_addr()
226 data->addr = 0; in numaker_usbd_reset_addr()
231 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_set_addr()
232 struct numaker_usbd_data *data = dev->data; in numaker_usbd_set_addr()
233 USBD_T *const base = config->base; in numaker_usbd_set_addr()
235 if (base->FADDR != data->addr) { in numaker_usbd_set_addr()
236 base->FADDR = data->addr; in numaker_usbd_set_addr()
243 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_ep_base()
244 USBD_T *const base = config->base; in numaker_usbd_ep_base()
246 return base->EP + ep_hw_idx; in numaker_usbd_ep_base()
251 /* NOTE: For one-shot implementation, effective size of EP FIFO is limited to EP MPS */ in numaker_usbd_ep_fifo_max()
252 __ASSERT_NO_MSG(ep_cur->dmabuf_valid); in numaker_usbd_ep_fifo_max()
253 __ASSERT_NO_MSG(ep_cur->mps_valid); in numaker_usbd_ep_fifo_max()
254 __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); in numaker_usbd_ep_fifo_max()
255 return ep_cur->mps; in numaker_usbd_ep_fifo_max()
260 __ASSERT_NO_MSG(ep_cur->dmabuf_valid); in numaker_usbd_ep_fifo_used()
262 return USB_EP_DIR_IS_OUT(ep_cur->addr) in numaker_usbd_ep_fifo_used()
263 ? ep_cur->read_fifo_used in numaker_usbd_ep_fifo_used()
264 : numaker_usbd_ep_fifo_max(ep_cur) - ep_cur->write_fifo_free; in numaker_usbd_ep_fifo_used()
273 if (ep_cur->dmabuf_valid && ep_cur->mps_valid) { in numaker_usbd_ep_fifo_reset()
274 if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { in numaker_usbd_ep_fifo_reset()
276 ep_cur->read_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_reset()
277 ep_cur->read_fifo_used = 0; in numaker_usbd_ep_fifo_reset()
280 ep_cur->write_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_reset()
281 ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); in numaker_usbd_ep_fifo_reset()
288 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_set_stall()
289 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_set_stall()
292 ep_base->CFGP |= USBD_CFGP_SSTALL_Msk; in numaker_usbd_ep_set_stall()
298 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_clear_stall_n_data_toggle()
299 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_clear_stall_n_data_toggle()
302 ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; in numaker_usbd_ep_clear_stall_n_data_toggle()
305 ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; in numaker_usbd_ep_clear_stall_n_data_toggle()
310 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_is_stalled()
311 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_is_stalled()
313 return ep_base->CFGP & USBD_CFGP_SSTALL_Msk; in numaker_usbd_ep_is_stalled()
318 struct numaker_usbd_data *data = dev->data; in numaker_usbd_send_msg()
321 rc = k_msgq_put(&data->msgq, msg, K_NO_WAIT); in numaker_usbd_send_msg()
331 k_msgq_purge(&data->msgq); in numaker_usbd_send_msg()
333 rc = k_msgq_put(&data->msgq, &msg_reconn, K_NO_WAIT); in numaker_usbd_send_msg()
344 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_hw_setup()
345 USBD_T *const base = config->base; in numaker_usbd_hw_setup()
350 if (!device_is_ready(config->reset.dev)) { in numaker_usbd_hw_setup()
352 return -ENODEV; in numaker_usbd_hw_setup()
358 SYS->USBPHY = (SYS->USBPHY & ~SYS_USBPHY_USBROLE_Msk) | in numaker_usbd_hw_setup()
364 scc_subsys.pcc.clk_modidx = config->clk_modidx; in numaker_usbd_hw_setup()
365 scc_subsys.pcc.clk_src = config->clk_src; in numaker_usbd_hw_setup()
366 scc_subsys.pcc.clk_div = config->clk_div; in numaker_usbd_hw_setup()
369 rc = clock_control_on(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); in numaker_usbd_hw_setup()
374 rc = clock_control_configure(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys, in numaker_usbd_hw_setup()
381 rc = pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); in numaker_usbd_hw_setup()
389 reset_line_toggle_dt(&config->reset); in numaker_usbd_hw_setup()
393 base->ATTR = USBD_ATTR_BYTEM_Msk | BIT(9) | USBD_ATTR_DPPUEN_Msk | USBD_ATTR_USBEN_Msk | in numaker_usbd_hw_setup()
399 /* NOTE: Ignore DT maximum-speed with USBD fixed to full-speed */ in numaker_usbd_hw_setup()
402 config->irq_config_func(dev); in numaker_usbd_hw_setup()
413 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_hw_shutdown()
414 USBD_T *const base = config->base; in numaker_usbd_hw_shutdown()
420 config->irq_unconfig_func(dev); in numaker_usbd_hw_shutdown()
426 base->ATTR &= ~USBD_PHY_EN; in numaker_usbd_hw_shutdown()
431 scc_subsys.pcc.clk_modidx = config->clk_modidx; in numaker_usbd_hw_shutdown()
434 clock_control_off(config->clkctrl_dev, (clock_control_subsys_t)&scc_subsys); in numaker_usbd_hw_shutdown()
438 reset_line_toggle_dt(&config->reset); in numaker_usbd_hw_shutdown()
446 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_bus_reset_th()
449 for (uint32_t i = 0ul; i < config->num_bidir_endpoints; i++) { in numaker_usbd_bus_reset_th()
452 /* Cancel EP on-going transaction */ in numaker_usbd_bus_reset_th()
453 ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; in numaker_usbd_bus_reset_th()
456 ep_base->CFGP &= ~USBD_CFGP_SSTALL_Msk; in numaker_usbd_bus_reset_th()
459 ep_base->CFG &= ~USBD_CFG_DSQSYNC_Msk; in numaker_usbd_bus_reset_th()
463 ep_base->CFG = 0; in numaker_usbd_bus_reset_th()
472 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_remote_wakeup()
473 USBD_T *const base = config->base; in numaker_usbd_remote_wakeup()
476 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; in numaker_usbd_remote_wakeup()
479 base->ATTR |= USBD_ATTR_RWAKEUP_Msk; in numaker_usbd_remote_wakeup()
481 base->ATTR ^= USBD_ATTR_RWAKEUP_Msk; in numaker_usbd_remote_wakeup()
487 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_buf_base()
488 USBD_T *const base = config->base; in numaker_usbd_buf_base()
493 /* Copy to user buffer from Setup FIFO */
496 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_setup_fifo_copy_to_user()
497 USBD_T *const base = config->base; in numaker_usbd_setup_fifo_copy_to_user()
500 dmabuf_addr = numaker_usbd_buf_base(dev) + (base->STBUFSEG & USBD_STBUFSEG_STBUFSEG_Msk); in numaker_usbd_setup_fifo_copy_to_user()
505 /* Copy data to user buffer from EP FIFO
512 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_fifo_copy_to_user()
516 __ASSERT_NO_MSG(ep_cur->dmabuf_valid); in numaker_usbd_ep_fifo_copy_to_user()
518 dmabuf_addr = numaker_usbd_buf_base(dev) + ep_cur->read_fifo_pos; in numaker_usbd_ep_fifo_copy_to_user()
526 ep_cur->read_fifo_pos += *size_p; in numaker_usbd_ep_fifo_copy_to_user()
527 ep_cur->read_fifo_used -= *size_p; in numaker_usbd_ep_fifo_copy_to_user()
528 if (ep_cur->read_fifo_used == 0) { in numaker_usbd_ep_fifo_copy_to_user()
529 ep_cur->read_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_copy_to_user()
535 /* Copy data from user buffer to EP FIFO
542 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_fifo_copy_from_user()
543 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_fifo_copy_from_user()
548 __ASSERT_NO_MSG(ep_cur->dmabuf_valid); in numaker_usbd_ep_fifo_copy_from_user()
549 __ASSERT_NO_MSG(ep_cur->mps_valid); in numaker_usbd_ep_fifo_copy_from_user()
550 __ASSERT_NO_MSG(ep_cur->mps <= ep_cur->dmabuf_size); in numaker_usbd_ep_fifo_copy_from_user()
552 dmabuf_addr = numaker_usbd_buf_base(dev) + ep_base->BUFSEG; in numaker_usbd_ep_fifo_copy_from_user()
553 fifo_free = numaker_usbd_ep_fifo_max(ep_cur) - numaker_usbd_ep_fifo_used(ep_cur); in numaker_usbd_ep_fifo_copy_from_user()
560 ep_cur->write_fifo_pos += *size_p; in numaker_usbd_ep_fifo_copy_from_user()
561 ep_cur->write_fifo_free -= *size_p; in numaker_usbd_ep_fifo_copy_from_user()
562 if (ep_cur->write_fifo_free == 0) { in numaker_usbd_ep_fifo_copy_from_user()
563 ep_cur->write_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_copy_from_user()
572 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_fifo_update()
573 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_fifo_update()
575 __ASSERT_NO_MSG(ep_cur->addr_valid); in numaker_usbd_ep_fifo_update()
576 __ASSERT_NO_MSG(ep_cur->dmabuf_valid); in numaker_usbd_ep_fifo_update()
578 if (USB_EP_DIR_IS_OUT(ep_cur->addr)) { in numaker_usbd_ep_fifo_update()
580 /* NOTE: For one-shot implementation, FIFO gets updated from empty. */ in numaker_usbd_ep_fifo_update()
581 ep_cur->read_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_update()
583 if (USB_EP_GET_IDX(ep_cur->addr) == 0) { in numaker_usbd_ep_fifo_update()
584 ep_cur->read_fifo_used = ep_cur->mxpld_ctrlout; in numaker_usbd_ep_fifo_update()
586 ep_cur->read_fifo_used = ep_base->MXPLD; in numaker_usbd_ep_fifo_update()
590 /* NOTE: For one-shot implementation, FIFO gets to empty. */ in numaker_usbd_ep_fifo_update()
591 ep_cur->write_fifo_pos = ep_cur->dmabuf_base; in numaker_usbd_ep_fifo_update()
592 ep_cur->write_fifo_free = numaker_usbd_ep_fifo_max(ep_cur); in numaker_usbd_ep_fifo_update()
599 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_config_dmabuf()
600 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_config_dmabuf()
602 ep_base->BUFSEG = dmabuf_base; in numaker_usbd_ep_config_dmabuf()
604 ep_cur->dmabuf_valid = true; in numaker_usbd_ep_config_dmabuf()
605 ep_cur->dmabuf_base = dmabuf_base; in numaker_usbd_ep_config_dmabuf()
606 ep_cur->dmabuf_size = dmabuf_size; in numaker_usbd_ep_config_dmabuf()
611 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_abort()
612 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_abort()
614 /* Abort EP on-going transaction */ in numaker_usbd_ep_abort()
615 ep_base->CFGP |= USBD_CFGP_CLRRDY_Msk; in numaker_usbd_ep_abort()
618 ep_cur->nak_clr = false; in numaker_usbd_ep_abort()
625 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_config_major()
626 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_config_major()
628 ep_cur->mps_valid = true; in numaker_usbd_ep_config_major()
629 ep_cur->mps = ep_cfg->ep_mps; in numaker_usbd_ep_config_major()
632 ep_cur->ep_hw_cfg = 0; in numaker_usbd_ep_config_major()
635 if (ep_cfg->ep_type == USB_DC_EP_CONTROL) { in numaker_usbd_ep_config_major()
636 ep_cur->ep_hw_cfg |= USBD_CFG_CSTALL; in numaker_usbd_ep_config_major()
640 ep_cur->ep_hw_cfg &= ~USBD_CFG_DSQSYNC_Msk; in numaker_usbd_ep_config_major()
643 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_DISABLE; in numaker_usbd_ep_config_major()
646 if (ep_cfg->ep_type == USB_DC_EP_ISOCHRONOUS) { in numaker_usbd_ep_config_major()
647 ep_cur->ep_hw_cfg |= USBD_CFG_TYPE_ISO; in numaker_usbd_ep_config_major()
651 ep_cur->ep_hw_cfg |= in numaker_usbd_ep_config_major()
652 (USB_EP_GET_IDX(ep_cfg->ep_addr) << USBD_CFG_EPNUM_Pos) & USBD_CFG_EPNUM_Msk; in numaker_usbd_ep_config_major()
654 ep_base->CFG = ep_cur->ep_hw_cfg; in numaker_usbd_ep_config_major()
659 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_enable()
660 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_enable()
662 /* For safe, EP (re-)enable from clean state */ in numaker_usbd_ep_enable()
668 ep_cur->ep_hw_cfg &= ~USBD_CFG_STATE_Msk; in numaker_usbd_ep_enable()
669 if (USB_EP_DIR_IS_IN(ep_cur->addr)) { in numaker_usbd_ep_enable()
670 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_IN; in numaker_usbd_ep_enable()
672 ep_cur->ep_hw_cfg |= USBD_CFG_EPMODE_OUT; in numaker_usbd_ep_enable()
675 ep_base->CFG = ep_cur->ep_hw_cfg; in numaker_usbd_ep_enable()
682 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_disable()
683 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_disable()
688 ep_cur->ep_hw_cfg = (ep_cur->ep_hw_cfg & ~USBD_CFG_STATE_Msk) | USBD_CFG_EPMODE_DISABLE; in numaker_usbd_ep_disable()
689 ep_base->CFG = ep_cur->ep_hw_cfg; in numaker_usbd_ep_disable()
692 /* Start EP data transaction */
695 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_trigger()
696 USBD_EP_T *ep_base = numaker_usbd_ep_base(dev, ep_cur->ep_hw_idx); in numaker_usbd_ep_trigger()
698 ep_base->MXPLD = len; in numaker_usbd_ep_trigger()
703 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_ep_mgmt_alloc_ep()
704 struct numaker_usbd_data *data = dev->data; in numaker_usbd_ep_mgmt_alloc_ep()
705 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_ep_mgmt_alloc_ep()
708 if (ep_mgmt->ep_idx < config->num_bidir_endpoints) { in numaker_usbd_ep_mgmt_alloc_ep()
709 ep_cur = ep_mgmt->ep_pool + ep_mgmt->ep_idx; in numaker_usbd_ep_mgmt_alloc_ep()
710 ep_mgmt->ep_idx++; in numaker_usbd_ep_mgmt_alloc_ep()
712 __ASSERT_NO_MSG(!ep_cur->valid); in numaker_usbd_ep_mgmt_alloc_ep()
715 ep_cur->valid = true; in numaker_usbd_ep_mgmt_alloc_ep()
723 * Return -ENOMEM on OOM error, or 0 on success with DMA buffer base/size (rounded up) allocated
728 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_ep_mgmt_alloc_dmabuf()
729 struct numaker_usbd_data *data = dev->data; in numaker_usbd_ep_mgmt_alloc_dmabuf()
730 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_ep_mgmt_alloc_dmabuf()
735 /* Required to be 8-byte aligned */ in numaker_usbd_ep_mgmt_alloc_dmabuf()
738 ep_mgmt->dmabuf_pos += size; in numaker_usbd_ep_mgmt_alloc_dmabuf()
739 if (ep_mgmt->dmabuf_pos > config->dmabuf_size) { in numaker_usbd_ep_mgmt_alloc_dmabuf()
740 ep_mgmt->dmabuf_pos -= size; in numaker_usbd_ep_mgmt_alloc_dmabuf()
741 return -ENOMEM; in numaker_usbd_ep_mgmt_alloc_dmabuf()
744 *dmabuf_base_p = ep_mgmt->dmabuf_pos - size; in numaker_usbd_ep_mgmt_alloc_dmabuf()
749 /* Initialize all endpoint-related */
752 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_ep_mgmt_init()
753 struct numaker_usbd_data *data = dev->data; in numaker_usbd_ep_mgmt_init()
754 USBD_T *const base = config->base; in numaker_usbd_ep_mgmt_init()
755 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_ep_mgmt_init()
763 ep_cur = ep_mgmt->ep_pool; in numaker_usbd_ep_mgmt_init()
764 ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; in numaker_usbd_ep_mgmt_init()
769 ep_cur->dev = dev; in numaker_usbd_ep_mgmt_init()
772 ep_cur->ep_hw_idx = EP0 + (ep_cur - ep_mgmt->ep_pool); in numaker_usbd_ep_mgmt_init()
776 ep_mgmt->ep_idx = 2; in numaker_usbd_ep_mgmt_init()
778 /* Reserve DMA buffer for Setup/CTRL OUT/CTRL IN, starting from 0 */ in numaker_usbd_ep_mgmt_init()
779 ep_mgmt->dmabuf_pos = 0; in numaker_usbd_ep_mgmt_init()
782 base->STBUFSEG = ep_mgmt->dmabuf_pos; in numaker_usbd_ep_mgmt_init()
783 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_SETUP; in numaker_usbd_ep_mgmt_init()
786 ep_cur = ep_mgmt->ep_pool + 0; in numaker_usbd_ep_mgmt_init()
787 ep_cur->valid = true; in numaker_usbd_ep_mgmt_init()
788 ep_cur->addr_valid = true; in numaker_usbd_ep_mgmt_init()
789 ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_OUT); in numaker_usbd_ep_mgmt_init()
790 numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, in numaker_usbd_ep_mgmt_init()
792 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; in numaker_usbd_ep_mgmt_init()
793 ep_cur->mps_valid = true; in numaker_usbd_ep_mgmt_init()
794 ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLOUT; in numaker_usbd_ep_mgmt_init()
797 ep_cur = ep_mgmt->ep_pool + 1; in numaker_usbd_ep_mgmt_init()
798 ep_cur->valid = true; in numaker_usbd_ep_mgmt_init()
799 ep_cur->addr_valid = true; in numaker_usbd_ep_mgmt_init()
800 ep_cur->addr = USB_EP_GET_ADDR(0, USB_EP_DIR_IN); in numaker_usbd_ep_mgmt_init()
801 numaker_usbd_ep_config_dmabuf(ep_cur, ep_mgmt->dmabuf_pos, NUMAKER_USBD_DMABUF_SIZE_CTRLIN); in numaker_usbd_ep_mgmt_init()
802 ep_mgmt->dmabuf_pos += NUMAKER_USBD_DMABUF_SIZE_CTRLIN; in numaker_usbd_ep_mgmt_init()
803 ep_cur->mps_valid = true; in numaker_usbd_ep_mgmt_init()
804 ep_cur->mps = NUMAKER_USBD_DMABUF_SIZE_CTRLIN; in numaker_usbd_ep_mgmt_init()
811 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_ep_mgmt_find_ep()
812 struct numaker_usbd_data *data = dev->data; in numaker_usbd_ep_mgmt_find_ep()
813 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_ep_mgmt_find_ep()
814 struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; in numaker_usbd_ep_mgmt_find_ep()
815 struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; in numaker_usbd_ep_mgmt_find_ep()
818 if (!ep_cur->valid) { in numaker_usbd_ep_mgmt_find_ep()
822 if (!ep_cur->addr_valid) { in numaker_usbd_ep_mgmt_find_ep()
826 if (ep == ep_cur->addr) { in numaker_usbd_ep_mgmt_find_ep()
848 ep_cur->addr = ep; in numaker_usbd_ep_mgmt_bind_ep()
849 ep_cur->addr_valid = true; in numaker_usbd_ep_mgmt_bind_ep()
853 __ASSERT_NO_MSG(ep_cur->valid); in numaker_usbd_ep_mgmt_bind_ep()
854 __ASSERT_NO_MSG(ep_cur->addr_valid); in numaker_usbd_ep_mgmt_bind_ep()
855 __ASSERT_NO_MSG(ep_cur->addr == ep); in numaker_usbd_ep_mgmt_bind_ep()
860 /* Interrupt bottom half processing for bus reset */
863 const struct numaker_usbd_config *config = dev->config; in numaker_usbd_bus_reset_bh()
864 struct numaker_usbd_data *data = dev->data; in numaker_usbd_bus_reset_bh()
865 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_bus_reset_bh()
867 struct numaker_usbd_ep *ep_cur = ep_mgmt->ep_pool; in numaker_usbd_bus_reset_bh()
868 struct numaker_usbd_ep *ep_end = ep_mgmt->ep_pool + config->num_bidir_endpoints; in numaker_usbd_bus_reset_bh()
874 /* Abort EP on-going transaction and signal H/W relinquishes DMA buffer ownership */ in numaker_usbd_bus_reset_bh()
884 /* Interrupt bottom half processing for Setup/EP data transaction */
888 const struct device *dev = ep_cur->dev; in numaker_usbd_ep_bh()
889 struct numaker_usbd_data *data = dev->data; in numaker_usbd_ep_bh()
890 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_usbd_ep_bh()
894 __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); in numaker_usbd_ep_bh()
901 __ASSERT_NO_MSG(ep_cur->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_OUT)); in numaker_usbd_ep_bh()
902 __ASSERT_NO_MSG((ep_cur + 1)->addr == USB_EP_GET_ADDR(0, USB_EP_DIR_IN)); in numaker_usbd_ep_bh()
913 numaker_usbd_setup_fifo_copy_to_user(dev, (uint8_t *)&ep_mgmt->setup_packet); in numaker_usbd_ep_bh()
914 ep_mgmt->new_setup = true; in numaker_usbd_ep_bh()
916 __ASSERT_NO_MSG(USB_EP_DIR_IS_OUT(ep_cur->addr)); in numaker_usbd_ep_bh()
922 ep_cur->nak_clr = false; in numaker_usbd_ep_bh()
924 __ASSERT_NO_MSG(USB_EP_DIR_IS_IN(ep_cur->addr)); in numaker_usbd_ep_bh()
930 ep_cur->nak_clr = false; in numaker_usbd_ep_bh()
937 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_SW_RECONN); in numaker_usbd_msg_sw_reconn()
948 struct numaker_usbd_data *data = dev->data; in numaker_usbd_msg_cb_state()
950 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_STATE); in numaker_usbd_msg_cb_state()
952 /* Interrupt bottom half processing for bus reset */ in numaker_usbd_msg_cb_state()
953 if (msg->cb_device.status_code == USB_DC_RESET) { in numaker_usbd_msg_cb_state()
963 if (data->status_cb) { in numaker_usbd_msg_cb_state()
964 data->status_cb(msg->cb_device.status_code, NULL); in numaker_usbd_msg_cb_state()
966 LOG_WRN("No status callback: status_code=%d", msg->cb_device.status_code); in numaker_usbd_msg_cb_state()
976 __ASSERT_NO_MSG(msg->type == NUMAKER_USBD_MSG_TYPE_CB_EP); in numaker_usbd_msg_cb_ep()
978 ep = msg->cb_ep.ep; in numaker_usbd_msg_cb_ep()
988 /* Interrupt bottom half processing for EP */ in numaker_usbd_msg_cb_ep()
990 numaker_usbd_ep_bh(ep_cur, msg->cb_ep.status_code); in numaker_usbd_msg_cb_ep()
994 if (ep_cur->cb) { in numaker_usbd_msg_cb_ep()
995 ep_cur->cb(ep, msg->cb_ep.status_code); in numaker_usbd_msg_cb_ep()
997 LOG_WRN("No EP callback: ep=0x%02x, status_code=%d", ep, msg->cb_ep.status_code); in numaker_usbd_msg_cb_ep()
1001 /* Interrupt bottom half processing
1004 * context. This is because callbacks from this stack may use mutex or other kernel functions
1010 struct numaker_usbd_data *data = dev->data; in numaker_usbd_msg_hdlr_thread_main()
1019 if (k_msgq_get(&data->msgq, &msg, K_FOREVER)) { in numaker_usbd_msg_hdlr_thread_main()
1044 const struct numaker_usbd_config *config = dev->config; in numaker_udbd_isr()
1045 struct numaker_usbd_data *data = dev->data; in numaker_udbd_isr()
1046 USBD_T *const base = config->base; in numaker_udbd_isr()
1047 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in numaker_udbd_isr()
1051 uint32_t volatile usbd_intsts = base->INTSTS; in numaker_udbd_isr()
1052 uint32_t volatile usbd_bus_state = base->ATTR; in numaker_udbd_isr()
1054 /* USB plug-in/unplug */ in numaker_udbd_isr()
1057 base->INTSTS = USBD_INTSTS_FLDET; in numaker_udbd_isr()
1059 if (base->VBUSDET & USBD_VBUSDET_VBUSDET_Msk) { in numaker_udbd_isr()
1060 /* USB plug-in */ in numaker_udbd_isr()
1063 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; in numaker_udbd_isr()
1065 /* Message for bottom-half processing */ in numaker_udbd_isr()
1070 LOG_DBG("USB plug-in"); in numaker_udbd_isr()
1075 base->ATTR &= ~USBD_USB_EN; in numaker_udbd_isr()
1077 /* Message for bottom-half processing */ in numaker_udbd_isr()
1086 /* USB wake-up */ in numaker_udbd_isr()
1089 base->INTSTS = USBD_INTSTS_WAKEUP; in numaker_udbd_isr()
1091 LOG_DBG("USB wake-up"); in numaker_udbd_isr()
1097 base->INTSTS = USBD_INTSTS_BUS; in numaker_udbd_isr()
1103 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; in numaker_udbd_isr()
1108 /* Message for bottom-half processing */ in numaker_udbd_isr()
1117 base->ATTR &= ~USBD_PHY_EN; in numaker_udbd_isr()
1119 /* Message for bottom-half processing */ in numaker_udbd_isr()
1128 base->ATTR |= USBD_ATTR_USBEN_Msk | USBD_ATTR_PHYEN_Msk; in numaker_udbd_isr()
1130 /* Message for bottom-half processing */ in numaker_udbd_isr()
1142 base->INTSTS = USBD_INTSTS_SOFIF_Msk; in numaker_udbd_isr()
1144 /* Message for bottom-half processing */ in numaker_udbd_isr()
1160 base->INTSTS = USBD_INTSTS_SETUP; in numaker_udbd_isr()
1163 ep0_base->CFGP |= USBD_CFGP_CLRRDY_Msk; in numaker_udbd_isr()
1164 ep1_base->CFGP |= USBD_CFGP_CLRRDY_Msk; in numaker_udbd_isr()
1169 ep0_base->CFG |= USBD_CFG_DSQSYNC_Msk; in numaker_udbd_isr()
1170 ep1_base->CFG |= USBD_CFG_DSQSYNC_Msk; in numaker_udbd_isr()
1172 /* Message for bottom-half processing */ in numaker_udbd_isr()
1183 epintsts = base->EPINTSTS; in numaker_udbd_isr()
1185 base->EPINTSTS = epintsts; in numaker_udbd_isr()
1196 * CTRL/BULK/INT or no-ACK for Iso), that is, no need to check EPSTS0, in numaker_udbd_isr()
1201 ep_dir = ((ep_base->CFG & USBD_CFG_STATE_Msk) == USBD_CFG_EPMODE_IN) in numaker_udbd_isr()
1204 ep_idx = (ep_base->CFG & USBD_CFG_EPNUM_Msk) >> USBD_CFG_EPNUM_Pos; in numaker_udbd_isr()
1218 struct numaker_usbd_ep *ep_ctrlout = ep_mgmt->ep_pool + 0; in numaker_udbd_isr()
1220 numaker_usbd_ep_base(dev, ep_ctrlout->ep_hw_idx); in numaker_udbd_isr()
1222 ep_ctrlout->mxpld_ctrlout = ep_ctrlout_base->MXPLD; in numaker_udbd_isr()
1225 /* Message for bottom-half processing */ in numaker_udbd_isr()
1279 struct numaker_usbd_data *data = dev->data; in usb_dc_detach()
1292 k_msgq_purge(&data->msgq); in usb_dc_detach()
1318 struct numaker_usbd_data *data = dev->data; in usb_dc_set_address()
1325 * in-between SET_ADDRESS control transfer and next transfer. For this, it is done in in usb_dc_set_address()
1328 data->addr = addr; in usb_dc_set_address()
1338 struct numaker_usbd_data *data = dev->data; in usb_dc_set_status_callback()
1342 data->status_cb = cb; in usb_dc_set_status_callback()
1350 const struct numaker_usbd_config *config = dev->config; in usb_dc_ep_check_cap()
1357 if ((ep_cfg->ep_type == USB_DC_EP_CONTROL) && USB_EP_GET_IDX(ep_cfg->ep_addr) != 0) { in usb_dc_ep_check_cap()
1359 rc = -ENOTSUP; in usb_dc_ep_check_cap()
1364 * This is addressed by limiting all OUT/IN EP addresses in top/bottom halves, in usb_dc_ep_check_cap()
1367 if (config->disallow_iso_inout_same && ep_cfg->ep_type != USB_DC_EP_CONTROL) { in usb_dc_ep_check_cap()
1368 /* Limit all OUT EP addresses in top-half, except CTRL OUT */ in usb_dc_ep_check_cap()
1369 if (USB_EP_DIR_IS_OUT(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) >= 8) { in usb_dc_ep_check_cap()
1371 ep_cfg->ep_addr); in usb_dc_ep_check_cap()
1372 rc = -ENOTSUP; in usb_dc_ep_check_cap()
1376 /* Limit all IN EP addresses in bottom-half , except CTRL IN */ in usb_dc_ep_check_cap()
1377 if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr) && USB_EP_GET_IDX(ep_cfg->ep_addr) < 8) { in usb_dc_ep_check_cap()
1379 ep_cfg->ep_addr); in usb_dc_ep_check_cap()
1380 rc = -ENOTSUP; in usb_dc_ep_check_cap()
1385 /* To respect this capability check, pre-bind EP context to EP address, in usb_dc_ep_check_cap()
1386 * and pre-determined its type in usb_dc_ep_check_cap()
1388 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); in usb_dc_ep_check_cap()
1390 LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); in usb_dc_ep_check_cap()
1391 rc = -ENOMEM; in usb_dc_ep_check_cap()
1415 rc = -ENOMEM; in usb_dc_ep_set_callback()
1419 ep_cur->cb = cb; in usb_dc_ep_set_callback()
1436 LOG_DBG("EP=0x%02x, MPS=%d, Type=%d", ep_cfg->ep_addr, ep_cfg->ep_mps, ep_cfg->ep_type); in usb_dc_ep_configure()
1441 ep_cur = numaker_usbd_ep_mgmt_bind_ep(dev, ep_cfg->ep_addr); in usb_dc_ep_configure()
1444 LOG_ERR("Bind EP context: ep=0x%02x", ep_cfg->ep_addr); in usb_dc_ep_configure()
1445 rc = -ENOMEM; in usb_dc_ep_configure()
1450 if (!ep_cur->dmabuf_valid || ep_cur->dmabuf_size < ep_cfg->ep_mps) { in usb_dc_ep_configure()
1452 rc = numaker_usbd_ep_mgmt_alloc_dmabuf(dev, ep_cfg->ep_mps, &dmabuf_base, in usb_dc_ep_configure()
1488 rc = -ENOMEM; in usb_dc_ep_set_stall()
1517 rc = -ENOMEM; in usb_dc_ep_clear_stall()
1538 return -EINVAL; in usb_dc_ep_is_stalled()
1548 rc = -ENOMEM; in usb_dc_ep_is_stalled()
1581 rc = -ENOMEM; in usb_dc_ep_enable()
1621 rc = -ENOMEM; in usb_dc_ep_disable()
1649 rc = -ENOMEM; in usb_dc_ep_flush()
1677 rc = -ENOMEM; in usb_dc_ep_write()
1683 rc = -EINVAL; in usb_dc_ep_write()
1688 if (ep_cur->nak_clr) { in usb_dc_ep_write()
1690 rc = -EAGAIN; in usb_dc_ep_write()
1694 /* For one-shot implementation, don't trigger next DATA IN with write FIFO not empty. */ in usb_dc_ep_write()
1696 LOG_WRN("ep 0x%02x: Write FIFO not empty for one-shot implementation", ep); in usb_dc_ep_write()
1697 rc = -EAGAIN; in usb_dc_ep_write()
1706 LOG_ERR("Copy to FIFO from user buffer"); in usb_dc_ep_write()
1716 /* NOTE: For one-shot implementation, at most MPS size can be written, though, in usb_dc_ep_write()
1724 rc = -EIO; in usb_dc_ep_write()
1763 struct numaker_usbd_data *data = dev->data; in usb_dc_ep_read_wait()
1765 struct numaker_usbd_ep_mgmt *ep_mgmt = &data->ep_mgmt; in usb_dc_ep_read_wait()
1776 rc = -ENOMEM; in usb_dc_ep_read_wait()
1782 rc = -EINVAL; in usb_dc_ep_read_wait()
1787 if (ep == USB_CONTROL_EP_OUT && ep_mgmt->new_setup) { in usb_dc_ep_read_wait()
1790 rc = -EINVAL; in usb_dc_ep_read_wait()
1794 memcpy(data_buf, &ep_mgmt->setup_packet, 8); in usb_dc_ep_read_wait()
1795 ep_mgmt->new_setup = false; in usb_dc_ep_read_wait()
1804 /* For one-shot implementation, don't read FIFO with EP busy. */ in usb_dc_ep_read_wait()
1805 if (ep_cur->nak_clr) { in usb_dc_ep_read_wait()
1807 rc = -EAGAIN; in usb_dc_ep_read_wait()
1818 LOG_ERR("Copy from FIFO to user buffer"); in usb_dc_ep_read_wait()
1826 LOG_ERR("Null data but non-zero data length"); in usb_dc_ep_read_wait()
1827 rc = -EINVAL; in usb_dc_ep_read_wait()
1861 rc = -ENOMEM; in usb_dc_ep_read_continue()
1867 rc = -EINVAL; in usb_dc_ep_read_continue()
1872 if (ep_cur->nak_clr) { in usb_dc_ep_read_continue()
1877 /* For one-shot implementation, don't trigger next DATA OUT, or overwrite. */ in usb_dc_ep_read_continue()
1882 __ASSERT_NO_MSG(ep_cur->mps_valid); in usb_dc_ep_read_continue()
1883 numaker_usbd_ep_trigger(ep_cur, ep_cur->mps); in usb_dc_ep_read_continue()
1906 rc = -ENOMEM; in usb_dc_ep_mps()
1910 __ASSERT_NO_MSG(ep_cur->mps_valid); in usb_dc_ep_mps()
1911 ep_mps = ep_cur->mps; in usb_dc_ep_mps()
1938 struct numaker_usbd_data *data = dev->data; in numaker_udbd_init()
1944 k_mutex_init(&data->sync_mutex); in numaker_udbd_init()
1946 /* Set up interrupt top/bottom halves processing */ in numaker_udbd_init()
1948 k_msgq_init(&data->msgq, (char *)data->msgq_buf, sizeof(struct numaker_usbd_msg), in numaker_udbd_init()
1951 k_thread_create(&data->msg_hdlr_thread, data->msg_hdlr_thread_stack, in numaker_udbd_init()
1956 k_thread_name_set(&data->msg_hdlr_thread, "numaker_usbd"); in numaker_udbd_init()