mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-09-20 05:11:30 +02:00
When bringing in the series 'arm: dts: am62-beagleplay: Fix Beagleplay Ethernet"' I failed to notice that b4 noticed it was based on next and so took that as the base commit and merged that part of next to master. This reverts commit c8ffd1356d42223cbb8c86280a083cc3c93e6426, reversing changes made to 2ee6f3a5f7550de3599faef9704e166e5dcace35. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
171 lines
3.7 KiB
C
171 lines
3.7 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Qualcomm EHCI driver
|
|
*
|
|
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
|
|
*
|
|
* Based on Linux driver
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <dm/lists.h>
|
|
#include <errno.h>
|
|
#include <usb.h>
|
|
#include <usb/ehci-ci.h>
|
|
#include <usb/ulpi.h>
|
|
#include <wait_bit.h>
|
|
#include <asm/gpio.h>
|
|
#include <asm/io.h>
|
|
#include <linux/compat.h>
|
|
#include "ehci.h"
|
|
|
|
struct msm_ehci_priv {
|
|
struct ehci_ctrl ctrl; /* Needed by EHCI */
|
|
struct usb_ehci *ehci; /* Start of IP core*/
|
|
struct ulpi_viewport ulpi_vp; /* ULPI Viewport */
|
|
struct phy phy;
|
|
};
|
|
|
|
static int msm_init_after_reset(struct ehci_ctrl *dev)
|
|
{
|
|
struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl);
|
|
struct usb_ehci *ehci = p->ehci;
|
|
|
|
generic_phy_reset(&p->phy);
|
|
|
|
/* set mode to host controller */
|
|
writel(CM_HOST, &ehci->usbmode);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct ehci_ops msm_ehci_ops = {
|
|
.init_after_reset = msm_init_after_reset
|
|
};
|
|
|
|
static int ehci_usb_probe(struct udevice *dev)
|
|
{
|
|
struct msm_ehci_priv *p = dev_get_priv(dev);
|
|
struct usb_ehci *ehci = p->ehci;
|
|
struct usb_plat *plat = dev_get_plat(dev);
|
|
struct ehci_hccr *hccr;
|
|
struct ehci_hcor *hcor;
|
|
int ret;
|
|
|
|
hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength);
|
|
hcor = (struct ehci_hcor *)((phys_addr_t)hccr +
|
|
HC_LENGTH(ehci_readl(&(hccr)->cr_capbase)));
|
|
|
|
ret = generic_setup_phy(dev, &p->phy, 0);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = board_usb_init(0, plat->init_type);
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0,
|
|
plat->init_type);
|
|
}
|
|
|
|
static int ehci_usb_remove(struct udevice *dev)
|
|
{
|
|
struct msm_ehci_priv *p = dev_get_priv(dev);
|
|
struct usb_ehci *ehci = p->ehci;
|
|
int ret;
|
|
|
|
ret = ehci_deregister(dev);
|
|
if (ret)
|
|
return ret;
|
|
|
|
/* Stop controller. */
|
|
clrbits_le32(&ehci->usbcmd, CMD_RUN);
|
|
|
|
ret = generic_shutdown_phy(&p->phy);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = board_usb_init(0, USB_INIT_DEVICE); /* Board specific hook */
|
|
if (ret < 0)
|
|
return ret;
|
|
|
|
/* Reset controller */
|
|
setbits_le32(&ehci->usbcmd, CMD_RESET);
|
|
|
|
/* Wait for reset */
|
|
if (wait_for_bit_le32(&ehci->usbcmd, CMD_RESET, false, 30, false)) {
|
|
printf("Stuck on USB reset.\n");
|
|
return -ETIMEDOUT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ehci_usb_of_to_plat(struct udevice *dev)
|
|
{
|
|
struct msm_ehci_priv *priv = dev_get_priv(dev);
|
|
|
|
priv->ulpi_vp.port_num = 0;
|
|
priv->ehci = dev_read_addr_ptr(dev);
|
|
|
|
if (priv->ehci == (void *)FDT_ADDR_T_NONE)
|
|
return -EINVAL;
|
|
|
|
/* Warning: this will not work if viewport address is > 64 bit due to
|
|
* ULPI design.
|
|
*/
|
|
priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ehci_usb_of_bind(struct udevice *dev)
|
|
{
|
|
ofnode ulpi_node = ofnode_first_subnode(dev_ofnode(dev));
|
|
ofnode phy_node;
|
|
|
|
if (!ofnode_valid(ulpi_node))
|
|
return 0;
|
|
|
|
phy_node = ofnode_first_subnode(ulpi_node);
|
|
if (!ofnode_valid(phy_node)) {
|
|
printf("%s: ulpi subnode with no phy\n", __func__);
|
|
return -ENOENT;
|
|
}
|
|
|
|
return device_bind_driver_to_node(dev, "msm8916_usbphy", "msm8916_usbphy",
|
|
phy_node, NULL);
|
|
}
|
|
|
|
#if defined(CONFIG_CI_UDC)
|
|
/* Little quirk that MSM needs with Chipidea controller
|
|
* Must reinit phy after reset
|
|
*/
|
|
void ci_init_after_reset(struct ehci_ctrl *ctrl)
|
|
{
|
|
struct msm_ehci_priv *p = ctrl->priv;
|
|
|
|
generic_phy_reset(&p->phy);
|
|
}
|
|
#endif
|
|
|
|
static const struct udevice_id ehci_usb_ids[] = {
|
|
{ .compatible = "qcom,ci-hdrc", },
|
|
{ }
|
|
};
|
|
|
|
U_BOOT_DRIVER(usb_ehci) = {
|
|
.name = "ehci_msm",
|
|
.id = UCLASS_USB,
|
|
.of_match = ehci_usb_ids,
|
|
.of_to_plat = ehci_usb_of_to_plat,
|
|
.bind = ehci_usb_of_bind,
|
|
.probe = ehci_usb_probe,
|
|
.remove = ehci_usb_remove,
|
|
.ops = &ehci_usb_ops,
|
|
.priv_auto = sizeof(struct msm_ehci_priv),
|
|
.plat_auto = sizeof(struct usb_plat),
|
|
.flags = DM_FLAG_ALLOC_PRIV_DMA,
|
|
};
|