18d154002SRoman Byshko /* 27b798658SHans de Goede * Sunxi ehci glue 38d154002SRoman Byshko * 47b798658SHans de Goede * Copyright (C) 2015 Hans de Goede <hdegoede@redhat.com> 57b798658SHans de Goede * Copyright (C) 2014 Roman Byshko <rbyshko@gmail.com> 68d154002SRoman Byshko * 78d154002SRoman Byshko * Based on code from 88d154002SRoman Byshko * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 98d154002SRoman Byshko * 108d154002SRoman Byshko * SPDX-License-Identifier: GPL-2.0+ 118d154002SRoman Byshko */ 128d154002SRoman Byshko 138d154002SRoman Byshko #include <common.h> 14375de017SHans de Goede #include <asm/arch/clock.h> 152aacc423SHans de Goede #include <asm/arch/usb_phy.h> 16375de017SHans de Goede #include <asm/io.h> 17*8d837a1fSHans de Goede #include <dm.h> 188d154002SRoman Byshko #include "ehci.h" 198d154002SRoman Byshko 20*8d837a1fSHans de Goede struct ehci_sunxi_priv { 21*8d837a1fSHans de Goede struct ehci_ctrl ehci; 22*8d837a1fSHans de Goede int ahb_gate_mask; /* Mask of ahb_gate0 clk gate bits for this hcd */ 23*8d837a1fSHans de Goede int phy_index; /* Index of the usb-phy attached to this hcd */ 24*8d837a1fSHans de Goede }; 25*8d837a1fSHans de Goede 26*8d837a1fSHans de Goede static int ehci_usb_probe(struct udevice *dev) 278d154002SRoman Byshko { 28375de017SHans de Goede struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 29*8d837a1fSHans de Goede struct usb_platdata *plat = dev_get_platdata(dev); 30*8d837a1fSHans de Goede struct ehci_sunxi_priv *priv = dev_get_priv(dev); 31*8d837a1fSHans de Goede struct ehci_hccr *hccr = (struct ehci_hccr *)dev_get_addr(dev); 32*8d837a1fSHans de Goede struct ehci_hcor *hcor; 3344fd5914SHans de Goede 34*8d837a1fSHans de Goede /* 35*8d837a1fSHans de Goede * This should go away once we've moved to the driver model for 36*8d837a1fSHans de Goede * clocks resp. phys. 37*8d837a1fSHans de Goede */ 38*8d837a1fSHans de Goede if (hccr == (void *)SUNXI_USB1_BASE) { 39*8d837a1fSHans de Goede priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI0; 40*8d837a1fSHans de Goede priv->phy_index = 1; 41*8d837a1fSHans de Goede } else { 42*8d837a1fSHans de Goede priv->ahb_gate_mask = 1 << AHB_GATE_OFFSET_USB_EHCI1; 43*8d837a1fSHans de Goede priv->phy_index = 2; 44*8d837a1fSHans de Goede } 45*8d837a1fSHans de Goede 46*8d837a1fSHans de Goede setbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask); 47375de017SHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I 48*8d837a1fSHans de Goede setbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask); 49375de017SHans de Goede #endif 50375de017SHans de Goede 51*8d837a1fSHans de Goede sunxi_usb_phy_init(priv->phy_index); 52*8d837a1fSHans de Goede sunxi_usb_phy_power_on(priv->phy_index); 538d154002SRoman Byshko 54*8d837a1fSHans de Goede hcor = (struct ehci_hcor *)((uint32_t)hccr + 55*8d837a1fSHans de Goede HC_LENGTH(ehci_readl(&hccr->cr_capbase))); 568d154002SRoman Byshko 57*8d837a1fSHans de Goede return ehci_register(dev, hccr, hcor, NULL, 0, plat->init_type); 58*8d837a1fSHans de Goede } 598d154002SRoman Byshko 60*8d837a1fSHans de Goede static int ehci_usb_remove(struct udevice *dev) 61*8d837a1fSHans de Goede { 62*8d837a1fSHans de Goede struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 63*8d837a1fSHans de Goede struct ehci_sunxi_priv *priv = dev_get_priv(dev); 64*8d837a1fSHans de Goede int ret; 65*8d837a1fSHans de Goede 66*8d837a1fSHans de Goede ret = ehci_deregister(dev); 67*8d837a1fSHans de Goede if (ret) 68*8d837a1fSHans de Goede return ret; 69*8d837a1fSHans de Goede 70*8d837a1fSHans de Goede sunxi_usb_phy_power_off(priv->phy_index); 71*8d837a1fSHans de Goede sunxi_usb_phy_exit(priv->phy_index); 72*8d837a1fSHans de Goede 73*8d837a1fSHans de Goede #ifdef CONFIG_SUNXI_GEN_SUN6I 74*8d837a1fSHans de Goede clrbits_le32(&ccm->ahb_reset0_cfg, priv->ahb_gate_mask); 75*8d837a1fSHans de Goede #endif 76*8d837a1fSHans de Goede clrbits_le32(&ccm->ahb_gate0, priv->ahb_gate_mask); 778d154002SRoman Byshko 788d154002SRoman Byshko return 0; 798d154002SRoman Byshko } 808d154002SRoman Byshko 81*8d837a1fSHans de Goede static const struct udevice_id ehci_usb_ids[] = { 82*8d837a1fSHans de Goede { .compatible = "allwinner,sun4i-a10-ehci", }, 83*8d837a1fSHans de Goede { .compatible = "allwinner,sun5i-a13-ehci", }, 84*8d837a1fSHans de Goede { .compatible = "allwinner,sun6i-a31-ehci", }, 85*8d837a1fSHans de Goede { .compatible = "allwinner,sun7i-a20-ehci", }, 86*8d837a1fSHans de Goede { .compatible = "allwinner,sun8i-a23-ehci", }, 87*8d837a1fSHans de Goede { .compatible = "allwinner,sun9i-a80-ehci", }, 88*8d837a1fSHans de Goede { } 89*8d837a1fSHans de Goede }; 90375de017SHans de Goede 91*8d837a1fSHans de Goede U_BOOT_DRIVER(usb_ehci) = { 92*8d837a1fSHans de Goede .name = "ehci_sunxi", 93*8d837a1fSHans de Goede .id = UCLASS_USB, 94*8d837a1fSHans de Goede .of_match = ehci_usb_ids, 95*8d837a1fSHans de Goede .probe = ehci_usb_probe, 96*8d837a1fSHans de Goede .remove = ehci_usb_remove, 97*8d837a1fSHans de Goede .ops = &ehci_usb_ops, 98*8d837a1fSHans de Goede .platdata_auto_alloc_size = sizeof(struct usb_platdata), 99*8d837a1fSHans de Goede .priv_auto_alloc_size = sizeof(struct ehci_sunxi_priv), 100*8d837a1fSHans de Goede .flags = DM_FLAG_ALLOC_PRIV_DMA, 101*8d837a1fSHans de Goede }; 102