diff mbox series

[7/7] pinctrl: scmi: implement pinctrl_scmi_imx_dt_node_to_map

Message ID 20231215-pinctrl-scmi-v1-7-0fe35e4611f7@nxp.com
State Superseded
Headers show
Series firmware: arm_scmi: Add SCMI v3.2 pincontrol protocol basic support | expand

Commit Message

Peng Fan (OSS) Dec. 15, 2023, 11:56 a.m. UTC
From: Peng Fan <peng.fan@nxp.com>

i.MX95 System Manager FW supports SCMI PINCTRL protocol, but uses
OEM Pin Configuration type, so need i.MX specific dt_node_to_map.

Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
 drivers/pinctrl/Makefile           |   2 +-
 drivers/pinctrl/pinctrl-scmi-imx.c | 117 +++++++++++++++++++++++++++++++++++++
 drivers/pinctrl/pinctrl-scmi.c     |  16 +++++
 drivers/pinctrl/pinctrl-scmi.h     |  12 ++++
 4 files changed, 146 insertions(+), 1 deletion(-)

Comments

Cristian Marussi Dec. 22, 2023, 5:43 p.m. UTC | #1
On Fri, Dec 15, 2023 at 07:56:35PM +0800, Peng Fan (OSS) wrote:
> From: Peng Fan <peng.fan@nxp.com>
> 
> i.MX95 System Manager FW supports SCMI PINCTRL protocol, but uses
> OEM Pin Configuration type, so need i.MX specific dt_node_to_map.
> 

This does not even compile for me, as of now, when configuring the Pinctrl
SCMI driver as a module with your IMX custom additions. (I think the
Makefile with the additional pinctrl-imx is wrong in how describes the
objects composing the pinctrl-scmi module with IMX addons...)

ERROR: modpost: "pinctrl_scmi_imx_dt_node_to_map" [drivers/pinctrl/pinctrl-scmi.ko] undefined!              
make[3]: *** [dev/src/linux/scripts/Makefile.modpost:145: Module.symvers] Error 1                                   
make[2]: *** [dev/src/linux/Makefile:1863: modpost] Error 2                                                         
make[1]: *** [dev/src/linux/Makefile:234: __sub-make] Error 2 
make[1]: Leaving directory dev/out_linux       
make: *** [Makefile:234: __sub-make] Error 2                                                  

More in general, I think that this NXP OEM specific additions, which are
in general welcome (and indeed as you know part of the spec was modified
to allow for OEM specific needs), do NOT belong to this generic SCMI
Pinctrl driver, because the driver from Oleksii/EPAM was born as a
generic SCMI driver and it fits perfectly with the Generic Pinctrl
Linux subsystem and related generic bindings parsing: now with this
you are trying to stick a custom OEM slight varied behaviour (and
related binding) on top of a generic thing.

And this choice leads to a number of additional changes in the SCMI core
to support an even more complex handling of SCMI devices, which is
already too complex IMO..

IOW...I dont think that the whole idea of the per-protocol optional
compatible to be able to select slightly different behaviours/parsing
would have a great chance to fly sincerely...

I know there is an issue with having a completely distinct SCMI IMX
pinctrl driver that uses the same protocol node @19 (without the need for
the compatible trick) due to the way in which the Pinctrl subsystem
searches for devices (by of_node)...I'll think about an alternative
way to allow this but I am not sure (as you saw) that would be so easily
doable...

Also, I am wondering if this is really a problem in reality since I would
NOT expect you to load/ship both the OEM/NXP custom specific SCMI pinctrl
driver AND the generic one on the same platform (after having made them
distinct I mean...) am I wrong ?
(so you could even made them exclude each other at compile time...far
from being the best option I agree...)

