usb: xhci: Add reset controller support

Some atypical users of xhci might need to manually reset their xHCI
controller before starting the HCD setup. Check if a reset controller
device is available to the PCI bus and trigger a reset.

Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de>
[mb: squash fix to only build xhci_reset_hw() if CONFIG_DM_BUS]
Signed-off-by: Matthias Brugger <mbrugger@suse.com>
This commit is contained in:
Nicolas Saenz Julienne 2020-06-29 18:37:25 +02:00 committed by Matthias Brugger
parent 6836d59094
commit 0b80371b35
3 changed files with 39 additions and 0 deletions

View File

@ -180,6 +180,8 @@ void xhci_cleanup(struct xhci_ctrl *ctrl)
xhci_free_virt_devices(ctrl);
free(ctrl->erst.entries);
free(ctrl->dcbaa);
if (reset_valid(&ctrl->reset))
reset_free(&ctrl->reset);
memset(ctrl, '\0', sizeof(struct xhci_ctrl));
}

View File

@ -190,6 +190,37 @@ static int xhci_start(struct xhci_hcor *hcor)
return ret;
}
#if CONFIG_IS_ENABLED(DM_USB)
/**
* Resets XHCI Hardware
*
* @param ctrl pointer to host controller
* @return 0 if OK, or a negative error code.
*/
static int xhci_reset_hw(struct xhci_ctrl *ctrl)
{
int ret;
ret = reset_get_by_index(ctrl->dev, 0, &ctrl->reset);
if (ret && ret != -ENOENT && ret != -ENOTSUPP) {
dev_err(ctrl->dev, "failed to get reset\n");
return ret;
}
if (reset_valid(&ctrl->reset)) {
ret = reset_assert(&ctrl->reset);
if (ret)
return ret;
ret = reset_deassert(&ctrl->reset);
if (ret)
return ret;
}
return 0;
}
#endif
/**
* Resets the XHCI Controller
*
@ -1508,6 +1539,10 @@ int xhci_register(struct udevice *dev, struct xhci_hccr *hccr,
ctrl->dev = dev;
ret = xhci_reset_hw(ctrl);
if (ret)
goto err;
/*
* XHCI needs to issue a Address device command to setup
* proper device context structures, before it can interact

View File

@ -16,6 +16,7 @@
#ifndef HOST_XHCI_H_
#define HOST_XHCI_H_
#include <reset.h>
#include <asm/types.h>
#include <asm/cache.h>
#include <asm/io.h>
@ -1209,6 +1210,7 @@ struct xhci_ctrl {
#if CONFIG_IS_ENABLED(DM_USB)
struct udevice *dev;
#endif
struct reset_ctl reset;
struct xhci_hccr *hccr; /* R/O registers, not need for volatile */
struct xhci_hcor *hcor;
struct xhci_doorbell_array *dba;