181c1f6f0SStefan Roese /*
281c1f6f0SStefan Roese * Copyright (C) 2015 Marvell International Ltd.
381c1f6f0SStefan Roese *
481c1f6f0SStefan Roese * MVEBU USB HOST xHCI Controller
581c1f6f0SStefan Roese *
681c1f6f0SStefan Roese * SPDX-License-Identifier: GPL-2.0+
781c1f6f0SStefan Roese */
881c1f6f0SStefan Roese
981c1f6f0SStefan Roese #include <common.h>
1081c1f6f0SStefan Roese #include <dm.h>
1181c1f6f0SStefan Roese #include <fdtdec.h>
1281c1f6f0SStefan Roese #include <usb.h>
1381192b79SKonstantin Porotchkin #include <power/regulator.h>
1481c1f6f0SStefan Roese #include <asm/gpio.h>
1581c1f6f0SStefan Roese
16*143fc13bSJean-Jacques Hiblot #include <usb/xhci.h>
1781c1f6f0SStefan Roese
1881c1f6f0SStefan Roese DECLARE_GLOBAL_DATA_PTR;
1981c1f6f0SStefan Roese
2081c1f6f0SStefan Roese struct mvebu_xhci_platdata {
2181c1f6f0SStefan Roese fdt_addr_t hcd_base;
2281c1f6f0SStefan Roese };
2381c1f6f0SStefan Roese
2481c1f6f0SStefan Roese /**
2581c1f6f0SStefan Roese * Contains pointers to register base addresses
2681c1f6f0SStefan Roese * for the usb controller.
2781c1f6f0SStefan Roese */
2881c1f6f0SStefan Roese struct mvebu_xhci {
2981c1f6f0SStefan Roese struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
3081c1f6f0SStefan Roese struct usb_platdata usb_plat;
3181c1f6f0SStefan Roese struct xhci_hccr *hcd;
3281c1f6f0SStefan Roese };
3381c1f6f0SStefan Roese
3481c1f6f0SStefan Roese /*
3581c1f6f0SStefan Roese * Dummy implementation that can be overwritten by a board
3681c1f6f0SStefan Roese * specific function
3781c1f6f0SStefan Roese */
board_xhci_enable(fdt_addr_t base)380e266cadSJon Nettleton __weak int board_xhci_enable(fdt_addr_t base)
3981c1f6f0SStefan Roese {
4081c1f6f0SStefan Roese return 0;
4181c1f6f0SStefan Roese }
4281c1f6f0SStefan Roese
xhci_usb_probe(struct udevice * dev)4381c1f6f0SStefan Roese static int xhci_usb_probe(struct udevice *dev)
4481c1f6f0SStefan Roese {
4581c1f6f0SStefan Roese struct mvebu_xhci_platdata *plat = dev_get_platdata(dev);
4681c1f6f0SStefan Roese struct mvebu_xhci *ctx = dev_get_priv(dev);
4781c1f6f0SStefan Roese struct xhci_hcor *hcor;
4881192b79SKonstantin Porotchkin int len, ret;
4981192b79SKonstantin Porotchkin struct udevice *regulator;
5081c1f6f0SStefan Roese
5181c1f6f0SStefan Roese ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
5281c1f6f0SStefan Roese len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
5381c1f6f0SStefan Roese hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
5481c1f6f0SStefan Roese
5581192b79SKonstantin Porotchkin ret = device_get_supply_regulator(dev, "vbus-supply", ®ulator);
5681192b79SKonstantin Porotchkin if (!ret) {
5781192b79SKonstantin Porotchkin ret = regulator_set_enable(regulator, true);
5881192b79SKonstantin Porotchkin if (ret) {
5981192b79SKonstantin Porotchkin printf("Failed to turn ON the VBUS regulator\n");
6081192b79SKonstantin Porotchkin return ret;
6181192b79SKonstantin Porotchkin }
6281192b79SKonstantin Porotchkin }
6381192b79SKonstantin Porotchkin
6481c1f6f0SStefan Roese /* Enable USB xHCI (VBUS, reset etc) in board specific code */
650e266cadSJon Nettleton board_xhci_enable(devfdt_get_addr_index(dev, 1));
6681c1f6f0SStefan Roese
6781c1f6f0SStefan Roese return xhci_register(dev, ctx->hcd, hcor);
6881c1f6f0SStefan Roese }
6981c1f6f0SStefan Roese
xhci_usb_ofdata_to_platdata(struct udevice * dev)7081c1f6f0SStefan Roese static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
7181c1f6f0SStefan Roese {
7281c1f6f0SStefan Roese struct mvebu_xhci_platdata *plat = dev_get_platdata(dev);
7381c1f6f0SStefan Roese
7481c1f6f0SStefan Roese /*
7581c1f6f0SStefan Roese * Get the base address for XHCI controller from the device node
7681c1f6f0SStefan Roese */
77a821c4afSSimon Glass plat->hcd_base = devfdt_get_addr(dev);
7881c1f6f0SStefan Roese if (plat->hcd_base == FDT_ADDR_T_NONE) {
7981c1f6f0SStefan Roese debug("Can't get the XHCI register base address\n");
8081c1f6f0SStefan Roese return -ENXIO;
8181c1f6f0SStefan Roese }
8281c1f6f0SStefan Roese
8381c1f6f0SStefan Roese return 0;
8481c1f6f0SStefan Roese }
8581c1f6f0SStefan Roese
8681c1f6f0SStefan Roese static const struct udevice_id xhci_usb_ids[] = {
8781c1f6f0SStefan Roese { .compatible = "marvell,armada3700-xhci" },
880e266cadSJon Nettleton { .compatible = "marvell,armada-380-xhci" },
89d36277efSStefan Roese { .compatible = "marvell,armada-8k-xhci" },
9081c1f6f0SStefan Roese { }
9181c1f6f0SStefan Roese };
9281c1f6f0SStefan Roese
9381c1f6f0SStefan Roese U_BOOT_DRIVER(usb_xhci) = {
9481c1f6f0SStefan Roese .name = "xhci_mvebu",
9581c1f6f0SStefan Roese .id = UCLASS_USB,
9681c1f6f0SStefan Roese .of_match = xhci_usb_ids,
9781c1f6f0SStefan Roese .ofdata_to_platdata = xhci_usb_ofdata_to_platdata,
9881c1f6f0SStefan Roese .probe = xhci_usb_probe,
999eea45f5SMasahiro Yamada .remove = xhci_deregister,
10081c1f6f0SStefan Roese .ops = &xhci_usb_ops,
10181c1f6f0SStefan Roese .platdata_auto_alloc_size = sizeof(struct mvebu_xhci_platdata),
10281c1f6f0SStefan Roese .priv_auto_alloc_size = sizeof(struct mvebu_xhci),
10381c1f6f0SStefan Roese .flags = DM_FLAG_ALLOC_PRIV_DMA,
10481c1f6f0SStefan Roese };
105