Thanks,
Cristian
Peng Fan Dec. 23, 2023, 2:14 a.m. UTC | #2
> Subject: Re: [PATCH 7/7] pinctrl: scmi: implement
> pinctrl_scmi_imx_dt_node_to_map
> 
> On Fri, Dec 15, 2023 at 07:56:35PM +0800, Peng Fan (OSS) wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > i.MX95 System Manager FW supports SCMI PINCTRL protocol, but uses
> OEM
> > Pin Configuration type, so need i.MX specific dt_node_to_map.
> >
> 
> This does not even compile for me, as of now, when configuring the Pinctrl
> SCMI driver as a module with your IMX custom additions. (I think the
> Makefile with the additional pinctrl-imx is wrong in how describes the objects
> composing the pinctrl-scmi module with IMX addons...)
> 
> ERROR: modpost: "pinctrl_scmi_imx_dt_node_to_map"
> [drivers/pinctrl/pinctrl-scmi.ko] undefined!
> make[3]: *** [dev/src/linux/scripts/Makefile.modpost:145: Module.symvers]
> Error 1
> make[2]: *** [dev/src/linux/Makefile:1863: modpost] Error 2
> make[1]: *** [dev/src/linux/Makefile:234: __sub-make] Error 2
> make[1]: Leaving directory dev/out_linux
> make: *** [Makefile:234: __sub-make] Error 2

Oh, sorry for this. I could post a new version if you require. But before
that we may better align on the approach on how to support i.MX.

> 
> More in general, I think that this NXP OEM specific additions, which are in
> general welcome (and indeed as you know part of the spec was modified to
> allow for OEM specific needs), do NOT belong to this generic SCMI Pinctrl
> driver, because the driver from Oleksii/EPAM was born as a generic SCMI
> driver and it fits perfectly with the Generic Pinctrl Linux subsystem and
> related generic bindings parsing: now with this you are trying to stick a
> custom OEM slight varied behaviour (and related binding) on top of a generic
> thing.
> 
> And this choice leads to a number of additional changes in the SCMI core to
> support an even more complex handling of SCMI devices, which is already too
> complex IMO..
> 
> IOW...I dont think that the whole idea of the per-protocol optional
> compatible to be able to select slightly different behaviours/parsing would
> have a great chance to fly sincerely...
> 
> I know there is an issue with having a completely distinct SCMI IMX pinctrl
> driver that uses the same protocol node @19 (without the need for the
> compatible trick) due to the way in which the Pinctrl subsystem searches for
> devices (by of_node)...I'll think about an alternative way to allow this but I am
> not sure (as you saw) that would be so easily doable...

For all protocols supports VENDOR extension attributes, we need a way
to handle I think. 

As Linus wrote in
https://lore.kernel.org/all/CACRpkdaRY+rU+md-r5gVyFH5ATt3Pqp9=M4=+WArYkfVLAFdpw@mail.gmail.com/:

We may need:
protocol@19 {
    compatible = "vendor,soc-scmi-pinctrl";
(...)

> 
> Also, I am wondering if this is really a problem in reality since I would NOT
> expect you to load/ship both the OEM/NXP custom specific SCMI pinctrl
> driver AND the generic one on the same platform (after having made them
> distinct I mean...) am I wrong ?

You are right, but that means the upstream ARM64 defconfig will not 
able to support both i.MX9 and others.

Thanks,
Peng.

> (so you could even made them exclude each other at compile time...far from
> being the best option I agree...)
> 
> Thanks,
> Cristian
diff mbox series

Patch

diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index ba755ed2d46c..d96b7ede1355 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -44,7 +44,7 @@  obj-$(CONFIG_PINCTRL_PIC32)	+= pinctrl-pic32.o
 obj-$(CONFIG_PINCTRL_PISTACHIO)	+= pinctrl-pistachio.o
 obj-$(CONFIG_PINCTRL_RK805)	+= pinctrl-rk805.o
 obj-$(CONFIG_PINCTRL_ROCKCHIP)	+= pinctrl-rockchip.o
-obj-$(CONFIG_PINCTRL_SCMI)	+= pinctrl-scmi.o
+obj-$(CONFIG_PINCTRL_SCMI)	+= pinctrl-scmi.o pinctrl-scmi-imx.o
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_ST) 	+= pinctrl-st.o
 obj-$(CONFIG_PINCTRL_STMFX) 	+= pinctrl-stmfx.o
