loongarch.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Support pinctrl for Loongson 2K0300 SoC
@ 2025-08-11 16:37 Yao Zi
  2025-08-11 16:37 ` [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Yao Zi
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Yao Zi @ 2025-08-11 16:37 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Huacai Chen, WANG Xuerui
  Cc: linux-gpio, devicetree, linux-kernel, loongarch, Mingcong Bai,
	Kexy Biscuit, Yao Zi

This series adds support for Loongson 2K0300's pin controller, which is
much different from the previous generation's one: pin multiplexing
could be done for each pin, instead of at units of pin groups. A new
driver, pinctrl-ls2k0300.c, is introduced to handle this.

This controller is also capable of drive-strength configuration for some
functions, with a limitation that all pins configured to the the same
function share the same drive-strength. Thus drive-strength is described
as a property of function, and is handled bypassing the generic pinconf
API for less complexity, since the pinconf API is based on the pingroups.

The devicetree patch depends on v3 of "Add clock support for Loongson
2K0300 SoC"[1] for applying. Further comments, especially on handling of
the only pinconf attribute, drive-strength, will be appreciated. Thanks
again for your time and review.

[1]: https://lore.kernel.org/all/20250805150147.25909-1-ziyao@disroot.org/

Yao Zi (3):
  dt-binding: pinctrl: Document Loongson 2K0300 pin controller
  pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  LoongArch: dts: Add pinctrl configuration for Loongson 2K0300

 .../pinctrl/loongson,ls2k0300-pinctrl.yaml    |  92 ++++
 MAINTAINERS                                   |   7 +
 arch/loongarch/boot/dts/loongson-2k0300.dtsi  |  39 ++
 drivers/pinctrl/Kconfig                       |  14 +
 drivers/pinctrl/Makefile                      |   1 +
 drivers/pinctrl/pinctrl-ls2k0300.c            | 515 ++++++++++++++++++
 6 files changed, 668 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
 create mode 100644 drivers/pinctrl/pinctrl-ls2k0300.c

-- 
2.50.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller
  2025-08-11 16:37 [PATCH 0/3] Support pinctrl for Loongson 2K0300 SoC Yao Zi
@ 2025-08-11 16:37 ` Yao Zi
  2025-08-18 17:58   ` Rob Herring
  2025-08-11 16:37 ` [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Yao Zi
  2025-08-11 16:37 ` [PATCH 3/3] LoongArch: dts: Add pinctrl configuration for Loongson 2K0300 Yao Zi
  2 siblings, 1 reply; 10+ messages in thread
From: Yao Zi @ 2025-08-11 16:37 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Huacai Chen, WANG Xuerui
  Cc: linux-gpio, devicetree, linux-kernel, loongarch, Mingcong Bai,
	Kexy Biscuit, Yao Zi

The pincontroller integarted in Loongson 2K0300 is able to configure
function multiplexing for all the pins. It could also configure drive
strength on basis of functions, which means all pins set to the same
function share drive-strength setting. Drive-strength configuration
isn't available for all functions, either.

This binding utilizes two levels of subnodes, where the outer represents
function and the inner represents groups. Drive-strength is allowed in
the outer since it's shared among all groups configured to the function.

Signed-off-by: Yao Zi <ziyao@disroot.org>
---
 .../pinctrl/loongson,ls2k0300-pinctrl.yaml    | 92 +++++++++++++++++++
 MAINTAINERS                                   |  6 ++
 2 files changed, 98 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
new file mode 100644
index 000000000000..cbd74cb45342
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/loongson,ls2k0300-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Loongson-2K0300 SoC Pinctrl Controller
+
+maintainers:
+  - Yao Zi <ziyao@disroot.org>
+
+allOf:
+  - $ref: pinctrl.yaml#
+
+properties:
+  compatible:
+    const: loongson,ls2k0300-pinctrl
+
+  reg:
+    items:
+      - description: Pin function-multiplexing configuration registers
+      - description: Pin drive-strength configuration registers
+
+  reg-names:
+    items:
+      - const: mux
+      - const: drive
+
+patternProperties:
+  '^func-':
+    type: object
+
+    $ref: pincfg-node.yaml#
+
+    properties:
+      drive-strength:
+        description:
+          Maximum sink or source current as defined in pincfg-node.yaml. Note
+          that drive strength could only be configured on function basis, i.e.,
+          all pins multiplexed to the same function share the same
+          configuration.
+
+          This could only be configured for several functions, including jtag,
+          dvo, uart, gmac, sdio, spi, i2s, timer, usb and emmc.
+        enum: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+    additionalProperties: false
+
+    patternProperties:
+      '-pins$':
+        type: object
+        $ref: pinmux-node.yaml#
+
+        properties:
+          pinmux:
+            description:
+              Integer array, represents GPIO pin number and multiplexing
+              setting. Configuration for each pin takes one cell. The pin
+              number locates at the high 24 bits, and the setting locates at
+              the low 8 bits.
+
+        additionalProperties: false
+
+        required:
+          - pinmux
+
+required:
+  - compatible
+  - reg
+  - reg-names
+
+additionalProperties: false
+
+examples:
+  - |
+    pinctrl@1fe00420 {
+        compatible = "loongson,ls2k0300-pinctrl";
+        reg = <0x16000490 0x20>, <0x16000110 0x4>;
+        reg-names = "mux", "drive";
+
+        func-uart {
+            drive-strength = <2>;
+
+            uart0-pins {
+                pinmux = <((40 << 8) | 0x3)>, <((41 << 8) | 0x3)>;
+            };
+
+            uart1_pins: uart1-pins {
+                pinmux = <((42 << 8) | 0x3)>, <((43 << 8) | 0x3)>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 7960e65d7dfc..dd50571b4072 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14414,6 +14414,12 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
 F:	drivers/thermal/loongson2_thermal.c
 
+LOONGSON-2K0300 SOC PINCTRL DRIVER
+M:	Yao Zi <ziyao@disroot.org>
+L:	linux-gpio@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
+
 LOONGSON EDAC DRIVER
 M:	Zhao Qunqin <zhaoqunqin@loongson.cn>
 L:	linux-edac@vger.kernel.org
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  2025-08-11 16:37 [PATCH 0/3] Support pinctrl for Loongson 2K0300 SoC Yao Zi
  2025-08-11 16:37 ` [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Yao Zi
@ 2025-08-11 16:37 ` Yao Zi
  2025-08-14  3:15   ` Yao Zi
  2025-08-19 10:02   ` Linus Walleij
  2025-08-11 16:37 ` [PATCH 3/3] LoongArch: dts: Add pinctrl configuration for Loongson 2K0300 Yao Zi
  2 siblings, 2 replies; 10+ messages in thread
From: Yao Zi @ 2025-08-11 16:37 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Huacai Chen, WANG Xuerui
  Cc: linux-gpio, devicetree, linux-kernel, loongarch, Mingcong Bai,
	Kexy Biscuit, Yao Zi

Support pin multiplexing and drive-strength setting for Loongson 2K0300
SoC. Pin multiplexing could be done separately for each pin, while
drive-strength could be only configured on function basis. This differs
a lot from the driver for previous generation of Loongson SoC, where
pinmux setting is based on group.

Pins are represented with pinmux properties in devicetrees, and we use
the generic pinmux API for parsing. The common pinconf interface isn't
used for drive-strength setting, since it handles pinconf settings at a
unit of pin groups or smaller.

Instead, the driver configures drive-strength settings just after
parsing the devicetree. The devicetree's structure ensures no conflicts
could happen in drive-strength settings.

Signed-off-by: Yao Zi <ziyao@disroot.org>
---
 MAINTAINERS                        |   1 +
 drivers/pinctrl/Kconfig            |  14 +
 drivers/pinctrl/Makefile           |   1 +
 drivers/pinctrl/pinctrl-ls2k0300.c | 515 +++++++++++++++++++++++++++++
 4 files changed, 531 insertions(+)
 create mode 100644 drivers/pinctrl/pinctrl-ls2k0300.c

diff --git a/MAINTAINERS b/MAINTAINERS
index dd50571b4072..e22d6a280f6c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14419,6 +14419,7 @@ M:	Yao Zi <ziyao@disroot.org>
 L:	linux-gpio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
+F:	drivers/pinctrl/pinctrl-ls2k0300.c
 
 LOONGSON EDAC DRIVER
 M:	Zhao Qunqin <zhaoqunqin@loongson.cn>
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index ddd11668457c..c45abf89211c 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -344,6 +344,20 @@ config PINCTRL_LOONGSON2
 	 pull-down functions are not supported. Say yes to enable
 	 pinctrl for Loongson-2 SoC.
 
+config PINCTRL_LS2K0300
+	bool "Pinctrl driver for Loongson-2K0300 SoC"
+	depends on OF
+	depends on LOONGARCH || COMPILE_TEST
+	select GENERIC_PINCONF
+	select GENERIC_PINCTRL_GROUPS
+	select GENERIC_PINMUX_FUNCTIONS
+	help
+	  This selects pin controller driver for the Loongson-2K0300 SoC.
+	  It supports pin function multiplexing and drive-strength
+	  configuration.
+
+	  If compiled as a module, the module name will be pinctrl-ls2k0300.
+
 config PINCTRL_XWAY
 	bool
 	depends on SOC_TYPE_XWAY
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 909ab89a56d2..8c65357dad40 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_PINCTRL_KEEMBAY)	+= pinctrl-keembay.o
 obj-$(CONFIG_PINCTRL_LANTIQ)	+= pinctrl-lantiq.o
 obj-$(CONFIG_PINCTRL_FALCON)	+= pinctrl-falcon.o
 obj-$(CONFIG_PINCTRL_LOONGSON2) += pinctrl-loongson2.o
+obj-$(CONFIG_PINCTRL_LS2K0300)	+= pinctrl-ls2k0300.o
 obj-$(CONFIG_PINCTRL_XWAY)	+= pinctrl-xway.o
 obj-$(CONFIG_PINCTRL_LPC18XX)	+= pinctrl-lpc18xx.o
 obj-$(CONFIG_PINCTRL_MAX77620)	+= pinctrl-max77620.o
diff --git a/drivers/pinctrl/pinctrl-ls2k0300.c b/drivers/pinctrl/pinctrl-ls2k0300.c
new file mode 100644
index 000000000000..11d448ba333d
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-ls2k0300.c
@@ -0,0 +1,515 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl driver for Loongson-2K0300 SoC
+ * Copyright (c) 2025 Yao Zi <ziyao@disroot.org>
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "core.h"
+#include "pinconf.h"
+#include "pinctrl-utils.h"
+
+#define LS2K0300_MUX_MASK		GENMASK(1, 0)
+#define LS2K0300_PIN_TO_OFFSET(pin)	((pin) / 16 * 4)
+#define LS2K0300_PIN_TO_SHIFT(pin)	((pin) % 16 * 2)
+
+#define LS2K0300_DRIVE_STRENGTH_MIN	2
+#define LS2K0300_DRIVE_STRENGTH_MAX	12
+
+#define LS2K0300_DRIVE_STRENGTH_DEFAULT	0xff
+
+static struct pinctrl_pin_desc ls2k0300_pins[] = {
+	PINCTRL_PIN(0, "LCD_CLK"),
+	PINCTRL_PIN(1, "LCD_VSYNC"),
+	PINCTRL_PIN(2, "LCD_HSYNC"),
+	PINCTRL_PIN(3, "LCD_EN"),
+	PINCTRL_PIN(4, "LCD_D0"),
+	PINCTRL_PIN(5, "LCD_D1"),
+	PINCTRL_PIN(6, "LCD_D2"),
+	PINCTRL_PIN(7, "LCD_D3"),
+	PINCTRL_PIN(8, "LCD_D4"),
+	PINCTRL_PIN(9, "LCD_D5"),
+	PINCTRL_PIN(10, "LCD_D6"),
+	PINCTRL_PIN(11, "LCD_D7"),
+	PINCTRL_PIN(12, "LCD_D8"),
+	PINCTRL_PIN(13, "LCD_D9"),
+	PINCTRL_PIN(14, "LCD_D10"),
+	PINCTRL_PIN(15, "LCD_D11"),
+	PINCTRL_PIN(16, "LCD_D12"),
+	PINCTRL_PIN(17, "LCD_D13"),
+	PINCTRL_PIN(18, "LCD_D14"),
+	PINCTRL_PIN(19, "LCD_D15"),
+	PINCTRL_PIN(20, "LCD_D16"),
+	PINCTRL_PIN(21, "LCD_D17"),
+	PINCTRL_PIN(22, "LCD_D19"),
+	PINCTRL_PIN(23, "LCD_D19"),
+	PINCTRL_PIN(24, "LCD_D20"),
+	PINCTRL_PIN(25, "LCD_D21"),
+	PINCTRL_PIN(26, "LCD_D22"),
+	PINCTRL_PIN(27, "LCD_D23"),
+	PINCTRL_PIN(28, "GMAC0_RX_CTL"),
+	PINCTRL_PIN(29, "GMAC0_RX0"),
+	PINCTRL_PIN(30, "GMAC0_RX1"),
+	PINCTRL_PIN(31, "GMAC0_RX2"),
+	PINCTRL_PIN(32, "GMAC0_RX3"),
+	PINCTRL_PIN(33, "GMAC0_TX_CTL"),
+	PINCTRL_PIN(34, "GMAC0_TX0"),
+	PINCTRL_PIN(35, "GMAC0_TX1"),
+	PINCTRL_PIN(36, "GMAC0_TX2"),
+	PINCTRL_PIN(37, "GMAC0_TX3"),
+	PINCTRL_PIN(38, "GMAC0_MDCK"),
+	PINCTRL_PIN(39, "GMAC0_MDIO"),
+	PINCTRL_PIN(40, "UART0_RX"),
+	PINCTRL_PIN(41, "UART0_TX"),
+	PINCTRL_PIN(42, "UART1_RX"),
+	PINCTRL_PIN(43, "UART1_TX"),
+	PINCTRL_PIN(44, "UART2_TX"),
+	PINCTRL_PIN(45, "UART2_RX"),
+	PINCTRL_PIN(46, "UART3_TX"),
+	PINCTRL_PIN(47, "UART3_RX"),
+	PINCTRL_PIN(48, "I2C0_SCL"),
+	PINCTRL_PIN(49, "I2C0_SDA"),
+	PINCTRL_PIN(50, "I2C1_SCL"),
+	PINCTRL_PIN(51, "I2C1_SDA"),
+	PINCTRL_PIN(52, "I2C2_SCL"),
+	PINCTRL_PIN(53, "I2C2_SDA"),
+	PINCTRL_PIN(54, "I2C3_SCL"),
+	PINCTRL_PIN(55, "I2C3_SDA"),
+	PINCTRL_PIN(56, "SPI0_CLK"),
+	PINCTRL_PIN(57, "SPI0_MISO"),
+	PINCTRL_PIN(58, "SPI0_MOSI"),
+	PINCTRL_PIN(59, "SPI0_CS"),
+	PINCTRL_PIN(60, "SPI1_CLK"),
+	PINCTRL_PIN(61, "SPI1_MISO"),
+	PINCTRL_PIN(62, "SPI1_MOSI"),
+	PINCTRL_PIN(63, "SPI1_CS"),
+	PINCTRL_PIN(64, "SPI2_CLK"),
+	PINCTRL_PIN(65, "SPI2_MISO"),
+	PINCTRL_PIN(66, "SPI2_MOSI"),
+	PINCTRL_PIN(67, "SPI2_CS"),
+	PINCTRL_PIN(68, "CAN0_RX"),
+	PINCTRL_PIN(69, "CAN0_TX"),
+	PINCTRL_PIN(70, "CAN1_RX"),
+	PINCTRL_PIN(71, "CAN1_TX"),
+	PINCTRL_PIN(72, "CAN2_RX"),
+	PINCTRL_PIN(73, "CAN2_TX"),
+	PINCTRL_PIN(74, "CAN3_RX"),
+	PINCTRL_PIN(75, "CAN3_TX"),
+	PINCTRL_PIN(76, "I2S_MCLK"),
+	PINCTRL_PIN(77, "I2S_BCLK"),
+	PINCTRL_PIN(78, "I2S_LR"),
+	PINCTRL_PIN(79, "I2S_DI"),
+	PINCTRL_PIN(80, "I2S_DO"),
+	PINCTRL_PIN(81, "TIM1_CH1"),
+	PINCTRL_PIN(82, "TIM1_CH2"),
+	PINCTRL_PIN(83, "TIM1_CH3"),
+	PINCTRL_PIN(84, "TIM1_CH1N"),
+	PINCTRL_PIN(85, "TIM1_CH2N"),
+	PINCTRL_PIN(86, "TIM1_CH3N"),
+	PINCTRL_PIN(87, "TIM2_CH1"),
+	PINCTRL_PIN(88, "TIM2_CH2"),
+	PINCTRL_PIN(89, "TIM2_CH3"),
+	PINCTRL_PIN(90, "SDIO0_CLK"),
+	PINCTRL_PIN(91, "SDIO0_CMD"),
+	PINCTRL_PIN(92, "SDIO0_D0"),
+	PINCTRL_PIN(93, "SDIO0_D1"),
+	PINCTRL_PIN(94, "SDIO0_D2"),
+	PINCTRL_PIN(95, "SDIO0_D3"),
+	PINCTRL_PIN(96, "SDIO0_D4"),
+	PINCTRL_PIN(97, "SDIO0_D5"),
+	PINCTRL_PIN(98, "SDIO0_D6"),
+	PINCTRL_PIN(99, "SDIO0_D7"),
+	PINCTRL_PIN(100, "SDIO1_CLK"),
+	PINCTRL_PIN(101, "SDIO1_CMD"),
+	PINCTRL_PIN(102, "SDIO1_D0"),
+	PINCTRL_PIN(103, "SDIO1_D1"),
+	PINCTRL_PIN(104, "SDIO1_D2"),
+	PINCTRL_PIN(105, "SDIO1_D3"),
+};
+
+struct ls2k0300_pinctrl_drive_conf {
+	const char *func;
+	unsigned int width;
+	unsigned int shift;
+};
+
+static struct ls2k0300_pinctrl_drive_conf ls2k0300_pinctrl_drive_confs[] = {
+	{ .func = "func-jtag",	.width = 2, .shift = 8 },
+	{ .func = "func-dvo",	.width = 2, .shift = 10 },
+	{ .func = "func-uart",	.width = 2, .shift = 12 },
+	{ .func = "func-gmac",	.width = 2, .shift = 14 },
+	{ .func = "func-sdio",	.width = 2, .shift = 16 },
+	{ .func = "func-spi",	.width = 2, .shift = 18 },
+	{ .func = "func-i2s",	.width = 2, .shift = 20 },
+	{ .func = "func-timer",	.width = 2, .shift = 22 },
+	{ .func = "func-usb",	.width = 2, .shift = 24 },
+	{ .func = "func-emmc",	.width = 3, .shift = 26 },
+};
+
+struct ls2k0300_pinctrl_group {
+	const char *name;
+	unsigned int *pins;
+	unsigned int npins;
+	unsigned int *muxes;
+};
+
+struct ls2k0300_pinctrl_func {
+	const char *name;
+	const char **group_names;
+	unsigned int *groups;
+	unsigned int ngroups;
+};
+
+struct ls2k0300_pinctrl {
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_desc pdesc;
+	struct device *dev;
+
+	struct ls2k0300_pinctrl_group *groups;
+	unsigned int ngroups;
+
+	struct ls2k0300_pinctrl_func *funcs;
+	unsigned int nfuncs;
+
+	u8 drive_confs[ARRAY_SIZE(ls2k0300_pinctrl_drive_confs)];
+
+	spinlock_t lock;
+
+	void __iomem *reg_mux;
+	void __iomem *reg_drive;
+};
+
+static int ls2k0300_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctrl->ngroups;
+}
+
+static const char *ls2k0300_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
+						   unsigned int selector)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctrl->groups[selector].name;
+}
+
+static int ls2k0300_pinctrl_get_group_pins(struct pinctrl_dev *pctldev,
+					   unsigned int selector,
+					   const unsigned int **pins,
+					   unsigned int *num_pins)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	struct ls2k0300_pinctrl_group *group = &pctrl->groups[selector];
+
+	*pins		= group->pins;
+	*num_pins	= group->npins;
+
+	return 0;
+}
+
+static const struct pinctrl_ops ls2k0300_pctrl_ops = {
+	.get_groups_count	= ls2k0300_pinctrl_get_groups_count,
+	.get_group_name		= ls2k0300_pinctrl_get_group_name,
+	.get_group_pins		= ls2k0300_pinctrl_get_group_pins,
+	.dt_node_to_map		= pinconf_generic_dt_node_to_map_pinmux,
+	.dt_free_map		= pinctrl_utils_free_map,
+};
+
+static int ls2k0300_pinmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctrl->nfuncs;
+}
+
+static const char *
+ls2k0300_pinmux_get_function_name(struct pinctrl_dev *pctldev,
+				  unsigned int selector)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+	return pctrl->funcs[selector].name;
+}
+
+static int ls2k0300_pinmux_get_function_groups(struct pinctrl_dev *pctldev,
+					       unsigned int selector,
+					       const char *const **groups,
+					       unsigned int *num_groups)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+	struct ls2k0300_pinctrl_func *func = &pctrl->funcs[selector];
+
+	*groups		= func->group_names;
+	*num_groups	= func->ngroups;
+
+	return 0;
+}
+
+static int ls2k0300_pinmux_set_mux(struct pinctrl_dev *pctrldev,
+				   unsigned int func_selector,
+				   unsigned int group_selector)
+{
+	struct ls2k0300_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctrldev);
+	struct ls2k0300_pinctrl_group *group = &pctrl->groups[group_selector];
+	unsigned int *muxes = group->muxes, *pins = group->pins;
+	unsigned int off, shift, i;
+	u32 reg;
+
+	guard(spinlock_irqsave)(&pctrl->lock);
+
+	for (i = 0; i < group->npins; i++) {
+		off	= LS2K0300_PIN_TO_OFFSET(pins[i]);
+		shift	= LS2K0300_PIN_TO_SHIFT(pins[i]);
+
+		reg = readl(pctrl->reg_mux + off);
+		reg &= ~(LS2K0300_MUX_MASK << shift);
+		reg |= muxes[i] << shift;
+		writel(reg, pctrl->reg_mux + off);
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops ls2k0300_pmux_ops = {
+	.get_functions_count	= ls2k0300_pinmux_get_functions_count,
+	.get_function_name	= ls2k0300_pinmux_get_function_name,
+	.get_function_groups	= ls2k0300_pinmux_get_function_groups,
+	.set_mux		= ls2k0300_pinmux_set_mux,
+};
+
+static int ls2k0300_pinctrl_parse_group(struct device *dev,
+					struct ls2k0300_pinctrl *pctrl,
+					struct device_node *np,
+					struct ls2k0300_pinctrl_group *group)
+{
+	group->name = np->name;
+
+	return pinconf_generic_parse_dt_pinmux(np, dev, &group->pins,
+					       &group->muxes,
+					       &group->npins);
+}
+
+static int ls2k0300_pinctrl_parse_function(struct device *dev,
+					   struct ls2k0300_pinctrl *pctrl,
+					   struct device_node *np,
+					   struct ls2k0300_pinctrl_func *func)
+{
+	struct ls2k0300_pinctrl_group *group;
+	unsigned int i;
+	int ret;
+
+	func->ngroups = of_get_child_count(np);
+
+	func->groups = devm_kcalloc(dev, func->ngroups, sizeof(*func->groups),
+				    GFP_KERNEL);
+	func->group_names = devm_kcalloc(dev, func->ngroups,
+					 sizeof(*func->group_names),
+					 GFP_KERNEL);
+	if (!func->groups || !func->group_names)
+		return -ENOMEM;
+
+	func->name = np->name;
+
+	i = 0;
+
+	for_each_child_of_node_scoped(np, child) {
+		group = &pctrl->groups[pctrl->ngroups];
+
+		ret = ls2k0300_pinctrl_parse_group(dev, pctrl, child, group);
+		if (ret)
+			return ret;
+
+		func->groups[i]		= pctrl->ngroups;
+		func->group_names[i]	= group->name;
+
+		i++;
+		pctrl->ngroups++;
+	}
+
+	return 0;
+}
+
+static int drive_strength_ma_to_val(struct ls2k0300_pinctrl_drive_conf *conf,
+				    u32 drive_strength_ma, u8 *val)
+{
+	u8 val_max;
+
+	if (drive_strength_ma < LS2K0300_DRIVE_STRENGTH_MIN ||
+	    drive_strength_ma > LS2K0300_DRIVE_STRENGTH_MAX)
+		return -EINVAL;
+
+	val_max = (1 << conf->width) - 1;
+	*val = (drive_strength_ma - LS2K0300_DRIVE_STRENGTH_MIN) * val_max;
+	*val = DIV_ROUND_UP(*val, LS2K0300_DRIVE_STRENGTH_MAX -
+				  LS2K0300_DRIVE_STRENGTH_MIN + 1);
+
+	return 0;
+}
+
+static int ls2k0300_pinctrl_parse_drive(struct device *dev,
+					struct ls2k0300_pinctrl *pctrl,
+					struct device_node *np)
+{
+	struct ls2k0300_pinctrl_drive_conf *conf;
+	struct device_node *func_np;
+	u32 drive_strength_ma;
+	int ret, i;
+
+	memset(pctrl->drive_confs, LS2K0300_DRIVE_STRENGTH_DEFAULT,
+	       ARRAY_SIZE(pctrl->drive_confs));
+
+	for (i = 0; i < ARRAY_SIZE(ls2k0300_pinctrl_drive_confs); i++) {
+		conf = &ls2k0300_pinctrl_drive_confs[i];
+
+		func_np = of_get_child_by_name(np, conf->func);
+		if (!func_np)
+			continue;
+
+		ret = of_property_read_u32(func_np, "drive-strength",
+					   &drive_strength_ma);
+		of_node_put(func_np);
+		if (ret == -EINVAL)
+			continue;
+		else if (ret)
+			return ret;
+
+		ret = drive_strength_ma_to_val(conf, drive_strength_ma,
+					       &pctrl->drive_confs[i]);
+		if (ret) {
+			dev_err(dev, "invalid drive-strength %d for \"%s\"\n",
+				drive_strength_ma, conf->func);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int ls2k0300_pinctrl_parse_dt(struct device *dev,
+				     struct ls2k0300_pinctrl *pctrl)
+{
+	struct device_node *np = dev->of_node;
+	struct ls2k0300_pinctrl_func *func;
+	unsigned int ngroups, nfuncs;
+	int ret;
+
+	for_each_child_of_node_scoped(np, child) {
+		nfuncs++;
+		ngroups += of_get_child_count(child);
+	}
+
+	pctrl->groups = devm_kcalloc(dev, ngroups, sizeof(*pctrl->groups),
+				     GFP_KERNEL);
+	pctrl->funcs = devm_kcalloc(dev, nfuncs, sizeof(*pctrl->funcs),
+				    GFP_KERNEL);
+	if (!pctrl->groups || !pctrl->funcs)
+		return -ENOMEM;
+
+	for_each_child_of_node_scoped(np, child) {
+		func = &pctrl->funcs[pctrl->nfuncs++];
+
+		ret = ls2k0300_pinctrl_parse_function(dev, pctrl, child, func);
+		if (ret)
+			return ret;
+	}
+
+	return ls2k0300_pinctrl_parse_drive(dev, pctrl, np);
+}
+
+static void ls2k0300_pinctrl_set_drive_strength(struct ls2k0300_pinctrl *pctrl)
+{
+	struct ls2k0300_pinctrl_drive_conf *conf;
+	u32 reg;
+	int i;
+
+	reg = readl(pctrl->reg_drive);
+
+	for (i = 0; i < ARRAY_SIZE(ls2k0300_pinctrl_drive_confs); i++) {
+		if (pctrl->drive_confs[i] == LS2K0300_DRIVE_STRENGTH_DEFAULT)
+			continue;
+
+		conf = &ls2k0300_pinctrl_drive_confs[i];
+		reg &= ~GENMASK(conf->shift + conf->width - 1, conf->shift);
+		reg |= pctrl->drive_confs[i] << conf->shift;
+	}
+
+	writel(reg, pctrl->reg_drive);
+}
+
+static int ls2k0300_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ls2k0300_pinctrl *pctrl;
+	int ret;
+
+	pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
+	if (!pctrl)
+		return -ENOMEM;
+
+	pctrl->reg_mux = devm_platform_ioremap_resource_byname(pdev, "mux");
+	if (IS_ERR(pctrl->reg_mux))
+		return dev_err_probe(dev, PTR_ERR(pctrl->reg_mux),
+				     "failed to map mux registers\n");
+
+	pctrl->reg_drive = devm_platform_ioremap_resource_byname(pdev, "drive");
+	if (IS_ERR(pctrl->reg_drive))
+		return dev_err_probe(dev, PTR_ERR(pctrl->reg_drive),
+				     "failed to map drive registers\n");
+
+	ret = ls2k0300_pinctrl_parse_dt(dev, pctrl);
+	if (ret)
+		return dev_err_probe(dev, ret, "failed to parse devicetree\n");
+
+	ls2k0300_pinctrl_set_drive_strength(pctrl);
+
+	spin_lock_init(&pctrl->lock);
+
+	pctrl->dev		= dev;
+	pctrl->pdesc.name	= "pinctrl-ls2k0300";
+	pctrl->pdesc.owner	= THIS_MODULE;
+	pctrl->pdesc.pins	= ls2k0300_pins;
+	pctrl->pdesc.npins	= ARRAY_SIZE(ls2k0300_pins);
+	pctrl->pdesc.pctlops	= &ls2k0300_pctrl_ops;
+	pctrl->pdesc.pmxops	= &ls2k0300_pmux_ops;
+	pctrl->pdesc.owner	= THIS_MODULE;
+
+	pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pdesc, pctrl);
+	if (IS_ERR(pctrl->pctldev))
+		return dev_err_probe(pctrl->dev, PTR_ERR(pctrl->pctldev),
+				     "failed to register pinctrl device");
+
+	return 0;
+}
+
+static const struct of_device_id ls2k0300_pinctrl_of_match[] = {
+	{ .compatible = "loongson,ls2k0300-pinctrl" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, ls2k0300_pinctrl_of_match);
+
+static struct platform_driver ls2k0300_pinctrl_driver = {
+	.probe	= ls2k0300_pinctrl_probe,
+	.driver	= {
+		.name			= "ls2k0300-pinctrl",
+		.suppress_bind_attrs	= true,
+		.of_match_table		= ls2k0300_pinctrl_of_match,
+	},
+};
+
+builtin_platform_driver(ls2k0300_pinctrl_driver);
+
+MODULE_AUTHOR("Yao Zi <ziyao@disroot.org>");
+MODULE_DESCRIPTION("Pinctrl driver for Loongson-2K0300 SoC");
+MODULE_LICENSE("GPL");
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 3/3] LoongArch: dts: Add pinctrl configuration for Loongson 2K0300
  2025-08-11 16:37 [PATCH 0/3] Support pinctrl for Loongson 2K0300 SoC Yao Zi
  2025-08-11 16:37 ` [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Yao Zi
  2025-08-11 16:37 ` [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Yao Zi
@ 2025-08-11 16:37 ` Yao Zi
  2 siblings, 0 replies; 10+ messages in thread
From: Yao Zi @ 2025-08-11 16:37 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Huacai Chen, WANG Xuerui
  Cc: linux-gpio, devicetree, linux-kernel, loongarch, Mingcong Bai,
	Kexy Biscuit, Yao Zi

Describe the pin controller for Loongson 2K0300 SoC. As default settings
for the existing UARTs, pinctrls are added and multiplexed to pins taken
corresponding UART as main functionaility.

Signed-off-by: Yao Zi <ziyao@disroot.org>
---
 arch/loongarch/boot/dts/loongson-2k0300.dtsi | 39 ++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/arch/loongarch/boot/dts/loongson-2k0300.dtsi b/arch/loongarch/boot/dts/loongson-2k0300.dtsi
index d909a4eca312..a8ad8bd43f5d 100644
--- a/arch/loongarch/boot/dts/loongson-2k0300.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k0300.dtsi
@@ -9,6 +9,8 @@
 #include <dt-bindings/clock/loongson,ls2k0300-clk.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 
+#define PINMUX(pin, func)	(((pin) << 8) | func)
+
 / {
 	compatible = "loongson,ls2k0300";
 	#address-cells = <2>;
@@ -55,6 +57,35 @@ clk: clock-controller@16000400 {
 			#clock-cells = <1>;
 		};
 
+		pinctrl: pinctrl@16000490 {
+			compatible = "loongson,ls2k0300-pinctrl";
+			reg = <0x0 0x16000490 0x0 0x20>,
+			      <0x0 0x16000110 0x0 0x4>;
+			reg-names = "mux", "drive";
+
+			func-uart {
+				uart0_pins: uart0-pins {
+					pinmux = <PINMUX(40, 0x3)>,
+						 <PINMUX(41, 0x3)>;
+				};
+
+				uart1_pins: uart1-pins {
+					pinmux = <PINMUX(42, 0x3)>,
+						 <PINMUX(43, 0x3)>;
+				};
+
+				uart2_pins: uart2-pins {
+					pinmux = <PINMUX(44, 0x3)>,
+						 <PINMUX(45, 0x3)>;
+				};
+
+				uart3_pins: uart3-pins {
+					pinmux = <PINMUX(46, 0x3)>,
+						 <PINMUX(47, 0x3)>;
+				};
+			};
+		};
+
 		liointc0: interrupt-controller@16001400 {
 			compatible = "loongson,liointc-2.0";
 			reg = <0x0 0x16001400 0x0 0x40>,
@@ -100,6 +131,8 @@ uart0: serial@16100000 {
 			interrupt-parent = <&liointc0>;
 			interrupts = <0 IRQ_TYPE_LEVEL_HIGH>;
 			no-loopback-test;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart0_pins>;
 			status = "disabled";
 		};
 
@@ -109,6 +142,8 @@ uart1: serial@16100400 {
 			interrupt-parent = <&liointc0>;
 			interrupts = <1 IRQ_TYPE_LEVEL_HIGH>;
 			no-loopback-test;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart1_pins>;
 			status = "disabled";
 		};
 
@@ -118,6 +153,8 @@ uart2: serial@16100800 {
 			interrupt-parent = <&liointc0>;
 			interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
 			no-loopback-test;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart2_pins>;
 			status = "disabled";
 		};
 
@@ -127,6 +164,8 @@ uart3: serial@16100c00 {
 			interrupt-parent = <&liointc0>;
 			interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
 			no-loopback-test;
+			pinctrl-names = "default";
+			pinctrl-0 = <&uart3_pins>;
 			status = "disabled";
 		};
 
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  2025-08-11 16:37 ` [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Yao Zi
@ 2025-08-14  3:15   ` Yao Zi
  2025-08-19 10:02   ` Linus Walleij
  1 sibling, 0 replies; 10+ messages in thread
From: Yao Zi @ 2025-08-14  3:15 UTC (permalink / raw)
  To: Linus Walleij, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Huacai Chen, WANG Xuerui
  Cc: linux-gpio, devicetree, linux-kernel, loongarch, Mingcong Bai,
	Kexy Biscuit

On Mon, Aug 11, 2025 at 04:37:49PM +0000, Yao Zi wrote:
> Support pin multiplexing and drive-strength setting for Loongson 2K0300
> SoC. Pin multiplexing could be done separately for each pin, while
> drive-strength could be only configured on function basis. This differs
> a lot from the driver for previous generation of Loongson SoC, where
> pinmux setting is based on group.
> 
> Pins are represented with pinmux properties in devicetrees, and we use
> the generic pinmux API for parsing. The common pinconf interface isn't
> used for drive-strength setting, since it handles pinconf settings at a
> unit of pin groups or smaller.
> 
> Instead, the driver configures drive-strength settings just after
> parsing the devicetree. The devicetree's structure ensures no conflicts
> could happen in drive-strength settings.
> 
> Signed-off-by: Yao Zi <ziyao@disroot.org>
> ---
>  MAINTAINERS                        |   1 +
>  drivers/pinctrl/Kconfig            |  14 +
>  drivers/pinctrl/Makefile           |   1 +
>  drivers/pinctrl/pinctrl-ls2k0300.c | 515 +++++++++++++++++++++++++++++
>  4 files changed, 531 insertions(+)
>  create mode 100644 drivers/pinctrl/pinctrl-ls2k0300.c

...

> diff --git a/drivers/pinctrl/pinctrl-ls2k0300.c b/drivers/pinctrl/pinctrl-ls2k0300.c
> new file mode 100644
> index 000000000000..11d448ba333d
> --- /dev/null
> +++ b/drivers/pinctrl/pinctrl-ls2k0300.c

...

> +static const struct pinmux_ops ls2k0300_pmux_ops = {
> +	.get_functions_count	= ls2k0300_pinmux_get_functions_count,
> +	.get_function_name	= ls2k0300_pinmux_get_function_name,
> +	.get_function_groups	= ls2k0300_pinmux_get_function_groups,
> +	.set_mux		= ls2k0300_pinmux_set_mux,
> +};

I forgot to enable strict mode for the pinmux operations. Will correct
this in v2. I'll wait a few days for more comments before sending it,
thanks for your time.

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller
  2025-08-11 16:37 ` [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Yao Zi
@ 2025-08-18 17:58   ` Rob Herring
  2025-08-19 11:37     ` Yao Zi
  0 siblings, 1 reply; 10+ messages in thread
From: Rob Herring @ 2025-08-18 17:58 UTC (permalink / raw)
  To: Yao Zi
  Cc: Linus Walleij, Krzysztof Kozlowski, Conor Dooley, Huacai Chen,
	WANG Xuerui, linux-gpio, devicetree, linux-kernel, loongarch,
	Mingcong Bai, Kexy Biscuit

On Mon, Aug 11, 2025 at 04:37:48PM +0000, Yao Zi wrote:
> The pincontroller integarted in Loongson 2K0300 is able to configure
> function multiplexing for all the pins. It could also configure drive
> strength on basis of functions, which means all pins set to the same
> function share drive-strength setting. Drive-strength configuration
> isn't available for all functions, either.
> 
> This binding utilizes two levels of subnodes, where the outer represents
> function and the inner represents groups. Drive-strength is allowed in
> the outer since it's shared among all groups configured to the function.
> 
> Signed-off-by: Yao Zi <ziyao@disroot.org>
> ---
>  .../pinctrl/loongson,ls2k0300-pinctrl.yaml    | 92 +++++++++++++++++++
>  MAINTAINERS                                   |  6 ++
>  2 files changed, 98 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> new file mode 100644
> index 000000000000..cbd74cb45342
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> @@ -0,0 +1,92 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pinctrl/loongson,ls2k0300-pinctrl.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Loongson-2K0300 SoC Pinctrl Controller
> +
> +maintainers:
> +  - Yao Zi <ziyao@disroot.org>
> +
> +allOf:
> +  - $ref: pinctrl.yaml#
> +
> +properties:
> +  compatible:
> +    const: loongson,ls2k0300-pinctrl
> +
> +  reg:
> +    items:
> +      - description: Pin function-multiplexing configuration registers
> +      - description: Pin drive-strength configuration registers
> +
> +  reg-names:
> +    items:
> +      - const: mux
> +      - const: drive
> +
> +patternProperties:
> +  '^func-':
> +    type: object
> +
> +    $ref: pincfg-node.yaml#
> +
> +    properties:
> +      drive-strength:
> +        description:
> +          Maximum sink or source current as defined in pincfg-node.yaml. Note
> +          that drive strength could only be configured on function basis, i.e.,
> +          all pins multiplexed to the same function share the same
> +          configuration.
> +
> +          This could only be configured for several functions, including jtag,
> +          dvo, uart, gmac, sdio, spi, i2s, timer, usb and emmc.
> +        enum: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]

How do you know what pin this drive strength corresponds to without any 
other properties? Node names generally aren't important, so you 
shouldn't be using that. 

> +
> +    additionalProperties: false
> +
> +    patternProperties:
> +      '-pins$':
> +        type: object
> +        $ref: pinmux-node.yaml#

Generally the pin config and muxing are in 1 node if you can control 
both.

> +
> +        properties:
> +          pinmux:
> +            description:
> +              Integer array, represents GPIO pin number and multiplexing
> +              setting. Configuration for each pin takes one cell. The pin
> +              number locates at the high 24 bits, and the setting locates at
> +              the low 8 bits.
> +
> +        additionalProperties: false
> +
> +        required:
> +          - pinmux
> +
> +required:
> +  - compatible
> +  - reg
> +  - reg-names
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    pinctrl@1fe00420 {
> +        compatible = "loongson,ls2k0300-pinctrl";
> +        reg = <0x16000490 0x20>, <0x16000110 0x4>;
> +        reg-names = "mux", "drive";
> +
> +        func-uart {
> +            drive-strength = <2>;
> +
> +            uart0-pins {
> +                pinmux = <((40 << 8) | 0x3)>, <((41 << 8) | 0x3)>;
> +            };
> +
> +            uart1_pins: uart1-pins {
> +                pinmux = <((42 << 8) | 0x3)>, <((43 << 8) | 0x3)>;
> +            };
> +        };
> +    };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 7960e65d7dfc..dd50571b4072 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -14414,6 +14414,12 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
>  F:	drivers/thermal/loongson2_thermal.c
>  
> +LOONGSON-2K0300 SOC PINCTRL DRIVER
> +M:	Yao Zi <ziyao@disroot.org>
> +L:	linux-gpio@vger.kernel.org
> +S:	Maintained
> +F:	Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> +
>  LOONGSON EDAC DRIVER
>  M:	Zhao Qunqin <zhaoqunqin@loongson.cn>
>  L:	linux-edac@vger.kernel.org
> -- 
> 2.50.1
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  2025-08-11 16:37 ` [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Yao Zi
  2025-08-14  3:15   ` Yao Zi
@ 2025-08-19 10:02   ` Linus Walleij
  2025-08-19 12:40     ` Yao Zi
  1 sibling, 1 reply; 10+ messages in thread
From: Linus Walleij @ 2025-08-19 10:02 UTC (permalink / raw)
  To: Yao Zi
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Huacai Chen,
	WANG Xuerui, linux-gpio, devicetree, linux-kernel, loongarch,
	Mingcong Bai, Kexy Biscuit

On Mon, Aug 11, 2025 at 6:39 PM Yao Zi <ziyao@disroot.org> wrote:

> Support pin multiplexing and drive-strength setting for Loongson 2K0300
> SoC. Pin multiplexing could be done separately for each pin, while
> drive-strength could be only configured on function basis. This differs
> a lot from the driver for previous generation of Loongson SoC, where
> pinmux setting is based on group.
>
> Pins are represented with pinmux properties in devicetrees, and we use
> the generic pinmux API for parsing. The common pinconf interface isn't
> used for drive-strength setting, since it handles pinconf settings at a
> unit of pin groups or smaller.
>
> Instead, the driver configures drive-strength settings just after
> parsing the devicetree. The devicetree's structure ensures no conflicts
> could happen in drive-strength settings.
>
> Signed-off-by: Yao Zi <ziyao@disroot.org>

Overall the driver looks very good, well done!

Look into Rob's comment on the bindings to use a single node
for mux and config.

I saw that you want to make the pin controller strict, if you also have
some pins with "GPIO mode" that will serve as back-end for a
GPIO driver (and I saw you posted a GPIO driver series as well)
then have a look at Bartosz recent patches to add infrastructure
for pinctrl to know about what a GPIO pin is:
https://lore.kernel.org/linux-gpio/20250815-pinctrl-gpio-pinfuncs-v5-0-955de9fd91db@linaro.org/T/

The current driver does not seem to know about any of these
pins being usable as GPIO and does not implement those:

        int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
                                    struct pinctrl_gpio_range *range,
                                    unsigned int offset);
        void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
                                   struct pinctrl_gpio_range *range,
                                   unsigned int offset);
        int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
                                   struct pinctrl_gpio_range *range,
                                   unsigned int offset,
                                   bool input);
        bool strict;

Which is fine if the pins actually cannot be used for GPIO, but if they
can, and this is just implicit for unconfigured pins ... then add
functions and groups for GPIO.

The other driver using pinconf_generic_parse_dt_pinmux()
drivers/pinctrl/meson/pinctrl-amlogic-a4.c has GPIO awareness.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller
  2025-08-18 17:58   ` Rob Herring
@ 2025-08-19 11:37     ` Yao Zi
  0 siblings, 0 replies; 10+ messages in thread
From: Yao Zi @ 2025-08-19 11:37 UTC (permalink / raw)
  To: Rob Herring
  Cc: Linus Walleij, Krzysztof Kozlowski, Conor Dooley, Huacai Chen,
	WANG Xuerui, linux-gpio, devicetree, linux-kernel, loongarch,
	Mingcong Bai, Kexy Biscuit

On Mon, Aug 18, 2025 at 12:58:27PM -0500, Rob Herring wrote:
> On Mon, Aug 11, 2025 at 04:37:48PM +0000, Yao Zi wrote:
> > The pincontroller integarted in Loongson 2K0300 is able to configure
> > function multiplexing for all the pins. It could also configure drive
> > strength on basis of functions, which means all pins set to the same
> > function share drive-strength setting. Drive-strength configuration
> > isn't available for all functions, either.
> > 
> > This binding utilizes two levels of subnodes, where the outer represents
> > function and the inner represents groups. Drive-strength is allowed in
> > the outer since it's shared among all groups configured to the function.
> > 
> > Signed-off-by: Yao Zi <ziyao@disroot.org>
> > ---
> >  .../pinctrl/loongson,ls2k0300-pinctrl.yaml    | 92 +++++++++++++++++++
> >  MAINTAINERS                                   |  6 ++
> >  2 files changed, 98 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> > 
> > diff --git a/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> > new file mode 100644
> > index 000000000000..cbd74cb45342
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> > @@ -0,0 +1,92 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/pinctrl/loongson,ls2k0300-pinctrl.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: Loongson-2K0300 SoC Pinctrl Controller
> > +
> > +maintainers:
> > +  - Yao Zi <ziyao@disroot.org>
> > +
> > +allOf:
> > +  - $ref: pinctrl.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    const: loongson,ls2k0300-pinctrl
> > +
> > +  reg:
> > +    items:
> > +      - description: Pin function-multiplexing configuration registers
> > +      - description: Pin drive-strength configuration registers
> > +
> > +  reg-names:
> > +    items:
> > +      - const: mux
> > +      - const: drive
> > +
> > +patternProperties:
> > +  '^func-':
> > +    type: object
> > +
> > +    $ref: pincfg-node.yaml#
> > +
> > +    properties:
> > +      drive-strength:
> > +        description:
> > +          Maximum sink or source current as defined in pincfg-node.yaml. Note
> > +          that drive strength could only be configured on function basis, i.e.,
> > +          all pins multiplexed to the same function share the same
> > +          configuration.
> > +
> > +          This could only be configured for several functions, including jtag,
> > +          dvo, uart, gmac, sdio, spi, i2s, timer, usb and emmc.
> > +        enum: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
> 
> How do you know what pin this drive strength corresponds to without any 
> other properties? Node names generally aren't important, so you 
> shouldn't be using that. 

Thanks for the hint... yes I'm matching the node name to identify
functions in this revision of driver. Could I introduce a "function"
property to the outer node for identification of the function?

> > +
> > +    additionalProperties: false
> > +
> > +    patternProperties:
> > +      '-pins$':
> > +        type: object
> > +        $ref: pinmux-node.yaml#
> 
> Generally the pin config and muxing are in 1 node if you can control 
> both.

On 2K0300, drive-strength could only be configured for each function,
not each pin, i.e. all pins configured to the same function share the
same drive-strength configuration.

Putting the driver-strength property in the outer node describes the
situation: a property in the outer node is function-specific and shared
between all groups (represented by inner nodes) configured to this
function.

Do you think it's better to move pin config (the driver-strength
property) to the inner node in this case? If so, should the new
"function" property for identifying functions reliably be in the inner
node or the outer node? Thanks for your explanation,

Best regards,
Yao Zi

> > +
> > +        properties:
> > +          pinmux:
> > +            description:
> > +              Integer array, represents GPIO pin number and multiplexing
> > +              setting. Configuration for each pin takes one cell. The pin
> > +              number locates at the high 24 bits, and the setting locates at
> > +              the low 8 bits.
> > +
> > +        additionalProperties: false
> > +
> > +        required:
> > +          - pinmux
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - reg-names
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    pinctrl@1fe00420 {
> > +        compatible = "loongson,ls2k0300-pinctrl";
> > +        reg = <0x16000490 0x20>, <0x16000110 0x4>;
> > +        reg-names = "mux", "drive";
> > +
> > +        func-uart {
> > +            drive-strength = <2>;
> > +
> > +            uart0-pins {
> > +                pinmux = <((40 << 8) | 0x3)>, <((41 << 8) | 0x3)>;
> > +            };
> > +
> > +            uart1_pins: uart1-pins {
> > +                pinmux = <((42 << 8) | 0x3)>, <((43 << 8) | 0x3)>;
> > +            };
> > +        };
> > +    };
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 7960e65d7dfc..dd50571b4072 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -14414,6 +14414,12 @@ S:	Maintained
> >  F:	Documentation/devicetree/bindings/thermal/loongson,ls2k-thermal.yaml
> >  F:	drivers/thermal/loongson2_thermal.c
> >  
> > +LOONGSON-2K0300 SOC PINCTRL DRIVER
> > +M:	Yao Zi <ziyao@disroot.org>
> > +L:	linux-gpio@vger.kernel.org
> > +S:	Maintained
> > +F:	Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml
> > +
> >  LOONGSON EDAC DRIVER
> >  M:	Zhao Qunqin <zhaoqunqin@loongson.cn>
> >  L:	linux-edac@vger.kernel.org
> > -- 
> > 2.50.1
> > 
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  2025-08-19 10:02   ` Linus Walleij
@ 2025-08-19 12:40     ` Yao Zi
  2025-08-21 11:27       ` Linus Walleij
  0 siblings, 1 reply; 10+ messages in thread
From: Yao Zi @ 2025-08-19 12:40 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Huacai Chen,
	WANG Xuerui, linux-gpio, devicetree, linux-kernel, loongarch,
	Mingcong Bai, Kexy Biscuit

On Tue, Aug 19, 2025 at 12:02:23PM +0200, Linus Walleij wrote:
> On Mon, Aug 11, 2025 at 6:39 PM Yao Zi <ziyao@disroot.org> wrote:
> 
> > Support pin multiplexing and drive-strength setting for Loongson 2K0300
> > SoC. Pin multiplexing could be done separately for each pin, while
> > drive-strength could be only configured on function basis. This differs
> > a lot from the driver for previous generation of Loongson SoC, where
> > pinmux setting is based on group.
> >
> > Pins are represented with pinmux properties in devicetrees, and we use
> > the generic pinmux API for parsing. The common pinconf interface isn't
> > used for drive-strength setting, since it handles pinconf settings at a
> > unit of pin groups or smaller.
> >
> > Instead, the driver configures drive-strength settings just after
> > parsing the devicetree. The devicetree's structure ensures no conflicts
> > could happen in drive-strength settings.
> >
> > Signed-off-by: Yao Zi <ziyao@disroot.org>
> 
> Overall the driver looks very good, well done!
> 
> Look into Rob's comment on the bindings to use a single node
> for mux and config.

I've raised several questions about the binding and will change the
binding and code according to Rob's answer.

> I saw that you want to make the pin controller strict, if you also have
> some pins with "GPIO mode" that will serve as back-end for a
> GPIO driver (and I saw you posted a GPIO driver series as well)
> then have a look at Bartosz recent patches to add infrastructure
> for pinctrl to know about what a GPIO pin is:
> https://lore.kernel.org/linux-gpio/20250815-pinctrl-gpio-pinfuncs-v5-0-955de9fd91db@linaro.org/T/

Thanks for the link! Actually according to the manual, all the 106 on
2K0300 pins could be multiplexed as GPIO. But the pinctrl cannot set up
any pin config for pins in GPIO mode.

> The current driver does not seem to know about any of these
> pins being usable as GPIO and does not implement those:
> 
>         int (*gpio_request_enable) (struct pinctrl_dev *pctldev,
>                                     struct pinctrl_gpio_range *range,
>                                     unsigned int offset);
>         void (*gpio_disable_free) (struct pinctrl_dev *pctldev,
>                                    struct pinctrl_gpio_range *range,
>                                    unsigned int offset);
>         int (*gpio_set_direction) (struct pinctrl_dev *pctldev,
>                                    struct pinctrl_gpio_range *range,
>                                    unsigned int offset,
>                                    bool input);
>         bool strict;
> 
> Which is fine if the pins actually cannot be used for GPIO, but if they
> can, and this is just implicit for unconfigured pins ... then add
> functions and groups for GPIO.

For 2K0300, we want these pins to be able to multiplexed as GPIOs, but
since this pinctrl driver could configure nothing for GPIO mode pins, I
think it's enough to implement only the gpio_request_enable() callback
and do the multiplexing work here, is this correct?

I originally thought it's okay to multiplex pins as GPIO with an usual
pinctrl configuration, and didn't realize that it causes conflicts on
strict controllers since the pin will be claimed by both pincontroller
and GPIO controller. Thanks for the reminder.

> The other driver using pinconf_generic_parse_dt_pinmux()
> drivers/pinctrl/meson/pinctrl-amlogic-a4.c has GPIO awareness.
> 
> Yours,
> Linus Walleij
> 

Much thanks for the detailed guidance!

Best regards,
Yao Zi

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC
  2025-08-19 12:40     ` Yao Zi
@ 2025-08-21 11:27       ` Linus Walleij
  0 siblings, 0 replies; 10+ messages in thread
From: Linus Walleij @ 2025-08-21 11:27 UTC (permalink / raw)
  To: Yao Zi
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Huacai Chen,
	WANG Xuerui, linux-gpio, devicetree, linux-kernel, loongarch,
	Mingcong Bai, Kexy Biscuit

On Tue, Aug 19, 2025 at 2:41 PM Yao Zi <ziyao@disroot.org> wrote:

> > Which is fine if the pins actually cannot be used for GPIO, but if they
> > can, and this is just implicit for unconfigured pins ... then add
> > functions and groups for GPIO.
>
> For 2K0300, we want these pins to be able to multiplexed as GPIOs, but
> since this pinctrl driver could configure nothing for GPIO mode pins, I
> think it's enough to implement only the gpio_request_enable() callback
> and do the multiplexing work here, is this correct?

Yes that is the quick and elegant solution.

> I originally thought it's okay to multiplex pins as GPIO with an usual
> pinctrl configuration, and didn't realize that it causes conflicts on
> strict controllers since the pin will be claimed by both pincontroller
> and GPIO controller. Thanks for the reminder.

This is true as well, some drivers use an explicit "gpio" function
and for these the the new .function_is_gpio() callback is especially
helpful.

I think it is helpful if you're using the callbacks too (we can
determine if we're already in GPIO mode) but it's not necessary.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2025-08-21 11:27 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-11 16:37 [PATCH 0/3] Support pinctrl for Loongson 2K0300 SoC Yao Zi
2025-08-11 16:37 ` [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Yao Zi
2025-08-18 17:58   ` Rob Herring
2025-08-19 11:37     ` Yao Zi
2025-08-11 16:37 ` [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Yao Zi
2025-08-14  3:15   ` Yao Zi
2025-08-19 10:02   ` Linus Walleij
2025-08-19 12:40     ` Yao Zi
2025-08-21 11:27       ` Linus Walleij
2025-08-11 16:37 ` [PATCH 3/3] LoongArch: dts: Add pinctrl configuration for Loongson 2K0300 Yao Zi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).