[PATCH] USB: net2282 and net2280 software compatibility

Below is a patch to gadgets/net2280.[ch] which adds support for the
net2282 controller. The original code was kindly provided by PLX
Technology, I just merged it with the current net2280 driver in the
kernel. Tested on 2.6.15.6, but only with 2282. I did the merge, so
that the behaviour for the 2280 is unaffected (except for short delays
for extra checks).

Signed-off-by: G. Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

Support for net2282 in net2280 driver.
This commit is contained in:
Guennadi Liakhovetski 2006-03-19 20:49:14 +01:00 committed by Greg Kroah-Hartman
parent f043ca43c1
commit 950ee4c8f0
3 changed files with 73 additions and 23 deletions

View file

@ -69,11 +69,11 @@ choice
often need board-specific hooks. often need board-specific hooks.
config USB_GADGET_NET2280 config USB_GADGET_NET2280
boolean "NetChip 2280" boolean "NetChip 228x"
depends on PCI depends on PCI
select USB_GADGET_DUALSPEED select USB_GADGET_DUALSPEED
help help
NetChip 2280 is a PCI based USB peripheral controller which NetChip 2280 / 2282 is a PCI based USB peripheral controller which
supports both full and high speed USB 2.0 data transfers. supports both full and high speed USB 2.0 data transfers.
It has six configurable endpoints, as well as endpoint zero It has six configurable endpoints, as well as endpoint zero

View file

