diff --git a/board/genesi/mx51_efikamx/efikamx-usb.c b/board/genesi/mx51_efikamx/efikamx-usb.c index 0c0b8d3181..9dfd24961a 100644 --- a/board/genesi/mx51_efikamx/efikamx-usb.c +++ b/board/genesi/mx51_efikamx/efikamx-usb.c @@ -173,8 +173,9 @@ int board_ehci_hcd_init(int port) return 0; } -void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, - uint32_t *reg) +/* This overrides a weak function */ +void mx5_ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_reg, + uint32_t *reg) { uint32_t port = OTG_BASE_ADDR + (0x200 * CONFIG_MXC_USB_PORT); struct usb_ehci *ehci = (struct usb_ehci *)port; diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c index b865fea3eb..821222cc5d 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(®s->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(®s->otg.otgcsr)); + else + spd = BMCSR_SPD(readl(®s->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 *)®s->usb.hccr; hcor = (struct ehci_hcor *)®s->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(®s->otg.otgcsr)); - else - spd = BMCSR_SPD(readl(®s->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 9a9ec01d9f..c6696aab50 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, ®); + ctrl->ops.powerup_fixup(ctrl, status_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) { - ehcic[index].priv = priv; + 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) +{ + 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 7566c61284..d3199622eb 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 0e6b60e0d6..9e380c309e 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 2ca111a300..cc23e1fe93 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