Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a99689ae authored by Mayank Rana's avatar Mayank Rana
Browse files

dwc3: Add QTI MSM platform specific feature and other changes



This change adds QTI MSM platform specific USB related features
and fixes.

Change-Id: I0f733d05f3f88a4a734d8489b5eb548391ab3af3
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent fabaa46d
Loading
Loading
Loading
Loading
+295 −122
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@
#include <linux/of.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
#include <linux/irq.h>

#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -49,6 +50,20 @@

#define DWC3_DEFAULT_AUTOSUSPEND_DELAY	5000 /* ms */

void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend)
{
	u32			reg;

	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));

	if (suspend)
		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
	else
		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;

	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
}

void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
{
	u32 reg;
@@ -57,6 +72,37 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
	reg |= DWC3_GCTL_PRTCAPDIR(mode);
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	/*
	 * Set this bit so that device attempts three more times at SS, even
	 * if it failed previously to operate in SS mode.
	 */
	reg |= DWC3_GCTL_U2RSTECN;
	reg &= ~(DWC3_GCTL_SOFITPSYNC);
	reg &= ~(DWC3_GCTL_PWRDNSCALEMASK);
	reg |= DWC3_GCTL_PWRDNSCALE(2);
	reg |= DWC3_GCTL_U2EXIT_LFPS;
	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	if (mode == DWC3_GCTL_PRTCAP_OTG || mode == DWC3_GCTL_PRTCAP_HOST) {
		/*
		 * Allow ITP generated off of ref clk based counter instead
		 * of UTMI/ULPI clk based counter, when superspeed only is
		 * active so that UTMI/ULPI PHY can be suspened.
		 *
		 * Starting with revision 2.50A, GFLADJ_REFCLK_LPM_SEL is used
		 * instead.
		 */
		if (dwc->revision < DWC3_REVISION_250A) {
			reg = dwc3_readl(dwc->regs, DWC3_GCTL);
			reg |= DWC3_GCTL_SOFITPSYNC;
			dwc3_writel(dwc->regs, DWC3_GCTL, reg);
		} else {
			reg = dwc3_readl(dwc->regs, DWC3_GFLADJ);
			reg |= DWC3_GFLADJ_REFCLK_LPM_SEL;
			dwc3_writel(dwc->regs, DWC3_GFLADJ, reg);
		}
	}
}

u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
@@ -74,17 +120,36 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
}

/**
 * dwc3_core_soft_reset - Issues core soft reset and PHY reset
 * Peforms initialization of HS and SS PHYs.
 * If used as a part of POR or init sequence it is recommended
 * that we should perform hard reset of the PHYs prior to invoking
 * this function.
 * @dwc: pointer to our context structure
*/
static int dwc3_core_soft_reset(struct dwc3 *dwc)
static int dwc3_init_usb_phys(struct dwc3 *dwc)
{
	u32		reg;
	int		retries = 1000;
	int		ret;

	usb_phy_init(dwc->usb2_phy);
	usb_phy_init(dwc->usb3_phy);
	/* Bring up PHYs */
	ret = usb_phy_init(dwc->usb2_phy);
	if (ret) {
		pr_err("%s: usb_phy_init(dwc->usb2_phy) returned %d\n",
				__func__, ret);
		return ret;
	}

	ret = usb_phy_init(dwc->usb3_phy);
	if (ret == -EBUSY) {
		/*
		 * Setting Max speed as high when USB3 PHY initialiation
		 * is failing and USB superspeed can't be supported.
		 */
		dwc->maximum_speed = USB_SPEED_HIGH;
	} else if (ret) {
		pr_err("%s: usb_phy_init(dwc->usb3_phy) returned %d\n",
				__func__, ret);
		return ret;
	}
	ret = phy_init(dwc->usb2_generic_phy);
	if (ret < 0)
		return ret;
@@ -95,27 +160,34 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
		return ret;
	}

	/*
	 * We're resetting only the device side because, if we're in host mode,
	 * XHCI driver will reset the host block. If dwc3 was configured for
	 * host-only mode, then we can return early.
	 */
	if (dwc->dr_mode == USB_DR_MODE_HOST)
	return 0;
}

	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
	reg |= DWC3_DCTL_CSFTRST;
	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
/**
 * dwc3_core_reset - Issues core soft reset and PHY reset
 * @dwc: pointer to our context structure
 */
static int dwc3_core_reset(struct dwc3 *dwc)
{
	int		ret;

	do {
		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
		if (!(reg & DWC3_DCTL_CSFTRST))
			return 0;
	/* Reset PHYs */
	usb_phy_reset(dwc->usb2_phy);
	usb_phy_reset(dwc->usb3_phy);

		udelay(1);
	} while (--retries);
	/* Initialize PHYs */
	ret = dwc3_init_usb_phys(dwc);
	if (ret) {
		pr_err("%s: dwc3_init_phys returned %d\n",
				__func__, ret);
		return ret;
	}

	return -ETIMEDOUT;
	dwc3_notify_event(dwc, DWC3_CONTROLLER_RESET_EVENT);

	dwc3_notify_event(dwc, DWC3_CONTROLLER_POST_RESET_EVENT);

	return 0;
}

/**
@@ -249,7 +321,7 @@ static int dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 *
 * Returns 0 on success otherwise negative errno.
 */
static int dwc3_event_buffers_setup(struct dwc3 *dwc)
int dwc3_event_buffers_setup(struct dwc3 *dwc)
{
	struct dwc3_event_buffer	*evt;

@@ -526,7 +598,7 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 *
 * Returns 0 on success otherwise negative errno.
 */
static int dwc3_core_init(struct dwc3 *dwc)
int dwc3_core_init(struct dwc3 *dwc)
{
	u32			hwparams4 = dwc->hwparams.hwparams4;
	u32			reg;
@@ -561,11 +633,12 @@ static int dwc3_core_init(struct dwc3 *dwc)
	}

	/* issue device SoftReset too */
	ret = dwc3_soft_reset(dwc);
	ret = dwc3_core_reset(dwc);
	if (ret)
		goto err0;

	ret = dwc3_core_soft_reset(dwc);
	/* issue device SoftReset too */
	ret = dwc3_soft_reset(dwc);
	if (ret)
		goto err0;

@@ -639,13 +712,26 @@ static int dwc3_core_init(struct dwc3 *dwc)
	if (dwc->revision < DWC3_REVISION_190A)
		reg |= DWC3_GCTL_U2RSTECN;

	dwc3_core_num_eps(dwc);

	/*
	 * Disable clock gating to work around a known HW bug that causes the
	 * internal RAM clock to get stuck when entering low power modes.
	 */
	if (dwc->disable_clk_gating) {
		dev_dbg(dwc->dev, "Disabling controller clock gating.\n");
		reg |= DWC3_GCTL_DSBLCLKGTNG;
	}

	dwc3_writel(dwc->regs, DWC3_GCTL, reg);

	dwc3_core_num_eps(dwc);
	ret = dwc3_alloc_scratch_buffers(dwc);
	if (ret)
		goto err1;

	ret = dwc3_setup_scratch_buffers(dwc);
	if (ret)
		goto err1;
		goto err2;

	/* Adjust Frame Length */
	dwc3_frame_length_adjustment(dwc);
@@ -656,28 +742,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
	if (ret < 0)
		goto err2;

	ret = phy_power_on(dwc->usb3_generic_phy);
	if (ret < 0)
		goto err3;

	ret = dwc3_event_buffers_setup(dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to setup event buffers\n");
		goto err4;
	/*
	 * clear Elastic buffer mode in GUSBPIPE_CTRL(0) register, otherwise
	 * it results in high link errors and could cause SS mode transfer
	 * failure.
	 */
	if (!dwc->nominal_elastic_buffer) {
		reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
		reg &= ~DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE;
		dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
	}

	return 0;

err4:
	phy_power_off(dwc->usb2_generic_phy);

err3:
	phy_power_off(dwc->usb3_generic_phy);

err2:
	usb_phy_set_suspend(dwc->usb2_phy, 1);
	usb_phy_set_suspend(dwc->usb3_phy, 1);
	dwc3_core_exit(dwc);
	dwc3_free_scratch_buffers(dwc);

err1:
	usb_phy_shutdown(dwc->usb2_phy);
@@ -759,42 +838,16 @@ static int dwc3_core_get_phy(struct dwc3 *dwc)
static int dwc3_core_init_mode(struct dwc3 *dwc)
{
	struct device *dev = dwc->dev;
	int ret;

	switch (dwc->dr_mode) {
	case USB_DR_MODE_PERIPHERAL:
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
		ret = dwc3_gadget_init(dwc);
		if (ret) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "failed to initialize gadget\n");
			return ret;
		}
		break;
	case USB_DR_MODE_HOST:
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
		ret = dwc3_host_init(dwc);
		if (ret) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "failed to initialize host\n");
			return ret;
		}
		break;
	case USB_DR_MODE_OTG:
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
		ret = dwc3_host_init(dwc);
		if (ret) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "failed to initialize host\n");
			return ret;
		}

		ret = dwc3_gadget_init(dwc);
		if (ret) {
			if (ret != -EPROBE_DEFER)
				dev_err(dev, "failed to initialize gadget\n");
			return ret;
		}
		break;
	default:
		dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
