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