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