@@ -823,6 +876,96 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
	}
}

/* XHCI reset, resets other CORE registers as well, re-init those */
void dwc3_post_host_reset_core_init(struct dwc3 *dwc)
{
	dwc3_core_init(dwc);
	dwc3_gadget_restart(dwc);
}

static void (*notify_event)(struct dwc3 *, unsigned int);
void dwc3_set_notifier(void (*notify)(struct dwc3 *, unsigned int))
{
	notify_event = notify;
}
EXPORT_SYMBOL(dwc3_set_notifier);

int dwc3_notify_event(struct dwc3 *dwc, unsigned int event)
{
	int ret = 0;

	if (dwc->notify_event)
		dwc->notify_event(dwc, event);
	else
		ret = -ENODEV;

	return ret;
}
EXPORT_SYMBOL(dwc3_notify_event);

int dwc3_core_pre_init(struct dwc3 *dwc)
{
	int ret;

	dwc3_cache_hwparams(dwc);

	ret = dwc3_phy_setup(dwc);
	if (ret)
		goto err0;

	if (!dwc->ev_buf) {
		ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
		if (ret) {
			dev_err(dwc->dev, "failed to allocate event buffers\n");
			ret = -ENOMEM;
			goto err1;
		}
	}

	ret = dwc3_core_init(dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to initialize core\n");
		goto err2;
	}

	ret = phy_power_on(dwc->usb2_generic_phy);
	if (ret < 0)
		goto err3;

	ret = phy_power_on(dwc->usb3_generic_phy);
	if (ret < 0)
		goto err4;

	ret = dwc3_event_buffers_setup(dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to setup event buffers\n");
		goto err5;
	}

	ret = dwc3_core_init_mode(dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to set mode with dwc3 core\n");
		goto err6;
	}

	return ret;

err6:
	dwc3_event_buffers_cleanup(dwc);
err5:
	phy_power_off(dwc->usb3_generic_phy);
err4:
	phy_power_off(dwc->usb2_generic_phy);
err3:
	dwc3_core_exit(dwc);
err2:
	dwc3_free_event_buffers(dwc);
err1:
	dwc3_ulpi_exit(dwc);
err0:
	return ret;
}

#define DWC3_ALIGN_MASK		(16 - 1)

static int dwc3_probe(struct platform_device *pdev)
@@ -833,6 +976,7 @@ static int dwc3_probe(struct platform_device *pdev)
	u8			lpm_nyet_threshold;
	u8			tx_de_emphasis;
	u8			hird_threshold;
	int			irq;

	int			ret;

@@ -847,12 +991,37 @@ static int dwc3_probe(struct platform_device *pdev)
	dwc->mem = mem;
	dwc->dev = dev;

	dwc->notify_event = notify_event;
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(dev, "missing IRQ\n");
		return -ENODEV;
	}
	dwc->xhci_resources[1].start = res->start;
	dwc->xhci_resources[1].end = res->end;
	dwc->xhci_resources[1].flags = res->flags;
	dwc->xhci_resources[1].name = res->name;

	irq = platform_get_irq(to_platform_device(dwc->dev), 0);

	/* will be enabled in dwc3_msm_resume() */
	irq_set_status_flags(irq, IRQ_NOAUTOEN);
	ret = devm_request_threaded_irq(dev, irq, NULL, dwc3_interrupt,
			IRQF_SHARED | IRQF_ONESHOT, "dwc3", dwc);
	if (ret) {
		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
				irq, ret);
		return -ENODEV;
	}

	dwc->irq = irq;
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "missing memory resource\n");
		return -ENODEV;
	}

	dwc->reg_phys = res->start;
	dwc->xhci_resources[0].start = res->start;
	dwc->xhci_resources[0].end = dwc->xhci_resources[0].start +
					DWC3_XHCI_REGS_END;
