Commit deb8508c authored by Simon Glass's avatar Simon Glass
Browse files

dm: usb: Drop the EHCI weak functions



These are a pain with driver model because we might have different EHCI
drivers which want to implement them differently. Now that they use
consistent function signatures, we can in good conscience move them to
a struct.
Signed-off-by: default avatarSimon Glass <sjg@chromium.org>
Reviewed-by: default avatarMarek Vasut <marex@denx.de>
Fix non-driver-model EHCI to set up the EHCI operations correctly:
Signed-off-by: default avatarTom Rini <trini@konsulko.com>
parent 7372b5bd
......@@ -173,7 +173,8 @@ int board_ehci_hcd_init(int port)
return 0;
}
void ehci_powerup_fixup(struct ehci_ctrl *ctrl, uint32_t *status_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);
......
......@@ -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);
}
......@@ -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;
......
......@@ -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();
......
......@@ -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:
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment