devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Roger Quadros <rogerq@ti.com>
To: Pawel Laszczak <pawell@cadence.com>, devicetree@vger.kernel.org
Cc: gregkh@linuxfoundation.org, linux-usb@vger.kernel.org,
	linux-kernel@vger.kernel.org, adouglas@cadence.com,
	jbergsagel@ti.com, nsekhar@ti.com, nm@ti.com,
	sureshp@cadence.com, peter.chen@nxp.com, pjez@cadence.com,
	kurahul@cadence.com
Subject: Re: [RFC PATCH v2 06/15] usb:cdns3: Adds Host support
Date: Fri, 23 Nov 2018 16:23:00 +0200	[thread overview]
Message-ID: <5BF80D44.2050600@ti.com> (raw)
In-Reply-To: <1542535751-16079-7-git-send-email-pawell@cadence.com>

On 18/11/18 12:09, Pawel Laszczak wrote:
> Patch adds host-export.h and host.c file and mplements functions that
> allow to initialize, start and stop XHCI host driver.
> 
> Signed-off-by: Pawel Laszczak <pawell@cadence.com>
> ---
>  drivers/usb/cdns3/Kconfig       |  10 ++
>  drivers/usb/cdns3/Makefile      |   1 +
>  drivers/usb/cdns3/core.c        |   7 +-
>  drivers/usb/cdns3/host-export.h |  30 ++++
>  drivers/usb/cdns3/host.c        | 256 ++++++++++++++++++++++++++++++++
>  5 files changed, 302 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/usb/cdns3/host-export.h
>  create mode 100644 drivers/usb/cdns3/host.c
> 
> diff --git a/drivers/usb/cdns3/Kconfig b/drivers/usb/cdns3/Kconfig
> index eb22a8692991..d92bc3d68eb0 100644
> --- a/drivers/usb/cdns3/Kconfig
> +++ b/drivers/usb/cdns3/Kconfig
> @@ -10,6 +10,16 @@ config USB_CDNS3
>  
>  if USB_CDNS3
>  
> +config USB_CDNS3_HOST
> +        bool "Cadence USB3 host controller"
> +        depends on USB_XHCI_HCD
> +        help
> +          Say Y here to enable host controller functionality of the
> +          cadence driver.
> +
> +          Host controller is compliance with XHCI so it will use
> +          standard XHCI driver.
> +
>  config USB_CDNS3_PCI_WRAP
>  	tristate "PCIe-based Platforms"
>  	depends on USB_PCI && ACPI
> diff --git a/drivers/usb/cdns3/Makefile b/drivers/usb/cdns3/Makefile
> index e779b2a2f8eb..976117ba67ff 100644
> --- a/drivers/usb/cdns3/Makefile
> +++ b/drivers/usb/cdns3/Makefile
> @@ -2,4 +2,5 @@ obj-$(CONFIG_USB_CDNS3)			+= cdns3.o
>  obj-$(CONFIG_USB_CDNS3_PCI_WRAP)	+= cdns3-pci.o
>  
>  cdns3-y					:= core.o drd.o
> +cdns3-$(CONFIG_USB_CDNS3_HOST)          += host.o
>  cdns3-pci-y		 		:= cdns3-pci-wrap.o
> diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c
> index dbee4325da7f..4cb820be9ff3 100644
> --- a/drivers/usb/cdns3/core.c
> +++ b/drivers/usb/cdns3/core.c
> @@ -17,6 +17,7 @@
>  
>  #include "gadget.h"
>  #include "core.h"
> +#include "host-export.h"
>  #include "drd.h"
>  
>  static inline struct cdns3_role_driver *cdns3_get_current_role_driver(struct cdns3 *cdns)
> @@ -98,7 +99,8 @@ static int cdns3_core_init_role(struct cdns3 *cdns)
>  	}
>  
>  	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST) {
> -		//TODO: implements host initialization
> +		if (cdns3_host_init(cdns))
> +			dev_info(dev, "doesn't support host\n");

dev_err()

And you need to error out with error code.

>  	}
>  
>  	if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_PERIPHERAL) {
> @@ -142,7 +144,7 @@ static irqreturn_t cdns3_irq(int irq, void *data)
>  
>  static void cdns3_remove_roles(struct cdns3 *cdns)
>  {
> -	//TODO: implements this function

if (dr_mode == USB_DR_MODE_OTG || dr_mode == USB_DR_MODE_HOST)

> +	cdns3_host_remove(cdns);

How about calling it cdns3_host_exit() to complement cdns3_host_init().

>  }
>  
>  static int cdns3_do_role_switch(struct cdns3 *cdns, enum cdns3_roles role)
> @@ -410,6 +412,7 @@ static struct platform_driver cdns3_driver = {
>  
>  static int __init cdns3_driver_platform_register(void)
>  {
> +	cdns3_host_driver_init();
>  	return platform_driver_register(&cdns3_driver);
>  }
>  module_init(cdns3_driver_platform_register);
> diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h
> new file mode 100644
> index 000000000000..f8f3b230b472
> --- /dev/null
> +++ b/drivers/usb/cdns3/host-export.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Cadence USBSS DRD Driver -Host Export APIs
> + *
> + * Copyright (C) 2017 NXP
> + *
> + * Authors: Peter Chen <peter.chen@nxp.com>
> + */
> +#ifndef __LINUX_CDNS3_HOST_EXPORT
> +#define __LINUX_CDNS3_HOST_EXPORT
> +
> +#ifdef CONFIG_USB_CDNS3_HOST
> +
> +int cdns3_host_init(struct cdns3 *cdns);
> +void cdns3_host_remove(struct cdns3 *cdns);
> +void cdns3_host_driver_init(void);
> +
> +#else
> +
> +static inline int cdns3_host_init(struct cdns3 *cdns)
> +{
> +	return -ENXIO;
> +}
> +
> +static inline void cdns3_host_remove(struct cdns3 *cdns) { }
> +static inline void cdns3_host_driver_init(void) {}
> +
> +#endif /* CONFIG_USB_CDNS3_HOST */
> +
> +#endif /* __LINUX_CDNS3_HOST_EXPORT */
> diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c
> new file mode 100644
> index 000000000000..0dd47976cb28
> --- /dev/null
> +++ b/drivers/usb/cdns3/host.c
> @@ -0,0 +1,256 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Cadence USBSS DRD Driver - host side
> + *
> + * Copyright (C) 2018 Cadence Design Systems.
> + * Copyright (C) 2018 NXP
> + *
> + * Authors: Peter Chen <peter.chen@nxp.com>
> + *	    Pawel Laszczak <pawell@cadence.com>
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/usb.h>
> +#include <linux/usb/hcd.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/usb/of.h>
> +
> +#include "../host/xhci.h"
> +#include "core.h"
> +#include "host-export.h"
> +
> +static struct hc_driver __read_mostly xhci_cdns3_hc_driver;
> +
> +static void xhci_cdns3_quirks(struct device *dev, struct xhci_hcd *xhci)
> +{
> +	/*
> +	 * As of now platform drivers don't provide MSI support so we ensure
> +	 * here that the generic code does not try to make a pci_dev from our
> +	 * dev struct in order to setup MSI
> +	 */
> +	xhci->quirks |= XHCI_PLAT;
> +}
> +
> +static int xhci_cdns3_setup(struct usb_hcd *hcd)
> +{
> +	struct xhci_hcd	*xhci = hcd_to_xhci(hcd);
> +	u32 command;
> +	int ret;
> +
> +	ret = xhci_gen_setup(hcd, xhci_cdns3_quirks);
> +	if (ret)
> +		return ret;
> +
> +	/* set usbcmd.EU3S */
> +	command = readl(&xhci->op_regs->command);
> +	command |= CMD_PM_INDEX;
> +	writel(command, &xhci->op_regs->command);
> +
> +	return 0;
> +}
> +
> +static const struct xhci_driver_overrides xhci_cdns3_overrides __initconst = {
> +	.extra_priv_size = sizeof(struct xhci_hcd),
> +	.reset = xhci_cdns3_setup,
> +};
> +
> +struct cdns3_host {
> +	struct device dev;
> +	struct usb_hcd *hcd;
> +};
> +
> +static irqreturn_t cdns3_host_irq(struct cdns3 *cdns)
> +{
> +	struct device *dev = cdns->host_dev;
> +	struct usb_hcd	*hcd;
> +
> +	if (dev)
> +		hcd = dev_get_drvdata(dev);
> +	else
> +		return IRQ_NONE;
> +
> +	if (hcd)
> +		return usb_hcd_irq(cdns->irq, hcd);
> +	else
> +		return IRQ_NONE;

Why can't you just reuse the xhci-platform driver and let it manage the IRQ?
Since it is a shared IRQ, different drivers can request the same IRQ and return IRQ_NONE
if the IRQ wasn't from their device.

> +}
> +
> +static void cdns3_host_release(struct device *dev)
> +{
> +	struct cdns3_host *host = container_of(dev, struct cdns3_host, dev);
> +
> +	kfree(host);
> +}
> +
> +static int cdns3_host_start(struct cdns3 *cdns)
> +{
> +	struct cdns3_host *host;
> +	struct device *dev;
> +	struct device *sysdev;
> +	struct xhci_hcd	*xhci;
> +	int ret;
> +
> +	host = kzalloc(sizeof(*host), GFP_KERNEL);
> +	if (!host)
> +		return -ENOMEM;
> +
> +	dev = &host->dev;
> +	dev->release = cdns3_host_release;
> +	dev->parent = cdns->dev;
> +	dev_set_name(dev, "xhci-cdns3");
> +	cdns->host_dev = dev;
> +	ret = device_register(dev);
> +	if (ret)
> +		goto err1;
> +
> +	sysdev = cdns->dev;
> +	/* Try to set 64-bit DMA first */
> +	if (WARN_ON(!sysdev->dma_mask))
> +		/* Platform did not initialize dma_mask */
> +		ret = dma_coerce_mask_and_coherent(sysdev,
> +						   DMA_BIT_MASK(64));
> +	else
> +		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(64));
> +
> +	/* If setting 64-bit DMA mask fails, fall back to 32-bit DMA mask */
> +	if (ret) {
> +		ret = dma_set_mask_and_coherent(sysdev, DMA_BIT_MASK(32));
> +		if (ret)
> +			return ret;
> +	}
> +
> +	pm_runtime_set_active(dev);
> +	pm_runtime_no_callbacks(dev);
> +	pm_runtime_enable(dev);
> +	host->hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
> +				     dev_name(dev), NULL);
> +	if (!host->hcd) {
> +		ret = -ENOMEM;
> +		goto err2;
> +	}
> +
> +	host->hcd->regs = cdns->xhci_regs;
> +	host->hcd->rsrc_start = cdns->xhci_res->start;
> +	host->hcd->rsrc_len = resource_size(cdns->xhci_res);
> +
> +	device_wakeup_enable(host->hcd->self.controller);
> +	xhci = hcd_to_xhci(host->hcd);
> +
> +	xhci->main_hcd = host->hcd;
> +	xhci->shared_hcd = __usb_create_hcd(&xhci_cdns3_hc_driver, sysdev, dev,
> +					    dev_name(dev), host->hcd);
> +	if (!xhci->shared_hcd) {
> +		ret = -ENOMEM;
> +		goto err3;
> +	}
> +
> +	host->hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
> +	xhci->shared_hcd->tpl_support = host->hcd->tpl_support;
> +	ret = usb_add_hcd(host->hcd, 0, IRQF_SHARED);
> +	if (ret)
> +		goto err4;
> +
> +	ret = usb_add_hcd(xhci->shared_hcd, 0, IRQF_SHARED);
> +	if (ret)
> +		goto err5;
> +
> +	device_set_wakeup_capable(dev, true);

All this is being done by the xhci-plat.c

You can make use of it by just creating a xhci-hcd platform device.

e.g.
platform_device_alloc("xhci-hcd", PLATFORM_DEVID_AUTO);
platform_device_add_resources() to add IRQ and memory resource.
platform_device_add_properties() to add any quirks.
platform_device_add()


> +
> +	return 0;
> +
> +err5:
> +	usb_remove_hcd(host->hcd);
> +err4:
> +	usb_put_hcd(xhci->shared_hcd);
> +err3:
> +	usb_put_hcd(host->hcd);
> +err2:
> +	device_del(dev);
> +err1:
> +	put_device(dev);
> +	cdns->host_dev = NULL;
> +	return ret;
> +}
> +
> +static void cdns3_host_stop(struct cdns3 *cdns)
> +{
> +	struct device *dev = cdns->host_dev;
> +	struct xhci_hcd	*xhci;
> +	struct usb_hcd	*hcd;
> +
> +	if (dev) {
> +		hcd = dev_get_drvdata(dev);
> +		xhci = hcd_to_xhci(hcd);
> +		usb_remove_hcd(xhci->shared_hcd);
> +		usb_remove_hcd(hcd);
> +		synchronize_irq(cdns->irq);
> +		usb_put_hcd(xhci->shared_hcd);
> +		usb_put_hcd(hcd);
> +		cdns->host_dev = NULL;
> +		pm_runtime_set_suspended(dev);
> +		pm_runtime_disable(dev);
> +		device_del(dev);
> +		put_device(dev);
> +	}

You can replace this with just
	platform_device_unregister(xhci_dev);

> +}
> +
> +#if CONFIG_PM
> +static int cdns3_host_suspend(struct cdns3 *cdns, bool do_wakeup)
> +{
> +	struct device *dev = cdns->host_dev;
> +	struct xhci_hcd	*xhci;
> +
> +	if (!dev)
> +		return 0;
> +
> +	xhci = hcd_to_xhci(dev_get_drvdata(dev));
> +	return xhci_suspend(xhci, do_wakeup);
> +}
> +
> +static int cdns3_host_resume(struct cdns3 *cdns, bool hibernated)
> +{
> +	struct device *dev = cdns->host_dev;
> +	struct xhci_hcd	*xhci;
> +
> +	if (!dev)
> +		return 0;
> +
> +	xhci = hcd_to_xhci(dev_get_drvdata(dev));
> +	return xhci_resume(xhci, hibernated);
> +}

These won't be required any more as xhci-plat is doing this.

> +#endif /* CONFIG_PM */
> +
> +int cdns3_host_init(struct cdns3 *cdns)
> +{
> +	struct cdns3_role_driver *rdrv;
> +
> +	rdrv = devm_kzalloc(cdns->dev, sizeof(*rdrv), GFP_KERNEL);
> +	if (!rdrv)
> +		return -ENOMEM;
> +
> +	rdrv->start	= cdns3_host_start;
> +	rdrv->stop	= cdns3_host_stop;
> +	rdrv->irq	= cdns3_host_irq;
> +#if CONFIG_PM
> +	rdrv->suspend	= cdns3_host_suspend;
> +	rdrv->resume	= cdns3_host_resume;
> +#endif /* CONFIG_PM */
> +	rdrv->name	= "host";
> +	cdns->roles[CDNS3_ROLE_HOST] = rdrv;
> +
> +	return 0;
> +}
> +
> +void cdns3_host_remove(struct cdns3 *cdns)
> +{
> +	cdns3_host_stop(cdns);

calling cdns3_host_stop() here can lead to problems as Controller might be in
peripheral mode at this point. The core driver needs to ensure that relevant role
is stopped before calling cdns3_host_remove().

Here you need to unregister the role driver though.

cdns->roles[CDNS3_ROLE_HOST] = NULL;

> +}
> +
> +void __init cdns3_host_driver_init(void)
> +{
> +	xhci_init_driver(&xhci_cdns3_hc_driver, &xhci_cdns3_overrides);
> +}
> 

cheers,
-roger

-- 
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

  reply	other threads:[~2018-11-23 14:23 UTC|newest]

Thread overview: 85+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-11-18 10:08 [RFC PATCH v2 00/15] Introduced new Cadence USBSS DRD Driver Pawel Laszczak
2018-11-18 10:08 ` [RFC PATCH v2 01/15] usb:cdns3: add pci to platform driver wrapper Pawel Laszczak
2018-11-23 10:44   ` Roger Quadros
2018-11-18 10:08 ` [RFC PATCH v2 02/15] usb:cdns3: Device side header file Pawel Laszczak
2018-11-30  6:48   ` PETER CHEN
2018-12-02 19:27     ` Pawel Laszczak
2018-11-18 10:08 ` [RFC PATCH v2 03/15] dt-bindings: add binding for USBSS-DRD controller Pawel Laszczak
2018-11-23 10:53   ` Roger Quadros
2018-11-25  7:33     ` Pawel Laszczak
2018-12-04 22:41   ` Rob Herring
2018-12-06 10:26     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 04/15] usb:cdns3: Driver initialization code Pawel Laszczak
2018-11-23 11:35   ` Roger Quadros
2018-11-25 12:35     ` Pawel Laszczak
2018-12-04  9:09       ` Peter Chen
2018-12-06  7:00         ` Pawel Laszczak
2018-12-04  8:50     ` Peter Chen
2018-12-04 10:46       ` Roger Quadros
2018-12-05  8:57         ` Peter Chen
2018-12-06  9:31         ` Pawel Laszczak
2018-12-05 19:24       ` Pawel Laszczak
2018-12-05 19:42       ` Pawel Laszczak
2018-12-06 10:02         ` Pawel Laszczak
2018-11-30  7:32   ` Peter Chen
2018-12-02 20:34     ` Pawel Laszczak
2018-12-04  7:11       ` Peter Chen
2018-12-05  7:19         ` Pawel Laszczak
2018-12-05  8:55           ` Alan Douglas
2018-12-05  9:07             ` Peter Chen
2018-11-18 10:09 ` [RFC PATCH v2 05/15] usb:cdns3: Added DRD support Pawel Laszczak
2018-11-23 14:51   ` Roger Quadros
2018-11-26  7:23     ` Pawel Laszczak
2018-11-26  8:07       ` Roger Quadros
2018-11-26  8:39         ` Pawel Laszczak
2018-11-26  9:39           ` Roger Quadros
2018-11-26 10:09             ` Pawel Laszczak
2018-11-26 10:15               ` Roger Quadros
2018-11-27 11:29       ` Pawel Laszczak
2018-11-27 12:10         ` Roger Quadros
2018-12-04  9:18   ` Peter Chen
2018-12-06  7:25     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 06/15] usb:cdns3: Adds Host support Pawel Laszczak
2018-11-23 14:23   ` Roger Quadros [this message]
2018-11-26  8:24     ` Pawel Laszczak
2018-11-26  9:50       ` Roger Quadros
2018-11-26 10:17         ` Pawel Laszczak
2018-12-05  8:41     ` Peter Chen
2018-11-18 10:09 ` [RFC PATCH v2 07/15] usb:cdns3: Adds Device mode support - initialization Pawel Laszczak
2018-11-28 11:34   ` Roger Quadros
2018-11-28 11:40     ` Felipe Balbi
2018-11-30  4:20       ` PETER CHEN
2018-11-30  6:29         ` Pawel Laszczak
2018-11-30 14:36     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 08/15] usb:cdns3: Implements device operations part of the API Pawel Laszczak
2018-11-28 12:22   ` Roger Quadros
2018-12-01 11:11     ` Pawel Laszczak
2018-12-03 10:19       ` Pawel Laszczak
2018-12-10  2:12     ` Peter Chen
2018-12-11 11:26       ` Sekhar Nori
2018-12-11 19:49         ` Pawel Laszczak
2018-12-14  1:34           ` Peter Chen
2018-12-14  6:49             ` Pawel Laszczak
2018-12-14 10:39             ` Sekhar Nori
2018-12-14 10:47               ` Felipe Balbi
2018-12-14 11:13                 ` Sekhar Nori
2018-12-14 11:26                   ` Felipe Balbi
2018-12-14 12:20                     ` Sekhar Nori
2018-12-14 12:30                       ` Felipe Balbi
2018-12-16 13:31                       ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 09/15] usb:cdns3: EpX " Pawel Laszczak
2018-11-28 12:46   ` Roger Quadros
2018-12-01 13:30     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 10/15] usb:cdns3: Ep0 " Pawel Laszczak
2018-11-28 14:31   ` Roger Quadros
2018-12-02 10:34     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 11/15] usb:cdns3: Implements ISR functionality Pawel Laszczak
2018-11-28 14:54   ` Roger Quadros
2018-12-02 11:49     ` Pawel Laszczak
2018-12-02 12:52       ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 12/15] usb:cdns3: Adds enumeration related function Pawel Laszczak
2018-11-28 15:50   ` Roger Quadros
2018-12-02 16:39     ` Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 13/15] usb:cdns3: Adds transfer " Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 14/15] usb:cdns3: Adds debugging function Pawel Laszczak
2018-11-18 10:09 ` [RFC PATCH v2 15/15] usb:cdns3: Feature for changing role Pawel Laszczak

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=5BF80D44.2050600@ti.com \
    --to=rogerq@ti.com \
    --cc=adouglas@cadence.com \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jbergsagel@ti.com \
    --cc=kurahul@cadence.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=nm@ti.com \
    --cc=nsekhar@ti.com \
    --cc=pawell@cadence.com \
    --cc=peter.chen@nxp.com \
    --cc=pjez@cadence.com \
    --cc=sureshp@cadence.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).