xref: /openbmc/u-boot/drivers/usb/host/xhci-mvebu.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
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", &regulator);
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