1 /* 2 * Sunxi ehci glue 3 * 4 * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com> 5 * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com> 6 * 7 * Based on code from 8 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 13 #include <common.h> 14 #include <asm/arch/clock.h> 15 #include <asm/arch/usb_phy.h> 16 #include <asm/io.h> 17 #include <dm.h> 18 #include "ehci.h" 19 20 struct ehci_sunxi_priv { 21 struct ehci_ctrl ehci; 22 int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ 23 int phy_index; /* Index of the usb-phy attached to this hcd */ 24 }; 25 26 static int ehci_usb_probe(struct udevice *dev) 27 { 28 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 29 struct usb_platdata *plat = dev_get_platdata(dev); 30 struct ehci_sunxi_priv *priv = dev_get_priv(dev); 31 struct ehci_hccr *hccr = (struct ehci_hccr *)dev_get_addr(dev); 32 struct ehci_hcor *hcor; 33 34 /* 35 * This should go away once we've moved to the driver model for 36 * clocks resp. phys. 37 */ 38 priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0; 39 #ifdef CONFIG_MACH_SUN8I_H3 40 priv->ahb_gate_mask |= 1 << AHB_GATE_OFFSET_USB_OHCI0; 41 #endif 42 priv->phy_index = ((u32)hccr - SUNXI_USB1_BASE) / 0x1000 + 1; 43 priv->ahb_gate_mask <<= priv->phy_index - 1; 44 45 setbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask); 46 #ifdef CONFIG_SUNXI_GEN_SUN6I 47 setbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask); 48 #endif 49 50 sunxi_usb_phy_init(priv->phy_index); 51 sunxi_usb_phy_power_on(priv->phy_index); 52 53 hcor = (struct ehci_hcor *)((uint32_t)hccr + 54 HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 55 56 return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type); 57 } 58 59 static int ehci_usb_remove(struct udevice *dev) 60 { 61 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 62 struct ehci_sunxi_priv *priv = dev_get_priv(dev); 63 int ret; 64 65 ret = ehci_deregister(dev); 66 if (ret) 67 return ret; 68 69 sunxi_usb_phy_exit(priv->phy_index); 70 71 #ifdef CONFIG_SUNXI_GEN_SUN6I 72 clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask); 73 #endif 74 clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask); 75 76 return 0; 77 } 78 79 static const struct udevice_id ehci_usb_ids[] = { 80 { .compatible = "allwinner,sun4i-a10-ehci", }, 81 { .compatible = "allwinner,sun5i-a13-ehci", }, 82 { .compatible = "allwinner,sun6i-a31-ehci", }, 83 { .compatible = "allwinner,sun7i-a20-ehci", }, 84 { .compatible = "allwinner,sun8i-a23-ehci", }, 85 { .compatible = "allwinner,sun8i-h3-ehci", }, 86 { .compatible = "allwinner,sun9i-a80-ehci", }, 87 { } 88 }; 89 90 U_BOOT_DRIVER(ehci_sunxi) = { 91 .name = "ehci_sunxi", 92 .id = UCLASS_USB, 93 .of_match = ehci_usb_ids, 94 .probe = ehci_usb_probe, 95 .remove = ehci_usb_remove, 96 .ops = &ehci_usb_ops, 97 .platdata_auto_alloc_size = sizeof(struct usb_platdata), 98 .priv_auto_alloc_size = sizeof(struct ehci_sunxi_priv), 99 .flags = DM_FLAG_ALLOC_PRIV_DMA, 100 }; 101