📄 amd5536udc.c
字号:
ep->num = tmp; /* txfifo size is calculated at enable time */ ep->txfifo = dev->txfifo; /* fifo size */ if (tmp < UDC_EPIN_NUM) { ep->fifo_depth = UDC_TXFIFO_SIZE; ep->in = 1; } else { ep->fifo_depth = UDC_RXFIFO_SIZE; ep->in = 0; } ep->regs = &dev->ep_regs[tmp]; /* * ep will be reset only if ep was not enabled before to avoid * disabling ep interrupts when ENUM interrupt occurs but ep is * not enabled by gadget driver */ if (!ep->desc) { ep_init(dev->regs, ep); } if (use_dma) { /* * ep->dma is not really used, just to indicate that * DMA is active: remove this * dma regs = dev control regs */ ep->dma = &dev->regs->ctl; /* nak OUT endpoints until enable - not for ep0 */ if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX && tmp > UDC_EPIN_NUM) { /* set NAK */ reg = readl(&dev->ep[tmp].regs->ctl); reg |= AMD_BIT(UDC_EPCTL_SNAK); writel(reg, &dev->ep[tmp].regs->ctl); dev->ep[tmp].naking = 1; } } } /* EP0 max packet */ if (dev->gadget.speed == USB_SPEED_FULL) { dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_FS_EP0OUT_MAX_PKT_SIZE; } else if (dev->gadget.speed == USB_SPEED_HIGH) { dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; } /* * with suspend bug workaround, ep0 params for gadget driver * are set at gadget driver bind() call */ dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; dev->ep[UDC_EP0IN_IX].halted = 0; INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); /* init cfg/alt/int */ dev->cur_config = 0; dev->cur_intf = 0; dev->cur_alt = 0;}/* Bringup after Connect event, initial bringup to be ready for ep0 events */static void usb_connect(struct udc *dev){ dev_info(&dev->pdev->dev, "USB Connect\n"); dev->connected = 1; /* put into initial config */ udc_basic_init(dev); /* enable device setup interrupts */ udc_enable_dev_setup_interrupts(dev);}/* * Calls gadget with disconnect event and resets the UDC and makes * initial bringup to be ready for ep0 events */static void usb_disconnect(struct udc *dev){ dev_info(&dev->pdev->dev, "USB Disconnect\n"); dev->connected = 0; /* mask interrupts */ udc_mask_unused_interrupts(dev); /* REVISIT there doesn't seem to be a point to having this * talk to a tasklet ... do it directly, we already hold * the spinlock needed to process the disconnect. */ tasklet_schedule(&disconnect_tasklet);}/* Tasklet for disconnect to be outside of interrupt context */static void udc_tasklet_disconnect(unsigned long par){ struct udc *dev = (struct udc *)(*((struct udc **) par)); u32 tmp; DBG(dev, "Tasklet disconnect\n"); spin_lock_irq(&dev->lock); if (dev->driver) { spin_unlock(&dev->lock); dev->driver->disconnect(&dev->gadget); spin_lock(&dev->lock); /* empty queues */ for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { empty_req_queue(&dev->ep[tmp]); } } /* disable ep0 */ ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); if (!soft_reset_occured) { /* init controller by soft reset */ udc_soft_reset(dev); soft_reset_occured++; } /* re-enable dev interrupts */ udc_enable_dev_setup_interrupts(dev); /* back to full speed ? */ if (use_fullspeed) { tmp = readl(&dev->regs->cfg); tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); writel(tmp, &dev->regs->cfg); } spin_unlock_irq(&dev->lock);}/* Reset the UDC core */static void udc_soft_reset(struct udc *dev){ unsigned long flags; DBG(dev, "Soft reset\n"); /* * reset possible waiting interrupts, because int. * status is lost after soft reset, * ep int. status reset */ writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts); /* device int. status reset */ writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts); spin_lock_irqsave(&udc_irq_spinlock, flags); writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); readl(&dev->regs->cfg); spin_unlock_irqrestore(&udc_irq_spinlock, flags);}/* RDE timer callback to set RDE bit */static void udc_timer_function(unsigned long v){ u32 tmp; spin_lock_irq(&udc_irq_spinlock); if (set_rde > 0) { /* * open the fifo if fifo was filled on last timer call * conditionally */ if (set_rde > 1) { /* set RDE to receive setup data */ tmp = readl(&udc->regs->ctl); tmp |= AMD_BIT(UDC_DEVCTL_RDE); writel(tmp, &udc->regs->ctl); set_rde = -1; } else if (readl(&udc->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { /* * if fifo empty setup polling, do not just * open the fifo */ udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV; if (!stop_timer) { add_timer(&udc_timer); } } else { /* * fifo contains data now, setup timer for opening * the fifo when timer expires to be able to receive * setup packets, when data packets gets queued by * gadget layer then timer will forced to expire with * set_rde=0 (RDE is set in udc_queue()) */ set_rde++; /* debug: lhadmot_timer_start = 221070 */ udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS; if (!stop_timer) { add_timer(&udc_timer); } } } else set_rde = -1; /* RDE was set by udc_queue() */ spin_unlock_irq(&udc_irq_spinlock); if (stop_timer) complete(&on_exit);}/* Handle halt state, used in stall poll timer */static void udc_handle_halt_state(struct udc_ep *ep){ u32 tmp; /* set stall as long not halted */ if (ep->halted == 1) { tmp = readl(&ep->regs->ctl); /* STALL cleared ? */ if (!(tmp & AMD_BIT(UDC_EPCTL_S))) { /* * FIXME: MSC spec requires that stall remains * even on receivng of CLEAR_FEATURE HALT. So * we would set STALL again here to be compliant. * But with current mass storage drivers this does * not work (would produce endless host retries). * So we clear halt on CLEAR_FEATURE. * DBG(ep->dev, "ep %d: set STALL again\n", ep->num); tmp |= AMD_BIT(UDC_EPCTL_S); writel(tmp, &ep->regs->ctl);*/ /* clear NAK by writing CNAK */ tmp |= AMD_BIT(UDC_EPCTL_CNAK); writel(tmp, &ep->regs->ctl); ep->halted = 0; UDC_QUEUE_CNAK(ep, ep->num); } }}/* Stall timer callback to poll S bit and set it again after */static void udc_pollstall_timer_function(unsigned long v){ struct udc_ep *ep; int halted = 0; spin_lock_irq(&udc_stall_spinlock); /* * only one IN and OUT endpoints are handled * IN poll stall */ ep = &udc->ep[UDC_EPIN_IX]; udc_handle_halt_state(ep); if (ep->halted) halted = 1; /* OUT poll stall */ ep = &udc->ep[UDC_EPOUT_IX]; udc_handle_halt_state(ep); if (ep->halted) halted = 1; /* setup timer again when still halted */ if (!stop_pollstall_timer && halted) { udc_pollstall_timer.expires = jiffies + HZ * UDC_POLLSTALL_TIMER_USECONDS / (1000 * 1000); add_timer(&udc_pollstall_timer); } spin_unlock_irq(&udc_stall_spinlock); if (stop_pollstall_timer) complete(&on_pollstall_exit);}/* Inits endpoint 0 so that SETUP packets are processed */static void activate_control_endpoints(struct udc *dev){ u32 tmp; DBG(dev, "activate_control_endpoints\n"); /* flush fifo */ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); tmp |= AMD_BIT(UDC_EPCTL_F); writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); /* set ep0 directions */ dev->ep[UDC_EP0IN_IX].in = 1; dev->ep[UDC_EP0OUT_IX].in = 0; /* set buffer size (tx fifo entries) of EP0_IN */ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); if (dev->gadget.speed == USB_SPEED_FULL) tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE); else if (dev->gadget.speed == USB_SPEED_HIGH) tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, UDC_EPIN_BUFF_SIZE); writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); /* set max packet size of EP0_IN */ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); if (dev->gadget.speed == USB_SPEED_FULL) tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE); else if (dev->gadget.speed == USB_SPEED_HIGH) tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE); writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); /* set max packet size of EP0_OUT */ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); if (dev->gadget.speed == USB_SPEED_FULL) tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE); else if (dev->gadget.speed == USB_SPEED_HIGH) tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, UDC_EP_MAX_PKT_SIZE); writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); /* set max packet size of EP0 in UDC CSR */ tmp = readl(&dev->csr->ne[0]); if (dev->gadget.speed == USB_SPEED_FULL) tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, UDC_CSR_NE_MAX_PKT); else if (dev->gadget.speed == USB_SPEED_HIGH) tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, UDC_CSR_NE_MAX_PKT); writel(tmp, &dev->csr->ne[0]); if (use_dma) { dev->ep[UDC_EP0OUT_IX].td->status |= AMD_BIT(UDC_DMA_OUT_STS_L); /* write dma desc address */ writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma, &dev->ep[UDC_EP0OUT_IX].regs->subptr); writel(dev->ep[UDC_EP0OUT_IX].td_phys, &dev->ep[UDC_EP0OUT_IX].regs->desptr); /* stop RDE timer */ if (timer_pending(&udc_timer)) { set_rde = 0; mod_timer(&udc_timer, jiffies - 1); } /* stop pollstall timer */ if (timer_pending(&udc_pollstall_timer)) { mod_timer(&udc_pollstall_timer, jiffies - 1); } /* enable DMA */ tmp = readl(&dev->regs->ctl); tmp |= AMD_BIT(UDC_DEVCTL_MODE) | AMD_BIT(UDC_DEVCTL_RDE) | AMD_BIT(UDC_DEVCTL_TDE); if (use_dma_bufferfill_mode) { tmp |= AMD_BIT(UDC_DEVCTL_BF); } else if (use_dma_ppb_du) { tmp |= AMD_BIT(UDC_DEVCTL_DU); } writel(tmp, &dev->regs->ctl); } /* clear NAK by writing CNAK for EP0IN */ tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); tmp |= AMD_BIT(UDC_EPCTL_CNAK); writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); dev->ep[UDC_EP0IN_IX].naking = 0; UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); /* clear NAK by writing CNAK for EP0OUT */ tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); tmp |= AMD_BIT(UDC_EPCTL_CNAK); writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); dev->ep[UDC_EP0OUT_IX].naking = 0; UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX);}/* Make endpoint 0 ready for control traffic */static int setup_ep0(struct udc *dev){ activate_control_endpoints(dev); /* enable ep0 interrupts */ udc_enable_ep0_interrupts(dev); /* enable device setup interrupts */ udc_enable_dev_setup_interrupts(dev); return 0;}/* Called by gadget driver to register itself */int usb_gadget_register_driver(struct usb_gadget_driver *driver){ struct udc *dev = udc; int retval; u32 tmp; if (!driver || !driver->bind || !driver->setup || driver->speed != USB_SPEED_HIGH) return -EINVAL; if (!dev) return -ENODEV; if (dev->driver) return -EBUSY; driver->driver.bus = NULL; dev->driver = driver; dev->gadget.dev.driver = &driver->driver; retval = driver->bind(&dev->gadget); /* Some gadget drivers use both ep0 directions. * NOTE: to gadget driver, ep0 is just one endpoint... */ dev->ep[UDC_EP0OUT_IX].ep.driver_data = dev->ep[UDC_EP0IN_IX].ep.driver_data; if (retval) { DBG(dev, "binding to %s returning %d\n", driver->driver.name, retval); dev->driver = NULL; dev->gadget.dev.driver = NULL; return retval; } /* get ready for ep0 traffic */ setup_ep0(dev); /* clear SD */ tmp = readl(&dev->regs->ctl); tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD); writel(tmp, &dev->regs->ctl); usb_connect(dev); return 0;}EXPORT_SYMBOL(usb_gadget_register_driver);/* shutdown requests and disconnect from gadget */static voidshutdown(struct udc *dev, struct usb_gadget_driver *driver)__releases(dev->lock)__acquires(dev->lock){ int tmp; /* empty queues and init hardware */ udc_basic_init(dev); for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { empty_req_queue(&dev->ep[tmp]); } if (dev->gadget.speed != USB_SPEED_UNKNOWN) { spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); spin_lock(&dev->lock); } /* init */ udc_setup_endpoints(dev);}/* Called by gadget driver to unregister itself */int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){ struct udc *dev = udc; unsigned long flags; u32 tmp; if (!dev) return -ENODEV; if (!driver || driver != dev->driver || !driver->unbind) return -EINVAL; spin_lock_irqsave(&dev->lock, flags); udc_mask_unused_interrupts(dev); shutdown(dev, driver); spin_unlock_irqrestore(&dev->lock, flags); driver->unbind(&dev->gadget); dev->driver = NULL; /* set SD */ tmp = readl(&dev->regs->ctl); tmp |= AMD_BIT(UDC_DEVCTL_SD); writel(tmp, &dev->regs->ctl); DBG(dev, "%s: unregistered\n", driver->driver.name); return 0;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/* Clear pending NAK bits */static void udc_process_cnak_queue(struct udc *dev){ u32 tmp; u32 reg; /* check epin's */ DBG(dev, "CNAK pending queue processing\n"); for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) { if (cnak_pending & (1 << tmp)) { DBG(dev, "CNAK pending for ep%d\n", tmp); /* clear NAK by writing CNAK */ reg = readl(&dev->ep[tmp].regs->ctl);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -