From nobody Sun Oct 5 00:14:18 2025 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D09D1DFDAB; Mon, 11 Aug 2025 16:39:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930346; cv=none; b=RvI8tsu5knWsBJEfuL7yNQsI1JhRtdjUiyi0zps7FSqa7NZXQS2Gq/Uuq7jOT1mW2siX9XVwnCDOCdfjMXJusn2MmtUpiNXBU403VglRo9jMoOJ96bnES/fvgqjLJEMAKoOgRtSlAz414/5DaXCBrbkaxxcXjjib6NP/4vzfnHo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930346; c=relaxed/simple; bh=dYPpJEmQpvSq4iDW/S25rTfoUpN/PhSh2PhokpZ7IQQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q8uHavga/VBDUu0NWBFnJmFblKd7Bkb07a5/nVIXKysbOwwLsBzRVw/2wBHKwedKvKG39Yij83HN5Ye6ZzNqS3jMjoWnhCU/b/mCNqCV60YdDtEZpeYbIpm25zxgZPk1v3OEq3pv1lqEw6Od1evgvpUzPERDpsp2S5R63kISTKI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=HCrhoKSK; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="HCrhoKSK" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 02D0820E4B; Mon, 11 Aug 2025 18:39:03 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id fWaBrpNGEVI4; Mon, 11 Aug 2025 18:39:02 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1754930303; bh=dYPpJEmQpvSq4iDW/S25rTfoUpN/PhSh2PhokpZ7IQQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=HCrhoKSKyXySqLc8qHCAxMFdNZpwcFHdFujM3fhEHIOBUXVVxmhSevfdEj6j8wmmx JYgftrVUMAATuDrflwrlegC9UgZoMRbssI8z7PEUZNsxQQFaP71RxLGVUB0dAezN8p r4gmF/xN8QQG5KRnQfua39PnpS3DkqaewIraayGPl4f8ZPoA6HKorG4j8ZH/zEbG+n ys5SwvgYYiU8WZCRNIs0Y1HhHxq7LfNEYTU+4P3UKWrKVsyP62iXvuSrMzHVtvAjN1 TgCQSf6axCFiruSxUMarNEDAYbeNxybosrUTFebosOPPL1RWTXLNgNKZE1Dlf9D6FU IbmzlPmzNkj5A== From: Yao Zi To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Huacai Chen , WANG Xuerui Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, loongarch@lists.linux.dev, Mingcong Bai , Kexy Biscuit , Yao Zi Subject: [PATCH 1/3] dt-binding: pinctrl: Document Loongson 2K0300 pin controller Date: Mon, 11 Aug 2025 16:37:48 +0000 Message-ID: <20250811163749.47028-3-ziyao@disroot.org> In-Reply-To: <20250811163749.47028-2-ziyao@disroot.org> References: <20250811163749.47028-2-ziyao@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- .../pinctrl/loongson,ls2k0300-pinctrl.yaml | 92 +++++++++++++++++++ MAINTAINERS | 6 ++ 2 files changed, 98 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/loongson,ls2k= 0300-pinctrl.yaml diff --git a/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pi= nctrl.yaml b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pi= nctrl.yaml new file mode 100644 index 000000000000..cbd74cb45342 --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.y= aml @@ -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 + +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. N= ote + 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 j= tag, + 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 =3D "loongson,ls2k0300-pinctrl"; + reg =3D <0x16000490 0x20>, <0x16000110 0x4>; + reg-names =3D "mux", "drive"; + + func-uart { + drive-strength =3D <2>; + + uart0-pins { + pinmux =3D <((40 << 8) | 0x3)>, <((41 << 8) | 0x3)>; + }; + + uart1_pins: uart1-pins { + pinmux =3D <((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 =20 +LOONGSON-2K0300 SOC PINCTRL DRIVER +M: Yao Zi +L: linux-gpio@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml + LOONGSON EDAC DRIVER M: Zhao Qunqin L: linux-edac@vger.kernel.org --=20 2.50.1 From nobody Sun Oct 5 00:14:18 2025 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 26BF1296BB4; Mon, 11 Aug 2025 16:39:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930375; cv=none; b=d0mxCNjIVP/oEk40Geb7uSWZH1DF3OKrT/CImXjPGXOHJiyd6PZvVpUnfsky/PajMrfPh9ljsB1ppFA42ZC4xgEwMw+u8jEgj9fjBJ9RJjOSYOzRj0f3k0FfguvHPL2wDaCoLmXq8dw2qelb5RqMbVtjxEq/0UPwksFdLjFeCR0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930375; c=relaxed/simple; bh=/sfDYsWaumJRNuxfDI3BONzrIgPEYzY2Gf7xU4ueNYg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ahODErJBq0mywrLp+JAq2lRAkHI+Hzm84HnRzjXwxIZf4iBGmaPNmvQZMYjkJIUWZQmroaY6B9etmfysEuyXO0On4RH3y34pMoYoYIf18RmIr+mBpIdoyJEyFxCqbGU56fIN4x9TvZ5o6dX9NQWEizlJulmDCFtUda8//MhFSBw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=I6lIUzBh; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="I6lIUzBh" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id AEE5F25CA7; Mon, 11 Aug 2025 18:39:31 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id SNxH-Bdj19kI; Mon, 11 Aug 2025 18:39:30 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1754930308; bh=/sfDYsWaumJRNuxfDI3BONzrIgPEYzY2Gf7xU4ueNYg=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=I6lIUzBhNSCr0bLspDIv54+UblG0579dbXgGlfIJKM/PzaMaeEDtKAyu016TxNDyi xqAQO3YKfkYDhn2G5vratdnK/Ca3+VdV9rPhD0gTS9pkxuLyaKctJB9pJOHc8CS8M9 GGkTsnnLIYh69bbz8YBpwiq69guybfBEbUhPizAV1qPMC2eo84HOhOMGBX67hTZBts lN3JeEOMt6yiJkvDgziFJ54pDYdY1lqhS+Borklvj0mbV6IRZWn3M/aAwYBH4A08uC 6Z00qEeRkYFL0vxA7U7IgIO5zmVhhmQnvb4qHoKeGzRr5tqVj7G6AVYlqgdGWGYmEO rNdw9mfEzdPNg== From: Yao Zi To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Huacai Chen , WANG Xuerui Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, loongarch@lists.linux.dev, Mingcong Bai , Kexy Biscuit , Yao Zi Subject: [PATCH 2/3] pinctrl: ls2k0300: Support Loongson 2K0300 SoC Date: Mon, 11 Aug 2025 16:37:49 +0000 Message-ID: <20250811163749.47028-4-ziyao@disroot.org> In-Reply-To: <20250811163749.47028-2-ziyao@disroot.org> References: <20250811163749.47028-2-ziyao@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 L: linux-gpio@vger.kernel.org S: Maintained F: Documentation/devicetree/bindings/pinctrl/loongson,ls2k0300-pinctrl.yaml +F: drivers/pinctrl/pinctrl-ls2k0300.c =20 LOONGSON EDAC DRIVER M: Zhao Qunqin 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. =20 +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) +=3D pinctrl-keembay.o obj-$(CONFIG_PINCTRL_LANTIQ) +=3D pinctrl-lantiq.o obj-$(CONFIG_PINCTRL_FALCON) +=3D pinctrl-falcon.o obj-$(CONFIG_PINCTRL_LOONGSON2) +=3D pinctrl-loongson2.o +obj-$(CONFIG_PINCTRL_LS2K0300) +=3D pinctrl-ls2k0300.o obj-$(CONFIG_PINCTRL_XWAY) +=3D pinctrl-xway.o obj-$(CONFIG_PINCTRL_LPC18XX) +=3D pinctrl-lpc18xx.o obj-$(CONFIG_PINCTRL_MAX77620) +=3D pinctrl-max77620.o diff --git a/drivers/pinctrl/pinctrl-ls2k0300.c b/drivers/pinctrl/pinctrl-l= s2k0300.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 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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[] =3D { + 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[] = =3D { + { .func =3D "func-jtag", .width =3D 2, .shift =3D 8 }, + { .func =3D "func-dvo", .width =3D 2, .shift =3D 10 }, + { .func =3D "func-uart", .width =3D 2, .shift =3D 12 }, + { .func =3D "func-gmac", .width =3D 2, .shift =3D 14 }, + { .func =3D "func-sdio", .width =3D 2, .shift =3D 16 }, + { .func =3D "func-spi", .width =3D 2, .shift =3D 18 }, + { .func =3D "func-i2s", .width =3D 2, .shift =3D 20 }, + { .func =3D "func-timer", .width =3D 2, .shift =3D 22 }, + { .func =3D "func-usb", .width =3D 2, .shift =3D 24 }, + { .func =3D "func-emmc", .width =3D 3, .shift =3D 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 =3D pinctrl_dev_get_drvdata(pctldev); + + return pctrl->ngroups; +} + +static const char *ls2k0300_pinctrl_get_group_name(struct pinctrl_dev *pct= ldev, + unsigned int selector) +{ + struct ls2k0300_pinctrl *pctrl =3D 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 =3D pinctrl_dev_get_drvdata(pctldev); + struct ls2k0300_pinctrl_group *group =3D &pctrl->groups[selector]; + + *pins =3D group->pins; + *num_pins =3D group->npins; + + return 0; +} + +static const struct pinctrl_ops ls2k0300_pctrl_ops =3D { + .get_groups_count =3D ls2k0300_pinctrl_get_groups_count, + .get_group_name =3D ls2k0300_pinctrl_get_group_name, + .get_group_pins =3D ls2k0300_pinctrl_get_group_pins, + .dt_node_to_map =3D pinconf_generic_dt_node_to_map_pinmux, + .dt_free_map =3D pinctrl_utils_free_map, +}; + +static int ls2k0300_pinmux_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct ls2k0300_pinctrl *pctrl =3D 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 =3D 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 =3D pinctrl_dev_get_drvdata(pctldev); + struct ls2k0300_pinctrl_func *func =3D &pctrl->funcs[selector]; + + *groups =3D func->group_names; + *num_groups =3D 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 =3D pinctrl_dev_get_drvdata(pctrldev); + struct ls2k0300_pinctrl_group *group =3D &pctrl->groups[group_selector]; + unsigned int *muxes =3D group->muxes, *pins =3D group->pins; + unsigned int off, shift, i; + u32 reg; + + guard(spinlock_irqsave)(&pctrl->lock); + + for (i =3D 0; i < group->npins; i++) { + off =3D LS2K0300_PIN_TO_OFFSET(pins[i]); + shift =3D LS2K0300_PIN_TO_SHIFT(pins[i]); + + reg =3D readl(pctrl->reg_mux + off); + reg &=3D ~(LS2K0300_MUX_MASK << shift); + reg |=3D muxes[i] << shift; + writel(reg, pctrl->reg_mux + off); + } + + return 0; +} + +static const struct pinmux_ops ls2k0300_pmux_ops =3D { + .get_functions_count =3D ls2k0300_pinmux_get_functions_count, + .get_function_name =3D ls2k0300_pinmux_get_function_name, + .get_function_groups =3D ls2k0300_pinmux_get_function_groups, + .set_mux =3D 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 =3D 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 =3D of_get_child_count(np); + + func->groups =3D devm_kcalloc(dev, func->ngroups, sizeof(*func->groups), + GFP_KERNEL); + func->group_names =3D devm_kcalloc(dev, func->ngroups, + sizeof(*func->group_names), + GFP_KERNEL); + if (!func->groups || !func->group_names) + return -ENOMEM; + + func->name =3D np->name; + + i =3D 0; + + for_each_child_of_node_scoped(np, child) { + group =3D &pctrl->groups[pctrl->ngroups]; + + ret =3D ls2k0300_pinctrl_parse_group(dev, pctrl, child, group); + if (ret) + return ret; + + func->groups[i] =3D pctrl->ngroups; + func->group_names[i] =3D group->name; + + i++; + pctrl->ngroups++; + } + + return 0; +} + +static int drive_strength_ma_to_val(struct ls2k0300_pinctrl_drive_conf *co= nf, + 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 =3D (1 << conf->width) - 1; + *val =3D (drive_strength_ma - LS2K0300_DRIVE_STRENGTH_MIN) * val_max; + *val =3D 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 =3D 0; i < ARRAY_SIZE(ls2k0300_pinctrl_drive_confs); i++) { + conf =3D &ls2k0300_pinctrl_drive_confs[i]; + + func_np =3D of_get_child_by_name(np, conf->func); + if (!func_np) + continue; + + ret =3D of_property_read_u32(func_np, "drive-strength", + &drive_strength_ma); + of_node_put(func_np); + if (ret =3D=3D -EINVAL) + continue; + else if (ret) + return ret; + + ret =3D 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 =3D dev->of_node; + struct ls2k0300_pinctrl_func *func; + unsigned int ngroups, nfuncs; + int ret; + + for_each_child_of_node_scoped(np, child) { + nfuncs++; + ngroups +=3D of_get_child_count(child); + } + + pctrl->groups =3D devm_kcalloc(dev, ngroups, sizeof(*pctrl->groups), + GFP_KERNEL); + pctrl->funcs =3D 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 =3D &pctrl->funcs[pctrl->nfuncs++]; + + ret =3D 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 *p= ctrl) +{ + struct ls2k0300_pinctrl_drive_conf *conf; + u32 reg; + int i; + + reg =3D readl(pctrl->reg_drive); + + for (i =3D 0; i < ARRAY_SIZE(ls2k0300_pinctrl_drive_confs); i++) { + if (pctrl->drive_confs[i] =3D=3D LS2K0300_DRIVE_STRENGTH_DEFAULT) + continue; + + conf =3D &ls2k0300_pinctrl_drive_confs[i]; + reg &=3D ~GENMASK(conf->shift + conf->width - 1, conf->shift); + reg |=3D pctrl->drive_confs[i] << conf->shift; + } + + writel(reg, pctrl->reg_drive); +} + +static int ls2k0300_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct ls2k0300_pinctrl *pctrl; + int ret; + + pctrl =3D devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->reg_mux =3D 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 =3D 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 =3D 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 =3D dev; + pctrl->pdesc.name =3D "pinctrl-ls2k0300"; + pctrl->pdesc.owner =3D THIS_MODULE; + pctrl->pdesc.pins =3D ls2k0300_pins; + pctrl->pdesc.npins =3D ARRAY_SIZE(ls2k0300_pins); + pctrl->pdesc.pctlops =3D &ls2k0300_pctrl_ops; + pctrl->pdesc.pmxops =3D &ls2k0300_pmux_ops; + pctrl->pdesc.owner =3D THIS_MODULE; + + pctrl->pctldev =3D 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[] =3D { + { .compatible =3D "loongson,ls2k0300-pinctrl" }, + { }, +}; +MODULE_DEVICE_TABLE(of, ls2k0300_pinctrl_of_match); + +static struct platform_driver ls2k0300_pinctrl_driver =3D { + .probe =3D ls2k0300_pinctrl_probe, + .driver =3D { + .name =3D "ls2k0300-pinctrl", + .suppress_bind_attrs =3D true, + .of_match_table =3D ls2k0300_pinctrl_of_match, + }, +}; + +builtin_platform_driver(ls2k0300_pinctrl_driver); + +MODULE_AUTHOR("Yao Zi "); +MODULE_DESCRIPTION("Pinctrl driver for Loongson-2K0300 SoC"); +MODULE_LICENSE("GPL"); --=20 2.50.1 From nobody Sun Oct 5 00:14:18 2025 Received: from layka.disroot.org (layka.disroot.org [178.21.23.139]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A7FF1296BBB; Mon, 11 Aug 2025 16:39:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=178.21.23.139 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930376; cv=none; b=RQD7kbZmaNAEGpHZOB7Alq9OVrf82OYhbycm0w86pE1JSVL58C9xSOdN3W0MnKvizWRun3F78vaLbfR7a/RYMlB7LOJEvKHUUIJcMsVpVgWQGdhQhNqath3JI2MJ/bBGYvyKiSPJW03metbgsf7nkAkSEuHIdFvIuwsTZaaWHvQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754930376; c=relaxed/simple; bh=CImX2ZC8/O9nTsmiCTmo3jTXIWUuTcllD4/cgqtt4O4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=cr2TLyn2rAW5gJWdABrQPrj+cFBfwUByOxzXXOkMO27p/bvf02BdS0n64BUojaFsBL6XC2mRKswTAkFprBTbNns10V3obFVGei0fncllYmunXViJKcpCXRjz7l/OmCRJeve43JwDeEm13dGAOOMcsx59SBV4IWYokBEz0SakRdY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org; spf=pass smtp.mailfrom=disroot.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b=dF/VohVw; arc=none smtp.client-ip=178.21.23.139 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=disroot.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=disroot.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=disroot.org header.i=@disroot.org header.b="dF/VohVw" Received: from mail01.disroot.lan (localhost [127.0.0.1]) by disroot.org (Postfix) with ESMTP id 3570725D17; Mon, 11 Aug 2025 18:39:33 +0200 (CEST) X-Virus-Scanned: SPAM Filter at disroot.org Received: from layka.disroot.org ([127.0.0.1]) by localhost (disroot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id n-X6d5Lyl1oP; Mon, 11 Aug 2025 18:39:32 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=disroot.org; s=mail; t=1754930372; bh=CImX2ZC8/O9nTsmiCTmo3jTXIWUuTcllD4/cgqtt4O4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=dF/VohVwEOAaJpnwJCQGUkpI32kKHPEXLvENEaO66IUsFCiirmwoBOD1Gx8hU8vOK RKI70kZ7QX8kA+TTPdEMQ4YOot113K9edUgmAaztQfxQ+T1hleTVex8C0MChv4uVBA F01kdFjxaSPqUoI30qDUj/PGT75HjEvsIcy6g49gExXweiR8c46V0qccrAA/9FGfID kqFOgE7U+mcGbRn/41QrQiWR4fhdNRVg+k1DTRLr7VCqmZkdWUPLaXUw43B9u4wbch jmmnaHtF1T5ZbY3U2kSzfXiPxoXVTJaaNJzwtHW9VFpBFGhwMWgvwayrjwJ/CwcXke u401OEmB+DZRQ== From: Yao Zi To: Linus Walleij , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Huacai Chen , WANG Xuerui Cc: linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, loongarch@lists.linux.dev, Mingcong Bai , Kexy Biscuit , Yao Zi Subject: [PATCH 3/3] LoongArch: dts: Add pinctrl configuration for Loongson 2K0300 Date: Mon, 11 Aug 2025 16:37:50 +0000 Message-ID: <20250811163749.47028-5-ziyao@disroot.org> In-Reply-To: <20250811163749.47028-2-ziyao@disroot.org> References: <20250811163749.47028-2-ziyao@disroot.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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 --- 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 #include =20 +#define PINMUX(pin, func) (((pin) << 8) | func) + / { compatible =3D "loongson,ls2k0300"; #address-cells =3D <2>; @@ -55,6 +57,35 @@ clk: clock-controller@16000400 { #clock-cells =3D <1>; }; =20 + pinctrl: pinctrl@16000490 { + compatible =3D "loongson,ls2k0300-pinctrl"; + reg =3D <0x0 0x16000490 0x0 0x20>, + <0x0 0x16000110 0x0 0x4>; + reg-names =3D "mux", "drive"; + + func-uart { + uart0_pins: uart0-pins { + pinmux =3D , + ; + }; + + uart1_pins: uart1-pins { + pinmux =3D , + ; + }; + + uart2_pins: uart2-pins { + pinmux =3D , + ; + }; + + uart3_pins: uart3-pins { + pinmux =3D , + ; + }; + }; + }; + liointc0: interrupt-controller@16001400 { compatible =3D "loongson,liointc-2.0"; reg =3D <0x0 0x16001400 0x0 0x40>, @@ -100,6 +131,8 @@ uart0: serial@16100000 { interrupt-parent =3D <&liointc0>; interrupts =3D <0 IRQ_TYPE_LEVEL_HIGH>; no-loopback-test; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&uart0_pins>; status =3D "disabled"; }; =20 @@ -109,6 +142,8 @@ uart1: serial@16100400 { interrupt-parent =3D <&liointc0>; interrupts =3D <1 IRQ_TYPE_LEVEL_HIGH>; no-loopback-test; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&uart1_pins>; status =3D "disabled"; }; =20 @@ -118,6 +153,8 @@ uart2: serial@16100800 { interrupt-parent =3D <&liointc0>; interrupts =3D <2 IRQ_TYPE_LEVEL_HIGH>; no-loopback-test; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&uart2_pins>; status =3D "disabled"; }; =20 @@ -127,6 +164,8 @@ uart3: serial@16100c00 { interrupt-parent =3D <&liointc0>; interrupts =3D <2 IRQ_TYPE_LEVEL_HIGH>; no-loopback-test; + pinctrl-names =3D "default"; + pinctrl-0 =3D <&uart3_pins>; status =3D "disabled"; }; =20 --=20 2.50.1