Merge branch 'for-usb' of git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-linux into usb-next
* 'for-usb' of git://git.kernel.org/pub/scm/linux/kernel/git/geoff/ps3-linux: usb: PS3 EHCI QH read work-around usb: Fix PS3 EHCI suspend usb: PS3 EHCI HC reset work-around usb: Remove ehci_reset call from ehci_run
This commit is contained in:
commit
332ceddb8c
8 changed files with 93 additions and 10 deletions
|
@ -23,6 +23,7 @@ static int au1xxx_ehci_setup(struct usb_hcd *hcd)
|
||||||
int ret = ehci_init(hcd);
|
int ret = ehci_init(hcd);
|
||||||
|
|
||||||
ehci->need_io_watchdog = 0;
|
ehci->need_io_watchdog = 0;
|
||||||
|
ehci_reset(ehci);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/unaligned.h>
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
|
#if defined(CONFIG_PPC_PS3)
|
||||||
|
#include <asm/firmware.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -230,12 +234,58 @@ static int ehci_halt (struct ehci_hcd *ehci)
|
||||||
STS_HALT, STS_HALT, 16 * 125);
|
STS_HALT, STS_HALT, 16 * 125);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The EHCI controller of the Cell Super Companion Chip used in the
|
||||||
|
* PS3 will stop the root hub after all root hub ports are suspended.
|
||||||
|
* When in this condition handshake will return -ETIMEDOUT. The
|
||||||
|
* STS_HLT bit will not be set, so inspection of the frame index is
|
||||||
|
* used here to test for the condition. If the condition is found
|
||||||
|
* return success to allow the USB suspend to complete.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
|
||||||
|
void __iomem *ptr, u32 mask, u32 done,
|
||||||
|
int usec)
|
||||||
|
{
|
||||||
|
unsigned int old_index;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
old_index = ehci_read_frame_index(ehci);
|
||||||
|
|
||||||
|
error = handshake(ehci, ptr, mask, done, usec);
|
||||||
|
|
||||||
|
if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
|
||||||
|
void __iomem *ptr, u32 mask, u32 done,
|
||||||
|
int usec)
|
||||||
|
{
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
|
static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
|
||||||
u32 mask, u32 done, int usec)
|
u32 mask, u32 done, int usec)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
error = handshake(ehci, ptr, mask, done, usec);
|
error = handshake(ehci, ptr, mask, done, usec);
|
||||||
|
if (error == -ETIMEDOUT)
|
||||||
|
error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
|
||||||
|
usec);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
ehci_halt(ehci);
|
ehci_halt(ehci);
|
||||||
ehci->rh_state = EHCI_RH_HALTED;
|
ehci->rh_state = EHCI_RH_HALTED;
|
||||||
|
@ -620,6 +670,7 @@ static int ehci_init(struct usb_hcd *hcd)
|
||||||
hw = ehci->async->hw;
|
hw = ehci->async->hw;
|
||||||
hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
|
hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
|
||||||
hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
|
hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
|
||||||
|
hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7)); /* I = 1 */
|
||||||
hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
|
hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
|
||||||
hw->hw_qtd_next = EHCI_LIST_END(ehci);
|
hw->hw_qtd_next = EHCI_LIST_END(ehci);
|
||||||
ehci->async->qh_state = QH_STATE_LINKED;
|
ehci->async->qh_state = QH_STATE_LINKED;
|
||||||
|
@ -677,22 +728,13 @@ static int ehci_init(struct usb_hcd *hcd)
|
||||||
static int ehci_run (struct usb_hcd *hcd)
|
static int ehci_run (struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
|
||||||
int retval;
|
|
||||||
u32 temp;
|
u32 temp;
|
||||||
u32 hcc_params;
|
u32 hcc_params;
|
||||||
|
|
||||||
hcd->uses_new_polling = 1;
|
hcd->uses_new_polling = 1;
|
||||||
|
|
||||||
/* EHCI spec section 4.1 */
|
/* EHCI spec section 4.1 */
|
||||||
/*
|
|
||||||
* TDI driver does the ehci_reset in their reset callback.
|
|
||||||
* Don't reset here, because configuration settings will
|
|
||||||
* vanish.
|
|
||||||
*/
|
|
||||||
if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) {
|
|
||||||
ehci_mem_cleanup(ehci);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
|
ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
|
||||||
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
|
ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
|
||||||
|
|
||||||
|
|
|
@ -155,6 +155,8 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
|
||||||
/* cache this readonly data; minimize chip reads */
|
/* cache this readonly data; minimize chip reads */
|
||||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||||
|
|
||||||
|
ehci_reset(ehci);
|
||||||
|
|
||||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
|
dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
|
||||||
|
|
|
@ -228,6 +228,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
|
||||||
/* cache this readonly data; minimize chip reads */
|
/* cache this readonly data; minimize chip reads */
|
||||||
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
|
omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
|
||||||
|
|
||||||
|
ehci_reset(omap_ehci);
|
||||||
|
|
||||||
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to add hcd with err %d\n", ret);
|
dev_err(dev, "failed to add hcd with err %d\n", ret);
|
||||||
|
|
|
@ -21,6 +21,34 @@
|
||||||
#include <asm/firmware.h>
|
#include <asm/firmware.h>
|
||||||
#include <asm/ps3.h>
|
#include <asm/ps3.h>
|
||||||
|
|
||||||
|
static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
|
||||||
|
{
|
||||||
|
/* PS3 HC internal setup register offsets. */
|
||||||
|
|
||||||
|
enum ps3_ehci_hc_insnreg {
|
||||||
|
ps3_ehci_hc_insnreg01 = 0x084,
|
||||||
|
ps3_ehci_hc_insnreg02 = 0x088,
|
||||||
|
ps3_ehci_hc_insnreg03 = 0x08c,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
|
||||||
|
* internal INSNREGXX setup regs back to the chip default values
|
||||||
|
* on Host Controller Reset (CMD_RESET) or Light Host Controller
|
||||||
|
* Reset (CMD_LRESET). The work-around for this is for the HC
|
||||||
|
* driver to re-initialise these regs when ever the HC is reset.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Set burst transfer counts to 256 out, 32 in. */
|
||||||
|
|
||||||
|
writel_be(0x01000020, (void __iomem *)ehci->regs +
|
||||||
|
ps3_ehci_hc_insnreg01);
|
||||||
|
|
||||||
|
/* Enable burst transfer counts. */
|
||||||
|
|
||||||
|
writel_be(0x00000001, (void __iomem *)ehci->regs +
|
||||||
|
ps3_ehci_hc_insnreg03);
|
||||||
|
}
|
||||||
|
|
||||||
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
@ -49,6 +77,8 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
|
||||||
|
|
||||||
ehci_reset(ehci);
|
ehci_reset(ehci);
|
||||||
|
|
||||||
|
ps3_ehci_setup_insnreg(ehci);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,8 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
|
||||||
/* cache this readonly data; minimize chip reads */
|
/* cache this readonly data; minimize chip reads */
|
||||||
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
ehci->hcs_params = readl(&ehci->caps->hcs_params);
|
||||||
|
|
||||||
|
ehci_reset(ehci);
|
||||||
|
|
||||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
dev_err(&pdev->dev, "Failed to add USB HCD\n");
|
||||||
|
|
|
@ -132,6 +132,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
ehci_port_power(ehci, 1);
|
ehci_port_power(ehci, 1);
|
||||||
|
|
||||||
|
ehci_reset(ehci);
|
||||||
|
|
||||||
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
ret = usb_add_hcd(hcd, pdev->resource[1].start,
|
||||||
IRQF_SHARED);
|
IRQF_SHARED);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
|
|
|
@ -78,6 +78,8 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
goto err4;
|
goto err4;
|
||||||
|
|
||||||
|
ehci_reset(ehci);
|
||||||
|
|
||||||
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
goto err4;
|
goto err4;
|
||||||
|
|
Loading…
Reference in a new issue