xref: /rk3399_rockchip-uboot/drivers/usb/host/xhci-mvebu.c (revision 1a4f6af8bfd44c8ae6e87a81ff125eed47042cc5)
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", &regulator);
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