blob: 7e726fead86e409304e9f6c0b0276255bf1e6cc1 [file] [log] [blame]
Patrick Williams8dd68482022-10-04 07:57:18 -05001From 178da5bee196f44c4c10e9804674fe5ac0bc1176 Mon Sep 17 00:00:00 2001
Brad Bishopbec4ebc2022-08-03 09:55:16 -04002From: Rui Miguel Silva <rui.silva@linaro.org>
3Date: Mon, 28 Jun 2021 23:20:55 +0100
Patrick Williams8dd68482022-10-04 07:57:18 -05004Subject: [PATCH 03/26] usb: common: move urb code to common
Brad Bishopbec4ebc2022-08-03 09:55:16 -04005
6Move urb code from musb only use to a more common scope, so other
7drivers in the future can use the handling of urb in usb.
8
9Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Patrick Williams8dd68482022-10-04 07:57:18 -050010Upstream-Status: Accepted [2022.10-rc1]
Brad Bishopbec4ebc2022-08-03 09:55:16 -040011---
12 drivers/usb/common/Makefile | 2 +
13 drivers/usb/common/usb_urb.c | 160 ++++++++++++++++++
14 drivers/usb/host/r8a66597-hcd.c | 30 +---
15 drivers/usb/musb-new/musb_core.c | 2 +-
16 drivers/usb/musb-new/musb_host.c | 2 +-
17 drivers/usb/musb-new/musb_host.h | 2 +-
18 drivers/usb/musb-new/musb_uboot.c | 38 +----
19 drivers/usb/musb-new/musb_uboot.h | 2 +-
20 .../linux/usb/usb_urb_compat.h | 46 ++++-
21 include/usb_defs.h | 32 ++++
22 10 files changed, 240 insertions(+), 76 deletions(-)
23 create mode 100644 drivers/usb/common/usb_urb.c
24 rename drivers/usb/musb-new/usb-compat.h => include/linux/usb/usb_urb_compat.h (60%)
25
26diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
Patrick Williams8dd68482022-10-04 07:57:18 -050027index 3bedbf213f..dc05cb0a50 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -040028--- a/drivers/usb/common/Makefile
29+++ b/drivers/usb/common/Makefile
30@@ -4,5 +4,7 @@
31 #
32
33 obj-$(CONFIG_$(SPL_)DM_USB) += common.o
34+obj-$(CONFIG_USB_MUSB_HCD) += usb_urb.o
35+obj-$(CONFIG_USB_MUSB_UDC) += usb_urb.o
36 obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o fsl-errata.o
37 obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o fsl-errata.o
38diff --git a/drivers/usb/common/usb_urb.c b/drivers/usb/common/usb_urb.c
39new file mode 100644
Patrick Williams8dd68482022-10-04 07:57:18 -050040index 0000000000..be3b6b9f32
Brad Bishopbec4ebc2022-08-03 09:55:16 -040041--- /dev/null
42+++ b/drivers/usb/common/usb_urb.c
43@@ -0,0 +1,160 @@
44+// SPDX-License-Identifier: GPL-2.0
45+/*
46+ * Common code for usb urb handling, based on the musb-new code
47+ *
48+ * Copyright 2021 Linaro, Rui Miguel Silva <rui.silva@linaro.org>
49+ *
50+ */
51+
52+#include <dm/device.h>
53+#include <dm/device_compat.h>
54+#include <linux/usb/usb_urb_compat.h>
55+
56+#include <time.h>
57+#include <usb.h>
58+
59+#if CONFIG_IS_ENABLED(DM_USB)
60+struct usb_device *usb_dev_get_parent(struct usb_device *udev)
61+{
62+ struct udevice *parent = udev->dev->parent;
63+
64+ /*
65+ * When called from usb-uclass.c: usb_scan_device() udev->dev points
66+ * to the parent udevice, not the actual udevice belonging to the
67+ * udev as the device is not instantiated yet.
68+ *
69+ * If dev is an usb-bus, then we are called from usb_scan_device() for
70+ * an usb-device plugged directly into the root port, return NULL.
71+ */
72+ if (device_get_uclass_id(udev->dev) == UCLASS_USB)
73+ return NULL;
74+
75+ /*
76+ * If these 2 are not the same we are being called from
77+ * usb_scan_device() and udev itself is the parent.
78+ */
79+ if (dev_get_parent_priv(udev->dev) != udev)
80+ return udev;
81+
82+ /* We are being called normally, use the parent pointer */
83+ if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
84+ return dev_get_parent_priv(parent);
85+
86+ return NULL;
87+}
88+#else
89+struct usb_device *usb_dev_get_parent(struct usb_device *udev)
90+{
91+ return udev->parent;
92+}
93+#endif
94+
95+static void usb_urb_complete(struct urb *urb)
96+{
97+ urb->dev->status &= ~USB_ST_NOT_PROC;
98+ urb->dev->act_len = urb->actual_length;
99+
100+ if (urb->status == -EINPROGRESS)
101+ urb->status = 0;
102+}
103+
104+void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep,
105+ struct usb_device *dev, int endpoint_type,
106+ unsigned long pipe, void *buffer, int len,
107+ struct devrequest *setup, int interval)
108+{
109+ int epnum = usb_pipeendpoint(pipe);
110+ int is_in = usb_pipein(pipe);
111+ u16 maxpacketsize = is_in ? dev->epmaxpacketin[epnum] :
112+ dev->epmaxpacketout[epnum];
113+
114+ memset(urb, 0, sizeof(struct urb));
115+ memset(hep, 0, sizeof(struct usb_host_endpoint));
116+ INIT_LIST_HEAD(&hep->urb_list);
117+ INIT_LIST_HEAD(&urb->urb_list);
118+ urb->ep = hep;
119+ urb->complete = usb_urb_complete;
120+ urb->status = -EINPROGRESS;
121+ urb->dev = dev;
122+ urb->pipe = pipe;
123+ urb->transfer_buffer = buffer;
124+ urb->transfer_dma = (unsigned long)buffer;
125+ urb->transfer_buffer_length = len;
126+ urb->setup_packet = (unsigned char *)setup;
127+
128+ urb->ep->desc.wMaxPacketSize = __cpu_to_le16(maxpacketsize);
129+ urb->ep->desc.bmAttributes = endpoint_type;
130+ urb->ep->desc.bEndpointAddress = ((is_in ? USB_DIR_IN : USB_DIR_OUT) |
131+ epnum);
132+ urb->ep->desc.bInterval = interval;
133+}
134+
135+int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb)
136+{
137+ const struct usb_urb_ops *ops = hcd->urb_ops;
138+ unsigned long timeout;
139+ int ret;
140+
141+ if (!ops)
142+ return -EINVAL;
143+
144+ ret = ops->urb_enqueue(hcd, urb, 0);
145+ if (ret < 0) {
146+ printf("Failed to enqueue URB to controller\n");
147+ return ret;
148+ }
149+
150+ timeout = get_timer(0) + USB_TIMEOUT_MS(urb->pipe);
151+ do {
152+ if (ctrlc())
153+ return -EIO;
154+ ops->isr(0, hcd);
155+ } while (urb->status == -EINPROGRESS && get_timer(0) < timeout);
156+
157+ if (urb->status == -EINPROGRESS)
158+ ops->urb_dequeue(hcd, urb, -ETIME);
159+
160+ return urb->status;
161+}
162+
163+int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb,
164+ struct usb_host_endpoint *hep,
165+ struct usb_device *dev, unsigned long pipe,
166+ void *buffer, int len, struct devrequest *setup,
167+ int interval, enum usb_device_speed speed)
168+{
169+ const struct usb_urb_ops *ops = hcd->urb_ops;
170+
171+ usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_CONTROL, pipe, buffer,
172+ len, setup, 0);
173+
174+ /* Fix speed for non hub-attached devices */
175+ if (!usb_dev_get_parent(dev)) {
176+ dev->speed = speed;
177+ if (ops->hub_control)
178+ return ops->hub_control(hcd, dev, pipe, buffer, len,
179+ setup);
180+ }
181+
182+ return usb_urb_submit(hcd, urb);
183+}
184+
185+int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb,
186+ struct usb_host_endpoint *hep, struct usb_device *dev,
187+ unsigned long pipe, void *buffer, int len)
188+{
189+ usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_BULK, pipe, buffer, len,
190+ NULL, 0);
191+
192+ return usb_urb_submit(hcd, urb);
193+}
194+
195+int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb,
196+ struct usb_host_endpoint *hep, struct usb_device *dev,
197+ unsigned long pipe, void *buffer, int len, int interval)
198+{
199+ usb_urb_fill(urb, hep, dev, USB_ENDPOINT_XFER_INT, pipe, buffer, len,
200+ NULL, interval);
201+
202+ return usb_urb_submit(hcd, urb);
203+}
204diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
Patrick Williams8dd68482022-10-04 07:57:18 -0500205index f1fc93f3d4..3ccbc16da3 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400206--- a/drivers/usb/host/r8a66597-hcd.c
207+++ b/drivers/usb/host/r8a66597-hcd.c
208@@ -14,6 +14,7 @@
209 #include <dm/device_compat.h>
210 #include <linux/delay.h>
211 #include <linux/iopoll.h>
212+#include <linux/usb/usb_urb_compat.h>
213 #include <power/regulator.h>
214
215 #include "r8a66597.h"
216@@ -24,35 +25,6 @@
217 #define R8A66597_DPRINT(...)
218 #endif
219
220-static inline struct usb_device *usb_dev_get_parent(struct usb_device *udev)
221-{
222- struct udevice *parent = udev->dev->parent;
223-
224- /*
225- * When called from usb-uclass.c: usb_scan_device() udev->dev points
226- * to the parent udevice, not the actual udevice belonging to the
227- * udev as the device is not instantiated yet.
228- *
229- * If dev is an usb-bus, then we are called from usb_scan_device() for
230- * an usb-device plugged directly into the root port, return NULL.
231- */
232- if (device_get_uclass_id(udev->dev) == UCLASS_USB)
233- return NULL;
234-
235- /*
236- * If these 2 are not the same we are being called from
237- * usb_scan_device() and udev itself is the parent.
238- */
239- if (dev_get_parent_priv(udev->dev) != udev)
240- return udev;
241-
242- /* We are being called normally, use the parent pointer */
243- if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
244- return dev_get_parent_priv(parent);
245-
246- return NULL;
247-}
248-
249 static void get_hub_data(struct usb_device *dev, u16 *hub_devnum, u16 *hubport)
250 {
251 struct usb_device *parent = usb_dev_get_parent(dev);
252diff --git a/drivers/usb/musb-new/musb_core.c b/drivers/usb/musb-new/musb_core.c
Patrick Williams8dd68482022-10-04 07:57:18 -0500253index 18d9bc805f..fc7af7484e 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400254--- a/drivers/usb/musb-new/musb_core.c
255+++ b/drivers/usb/musb-new/musb_core.c
256@@ -89,9 +89,9 @@
257 #include <linux/usb/ch9.h>
258 #include <linux/usb/gadget.h>
259 #include <linux/usb/musb.h>
260+#include <linux/usb/usb_urb_compat.h>
261 #include <asm/io.h>
262 #include "linux-compat.h"
263-#include "usb-compat.h"
264 #endif
265
266 #include "musb_core.h"
267diff --git a/drivers/usb/musb-new/musb_host.c b/drivers/usb/musb-new/musb_host.c
Patrick Williams8dd68482022-10-04 07:57:18 -0500268index acb2d40f3b..e5905d90d6 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400269--- a/drivers/usb/musb-new/musb_host.c
270+++ b/drivers/usb/musb-new/musb_host.c
271@@ -26,8 +26,8 @@
272 #include <dm/device_compat.h>
273 #include <usb.h>
274 #include <linux/bug.h>
275+#include <linux/usb/usb_urb_compat.h>
276 #include "linux-compat.h"
277-#include "usb-compat.h"
278 #endif
279
280 #include "musb_core.h"
281diff --git a/drivers/usb/musb-new/musb_host.h b/drivers/usb/musb-new/musb_host.h
Patrick Williams8dd68482022-10-04 07:57:18 -0500282index afc8fa35a7..5a604bdb0c 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400283--- a/drivers/usb/musb-new/musb_host.h
284+++ b/drivers/usb/musb-new/musb_host.h
285@@ -10,7 +10,7 @@
286 #ifndef _MUSB_HOST_H
287 #define _MUSB_HOST_H
288 #ifdef __UBOOT__
289-#include "usb-compat.h"
290+#include <linux/usb/usb_urb_compat.h>
291 #endif
292
293 static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
294diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
Patrick Williams8dd68482022-10-04 07:57:18 -0500295index 61ff68def2..d186facc7e 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400296--- a/drivers/usb/musb-new/musb_uboot.c
297+++ b/drivers/usb/musb-new/musb_uboot.c
298@@ -8,10 +8,10 @@
299 #include <linux/errno.h>
300 #include <linux/usb/ch9.h>
301 #include <linux/usb/gadget.h>
302+#include <linux/usb/usb_urb_compat.h>
303
304 #include <usb.h>
305 #include "linux-compat.h"
306-#include "usb-compat.h"
307 #include "musb_core.h"
308 #include "musb_host.h"
309 #include "musb_gadget.h"
310@@ -453,39 +453,3 @@ struct musb *musb_register(struct musb_hdrc_platform_data *plat, void *bdata,
311
312 return *musbp;
313 }
314-
315-#if CONFIG_IS_ENABLED(DM_USB)
316-struct usb_device *usb_dev_get_parent(struct usb_device *udev)
317-{
318- struct udevice *parent = udev->dev->parent;
319-
320- /*
321- * When called from usb-uclass.c: usb_scan_device() udev->dev points
322- * to the parent udevice, not the actual udevice belonging to the
323- * udev as the device is not instantiated yet.
324- *
325- * If dev is an usb-bus, then we are called from usb_scan_device() for
326- * an usb-device plugged directly into the root port, return NULL.
327- */
328- if (device_get_uclass_id(udev->dev) == UCLASS_USB)
329- return NULL;
330-
331- /*
332- * If these 2 are not the same we are being called from
333- * usb_scan_device() and udev itself is the parent.
334- */
335- if (dev_get_parent_priv(udev->dev) != udev)
336- return udev;
337-
338- /* We are being called normally, use the parent pointer */
339- if (device_get_uclass_id(parent) == UCLASS_USB_HUB)
340- return dev_get_parent_priv(parent);
341-
342- return NULL;
343-}
344-#else
345-struct usb_device *usb_dev_get_parent(struct usb_device *udev)
346-{
347- return udev->parent;
348-}
349-#endif
350diff --git a/drivers/usb/musb-new/musb_uboot.h b/drivers/usb/musb-new/musb_uboot.h
Patrick Williams8dd68482022-10-04 07:57:18 -0500351index 18282efccc..6b162f03b1 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400352--- a/drivers/usb/musb-new/musb_uboot.h
353+++ b/drivers/usb/musb-new/musb_uboot.h
354@@ -8,8 +8,8 @@
355 #define __MUSB_UBOOT_H__
356
357 #include <usb.h>
358+#include <linux/usb/usb_urb_compat.h>
359 #include "linux-compat.h"
360-#include "usb-compat.h"
361 #include "musb_core.h"
362
363 struct musb_host_data {
364diff --git a/drivers/usb/musb-new/usb-compat.h b/include/linux/usb/usb_urb_compat.h
365similarity index 60%
366rename from drivers/usb/musb-new/usb-compat.h
367rename to include/linux/usb/usb_urb_compat.h
Patrick Williams8dd68482022-10-04 07:57:18 -0500368index df68c9220a..5ed96fa64e 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400369--- a/drivers/usb/musb-new/usb-compat.h
370+++ b/include/linux/usb/usb_urb_compat.h
371@@ -1,16 +1,31 @@
372-#ifndef __USB_COMPAT_H__
373-#define __USB_COMPAT_H__
374+#ifndef __USB_URB_COMPAT_H__
375+#define __USB_URB_COMPAT_H__
376
377-#include "usb.h"
378+#include <linux/compat.h>
379+#include <usb.h>
380
381 struct udevice;
382+struct urb;
383+struct usb_hcd;
384+
385+
386+struct usb_urb_ops {
387+ int (*urb_enqueue)(struct usb_hcd *hcd, struct urb *urb,
388+ gfp_t mem_flags);
389+ int (*urb_dequeue)(struct usb_hcd *hcd, struct urb *urb, int status);
390+ int (*hub_control)(struct usb_hcd *hcd, struct usb_device *dev,
391+ unsigned long pipe, void *buffer, int len,
392+ struct devrequest *setup);
393+ irqreturn_t (*isr)(int irq, void *priv);
394+};
395
396 struct usb_hcd {
397 void *hcd_priv;
398+ const struct usb_urb_ops *urb_ops;
399 };
400
401 struct usb_host_endpoint {
402- struct usb_endpoint_descriptor desc;
403+ struct usb_endpoint_descriptor desc;
404 struct list_head urb_list;
405 void *hcpriv;
406 };
407@@ -23,8 +38,6 @@ struct usb_host_endpoint {
408 #define URB_SHORT_NOT_OK 0x0001 /* report short reads as errors */
409 #define URB_ZERO_PACKET 0x0040 /* Finish bulk OUT with short packet */
410
411-struct urb;
412-
413 typedef void (*usb_complete_t)(struct urb *);
414
415 struct urb {
416@@ -76,4 +89,25 @@ static inline int usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd,
417 */
418 struct usb_device *usb_dev_get_parent(struct usb_device *udev);
419
420+int usb_urb_submit_control(struct usb_hcd *hcd, struct urb *urb,
421+ struct usb_host_endpoint *hep,
422+ struct usb_device *dev, unsigned long pipe,
423+ void *buffer, int len, struct devrequest *setup,
424+ int interval, enum usb_device_speed speed);
425+
426+int usb_urb_submit_bulk(struct usb_hcd *hcd, struct urb *urb,
427+ struct usb_host_endpoint *hep, struct usb_device *dev,
428+ unsigned long pipe, void *buffer, int len);
429+
430+int usb_urb_submit_irq(struct usb_hcd *hcd, struct urb *urb,
431+ struct usb_host_endpoint *hep, struct usb_device *dev,
432+ unsigned long pipe, void *buffer, int len, int interval);
433+
434+void usb_urb_fill(struct urb *urb, struct usb_host_endpoint *hep,
435+ struct usb_device *dev, int endpoint_type,
436+ unsigned long pipe, void *buffer, int len,
437+ struct devrequest *setup, int interval);
438+
439+int usb_urb_submit(struct usb_hcd *hcd, struct urb *urb);
440+
441 #endif /* __USB_COMPAT_H__ */
442diff --git a/include/usb_defs.h b/include/usb_defs.h
Patrick Williams8dd68482022-10-04 07:57:18 -0500443index 6dd2c997f9..ec00161710 100644
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400444--- a/include/usb_defs.h
445+++ b/include/usb_defs.h
446@@ -81,6 +81,32 @@
447 #define EndpointOutRequest \
448 ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8)
449
450+/* class requests from the USB 2.0 hub spec, table 11-15 */
451+#define HUB_CLASS_REQ(dir, type, request) ((((dir) | (type)) << 8) | (request))
452+/* GetBusState and SetHubDescriptor are optional, omitted */
453+#define ClearHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, \
454+ USB_REQ_CLEAR_FEATURE)
455+#define ClearPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \
456+ USB_REQ_CLEAR_FEATURE)
457+#define GetHubDescriptor HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, \
458+ USB_REQ_GET_DESCRIPTOR)
459+#define GetHubStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_HUB, \
460+ USB_REQ_GET_STATUS)
461+#define GetPortStatus HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, \
462+ USB_REQ_GET_STATUS)
463+#define SetHubFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_HUB, \
464+ USB_REQ_SET_FEATURE)
465+#define SetPortFeature HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \
466+ USB_REQ_SET_FEATURE)
467+#define ClearTTBuffer HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \
468+ HUB_CLEAR_TT_BUFFER)
469+#define ResetTT HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \
470+ HUB_RESET_TT)
471+#define GetTTState HUB_CLASS_REQ(USB_DIR_IN, USB_RT_PORT, \
472+ HUB_GET_TT_STATE)
473+#define StopTT HUB_CLASS_REQ(USB_DIR_OUT, USB_RT_PORT, \
474+ HUB_STOP_TT)
475+
476 /* Descriptor types */
477 #define USB_DT_DEVICE 0x01
478 #define USB_DT_CONFIG 0x02
479@@ -289,10 +315,16 @@
480 #define USB_SS_PORT_STAT_C_CONFIG_ERROR 0x0080
481
482 /* wHubCharacteristics (masks) */
483+#define HUB_CHAR_COMMON_OCPM 0x0000 /* All ports Over-Current reporting */
484+#define HUB_CHAR_INDV_PORT_LPSM 0x0001 /* per-port power control */
485+#define HUB_CHAR_NO_LPSM 0x0002 /* no power switching */
486 #define HUB_CHAR_LPSM 0x0003
487 #define HUB_CHAR_COMPOUND 0x0004
488+#define HUB_CHAR_INDV_PORT_OCPM 0x0008 /* per-port Over-current reporting */
489+#define HUB_CHAR_NO_OCPM 0x0010 /* No Over-current Protection support */
490 #define HUB_CHAR_OCPM 0x0018
491 #define HUB_CHAR_TTTT 0x0060 /* TT Think Time mask */
492+#define HUB_CHAR_PORTIND 0x0080 /* per-port indicators (LEDs) */
493
494 /*
495 * Hub Status & Hub Change bit masks
496--
Patrick Williams8dd68482022-10-04 07:57:18 -05004972.17.1
Brad Bishopbec4ebc2022-08-03 09:55:16 -0400498