@ -26,6 +26,8 @@
* Copyright (C) 2003 David Brownell * Copyright (C) 2003 David Brownell
* Copyright (C) 2003-2005 PLX Technology, Inc. * Copyright (C) 2003-2005 PLX Technology, Inc.
* *
* Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
*
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or * the Free Software Foundation; either version 2 of the License, or
@ -71,8 +73,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define DRIVER_DESC "PLX NET2280 USB Peripheral Controller" #define DRIVER_DESC "PLX NET228x USB Peripheral Controller"
#define DRIVER_VERSION "2005 Feb 03" #define DRIVER_VERSION "2005 Sept 27"
#define DMA_ADDR_INVALID (~(dma_addr_t)0) #define DMA_ADDR_INVALID (~(dma_addr_t)0)
#define EP_DONTUSE 13 /* nonzero */ #define EP_DONTUSE 13 /* nonzero */
@ -118,7 +120,7 @@ module_param (fifo_mode, ushort, 0644);
/* enable_suspend -- When enabled, the driver will respond to /* enable_suspend -- When enabled, the driver will respond to
* USB suspend requests by powering down the NET2280. Otherwise, * USB suspend requests by powering down the NET2280. Otherwise,
* USB suspend requests will be ignored. This is acceptible for * USB suspend requests will be ignored. This is acceptible for
* self-powered devices, and helps avoid some quirks. * self-powered devices
*/ */
static int enable_suspend = 0; static int enable_suspend = 0;
@ -223,6 +225,11 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
ep->is_in = (tmp & USB_DIR_IN) != 0; ep->is_in = (tmp & USB_DIR_IN) != 0;
if (!ep->is_in) if (!ep->is_in)
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp); writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
else if (dev->pdev->device != 0x2280) {
/* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
writel ((1 << CLEAR_NAK_OUT_PACKETS)
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
writel (tmp, &ep->regs->ep_cfg); writel (tmp, &ep->regs->ep_cfg);
@ -232,8 +239,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
writel (tmp, &dev->regs->pciirqenb0); writel (tmp, &dev->regs->pciirqenb0);
tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE) tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE) | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE);
| readl (&ep->regs->ep_irqenb); if (dev->pdev->device == 0x2280)
tmp |= readl (&ep->regs->ep_irqenb);
writel (tmp, &ep->regs->ep_irqenb); writel (tmp, &ep->regs->ep_irqenb);
} else { /* dma, per-request */ } else { /* dma, per-request */
tmp = (1 << (8 + ep->num)); /* completion */ tmp = (1 << (8 + ep->num)); /* completion */
@ -314,10 +322,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
/* init to our chosen defaults, notably so that we NAK OUT /* init to our chosen defaults, notably so that we NAK OUT
* packets until the driver queues a read (+note erratum 0112) * packets until the driver queues a read (+note erratum 0112)
*/ */
tmp = (1 << SET_NAK_OUT_PACKETS_MODE) if (!ep->is_in || ep->dev->pdev->device == 0x2280) {
tmp = (1 << SET_NAK_OUT_PACKETS_MODE)
| (1 << SET_NAK_OUT_PACKETS) | (1 << SET_NAK_OUT_PACKETS)
| (1 << CLEAR_EP_HIDE_STATUS_PHASE) | (1 << CLEAR_EP_HIDE_STATUS_PHASE)
| (1 << CLEAR_INTERRUPT_MODE); | (1 << CLEAR_INTERRUPT_MODE);
} else {
/* added for 2282 */
tmp = (1 << CLEAR_NAK_OUT_PACKETS_MODE)
| (1 << CLEAR_NAK_OUT_PACKETS)
| (1 << CLEAR_EP_HIDE_STATUS_PHASE)
| (1 << CLEAR_INTERRUPT_MODE);
}
if (ep->num != 0) { if (ep->num != 0) {
tmp |= (1 << CLEAR_ENDPOINT_TOGGLE) tmp |= (1 << CLEAR_ENDPOINT_TOGGLE)
@ -326,14 +342,18 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
writel (tmp, &ep->regs->ep_rsp); writel (tmp, &ep->regs->ep_rsp);
/* scrub most status bits, and flush any fifo state */ /* scrub most status bits, and flush any fifo state */
writel ( (1 << TIMEOUT) if (ep->dev->pdev->device == 0x2280)
tmp = (1 << FIFO_OVERFLOW)
| (1 << FIFO_UNDERFLOW);
else
tmp = 0;
writel (tmp | (1 << TIMEOUT)
| (1 << USB_STALL_SENT) | (1 << USB_STALL_SENT)
| (1 << USB_IN_NAK_SENT) | (1 << USB_IN_NAK_SENT)
| (1 << USB_IN_ACK_RCVD) | (1 << USB_IN_ACK_RCVD)
| (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_PING_NAK_SENT)
| (1 << USB_OUT_ACK_SENT) | (1 << USB_OUT_ACK_SENT)
| (1 << FIFO_OVERFLOW)
| (1 << FIFO_UNDERFLOW)
| (1 << FIFO_FLUSH) | (1 << FIFO_FLUSH)
| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
@ -718,7 +738,7 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
*/ */
if (ep->is_in) if (ep->is_in)
dmacount |= (1 << DMA_DIRECTION); dmacount |= (1 << DMA_DIRECTION);
else if ((dmacount % ep->ep.maxpacket) != 0) if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
dmacount |= (1 << END_OF_CHAIN); dmacount |= (1 << END_OF_CHAIN);
req->valid = valid; req->valid = valid;
@ -760,9 +780,12 @@ static inline void stop_dma (struct net2280_dma_regs __iomem *dma)
static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma) static void start_queue (struct net2280_ep *ep, u32 dmactl, u32 td_dma)
{ {
struct net2280_dma_regs __iomem *dma = ep->dma; struct net2280_dma_regs __iomem *dma = ep->dma;
unsigned int tmp = (1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION);
writel ((1 << VALID_BIT) | (ep->is_in << DMA_DIRECTION), if (ep->dev->pdev->device != 0x2280)
&dma->dmacount); tmp |= (1 << END_OF_CHAIN);
writel (tmp, &dma->dmacount);
writel (readl (&dma->dmastat), &dma->dmastat); writel (readl (&dma->dmastat), &dma->dmastat);
writel (td_dma, &dma->dmadesc); writel (td_dma, &dma->dmadesc);
@ -2110,7 +2133,11 @@ static void handle_ep_small (struct net2280_ep *ep)
VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n", VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
ep->ep.name, t, req ? &req->req : 0); ep->ep.name, t, req ? &req->req : 0);
#endif #endif
writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat); if (!ep->is_in || ep->dev->pdev->device == 0x2280)
writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
else
/* Added for 2282 */
writel (t, &ep->regs->ep_stat);
/* for ep0, monitor token irqs to catch data stage length errors /* for ep0, monitor token irqs to catch data stage length errors
* and to synchronize on status. * and to synchronize on status.
@ -2337,7 +2364,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
u32 raw [2]; u32 raw [2];
struct usb_ctrlrequest r; struct usb_ctrlrequest r;
} u; } u;
int tmp = 0; int tmp;
struct net2280_request *req; struct net2280_request *req;
if (dev->gadget.speed == USB_SPEED_UNKNOWN) { if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
@ -2364,14 +2391,19 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
} }
ep->stopped = 0; ep->stopped = 0;
dev->protocol_stall = 0; dev->protocol_stall = 0;
writel ( (1 << TIMEOUT)
if (ep->dev->pdev->device == 0x2280)
tmp = (1 << FIFO_OVERFLOW)
| (1 << FIFO_UNDERFLOW);
else
tmp = 0;
writel (tmp | (1 << TIMEOUT)
| (1 << USB_STALL_SENT) | (1 << USB_STALL_SENT)
| (1 << USB_IN_NAK_SENT) | (1 << USB_IN_NAK_SENT)
| (1 << USB_IN_ACK_RCVD) | (1 << USB_IN_ACK_RCVD)
| (1 << USB_OUT_PING_NAK_SENT) | (1 << USB_OUT_PING_NAK_SENT)
| (1 << USB_OUT_ACK_SENT) | (1 << USB_OUT_ACK_SENT)
| (1 << FIFO_OVERFLOW)
| (1 << FIFO_UNDERFLOW)
| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT) | (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
| (1 << DATA_PACKET_RECEIVED_INTERRUPT) | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
@ -2385,6 +2417,8 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
cpu_to_le32s (&u.raw [0]); cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]); cpu_to_le32s (&u.raw [1]);
tmp = 0;
#define w_value le16_to_cpup (&u.r.wValue) #define w_value le16_to_cpup (&u.r.wValue)
#define w_index le16_to_cpup (&u.r.wIndex) #define w_index le16_to_cpup (&u.r.wIndex)
#define w_length le16_to_cpup (&u.r.wLength) #define w_length le16_to_cpup (&u.r.wLength)
@ -2594,10 +2628,17 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
writel (stat, &dev->regs->irqstat1); writel (stat, &dev->regs->irqstat1);
/* some status we can just ignore */ /* some status we can just ignore */
stat &= ~((1 << CONTROL_STATUS_INTERRUPT) if (dev->pdev->device == 0x2280)
| (1 << SUSPEND_REQUEST_INTERRUPT) stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
| (1 << RESUME_INTERRUPT) | (1 << SUSPEND_REQUEST_INTERRUPT)
| (1 << SOF_INTERRUPT)); | (1 << RESUME_INTERRUPT)
| (1 << SOF_INTERRUPT));
else
stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
| (1 << RESUME_INTERRUPT)
| (1 << SOF_DOWN_INTERRUPT)
| (1 << SOF_INTERRUPT));
if (!stat) if (!stat)
return; return;
// DEBUG (dev, "irqstat1 %08x\n", stat); // DEBUG (dev, "irqstat1 %08x\n", stat);
@ -2939,6 +2980,13 @@ static struct pci_device_id pci_ids [] = { {
.device = 0x2280, .device = 0x2280,
.subvendor = PCI_ANY_ID, .subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID, .subdevice = PCI_ANY_ID,
}, {
.class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
.class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2282,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, { /* end: all zeroes */ } }, { /* end: all zeroes */ }
}; };

