Removed since could be reverse-applied by quilt and found to be included upstream: backport-5.4/789-net-usb-qmi_wwan-Set-DTR-quirk-for-MR400.patch All modifications made by update_kernel.sh Build system: x86_64 Build-tested: ipq806x/R7800, bcm27xx/bcm2711, ath79/generic Run-tested: ipq806x/R7800 No dmesg regressions, everything functional Signed-off-by: John Audia <graysky@archlinux.us> Tested-by: Curtis Deptuck <curtdept@me.com> [x86_64 build/run]
		
			
				
	
	
		
			194 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 140de383d9d26e8be300b7ba86d56b47898cd8c9 Mon Sep 17 00:00:00 2001
 | 
						|
From: Joakim Zhang <qiangqing.zhang@nxp.com>
 | 
						|
Date: Tue, 30 Jul 2019 18:01:11 +0800
 | 
						|
Subject: [PATCH] can: flexcan: add CAN wakeup function for i.MX8
 | 
						|
 | 
						|
The System Controller Firmware (SCFW) is a low-level system function
 | 
						|
which runs on a dedicated Cortex-M core to provide power, clock, and
 | 
						|
resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
 | 
						|
(QM, QP), and i.MX8QX (QXP, DX).
 | 
						|
 | 
						|
SCU driver manages the IPC interface between host CPU and the
 | 
						|
SCU firmware running on M4.
 | 
						|
 | 
						|
For i.MX8, stop mode request is controlled by System Controller Unit(SCU)
 | 
						|
firmware.
 | 
						|
 | 
						|
Signed-off-by: Joakim Zhang <qiangqing.zhang@nxp.com>
 | 
						|
---
 | 
						|
 drivers/net/can/flexcan.c | 99 ++++++++++++++++++++++++++++++++++++++++-------
 | 
						|
 1 file changed, 86 insertions(+), 13 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/can/flexcan.c
 | 
						|
+++ b/drivers/net/can/flexcan.c
 | 
						|
@@ -29,6 +29,11 @@
 | 
						|
 #include <linux/pinctrl/consumer.h>
 | 
						|
 #include <linux/regmap.h>
 | 
						|
 
 | 
						|
+#ifdef CONFIG_IMX_SCU_SOC
 | 
						|
+#include <linux/firmware/imx/sci.h>
 | 
						|
+#include <dt-bindings/firmware/imx/rsrc.h>
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 #define DRV_NAME			"flexcan"
 | 
						|
 
 | 
						|
 /* 8 for RX fifo and 2 error handling */
 | 
						|
@@ -223,6 +228,7 @@
 | 
						|
 #define FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN	BIT(7) /* default to BE register access */
 | 
						|
 #define FLEXCAN_QUIRK_SETUP_STOP_MODE		BIT(8) /* Setup stop mode to support wakeup */
 | 
						|
 #define FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD	BIT(9) /* Use timestamp then support can fd mode */
 | 
						|
+#define FLEXCAN_QUIRK_USE_SCFW			BIT(10) /* Use System Controller Firmware */
 | 
						|
 
 | 
						|
 /* Structure of the message buffer */
 | 
						|
 struct flexcan_mb {
 | 
						|
@@ -323,6 +329,11 @@ struct flexcan_priv {
 | 
						|
 	struct regulator *reg_xceiver;
 | 
						|
 	struct flexcan_stop_mode stm;
 | 
						|
 
 | 
						|
+#ifdef CONFIG_IMX_SCU_SOC
 | 
						|
+	/* IPC handle when enable stop mode by System Controller firmware(scfw) */
 | 
						|
+	struct imx_sc_ipc *sc_ipc_handle;
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 	/* Read and Write APIs */
 | 
						|
 	u32 (*read)(void __iomem *addr);
 | 
						|
 	void (*write)(u32 val, void __iomem *addr);
 | 
						|
@@ -352,7 +363,8 @@ static const struct flexcan_devtype_data
 | 
						|
 static struct flexcan_devtype_data fsl_imx8qm_devtype_data = {
 | 
						|
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 | 
						|
 		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
 | 
						|
-		FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD,
 | 
						|
+		FLEXCAN_QUIRK_TIMESTAMP_SUPPORT_FD | FLEXCAN_QUIRK_SETUP_STOP_MODE |
 | 
						|
+		FLEXCAN_QUIRK_USE_SCFW,
 | 
						|
 };
 | 
						|
 
 | 
						|
 static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
 | 
						|
@@ -503,6 +515,32 @@ static void flexcan_enable_wakeup_irq(st
 | 
						|
 	priv->write(reg_mcr, ®s->mcr);
 | 
						|
 }
 | 
						|
 
 | 
						|
+#ifdef CONFIG_IMX_SCU_SOC
 | 
						|
+static void flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
 | 
						|
+{
 | 
						|
+	struct device_node *np = priv->dev->of_node;
 | 
						|
+	u32 rsrc_id, val;
 | 
						|
+	int idx;
 | 
						|
+
 | 
						|
+	idx = of_alias_get_id(np, "can");
 | 
						|
+	if (idx == 0)
 | 
						|
+		rsrc_id = IMX_SC_R_CAN_0;
 | 
						|
+	else if (idx == 1)
 | 
						|
+		rsrc_id = IMX_SC_R_CAN_1;
 | 
						|
+	else
 | 
						|
+		rsrc_id = IMX_SC_R_CAN_2;
 | 
						|
+
 | 
						|
+	val = enabled ? 1 : 0;
 | 
						|
+	/* stop mode request */
 | 
						|
+	imx_sc_misc_set_control(priv->sc_ipc_handle, rsrc_id, IMX_SC_C_IPG_STOP, val);
 | 
						|
+}
 | 
						|
+#else
 | 
						|
+static int flexcan_stop_mode_enable_scfw(struct flexcan_priv *priv, bool enabled)
 | 
						|
+{
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 static inline int flexcan_enter_stop_mode(struct flexcan_priv *priv)
 | 
						|
 {
 | 
						|
 	struct flexcan_regs __iomem *regs = priv->regs;
 | 
						|
@@ -512,9 +550,12 @@ static inline int flexcan_enter_stop_mod
 | 
						|
 	reg_mcr |= FLEXCAN_MCR_SLF_WAK;
 | 
						|
 	priv->write(reg_mcr, ®s->mcr);
 | 
						|
 
 | 
						|
-	/* enable stop request */
 | 
						|
-	regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 | 
						|
-			   1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
 | 
						|
+	 /* enable stop request */
 | 
						|
+	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
 | 
						|
+		flexcan_stop_mode_enable_scfw(priv, true);
 | 
						|
+	else
 | 
						|
+		regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 | 
						|
+				   1 << priv->stm.req_bit, 1 << priv->stm.req_bit);
 | 
						|
 
 | 
						|
 	return flexcan_low_power_enter_ack(priv);
 | 
						|
 }
 | 
						|
@@ -525,8 +566,11 @@ static inline int flexcan_exit_stop_mode
 | 
						|
 	u32 reg_mcr;
 | 
						|
 
 | 
						|
 	/* remove stop request */
 | 
						|
-	regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 | 
						|
-			   1 << priv->stm.req_bit, 0);
 | 
						|
+	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
 | 
						|
+		flexcan_stop_mode_enable_scfw(priv, false);
 | 
						|
+	else
 | 
						|
+		regmap_update_bits(priv->stm.gpr, priv->stm.req_gpr,
 | 
						|
+				   1 << priv->stm.req_bit, 0);
 | 
						|
 
 | 
						|
 
 | 
						|
 	reg_mcr = priv->read(®s->mcr);
 | 
						|
@@ -1770,11 +1814,6 @@ static int flexcan_setup_stop_mode(struc
 | 
						|
 		gpr_np->full_name, priv->stm.req_gpr, priv->stm.req_bit,
 | 
						|
 		priv->stm.ack_gpr, priv->stm.ack_bit);
 | 
						|
 
 | 
						|
-	device_set_wakeup_capable(&pdev->dev, true);
 | 
						|
-
 | 
						|
-	if (of_property_read_bool(np, "wakeup-source"))
 | 
						|
-		device_set_wakeup_enable(&pdev->dev, true);
 | 
						|
-
 | 
						|
 	return 0;
 | 
						|
 
 | 
						|
 out_put_node:
 | 
						|
@@ -1782,6 +1821,30 @@ out_put_node:
 | 
						|
 	return ret;
 | 
						|
 }
 | 
						|
 
 | 
						|
+#ifdef CONFIG_IMX_SCU_SOC
 | 
						|
+static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
 | 
						|
+{
 | 
						|
+	struct net_device *dev = platform_get_drvdata(pdev);
 | 
						|
+	struct flexcan_priv *priv;
 | 
						|
+	int ret;
 | 
						|
+
 | 
						|
+	priv = netdev_priv(dev);
 | 
						|
+
 | 
						|
+	ret = imx_scu_get_handle(&(priv->sc_ipc_handle));
 | 
						|
+	if (ret < 0) {
 | 
						|
+		dev_err(&pdev->dev, "get ipc handle used by SCU failed\n");
 | 
						|
+		return ret;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+#else
 | 
						|
+static int flexcan_setup_stop_mode_scfw(struct platform_device *pdev)
 | 
						|
+{
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+#endif
 | 
						|
+
 | 
						|
 static const struct of_device_id flexcan_of_match[] = {
 | 
						|
 	{ .compatible = "fsl,imx8qm-flexcan", .data = &fsl_imx8qm_devtype_data, },
 | 
						|
 	{ .compatible = "fsl,imx6q-flexcan", .data = &fsl_imx6q_devtype_data, },
 | 
						|
@@ -1924,9 +1987,19 @@ static int flexcan_probe(struct platform
 | 
						|
 	devm_can_led_init(dev);
 | 
						|
 
 | 
						|
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SETUP_STOP_MODE) {
 | 
						|
-		err = flexcan_setup_stop_mode(pdev);
 | 
						|
-		if (err)
 | 
						|
+		if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_SCFW)
 | 
						|
+			err = flexcan_setup_stop_mode_scfw(pdev);
 | 
						|
+		else
 | 
						|
+			err = flexcan_setup_stop_mode(pdev);
 | 
						|
+
 | 
						|
+		if (err) {
 | 
						|
 			dev_dbg(&pdev->dev, "failed to setup stop-mode\n");
 | 
						|
+		} else {
 | 
						|
+			device_set_wakeup_capable(&pdev->dev, true);
 | 
						|
+
 | 
						|
+			if (of_property_read_bool(pdev->dev.of_node, "wakeup-source"))
 | 
						|
+				device_set_wakeup_enable(&pdev->dev, true);
 | 
						|
+		}
 | 
						|
 	}
 | 
						|
 
 | 
						|
 	return 0;
 |