cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dwc3-qcom.c (23774B)


      1// SPDX-License-Identifier: GPL-2.0
      2/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
      3 *
      4 * Inspired by dwc3-of-simple.c
      5 */
      6
      7#include <linux/acpi.h>
      8#include <linux/io.h>
      9#include <linux/of.h>
     10#include <linux/clk.h>
     11#include <linux/irq.h>
     12#include <linux/of_clk.h>
     13#include <linux/module.h>
     14#include <linux/kernel.h>
     15#include <linux/extcon.h>
     16#include <linux/interconnect.h>
     17#include <linux/of_platform.h>
     18#include <linux/platform_device.h>
     19#include <linux/phy/phy.h>
     20#include <linux/usb/of.h>
     21#include <linux/reset.h>
     22#include <linux/iopoll.h>
     23
     24#include "core.h"
     25
     26/* USB QSCRATCH Hardware registers */
     27#define QSCRATCH_HS_PHY_CTRL			0x10
     28#define UTMI_OTG_VBUS_VALID			BIT(20)
     29#define SW_SESSVLD_SEL				BIT(28)
     30
     31#define QSCRATCH_SS_PHY_CTRL			0x30
     32#define LANE0_PWR_PRESENT			BIT(24)
     33
     34#define QSCRATCH_GENERAL_CFG			0x08
     35#define PIPE_UTMI_CLK_SEL			BIT(0)
     36#define PIPE3_PHYSTATUS_SW			BIT(3)
     37#define PIPE_UTMI_CLK_DIS			BIT(8)
     38
     39#define PWR_EVNT_IRQ_STAT_REG			0x58
     40#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
     41#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
     42
     43#define SDM845_QSCRATCH_BASE_OFFSET		0xf8800
     44#define SDM845_QSCRATCH_SIZE			0x400
     45#define SDM845_DWC3_CORE_SIZE			0xcd00
     46
     47/* Interconnect path bandwidths in MBps */
     48#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
     49#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
     50#define USB_MEMORY_AVG_SS_BW  MBps_to_icc(1000)
     51#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
     52#define APPS_USB_AVG_BW 0
     53#define APPS_USB_PEAK_BW MBps_to_icc(40)
     54
     55struct dwc3_acpi_pdata {
     56	u32			qscratch_base_offset;
     57	u32			qscratch_base_size;
     58	u32			dwc3_core_base_size;
     59	int			hs_phy_irq_index;
     60	int			dp_hs_phy_irq_index;
     61	int			dm_hs_phy_irq_index;
     62	int			ss_phy_irq_index;
     63	bool			is_urs;
     64};
     65
     66struct dwc3_qcom {
     67	struct device		*dev;
     68	void __iomem		*qscratch_base;
     69	struct platform_device	*dwc3;
     70	struct platform_device	*urs_usb;
     71	struct clk		**clks;
     72	int			num_clocks;
     73	struct reset_control	*resets;
     74
     75	int			hs_phy_irq;
     76	int			dp_hs_phy_irq;
     77	int			dm_hs_phy_irq;
     78	int			ss_phy_irq;
     79
     80	struct extcon_dev	*edev;
     81	struct extcon_dev	*host_edev;
     82	struct notifier_block	vbus_nb;
     83	struct notifier_block	host_nb;
     84
     85	const struct dwc3_acpi_pdata *acpi_pdata;
     86
     87	enum usb_dr_mode	mode;
     88	bool			is_suspended;
     89	bool			pm_suspended;
     90	struct icc_path		*icc_path_ddr;
     91	struct icc_path		*icc_path_apps;
     92};
     93
     94static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
     95{
     96	u32 reg;
     97
     98	reg = readl(base + offset);
     99	reg |= val;
    100	writel(reg, base + offset);
    101
    102	/* ensure that above write is through */
    103	readl(base + offset);
    104}
    105
    106static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
    107{
    108	u32 reg;
    109
    110	reg = readl(base + offset);
    111	reg &= ~val;
    112	writel(reg, base + offset);
    113
    114	/* ensure that above write is through */
    115	readl(base + offset);
    116}
    117
    118static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
    119{
    120	if (enable) {
    121		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
    122				  LANE0_PWR_PRESENT);
    123		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
    124				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
    125	} else {
    126		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
    127				  LANE0_PWR_PRESENT);
    128		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
    129				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
    130	}
    131}
    132
    133static int dwc3_qcom_vbus_notifier(struct notifier_block *nb,
    134				   unsigned long event, void *ptr)
    135{
    136	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb);
    137
    138	/* enable vbus override for device mode */
    139	dwc3_qcom_vbus_override_enable(qcom, event);
    140	qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST;
    141
    142	return NOTIFY_DONE;
    143}
    144
    145static int dwc3_qcom_host_notifier(struct notifier_block *nb,
    146				   unsigned long event, void *ptr)
    147{
    148	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb);
    149
    150	/* disable vbus override in host mode */
    151	dwc3_qcom_vbus_override_enable(qcom, !event);
    152	qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL;
    153
    154	return NOTIFY_DONE;
    155}
    156
    157static int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
    158{
    159	struct device		*dev = qcom->dev;
    160	struct extcon_dev	*host_edev;
    161	int			ret;
    162
    163	if (!of_property_read_bool(dev->of_node, "extcon"))
    164		return 0;
    165
    166	qcom->edev = extcon_get_edev_by_phandle(dev, 0);
    167	if (IS_ERR(qcom->edev))
    168		return PTR_ERR(qcom->edev);
    169
    170	qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier;
    171
    172	qcom->host_edev = extcon_get_edev_by_phandle(dev, 1);
    173	if (IS_ERR(qcom->host_edev))
    174		qcom->host_edev = NULL;
    175
    176	ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB,
    177					    &qcom->vbus_nb);
    178	if (ret < 0) {
    179		dev_err(dev, "VBUS notifier register failed\n");
    180		return ret;
    181	}
    182
    183	if (qcom->host_edev)
    184		host_edev = qcom->host_edev;
    185	else
    186		host_edev = qcom->edev;
    187
    188	qcom->host_nb.notifier_call = dwc3_qcom_host_notifier;
    189	ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST,
    190					    &qcom->host_nb);
    191	if (ret < 0) {
    192		dev_err(dev, "Host notifier register failed\n");
    193		return ret;
    194	}
    195
    196	/* Update initial VBUS override based on extcon state */
    197	if (extcon_get_state(qcom->edev, EXTCON_USB) ||
    198	    !extcon_get_state(host_edev, EXTCON_USB_HOST))
    199		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev);
    200	else
    201		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev);
    202
    203	return 0;
    204}
    205
    206static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
    207{
    208	int ret;
    209
    210	ret = icc_enable(qcom->icc_path_ddr);
    211	if (ret)
    212		return ret;
    213
    214	ret = icc_enable(qcom->icc_path_apps);
    215	if (ret)
    216		icc_disable(qcom->icc_path_ddr);
    217
    218	return ret;
    219}
    220
    221static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
    222{
    223	int ret;
    224
    225	ret = icc_disable(qcom->icc_path_ddr);
    226	if (ret)
    227		return ret;
    228
    229	ret = icc_disable(qcom->icc_path_apps);
    230	if (ret)
    231		icc_enable(qcom->icc_path_ddr);
    232
    233	return ret;
    234}
    235
    236/**
    237 * dwc3_qcom_interconnect_init() - Get interconnect path handles
    238 * and set bandwidth.
    239 * @qcom:			Pointer to the concerned usb core.
    240 *
    241 */
    242static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
    243{
    244	struct device *dev = qcom->dev;
    245	int ret;
    246
    247	if (has_acpi_companion(dev))
    248		return 0;
    249
    250	qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
    251	if (IS_ERR(qcom->icc_path_ddr)) {
    252		dev_err(dev, "failed to get usb-ddr path: %ld\n",
    253			PTR_ERR(qcom->icc_path_ddr));
    254		return PTR_ERR(qcom->icc_path_ddr);
    255	}
    256
    257	qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
    258	if (IS_ERR(qcom->icc_path_apps)) {
    259		dev_err(dev, "failed to get apps-usb path: %ld\n",
    260				PTR_ERR(qcom->icc_path_apps));
    261		return PTR_ERR(qcom->icc_path_apps);
    262	}
    263
    264	if (usb_get_maximum_speed(&qcom->dwc3->dev) >= USB_SPEED_SUPER ||
    265			usb_get_maximum_speed(&qcom->dwc3->dev) == USB_SPEED_UNKNOWN)
    266		ret = icc_set_bw(qcom->icc_path_ddr,
    267			USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
    268	else
    269		ret = icc_set_bw(qcom->icc_path_ddr,
    270			USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
    271
    272	if (ret) {
    273		dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
    274		return ret;
    275	}
    276
    277	ret = icc_set_bw(qcom->icc_path_apps,
    278		APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
    279	if (ret) {
    280		dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
    281		return ret;
    282	}
    283
    284	return 0;
    285}
    286
    287/**
    288 * dwc3_qcom_interconnect_exit() - Release interconnect path handles
    289 * @qcom:			Pointer to the concerned usb core.
    290 *
    291 * This function is used to release interconnect path handle.
    292 */
    293static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
    294{
    295	icc_put(qcom->icc_path_ddr);
    296	icc_put(qcom->icc_path_apps);
    297}
    298
    299static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
    300{
    301	if (qcom->hs_phy_irq) {
    302		disable_irq_wake(qcom->hs_phy_irq);
    303		disable_irq_nosync(qcom->hs_phy_irq);
    304	}
    305
    306	if (qcom->dp_hs_phy_irq) {
    307		disable_irq_wake(qcom->dp_hs_phy_irq);
    308		disable_irq_nosync(qcom->dp_hs_phy_irq);
    309	}
    310
    311	if (qcom->dm_hs_phy_irq) {
    312		disable_irq_wake(qcom->dm_hs_phy_irq);
    313		disable_irq_nosync(qcom->dm_hs_phy_irq);
    314	}
    315
    316	if (qcom->ss_phy_irq) {
    317		disable_irq_wake(qcom->ss_phy_irq);
    318		disable_irq_nosync(qcom->ss_phy_irq);
    319	}
    320}
    321
    322static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
    323{
    324	if (qcom->hs_phy_irq) {
    325		enable_irq(qcom->hs_phy_irq);
    326		enable_irq_wake(qcom->hs_phy_irq);
    327	}
    328
    329	if (qcom->dp_hs_phy_irq) {
    330		enable_irq(qcom->dp_hs_phy_irq);
    331		enable_irq_wake(qcom->dp_hs_phy_irq);
    332	}
    333
    334	if (qcom->dm_hs_phy_irq) {
    335		enable_irq(qcom->dm_hs_phy_irq);
    336		enable_irq_wake(qcom->dm_hs_phy_irq);
    337	}
    338
    339	if (qcom->ss_phy_irq) {
    340		enable_irq(qcom->ss_phy_irq);
    341		enable_irq_wake(qcom->ss_phy_irq);
    342	}
    343}
    344
    345static int dwc3_qcom_suspend(struct dwc3_qcom *qcom)
    346{
    347	u32 val;
    348	int i, ret;
    349
    350	if (qcom->is_suspended)
    351		return 0;
    352
    353	val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG);
    354	if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
    355		dev_err(qcom->dev, "HS-PHY not in L2\n");
    356
    357	for (i = qcom->num_clocks - 1; i >= 0; i--)
    358		clk_disable_unprepare(qcom->clks[i]);
    359
    360	ret = dwc3_qcom_interconnect_disable(qcom);
    361	if (ret)
    362		dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
    363
    364	if (device_may_wakeup(qcom->dev))
    365		dwc3_qcom_enable_interrupts(qcom);
    366
    367	qcom->is_suspended = true;
    368
    369	return 0;
    370}
    371
    372static int dwc3_qcom_resume(struct dwc3_qcom *qcom)
    373{
    374	int ret;
    375	int i;
    376
    377	if (!qcom->is_suspended)
    378		return 0;
    379
    380	if (device_may_wakeup(qcom->dev))
    381		dwc3_qcom_disable_interrupts(qcom);
    382
    383	for (i = 0; i < qcom->num_clocks; i++) {
    384		ret = clk_prepare_enable(qcom->clks[i]);
    385		if (ret < 0) {
    386			while (--i >= 0)
    387				clk_disable_unprepare(qcom->clks[i]);
    388			return ret;
    389		}
    390	}
    391
    392	ret = dwc3_qcom_interconnect_enable(qcom);
    393	if (ret)
    394		dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
    395
    396	/* Clear existing events from PHY related to L2 in/out */
    397	dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
    398			  PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
    399
    400	qcom->is_suspended = false;
    401
    402	return 0;
    403}
    404
    405static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
    406{
    407	struct dwc3_qcom *qcom = data;
    408	struct dwc3	*dwc = platform_get_drvdata(qcom->dwc3);
    409
    410	/* If pm_suspended then let pm_resume take care of resuming h/w */
    411	if (qcom->pm_suspended)
    412		return IRQ_HANDLED;
    413
    414	if (dwc->xhci)
    415		pm_runtime_resume(&dwc->xhci->dev);
    416
    417	return IRQ_HANDLED;
    418}
    419
    420static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
    421{
    422	/* Configure dwc3 to use UTMI clock as PIPE clock not present */
    423	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
    424			  PIPE_UTMI_CLK_DIS);
    425
    426	usleep_range(100, 1000);
    427
    428	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
    429			  PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
    430
    431	usleep_range(100, 1000);
    432
    433	dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
    434			  PIPE_UTMI_CLK_DIS);
    435}
    436
    437static int dwc3_qcom_get_irq(struct platform_device *pdev,
    438			     const char *name, int num)
    439{
    440	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
    441	struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : pdev;
    442	struct device_node *np = pdev->dev.of_node;
    443	int ret;
    444
    445	if (np)
    446		ret = platform_get_irq_byname(pdev_irq, name);
    447	else
    448		ret = platform_get_irq(pdev_irq, num);
    449
    450	return ret;
    451}
    452
    453static int dwc3_qcom_setup_irq(struct platform_device *pdev)
    454{
    455	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
    456	const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
    457	int irq;
    458	int ret;
    459
    460	irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
    461				pdata ? pdata->hs_phy_irq_index : -1);
    462	if (irq > 0) {
    463		/* Keep wakeup interrupts disabled until suspend */
    464		irq_set_status_flags(irq, IRQ_NOAUTOEN);
    465		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
    466					qcom_dwc3_resume_irq,
    467					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    468					"qcom_dwc3 HS", qcom);
    469		if (ret) {
    470			dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret);
    471			return ret;
    472		}
    473		qcom->hs_phy_irq = irq;
    474	}
    475
    476	irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
    477				pdata ? pdata->dp_hs_phy_irq_index : -1);
    478	if (irq > 0) {
    479		irq_set_status_flags(irq, IRQ_NOAUTOEN);
    480		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
    481					qcom_dwc3_resume_irq,
    482					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    483					"qcom_dwc3 DP_HS", qcom);
    484		if (ret) {
    485			dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
    486			return ret;
    487		}
    488		qcom->dp_hs_phy_irq = irq;
    489	}
    490
    491	irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
    492				pdata ? pdata->dm_hs_phy_irq_index : -1);
    493	if (irq > 0) {
    494		irq_set_status_flags(irq, IRQ_NOAUTOEN);
    495		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
    496					qcom_dwc3_resume_irq,
    497					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    498					"qcom_dwc3 DM_HS", qcom);
    499		if (ret) {
    500			dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
    501			return ret;
    502		}
    503		qcom->dm_hs_phy_irq = irq;
    504	}
    505
    506	irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
    507				pdata ? pdata->ss_phy_irq_index : -1);
    508	if (irq > 0) {
    509		irq_set_status_flags(irq, IRQ_NOAUTOEN);
    510		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
    511					qcom_dwc3_resume_irq,
    512					IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
    513					"qcom_dwc3 SS", qcom);
    514		if (ret) {
    515			dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
    516			return ret;
    517		}
    518		qcom->ss_phy_irq = irq;
    519	}
    520
    521	return 0;
    522}
    523
    524static int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
    525{
    526	struct device		*dev = qcom->dev;
    527	struct device_node	*np = dev->of_node;
    528	int			i;
    529
    530	if (!np || !count)
    531		return 0;
    532
    533	if (count < 0)
    534		return count;
    535
    536	qcom->num_clocks = count;
    537
    538	qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
    539				  sizeof(struct clk *), GFP_KERNEL);
    540	if (!qcom->clks)
    541		return -ENOMEM;
    542
    543	for (i = 0; i < qcom->num_clocks; i++) {
    544		struct clk	*clk;
    545		int		ret;
    546
    547		clk = of_clk_get(np, i);
    548		if (IS_ERR(clk)) {
    549			while (--i >= 0)
    550				clk_put(qcom->clks[i]);
    551			return PTR_ERR(clk);
    552		}
    553
    554		ret = clk_prepare_enable(clk);
    555		if (ret < 0) {
    556			while (--i >= 0) {
    557				clk_disable_unprepare(qcom->clks[i]);
    558				clk_put(qcom->clks[i]);
    559			}
    560			clk_put(clk);
    561
    562			return ret;
    563		}
    564
    565		qcom->clks[i] = clk;
    566	}
    567
    568	return 0;
    569}
    570
    571static const struct property_entry dwc3_qcom_acpi_properties[] = {
    572	PROPERTY_ENTRY_STRING("dr_mode", "host"),
    573	{}
    574};
    575
    576static const struct software_node dwc3_qcom_swnode = {
    577	.properties = dwc3_qcom_acpi_properties,
    578};
    579
    580static int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
    581{
    582	struct dwc3_qcom	*qcom = platform_get_drvdata(pdev);
    583	struct device		*dev = &pdev->dev;
    584	struct resource		*res, *child_res = NULL;
    585	struct platform_device	*pdev_irq = qcom->urs_usb ? qcom->urs_usb :
    586							    pdev;
    587	int			irq;
    588	int			ret;
    589
    590	qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
    591	if (!qcom->dwc3)
    592		return -ENOMEM;
    593
    594	qcom->dwc3->dev.parent = dev;
    595	qcom->dwc3->dev.type = dev->type;
    596	qcom->dwc3->dev.dma_mask = dev->dma_mask;
    597	qcom->dwc3->dev.dma_parms = dev->dma_parms;
    598	qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
    599
    600	child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
    601	if (!child_res) {
    602		platform_device_put(qcom->dwc3);
    603		return -ENOMEM;
    604	}
    605
    606	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    607	if (!res) {
    608		dev_err(&pdev->dev, "failed to get memory resource\n");
    609		ret = -ENODEV;
    610		goto out;
    611	}
    612
    613	child_res[0].flags = res->flags;
    614	child_res[0].start = res->start;
    615	child_res[0].end = child_res[0].start +
    616		qcom->acpi_pdata->dwc3_core_base_size;
    617
    618	irq = platform_get_irq(pdev_irq, 0);
    619	if (irq < 0) {
    620		ret = irq;
    621		goto out;
    622	}
    623	child_res[1].flags = IORESOURCE_IRQ;
    624	child_res[1].start = child_res[1].end = irq;
    625
    626	ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
    627	if (ret) {
    628		dev_err(&pdev->dev, "failed to add resources\n");
    629		goto out;
    630	}
    631
    632	ret = device_add_software_node(&qcom->dwc3->dev, &dwc3_qcom_swnode);
    633	if (ret < 0) {
    634		dev_err(&pdev->dev, "failed to add properties\n");
    635		goto out;
    636	}
    637
    638	ret = platform_device_add(qcom->dwc3);
    639	if (ret) {
    640		dev_err(&pdev->dev, "failed to add device\n");
    641		device_remove_software_node(&qcom->dwc3->dev);
    642		goto out;
    643	}
    644	kfree(child_res);
    645	return 0;
    646
    647out:
    648	platform_device_put(qcom->dwc3);
    649	kfree(child_res);
    650	return ret;
    651}
    652
    653static int dwc3_qcom_of_register_core(struct platform_device *pdev)
    654{
    655	struct dwc3_qcom	*qcom = platform_get_drvdata(pdev);
    656	struct device_node	*np = pdev->dev.of_node, *dwc3_np;
    657	struct device		*dev = &pdev->dev;
    658	int			ret;
    659
    660	dwc3_np = of_get_compatible_child(np, "snps,dwc3");
    661	if (!dwc3_np) {
    662		dev_err(dev, "failed to find dwc3 core child\n");
    663		return -ENODEV;
    664	}
    665
    666	ret = of_platform_populate(np, NULL, NULL, dev);
    667	if (ret) {
    668		dev_err(dev, "failed to register dwc3 core - %d\n", ret);
    669		goto node_put;
    670	}
    671
    672	qcom->dwc3 = of_find_device_by_node(dwc3_np);
    673	if (!qcom->dwc3) {
    674		ret = -ENODEV;
    675		dev_err(dev, "failed to get dwc3 platform device\n");
    676	}
    677
    678node_put:
    679	of_node_put(dwc3_np);
    680
    681	return ret;
    682}
    683
    684static struct platform_device *
    685dwc3_qcom_create_urs_usb_platdev(struct device *dev)
    686{
    687	struct fwnode_handle *fwh;
    688	struct acpi_device *adev;
    689	char name[8];
    690	int ret;
    691	int id;
    692
    693	/* Figure out device id */
    694	ret = sscanf(fwnode_get_name(dev->fwnode), "URS%d", &id);
    695	if (!ret)
    696		return NULL;
    697
    698	/* Find the child using name */
    699	snprintf(name, sizeof(name), "USB%d", id);
    700	fwh = fwnode_get_named_child_node(dev->fwnode, name);
    701	if (!fwh)
    702		return NULL;
    703
    704	adev = to_acpi_device_node(fwh);
    705	if (!adev)
    706		return NULL;
    707
    708	return acpi_create_platform_device(adev, NULL);
    709}
    710
    711static int dwc3_qcom_probe(struct platform_device *pdev)
    712{
    713	struct device_node	*np = pdev->dev.of_node;
    714	struct device		*dev = &pdev->dev;
    715	struct dwc3_qcom	*qcom;
    716	struct resource		*res, *parent_res = NULL;
    717	int			ret, i;
    718	bool			ignore_pipe_clk;
    719
    720	qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
    721	if (!qcom)
    722		return -ENOMEM;
    723
    724	platform_set_drvdata(pdev, qcom);
    725	qcom->dev = &pdev->dev;
    726
    727	if (has_acpi_companion(dev)) {
    728		qcom->acpi_pdata = acpi_device_get_match_data(dev);
    729		if (!qcom->acpi_pdata) {
    730			dev_err(&pdev->dev, "no supporting ACPI device data\n");
    731			return -EINVAL;
    732		}
    733	}
    734
    735	qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
    736	if (IS_ERR(qcom->resets)) {
    737		ret = PTR_ERR(qcom->resets);
    738		dev_err(&pdev->dev, "failed to get resets, err=%d\n", ret);
    739		return ret;
    740	}
    741
    742	ret = reset_control_assert(qcom->resets);
    743	if (ret) {
    744		dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
    745		return ret;
    746	}
    747
    748	usleep_range(10, 1000);
    749
    750	ret = reset_control_deassert(qcom->resets);
    751	if (ret) {
    752		dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
    753		goto reset_assert;
    754	}
    755
    756	ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
    757	if (ret) {
    758		dev_err(dev, "failed to get clocks\n");
    759		goto reset_assert;
    760	}
    761
    762	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    763
    764	if (np) {
    765		parent_res = res;
    766	} else {
    767		parent_res = kmemdup(res, sizeof(struct resource), GFP_KERNEL);
    768		if (!parent_res)
    769			return -ENOMEM;
    770
    771		parent_res->start = res->start +
    772			qcom->acpi_pdata->qscratch_base_offset;
    773		parent_res->end = parent_res->start +
    774			qcom->acpi_pdata->qscratch_base_size;
    775
    776		if (qcom->acpi_pdata->is_urs) {
    777			qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev);
    778			if (IS_ERR_OR_NULL(qcom->urs_usb)) {
    779				dev_err(dev, "failed to create URS USB platdev\n");
    780				if (!qcom->urs_usb)
    781					return -ENODEV;
    782				else
    783					return PTR_ERR(qcom->urs_usb);
    784			}
    785		}
    786	}
    787
    788	qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
    789	if (IS_ERR(qcom->qscratch_base)) {
    790		ret = PTR_ERR(qcom->qscratch_base);
    791		goto clk_disable;
    792	}
    793
    794	ret = dwc3_qcom_setup_irq(pdev);
    795	if (ret) {
    796		dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
    797		goto clk_disable;
    798	}
    799
    800	/*
    801	 * Disable pipe_clk requirement if specified. Used when dwc3
    802	 * operates without SSPHY and only HS/FS/LS modes are supported.
    803	 */
    804	ignore_pipe_clk = device_property_read_bool(dev,
    805				"qcom,select-utmi-as-pipe-clk");
    806	if (ignore_pipe_clk)
    807		dwc3_qcom_select_utmi_clk(qcom);
    808
    809	if (np)
    810		ret = dwc3_qcom_of_register_core(pdev);
    811	else
    812		ret = dwc3_qcom_acpi_register_core(pdev);
    813
    814	if (ret) {
    815		dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
    816		goto depopulate;
    817	}
    818
    819	ret = dwc3_qcom_interconnect_init(qcom);
    820	if (ret)
    821		goto depopulate;
    822
    823	qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
    824
    825	/* enable vbus override for device mode */
    826	if (qcom->mode == USB_DR_MODE_PERIPHERAL)
    827		dwc3_qcom_vbus_override_enable(qcom, true);
    828
    829	/* register extcon to override sw_vbus on Vbus change later */
    830	ret = dwc3_qcom_register_extcon(qcom);
    831	if (ret)
    832		goto interconnect_exit;
    833
    834	device_init_wakeup(&pdev->dev, 1);
    835	qcom->is_suspended = false;
    836	pm_runtime_set_active(dev);
    837	pm_runtime_enable(dev);
    838	pm_runtime_forbid(dev);
    839
    840	return 0;
    841
    842interconnect_exit:
    843	dwc3_qcom_interconnect_exit(qcom);
    844depopulate:
    845	if (np)
    846		of_platform_depopulate(&pdev->dev);
    847	else
    848		platform_device_put(pdev);
    849clk_disable:
    850	for (i = qcom->num_clocks - 1; i >= 0; i--) {
    851		clk_disable_unprepare(qcom->clks[i]);
    852		clk_put(qcom->clks[i]);
    853	}
    854reset_assert:
    855	reset_control_assert(qcom->resets);
    856
    857	return ret;
    858}
    859
    860static int dwc3_qcom_remove(struct platform_device *pdev)
    861{
    862	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
    863	struct device *dev = &pdev->dev;
    864	int i;
    865
    866	device_remove_software_node(&qcom->dwc3->dev);
    867	of_platform_depopulate(dev);
    868
    869	for (i = qcom->num_clocks - 1; i >= 0; i--) {
    870		clk_disable_unprepare(qcom->clks[i]);
    871		clk_put(qcom->clks[i]);
    872	}
    873	qcom->num_clocks = 0;
    874
    875	dwc3_qcom_interconnect_exit(qcom);
    876	reset_control_assert(qcom->resets);
    877
    878	pm_runtime_allow(dev);
    879	pm_runtime_disable(dev);
    880
    881	return 0;
    882}
    883
    884static int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
    885{
    886	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
    887	int ret = 0;
    888
    889	ret = dwc3_qcom_suspend(qcom);
    890	if (!ret)
    891		qcom->pm_suspended = true;
    892
    893	return ret;
    894}
    895
    896static int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
    897{
    898	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
    899	int ret;
    900
    901	ret = dwc3_qcom_resume(qcom);
    902	if (!ret)
    903		qcom->pm_suspended = false;
    904
    905	return ret;
    906}
    907
    908static int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
    909{
    910	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
    911
    912	return dwc3_qcom_suspend(qcom);
    913}
    914
    915static int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
    916{
    917	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
    918
    919	return dwc3_qcom_resume(qcom);
    920}
    921
    922static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
    923	SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
    924	SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
    925			   NULL)
    926};
    927
    928static const struct of_device_id dwc3_qcom_of_match[] = {
    929	{ .compatible = "qcom,dwc3" },
    930	{ .compatible = "qcom,msm8996-dwc3" },
    931	{ .compatible = "qcom,msm8998-dwc3" },
    932	{ .compatible = "qcom,sdm660-dwc3" },
    933	{ .compatible = "qcom,sdm845-dwc3" },
    934	{ }
    935};
    936MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
    937
    938#ifdef CONFIG_ACPI
    939static const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
    940	.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
    941	.qscratch_base_size = SDM845_QSCRATCH_SIZE,
    942	.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
    943	.hs_phy_irq_index = 1,
    944	.dp_hs_phy_irq_index = 4,
    945	.dm_hs_phy_irq_index = 3,
    946	.ss_phy_irq_index = 2
    947};
    948
    949static const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
    950	.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
    951	.qscratch_base_size = SDM845_QSCRATCH_SIZE,
    952	.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
    953	.hs_phy_irq_index = 1,
    954	.dp_hs_phy_irq_index = 4,
    955	.dm_hs_phy_irq_index = 3,
    956	.ss_phy_irq_index = 2,
    957	.is_urs = true,
    958};
    959
    960static const struct acpi_device_id dwc3_qcom_acpi_match[] = {
    961	{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
    962	{ "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
    963	{ "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
    964	{ "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
    965	{ },
    966};
    967MODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
    968#endif
    969
    970static struct platform_driver dwc3_qcom_driver = {
    971	.probe		= dwc3_qcom_probe,
    972	.remove		= dwc3_qcom_remove,
    973	.driver		= {
    974		.name	= "dwc3-qcom",
    975		.pm	= &dwc3_qcom_dev_pm_ops,
    976		.of_match_table	= dwc3_qcom_of_match,
    977		.acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
    978	},
    979};
    980
    981module_platform_driver(dwc3_qcom_driver);
    982
    983MODULE_LICENSE("GPL v2");
    984MODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");