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