aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c20
-rw-r--r--drivers/usb/host/ehci-mxc.c13
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c2
-rw-r--r--drivers/usb/host/isp1362-hcd.c15
-rw-r--r--drivers/usb/host/isp1362.h2
-rw-r--r--drivers/usb/host/r8a66597-hcd.c6
-rw-r--r--drivers/usb/host/r8a66597.h26
-rw-r--r--drivers/usb/host/xhci-pci.c2
-rw-r--r--drivers/usb/host/xhci-ring.c93
-rw-r--r--drivers/usb/host/xhci.c57
-rw-r--r--drivers/usb/host/xhci.h12
11 files changed, 194 insertions, 54 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ef3e88f0b3c3..a3ef2a9d9dc2 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1135,7 +1135,7 @@ MODULE_LICENSE ("GPL");
#ifdef CONFIG_XPS_USB_HCD_XILINX
#include "ehci-xilinx-of.c"
-#define OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
+#define XILINX_OF_PLATFORM_DRIVER ehci_hcd_xilinx_of_driver
#endif
#ifdef CONFIG_PLAT_ORION
@@ -1159,7 +1159,8 @@ MODULE_LICENSE ("GPL");
#endif
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
- !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER)
+ !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
+ !defined(XILINX_OF_PLATFORM_DRIVER)
#error "missing bus glue for ehci-hcd"
#endif
@@ -1213,10 +1214,20 @@ static int __init ehci_hcd_init(void)
if (retval < 0)
goto clean3;
#endif
+
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ retval = of_register_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+ if (retval < 0)
+ goto clean4;
+#endif
return retval;
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ /* of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER); */
+clean4:
+#endif
#ifdef OF_PLATFORM_DRIVER
- /* of_unregister_platform_driver(&OF_PLATFORM_DRIVER); */
+ of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
clean3:
#endif
#ifdef PS3_SYSTEM_BUS_DRIVER
@@ -1243,6 +1254,9 @@ module_init(ehci_hcd_init);
static void __exit ehci_hcd_cleanup(void)
{
+#ifdef XILINX_OF_PLATFORM_DRIVER
+ of_unregister_platform_driver(&XILINX_OF_PLATFORM_DRIVER);
+#endif
#ifdef OF_PLATFORM_DRIVER
of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
#endif
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 544ccfd7056e..bd4027745aa7 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -207,10 +207,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
- if (otg_init(pdata->otg) != 0)
- dev_err(dev, "unable to init transceiver\n");
- else if (otg_set_vbus(pdata->otg, 1) != 0)
+ ret = otg_init(pdata->otg);
+ if (ret) {
+ dev_err(dev, "unable to init transceiver, probably missing\n");
+ ret = -ENODEV;
+ goto err_add;
+ }
+ ret = otg_set_vbus(pdata->otg, 1);
+ if (ret) {
dev_err(dev, "unable to enable vbus on transceiver\n");
+ goto err_add;
+ }
}
priv->hcd = hcd;
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index 013972bbde57..4899f451add9 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -151,7 +151,7 @@ static const struct hc_driver ehci_xilinx_of_hc_driver = {
static int __devinit
ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
{
- struct device_node *dn = op->node;
+ struct device_node *dn = op->dev.of_node;
struct usb_hcd *hcd;
struct ehci_hcd *ehci;
struct resource res;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 20a0dfe0fe36..0587ad4ce5c2 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2224,12 +2224,9 @@ static void remove_debug_file(struct isp1362_hcd *isp1362_hcd)
/*-------------------------------------------------------------------------*/
-static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
+static void __isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
{
int tmp = 20;
- unsigned long flags;
-
- spin_lock_irqsave(&isp1362_hcd->lock, flags);
isp1362_write_reg16(isp1362_hcd, HCSWRES, HCSWRES_MAGIC);
isp1362_write_reg32(isp1362_hcd, HCCMDSTAT, OHCI_HCR);
@@ -2240,6 +2237,14 @@ static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
}
if (!tmp)
pr_err("Software reset timeout\n");
+}
+
+static void isp1362_sw_reset(struct isp1362_hcd *isp1362_hcd)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp1362_hcd->lock, flags);
+ __isp1362_sw_reset(isp1362_hcd);
spin_unlock_irqrestore(&isp1362_hcd->lock, flags);
}
@@ -2418,7 +2423,7 @@ static void isp1362_hc_stop(struct usb_hcd *hcd)
if (isp1362_hcd->board && isp1362_hcd->board->reset)
isp1362_hcd->board->reset(hcd->self.controller, 1);
else
- isp1362_sw_reset(isp1362_hcd);
+ __isp1362_sw_reset(isp1362_hcd);
if (isp1362_hcd->board && isp1362_hcd->board->clock)
isp1362_hcd->board->clock(hcd->self.controller, 0);
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index 5151516ea1de..d995351f9bed 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -65,7 +65,7 @@ static inline void delayed_insw(unsigned int addr, void *buf, int len)
unsigned short *bp = (unsigned short *)buf;
while (len--) {
DUMMY_DELAY_ACCESS;
- *bp++ = inw((void *)addr);
+ *bp++ = inw(addr);
}
}
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index 6db57ab6079d..77be3c24a427 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -1065,7 +1065,7 @@ static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port)
else if (speed == LSMODE)
rh->port |= USB_PORT_STAT_LOW_SPEED;
- rh->port &= USB_PORT_STAT_RESET;
+ rh->port &= ~USB_PORT_STAT_RESET;
rh->port |= USB_PORT_STAT_ENABLE;
}
@@ -2404,7 +2404,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
del_timer_sync(&r8a66597->rh_timer);
usb_remove_hcd(hcd);
- iounmap((void *)r8a66597->reg);
+ iounmap(r8a66597->reg);
#ifdef CONFIG_HAVE_CLK
if (r8a66597->pdata->on_chip)
clk_put(r8a66597->clk);
@@ -2496,7 +2496,7 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
init_timer(&r8a66597->rh_timer);
r8a66597->rh_timer.function = r8a66597_timer;
r8a66597->rh_timer.data = (unsigned long)r8a66597;
- r8a66597->reg = (unsigned long)reg;
+ r8a66597->reg = reg;
/* make sure no interrupts are pending */
ret = r8a66597_clock_enable(r8a66597);
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index 228e3fb23854..95d0f5adfdcf 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -112,7 +112,7 @@ struct r8a66597_root_hub {
struct r8a66597 {
spinlock_t lock;
- unsigned long reg;
+ void __iomem *reg;
#ifdef CONFIG_HAVE_CLK
struct clk *clk;
#endif
@@ -170,67 +170,67 @@ static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597,
static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
{
- return inw(r8a66597->reg + offset);
+ return ioread16(r8a66597->reg + offset);
}
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
unsigned long count;
if (r8a66597->pdata->on_chip) {
count = len / 4;
- insl(fifoaddr, buf, count);
+ ioread32_rep(fifoaddr, buf, count);
if (len & 0x00000003) {
- unsigned long tmp = inl(fifoaddr);
+ unsigned long tmp = ioread32(fifoaddr);
memcpy((unsigned char *)buf + count * 4, &tmp,
len & 0x03);
}
} else {
len = (len + 1) / 2;
- insw(fifoaddr, buf, len);
+ ioread16_rep(fifoaddr, buf, len);
}
}
static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
unsigned long offset)
{
- outw(val, r8a66597->reg + offset);
+ iowrite16(val, r8a66597->reg + offset);
}
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
unsigned long offset, u16 *buf,
int len)
{
- unsigned long fifoaddr = r8a66597->reg + offset;
+ void __iomem *fifoaddr = r8a66597->reg + offset;
unsigned long count;
unsigned char *pb;
int i;
if (r8a66597->pdata->on_chip) {
count = len / 4;
- outsl(fifoaddr, buf, count);
+ iowrite32_rep(fifoaddr, buf, count);
if (len & 0x00000003) {
pb = (unsigned char *)buf + count * 4;
for (i = 0; i < (len & 0x00000003); i++) {
if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
- outb(pb[i], fifoaddr + i);
+ iowrite8(pb[i], fifoaddr + i);
else
- outb(pb[i], fifoaddr + 3 - i);
+ iowrite8(pb[i], fifoaddr + 3 - i);
}
}
} else {
int odd = len & 0x0001;
len = len / 2;
- outsw(fifoaddr, buf, len);
+ ioread16_rep(fifoaddr, buf, len);
if (unlikely(odd)) {
buf = &buf[len];
- outb((unsigned char)*buf, fifoaddr);
+ iowrite8((unsigned char)*buf, fifoaddr);
}
}
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index edffd81fc253..11482b6b9381 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -78,6 +78,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure"
" endpoint cmd after reset endpoint\n");
}
+ if (pdev->vendor == PCI_VENDOR_ID_NEC)
+ xhci->quirks |= XHCI_NEC_HOST;
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 36c858e5b529..94e6934edb09 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -182,8 +182,12 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
* set, but other sections talk about dealing with the chain bit set. This was
* fixed in the 0.96 specification errata, but we have to assume that all 0.95
* xHCI hardware can't handle the chain bit being cleared on a link TRB.
+ *
+ * @more_trbs_coming: Will you enqueue more TRBs before calling
+ * prepare_transfer()?
*/
-static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
+ bool consumer, bool more_trbs_coming)
{
u32 chain;
union xhci_trb *next;
@@ -199,15 +203,28 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
while (last_trb(xhci, ring, ring->enq_seg, next)) {
if (!consumer) {
if (ring != xhci->event_ring) {
- if (chain) {
- next->link.control |= TRB_CHAIN;
-
- /* Give this link TRB to the hardware */
- wmb();
- next->link.control ^= TRB_CYCLE;
- } else {
+ /*
+ * If the caller doesn't plan on enqueueing more
+ * TDs before ringing the doorbell, then we
+ * don't want to give the link TRB to the
+ * hardware just yet. We'll give the link TRB
+ * back in prepare_ring() just before we enqueue
+ * the TD at the top of the ring.
+ */
+ if (!chain && !more_trbs_coming)
break;
+
+ /* If we're not dealing with 0.95 hardware,
+ * carry over the chain bit of the previous TRB
+ * (which may mean the chain bit is cleared).
+ */
+ if (!xhci_link_trb_quirk(xhci)) {
+ next->link.control &= ~TRB_CHAIN;
+ next->link.control |= chain;
}
+ /* Give this link TRB to the hardware */
+ wmb();
+ next->link.control ^= TRB_CYCLE;
}
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
@@ -1071,6 +1088,15 @@ bandwidth_change:
xhci_warn(xhci, "Reset device command completion "
"for disabled slot %u\n", slot_id);
break;
+ case TRB_TYPE(TRB_NEC_GET_FW):
+ if (!(xhci->quirks & XHCI_NEC_HOST)) {
+ xhci->error_bitmask |= 1 << 6;
+ break;
+ }
+ xhci_dbg(xhci, "NEC firmware version %2x.%02x\n",
+ NEC_FW_MAJOR(event->status),
+ NEC_FW_MINOR(event->status));
+ break;
default:
/* Skip over unknown commands on the event ring */
xhci->error_bitmask |= 1 << 6;
@@ -1079,6 +1105,17 @@ bandwidth_change:
inc_deq(xhci, xhci->cmd_ring, false);
}
+static void handle_vendor_event(struct xhci_hcd *xhci,
+ union xhci_trb *event)
+{
+ u32 trb_type;
+
+ trb_type = TRB_FIELD_TO_TYPE(event->generic.field[3]);
+ xhci_dbg(xhci, "Vendor specific event TRB type = %u\n", trb_type);
+ if (trb_type == TRB_NEC_CMD_COMP && (xhci->quirks & XHCI_NEC_HOST))
+ handle_cmd_completion(xhci, &event->event_cmd);
+}
+
static void handle_port_status(struct xhci_hcd *xhci,
union xhci_trb *event)
{
@@ -1659,7 +1696,10 @@ void xhci_handle_event(struct xhci_hcd *xhci)
update_ptrs = 0;
break;
default:
- xhci->error_bitmask |= 1 << 3;
+ if ((event->event_cmd.flags & TRB_TYPE_BITMASK) >= TRB_TYPE(48))
+ handle_vendor_event(xhci, event);
+ else
+ xhci->error_bitmask |= 1 << 3;
}
/* Any of the above functions may drop and re-acquire the lock, so check
* to make sure a watchdog timer didn't mark the host as non-responsive.
@@ -1684,9 +1724,12 @@ void xhci_handle_event(struct xhci_hcd *xhci)
/*
* Generic function for queueing a TRB on a ring.
* The caller must have checked to make sure there's room on the ring.
+ *
+ * @more_trbs_coming: Will you enqueue more TRBs before calling
+ * prepare_transfer()?
*/
static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
- bool consumer,
+ bool consumer, bool more_trbs_coming,
u32 field1, u32 field2, u32 field3, u32 field4)
{
struct xhci_generic_trb *trb;
@@ -1696,7 +1739,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
trb->field[1] = field2;
trb->field[2] = field3;
trb->field[3] = field4;
- inc_enq(xhci, ring, consumer);
+ inc_enq(xhci, ring, consumer, more_trbs_coming);
}
/*
@@ -1965,6 +2008,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
int trb_buff_len, this_sg_len, running_total;
bool first_trb;
u64 addr;
+ bool more_trbs_coming;
struct xhci_generic_trb *start_trb;
int start_cycle;
@@ -2050,7 +2094,11 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
length_field = TRB_LEN(trb_buff_len) |
remainder |
TRB_INTR_TARGET(0);
- queue_trb(xhci, ep_ring, false,
+ if (num_trbs > 1)
+ more_trbs_coming = true;
+ else
+ more_trbs_coming = false;
+ queue_trb(xhci, ep_ring, false, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -2101,6 +2149,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
int num_trbs;
struct xhci_generic_trb *start_trb;
bool first_trb;
+ bool more_trbs_coming;
int start_cycle;
u32 field, length_field;
@@ -2189,7 +2238,11 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
length_field = TRB_LEN(trb_buff_len) |
remainder |
TRB_INTR_TARGET(0);
- queue_trb(xhci, ep_ring, false,
+ if (num_trbs > 1)
+ more_trbs_coming = true;
+ else
+ more_trbs_coming = false;
+ queue_trb(xhci, ep_ring, false, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -2268,7 +2321,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
/* Queue setup TRB - see section 6.4.1.2.1 */
/* FIXME better way to translate setup_packet into two u32 fields? */
setup = (struct usb_ctrlrequest *) urb->setup_packet;
- queue_trb(xhci, ep_ring, false,
+ queue_trb(xhci, ep_ring, false, true,
/* FIXME endianness is probably going to bite my ass here. */
setup->bRequestType | setup->bRequest << 8 | setup->wValue << 16,
setup->wIndex | setup->wLength << 16,
@@ -2284,7 +2337,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false,
+ queue_trb(xhci, ep_ring, false, true,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
length_field,
@@ -2301,7 +2354,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field = 0;
else
field = TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false,
+ queue_trb(xhci, ep_ring, false, false,
0,
0,
TRB_INTR_TARGET(0),
@@ -2338,7 +2391,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
"unfailable commands failed.\n");
return -ENOMEM;
}
- queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
+ queue_trb(xhci, xhci->cmd_ring, false, false, field1, field2, field3,
field4 | xhci->cmd_ring->cycle_state);
return 0;
}
@@ -2378,6 +2431,12 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
false);
}
+int xhci_queue_vendor_command(struct xhci_hcd *xhci,
+ u32 field1, u32 field2, u32 field3, u32 field4)
+{
+ return queue_command(xhci, field1, field2, field3, field4, false);
+}
+
/* Queue a reset device command TRB */
int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
{
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 40e0a0c221b8..27345cd04da0 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -106,6 +106,33 @@ int xhci_halt(struct xhci_hcd *xhci)
}
/*
+ * Set the run bit and wait for the host to be running.
+ */
+int xhci_start(struct xhci_hcd *xhci)
+{
+ u32 temp;
+ int ret;
+
+ temp = xhci_readl(xhci, &xhci->op_regs->command);
+ temp |= (CMD_RUN);
+ xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
+ temp);
+ xhci_writel(xhci, temp, &xhci->op_regs->command);
+
+ /*
+ * Wait for the HCHalted Status bit to be 0 to indicate the host is
+ * running.
+ */
+ ret = handshake(xhci, &xhci->op_regs->status,
+ STS_HALT, 0, XHCI_MAX_HALT_USEC);
+ if (ret == -ETIMEDOUT)
+ xhci_err(xhci, "Host took too long to start, "
+ "waited %u microseconds.\n",
+ XHCI_MAX_HALT_USEC);
+ return ret;
+}
+
+/*
* Reset a halted HC, and set the internal HC state to HC_STATE_HALT.
*
* This resets pipelines, timers, counters, state machines, etc.
@@ -116,6 +143,7 @@ int xhci_reset(struct xhci_hcd *xhci)
{
u32 command;
u32 state;
+ int ret;
state = xhci_readl(xhci, &xhci->op_regs->status);
if ((state & STS_HALT) == 0) {
@@ -130,7 +158,17 @@ int xhci_reset(struct xhci_hcd *xhci)
/* XXX: Why does EHCI set this here? Shouldn't other code do this? */
xhci_to_hcd(xhci)->state = HC_STATE_HALT;
- return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000);
+ ret = handshake(xhci, &xhci->op_regs->command,
+ CMD_RESET, 0, 250 * 1000);
+ if (ret)
+ return ret;
+
+ xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n");
+ /*
+ * xHCI cannot write to any doorbells or operational registers other
+ * than status until the "Controller Not Ready" flag is cleared.
+ */
+ return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
}
@@ -448,17 +486,20 @@ int xhci_run(struct usb_hcd *hcd)
if (NUM_TEST_NOOPS > 0)
doorbell = xhci_setup_one_noop(xhci);
+ if (xhci->quirks & XHCI_NEC_HOST)
+ xhci_queue_vendor_command(xhci, 0, 0, 0,
+ TRB_TYPE(TRB_NEC_GET_FW));
+
+ if (xhci_start(xhci)) {
+ xhci_halt(xhci);
+ return -ENODEV;
+ }
- temp = xhci_readl(xhci, &xhci->op_regs->command);
- temp |= (CMD_RUN);
- xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n",
- temp);
- xhci_writel(xhci, temp, &xhci->op_regs->command);
- /* Flush PCI posted writes */
- temp = xhci_readl(xhci, &xhci->op_regs->command);
xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);
if (doorbell)
(*doorbell)(xhci);
+ if (xhci->quirks & XHCI_NEC_HOST)
+ xhci_ring_cmd_db(xhci);
xhci_dbg(xhci, "Finished xhci_run\n");
return 0;
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index dada2fb59261..8b4b7d39f79c 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -925,6 +925,7 @@ union xhci_trb {
/* TRB bit mask */
#define TRB_TYPE_BITMASK (0xfc00)
#define TRB_TYPE(p) ((p) << 10)
+#define TRB_FIELD_TO_TYPE(p) (((p) & TRB_TYPE_BITMASK) >> 10)
/* TRB type IDs */
/* bulk, interrupt, isoc scatter/gather, and control data stage */
#define TRB_NORMAL 1
@@ -992,6 +993,14 @@ union xhci_trb {
#define TRB_MFINDEX_WRAP 39
/* TRB IDs 40-47 reserved, 48-63 is vendor-defined */
+/* Nec vendor-specific command completion event. */
+#define TRB_NEC_CMD_COMP 48
+/* Get NEC firmware revision. */
+#define TRB_NEC_GET_FW 49
+
+#define NEC_FW_MINOR(p) (((p) >> 0) & 0xff)
+#define NEC_FW_MAJOR(p) (((p) >> 8) & 0xff)
+
/*
* TRBS_PER_SEGMENT must be a multiple of 4,
* since the command ring is 64-byte aligned.
@@ -1172,6 +1181,7 @@ struct xhci_hcd {
unsigned int quirks;
#define XHCI_LINK_TRB_QUIRK (1 << 0)
#define XHCI_RESET_EP_QUIRK (1 << 1)
+#define XHCI_NEC_HOST (1 << 2)
};
/* For testing purposes */
@@ -1379,6 +1389,8 @@ void xhci_set_hc_event_deq(struct xhci_hcd *xhci);
int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id);
int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
u32 slot_id);
+int xhci_queue_vendor_command(struct xhci_hcd *xhci,
+ u32 field1, u32 field2, u32 field3, u32 field4);
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
unsigned int ep_index);
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,