@@ -934,14 +1103,19 @@ static int dwc3_probe(struct platform_device *pdev)
	device_property_read_u32(dev, "snps,quirk-frame-length-adjustment",
				 &dwc->fladj);

	if (dwc->enable_bus_suspend) {
		pm_runtime_set_autosuspend_delay(dev, 500);
		pm_runtime_use_autosuspend(dev);
	}

	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
	dwc->tx_de_emphasis = tx_de_emphasis;

	dwc->hird_threshold = hird_threshold
		| (dwc->is_utmi_l1_suspend << 4);

	init_waitqueue_head(&dwc->wait_linkstate);
	platform_set_drvdata(pdev, dwc);
	dwc3_cache_hwparams(dwc);

	ret = dwc3_core_get_phy(dwc);
	if (ret)
@@ -955,43 +1129,21 @@ static int dwc3_probe(struct platform_device *pdev)
		dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask);
	}

	pm_runtime_no_callbacks(dev);
	pm_runtime_set_active(dev);
	pm_runtime_use_autosuspend(dev);
	pm_runtime_set_autosuspend_delay(dev, DWC3_DEFAULT_AUTOSUSPEND_DELAY);
	pm_runtime_enable(dev);
	ret = pm_runtime_get_sync(dev);
	if (ret < 0)
		goto err1;

	pm_runtime_forbid(dev);

	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
	if (ret) {
		dev_err(dwc->dev, "failed to allocate event buffers\n");
		ret = -ENOMEM;
		goto err2;
	}

	if (IS_ENABLED(CONFIG_USB_DWC3_HOST) &&
			(dwc->dr_mode == USB_DR_MODE_OTG ||
					dwc->dr_mode == USB_DR_MODE_UNKNOWN))
	if (IS_ENABLED(CONFIG_USB_DWC3_HOST))
		dwc->dr_mode = USB_DR_MODE_HOST;
	else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET) &&
			(dwc->dr_mode == USB_DR_MODE_OTG ||
					dwc->dr_mode == USB_DR_MODE_UNKNOWN))
		dwc->dr_mode = USB_DR_MODE_PERIPHERAL;

	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN)
	if (dwc->dr_mode == USB_DR_MODE_UNKNOWN) {
		dwc->dr_mode = USB_DR_MODE_OTG;

	ret = dwc3_alloc_scratch_buffers(dwc);
	if (ret)
		goto err3;

	ret = dwc3_core_init(dwc);
	if (ret) {
		dev_err(dev, "failed to initialize core\n");
		goto err4;
		dwc->is_drd = true;
	}

	/* Check the maximum_speed parameter */
@@ -1021,32 +1173,48 @@ static int dwc3_probe(struct platform_device *pdev)
		break;
	}

	ret = dwc3_core_init_mode(dwc);
	if (ret)
		goto err5;

	dwc3_debugfs_init(dwc);
	pm_runtime_put(dev);

	return 0;
	/* Adjust Frame Length */
	dwc3_frame_length_adjustment(dwc);

err5:
	dwc3_event_buffers_cleanup(dwc);
	/* Hardcode number of eps */
	dwc->num_in_eps = 16;
	dwc->num_out_eps = 16;

err4:
	dwc3_free_scratch_buffers(dwc);
	if (dwc->dr_mode == USB_DR_MODE_OTG ||
		dwc->dr_mode == USB_DR_MODE_PERIPHERAL) {
		ret = dwc3_gadget_init(dwc);
		if (ret) {
			dev_err(dev, "failed to initialize gadget\n");
			goto err0;
		}
	}

