xref: /openbmc/u-boot/drivers/usb/host/ehci-aspeed.c (revision 0d1d4e81)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) ASPEED Technology Inc.
4  * Ryan Chen <ryan_chen@aspeedtech.com>
5  */
6 
7 #include <common.h>
8 #include <clk.h>
9 #include <dm.h>
10 #include <usb.h>
11 #include <asm/io.h>
12 
13 #include "ehci.h"
14 
15 struct ehci_aspeed_priv {
16 	struct ehci_ctrl ehci;
17 };
18 
19 static void aspeed_ehci_powerup_fixup(struct ehci_ctrl *ctrl,
20 				     uint32_t *status_reg, uint32_t *reg)
21 {
22 	mdelay(50);
23 	/* This is to avoid PORT_ENABLE bit to be cleared in "ehci-hcd.c". */
24 	*reg |= EHCI_PS_PE;
25 
26 	/* For EHCI_PS_CSC to be cleared in ehci_hcd.c */
27 	if (ehci_readl(status_reg) & EHCI_PS_CSC)
28 		*reg |= EHCI_PS_CSC;
29 }
30 
31 static const struct ehci_ops aspeed_ehci_ops = {
32 	.powerup_fixup		= aspeed_ehci_powerup_fixup,
33 };
34 
35 static int ehci_aspeed_probe(struct udevice *dev)
36 {
37 	struct ehci_hccr *hccr;
38 	struct ehci_hcor *hcor;
39 	fdt_addr_t hcd_base;
40 	struct clk clk;
41 	int ret;
42 
43 	ret = clk_get_by_index(dev, 0, &clk);
44 	if (ret)
45 		return ret;
46 
47 	ret = clk_enable(&clk);
48 	if (ret)
49 		return ret;
50 
51 	/*
52 	* Get the base address for EHCI controller from the device node
53 	*/
54 	hcd_base = devfdt_get_addr(dev);
55 	if (hcd_base == FDT_ADDR_T_NONE) {
56 		debug("Can't get the EHCI register base address\n");
57 		return -ENXIO;
58 	}
59 
60 	hccr = (struct ehci_hccr *)hcd_base;
61 	hcor = (struct ehci_hcor *)
62 	((u32)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
63 
64 	debug("echi-aspeed: init hccr %x and hcor %x hc_length %d\n",
65 	(u32)hccr, (u32)hcor,
66 	(u32)HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
67 
68 	return ehci_register(dev, hccr, hcor, &aspeed_ehci_ops, 0, USB_INIT_HOST);
69 }
70 
71 static const struct udevice_id ehci_usb_ids[] = {
72 	{ .compatible = "aspeed,aspeed-ehci", },
73 	{ }
74 };
75 
76 U_BOOT_DRIVER(ehci_aspeed) = {
77 	.name           = "ehci_aspeed",
78 	.id             = UCLASS_USB,
79 	.of_match       = ehci_usb_ids,
80 	.probe          = ehci_aspeed_probe,
81 	.remove         = ehci_deregister,
82 	.ops            = &ehci_usb_ops,
83 	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
84 	.priv_auto_alloc_size = sizeof(struct ehci_aspeed_priv),
85 	.flags          = DM_FLAG_ALLOC_PRIV_DMA,
86 };
87