1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 Ãlvaro Fernández Rojas <noltari@gmail.com> 4 * 5 * Derived from linux/arch/mips/bcm63xx/usb-common.c: 6 * Copyright 2008 Maxime Bizon <mbizon@freebox.fr> 7 * Copyright 2013 Florian Fainelli <florian@openwrt.org> 8 */ 9 10 #include <common.h> 11 #include <clk.h> 12 #include <dm.h> 13 #include <generic-phy.h> 14 #include <power-domain.h> 15 #include <reset.h> 16 #include <asm/io.h> 17 #include <dm/device.h> 18 19 /* USBH Setup register */ 20 #define USBH_SETUP_REG 0x00 21 #define USBH_SETUP_IOC BIT(4) 22 23 /* USBH PLL Control register */ 24 #define USBH_PLL_REG 0x04 25 #define USBH_PLL_SUSP_EN BIT(27) 26 #define USBH_PLL_IDDQ_PWRDN BIT(31) 27 28 /* USBH Swap Control register */ 29 #define USBH_SWAP_REG 0x0c 30 #define USBH_SWAP_OHCI_DATA BIT(0) 31 #define USBH_SWAP_OHCI_ENDIAN BIT(1) 32 #define USBH_SWAP_EHCI_DATA BIT(3) 33 #define USBH_SWAP_EHCI_ENDIAN BIT(4) 34 35 /* USBH Sim Control register */ 36 #define USBH_SIM_REG 0x20 37 #define USBH_SIM_LADDR BIT(5) 38 39 struct bcm6318_usbh_priv { 40 void __iomem *regs; 41 }; 42 43 static int bcm6318_usbh_init(struct phy *phy) 44 { 45 struct bcm6318_usbh_priv *priv = dev_get_priv(phy->dev); 46 47 /* enable pll control susp */ 48 setbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_SUSP_EN); 49 50 /* configure to work in native cpu endian */ 51 clrsetbits_be32(priv->regs + USBH_SWAP_REG, 52 USBH_SWAP_EHCI_ENDIAN | USBH_SWAP_OHCI_ENDIAN, 53 USBH_SWAP_EHCI_DATA | USBH_SWAP_OHCI_DATA); 54 55 /* setup config */ 56 setbits_be32(priv->regs + USBH_SETUP_REG, USBH_SETUP_IOC); 57 58 /* disable pll control pwrdn */ 59 clrbits_be32(priv->regs + USBH_PLL_REG, USBH_PLL_IDDQ_PWRDN); 60 61 /* sim control config */ 62 setbits_be32(priv->regs + USBH_SIM_REG, USBH_SIM_LADDR); 63 64 return 0; 65 } 66 67 static struct phy_ops bcm6318_usbh_ops = { 68 .init = bcm6318_usbh_init, 69 }; 70 71 static const struct udevice_id bcm6318_usbh_ids[] = { 72 { .compatible = "brcm,bcm6318-usbh" }, 73 { /* sentinel */ } 74 }; 75 76 static int bcm6318_usbh_probe(struct udevice *dev) 77 { 78 struct bcm6318_usbh_priv *priv = dev_get_priv(dev); 79 struct power_domain pwr_dom; 80 struct reset_ctl rst_ctl; 81 struct clk clk; 82 fdt_addr_t addr; 83 fdt_size_t size; 84 int ret; 85 86 addr = devfdt_get_addr_size_index(dev, 0, &size); 87 if (addr == FDT_ADDR_T_NONE) 88 return -EINVAL; 89 90 priv->regs = ioremap(addr, size); 91 92 /* enable usbh clock */ 93 ret = clk_get_by_name(dev, "usbh", &clk); 94 if (ret < 0) 95 return ret; 96 97 ret = clk_enable(&clk); 98 if (ret < 0) 99 return ret; 100 101 ret = clk_free(&clk); 102 if (ret < 0) 103 return ret; 104 105 /* enable power domain */ 106 ret = power_domain_get(dev, &pwr_dom); 107 if (ret < 0) 108 return ret; 109 110 ret = power_domain_on(&pwr_dom); 111 if (ret < 0) 112 return ret; 113 114 ret = power_domain_free(&pwr_dom); 115 if (ret < 0) 116 return ret; 117 118 /* perform reset */ 119 ret = reset_get_by_index(dev, 0, &rst_ctl); 120 if (ret < 0) 121 return ret; 122 123 ret = reset_deassert(&rst_ctl); 124 if (ret < 0) 125 return ret; 126 127 ret = reset_free(&rst_ctl); 128 if (ret < 0) 129 return ret; 130 131 mdelay(100); 132 133 return 0; 134 } 135 136 U_BOOT_DRIVER(bcm6318_usbh) = { 137 .name = "bcm6318-usbh", 138 .id = UCLASS_PHY, 139 .of_match = bcm6318_usbh_ids, 140 .ops = &bcm6318_usbh_ops, 141 .priv_auto_alloc_size = sizeof(struct bcm6318_usbh_priv), 142 .probe = bcm6318_usbh_probe, 143 }; 144