[v9,4/7] usb: misc: eud: Add driver support for SM6115 / SM4250

Message ID 20230718061052.1332993-5-bhupesh.sharma@linaro.org
State New
Headers
Series Add Qualcomm SM6115 / SM4250 EUD dt-bindings & driver support |

Commit Message

Bhupesh Sharma July 18, 2023, 6:10 a.m. UTC
  Add SM6115 / SM4250 SoC EUD support in qcom_eud driver.

On some SoCs (like the SM6115 / SM4250 SoC), the mode manager
needs to be accessed only via the secure world (through 'scm'
calls).

Also, the enable bit inside 'tcsr_check_reg' needs to be set
first to set the eud in 'enable' mode on these SoCs.

Signed-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>
---
 drivers/usb/misc/Kconfig    |  2 +-
 drivers/usb/misc/qcom_eud.c | 76 ++++++++++++++++++++++++++++++++++---
 2 files changed, 72 insertions(+), 6 deletions(-)
  

Comments

Krzysztof Kozlowski July 18, 2023, 6:31 a.m. UTC | #1
On 18/07/2023 08:10, Bhupesh Sharma wrote:
> Add SM6115 / SM4250 SoC EUD support in qcom_eud driver.
> 
> On some SoCs (like the SM6115 / SM4250 SoC), the mode manager
> needs to be accessed only via the secure world (through 'scm'
> calls).
> 
> Also, the enable bit inside 'tcsr_check_reg' needs to be set
> first to set the eud in 'enable' mode on these SoCs.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>
> ---
>  drivers/usb/misc/Kconfig    |  2 +-
>  drivers/usb/misc/qcom_eud.c | 76 ++++++++++++++++++++++++++++++++++---
>  2 files changed, 72 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
> index 99b15b77dfd57..51eb5140caa14 100644
> --- a/drivers/usb/misc/Kconfig
> +++ b/drivers/usb/misc/Kconfig
> @@ -146,7 +146,7 @@ config USB_APPLEDISPLAY
>  
>  config USB_QCOM_EUD
>  	tristate "QCOM Embedded USB Debugger(EUD) Driver"
> -	depends on ARCH_QCOM || COMPILE_TEST
> +	depends on (ARCH_QCOM && QCOM_SCM) || COMPILE_TEST
>  	select USB_ROLE_SWITCH
>  	help
>  	  This module enables support for Qualcomm Technologies, Inc.
> diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
> index 7f371ea1248c3..a5b28fc24116a 100644
> --- a/drivers/usb/misc/qcom_eud.c
> +++ b/drivers/usb/misc/qcom_eud.c
> @@ -11,9 +11,12 @@
>  #include <linux/kernel.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
>  #include <linux/sysfs.h>
> +#include <linux/firmware/qcom/qcom_scm.h>
>  #include <linux/usb/role.h>
>  
>  #define EUD_REG_INT1_EN_MASK	0x0024
> @@ -30,6 +33,10 @@
>  #define EUD_INT_SAFE_MODE	BIT(4)
>  #define EUD_INT_ALL		(EUD_INT_VBUS | EUD_INT_SAFE_MODE)
>  
> +#define EUD_EN2_EN		BIT(0)
> +#define EUD_EN2_DISABLE		(0)
> +#define TCSR_CHECK_EN		BIT(0)
> +
>  struct eud_chip {
>  	struct device			*dev;
>  	struct usb_role_switch		*role_sw;
> @@ -39,6 +46,7 @@ struct eud_chip {
>  	int				irq;
>  	bool				enabled;
>  	bool				usb_attached;
> +	phys_addr_t			secure_mode_mgr;
>  };
>  
>  static int enable_eud(struct eud_chip *priv)
> @@ -46,7 +54,11 @@ static int enable_eud(struct eud_chip *priv)
>  	writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN);
>  	writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE,
>  			priv->base + EUD_REG_INT1_EN_MASK);
> -	writel(1, priv->mode_mgr + EUD_REG_EUD_EN2);
> +
> +	if (priv->secure_mode_mgr)
> +		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_EN);
> +	else
> +		writel(EUD_EN2_EN, priv->mode_mgr + EUD_REG_EUD_EN2);
>  
>  	return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE);
>  }
> @@ -54,7 +66,11 @@ static int enable_eud(struct eud_chip *priv)
>  static void disable_eud(struct eud_chip *priv)
>  {
>  	writel(0, priv->base + EUD_REG_CSR_EUD_EN);
> -	writel(0, priv->mode_mgr + EUD_REG_EUD_EN2);
> +
> +	if (priv->secure_mode_mgr)
> +		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_DISABLE);
> +	else
> +		writel(EUD_EN2_DISABLE, priv->mode_mgr + EUD_REG_EUD_EN2);
>  }
>  
>  static ssize_t enable_show(struct device *dev,
> @@ -175,9 +191,37 @@ static void eud_role_switch_release(void *data)
>  	usb_role_switch_put(chip->role_sw);
>  }
>  
> +static int eud_find_secure_reg_addr(struct device *dev, u64 *addr)
> +{
> +	struct device_node *tcsr;
> +	struct device_node *np = dev->of_node;
> +	struct resource res;
> +	u32 offset;
> +	int ret;
> +
> +	tcsr = of_parse_phandle(np, "qcom,secure-eud-reg", 0);
> +	if (!tcsr)
> +		return 0;
> +
> +	ret = of_address_to_resource(tcsr, 0, &res);
> +	of_node_put(tcsr);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_property_read_u32_index(np, "qcom,secure-eud-reg", 1, &offset);
> +	if (ret < 0)
> +		return ret;
> +
> +	*addr = res.start + offset;
> +
> +	return 0;
> +}
> +
>  static int eud_probe(struct platform_device *pdev)
>  {
>  	struct eud_chip *chip;
> +	struct resource *res;
> +	phys_addr_t tcsr_check = 0;
>  	int ret;
>  
>  	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> @@ -200,9 +244,30 @@ static int eud_probe(struct platform_device *pdev)
>  	if (IS_ERR(chip->base))
>  		return PTR_ERR(chip->base);
>  
> -	chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
> -	if (IS_ERR(chip->mode_mgr))
> -		return PTR_ERR(chip->mode_mgr);
> +	/*
> +	 * EUD block on a few Qualcomm SoCs needs secure register access.
> +	 * Check for the same via vendor-specific dt property.
> +	 */
> +	ret = eud_find_secure_reg_addr(&pdev->dev, &tcsr_check);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (tcsr_check) {
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);

I don't understand this code. If you have syscon to eud reg, then why
you are not using it, but instead map again second address space?

> +		if (!res)
> +			return dev_err_probe(chip->dev, -ENODEV,
> +					     "failed to get secure_mode_mgr reg base\n");
> +
> +		chip->secure_mode_mgr = res->start;
> +
> +		ret = qcom_scm_io_writel(tcsr_check, TCSR_CHECK_EN);

That's not how syscon is used. Your bindings defined it as syscon, so
are you sure you are using it correctly?



Best regards,
Krzysztof
  
Souradeep Chowdhury July 18, 2023, 7:51 a.m. UTC | #2
Hi Bhupesh,

On 7/18/2023 11:40 AM, Bhupesh Sharma wrote:
> Add SM6115 / SM4250 SoC EUD support in qcom_eud driver.
> 
> On some SoCs (like the SM6115 / SM4250 SoC), the mode manager
> needs to be accessed only via the secure world (through 'scm'
> calls).
> 
> Also, the enable bit inside 'tcsr_check_reg' needs to be set
> first to set the eud in 'enable' mode on these SoCs.
> 
> Signed-off-by: Bhupesh Sharma <bhupesh.sharma@linaro.org>
> ---
>   drivers/usb/misc/Kconfig    |  2 +-
>   drivers/usb/misc/qcom_eud.c | 76 ++++++++++++++++++++++++++++++++++---
>   2 files changed, 72 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
> index 99b15b77dfd57..51eb5140caa14 100644
> --- a/drivers/usb/misc/Kconfig
> +++ b/drivers/usb/misc/Kconfig
> @@ -146,7 +146,7 @@ config USB_APPLEDISPLAY
>   
>   config USB_QCOM_EUD
>   	tristate "QCOM Embedded USB Debugger(EUD) Driver"
> -	depends on ARCH_QCOM || COMPILE_TEST
> +	depends on (ARCH_QCOM && QCOM_SCM) || COMPILE_TEST
>   	select USB_ROLE_SWITCH
>   	help
>   	  This module enables support for Qualcomm Technologies, Inc.
> diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
> index 7f371ea1248c3..a5b28fc24116a 100644
> --- a/drivers/usb/misc/qcom_eud.c
> +++ b/drivers/usb/misc/qcom_eud.c
> @@ -11,9 +11,12 @@
>   #include <linux/kernel.h>
>   #include <linux/module.h>
>   #include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
>   #include <linux/platform_device.h>
>   #include <linux/slab.h>
>   #include <linux/sysfs.h>
> +#include <linux/firmware/qcom/qcom_scm.h>
>   #include <linux/usb/role.h>
>   
>   #define EUD_REG_INT1_EN_MASK	0x0024
> @@ -30,6 +33,10 @@
>   #define EUD_INT_SAFE_MODE	BIT(4)
>   #define EUD_INT_ALL		(EUD_INT_VBUS | EUD_INT_SAFE_MODE)
>   
> +#define EUD_EN2_EN		BIT(0)
> +#define EUD_EN2_DISABLE		(0)
> +#define TCSR_CHECK_EN		BIT(0)
> +
>   struct eud_chip {
>   	struct device			*dev;
>   	struct usb_role_switch		*role_sw;
> @@ -39,6 +46,7 @@ struct eud_chip {
>   	int				irq;
>   	bool				enabled;
>   	bool				usb_attached;
> +	phys_addr_t			secure_mode_mgr;
>   };
>   
>   static int enable_eud(struct eud_chip *priv)
> @@ -46,7 +54,11 @@ static int enable_eud(struct eud_chip *priv)
>   	writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN);
>   	writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE,
>   			priv->base + EUD_REG_INT1_EN_MASK);
> -	writel(1, priv->mode_mgr + EUD_REG_EUD_EN2);
> +
> +	if (priv->secure_mode_mgr)
> +		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_EN);
> +	else
> +		writel(EUD_EN2_EN, priv->mode_mgr + EUD_REG_EUD_EN2);
>   
>   	return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE);
>   }
> @@ -54,7 +66,11 @@ static int enable_eud(struct eud_chip *priv)
>   static void disable_eud(struct eud_chip *priv)
>   {
>   	writel(0, priv->base + EUD_REG_CSR_EUD_EN);
> -	writel(0, priv->mode_mgr + EUD_REG_EUD_EN2);
> +
> +	if (priv->secure_mode_mgr)
> +		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_DISABLE);
> +	else
> +		writel(EUD_EN2_DISABLE, priv->mode_mgr + EUD_REG_EUD_EN2);
>   }
>   
>   static ssize_t enable_show(struct device *dev,
> @@ -175,9 +191,37 @@ static void eud_role_switch_release(void *data)
>   	usb_role_switch_put(chip->role_sw);
>   }
>   
> +static int eud_find_secure_reg_addr(struct device *dev, u64 *addr)
> +{
> +	struct device_node *tcsr;
> +	struct device_node *np = dev->of_node;
> +	struct resource res;
> +	u32 offset;
> +	int ret;
> +
> +	tcsr = of_parse_phandle(np, "qcom,secure-eud-reg", 0);
> +	if (!tcsr)
> +		return 0;
> +
> +	ret = of_address_to_resource(tcsr, 0, &res);
> +	of_node_put(tcsr);
> +	if (ret)
> +		return ret;
> +
> +	ret = of_property_read_u32_index(np, "qcom,secure-eud-reg", 1, &offset);
> +	if (ret < 0)
> +		return ret;
> +
> +	*addr = res.start + offset;
> +
> +	return 0;
> +}
> +
>   static int eud_probe(struct platform_device *pdev)
>   {
>   	struct eud_chip *chip;
> +	struct resource *res;
> +	phys_addr_t tcsr_check = 0;
>   	int ret;
>   
>   	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
> @@ -200,9 +244,30 @@ static int eud_probe(struct platform_device *pdev)
>   	if (IS_ERR(chip->base))
>   		return PTR_ERR(chip->base);
>   
> -	chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
> -	if (IS_ERR(chip->mode_mgr))
> -		return PTR_ERR(chip->mode_mgr);
> +	/*
> +	 * EUD block on a few Qualcomm SoCs needs secure register access.
> +	 * Check for the same via vendor-specific dt property.
> +	 */
> +	ret = eud_find_secure_reg_addr(&pdev->dev, &tcsr_check);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (tcsr_check) {
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +		if (!res)
> +			return dev_err_probe(chip->dev, -ENODEV,
> +					     "failed to get secure_mode_mgr reg base\n");
> +
> +		chip->secure_mode_mgr = res->start;

There are multiple instances where the addresses are being mapped from 
the dt property without using the devm version. Either we should switch 
to the later or ensure that these addresses are unmapped in the removal
path of the driver.

Thanks,
Souradeep

> +
> +		ret = qcom_scm_io_writel(tcsr_check, TCSR_CHECK_EN);
> +		if (ret)
> +			return dev_err_probe(chip->dev, ret, "failed to write tcsr check reg\n");
> +	} else {
> +		chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
> +		if (IS_ERR(chip->mode_mgr))
> +			return PTR_ERR(chip->mode_mgr);
> +	}
>   
>   	chip->irq = platform_get_irq(pdev, 0);
>   	ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq,
> @@ -230,6 +295,7 @@ static void eud_remove(struct platform_device *pdev)
>   
>   static const struct of_device_id eud_dt_match[] = {
>   	{ .compatible = "qcom,sc7280-eud" },
> +	{ .compatible = "qcom,sm6115-eud" },
>   	{ }
>   };
>   MODULE_DEVICE_TABLE(of, eud_dt_match);
  
kernel test robot July 19, 2023, 2:46 a.m. UTC | #3
Hi Bhupesh,

kernel test robot noticed the following build errors:

[auto build test ERROR on usb/usb-testing]
[also build test ERROR on usb/usb-next usb/usb-linus lee-mfd/for-mfd-next linus/master v6.5-rc2 next-20230718]
[cannot apply to robh/for-next lee-mfd/for-mfd-fixes]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Bhupesh-Sharma/dt-bindings-mfd-qcom-tcsr-Add-the-compatible-for-SM6115/20230718-190223
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb.git usb-testing
patch link:    https://lore.kernel.org/r/20230718061052.1332993-5-bhupesh.sharma%40linaro.org
patch subject: [PATCH v9 4/7] usb: misc: eud: Add driver support for SM6115 / SM4250
config: arm-allmodconfig (https://download.01.org/0day-ci/archive/20230719/202307191045.FMNOhyay-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230719/202307191045.FMNOhyay-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202307191045.FMNOhyay-lkp@intel.com/

All errors (new ones prefixed by >>):

   drivers/usb/misc/qcom_eud.c: In function 'eud_probe':
>> drivers/usb/misc/qcom_eud.c:251:52: error: passing argument 2 of 'eud_find_secure_reg_addr' from incompatible pointer type [-Werror=incompatible-pointer-types]
     251 |         ret = eud_find_secure_reg_addr(&pdev->dev, &tcsr_check);
         |                                                    ^~~~~~~~~~~
         |                                                    |
         |                                                    phys_addr_t * {aka unsigned int *}
   drivers/usb/misc/qcom_eud.c:194:62: note: expected 'u64 *' {aka 'long long unsigned int *'} but argument is of type 'phys_addr_t *' {aka 'unsigned int *'}
     194 | static int eud_find_secure_reg_addr(struct device *dev, u64 *addr)
         |                                                         ~~~~~^~~~
   cc1: some warnings being treated as errors

Kconfig warnings: (for reference only)
   WARNING: unmet direct dependencies detected for SM_GCC_8350
   Depends on [n]: COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] && (ARM64 || COMPILE_TEST [=n])
   Selected by [m]:
   - SM_VIDEOCC_8350 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m]
   WARNING: unmet direct dependencies detected for SM_GCC_8450
   Depends on [n]: COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] && (ARM64 || COMPILE_TEST [=n])
   Selected by [m]:
   - SM_GPUCC_8450 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m]
   - SM_VIDEOCC_8450 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m]
   WARNING: unmet direct dependencies detected for SM_GCC_8550
   Depends on [n]: COMMON_CLK [=y] && COMMON_CLK_QCOM [=m] && (ARM64 || COMPILE_TEST [=n])
   Selected by [m]:
   - SM_GPUCC_8550 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m]
   - SM_VIDEOCC_8550 [=m] && COMMON_CLK [=y] && COMMON_CLK_QCOM [=m]


