1 // SPDX-License-Identifier: GPL-2.0
3 * Cadence USBSS DRD Driver.
5 * Copyright (C) 2018-2019 Cadence.
6 * Copyright (C) 2017-2018 NXP
7 * Copyright (C) 2019 Texas Instruments
9 * Author: Peter Chen <peter.chen@nxp.com>
10 * Pawel Laszczak <pawell@cadence.com>
11 * Roger Quadros <rogerq@ti.com>
16 #include <dm/device-internal.h>
17 #include <dm/device_compat.h>
18 #include <dm/devres.h>
20 #include <linux/bug.h>
21 #include <linux/kernel.h>
23 #include <linux/usb/gadget.h>
28 #include "host-export.h"
29 #include "gadget-export.h"
32 static int cdns3_idle_init(struct cdns3
*cdns
);
34 struct cdns3_host_priv
{
35 struct xhci_ctrl xhci_ctrl
;
39 struct cdns3_gadget_priv
{
44 struct cdns3_role_driver
*cdns3_get_current_role_driver(struct cdns3
*cdns
)
46 WARN_ON(!cdns
->roles
[cdns
->role
]);
47 return cdns
->roles
[cdns
->role
];
50 static int cdns3_role_start(struct cdns3
*cdns
, enum usb_role role
)
54 if (WARN_ON(role
> USB_ROLE_DEVICE
))
57 mutex_lock(&cdns
->mutex
);
59 mutex_unlock(&cdns
->mutex
);
61 if (!cdns
->roles
[role
])
64 if (cdns
->roles
[role
]->state
== CDNS3_ROLE_STATE_ACTIVE
)
67 mutex_lock(&cdns
->mutex
);
68 ret
= cdns
->roles
[role
]->start(cdns
);
70 cdns
->roles
[role
]->state
= CDNS3_ROLE_STATE_ACTIVE
;
71 mutex_unlock(&cdns
->mutex
);
76 static void cdns3_role_stop(struct cdns3
*cdns
)
78 enum usb_role role
= cdns
->role
;
80 if (WARN_ON(role
> USB_ROLE_DEVICE
))
83 if (cdns
->roles
[role
]->state
== CDNS3_ROLE_STATE_INACTIVE
)
86 mutex_lock(&cdns
->mutex
);
87 cdns
->roles
[role
]->stop(cdns
);
88 cdns
->roles
[role
]->state
= CDNS3_ROLE_STATE_INACTIVE
;
89 mutex_unlock(&cdns
->mutex
);
92 static void cdns3_exit_roles(struct cdns3
*cdns
)
94 cdns3_role_stop(cdns
);
98 static enum usb_role
cdsn3_hw_role_state_machine(struct cdns3
*cdns
);
101 * cdns3_core_init_role - initialize role of operation
102 * @cdns: Pointer to cdns3 structure
104 * Returns 0 on success otherwise negative errno
106 static int cdns3_core_init_role(struct cdns3
*cdns
)
108 struct udevice
*dev
= cdns
->dev
;
109 enum usb_dr_mode best_dr_mode
;
110 enum usb_dr_mode dr_mode
;
113 dr_mode
= usb_get_dr_mode(dev_ofnode(dev
));
114 cdns
->role
= USB_ROLE_NONE
;
117 * If driver can't read mode by means of usb_get_dr_mode function then
118 * chooses mode according with Kernel configuration. This setting
119 * can be restricted later depending on strap pin configuration.
121 if (dr_mode
== USB_DR_MODE_UNKNOWN
) {
122 if (IS_ENABLED(CONFIG_USB_CDNS3_HOST
) &&
123 IS_ENABLED(CONFIG_USB_CDNS3_GADGET
))
124 dr_mode
= USB_DR_MODE_OTG
;
125 else if (IS_ENABLED(CONFIG_USB_CDNS3_HOST
))
126 dr_mode
= USB_DR_MODE_HOST
;
127 else if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET
))
128 dr_mode
= USB_DR_MODE_PERIPHERAL
;
132 * At this point cdns->dr_mode contains strap configuration.
133 * Driver try update this setting considering kernel configuration
135 best_dr_mode
= cdns
->dr_mode
;
137 ret
= cdns3_idle_init(cdns
);
141 if (dr_mode
== USB_DR_MODE_OTG
) {
142 best_dr_mode
= cdns
->dr_mode
;
143 } else if (cdns
->dr_mode
== USB_DR_MODE_OTG
) {
144 best_dr_mode
= dr_mode
;
145 } else if (cdns
->dr_mode
!= dr_mode
) {
146 dev_err(dev
, "Incorrect DRD configuration\n");
150 dr_mode
= best_dr_mode
;
152 #if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_XPL_BUILD)
153 if (dr_mode
== USB_DR_MODE_OTG
|| dr_mode
== USB_DR_MODE_HOST
) {
154 ret
= cdns3_host_init(cdns
);
156 dev_err(dev
, "Host initialization failed with %d\n",
163 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
164 if (dr_mode
== USB_DR_MODE_OTG
|| dr_mode
== USB_DR_MODE_PERIPHERAL
) {
165 ret
= cdns3_gadget_init(cdns
);
167 dev_err(dev
, "Device initialization failed with %d\n",
174 cdns
->dr_mode
= dr_mode
;
176 ret
= cdns3_drd_update_mode(cdns
);
180 if (cdns
->dr_mode
!= USB_DR_MODE_OTG
) {
181 ret
= cdns3_hw_role_switch(cdns
);
188 cdns3_exit_roles(cdns
);
193 * cdsn3_hw_role_state_machine - role switch state machine based on hw events
194 * @cdns: Pointer to controller structure.
196 * Returns next role to be entered based on hw events.
198 static enum usb_role
cdsn3_hw_role_state_machine(struct cdns3
*cdns
)
203 if (cdns
->dr_mode
!= USB_DR_MODE_OTG
)
206 id
= cdns3_get_id(cdns
);
207 vbus
= cdns3_get_vbus(cdns
);
210 * Role change state machine
212 * Previous state: cdns->role
220 * Driver treats USB_ROLE_NONE synonymous to IDLE state from
221 * controller specification.
224 role
= USB_ROLE_HOST
;
226 role
= USB_ROLE_DEVICE
;
228 case USB_ROLE_HOST
: /* from HOST, we can only change to NONE */
230 role
= USB_ROLE_NONE
;
232 case USB_ROLE_DEVICE
: /* from GADGET, we can only change to NONE*/
234 role
= USB_ROLE_NONE
;
238 dev_dbg(cdns
->dev
, "role %d -> %d\n", cdns
->role
, role
);
243 if (cdns3_is_host(cdns
))
244 role
= USB_ROLE_HOST
;
245 if (cdns3_is_device(cdns
))
246 role
= USB_ROLE_DEVICE
;
251 static int cdns3_idle_role_start(struct cdns3
*cdns
)
256 static void cdns3_idle_role_stop(struct cdns3
*cdns
)
258 /* Program Lane swap and bring PHY out of RESET */
259 generic_phy_reset(&cdns
->usb3_phy
);
262 static int cdns3_idle_init(struct cdns3
*cdns
)
264 struct cdns3_role_driver
*rdrv
;
266 rdrv
= devm_kzalloc(cdns
->dev
, sizeof(*rdrv
), GFP_KERNEL
);
270 rdrv
->start
= cdns3_idle_role_start
;
271 rdrv
->stop
= cdns3_idle_role_stop
;
272 rdrv
->state
= CDNS3_ROLE_STATE_INACTIVE
;
273 rdrv
->suspend
= NULL
;
277 cdns
->roles
[USB_ROLE_NONE
] = rdrv
;
283 * cdns3_hw_role_switch - switch roles based on HW state
286 int cdns3_hw_role_switch(struct cdns3
*cdns
)
288 enum usb_role real_role
, current_role
;
291 /* Do nothing if role based on syfs. */
292 if (cdns
->role_override
)
295 current_role
= cdns
->role
;
296 real_role
= cdsn3_hw_role_state_machine(cdns
);
298 /* Do nothing if nothing changed */
299 if (current_role
== real_role
)
302 cdns3_role_stop(cdns
);
304 dev_dbg(cdns
->dev
, "Switching role %d -> %d", current_role
, real_role
);
306 ret
= cdns3_role_start(cdns
, real_role
);
308 /* Back to current role */
309 dev_err(cdns
->dev
, "set %d has failed, back to %d\n",
310 real_role
, current_role
);
311 ret
= cdns3_role_start(cdns
, current_role
);
313 dev_err(cdns
->dev
, "back to %d failed too\n",
320 static int cdns3_probe(struct cdns3
*cdns
)
322 struct udevice
*dev
= cdns
->dev
;
325 cdns
->xhci_regs
= dev_remap_addr_name(dev
, "xhci");
326 if (!cdns
->xhci_regs
)
329 cdns
->dev_regs
= dev_remap_addr_name(dev
, "dev");
333 mutex_init(&cdns
->mutex
);
335 ret
= generic_phy_get_by_name(dev
, "cdns3,usb2-phy", &cdns
->usb2_phy
);
337 ret
= generic_phy_init(&cdns
->usb2_phy
);
339 dev_err(dev
, "USB2 PHY init failed: %d\n", ret
);
342 } else if (ret
!= -ENOENT
&& ret
!= -ENODATA
) {
343 dev_err(dev
, "Couldn't get USB2 PHY: %d\n", ret
);
347 ret
= generic_phy_get_by_name(dev
, "cdns3,usb3-phy", &cdns
->usb3_phy
);
349 ret
= generic_phy_init(&cdns
->usb3_phy
);
351 dev_err(dev
, "USB3 PHY init failed: %d\n", ret
);
354 } else if (ret
!= -ENOENT
&& ret
!= -ENODATA
) {
355 dev_err(dev
, "Couldn't get USB3 PHY: %d\n", ret
);
359 ret
= generic_phy_power_on(&cdns
->usb2_phy
);
363 ret
= generic_phy_power_on(&cdns
->usb3_phy
);
367 ret
= cdns3_drd_init(cdns
);
371 ret
= cdns3_core_init_role(cdns
);
375 dev_dbg(dev
, "Cadence USB3 core: probe succeed\n");
380 static int cdns3_remove(struct cdns3
*cdns
)
382 cdns3_exit_roles(cdns
);
383 generic_phy_power_off(&cdns
->usb2_phy
);
384 generic_phy_power_off(&cdns
->usb3_phy
);
385 generic_phy_exit(&cdns
->usb2_phy
);
386 generic_phy_exit(&cdns
->usb3_phy
);
390 static const struct udevice_id cdns3_ids
[] = {
391 { .compatible
= "cdns,usb3" },
395 int cdns3_bind(struct udevice
*parent
)
397 enum usb_dr_mode dr_mode
;
404 node
= ofnode_by_compatible(dev_ofnode(parent
), "cdns,usb3");
405 if (!ofnode_valid(node
)) {
410 name
= ofnode_get_name(node
);
411 dr_mode
= usb_get_dr_mode(node
);
413 if (dr_mode
== USB_DR_MODE_UNKNOWN
)
414 dr_mode
= usb_get_dr_mode(dev_ofnode(parent
));
417 #if defined(CONFIG_SPL_USB_HOST) || \
418 (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST))
419 case USB_DR_MODE_HOST
:
420 debug("%s: dr_mode: HOST\n", __func__
);
421 driver
= "cdns-usb3-host";
424 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
425 case USB_DR_MODE_PERIPHERAL
:
426 debug("%s: dr_mode: PERIPHERAL\n", __func__
);
427 driver
= "cdns-usb3-peripheral";
431 printf("%s: unsupported dr_mode\n", __func__
);
436 ret
= device_bind_driver_to_node(parent
, driver
, name
, node
, &dev
);
438 printf("%s: not able to bind usb device mode\n",
446 /* do not return an error: failing to bind would hang the board */
450 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
451 static int cdns3_gadget_probe(struct udevice
*dev
)
453 struct cdns3_gadget_priv
*priv
= dev_get_priv(dev
);
454 struct cdns3
*cdns
= &priv
->cdns
;
458 return cdns3_probe(cdns
);
461 static int cdns3_gadget_remove(struct udevice
*dev
)
463 struct cdns3_gadget_priv
*priv
= dev_get_priv(dev
);
464 struct cdns3
*cdns
= &priv
->cdns
;
466 return cdns3_remove(cdns
);
469 static int cdns3_gadget_handle_interrupts(struct udevice
*dev
)
471 struct cdns3
*cdns
= dev_get_priv(dev
);
473 cdns3_gadget_uboot_handle_interrupt(cdns
);
478 static const struct usb_gadget_generic_ops cdns3_gadget_ops
= {
479 .handle_interrupts
= cdns3_gadget_handle_interrupts
,
482 U_BOOT_DRIVER(cdns_usb3_peripheral
) = {
483 .name
= "cdns-usb3-peripheral",
484 .id
= UCLASS_USB_GADGET_GENERIC
,
485 .of_match
= cdns3_ids
,
486 .ops
= &cdns3_gadget_ops
,
487 .probe
= cdns3_gadget_probe
,
488 .remove
= cdns3_gadget_remove
,
489 .priv_auto
= sizeof(struct cdns3_gadget_priv
),
490 .flags
= DM_FLAG_ALLOC_PRIV_DMA
,
493 int dm_usb_gadget_handle_interrupts(struct udevice
*dev
)
495 struct cdns3
*cdns
= dev_get_priv(dev
);
497 cdns3_gadget_uboot_handle_interrupt(cdns
);
503 #if defined(CONFIG_SPL_USB_HOST) || \
504 (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST))
505 static int cdns3_host_probe(struct udevice
*dev
)
507 struct cdns3_host_priv
*priv
= dev_get_priv(dev
);
508 struct cdns3
*cdns
= &priv
->cdns
;
512 return cdns3_probe(cdns
);
515 static int cdns3_host_remove(struct udevice
*dev
)
517 struct cdns3_host_priv
*priv
= dev_get_priv(dev
);
518 struct cdns3
*cdns
= &priv
->cdns
;
520 return cdns3_remove(cdns
);
523 U_BOOT_DRIVER(cdns_usb3_host
) = {
524 .name
= "cdns-usb3-host",
526 .of_match
= cdns3_ids
,
527 .probe
= cdns3_host_probe
,
528 .remove
= cdns3_host_remove
,
529 .priv_auto
= sizeof(struct cdns3_host_priv
),
530 .ops
= &xhci_usb_ops
,
531 .flags
= DM_FLAG_ALLOC_PRIV_DMA
,