blob: b6c6aaf78ec5882c406425119907ff1d29bbebfa [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Stefan Roese81c1f6f2016-07-14 11:39:20 +02002/*
3 * Copyright (C) 2015 Marvell International Ltd.
4 *
5 * MVEBU USB HOST xHCI Controller
Stefan Roese81c1f6f2016-07-14 11:39:20 +02006 */
7
8#include <common.h>
9#include <dm.h>
10#include <fdtdec.h>
11#include <usb.h>
Konstantin Porotchkin81192b72017-02-12 11:10:30 +020012#include <power/regulator.h>
Stefan Roese81c1f6f2016-07-14 11:39:20 +020013#include <asm/gpio.h>
14
15#include "xhci.h"
16
Stefan Roese81c1f6f2016-07-14 11:39:20 +020017struct mvebu_xhci_platdata {
18 fdt_addr_t hcd_base;
19};
20
21/**
22 * Contains pointers to register base addresses
23 * for the usb controller.
24 */
25struct mvebu_xhci {
26 struct xhci_ctrl ctrl; /* Needs to come first in this struct! */
27 struct usb_platdata usb_plat;
28 struct xhci_hccr *hcd;
29};
30
31/*
32 * Dummy implementation that can be overwritten by a board
33 * specific function
34 */
Jon Nettletond3d036a2017-11-06 10:33:19 +020035__weak int board_xhci_enable(fdt_addr_t base)
Stefan Roese81c1f6f2016-07-14 11:39:20 +020036{
37 return 0;
38}
39
40static int xhci_usb_probe(struct udevice *dev)
41{
42 struct mvebu_xhci_platdata *plat = dev_get_platdata(dev);
43 struct mvebu_xhci *ctx = dev_get_priv(dev);
44 struct xhci_hcor *hcor;
Konstantin Porotchkin81192b72017-02-12 11:10:30 +020045 int len, ret;
46 struct udevice *regulator;
Stefan Roese81c1f6f2016-07-14 11:39:20 +020047
48 ctx->hcd = (struct xhci_hccr *)plat->hcd_base;
49 len = HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase));
50 hcor = (struct xhci_hcor *)((uintptr_t)ctx->hcd + len);
51
Konstantin Porotchkin81192b72017-02-12 11:10:30 +020052 ret = device_get_supply_regulator(dev, "vbus-supply", &regulator);
53 if (!ret) {
54 ret = regulator_set_enable(regulator, true);
55 if (ret) {
56 printf("Failed to turn ON the VBUS regulator\n");
57 return ret;
58 }
59 }
60
Stefan Roese81c1f6f2016-07-14 11:39:20 +020061 /* Enable USB xHCI (VBUS, reset etc) in board specific code */
Jon Nettletond3d036a2017-11-06 10:33:19 +020062 board_xhci_enable(devfdt_get_addr_index(dev, 1));
Stefan Roese81c1f6f2016-07-14 11:39:20 +020063
64 return xhci_register(dev, ctx->hcd, hcor);
65}
66
Stefan Roese81c1f6f2016-07-14 11:39:20 +020067static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
68{
69 struct mvebu_xhci_platdata *plat = dev_get_platdata(dev);
70
71 /*
72 * Get the base address for XHCI controller from the device node
73 */
Simon Glassa821c4a2017-05-17 17:18:05 -060074 plat->hcd_base = devfdt_get_addr(dev);
Stefan Roese81c1f6f2016-07-14 11:39:20 +020075 if (plat->hcd_base == FDT_ADDR_T_NONE) {
76 debug("Can't get the XHCI register base address\n");
77 return -ENXIO;
78 }
79
80 return 0;
81}
82
83static const struct udevice_id xhci_usb_ids[] = {
84 { .compatible = "marvell,armada3700-xhci" },
Jon Nettletond3d036a2017-11-06 10:33:19 +020085 { .compatible = "marvell,armada-380-xhci" },
Stefan Roesed36277e2016-08-31 06:48:56 +020086 { .compatible = "marvell,armada-8k-xhci" },
Stefan Roese81c1f6f2016-07-14 11:39:20 +020087 { }
88};
89
90U_BOOT_DRIVER(usb_xhci) = {
91 .name = "xhci_mvebu",
92 .id = UCLASS_USB,
93 .of_match = xhci_usb_ids,
94 .ofdata_to_platdata = xhci_usb_ofdata_to_platdata,
95 .probe = xhci_usb_probe,
Masahiro Yamada9eea45f2016-10-14 10:30:01 +090096 .remove = xhci_deregister,
Stefan Roese81c1f6f2016-07-14 11:39:20 +020097 .ops = &xhci_usb_ops,
98 .platdata_auto_alloc_size = sizeof(struct mvebu_xhci_platdata),
99 .priv_auto_alloc_size = sizeof(struct mvebu_xhci),
100 .flags = DM_FLAG_ALLOC_PRIV_DMA,
101};