1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2021 Nuvoton Technology Corp. 4 */ 5 6#include <common.h> 7#include <dm.h> 8#include <generic-phy.h> 9#include <reset.h> 10#include <asm/io.h> 11#include <dm/device_compat.h> 12#include <linux/delay.h> 13#include "ehci.h" 14 15struct npcm_ehci_priv { 16 struct ehci_ctrl ctrl; 17 struct ehci_hccr *hcd; 18 struct phy phy; 19}; 20 21static int npcm_ehci_setup_phy(struct udevice *dev, struct phy *phy) 22{ 23 int ret; 24 25 if (!phy) 26 return 0; 27 28 ret = generic_phy_get_by_index(dev, 0, phy); 29 if (ret) { 30 if (ret != -ENOENT) { 31 dev_err(dev, "failed to get usb phy\n"); 32 return ret; 33 } 34 } else { 35 ret = generic_phy_init(phy); 36 if (ret) { 37 dev_err(dev, "failed to init usb phy\n"); 38 return ret; 39 } 40 } 41 42 return 0; 43} 44 45static int npcm_ehci_init(struct udevice *dev) 46{ 47 struct npcm_ehci_priv *priv = dev_get_priv(dev); 48 struct reset_ctl reset; 49 int ret; 50 51 ret = reset_get_by_index(dev, 0, &reset); 52 if (ret && ret != -ENOENT && ret != -ENOTSUPP) { 53 dev_err(dev, "failed to get reset\n"); 54 return ret; 55 } 56 57 /* reset controller */ 58 if (reset_valid(&reset)) 59 reset_assert(&reset); 60 61 /* setup phy */ 62 ret = npcm_ehci_setup_phy(dev, &priv->phy); 63 if (ret) 64 return ret; 65 66 /* release controller from reset */ 67 if (reset_valid(&reset)) 68 reset_deassert(&reset); 69 70 return 0; 71} 72 73static int npcm_ehci_probe(struct udevice *dev) 74{ 75 struct npcm_ehci_priv *priv = dev_get_priv(dev); 76 struct ehci_hcor *hcor; 77 enum usb_init_type type = dev_get_driver_data(dev); 78 int ret; 79 80 ret = npcm_ehci_init(dev); 81 if (ret) 82 return ret; 83 84 priv->hcd = (struct ehci_hccr *)dev_read_addr_ptr(dev); 85 debug("USB HCD @0x%p\n", priv->hcd); 86 hcor = (struct ehci_hcor *)((uintptr_t)priv->hcd + 87 HC_LENGTH(ehci_readl(&priv->hcd->cr_capbase))); 88 89 return ehci_register(dev, priv->hcd, hcor, NULL, 0, type); 90} 91 92static int npcm_ehci_remove(struct udevice *dev) 93{ 94 struct npcm_ehci_priv *priv = dev_get_priv(dev); 95 96 generic_phy_exit(&priv->phy); 97 98 return ehci_deregister(dev); 99} 100 101static const struct udevice_id npcm_ehci_ids[] = { 102 { .compatible = "nuvoton,npcm845-ehci", .data = USB_INIT_HOST }, 103 { .compatible = "nuvoton,npcm845-udc", .data = USB_INIT_DEVICE }, 104 { .compatible = "nuvoton,npcm750-ehci", .data = USB_INIT_HOST }, 105 { .compatible = "nuvoton,npcm750-udc", .data = USB_INIT_DEVICE }, 106 { } 107}; 108 109U_BOOT_DRIVER(ehci_npcm) = { 110 .name = "ehci_npcm", 111 .id = UCLASS_USB, 112 .of_match = npcm_ehci_ids, 113 .probe = npcm_ehci_probe, 114 .remove = npcm_ehci_remove, 115 .ops = &ehci_usb_ops, 116 .priv_auto = sizeof(struct npcm_ehci_priv), 117 .plat_auto = sizeof(struct usb_plat), 118 .flags = DM_FLAG_ALLOC_PRIV_DMA, 119}; 120