vim +/eud_find_secure_reg_addr +251 drivers/usb/misc/qcom_eud.c

   219	
   220	static int eud_probe(struct platform_device *pdev)
   221	{
   222		struct eud_chip *chip;
   223		struct resource *res;
   224		phys_addr_t tcsr_check = 0;
   225		int ret;
   226	
   227		chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
   228		if (!chip)
   229			return -ENOMEM;
   230	
   231		chip->dev = &pdev->dev;
   232	
   233		chip->role_sw = usb_role_switch_get(&pdev->dev);
   234		if (IS_ERR(chip->role_sw))
   235			return dev_err_probe(chip->dev, PTR_ERR(chip->role_sw),
   236						"failed to get role switch\n");
   237	
   238		ret = devm_add_action_or_reset(chip->dev, eud_role_switch_release, chip);
   239		if (ret)
   240			return dev_err_probe(chip->dev, ret,
   241					"failed to add role switch release action\n");
   242	
   243		chip->base = devm_platform_ioremap_resource(pdev, 0);
   244		if (IS_ERR(chip->base))
   245			return PTR_ERR(chip->base);
   246	
   247		/*
   248		 * EUD block on a few Qualcomm SoCs needs secure register access.
   249		 * Check for the same via vendor-specific dt property.
   250		 */
 > 251		ret = eud_find_secure_reg_addr(&pdev->dev, &tcsr_check);
   252		if (ret < 0)
   253			return ret;
   254	
   255		if (tcsr_check) {
   256			res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
   257			if (!res)
   258				return dev_err_probe(chip->dev, -ENODEV,
   259						     "failed to get secure_mode_mgr reg base\n");
   260	
   261			chip->secure_mode_mgr = res->start;
   262	
   263			ret = qcom_scm_io_writel(tcsr_check, TCSR_CHECK_EN);
   264			if (ret)
   265				return dev_err_probe(chip->dev, ret, "failed to write tcsr check reg\n");
   266		} else {
   267			chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
   268			if (IS_ERR(chip->mode_mgr))
   269				return PTR_ERR(chip->mode_mgr);
   270		}
   271	
   272		chip->irq = platform_get_irq(pdev, 0);
   273		ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq,
   274				handle_eud_irq_thread, IRQF_ONESHOT, NULL, chip);
   275		if (ret)
   276			return dev_err_probe(chip->dev, ret, "failed to allocate irq\n");
   277	
   278		enable_irq_wake(chip->irq);
   279	
   280		platform_set_drvdata(pdev, chip);
   281	
   282		return 0;
   283	}
   284
  