View file

@ -179,6 +179,7 @@ struct net2280_regs {
#define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19 #define PCI_TARGET_ABORT_RECEIVED_INTERRUPT 19
#define PCI_RETRY_ABORT_INTERRUPT 17 #define PCI_RETRY_ABORT_INTERRUPT 17
#define PCI_MASTER_CYCLE_DONE_INTERRUPT 16 #define PCI_MASTER_CYCLE_DONE_INTERRUPT 16
#define SOF_DOWN_INTERRUPT 14
#define GPIO_INTERRUPT 13 #define GPIO_INTERRUPT 13
#define DMA_D_INTERRUPT 12 #define DMA_D_INTERRUPT 12
#define DMA_C_INTERRUPT 11 #define DMA_C_INTERRUPT 11
@ -346,6 +347,7 @@ struct net2280_dma_regs { /* [11.7] */
#define DMA_ENABLE 1 #define DMA_ENABLE 1
#define DMA_ADDRESS_HOLD 0 #define DMA_ADDRESS_HOLD 0
u32 dmastat; u32 dmastat;
#define DMA_ABORT_DONE_INTERRUPT 27
#define DMA_SCATTER_GATHER_DONE_INTERRUPT 25 #define DMA_SCATTER_GATHER_DONE_INTERRUPT 25
#define DMA_TRANSACTION_DONE_INTERRUPT 24 #define DMA_TRANSACTION_DONE_INTERRUPT 24
#define DMA_ABORT 1 #define DMA_ABORT 1