diff --git a/drivers/pinctrl/pinctrl-scmi-imx.c b/drivers/pinctrl/pinctrl-scmi-imx.c
new file mode 100644
index 000000000000..e9d02e4c2cc1
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-scmi-imx.c
@@ -0,0 +1,117 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 NXP
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "pinctrl-scmi.h"
+#include "pinctrl-utils.h"
+#include "core.h"
+#include "pinconf.h"
+
+/* SCMI pin control types, aligned with SCMI firmware */
+#define IMX_SCMI_PIN_TYPE_MUX		192
+#define IMX_SCMI_PIN_TYPE_CONFIG	193
+#define IMX_SCMI_PIN_TYPE_DAISY_ID	194
+#define IMX_SCMI_PIN_TYPE_DAISY_CFG	195
+
+#define IMX_SCMI_NO_PAD_CTL		BIT(31)
+#define IMX_SCMI_PAD_SION		BIT(30)
+#define IMX_SCMI_IOMUXC_CONFIG_SION	BIT(4)
+
+#define IMX_SCMI_NUM_CFG	4
+#define IMX_SCMI_PIN_SIZE	24
+
+int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np,
+				    struct pinctrl_map **map, unsigned int *num_maps)
+{
+	struct pinctrl_map *new_map;
+	const __be32 *list;
+	unsigned long *configs = NULL;
+	unsigned long cfg[IMX_SCMI_NUM_CFG];
+	int map_num, size, pin_size, pin_id, num_pins;
+	int mux_reg, conf_reg, input_reg, mux_val, conf_val, input_val;
+	int i, j;
+	uint32_t ncfg;
+	static uint32_t daisy_off;
+
+	if (!daisy_off) {
+		if (of_machine_is_compatible("fsl,imx95"))
+			daisy_off = 0x408;
+		else
+			dev_err(pctldev->dev, "platform not support scmi pinctrl\n");
+	}
+
+	list = of_get_property(np, "fsl,pins", &size);
+	if (!list) {
+		dev_err(pctldev->dev, "no fsl,pins property in node %pOF\n", np);
+		return -EINVAL;
+	}
+
+	pin_size = IMX_SCMI_PIN_SIZE;
+
+	if (!size || size % pin_size) {
+		dev_err(pctldev->dev, "Invalid fsl,pins or pins property in node %pOF\n", np);
+		return -EINVAL;
+	}
+
+	num_pins = size / pin_size;
+	map_num = num_pins;
+
+	new_map = kmalloc_array(map_num, sizeof(struct pinctrl_map),
+				GFP_KERNEL);
+	if (!new_map)
+		return -ENOMEM;
+
+	*map = new_map;
+	*num_maps = map_num;
+
+	/* create config map */
+	for (i = 0; i < num_pins; i++) {
+		j = 0;
+		ncfg = IMX_SCMI_NUM_CFG;
+		mux_reg = be32_to_cpu(*list++);
+		conf_reg = be32_to_cpu(*list++);
+		input_reg = be32_to_cpu(*list++);
+		mux_val = be32_to_cpu(*list++);
+		input_val = be32_to_cpu(*list++);
+		conf_val = be32_to_cpu(*list++);
+		if (conf_val & IMX_SCMI_PAD_SION)
+			mux_val |= IMX_SCMI_IOMUXC_CONFIG_SION;
+
+		pin_id = mux_reg / 4;
+
+		cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_TYPE_MUX, mux_val);
+
+		if (!conf_reg || (conf_val & IMX_SCMI_NO_PAD_CTL))
+			ncfg--;
+		else
+			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_TYPE_CONFIG, conf_val);
+
+		if (!input_reg) {
+			ncfg -= 2;
+		} else {
+			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_TYPE_DAISY_ID,
+							    (input_reg - daisy_off) / 4);
+			cfg[j++] = pinconf_to_config_packed(IMX_SCMI_PIN_TYPE_DAISY_CFG, input_val);
+		}
+
+		configs = kmemdup(cfg, ncfg * sizeof(unsigned long), GFP_KERNEL);
+
+		new_map[i].type = PIN_MAP_TYPE_CONFIGS_PIN;
+		new_map[i].data.configs.group_or_pin = pin_get_name(pctldev, pin_id);
+		new_map[i].data.configs.configs = configs;
+		new_map[i].data.configs.num_configs = ncfg;
+	}
+
+	return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-scmi.c b/drivers/pinctrl/pinctrl-scmi.c
index 0710ce9a1b42..e677e2064ba7 100644
--- a/drivers/pinctrl/pinctrl-scmi.c
+++ b/drivers/pinctrl/pinctrl-scmi.c
@@ -8,6 +8,7 @@ 
 #include <linux/device.h>
 #include <linux/err.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/seq_file.h>
 #include <linux/scmi_protocol.h>
 #include <linux/slab.h>
