1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * drd.c - DesignWare USB2 DRD Controller Dual-role support 4 * 5 * Copyright (C) 2020 STMicroelectronics 6 * 7 * Author(s): Amelie Delaunay <amelie.delaunay@st.com> 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/iopoll.h> 12 #include <linux/platform_device.h> 13 #include <linux/usb/role.h> 14 #include "core.h" 15 16 #define dwc2_ovr_gotgctl(gotgctl) \ 17 ((gotgctl) |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN | \ 18 GOTGCTL_DBNCE_FLTR_BYPASS) 19 20 static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) 21 { 22 unsigned long flags; 23 u32 gotgctl; 24 25 spin_lock_irqsave(&hsotg->lock, flags); 26 27 gotgctl = dwc2_readl(hsotg, GOTGCTL); 28 dwc2_ovr_gotgctl(gotgctl); 29 gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); 30 if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) 31 gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; 32 else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) 33 gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; 34 dwc2_writel(hsotg, gotgctl, GOTGCTL); 35 36 spin_unlock_irqrestore(&hsotg->lock, flags); 37 38 dwc2_force_mode(hsotg, (hsotg->dr_mode == USB_DR_MODE_HOST)); 39 } 40 41 static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) 42 { 43 u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 44 45 /* Check if A-Session is already in the right state */ 46 if ((valid && (gotgctl & GOTGCTL_ASESVLD)) || 47 (!valid && !(gotgctl & GOTGCTL_ASESVLD))) 48 return -EALREADY; 49 50 /* Always enable overrides to handle the resume case */ 51 dwc2_ovr_gotgctl(gotgctl); 52 53 gotgctl &= ~GOTGCTL_BVALOVAL; 54 if (valid) 55 gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; 56 else 57 gotgctl &= ~(GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); 58 dwc2_writel(hsotg, gotgctl, GOTGCTL); 59 60 return 0; 61 } 62 63 static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) 64 { 65 u32 gotgctl = dwc2_readl(hsotg, GOTGCTL); 66 67 /* Check if B-Session is already in the right state */ 68 if ((valid && (gotgctl & GOTGCTL_BSESVLD)) || 69 (!valid && !(gotgctl & GOTGCTL_BSESVLD))) 70 return -EALREADY; 71 72 /* Always enable overrides to handle the resume case */ 73 dwc2_ovr_gotgctl(gotgctl); 74 75 gotgctl &= ~GOTGCTL_AVALOVAL; 76 if (valid) 77 gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; 78 else 79 gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL); 80 dwc2_writel(hsotg, gotgctl, GOTGCTL); 81 82 return 0; 83 } 84 85 static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) 86 { 87 struct dwc2_hsotg *hsotg = usb_role_switch_get_drvdata(sw); 88 unsigned long flags; 89 int already = 0; 90 91 /* Skip session not in line with dr_mode */ 92 if ((role == USB_ROLE_DEVICE && hsotg->dr_mode == USB_DR_MODE_HOST) || 93 (role == USB_ROLE_HOST && hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)) 94 return -EINVAL; 95 96 #if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ 97 IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) 98 /* Skip session if core is in test mode */ 99 if (role == USB_ROLE_NONE && hsotg->test_mode) { 100 dev_dbg(hsotg->dev, "Core is in test mode\n"); 101 return -EBUSY; 102 } 103 #endif 104 105 /* 106 * In case of USB_DR_MODE_PERIPHERAL, clock is disabled at the end of 107 * the probe and enabled on udc_start. 108 * If role-switch set is called before the udc_start, we need to enable 109 * the clock to read/write GOTGCTL and GUSBCFG registers to override 110 * mode and sessions. It is the case if cable is plugged at boot. 111 */ 112 if (!hsotg->ll_hw_enabled && hsotg->clk) { 113 int ret = clk_prepare_enable(hsotg->clk); 114 115 if (ret) 116 return ret; 117 } 118 119 spin_lock_irqsave(&hsotg->lock, flags); 120 121 if (role == USB_ROLE_NONE) { 122 /* default operation mode when usb role is USB_ROLE_NONE */ 123 if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) 124 role = USB_ROLE_HOST; 125 else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) 126 role = USB_ROLE_DEVICE; 127 } 128 129 if (role == USB_ROLE_HOST) { 130 already = dwc2_ovr_avalid(hsotg, true); 131 } else if (role == USB_ROLE_DEVICE) { 132 already = dwc2_ovr_bvalid(hsotg, true); 133 if (dwc2_is_device_enabled(hsotg)) { 134 /* This clear DCTL.SFTDISCON bit */ 135 dwc2_hsotg_core_connect(hsotg); 136 } 137 } else { 138 if (dwc2_is_device_mode(hsotg)) { 139 if (!dwc2_ovr_bvalid(hsotg, false)) 140 /* This set DCTL.SFTDISCON bit */ 141 dwc2_hsotg_core_disconnect(hsotg); 142 } else { 143 dwc2_ovr_avalid(hsotg, false); 144 } 145 } 146 147 spin_unlock_irqrestore(&hsotg->lock, flags); 148 149 if (!already && hsotg->dr_mode == USB_DR_MODE_OTG) 150 /* This will raise a Connector ID Status Change Interrupt */ 151 dwc2_force_mode(hsotg, role == USB_ROLE_HOST); 152 153 if (!hsotg->ll_hw_enabled && hsotg->clk) 154 clk_disable_unprepare(hsotg->clk); 155 156 dev_dbg(hsotg->dev, "%s-session valid\n", 157 role == USB_ROLE_NONE ? "No" : 158 role == USB_ROLE_HOST ? "A" : "B"); 159 160 return 0; 161 } 162 163 int dwc2_drd_init(struct dwc2_hsotg *hsotg) 164 { 165 struct usb_role_switch_desc role_sw_desc = {0}; 166 struct usb_role_switch *role_sw; 167 int ret; 168 169 if (!device_property_read_bool(hsotg->dev, "usb-role-switch")) 170 return 0; 171 172 hsotg->role_sw_default_mode = usb_get_role_switch_default_mode(hsotg->dev); 173 role_sw_desc.driver_data = hsotg; 174 role_sw_desc.fwnode = dev_fwnode(hsotg->dev); 175 role_sw_desc.set = dwc2_drd_role_sw_set; 176 role_sw_desc.allow_userspace_control = true; 177 178 role_sw = usb_role_switch_register(hsotg->dev, &role_sw_desc); 179 if (IS_ERR(role_sw)) { 180 ret = PTR_ERR(role_sw); 181 dev_err(hsotg->dev, 182 "failed to register role switch: %d\n", ret); 183 return ret; 184 } 185 186 hsotg->role_sw = role_sw; 187 188 /* Enable override and initialize values */ 189 dwc2_ovr_init(hsotg); 190 191 return 0; 192 } 193 194 void dwc2_drd_suspend(struct dwc2_hsotg *hsotg) 195 { 196 u32 gintsts, gintmsk; 197 198 if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { 199 gintmsk = dwc2_readl(hsotg, GINTMSK); 200 gintmsk &= ~GINTSTS_CONIDSTSCHNG; 201 dwc2_writel(hsotg, gintmsk, GINTMSK); 202 gintsts = dwc2_readl(hsotg, GINTSTS); 203 dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); 204 } 205 } 206 207 void dwc2_drd_resume(struct dwc2_hsotg *hsotg) 208 { 209 u32 gintsts, gintmsk; 210 enum usb_role role; 211 212 if (hsotg->role_sw) { 213 /* get last known role (as the get ops isn't implemented by this driver) */ 214 role = usb_role_switch_get_role(hsotg->role_sw); 215 216 if (role == USB_ROLE_NONE) { 217 if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) 218 role = USB_ROLE_HOST; 219 else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) 220 role = USB_ROLE_DEVICE; 221 } 222 223 /* restore last role that may have been lost */ 224 if (role == USB_ROLE_HOST) 225 dwc2_ovr_avalid(hsotg, true); 226 else if (role == USB_ROLE_DEVICE) 227 dwc2_ovr_bvalid(hsotg, true); 228 229 dwc2_force_mode(hsotg, role == USB_ROLE_HOST); 230 231 dev_dbg(hsotg->dev, "resuming %s-session valid\n", 232 role == USB_ROLE_NONE ? "No" : 233 role == USB_ROLE_HOST ? "A" : "B"); 234 } 235 236 if (hsotg->role_sw && !hsotg->params.external_id_pin_ctl) { 237 gintsts = dwc2_readl(hsotg, GINTSTS); 238 dwc2_writel(hsotg, gintsts | GINTSTS_CONIDSTSCHNG, GINTSTS); 239 gintmsk = dwc2_readl(hsotg, GINTMSK); 240 gintmsk |= GINTSTS_CONIDSTSCHNG; 241 dwc2_writel(hsotg, gintmsk, GINTMSK); 242 } 243 } 244 245 void dwc2_drd_exit(struct dwc2_hsotg *hsotg) 246 { 247 if (hsotg->role_sw) 248 usb_role_switch_unregister(hsotg->role_sw); 249 } 250