err3:
	dwc3_free_event_buffers(dwc);
	dwc3_ulpi_exit(dwc);
	if (dwc->dr_mode == USB_DR_MODE_OTG ||
		dwc->dr_mode ==  USB_DR_MODE_HOST) {
		ret = dwc3_host_init(dwc);
		if (ret) {
			dev_err(dev, "failed to initialize host\n");
			goto err_gadget;
		}
	}

err2:
	pm_runtime_allow(&pdev->dev);
	ret = dwc3_debugfs_init(dwc);
	if (ret) {
		dev_err(dev, "failed to initialize debugfs\n");
		goto err_host;
	}

err1:
	pm_runtime_put_sync(&pdev->dev);
	pm_runtime_disable(&pdev->dev);
	pm_runtime_allow(dev);
	return 0;

err_host:
	if (dwc->dr_mode == USB_DR_MODE_OTG ||
		dwc->dr_mode == USB_DR_MODE_HOST)
		dwc3_host_exit(dwc);
err_gadget:
	if (dwc->dr_mode == USB_DR_MODE_OTG ||
		dwc->dr_mode == USB_DR_MODE_PERIPHERAL)
		dwc3_gadget_exit(dwc);
err0:
	/*
	 * restore res->start back to its original value so that, in case the
@@ -1157,8 +1325,9 @@ static int dwc3_runtime_suspend(struct device *dev)
	struct dwc3     *dwc = dev_get_drvdata(dev);
	int		ret;

	if (dwc3_runtime_checks(dwc))
		return -EBUSY;
	/* Check if platform glue driver handling PM, if not then handle here */
	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
		return 0;

	ret = dwc3_suspend_common(dwc);
	if (ret)
@@ -1174,6 +1343,10 @@ static int dwc3_runtime_resume(struct device *dev)
	struct dwc3     *dwc = dev_get_drvdata(dev);
	int		ret;

	/* Check if platform glue driver handling PM, if not then handle here */
	if (!dwc3_notify_event(dwc, DWC3_CORE_PM_RESUME_EVENT))
		return 0;

	device_init_wakeup(dev, false);

	ret = dwc3_resume_common(dwc);
+113 −1
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@
#include <linux/dma-mapping.h>
#include <linux/mm.h>
#include <linux/debugfs.h>
#include <linux/workqueue.h>
#include <linux/wait.h>


#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -45,7 +48,7 @@
#define DWC3_SCRATCHBUF_SIZE	4096	/* each buffer is assumed to be 4KiB */
#define DWC3_EVENT_SIZE		4	/* bytes */
#define DWC3_EVENT_MAX_NUM	64	/* 2 events/endpoint */
#define DWC3_EVENT_BUFFERS_SIZE	(DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM)
#define DWC3_EVENT_BUFFERS_SIZE	(2 * PAGE_SIZE)
#define DWC3_EVENT_TYPE_MASK	0xfe

#define DWC3_EVENT_TYPE_DEV	0
@@ -59,6 +62,8 @@
#define DWC3_DEVICE_EVENT_WAKEUP		4
#define DWC3_DEVICE_EVENT_HIBER_REQ		5
#define DWC3_DEVICE_EVENT_EOPF			6
/* For version 2.30a and above */
#define DWC3_DEVICE_EVENT_SUSPEND		6
#define DWC3_DEVICE_EVENT_SOF			7
#define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
#define DWC3_DEVICE_EVENT_CMD_CMPL		10
@@ -155,6 +160,10 @@

/* Bit fields */

/* Global SoC Bus Configuration Register 1 */
#define DWC3_GSBUSCFG1_PIPETRANSLIMIT_MASK	(0x0f << 8)
#define DWC3_GSBUSCFG1_PIPETRANSLIMIT(n)	((n) << 8)

/* Global Debug Queue/FIFO Space Available Register */
#define DWC3_GDBGFIFOSPACE_NUM(n)	((n) & 0x1f)
#define DWC3_GDBGFIFOSPACE_TYPE(n)	(((n) << 5) & 0x1e0)
@@ -175,7 +184,10 @@