@@ -18,6 +19,7 @@ 
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinmux.h>
 
+#include "pinctrl-scmi.h"
 #include "pinctrl-utils.h"
 #include "core.h"
 #include "pinconf.h"
@@ -86,6 +88,16 @@  static const struct pinctrl_ops pinctrl_scmi_pinctrl_ops = {
 #endif
 };
 
+static const struct pinctrl_ops pinctrl_scmi_imx_pinctrl_ops = {
+	.get_groups_count = pinctrl_scmi_get_groups_count,
+	.get_group_name = pinctrl_scmi_get_group_name,
+	.get_group_pins = pinctrl_scmi_get_group_pins,
+#ifdef CONFIG_OF
+	.dt_node_to_map = pinctrl_scmi_imx_dt_node_to_map,
+	.dt_free_map = pinconf_generic_dt_free_map,
+#endif
+};
+
 static int pinctrl_scmi_get_functions_count(struct pinctrl_dev *pctldev)
 {
 	struct scmi_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
@@ -327,6 +339,7 @@  static int pinctrl_scmi_get_pins(struct scmi_pinctrl *pmx,
 
 static const struct scmi_device_id scmi_id_table[] = {
 	{ SCMI_PROTOCOL_PINCTRL, "pinctrl" },
+	{ SCMI_PROTOCOL_PINCTRL, "pinctrl-scmi-imx", "fsl,imx95-scmi-pinctrl" },
 	{ }
 };
 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
@@ -361,6 +374,9 @@  static int scmi_pinctrl_probe(struct scmi_device *sdev)
 	pmx->pctl_desc.pmxops = &pinctrl_scmi_pinmux_ops;
 	pmx->pctl_desc.confops = &pinctrl_scmi_pinconf_ops;
 
+	if (device_is_compatible(dev, "fsl,imx95-scmi-pinctrl"))
+		pmx->pctl_desc.pctlops = &pinctrl_scmi_imx_pinctrl_ops;
+
 	ret = pinctrl_scmi_get_pins(pmx, &pmx->pctl_desc.npins,
 				    &pmx->pctl_desc.pins);
 	if (ret)
diff --git a/drivers/pinctrl/pinctrl-scmi.h b/drivers/pinctrl/pinctrl-scmi.h
new file mode 100644
index 000000000000..25863b4428fe
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-scmi.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright 2023 NXP
+ */
+
+#ifndef __DRIVERS_PINCTRL_SCMI_H
+#define __DRIVERS_PINCTRL_SCMI_H
+
+int pinctrl_scmi_imx_dt_node_to_map(struct pinctrl_dev *pctldev, struct device_node *np,
+				    struct pinctrl_map **map, unsigned int *num_maps);
+
+#endif /* __DRIVERS_PINCTRL_SCMI_H */