summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-faraday.c113
-rw-r--r--drivers/usb/host/ehci-hcd.c55
-rw-r--r--drivers/usb/host/ehci-mx5.c12
-rw-r--r--drivers/usb/host/ehci-tegra.c26
-rw-r--r--drivers/usb/host/ehci.h27
5 files changed, 139 insertions, 94 deletions
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
index b865fea3eba..821222cc5d7 100644
--- a/drivers/usb/host/ehci-faraday.c
+++ b/drivers/usb/host/ehci-faraday.c
@@ -29,6 +29,59 @@ static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
return !readl(&regs->usb.easstr);
}
+void faraday_ehci_set_usbmode(struct ehci_ctrl *ctrl)
+{
+ /* nothing needs to be done */
+}
+
+int faraday_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+{
+ int spd, ret = PORTSC_PSPD_HS;
+ union ehci_faraday_regs *regs;
+
+ ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
+ if (ehci_is_fotg2xx(regs))
+ spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+ else
+ spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+ switch (spd) {
+ case 0: /* full speed */
+ ret = PORTSC_PSPD_FS;
+ break;
+ case 1: /* low speed */
+ ret = PORTSC_PSPD_LS;
+ break;
+ case 2: /* high speed */
+ ret = PORTSC_PSPD_HS;
+ break;
+ default:
+ printf("ehci-faraday: invalid device speed\n");
+ break;
+ }
+
+ return ret;
+}
+
+uint32_t *faraday_ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+{
+ /* Faraday EHCI has one and only one portsc register */
+ if (port) {
+ /* Printing the message would cause a scan failure! */
+ debug("The request port(%d) is not configured\n", port);
+ return NULL;
+ }
+
+ /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+ return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
+}
+
+static const struct ehci_ops faraday_ehci_ops = {
+ .set_usb_mode = faraday_ehci_set_usbmode,
+ .get_port_speed = faraday_ehci_get_port_speed,
+ .get_portsc_register = faraday_ehci_get_portsc_register,
+};
+
/*
* Create the appropriate control structures to manage
* a new EHCI host controller.
@@ -43,6 +96,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
if (index < 0 || index >= ARRAY_SIZE(base_list))
return -1;
+ ehci_set_controller_priv(index, NULL, &faraday_ehci_ops);
regs = (void __iomem *)base_list[index];
hccr = (struct ehci_hccr *)&regs->usb.hccr;
hcor = (struct ehci_hcor *)&regs->usb.hcor;
@@ -87,62 +141,3 @@ int ehci_hcd_stop(int index)
{
return 0;
}
-
-/*
- * This ehci_set_usbmode() overrides the weak function
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(struct ehci_ctrl *ctrl)
-{
- /* nothing needs to be done */
-}
-
-/*
- * This ehci_get_port_speed() overrides the weak function
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
-{
- int spd, ret = PORTSC_PSPD_HS;
- union ehci_faraday_regs *regs;
-
- ret = (void __iomem *)((ulong)ctrl->hcor - 0x10);
- if (ehci_is_fotg2xx(regs))
- spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
- else
- spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
-
- switch (spd) {
- case 0: /* full speed */
- ret = PORTSC_PSPD_FS;
- break;
- case 1: /* low speed */
- ret = PORTSC_PSPD_LS;
- break;
- case 2: /* high speed */
- ret = PORTSC_PSPD_HS;
- break;
- default:
- printf("ehci-faraday: invalid device speed\n");
- break;
- }
-
- return ret;
-}
-
-/*
- * This ehci_get_portsc_register() overrides the weak function
- * in "ehci-hcd.c".
- */
-uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
-{
- /* Faraday EHCI has one and only one portsc register */
- if (port) {
- /* Printing the message would cause a scan failure! */
- debug("The request port(%d) is not configured\n", port);
- return NULL;
- }
-
- /* Faraday EHCI PORTSC register offset is 0x20 from hcor */
- return (uint32_t *)((uint8_t *)ctrl->hcor + 0x20);
-}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 9a9ec01d9f6..c6696aab506 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -124,12 +124,12 @@ static struct ehci_ctrl *ehci_get_ctrl(struct usb_device *udev)
return udev->controller;
}
-__weak int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+static int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
{
return PORTSC_PSPD(reg);
}
-__weak void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+static void ehci_set_usbmode(struct ehci_ctrl *ctrl)
{
uint32_t tmp;
uint32_t *reg_ptr;
@@ -143,13 +143,13 @@ __weak void ehci_set_usbmode(struct ehci_ctrl *ctrl)
ehci_writel(reg_ptr, tmp);
}
-__weak void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+static void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
uint32_t *reg)
{
mdelay(50);
}
-__weak uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
+static uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port)
{
if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
/* Printing the message would cause a scan failure! */
@@ -178,6 +178,7 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
static int ehci_reset(int index)
{
+ struct ehci_ctrl *ctrl = &ehcic[index];
uint32_t cmd;
int ret = 0;
@@ -192,7 +193,7 @@ static int ehci_reset(int index)
}
if (ehci_is_TDI())
- ehci_set_usbmode(&ehcic[index]);
+ ctrl->ops.set_usb_mode(&ehcic[index]);
#ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -691,7 +692,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
- status_reg = ehci_get_portsc_register(ctrl, port - 1);
+ status_reg = ctrl->ops.get_portsc_register(ctrl, port - 1);
if (!status_reg)
return -1;
break;
@@ -786,7 +787,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
if (ehci_is_TDI()) {
- switch (ehci_get_port_speed(ctrl, reg)) {
+ switch (ctrl->ops.get_port_speed(ctrl, reg)) {
case PORTSC_PSPD_FS:
break;
case PORTSC_PSPD_LS:
@@ -848,7 +849,7 @@ static int ehci_submit_root(struct usb_device *dev, unsigned long pipe,
* usb 2.0 specification say 50 ms resets on
* root
*/
- ehci_powerup_fixup(ctrl, status_reg, &reg);
+ ctrl->ops.powerup_fixup(ctrl, status_reg, &reg);
ehci_writel(status_reg, reg & ~EHCI_PS_PR);
/*
@@ -935,9 +936,37 @@ unknown:
return -1;
}
-void ehci_set_controller_priv(int index, void *priv)
+const struct ehci_ops default_ehci_ops = {
+ .set_usb_mode = ehci_set_usbmode,
+ .get_port_speed = ehci_get_port_speed,
+ .powerup_fixup = ehci_powerup_fixup,
+ .get_portsc_register = ehci_get_portsc_register,
+};
+
+static void ehci_setup_ops(struct ehci_ctrl *ctrl, const struct ehci_ops *ops)
+{
+ if (!ops) {
+ ctrl->ops = default_ehci_ops;
+ } else {
+ ctrl->ops = *ops;
+ if (!ctrl->ops.set_usb_mode)
+ ctrl->ops.set_usb_mode = ehci_set_usbmode;
+ if (!ctrl->ops.get_port_speed)
+ ctrl->ops.get_port_speed = ehci_get_port_speed;
+ if (!ctrl->ops.powerup_fixup)
+ ctrl->ops.powerup_fixup = ehci_powerup_fixup;
+ if (!ctrl->ops.get_portsc_register)
+ ctrl->ops.get_portsc_register =
+ ehci_get_portsc_register;
+ }
+}
+
+void ehci_set_controller_priv(int index, void *priv, const struct ehci_ops *ops)
{
- ehcic[index].priv = priv;
+ struct ehci_ctrl *ctrl = &ehcic[index];
+
+ ctrl->priv = priv;
+ ehci_setup_ops(ctrl, ops);
}
void *ehci_get_controller_priv(int index)
@@ -1066,6 +1095,12 @@ int usb_lowlevel_init(int index, enum usb_init_type init, void **controller)
uint tweaks = 0;
int rc;
+ /**
+ * Set ops to default_ehci_ops, ehci_hcd_init should call
+ * ehci_set_controller_priv to change any of these function pointers.
+ */
+ ctrl->ops = default_ehci_ops;
+
rc = ehci_hcd_init(index, init, &ctrl->hccr, &ctrl->hcor);
if (rc)
return rc;
diff --git a/drivers/usb/host/ehci-mx5.c b/drivers/usb/host/ehci-mx5.c
index 7566c61284e..d3199622eb9 100644
--- a/drivers/usb/host/ehci-mx5.c
+++ b/drivers/usb/host/ehci-mx5.c
@@ -218,11 +218,23 @@ void __weak board_ehci_hcd_postinit(struct usb_ehci *ehci, int port)
{
}
+__weak void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+ uint32_t *reg)
+{
+ mdelay(50);
+}
+
+static const struct ehci_ops mx5_ehci_ops = {
+ .powerup_fixup = mx5_ehci_powerup_fixup,
+};
+
int ehci_hcd_init(int index, enum usb_init_type init,
struct ehci_hccr **hccr, struct ehci_hcor **hcor)
{
struct usb_ehci *ehci;
+ /* The only user for this is efikamx-usb */
+ ehci_set_controller_priv(index, NULL, &mx5_ehci_ops);
set_usboh3_clk();
enable_usboh3_clk(true);
set_usb_phy_clk();
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 0e6b60e0d6a..9e380c309ee 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -193,11 +193,9 @@ static struct fdt_usb_controller fdt_usb_controllers[USB_CTRL_COUNT] = {
* A known hardware issue where Connect Status Change bit of PORTSC register
* of USB1 controller will be set after Port Reset.
* We have to clear it in order for later device enumeration to proceed.
- * This ehci_powerup_fixup overrides the weak function ehci_powerup_fixup
- * in "ehci-hcd.c".
*/
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
- uint32_t *reg)
+static void tegra_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
+ uint32_t *status_reg, uint32_t *reg)
{
struct fdt_usb *config = ctrl->priv;
struct fdt_usb_controller *controller;
@@ -215,11 +213,7 @@ void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
*reg |= EHCI_PS_CSC;
}
-/*
- * This ehci_set_usbmode overrides the weak function ehci_set_usbmode
- * in "ehci-hcd.c".
- */
-void ehci_set_usbmode(struct ehci_ctrl *ctrl)
+static void tegra_ehci_set_usbmode(struct ehci_ctrl *ctrl)
{
struct fdt_usb *config = ctrl->priv;
struct usb_ctlr *usbctlr;
@@ -232,11 +226,7 @@ void ehci_set_usbmode(struct ehci_ctrl *ctrl)
ehci_writel(&usbctlr->usb_mode, tmp);
}
-/*
- * This ehci_get_port_speed overrides the weak function ehci_get_port_speed
- * in "ehci-hcd.c".
- */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
+static int tegra_ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg)
{
struct fdt_usb *config = ctrl->priv;
struct fdt_usb_controller *controller;
@@ -714,6 +704,12 @@ static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
return 0;
}
+static const struct ehci_ops tegra_ehci_ops = {
+ .set_usb_mode = tegra_ehci_set_usbmode,
+ .get_port_speed = tegra_ehci_get_port_speed,
+ .powerup_fixup = tegra_ehci_powerup_fixup,
+};
+
/*
* process_usb_nodes() - Process a list of USB nodes, adding them to our list
* of USB ports.
@@ -805,7 +801,7 @@ int ehci_hcd_init(int index, enum usb_init_type init,
return -1;
config = &port[index];
- ehci_set_controller_priv(index, config);
+ ehci_set_controller_priv(index, config, &tegra_ehci_ops);
switch (init) {
case USB_INIT_HOST:
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2ca111a3002..cc23e1fe93f 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -244,6 +244,16 @@ enum {
EHCI_TWEAK_NO_INIT_CF = 1 << 0,
};
+struct ehci_ctrl;
+
+struct ehci_ops {
+ void (*set_usb_mode)(struct ehci_ctrl *ctrl);
+ int (*get_port_speed)(struct ehci_ctrl *ctrl, uint32_t reg);
+ void (*powerup_fixup)(struct ehci_ctrl *ctrl, uint32_t *status_reg,
+ uint32_t *reg);
+ uint32_t *(*get_portsc_register)(struct ehci_ctrl *ctrl, int port);
+};
+
struct ehci_ctrl {
struct ehci_hccr *hccr; /* R/O registers, not need for volatile */
struct ehci_hcor *hcor;
@@ -254,27 +264,24 @@ struct ehci_ctrl {
uint32_t *periodic_list;
int periodic_schedules;
int ntds;
+ struct ehci_ops ops;
void *priv; /* client's private data */
};
-/* Weak functions that drivers can override */
-int ehci_get_port_speed(struct ehci_ctrl *ctrl, uint32_t reg);
-void ehci_set_usbmode(struct ehci_ctrl *ctrl);
-void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg,
- uint32_t *reg);
-uint32_t *ehci_get_portsc_register(struct ehci_ctrl *ctrl, int port);
-
/**
- * ehci_set_controller_priv() - Set up private data for the controller
+ * ehci_set_controller_info() - Set up private data for the controller
*
* This function can be called in ehci_hcd_init() to tell the EHCI layer
* about the controller's private data pointer. Then in the above functions
- * this can be accessed given the struct ehci_ctrl pointer.
+ * this can be accessed given the struct ehci_ctrl pointer. Also special
+ * EHCI operation methods can be provided if required
*
* @index: Controller number to set
* @priv: Controller pointer
+ * @ops: Controller operations, or NULL to use default
*/
-void ehci_set_controller_priv(int index, void *priv);
+void ehci_set_controller_priv(int index, void *priv,
+ const struct ehci_ops *ops);
/**
* ehci_get_controller_priv() - Get controller private data