Patch

diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 99b15b77dfd57..51eb5140caa14 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -146,7 +146,7 @@  config USB_APPLEDISPLAY
 
 config USB_QCOM_EUD
 	tristate "QCOM Embedded USB Debugger(EUD) Driver"
-	depends on ARCH_QCOM || COMPILE_TEST
+	depends on (ARCH_QCOM && QCOM_SCM) || COMPILE_TEST
 	select USB_ROLE_SWITCH
 	help
 	  This module enables support for Qualcomm Technologies, Inc.
diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
index 7f371ea1248c3..a5b28fc24116a 100644
--- a/drivers/usb/misc/qcom_eud.c
+++ b/drivers/usb/misc/qcom_eud.c
@@ -11,9 +11,12 @@ 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/sysfs.h>
+#include <linux/firmware/qcom/qcom_scm.h>
 #include <linux/usb/role.h>
 
 #define EUD_REG_INT1_EN_MASK	0x0024
@@ -30,6 +33,10 @@ 
 #define EUD_INT_SAFE_MODE	BIT(4)
 #define EUD_INT_ALL		(EUD_INT_VBUS | EUD_INT_SAFE_MODE)
 
+#define EUD_EN2_EN		BIT(0)
+#define EUD_EN2_DISABLE		(0)
+#define TCSR_CHECK_EN		BIT(0)
+
 struct eud_chip {
 	struct device			*dev;
 	struct usb_role_switch		*role_sw;
@@ -39,6 +46,7 @@  struct eud_chip {
 	int				irq;
 	bool				enabled;
 	bool				usb_attached;
+	phys_addr_t			secure_mode_mgr;
 };
 
 static int enable_eud(struct eud_chip *priv)
@@ -46,7 +54,11 @@  static int enable_eud(struct eud_chip *priv)
 	writel(EUD_ENABLE, priv->base + EUD_REG_CSR_EUD_EN);
 	writel(EUD_INT_VBUS | EUD_INT_SAFE_MODE,
 			priv->base + EUD_REG_INT1_EN_MASK);
-	writel(1, priv->mode_mgr + EUD_REG_EUD_EN2);
+
+	if (priv->secure_mode_mgr)
+		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_EN);
+	else
+		writel(EUD_EN2_EN, priv->mode_mgr + EUD_REG_EUD_EN2);
 
 	return usb_role_switch_set_role(priv->role_sw, USB_ROLE_DEVICE);
 }