/* Global Configuration Register */
#define DWC3_GCTL_PWRDNSCALE(n)	((n) << 19)
#define DWC3_GCTL_PWRDNSCALEMASK (0xFFF80000)
#define DWC3_GCTL_U2RSTECN	(1 << 16)
#define DWC3_GCTL_SOFITPSYNC	(1 << 10)
#define DWC3_GCTL_U2EXIT_LFPS	(1 << 2)
#define DWC3_GCTL_RAMCLKSEL(x)	(((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS	(0)
#define DWC3_GCTL_CLK_PIPE	(1)
@@ -197,8 +209,15 @@
#define DWC3_GCTL_GBLHIBERNATIONEN	(1 << 1)
#define DWC3_GCTL_DSBLCLKGTNG		(1 << 0)

/* Global User Control Register */
#define DWC3_GUCTL_REFCLKPER		(0x3FF << 22)

/* Global Debug LTSSM Register */
#define DWC3_GDBGLTSSM_LINKSTATE_MASK	(0xF << 22)

/* Global USB2 PHY Configuration Register */
#define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
#define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
#define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
#define DWC3_GUSB2PHYCFG_ULPI_UTMI	(1 << 4)
#define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
@@ -225,6 +244,8 @@
#define DWC3_GUSB3PIPECTL_RX_DETOPOLL	(1 << 8)
#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK	DWC3_GUSB3PIPECTL_TX_DEEPH(3)
#define DWC3_GUSB3PIPECTL_TX_DEEPH(n)	((n) << 1)
#define DWC3_GUSB3PIPECTL_DELAYP1TRANS  (1 << 18)
#define DWC3_GUSB3PIPECTL_ELASTIC_BUF_MODE	(1 << 0)

/* Global TX Fifo Size Register */
#define DWC3_GTXFIFOSIZ_TXFDEF(n)	((n) & 0xffff)
@@ -279,6 +300,11 @@
#define DWC3_GFLADJ_30MHZ_SDBND_SEL		(1 << 7)
#define DWC3_GFLADJ_30MHZ_MASK			0x3f

#define DWC3_GFLADJ_REFCLK_240MHZDECR_PLS1      (1 << 31)
#define DWC3_GFLADJ_REFCLK_240MHZ_DECR          (0x7F << 24)
#define DWC3_GFLADJ_REFCLK_LPM_SEL              (1 << 23)
#define DWC3_GFLADJ_REFCLK_FLADJ                (0x3FFF << 8)

/* Device Configuration Register */
#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
#define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
@@ -348,6 +374,8 @@
#define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
#define DWC3_DEVTEN_SOFEN		(1 << 7)
#define DWC3_DEVTEN_EOPFEN		(1 << 6)
/* For version 2.30a and above*/
#define DWC3_DEVTEN_SUSPEND		(1 << 6)
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN	(1 << 5)
#define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
#define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
@@ -389,6 +417,7 @@
#define DWC3_DGCMD_SET_LMP		0x01
#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
#define DWC3_DGCMD_XMIT_FUNCTION	0x03
#define DWC3_DGCMD_XMIT_DEV		0x07

