1*f6ce6072SVignesh Raghavendra // SPDX-License-Identifier: GPL-2.0 2*f6ce6072SVignesh Raghavendra /* 3*f6ce6072SVignesh Raghavendra * Cadence USBSS DRD Driver. 4*f6ce6072SVignesh Raghavendra * 5*f6ce6072SVignesh Raghavendra * Copyright (C) 2018-2019 Cadence. 6*f6ce6072SVignesh Raghavendra * Copyright (C) 2017-2018 NXP 7*f6ce6072SVignesh Raghavendra * Copyright (C) 2019 Texas Instruments 8*f6ce6072SVignesh Raghavendra * 9*f6ce6072SVignesh Raghavendra * Author: Peter Chen <peter.chen@nxp.com> 10*f6ce6072SVignesh Raghavendra * Pawel Laszczak <pawell@cadence.com> 11*f6ce6072SVignesh Raghavendra * Roger Quadros <rogerq@ti.com> 12*f6ce6072SVignesh Raghavendra */ 13*f6ce6072SVignesh Raghavendra 14*f6ce6072SVignesh Raghavendra #include <common.h> 15*f6ce6072SVignesh Raghavendra #include <dm.h> 16*f6ce6072SVignesh Raghavendra #include <dm/device-internal.h> 17*f6ce6072SVignesh Raghavendra #include <dm/lists.h> 18*f6ce6072SVignesh Raghavendra #include <linux/kernel.h> 19*f6ce6072SVignesh Raghavendra #include <linux/io.h> 20*f6ce6072SVignesh Raghavendra #include <usb.h> 21*f6ce6072SVignesh Raghavendra #include "../host/xhci.h" 22*f6ce6072SVignesh Raghavendra 23*f6ce6072SVignesh Raghavendra #include "core.h" 24*f6ce6072SVignesh Raghavendra #include "host-export.h" 25*f6ce6072SVignesh Raghavendra #include "gadget-export.h" 26*f6ce6072SVignesh Raghavendra #include "drd.h" 27*f6ce6072SVignesh Raghavendra 28*f6ce6072SVignesh Raghavendra static int cdns3_idle_init(struct cdns3 *cdns); 29*f6ce6072SVignesh Raghavendra 30*f6ce6072SVignesh Raghavendra struct cdns3_host_priv { 31*f6ce6072SVignesh Raghavendra struct xhci_ctrl xhci_ctrl; 32*f6ce6072SVignesh Raghavendra struct cdns3 cdns; 33*f6ce6072SVignesh Raghavendra }; 34*f6ce6072SVignesh Raghavendra 35*f6ce6072SVignesh Raghavendra struct cdns3_gadget_priv { 36*f6ce6072SVignesh Raghavendra struct cdns3 cdns; 37*f6ce6072SVignesh Raghavendra }; 38*f6ce6072SVignesh Raghavendra 39*f6ce6072SVignesh Raghavendra static inline 40*f6ce6072SVignesh Raghavendra struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns) 41*f6ce6072SVignesh Raghavendra { 42*f6ce6072SVignesh Raghavendra WARN_ON(!cdns->roles[cdns->role]); 43*f6ce6072SVignesh Raghavendra return cdns->roles[cdns->role]; 44*f6ce6072SVignesh Raghavendra } 45*f6ce6072SVignesh Raghavendra 46*f6ce6072SVignesh Raghavendra static int cdns3_role_start(struct cdns3 *cdns, enum usb_role role) 47*f6ce6072SVignesh Raghavendra { 48*f6ce6072SVignesh Raghavendra int ret; 49*f6ce6072SVignesh Raghavendra 50*f6ce6072SVignesh Raghavendra if (WARN_ON(role > USB_ROLE_DEVICE)) 51*f6ce6072SVignesh Raghavendra return 0; 52*f6ce6072SVignesh Raghavendra 53*f6ce6072SVignesh Raghavendra mutex_lock(&cdns->mutex); 54*f6ce6072SVignesh Raghavendra cdns->role = role; 55*f6ce6072SVignesh Raghavendra mutex_unlock(&cdns->mutex); 56*f6ce6072SVignesh Raghavendra 57*f6ce6072SVignesh Raghavendra if (!cdns->roles[role]) 58*f6ce6072SVignesh Raghavendra return -ENXIO; 59*f6ce6072SVignesh Raghavendra 60*f6ce6072SVignesh Raghavendra if (cdns->roles[role]->state == CDNS3_ROLE_STATE_ACTIVE) 61*f6ce6072SVignesh Raghavendra return 0; 62*f6ce6072SVignesh Raghavendra 63*f6ce6072SVignesh Raghavendra mutex_lock(&cdns->mutex); 64*f6ce6072SVignesh Raghavendra ret = cdns->roles[role]->start(cdns); 65*f6ce6072SVignesh Raghavendra if (!ret) 66*f6ce6072SVignesh Raghavendra cdns->roles[role]->state = CDNS3_ROLE_STATE_ACTIVE; 67*f6ce6072SVignesh Raghavendra mutex_unlock(&cdns->mutex); 68*f6ce6072SVignesh Raghavendra 69*f6ce6072SVignesh Raghavendra return ret; 70*f6ce6072SVignesh Raghavendra } 71*f6ce6072SVignesh Raghavendra 72*f6ce6072SVignesh Raghavendra static void cdns3_role_stop(struct cdns3 *cdns) 73*f6ce6072SVignesh Raghavendra { 74*f6ce6072SVignesh Raghavendra enum usb_role role = cdns->role; 75*f6ce6072SVignesh Raghavendra 76*f6ce6072SVignesh Raghavendra if (WARN_ON(role > USB_ROLE_DEVICE)) 77*f6ce6072SVignesh Raghavendra return; 78*f6ce6072SVignesh Raghavendra 79*f6ce6072SVignesh Raghavendra if (cdns->roles[role]->state == CDNS3_ROLE_STATE_INACTIVE) 80*f6ce6072SVignesh Raghavendra return; 81*f6ce6072SVignesh Raghavendra 82*f6ce6072SVignesh Raghavendra mutex_lock(&cdns->mutex); 83*f6ce6072SVignesh Raghavendra cdns->roles[role]->stop(cdns); 84*f6ce6072SVignesh Raghavendra cdns->roles[role]->state = CDNS3_ROLE_STATE_INACTIVE; 85*f6ce6072SVignesh Raghavendra mutex_unlock(&cdns->mutex); 86*f6ce6072SVignesh Raghavendra } 87*f6ce6072SVignesh Raghavendra 88*f6ce6072SVignesh Raghavendra static void cdns3_exit_roles(struct cdns3 *cdns) 89*f6ce6072SVignesh Raghavendra { 90*f6ce6072SVignesh Raghavendra cdns3_role_stop(cdns); 91*f6ce6072SVignesh Raghavendra cdns3_drd_exit(cdns); 92*f6ce6072SVignesh Raghavendra } 93*f6ce6072SVignesh Raghavendra 94*f6ce6072SVignesh Raghavendra static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns); 95*f6ce6072SVignesh Raghavendra 96*f6ce6072SVignesh Raghavendra /** 97*f6ce6072SVignesh Raghavendra * cdns3_core_init_role - initialize role of operation 98*f6ce6072SVignesh Raghavendra * @cdns: Pointer to cdns3 structure 99*f6ce6072SVignesh Raghavendra * 100*f6ce6072SVignesh Raghavendra * Returns 0 on success otherwise negative errno 101*f6ce6072SVignesh Raghavendra */ 102*f6ce6072SVignesh Raghavendra static int cdns3_core_init_role(struct cdns3 *cdns) 103*f6ce6072SVignesh Raghavendra { 104*f6ce6072SVignesh Raghavendra struct udevice *dev = cdns->dev; 105*f6ce6072SVignesh Raghavendra enum usb_dr_mode best_dr_mode; 106*f6ce6072SVignesh Raghavendra enum usb_dr_mode dr_mode; 107*f6ce6072SVignesh Raghavendra int ret = 0; 108*f6ce6072SVignesh Raghavendra 109*f6ce6072SVignesh Raghavendra dr_mode = usb_get_dr_mode(dev_of_offset(dev)); 110*f6ce6072SVignesh Raghavendra cdns->role = USB_ROLE_NONE; 111*f6ce6072SVignesh Raghavendra 112*f6ce6072SVignesh Raghavendra /* 113*f6ce6072SVignesh Raghavendra * If driver can't read mode by means of usb_get_dr_mode function then 114*f6ce6072SVignesh Raghavendra * chooses mode according with Kernel configuration. This setting 115*f6ce6072SVignesh Raghavendra * can be restricted later depending on strap pin configuration. 116*f6ce6072SVignesh Raghavendra */ 117*f6ce6072SVignesh Raghavendra if (dr_mode == USB_DR_MODE_UNKNOWN) { 118*f6ce6072SVignesh Raghavendra if (IS_ENABLED(CONFIG_USB_CDNS3_HOST) && 119*f6ce6072SVignesh Raghavendra IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) 120*f6ce6072SVignesh Raghavendra dr_mode = USB_DR_MODE_OTG; 121*f6ce6072SVignesh Raghavendra else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST)) 122*f6ce6072SVignesh Raghavendra dr_mode = USB_DR_MODE_HOST; 123*f6ce6072SVignesh Raghavendra else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET)) 124*f6ce6072SVignesh Raghavendra dr_mode = USB_DR_MODE_PERIPHERAL; 125*f6ce6072SVignesh Raghavendra } 126*f6ce6072SVignesh Raghavendra 127*f6ce6072SVignesh Raghavendra /* 128*f6ce6072SVignesh Raghavendra * At this point cdns->dr_mode contains strap configuration. 129*f6ce6072SVignesh Raghavendra * Driver try update this setting considering kernel configuration 130*f6ce6072SVignesh Raghavendra */ 131*f6ce6072SVignesh Raghavendra best_dr_mode = cdns->dr_mode; 132*f6ce6072SVignesh Raghavendra 133*f6ce6072SVignesh Raghavendra ret = cdns3_idle_init(cdns); 134*f6ce6072SVignesh Raghavendra if (ret) 135*f6ce6072SVignesh Raghavendra return ret; 136*f6ce6072SVignesh Raghavendra 137*f6ce6072SVignesh Raghavendra if (dr_mode == USB_DR_MODE_OTG) { 138*f6ce6072SVignesh Raghavendra best_dr_mode = cdns->dr_mode; 139*f6ce6072SVignesh Raghavendra } else if (cdns->dr_mode == USB_DR_MODE_OTG) { 140*f6ce6072SVignesh Raghavendra best_dr_mode = dr_mode; 141*f6ce6072SVignesh Raghavendra } else if (cdns->dr_mode != dr_mode) { 142*f6ce6072SVignesh Raghavendra dev_err(dev, "Incorrect DRD configuration\n"); 143*f6ce6072SVignesh Raghavendra return -EINVAL; 144*f6ce6072SVignesh Raghavendra } 145*f6ce6072SVignesh Raghavendra 146*f6ce6072SVignesh Raghavendra dr_mode = best_dr_mode; 147*f6ce6072SVignesh Raghavendra 148*f6ce6072SVignesh Raghavendra #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD) 149*f6ce6072SVignesh Raghavendra if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) { 150*f6ce6072SVignesh Raghavendra ret = cdns3_host_init(cdns); 151*f6ce6072SVignesh Raghavendra if (ret) { 152*f6ce6072SVignesh Raghavendra dev_err(dev, "Host initialization failed with %d\n", 153*f6ce6072SVignesh Raghavendra ret); 154*f6ce6072SVignesh Raghavendra goto err; 155*f6ce6072SVignesh Raghavendra } 156*f6ce6072SVignesh Raghavendra } 157*f6ce6072SVignesh Raghavendra #endif 158*f6ce6072SVignesh Raghavendra 159*f6ce6072SVignesh Raghavendra #if CONFIG_IS_ENABLED(DM_USB_GADGET) 160*f6ce6072SVignesh Raghavendra if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) { 161*f6ce6072SVignesh Raghavendra ret = cdns3_gadget_init(cdns); 162*f6ce6072SVignesh Raghavendra if (ret) { 163*f6ce6072SVignesh Raghavendra dev_err(dev, "Device initialization failed with %d\n", 164*f6ce6072SVignesh Raghavendra ret); 165*f6ce6072SVignesh Raghavendra goto err; 166*f6ce6072SVignesh Raghavendra } 167*f6ce6072SVignesh Raghavendra } 168*f6ce6072SVignesh Raghavendra #endif 169*f6ce6072SVignesh Raghavendra 170*f6ce6072SVignesh Raghavendra cdns->dr_mode = dr_mode; 171*f6ce6072SVignesh Raghavendra 172*f6ce6072SVignesh Raghavendra ret = cdns3_drd_update_mode(cdns); 173*f6ce6072SVignesh Raghavendra if (ret) 174*f6ce6072SVignesh Raghavendra goto err; 175*f6ce6072SVignesh Raghavendra 176*f6ce6072SVignesh Raghavendra if (cdns->dr_mode != USB_DR_MODE_OTG) { 177*f6ce6072SVignesh Raghavendra ret = cdns3_hw_role_switch(cdns); 178*f6ce6072SVignesh Raghavendra if (ret) 179*f6ce6072SVignesh Raghavendra goto err; 180*f6ce6072SVignesh Raghavendra } 181*f6ce6072SVignesh Raghavendra 182*f6ce6072SVignesh Raghavendra return ret; 183*f6ce6072SVignesh Raghavendra err: 184*f6ce6072SVignesh Raghavendra cdns3_exit_roles(cdns); 185*f6ce6072SVignesh Raghavendra return ret; 186*f6ce6072SVignesh Raghavendra } 187*f6ce6072SVignesh Raghavendra 188*f6ce6072SVignesh Raghavendra /** 189*f6ce6072SVignesh Raghavendra * cdsn3_hw_role_state_machine - role switch state machine based on hw events 190*f6ce6072SVignesh Raghavendra * @cdns: Pointer to controller structure. 191*f6ce6072SVignesh Raghavendra * 192*f6ce6072SVignesh Raghavendra * Returns next role to be entered based on hw events. 193*f6ce6072SVignesh Raghavendra */ 194*f6ce6072SVignesh Raghavendra static enum usb_role cdsn3_hw_role_state_machine(struct cdns3 *cdns) 195*f6ce6072SVignesh Raghavendra { 196*f6ce6072SVignesh Raghavendra enum usb_role role; 197*f6ce6072SVignesh Raghavendra int id, vbus; 198*f6ce6072SVignesh Raghavendra 199*f6ce6072SVignesh Raghavendra if (cdns->dr_mode != USB_DR_MODE_OTG) 200*f6ce6072SVignesh Raghavendra goto not_otg; 201*f6ce6072SVignesh Raghavendra 202*f6ce6072SVignesh Raghavendra id = cdns3_get_id(cdns); 203*f6ce6072SVignesh Raghavendra vbus = cdns3_get_vbus(cdns); 204*f6ce6072SVignesh Raghavendra 205*f6ce6072SVignesh Raghavendra /* 206*f6ce6072SVignesh Raghavendra * Role change state machine 207*f6ce6072SVignesh Raghavendra * Inputs: ID, VBUS 208*f6ce6072SVignesh Raghavendra * Previous state: cdns->role 209*f6ce6072SVignesh Raghavendra * Next state: role 210*f6ce6072SVignesh Raghavendra */ 211*f6ce6072SVignesh Raghavendra role = cdns->role; 212*f6ce6072SVignesh Raghavendra 213*f6ce6072SVignesh Raghavendra switch (role) { 214*f6ce6072SVignesh Raghavendra case USB_ROLE_NONE: 215*f6ce6072SVignesh Raghavendra /* 216*f6ce6072SVignesh Raghavendra * Driver treats USB_ROLE_NONE synonymous to IDLE state from 217*f6ce6072SVignesh Raghavendra * controller specification. 218*f6ce6072SVignesh Raghavendra */ 219*f6ce6072SVignesh Raghavendra if (!id) 220*f6ce6072SVignesh Raghavendra role = USB_ROLE_HOST; 221*f6ce6072SVignesh Raghavendra else if (vbus) 222*f6ce6072SVignesh Raghavendra role = USB_ROLE_DEVICE; 223*f6ce6072SVignesh Raghavendra break; 224*f6ce6072SVignesh Raghavendra case USB_ROLE_HOST: /* from HOST, we can only change to NONE */ 225*f6ce6072SVignesh Raghavendra if (id) 226*f6ce6072SVignesh Raghavendra role = USB_ROLE_NONE; 227*f6ce6072SVignesh Raghavendra break; 228*f6ce6072SVignesh Raghavendra case USB_ROLE_DEVICE: /* from GADGET, we can only change to NONE*/ 229*f6ce6072SVignesh Raghavendra if (!vbus) 230*f6ce6072SVignesh Raghavendra role = USB_ROLE_NONE; 231*f6ce6072SVignesh Raghavendra break; 232*f6ce6072SVignesh Raghavendra } 233*f6ce6072SVignesh Raghavendra 234*f6ce6072SVignesh Raghavendra dev_dbg(cdns->dev, "role %d -> %d\n", cdns->role, role); 235*f6ce6072SVignesh Raghavendra 236*f6ce6072SVignesh Raghavendra return role; 237*f6ce6072SVignesh Raghavendra 238*f6ce6072SVignesh Raghavendra not_otg: 239*f6ce6072SVignesh Raghavendra if (cdns3_is_host(cdns)) 240*f6ce6072SVignesh Raghavendra role = USB_ROLE_HOST; 241*f6ce6072SVignesh Raghavendra if (cdns3_is_device(cdns)) 242*f6ce6072SVignesh Raghavendra role = USB_ROLE_DEVICE; 243*f6ce6072SVignesh Raghavendra 244*f6ce6072SVignesh Raghavendra return role; 245*f6ce6072SVignesh Raghavendra } 246*f6ce6072SVignesh Raghavendra 247*f6ce6072SVignesh Raghavendra static int cdns3_idle_role_start(struct cdns3 *cdns) 248*f6ce6072SVignesh Raghavendra { 249*f6ce6072SVignesh Raghavendra return 0; 250*f6ce6072SVignesh Raghavendra } 251*f6ce6072SVignesh Raghavendra 252*f6ce6072SVignesh Raghavendra static void cdns3_idle_role_stop(struct cdns3 *cdns) 253*f6ce6072SVignesh Raghavendra { 254*f6ce6072SVignesh Raghavendra /* Program Lane swap and bring PHY out of RESET */ 255*f6ce6072SVignesh Raghavendra generic_phy_reset(&cdns->usb3_phy); 256*f6ce6072SVignesh Raghavendra } 257*f6ce6072SVignesh Raghavendra 258*f6ce6072SVignesh Raghavendra static int cdns3_idle_init(struct cdns3 *cdns) 259*f6ce6072SVignesh Raghavendra { 260*f6ce6072SVignesh Raghavendra struct cdns3_role_driver *rdrv; 261*f6ce6072SVignesh Raghavendra 262*f6ce6072SVignesh Raghavendra rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL); 263*f6ce6072SVignesh Raghavendra if (!rdrv) 264*f6ce6072SVignesh Raghavendra return -ENOMEM; 265*f6ce6072SVignesh Raghavendra 266*f6ce6072SVignesh Raghavendra rdrv->start = cdns3_idle_role_start; 267*f6ce6072SVignesh Raghavendra rdrv->stop = cdns3_idle_role_stop; 268*f6ce6072SVignesh Raghavendra rdrv->state = CDNS3_ROLE_STATE_INACTIVE; 269*f6ce6072SVignesh Raghavendra rdrv->suspend = NULL; 270*f6ce6072SVignesh Raghavendra rdrv->resume = NULL; 271*f6ce6072SVignesh Raghavendra rdrv->name = "idle"; 272*f6ce6072SVignesh Raghavendra 273*f6ce6072SVignesh Raghavendra cdns->roles[USB_ROLE_NONE] = rdrv; 274*f6ce6072SVignesh Raghavendra 275*f6ce6072SVignesh Raghavendra return 0; 276*f6ce6072SVignesh Raghavendra } 277*f6ce6072SVignesh Raghavendra 278*f6ce6072SVignesh Raghavendra /** 279*f6ce6072SVignesh Raghavendra * cdns3_hw_role_switch - switch roles based on HW state 280*f6ce6072SVignesh Raghavendra * @cdns3: controller 281*f6ce6072SVignesh Raghavendra */ 282*f6ce6072SVignesh Raghavendra int cdns3_hw_role_switch(struct cdns3 *cdns) 283*f6ce6072SVignesh Raghavendra { 284*f6ce6072SVignesh Raghavendra enum usb_role real_role, current_role; 285*f6ce6072SVignesh Raghavendra int ret = 0; 286*f6ce6072SVignesh Raghavendra 287*f6ce6072SVignesh Raghavendra /* Do nothing if role based on syfs. */ 288*f6ce6072SVignesh Raghavendra if (cdns->role_override) 289*f6ce6072SVignesh Raghavendra return 0; 290*f6ce6072SVignesh Raghavendra 291*f6ce6072SVignesh Raghavendra current_role = cdns->role; 292*f6ce6072SVignesh Raghavendra real_role = cdsn3_hw_role_state_machine(cdns); 293*f6ce6072SVignesh Raghavendra 294*f6ce6072SVignesh Raghavendra /* Do nothing if nothing changed */ 295*f6ce6072SVignesh Raghavendra if (current_role == real_role) 296*f6ce6072SVignesh Raghavendra goto exit; 297*f6ce6072SVignesh Raghavendra 298*f6ce6072SVignesh Raghavendra cdns3_role_stop(cdns); 299*f6ce6072SVignesh Raghavendra 300*f6ce6072SVignesh Raghavendra dev_dbg(cdns->dev, "Switching role %d -> %d", current_role, real_role); 301*f6ce6072SVignesh Raghavendra 302*f6ce6072SVignesh Raghavendra ret = cdns3_role_start(cdns, real_role); 303*f6ce6072SVignesh Raghavendra if (ret) { 304*f6ce6072SVignesh Raghavendra /* Back to current role */ 305*f6ce6072SVignesh Raghavendra dev_err(cdns->dev, "set %d has failed, back to %d\n", 306*f6ce6072SVignesh Raghavendra real_role, current_role); 307*f6ce6072SVignesh Raghavendra ret = cdns3_role_start(cdns, current_role); 308*f6ce6072SVignesh Raghavendra if (ret) 309*f6ce6072SVignesh Raghavendra dev_err(cdns->dev, "back to %d failed too\n", 310*f6ce6072SVignesh Raghavendra current_role); 311*f6ce6072SVignesh Raghavendra } 312*f6ce6072SVignesh Raghavendra exit: 313*f6ce6072SVignesh Raghavendra return ret; 314*f6ce6072SVignesh Raghavendra } 315*f6ce6072SVignesh Raghavendra 316*f6ce6072SVignesh Raghavendra static int cdns3_probe(struct cdns3 *cdns) 317*f6ce6072SVignesh Raghavendra { 318*f6ce6072SVignesh Raghavendra struct udevice *dev = cdns->dev; 319*f6ce6072SVignesh Raghavendra int ret; 320*f6ce6072SVignesh Raghavendra 321*f6ce6072SVignesh Raghavendra cdns->xhci_regs = dev_remap_addr_name(dev, "xhci"); 322*f6ce6072SVignesh Raghavendra if (!cdns->xhci_regs) 323*f6ce6072SVignesh Raghavendra return -EINVAL; 324*f6ce6072SVignesh Raghavendra 325*f6ce6072SVignesh Raghavendra cdns->dev_regs = dev_remap_addr_name(dev, "dev"); 326*f6ce6072SVignesh Raghavendra if (!cdns->dev_regs) 327*f6ce6072SVignesh Raghavendra return -EINVAL; 328*f6ce6072SVignesh Raghavendra 329*f6ce6072SVignesh Raghavendra mutex_init(&cdns->mutex); 330*f6ce6072SVignesh Raghavendra 331*f6ce6072SVignesh Raghavendra ret = generic_phy_get_by_name(dev, "cdns3,usb2-phy", &cdns->usb2_phy); 332*f6ce6072SVignesh Raghavendra if (ret) 333*f6ce6072SVignesh Raghavendra dev_warn(dev, "Unable to get USB2 phy (ret %d)\n", ret); 334*f6ce6072SVignesh Raghavendra 335*f6ce6072SVignesh Raghavendra ret = generic_phy_init(&cdns->usb2_phy); 336*f6ce6072SVignesh Raghavendra if (ret) 337*f6ce6072SVignesh Raghavendra return ret; 338*f6ce6072SVignesh Raghavendra 339*f6ce6072SVignesh Raghavendra ret = generic_phy_get_by_name(dev, "cdns3,usb3-phy", &cdns->usb3_phy); 340*f6ce6072SVignesh Raghavendra if (ret) 341*f6ce6072SVignesh Raghavendra dev_warn(dev, "Unable to get USB3 phy (ret %d)\n", ret); 342*f6ce6072SVignesh Raghavendra 343*f6ce6072SVignesh Raghavendra ret = generic_phy_init(&cdns->usb3_phy); 344*f6ce6072SVignesh Raghavendra if (ret) 345*f6ce6072SVignesh Raghavendra return ret; 346*f6ce6072SVignesh Raghavendra 347*f6ce6072SVignesh Raghavendra ret = generic_phy_power_on(&cdns->usb2_phy); 348*f6ce6072SVignesh Raghavendra if (ret) 349*f6ce6072SVignesh Raghavendra return ret; 350*f6ce6072SVignesh Raghavendra 351*f6ce6072SVignesh Raghavendra ret = generic_phy_power_on(&cdns->usb3_phy); 352*f6ce6072SVignesh Raghavendra if (ret) 353*f6ce6072SVignesh Raghavendra return ret; 354*f6ce6072SVignesh Raghavendra 355*f6ce6072SVignesh Raghavendra ret = cdns3_drd_init(cdns); 356*f6ce6072SVignesh Raghavendra if (ret) 357*f6ce6072SVignesh Raghavendra return ret; 358*f6ce6072SVignesh Raghavendra 359*f6ce6072SVignesh Raghavendra ret = cdns3_core_init_role(cdns); 360*f6ce6072SVignesh Raghavendra if (ret) 361*f6ce6072SVignesh Raghavendra return ret; 362*f6ce6072SVignesh Raghavendra 363*f6ce6072SVignesh Raghavendra dev_dbg(dev, "Cadence USB3 core: probe succeed\n"); 364*f6ce6072SVignesh Raghavendra 365*f6ce6072SVignesh Raghavendra return 0; 366*f6ce6072SVignesh Raghavendra } 367*f6ce6072SVignesh Raghavendra 368*f6ce6072SVignesh Raghavendra static int cdns3_remove(struct cdns3 *cdns) 369*f6ce6072SVignesh Raghavendra { 370*f6ce6072SVignesh Raghavendra cdns3_exit_roles(cdns); 371*f6ce6072SVignesh Raghavendra generic_phy_power_off(&cdns->usb2_phy); 372*f6ce6072SVignesh Raghavendra generic_phy_power_off(&cdns->usb3_phy); 373*f6ce6072SVignesh Raghavendra generic_phy_exit(&cdns->usb2_phy); 374*f6ce6072SVignesh Raghavendra generic_phy_exit(&cdns->usb3_phy); 375*f6ce6072SVignesh Raghavendra return 0; 376*f6ce6072SVignesh Raghavendra } 377*f6ce6072SVignesh Raghavendra 378*f6ce6072SVignesh Raghavendra static const struct udevice_id cdns3_ids[] = { 379*f6ce6072SVignesh Raghavendra { .compatible = "cdns,usb3" }, 380*f6ce6072SVignesh Raghavendra { }, 381*f6ce6072SVignesh Raghavendra }; 382*f6ce6072SVignesh Raghavendra 383*f6ce6072SVignesh Raghavendra int cdns3_bind(struct udevice *parent) 384*f6ce6072SVignesh Raghavendra { 385*f6ce6072SVignesh Raghavendra int from = dev_of_offset(parent); 386*f6ce6072SVignesh Raghavendra const void *fdt = gd->fdt_blob; 387*f6ce6072SVignesh Raghavendra enum usb_dr_mode dr_mode; 388*f6ce6072SVignesh Raghavendra struct udevice *dev; 389*f6ce6072SVignesh Raghavendra const char *driver; 390*f6ce6072SVignesh Raghavendra const char *name; 391*f6ce6072SVignesh Raghavendra int node; 392*f6ce6072SVignesh Raghavendra int ret; 393*f6ce6072SVignesh Raghavendra 394*f6ce6072SVignesh Raghavendra node = fdt_node_offset_by_compatible(fdt, from, "cdns,usb3"); 395*f6ce6072SVignesh Raghavendra if (node < 0) { 396*f6ce6072SVignesh Raghavendra ret = -ENODEV; 397*f6ce6072SVignesh Raghavendra goto fail; 398*f6ce6072SVignesh Raghavendra } 399*f6ce6072SVignesh Raghavendra 400*f6ce6072SVignesh Raghavendra name = fdt_get_name(fdt, node, NULL); 401*f6ce6072SVignesh Raghavendra dr_mode = usb_get_dr_mode(node); 402*f6ce6072SVignesh Raghavendra 403*f6ce6072SVignesh Raghavendra switch (dr_mode) { 404*f6ce6072SVignesh Raghavendra #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \ 405*f6ce6072SVignesh Raghavendra (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) 406*f6ce6072SVignesh Raghavendra case USB_DR_MODE_HOST: 407*f6ce6072SVignesh Raghavendra debug("%s: dr_mode: HOST\n", __func__); 408*f6ce6072SVignesh Raghavendra driver = "cdns-usb3-host"; 409*f6ce6072SVignesh Raghavendra break; 410*f6ce6072SVignesh Raghavendra #endif 411*f6ce6072SVignesh Raghavendra #if CONFIG_IS_ENABLED(DM_USB_GADGET) 412*f6ce6072SVignesh Raghavendra case USB_DR_MODE_PERIPHERAL: 413*f6ce6072SVignesh Raghavendra debug("%s: dr_mode: PERIPHERAL\n", __func__); 414*f6ce6072SVignesh Raghavendra driver = "cdns-usb3-peripheral"; 415*f6ce6072SVignesh Raghavendra break; 416*f6ce6072SVignesh Raghavendra #endif 417*f6ce6072SVignesh Raghavendra default: 418*f6ce6072SVignesh Raghavendra printf("%s: unsupported dr_mode\n", __func__); 419*f6ce6072SVignesh Raghavendra ret = -ENODEV; 420*f6ce6072SVignesh Raghavendra goto fail; 421*f6ce6072SVignesh Raghavendra }; 422*f6ce6072SVignesh Raghavendra 423*f6ce6072SVignesh Raghavendra ret = device_bind_driver_to_node(parent, driver, name, 424*f6ce6072SVignesh Raghavendra offset_to_ofnode(node), &dev); 425*f6ce6072SVignesh Raghavendra if (ret) { 426*f6ce6072SVignesh Raghavendra printf("%s: not able to bind usb device mode\n", 427*f6ce6072SVignesh Raghavendra __func__); 428*f6ce6072SVignesh Raghavendra goto fail; 429*f6ce6072SVignesh Raghavendra } 430*f6ce6072SVignesh Raghavendra 431*f6ce6072SVignesh Raghavendra return 0; 432*f6ce6072SVignesh Raghavendra 433*f6ce6072SVignesh Raghavendra fail: 434*f6ce6072SVignesh Raghavendra /* do not return an error: failing to bind would hang the board */ 435*f6ce6072SVignesh Raghavendra return 0; 436*f6ce6072SVignesh Raghavendra } 437*f6ce6072SVignesh Raghavendra 438*f6ce6072SVignesh Raghavendra #if CONFIG_IS_ENABLED(DM_USB_GADGET) 439*f6ce6072SVignesh Raghavendra static int cdns3_gadget_probe(struct udevice *dev) 440*f6ce6072SVignesh Raghavendra { 441*f6ce6072SVignesh Raghavendra struct cdns3_gadget_priv *priv = dev_get_priv(dev); 442*f6ce6072SVignesh Raghavendra struct cdns3 *cdns = &priv->cdns; 443*f6ce6072SVignesh Raghavendra 444*f6ce6072SVignesh Raghavendra cdns->dev = dev; 445*f6ce6072SVignesh Raghavendra 446*f6ce6072SVignesh Raghavendra return cdns3_probe(cdns); 447*f6ce6072SVignesh Raghavendra } 448*f6ce6072SVignesh Raghavendra 449*f6ce6072SVignesh Raghavendra static int cdns3_gadget_remove(struct udevice *dev) 450*f6ce6072SVignesh Raghavendra { 451*f6ce6072SVignesh Raghavendra struct cdns3_gadget_priv *priv = dev_get_priv(dev); 452*f6ce6072SVignesh Raghavendra struct cdns3 *cdns = &priv->cdns; 453*f6ce6072SVignesh Raghavendra 454*f6ce6072SVignesh Raghavendra return cdns3_remove(cdns); 455*f6ce6072SVignesh Raghavendra } 456*f6ce6072SVignesh Raghavendra 457*f6ce6072SVignesh Raghavendra U_BOOT_DRIVER(cdns_usb3_peripheral) = { 458*f6ce6072SVignesh Raghavendra .name = "cdns-usb3-peripheral", 459*f6ce6072SVignesh Raghavendra .id = UCLASS_USB_GADGET_GENERIC, 460*f6ce6072SVignesh Raghavendra .of_match = cdns3_ids, 461*f6ce6072SVignesh Raghavendra .probe = cdns3_gadget_probe, 462*f6ce6072SVignesh Raghavendra .remove = cdns3_gadget_remove, 463*f6ce6072SVignesh Raghavendra .priv_auto_alloc_size = sizeof(struct cdns3_gadget_priv), 464*f6ce6072SVignesh Raghavendra .flags = DM_FLAG_ALLOC_PRIV_DMA, 465*f6ce6072SVignesh Raghavendra }; 466*f6ce6072SVignesh Raghavendra #endif 467*f6ce6072SVignesh Raghavendra 468*f6ce6072SVignesh Raghavendra #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \ 469*f6ce6072SVignesh Raghavendra (!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)) 470*f6ce6072SVignesh Raghavendra static int cdns3_host_probe(struct udevice *dev) 471*f6ce6072SVignesh Raghavendra { 472*f6ce6072SVignesh Raghavendra struct cdns3_host_priv *priv = dev_get_priv(dev); 473*f6ce6072SVignesh Raghavendra struct cdns3 *cdns = &priv->cdns; 474*f6ce6072SVignesh Raghavendra 475*f6ce6072SVignesh Raghavendra cdns->dev = dev; 476*f6ce6072SVignesh Raghavendra 477*f6ce6072SVignesh Raghavendra return cdns3_probe(cdns); 478*f6ce6072SVignesh Raghavendra } 479*f6ce6072SVignesh Raghavendra 480*f6ce6072SVignesh Raghavendra static int cdns3_host_remove(struct udevice *dev) 481*f6ce6072SVignesh Raghavendra { 482*f6ce6072SVignesh Raghavendra struct cdns3_host_priv *priv = dev_get_priv(dev); 483*f6ce6072SVignesh Raghavendra struct cdns3 *cdns = &priv->cdns; 484*f6ce6072SVignesh Raghavendra 485*f6ce6072SVignesh Raghavendra return cdns3_remove(cdns); 486*f6ce6072SVignesh Raghavendra } 487*f6ce6072SVignesh Raghavendra 488*f6ce6072SVignesh Raghavendra U_BOOT_DRIVER(cdns_usb3_host) = { 489*f6ce6072SVignesh Raghavendra .name = "cdns-usb3-host", 490*f6ce6072SVignesh Raghavendra .id = UCLASS_USB, 491*f6ce6072SVignesh Raghavendra .of_match = cdns3_ids, 492*f6ce6072SVignesh Raghavendra .probe = cdns3_host_probe, 493*f6ce6072SVignesh Raghavendra .remove = cdns3_host_remove, 494*f6ce6072SVignesh Raghavendra .priv_auto_alloc_size = sizeof(struct cdns3_host_priv), 495*f6ce6072SVignesh Raghavendra .ops = &xhci_usb_ops, 496*f6ce6072SVignesh Raghavendra .flags = DM_FLAG_ALLOC_PRIV_DMA, 497*f6ce6072SVignesh Raghavendra }; 498*f6ce6072SVignesh Raghavendra #endif 499