@@ -54,7 +66,11 @@  static int enable_eud(struct eud_chip *priv)
 static void disable_eud(struct eud_chip *priv)
 {
 	writel(0, priv->base + EUD_REG_CSR_EUD_EN);
-	writel(0, priv->mode_mgr + EUD_REG_EUD_EN2);
+
+	if (priv->secure_mode_mgr)
+		qcom_scm_io_writel(priv->secure_mode_mgr + EUD_REG_EUD_EN2, EUD_EN2_DISABLE);
+	else
+		writel(EUD_EN2_DISABLE, priv->mode_mgr + EUD_REG_EUD_EN2);
 }
 
 static ssize_t enable_show(struct device *dev,
@@ -175,9 +191,37 @@  static void eud_role_switch_release(void *data)
 	usb_role_switch_put(chip->role_sw);
 }
 
+static int eud_find_secure_reg_addr(struct device *dev, u64 *addr)
+{
+	struct device_node *tcsr;
+	struct device_node *np = dev->of_node;
+	struct resource res;
+	u32 offset;
+	int ret;
+
+	tcsr = of_parse_phandle(np, "qcom,secure-eud-reg", 0);
+	if (!tcsr)
+		return 0;
+
+	ret = of_address_to_resource(tcsr, 0, &res);
+	of_node_put(tcsr);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32_index(np, "qcom,secure-eud-reg", 1, &offset);
+	if (ret < 0)
+		return ret;
+
+	*addr = res.start + offset;
+
+	return 0;
+}
+
 static int eud_probe(struct platform_device *pdev)
 {
 	struct eud_chip *chip;
+	struct resource *res;
+	phys_addr_t tcsr_check = 0;
 	int ret;
 
 	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
@@ -200,9 +244,30 @@  static int eud_probe(struct platform_device *pdev)
 	if (IS_ERR(chip->base))
 		return PTR_ERR(chip->base);
 
-	chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
-	if (IS_ERR(chip->mode_mgr))
-		return PTR_ERR(chip->mode_mgr);
+	/*
+	 * EUD block on a few Qualcomm SoCs needs secure register access.
+	 * Check for the same via vendor-specific dt property.
+	 */
+	ret = eud_find_secure_reg_addr(&pdev->dev, &tcsr_check);
+	if (ret < 0)
+		return ret;
+
+	if (tcsr_check) {
+		res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+		if (!res)
+			return dev_err_probe(chip->dev, -ENODEV,
+					     "failed to get secure_mode_mgr reg base\n");
+
+		chip->secure_mode_mgr = res->start;
+
+		ret = qcom_scm_io_writel(tcsr_check, TCSR_CHECK_EN);
+		if (ret)
+			return dev_err_probe(chip->dev, ret, "failed to write tcsr check reg\n");
+	} else {
+		chip->mode_mgr = devm_platform_ioremap_resource(pdev, 1);
+		if (IS_ERR(chip->mode_mgr))
+			return PTR_ERR(chip->mode_mgr);
+	}
 
 	chip->irq = platform_get_irq(pdev, 0);
 	ret = devm_request_threaded_irq(&pdev->dev, chip->irq, handle_eud_irq,
@@ -230,6 +295,7 @@  static void eud_remove(struct platform_device *pdev)
 
 static const struct of_device_id eud_dt_match[] = {
 	{ .compatible = "qcom,sc7280-eud" },
+	{ .compatible = "qcom,sm6115-eud" },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, eud_dt_match);