1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (c) 2021 Nuvoton Technology Corp. 4 */ 5 6#include <dm.h> 7#include <generic-phy.h> 8#include <regmap.h> 9#include <reset.h> 10#include <syscon.h> 11#include <dm/device_compat.h> 12#include <linux/bitfield.h> 13#include <linux/delay.h> 14 15/* GCR Register Offsets */ 16#define GCR_INTCR3 0x9C 17#define GCR_USB1PHYCTL 0x140 18#define GCR_USB2PHYCTL 0x144 19#define GCR_USB3PHYCTL 0x148 20 21/* USBnPHYCTL bit fields */ 22#define PHYCTL_RS BIT(28) 23 24#define USBPHY2SW GENMASK(13, 12) 25#define USBPHY3SW GENMASK(15, 14) 26 27#define USBPHY2SW_DEV9_PHY1 FIELD_PREP(USBPHY2SW, 0) 28#define USBPHY2SW_HOST1 FIELD_PREP(USBPHY2SW, 1) 29#define USBPHY2SW_DEV9_PHY2 FIELD_PREP(USBPHY2SW, 3) 30#define USBPHY3SW_DEV8_PHY1 FIELD_PREP(USBPHY3SW, 0) 31#define USBPHY3SW_HOST2 FIELD_PREP(USBPHY3SW, 1) 32#define USBPHY3SW_DEV8_PHY3 FIELD_PREP(USBPHY3SW, 3) 33 34enum controller_id { 35 UDC0_7, 36 UDC8, 37 UDC9, 38 USBH1, 39 USBH2, 40}; 41 42enum phy_id { 43 PHY1 = 1, 44 PHY2, 45 PHY3, 46}; 47 48/* Phy Switch Settings */ 49#define USBDPHY1 ((PHY1 << 8) | UDC0_7) /* Connect UDC0~7 to PHY1 */ 50#define USBD8PHY1 ((PHY1 << 8) | UDC8) /* Connect UDC8 to PHY1 */ 51#define USBD9PHY1 ((PHY1 << 8) | UDC9) /* Connect UDC9 to PHY1 */ 52#define USBD9PHY2 ((PHY2 << 8) | UDC9) /* Connect UDC9 to PHY2 */ 53#define USBH1PHY2 ((PHY2 << 8) | USBH1) /* Connect USBH1 to PHY2 */ 54#define USBD8PHY3 ((PHY3 << 8) | UDC8) /* Connect UDC8 to PHY3 */ 55#define USBH2PHY3 ((PHY3 << 8) | USBH2) /* Connect USBH2 to PHY3 */ 56 57struct npcm_usbphy { 58 struct regmap *syscon; 59 u8 id; 60 u16 phy_switch; /* (phy_id << 8) | controller_id */ 61}; 62 63static int npcm_usb_phy_init(struct phy *phy) 64{ 65 struct npcm_usbphy *priv = dev_get_priv(phy->dev); 66 struct reset_ctl reset; 67 int ret; 68 69 ret = reset_get_by_index(phy->dev, 0, &reset); 70 if (ret && ret != -ENOENT && ret != -ENOTSUPP) { 71 dev_err(phy->dev, "can't get phy reset ctrl (err %d)", ret); 72 return ret; 73 } 74 75 /* setup PHY switch */ 76 switch (priv->phy_switch) { 77 case USBD8PHY1: 78 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW, 79 USBPHY3SW_DEV8_PHY1); 80 break; 81 case USBD8PHY3: 82 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW, 83 USBPHY3SW_DEV8_PHY3); 84 break; 85 case USBD9PHY1: 86 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW, 87 USBPHY2SW_DEV9_PHY1); 88 break; 89 case USBD9PHY2: 90 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW, 91 USBPHY2SW_DEV9_PHY2); 92 break; 93 case USBH1PHY2: 94 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW, 95 USBPHY2SW_HOST1); 96 break; 97 case USBH2PHY3: 98 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW, 99 USBPHY3SW_HOST2); 100 break; 101 default: 102 break; 103 } 104 /* reset phy */ 105 if (reset_valid(&reset)) 106 reset_assert(&reset); 107 108 /* Wait for PHY clocks to stablize for 50us or more */ 109 udelay(100); 110 111 /* release phy from reset */ 112 if (reset_valid(&reset)) 113 reset_deassert(&reset); 114 115 /* PHY RS bit should be set after reset */ 116 switch (priv->id) { 117 case PHY1: 118 regmap_update_bits(priv->syscon, GCR_USB1PHYCTL, PHYCTL_RS, PHYCTL_RS); 119 break; 120 case PHY2: 121 regmap_update_bits(priv->syscon, GCR_USB2PHYCTL, PHYCTL_RS, PHYCTL_RS); 122 break; 123 case PHY3: 124 regmap_update_bits(priv->syscon, GCR_USB3PHYCTL, PHYCTL_RS, PHYCTL_RS); 125 break; 126 default: 127 break; 128 } 129 130 return 0; 131} 132 133static int npcm_usb_phy_exit(struct phy *phy) 134{ 135 struct npcm_usbphy *priv = dev_get_priv(phy->dev); 136 137 /* set PHY switch to default state */ 138 switch (priv->phy_switch) { 139 case USBD8PHY1: 140 case USBD8PHY3: 141 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY3SW, 142 USBPHY3SW_HOST2); 143 break; 144 case USBD9PHY1: 145 case USBD9PHY2: 146 regmap_update_bits(priv->syscon, GCR_INTCR3, USBPHY2SW, 147 USBPHY2SW_HOST1); 148 break; 149 default: 150 break; 151 } 152 return 0; 153} 154 155static int npcm_usb_phy_xlate(struct phy *phy, struct ofnode_phandle_args *args) 156{ 157 struct npcm_usbphy *priv = dev_get_priv(phy->dev); 158 u16 phy_switch; 159 160 if (args->args_count < 1 || args->args[0] > USBH2) 161 return -EINVAL; 162 163 phy_switch = (priv->id << 8) | args->args[0]; 164 switch (phy_switch) { 165 case USBD9PHY1: 166 case USBH2PHY3: 167 case USBD8PHY3: 168 if (!IS_ENABLED(CONFIG_ARCH_NPCM8XX)) 169 return -EINVAL; 170 case USBDPHY1: 171 case USBD8PHY1: 172 case USBD9PHY2: 173 case USBH1PHY2: 174 priv->phy_switch = phy_switch; 175 return 0; 176 default: 177 return -EINVAL; 178 } 179} 180 181static int npcm_usb_phy_probe(struct udevice *dev) 182{ 183 struct npcm_usbphy *priv = dev_get_priv(dev); 184 185 priv->syscon = syscon_regmap_lookup_by_phandle(dev->parent, "syscon"); 186 if (IS_ERR(priv->syscon)) { 187 dev_err(dev, "%s: unable to get syscon\n", __func__); 188 return PTR_ERR(priv->syscon); 189 } 190 priv->id = dev_read_u32_default(dev, "reg", -1); 191 192 return 0; 193} 194 195static const struct udevice_id npcm_phy_ids[] = { 196 { .compatible = "nuvoton,npcm845-usb-phy",}, 197 { .compatible = "nuvoton,npcm750-usb-phy",}, 198 { } 199}; 200 201static struct phy_ops npcm_phy_ops = { 202 .init = npcm_usb_phy_init, 203 .exit = npcm_usb_phy_exit, 204 .of_xlate = npcm_usb_phy_xlate, 205}; 206 207U_BOOT_DRIVER(npcm_phy) = { 208 .name = "npcm-usb-phy", 209 .id = UCLASS_PHY, 210 .of_match = npcm_phy_ids, 211 .ops = &npcm_phy_ops, 212 .probe = npcm_usb_phy_probe, 213 .priv_auto = sizeof(struct npcm_usbphy), 214}; 215