/* These apply for core versions 1.94a and later */
#define DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO	0x04
@@ -485,8 +514,10 @@ struct dwc3_event_buffer {
 * @started_list: list of started requests on this endpoint
 * @lock: spinlock for endpoint request queue traversal
 * @regs: pointer to first endpoint register
 * @trb_dma_pool: dma pool used to get aligned trb memory pool
 * @trb_pool: array of transaction buffers
 * @trb_pool_dma: dma address of @trb_pool
 * @num_trbs: num of trbs in the trb dma pool
 * @trb_enqueue: enqueue 'pointer' into TRB array
 * @trb_dequeue: dequeue 'pointer' into TRB array
 * @desc: usb_endpoint_descriptor pointer
@@ -511,8 +542,10 @@ struct dwc3_ep {
	spinlock_t		lock;
	void __iomem		*regs;

	struct dma_pool		*trb_dma_pool;
	struct dwc3_trb		*trb_pool;
	dma_addr_t		trb_pool_dma;
	u32			num_trbs;
	const struct usb_ss_ep_comp_descriptor *comp_desc;
	struct dwc3		*dwc;

@@ -716,6 +749,18 @@ struct dwc3_scratchpad_array {
	__le64	dma_adr[DWC3_MAX_HIBER_SCRATCHBUFS];
};

#define DWC3_CONTROLLER_ERROR_EVENT		0
#define DWC3_CONTROLLER_RESET_EVENT		1
#define DWC3_CONTROLLER_POST_RESET_EVENT	2
#define DWC3_CORE_PM_SUSPEND_EVENT		3
#define DWC3_CORE_PM_RESUME_EVENT		4
#define DWC3_CONTROLLER_CONNDONE_EVENT		5
#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT	6
#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT	7
#define DWC3_CONTROLLER_RESTART_USB_SESSION	8

#define MAX_INTR_STATS				10

/**
 * struct dwc3 - representation of our controller
 * @ctrl_req: usb control request which is used for ep0
@@ -738,6 +783,7 @@ struct dwc3_scratchpad_array {
 * @regs_size: address space size
 * @fladj: frame length adjustment
 * @irq_gadget: peripheral controller's IRQ number
 * @reg_phys: physical base address of dwc3 core register address space
 * @nr_scratch: number of scratch buffers
 * @u1u2: only used on revisions <1.83a for workaround
 * @maximum_speed: maximum speed requested (mainly for testing purposes)
@@ -805,6 +851,19 @@ struct dwc3_scratchpad_array {
 * 	1	- -3.5dB de-emphasis
 * 	2	- No de-emphasis
 * 	3	- Reserved
 * @is_drd: device supports dual-role or not
 * @err_evt_seen: previous event in queue was erratic error
 * @usb3_u1u2_disable: if true, disable U1U2 low power modes in Superspeed mode.
 * @in_lpm: indicates if controller is in low power mode (no clocks)
 * @tx_fifo_size: Available RAM size for TX fifo allocation
 * @irq: irq number
 * @bh: tasklet which handles the interrupt
 * @irq_cnt: total irq count
 * @bh_completion_time: time taken for taklet completion
 * @bh_handled_evt_cnt: no. of events handled by tasklet per interrupt
 * @bh_dbg_index: index for capturing bh_completion_time and bh_handled_evt_cnt
 * @wait_linkstate: waitqueue for waiting LINK to move into required state
 * @vbus_draw: current to be drawn from USB
 */
struct dwc3 {
	struct usb_ctrlrequest	*ctrl_req;
@@ -843,6 +902,7 @@ struct dwc3 {

	void __iomem		*regs;
	size_t			regs_size;
	phys_addr_t		reg_phys;

	enum usb_dr_mode	dr_mode;

@@ -917,6 +977,9 @@ struct dwc3 {
	const char		*hsphy_interface;

	unsigned		connected:1;
	void (*notify_event)(struct dwc3 *, unsigned int);
	struct work_struct	wakeup_work;

	unsigned		delayed_status:1;
	unsigned		ep0_bounced:1;
	unsigned		ep0_expect_in:1;
@@ -945,6 +1008,37 @@ struct dwc3 {

	unsigned		tx_de_emphasis_quirk:1;
	unsigned		tx_de_emphasis:2;
	unsigned		is_drd:1;
	/* Indicate if the gadget was powered by the otg driver */
	unsigned		vbus_active:1;
	/* Indicate if software connect was issued by the usb_gadget_driver */
	unsigned		softconnect:1;
	unsigned		nominal_elastic_buffer:1;
	unsigned		err_evt_seen:1;
	unsigned		usb3_u1u2_disable:1;
	/* Indicate if need to disable controller internal clkgating */
	unsigned		disable_clk_gating:1;
	unsigned		enable_bus_suspend:1;

	atomic_t		in_lpm;
	int			tx_fifo_size;
	bool			b_suspend;
	unsigned int		vbus_draw;

	/* IRQ timing statistics */
	int			irq;
	struct tasklet_struct	bh;
	unsigned long		irq_cnt;
	unsigned int		bh_completion_time[MAX_INTR_STATS];
	unsigned int		bh_handled_evt_cnt[MAX_INTR_STATS];
	unsigned int		bh_dbg_index;
	ktime_t			irq_start_time[MAX_INTR_STATS];
	ktime_t			t_pwr_evt_irq;
	unsigned int		irq_completion_time[MAX_INTR_STATS];
	unsigned int		irq_event_count[MAX_INTR_STATS];
	unsigned int		irq_dbg_index;

	wait_queue_head_t	wait_linkstate;
};

/* -------------------------------------------------------------------------- */
@@ -1119,17 +1213,22 @@ static inline void dwc3_host_exit(struct dwc3 *dwc)
#if IS_ENABLED(CONFIG_USB_DWC3_GADGET) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
int dwc3_gadget_init(struct dwc3 *dwc);
void dwc3_gadget_exit(struct dwc3 *dwc);
void dwc3_gadget_restart(struct dwc3 *dwc);
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
int dwc3_gadget_get_link_state(struct dwc3 *dwc);
int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
		struct dwc3_gadget_ep_cmd_params *params);
int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param);
void dwc3_gadget_enable_irq(struct dwc3 *dwc);
void dwc3_gadget_disable_irq(struct dwc3 *dwc);
#else
static inline int dwc3_gadget_init(struct dwc3 *dwc)
{ return 0; }
static inline void dwc3_gadget_exit(struct dwc3 *dwc)
{ }
static inline void dwc3_gadget_restart(struct dwc3 *dwc)
{ }
static inline int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
{ return 0; }
static inline int dwc3_gadget_get_link_state(struct dwc3 *dwc)
@@ -1144,6 +1243,10 @@ static inline int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
		int cmd, u32 param)
{ return 0; }
static inline void dwc3_gadget_enable_irq(struct dwc3 *dwc)
{ }
static inline void dwc3_gadget_disable_irq(struct dwc3 *dwc)
{ }
#endif

/* power management interface */
@@ -1177,4 +1280,13 @@ static inline void dwc3_ulpi_exit(struct dwc3 *dwc)
{ }
#endif

int dwc3_core_init(struct dwc3 *dwc);
int dwc3_core_pre_init(struct dwc3 *dwc);
void dwc3_post_host_reset_core_init(struct dwc3 *dwc);
int dwc3_event_buffers_setup(struct dwc3 *dwc);
void dwc3_usb3_phy_suspend(struct dwc3 *dwc, int suspend);

extern void dwc3_set_notifier(
		void (*notify)(struct dwc3 *dwc3, unsigned int event));
extern int dwc3_notify_event(struct dwc3 *dwc3, unsigned int event);
#endif /* __DRIVERS_USB_DWC3_CORE_H */
+3 −3
Original line number Diff line number Diff line
@@ -313,11 +313,11 @@ static inline const char *dwc3_gadget_generic_cmd_status_string(int status)
void dwc3_trace(void (*trace)(struct va_format *), const char *fmt, ...);

#ifdef CONFIG_DEBUG_FS
extern void dwc3_debugfs_init(struct dwc3 *);
extern int dwc3_debugfs_init(struct dwc3 *);
extern void dwc3_debugfs_exit(struct dwc3 *);
#else
static inline void dwc3_debugfs_init(struct dwc3 *d)
{  }
static inline int dwc3_debugfs_init(struct dwc3 *d)
{ return 0; }
static inline void dwc3_debugfs_exit(struct dwc3 *d)
{  }
#endif
+13 −4
Original line number Diff line number Diff line
@@ -843,23 +843,25 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
	}
}

void dwc3_debugfs_init(struct dwc3 *dwc)
int dwc3_debugfs_init(struct dwc3 *dwc)
{
	struct dentry		*root;
	struct dentry           *file;
	int			ret;

	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
	if (IS_ERR_OR_NULL(root)) {
		if (!root)
			dev_err(dwc->dev, "Can't create debugfs root\n");
		return;
		ret = -ENOMEM;
		goto err0;
	}
	dwc->root = root;

	dwc->regset = kzalloc(sizeof(*dwc->regset), GFP_KERNEL);
	if (!dwc->regset) {
		debugfs_remove_recursive(root);
		return;
		ret = -ENOMEM;
		goto err1;
	}

	dwc->regset->regs = dwc3_regs;
@@ -891,6 +893,13 @@ void dwc3_debugfs_init(struct dwc3 *dwc)

		dwc3_debugfs_create_endpoint_dirs(dwc, root);
	}

	return 0;

err1:
	debugfs_remove_recursive(root);
err0:
	return ret;
}

void dwc3_debugfs_exit(struct dwc3 *dwc)
+646 −108

File changed.

Preview size limit exceeded, changes collapsed.

Loading