/*
* The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536.
* It is a USB Highspeed DMA capable USB device controller. Beside ep0 it
* provides 4 IN and 4 OUT endpoints (bulk or interrupt type).
*
* Make sure that UDC is assigned to port 4 by BIOS settings (port can also
* be used as host port) and UOC bits PAD_EN and APU are set (should be done
* by BIOS init).
*
* UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not
* work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0")
* can be used with gadget ether.
*/
/* debug control */
/* #define UDC_VERBOSE */
/* Driver strings */
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
#define UDC_DRIVER_VERSION_STRING "01.00.0206"
/* system */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/dmapool.h>
#include <linux/moduleparam.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/prefetch.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
/* gadget stack */
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
/* udc specific */
#include "amd5536udc.h"
static void udc_tasklet_disconnect(unsigned long);
static void empty_req_queue(struct udc_ep *);
static int udc_probe(struct udc *dev);
static void udc_basic_init(struct udc *dev);
static void udc_setup_endpoints(struct udc *dev);
static void udc_soft_reset(struct udc *dev);
static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep);
static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq);
static int udc_free_dma_chain(struct udc *dev, struct udc_request *req);
static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req,
unsigned long buf_len, gfp_t gfp_flags);
static int udc_remote_wakeup(struct udc *dev);
static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id);
static void udc_pci_remove(struct pci_dev *pdev);
/* description */
static const char mod_desc[] = UDC_MOD_DESCRIPTION;
static const char name[] = "amd5536udc";
/* structure to hold endpoint function pointers */
static const struct usb_ep_ops udc_ep_ops;
/* received setup data */
static union udc_setup_data setup_data;
/* pointer to device object */
static struct udc *udc;
/* irq spin lock for soft reset */
static DEFINE_SPINLOCK(udc_irq_spinlock);
/* stall spin lock */
static DEFINE_SPINLOCK(udc_stall_spinlock);
/*
* slave mode: pending bytes in rx fifo after nyet,
* used if EPIN irq came but no req was available
*/
static unsigned int udc_rxfifo_pending;
/* count soft resets after suspend to avoid loop */
static int soft_reset_occured;
static int soft_reset_after_usbreset_occured;
/* timer */
static struct timer_list udc_timer;
static int stop_timer;
/* set_rde -- Is used to control enabling of RX DMA. Problem is
* that UDC has only one bit (RDE) to enable/disable RX DMA for
* all OUT endpoints. So we have to handle race conditions like
* when OUT data reaches the fifo but no request was queued yet.
* This cannot be solved by letting the RX DMA disabled until a
* request gets queued because there may be other OUT packets
* in the FIFO (important for not blocking control traffic).
* The value of set_rde controls the correspondig timer.
*
* set_rde -1 == not used, means it is alloed to be set to 0 or 1
* set_rde 0 == do not touch RDE, do no start the RDE timer
* set_rde 1 == timer function will look whether FIFO has data
* set_rde 2 == set by timer function to enable RX DMA on next call
*/
static int set_rde = -1;
static DECLARE_COMPLETION(on_exit);
static struct timer_list udc_pollstall_timer;
static int stop_pollstall_timer;
static DECLARE_COMPLETION(on_pollstall_exit);
/* tasklet for usb disconnect */
static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
(unsigned long) &udc);
/* endpoint names used for print */
static const char ep0_string[] = "ep0in";
static const char *const ep_string[] = {
ep0_string,
"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
"ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk",
"ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk",
"ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk",
"ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk",
"ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk"
};
/* DMA usage flag */
static bool use_dma = 1;
/* packet per buffer dma */
static bool use_dma_ppb = 1;
/* with per descr. update */
static bool use_dma_ppb_du;
/* buffer fill mode */
static int use_dma_bufferfill_mode;
/* full speed only mode */
static bool use_fullspeed;
/* tx buffer size for high speed */
static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE;
/* module parameters */
module_param(use_dma, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma, "true for DMA");
module_param(use_dma_ppb, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode");
module_param(use_dma_ppb_du, bool, S_IRUGO);
MODULE_PARM_DESC(use_dma_ppb_du,
"true for DMA in packet per buffer mode with descriptor update");
module_param(use_fullspeed, bool, S_IRUGO);
MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only");
/*---------------------------------------------------------------------------*/
/* Prints UDC device registers and endpoint irq registers */
static void print_regs(struct udc *dev)
{
DBG(dev, "------- Device registers -------\n");
DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg));
DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl));
DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts));
DBG(dev, "\n");
DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts));
DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk));
DBG(dev, "\n");
DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts));
DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk));
DBG(dev, "\n");
DBG(dev, "USE DMA = %d\n", use_dma);
if (use_dma && use_dma_ppb && !use_dma_ppb_du) {
DBG(dev, "DMA mode = PPBNDU (packet per buffer "
"WITHOUT desc. update)\n");
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
} else if (use_dma && use_dma_ppb && use_dma_ppb_du) {
DBG(dev, "DMA mode = PPBDU (packet per buffer "
"WITH desc. update)\n");
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
}
if (use_dma && use_dma_bufferfill_mode) {
DBG(dev, "DMA mode = BF (buffer fill mode)\n");
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
}
if (!use_dma)
dev_info(&dev->pdev->dev, "FIFO mode\n");
DBG(dev, "-------------------------------------------------------\n");
}
/* Masks unused interrupts */
static int udc_mask_unused_interrupts(struct udc *dev)
{
u32 tmp;
/* mask all dev interrupts */
tmp = AMD_BIT(UDC_DEVINT_SVC) |
AMD_BIT(UDC_DEVINT_ENUM) |
AMD_BIT(UDC_DEVINT_US) |
AMD_BIT(UDC_DEVINT_UR) |
AMD_BIT(UDC_DEVINT_ES) |
AMD_BIT(UDC_DEVINT_SI) |
AMD_BIT(UDC_DEVINT_SOF)|
AMD_BIT(UDC_DEVINT_SC);
writel(tmp, &dev->regs->irqmsk);
/* mask all ep interrupts */
writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk);
return 0;
}
/* Enables endpoint 0 interrupts */
static int udc_enable_ep0_interrupts(struct udc *dev)
{
u32 tmp;
DBG(dev, "udc_enable_ep0_interrupts()\n");
/* read irq mask */
tmp = readl(&dev->regs->ep_irqmsk);
/* enable ep0 irq's */
tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0)
& AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0);
writel(tmp, &dev->regs->ep_irqmsk);
return 0;
}
/* Enables device interrupts for SET_INTF and SET_CONFIG */
static int udc_enable_dev_se
amd5536udc.rar_high
版权申诉
48 浏览量
2022-09-14
21:42:43
上传
评论
收藏 22KB RAR 举报
四散
- 粉丝: 54
- 资源: 1万+
最新资源
- FPGA读写 AD9708+ AD9280 ADDA实验Verilog逻辑源码Quartus工程文件+文档说明+硬件参考原理图
- 基于CH340C设计USB转TLL串口通信模块PADS 9.5设计硬件(原理图+PCB)文件.zip
- 信号与系统大作业-图像处理 实现了直接滤波法维纳滤波法最小二乘滤波法LR递归法matlab源码.zip
- php-leetcode题解之最小栈.zip
- php-leetcode题解之最长不含重复字符的子字符串.zip
- php-leetcode题解之最长公共前缀.zip
- php-leetcode题解之最小差值.zip
- php-leetcode题解之最小基因变化.zip
- php-leetcode题解之最小路径和.zip
- php-leetcode题解之最大正方形.zip
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