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