From: Wojciech Dubowik <wojciech.dubowik@mt.com>
To: Sam Day <me@samcday.com>
Cc: u-boot@lists.denx.de
Subject: Re: [PATCH 1/3] usb: udc: ci: support USB gadget driver model
Date: Wed, 4 Jun 2025 09:07:04 +0200 [thread overview]
Message-ID: <aD_wmIj-odxVYLIq@mt.com> (raw)
In-Reply-To: <D9AIEUQMBE8M.2OVJ76ZRNATCM@samcday.com>
On Sat, Apr 19, 2025 at 09:32:04AM +0000, Sam Day wrote:
> Heya Stephan,
>
> On Wed Apr 16, 2025 at 8:51 PM CEST, Stephan Gerhold wrote:
> > On Sat, Apr 12, 2025 at 07:39:57PM +0000, Sam Day wrote:
> >> When CONFIG_DM_USB_GADGET is enabled, a UCLASS_USB_GADGET_GENERIC driver
> >> will be defined that wraps the ChipIdea UDC operations. The
> >> (dm_)?usb_gadget_.* symbols will no longer be defined (as these are now
> >> handled by the UDC uclass).
> >>
> >> If CONFIG_DM_USB_GADGET is not enabled, this driver behaves as it
> >> previously did.
> >>
> >> This new driver does not declare any compatibles of its own. It requires
> >> a glue driver to bind it. The ehci_msm driver will be updated in the
> >> following commit to do exactly that.
> >>
> >> Signed-off-by: Sam Day <me at samcday.com>
> >
> > Thanks a lot for working on this. Seems to work without problems on my
> > dragonboard410c. Just some minor nits below to reduce code duplication.
>
> \0/ Thanks for the review and testing!
>
> >
> >> ---
> >> drivers/usb/gadget/ci_udc.c | 84 ++++++++++++++++++++++++++++++++++++++++++++-
> >> 1 file changed, 83 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/drivers/usb/gadget/ci_udc.c b/drivers/usb/gadget/ci_udc.c
> >> index 4bff75da759ded6716641713fbe47f6ba79386dc..179f8540da30c693d11d772aacc00cc37f7669c5 100644
> >> --- a/drivers/usb/gadget/ci_udc.c
> >> +++ b/drivers/usb/gadget/ci_udc.c
> >> @@ -10,6 +10,7 @@
> >> #include <command.h>
> >> #include <config.h>
> >> #include <cpu_func.h>
> >> +#include <dm.h>
> >> #include <net.h>
> >> #include <malloc.h>
> >> #include <wait_bit.h>
> >> @@ -94,8 +95,18 @@ static struct usb_request *
> >> ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags);
> >> static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req);
> >>
> >> +#if CONFIG_IS_ENABLED(DM_USB_GADGET)
> >> +static int ci_udc_gadget_start(struct usb_gadget *g,
> >> + struct usb_gadget_driver *driver);
> >> +static int ci_udc_gadget_stop(struct usb_gadget *g);
> >> +#endif
> >> +
> >> static const struct usb_gadget_ops ci_udc_ops = {
> >> .pullup = ci_pullup,
> >> +#if CONFIG_IS_ENABLED(DM_USB_GADGET)
> >> + .udc_start = ci_udc_gadget_start,
> >> + .udc_stop = ci_udc_gadget_stop,
> >> +#endif
> >> };
> >>
> >> static const struct usb_ep_ops ci_ep_ops = {
> >> @@ -927,7 +938,7 @@ void udc_irq(void)
> >> }
> >> }
> >>
> >> -int dm_usb_gadget_handle_interrupts(struct udevice *dev)
> >> +static int ci_udc_handle_interrupts(struct udevice *dev)
> >> {
> >> struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor;
> >> u32 value;
> >> @@ -1072,6 +1083,71 @@ static int ci_udc_probe(void)
> >> return 0;
> >> }
> >>
> >> +#if CONFIG_IS_ENABLED(DM_USB_GADGET)
> >> +static int ci_udc_generic_probe(struct udevice *dev)
> >> +{
> >> + int ret;
> >> +#if CONFIG_IS_ENABLED(DM_USB)
> >> + ret = usb_setup_ehci_gadget(&controller.ctrl);
> >> +#else
> >> + ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
> >> +#endif
> >
> > ...
> >
> >> [...]
> >> +static int ci_udc_generic_remove(struct udevice *dev)
> >> +{
> >> + usb_del_gadget_udc(&controller.gadget);
> >> +
> >> + if (IS_ENABLED(CONFIG_DM_USB)) {
> >> + usb_remove_ehci_gadget(&controller.ctrl);
> >> + } else {
> >> + usb_lowlevel_stop(0);
> >> + controller.ctrl = NULL;
> >> + }
> >
> > This style is nice for compile testing. But in the probe() function
> > above you're still using the #if/#else pre-processor style. Can it use
> > if (IS_ENABLED(...)) too?
>
> Ah, I had converted a few of these when checkpatch reprimanded me. Guess
> I missed this one - oops!
>
> >
> > if (IS_ENABLED(CONFIG_DM_USB))
> > ret = usb_setup_ehci_gadget(&controller.ctrl);
> > else
> > ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl);
> > if (ret)
> > return ret;
> >
> > This seems to compile at least.
> >
> > If yes, can you make the same cleanup for the old !DM_USB_GADGET case,
> > so the two code paths are consistent?
>
> Thanks, I've done this in v2.
>
> >
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +static const struct usb_gadget_generic_ops ci_udc_generic_ops = {
> >> + .handle_interrupts = ci_udc_handle_interrupts,
> >> +};
> >> +
> >> +U_BOOT_DRIVER(ci_udc_generic) = {
> >> + .name = "ci-udc",
> >> + .id = UCLASS_USB_GADGET_GENERIC,
> >> + .ops = &ci_udc_generic_ops,
> >> + .probe = ci_udc_generic_probe,
> >> + .remove = ci_udc_generic_remove,
> >> +};
> >> +
> >> +static int ci_udc_gadget_start(struct usb_gadget *g,
> >> + struct usb_gadget_driver *driver)
> >> +{
> >> + controller.driver = driver;
> >> + return 0;
> >> +}
> >> +
> >> +static int ci_udc_gadget_stop(struct usb_gadget *g)
> >> +{
> >> + controller.driver = NULL;
> >> + udc_disconnect();
> >> +
> >> + ci_ep_free_request(&controller.ep[0].ep, &controller.ep0_req->req);
> >> + free(controller.items_mem);
> >> + free(controller.epts);
> >> +
> >> + return 0;
> >> +}
> >
> > I wonder if you could just define the start and stop function outside
> > the #if blocks and call them from usb_gadget_unregister_driver()
> > and usb_gadget_register_driver(). This would avoid duplicating the code,
> > reducing the risk that someone forgets to update one of those when
> > making changes.
>
> So, not quite unfortunately. In the case of ci_udc_gadget_stop(), the
> controller.driver = NULL happening before calling into udc_disconnect()
> is important: the generic UDC uclass code has already called
> driver->disconnect() and calling it again is a Very Bad Thing to do. So
> we can't just delegate usb_gadget_unregister_driver to
> ci_udc_gadget_stop outright.
>
> In v2 I've tried to unify the codepaths as much as possible though,
> both to avoid duplication and the risks of future patches making
> incomplete changes.
>
> >
> > The same could be also said for probe()/remove(), i.e. moving the
> >
> > if (IS_ENABLED(CONFIG_DM_USB)) {
> > usb_remove_ehci_gadget(&controller.ctrl);
> > } else {
> > usb_lowlevel_stop(0);
> > controller.ctrl = NULL;
> > }
> >
> > block to a separate function and calling that from both variants. Not
> > sure if that would also be worth it?
>
> Good call, these ones are less problematic, and I've done that in v2.
Hello Sam,
Are you going to send v2 soon? I am just asking as I had something similar
in the pipeline.
Regrads,
Wojtek
>
> Rock on \m/,
> -Sam
>
> >
> > Thanks,
> > Stephan
>
>
next prev parent reply other threads:[~2025-06-04 12:48 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-12 19:39 [PATCH 0/3] Support MSM8916 USB PHY + UDC in qcom_defconfig Sam Day
2025-04-12 19:39 ` [PATCH 1/3] usb: udc: ci: support USB gadget driver model Sam Day
2025-04-16 18:51 ` Stephan Gerhold
2025-04-19 9:32 ` Sam Day
2025-06-04 7:07 ` Wojciech Dubowik [this message]
2025-04-12 19:40 ` [PATCH 2/3] usb: host: ehci-msm: Register ChipIdea UDC from glue wrapper Sam Day
2025-04-16 18:57 ` Stephan Gerhold
2025-04-12 19:40 ` [PATCH 3/3] qcom_defconfig: Enable MSM8916 USB PHY + ChipIdea UDC Sam Day
2025-04-16 19:03 ` Stephan Gerhold
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aD_wmIj-odxVYLIq@mt.com \
--to=wojciech.dubowik@mt.com \
--cc=me@samcday.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.