lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <12507116.O9o76ZdvQC@steina-w>
Date: Tue, 27 Aug 2024 08:32:31 +0200
From: Alexander Stein <alexander.stein@...tq-group.com>
To: linux-arm-kernel@...ts.infradead.org, David Leonard <David.Leonard@...i.com>
Cc: Dong Aisheng <aisheng.dong@....com>, Fabio Estevam <festevam@...il.com>, Shawn Guo <shawnguo@...nel.org>, Jacky Bai <ping.bai@....com>, Pengutronix Kernel Team <kernel@...gutronix.de>, Linus Walleij <linus.walleij@...aro.org>, linux-kernel@...r.kernel.org, linux-gpio@...r.kernel.org
Subject: Re: [PATCH 1/6] pinctrl: ls1012a: Add pinctrl driver support

Am Dienstag, 27. August 2024, 04:05:24 CEST schrieb David Leonard:
> Add QorIQ LS1012A pinctrl driver, allowing i2c-core to exert
> GPIO control over the second I2C bus.

Can you please elaborate? AFAIK the pinmuxing is set by the RCW on layerscape.
How can you change the pinmuxing at runtime. How is this related to i2c
controlling GPIO?

Best regards,
Alexander

> Signed-off-by: David Leonard <David.Leonard@...i.com>
> ---
>   drivers/pinctrl/freescale/Kconfig           |   8 +
>   drivers/pinctrl/freescale/Makefile          |   1 +
>   drivers/pinctrl/freescale/pinctrl-ls1012a.c | 381 ++++++++++++++++++++
>   3 files changed, 390 insertions(+)
>   create mode 100644 drivers/pinctrl/freescale/pinctrl-ls1012a.c
> 
> diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig
> index 3b59d7189004..a2038042eeae 100644
> --- a/drivers/pinctrl/freescale/Kconfig
> +++ b/drivers/pinctrl/freescale/Kconfig
> @@ -209,6 +209,14 @@ config PINCTRL_IMX93
>   	help
>   	  Say Y here to enable the imx93 pinctrl driver
> 
> +config PINCTRL_LS1012A
> +	tristate "LS1012A pinctrl driver"
> +	depends on ARCH_LAYERSCAPE && OF || COMPILE_TEST
> +	select PINMUX
> +	select GENERIC_PINCONF
> +	help
> +	  Say Y here to enable the ls1012a pinctrl driver
> +
>   config PINCTRL_VF610
>   	bool "Freescale Vybrid VF610 pinctrl driver"
>   	depends on SOC_VF610
> diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile
> index d27085c2b4c4..6926529d8635 100644
> --- a/drivers/pinctrl/freescale/Makefile
> +++ b/drivers/pinctrl/freescale/Makefile
> @@ -35,3 +35,4 @@ obj-$(CONFIG_PINCTRL_IMX25)	+= pinctrl-imx25.o
>   obj-$(CONFIG_PINCTRL_IMX28)	+= pinctrl-imx28.o
>   obj-$(CONFIG_PINCTRL_IMXRT1050)	+= pinctrl-imxrt1050.o
>   obj-$(CONFIG_PINCTRL_IMXRT1170)	+= pinctrl-imxrt1170.o
> +obj-$(CONFIG_PINCTRL_LS1012A)	+= pinctrl-ls1012a.o
> diff --git a/drivers/pinctrl/freescale/pinctrl-ls1012a.c b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
> new file mode 100644
> index 000000000000..d4c535ed6c07
> --- /dev/null
> +++ b/drivers/pinctrl/freescale/pinctrl-ls1012a.c
> @@ -0,0 +1,381 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Pin controller for NXP QorIQ LS1012A.
> + *
> + * Copyright (c) 2024 Digi International, Inc.
> + * Author: David Leonard <David.Leonard@...i.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/pinctrl/pinctrl.h>
> +#include <linux/pinctrl/pinmux.h>
> +#include <linux/pinctrl/pinconf-generic.h>
> +#include <linux/of.h>
> +#include <linux/io.h>
> +#include <linux/regmap.h>
> +#include <linux/platform_device.h>
> +#include <linux/sys_soc.h>
> +
> +struct ls1012a_pinctrl_pdata {
> +	struct pinctrl_dev *pctl_dev;
> +	void __iomem *cr0mem;
> +	bool big_endian;
> +	u32 ssc;
> +};
> +
> +/* Bitfield macros for masks and values that follow the datasheet's
> + * bit numbering schemes for registers of different bit-endianess. */
> +#define BITV_BE(hi, v)	((v) << (31 - (hi) % 32))
> +#define BITM_BE(hi, lo)	(((1 << ((hi) - (lo) + 1)) - 1) << (31 - (hi) % 32))
> +#define BITV_LE(lo, v)	((v) << ((lo) % 32))
> +#define BITM_LE(lo, hi)	(((1 << ((hi) - (lo) + 1)) - 1) << ((lo) % 32))
> +
> +/* SCFG PMUXCR0 pinmux control register */
> +#define SCFG_PMUXCR0			0x430
> +#define QSPI_MUX_OVRD_MASK		BITM_BE(0, 0)	/* [0] */
> +#define QSPI_MUX_DISABLE		BITV_BE(0, 0)	/*  use RCW */
> +#define QSPI_MUX_ENABLE			BITV_BE(0, 1)	/*  use PMUXCR0 */
> +#define QSPI_DATA0_GPIO_OVR_MASK	BITM_BE(1, 1)	/* [1] */
> +#define QSPI_DATA0_GPIO_SEL_SPI		BITV_BE(1, 0)	/*  DATA0,SCK,CS0 */
> +#define QSPI_DATA0_GPIO_SEL_GPIO	BITV_BE(1, 1)	/*  GPIO1[4,11,5] */
> +#define QSPI_DATA1_GPIO_OVR_MASK	BITM_BE(3, 2)	/* [3:2] */
> +#define QSPI_DATA1_GPIO_SEL_SPI		BITV_BE(3, 0)	/*  DATA1 */
> +#define QSPI_DATA1_GPIO_SEL_GPIO	BITV_BE(3, 1)	/*  GPIO1[12] */
> +#define QSPI_IIC2_OVR_MASK		BITM_BE(5, 4)	/* [5:4] */
> +#define QSPI_IIC2_SEL_GPIO		BITV_BE(5, 0)	/*  GPIO1[13,14] */
> +#define QSPI_IIC2_SEL_I2C		BITV_BE(5, 1)	/*  SCL,SDA (rev0) */
> +#define QSPI_IIC2_SEL_SPI		BITV_BE(5, 2)	/*  DATA2,DATA3 */
> +
> +/* RCW SoC-specific configuration (read-only) */
> +#define DCFG_RCWSR			0x100
> +#define SOC_SPEC_CONFIG			416		/* word 13 */
> +#define DCFG_SSC_REG			(DCFG_RCWSR + SOC_SPEC_CONFIG / 8)
> +#define SSC_DATA0_GPIO_MASK		BITM_LE(421, 421)
> +#define SSC_DATA0_GPIO_SEL_SPI		BITV_LE(421, 0)	/*  DATA0,SCK,CS0 */
> +#define SSC_DATA0_GPIO_SEL_GPIO		BITV_LE(421, 1)	/*  GPIO1[11,4,5] */
> +#define SSC_DATA1_GPIO_MASK		BITM_LE(422, 423)
> +#define SSC_DATA1_GPIO_SEL_SPI		BITV_LE(422, 0)	/*  DATA1 */
> +#define SSC_DATA1_GPIO_SEL_GPIO		BITV_LE(422, 2)	/*  GPIO1[12] */
> +#define SSC_IIC2_MASK			BITM_LE(424, 425)
> +#define SSC_IIC2_SEL_GPIO		BITV_LE(424, 0)	/*  GPIO1[13,14] */
> +#define SSC_IIC2_SEL_I2C		BITV_LE(424, 2)	/*  SCL,SDA */
> +#define SSC_IIC2_SEL_SPI		BITV_LE(424, 1)	/*  DATA2,DATA3 */
> +#define SSC_IIC2_SEL_GPIO_RESET		BITV_LE(424, 3)	/*  GPIO1[13],RESET_REQ_B*/
> +
> +const struct pinctrl_pin_desc ls1012a_pins[] = {
> +	PINCTRL_PIN(60, "QSPI_A_DATA3/GPIO1_14/IIC2_SDA/RESET_REQ_B"),
> +	PINCTRL_PIN(61, "QSPI_A_DATA1/GPIO1_12"),
> +	PINCTRL_PIN(62, "QSPI_A_SCK/GPIO1_04"),
> +	PINCTRL_PIN(122, "QSPI_A_DATA2/GPIO1_13/IIC2_SCL"),
> +	PINCTRL_PIN(123, "QSPI_A_DATA0/GPIO1_11"),
> +	PINCTRL_PIN(124, "QSPI_A_CS0/GPIO1_05"),
> +};
> +
> +static const unsigned int qspi_1_grp[] = { 62, 123, 124 };
> +static const unsigned int qspi_2_grp[] = { 61 };
> +static const unsigned int qspi_3_grp[] = { 122, 60 };
> +
> +#define GRP_qspi_1	0	/* SCK,CS0,DATA0 */
> +#define GRP_qspi_2	1	/* DATA1 */
> +#define GRP_qspi_3	2	/* DATA2,DATA3 */
> +#define _GRP_max	3
> +
> +#define _PINGROUP(name) \
> +	[GRP_##name] = PINCTRL_PINGROUP(#name "_grp", name##_grp, ARRAY_SIZE(name##_grp))
> +static const struct pingroup ls1012a_groups[] = {
> +	_PINGROUP(qspi_1),
> +	_PINGROUP(qspi_2),
> +	_PINGROUP(qspi_3),
> +};
> +
> +
> +static void ls1012a_write_cr0(struct ls1012a_pinctrl_pdata *pd, u32 val)
> +{
> +	if (pd->big_endian)
> +		iowrite32be(val, pd->cr0mem);
> +	else
> +		iowrite32(val, pd->cr0mem);
> +}
> +
> +static u32 ls1012a_read_cr0(struct ls1012a_pinctrl_pdata *pd)
> +{
> +	return pd->big_endian ? ioread32be(pd->cr0mem) : ioread32(pd->cr0mem);
> +}
> +
> +static int ls1012a_get_groups_count(struct pinctrl_dev *pcdev)
> +{
> +	return ARRAY_SIZE(ls1012a_groups);
> +}
> +
> +static const char *ls1012a_get_group_name(struct pinctrl_dev *pcdev,
> +	unsigned int selector)
> +{
> +	return ls1012a_groups[selector].name;
> +}
> +
> +static int ls1012a_get_group_pins(struct pinctrl_dev *pcdev,
> +	unsigned int selector, const unsigned int **pins, unsigned int *npins)
> +{
> +	*pins = ls1012a_groups[selector].pins;
> +	*npins = ls1012a_groups[selector].npins;
> +	return 0;
> +}
> +
> +static const struct pinctrl_ops ls1012a_pinctrl_ops = {
> +	.get_groups_count = ls1012a_get_groups_count,
> +	.get_group_name = ls1012a_get_group_name,
> +	.get_group_pins = ls1012a_get_group_pins,
> +	.dt_node_to_map = pinconf_generic_dt_node_to_map_group,
> +	.dt_free_map = pinconf_generic_dt_free_map,
> +};
> +
> +static const char * const i2c_groups[] = { "qspi_3_grp" };
> +static const char * const spi_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
> +static const char * const gpio_groups[] = { "qspi_1_grp", "qspi_2_grp", "qspi_3_grp" };
> +static const char * const gpio_reset_groups[] = { "qspi_3_grp" };
> +
> +#define FUNC_i2c	0
> +#define FUNC_spi	1
> +#define FUNC_gpio	2
> +#define FUNC_gpio_reset 3
> +#define _FUNC_max	4
> +
> +#define _PINFUNC(name) \
> +	[FUNC_##name] = PINCTRL_PINFUNCTION(#name, name##_groups, ARRAY_SIZE(name##_groups))
> +static const struct pinfunction ls1012a_functions[] = {
> +	_PINFUNC(i2c),
> +	_PINFUNC(spi),
> +	_PINFUNC(gpio),
> +	_PINFUNC(gpio_reset),
> +};
> +
> +static int ls1012a_get_functions_count(struct pinctrl_dev *pctldev)
> +{
> +	return ARRAY_SIZE(ls1012a_functions);
> +}
> +
> +static const char *ls1012a_get_function_name(struct pinctrl_dev *pctldev, unsigned int func)
> +{
> +	return ls1012a_functions[func].name;
> +}
> +
> +static int ls1012a_get_function_groups(struct pinctrl_dev *pctldev, unsigned int func,
> +	const char * const **groups,
> +	unsigned int * const ngroups)
> +{
> +	*groups = ls1012a_functions[func].groups;
> +	*ngroups = ls1012a_functions[func].ngroups;
> +	return 0;
> +}
> +
> +/*
> + * LS1012A
> + *    Group: qspi_1             qspi_2      qspi_3
> + *           ================== =========== =============
> + *    Pin:   62    123    124   61          122    60
> + *           ----- ------ ----- ----------- ------ ------
> + * i2c                                      SCL    SDA    (RCW only)
> + * spi       SCK   DATA0
> + * spi       SCK   DATA0        DATA1
> + * spi       SCK   DATA0        DATA1       DATA2  DATA3
> + * gpio      GPIO4 GPIO11 GPIO5
> + * gpio                         GPIO12
> + * gpio                                     GPIO13 GPIO14
> + * gpio_reset                               GPIO13 REQ_B  (RCW only)
> + */
> +
> +static const struct ls1012a_func_mux {
> +	u32 cr0mask, cr0; /* mux control */
> +	u32 sscmask, ssc; /* equivalent in RCW */
> +} ls1012a_func_mux[_FUNC_max][_GRP_max] = {
> +	[FUNC_i2c] = {
> +		[GRP_qspi_3] = {
> +			.sscmask = SSC_IIC2_MASK,
> +			.ssc =     SSC_IIC2_SEL_I2C,
> +		},
> +	},
> +	[FUNC_spi] = {
> +		[GRP_qspi_1] = {
> +			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
> +			.cr0 =     QSPI_DATA0_GPIO_SEL_SPI,
> +			.sscmask = SSC_DATA0_GPIO_MASK,
> +			.ssc =     SSC_DATA0_GPIO_SEL_SPI
> +		},
> +		[GRP_qspi_2] = {
> +			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
> +			.cr0 =     QSPI_DATA1_GPIO_SEL_SPI,
> +			.sscmask = SSC_DATA1_GPIO_MASK,
> +			.ssc =     SSC_DATA1_GPIO_SEL_SPI,
> +		},
> +		[GRP_qspi_3] = {
> +			.cr0mask = QSPI_IIC2_OVR_MASK,
> +			.cr0 =     QSPI_IIC2_SEL_SPI,
> +			.sscmask = SSC_IIC2_MASK,
> +			.ssc =     SSC_IIC2_SEL_SPI,
> +		},
> +	},
> +	[FUNC_gpio] = {
> +		[GRP_qspi_1] = {
> +			.cr0mask = QSPI_DATA0_GPIO_OVR_MASK,
> +			.cr0 =     QSPI_DATA0_GPIO_SEL_GPIO,
> +			.sscmask = SSC_DATA0_GPIO_MASK,
> +			.ssc =     SSC_DATA0_GPIO_SEL_GPIO,
> +		},
> +		[GRP_qspi_2] = {
> +			.cr0mask = QSPI_DATA1_GPIO_OVR_MASK,
> +			.cr0 =     QSPI_DATA1_GPIO_SEL_GPIO,
> +			.sscmask = SSC_DATA1_GPIO_MASK,
> +			.ssc =     SSC_DATA1_GPIO_SEL_GPIO,
> +		},
> +		[GRP_qspi_3] = {
> +			.cr0mask = QSPI_IIC2_OVR_MASK,
> +			.cr0 =     QSPI_IIC2_SEL_GPIO,
> +			.sscmask = SSC_IIC2_MASK,
> +			.ssc =     SSC_IIC2_SEL_GPIO,
> +		},
> +	},
> +	[FUNC_gpio_reset] = {
> +		[GRP_qspi_3] = {
> +			.sscmask = SSC_IIC2_MASK,
> +			.ssc =     SSC_IIC2_SEL_GPIO_RESET,
> +		},
> +	},
> +};
> +
> +static int ls1012a_set_mux(struct pinctrl_dev *pcdev,
> +	unsigned int func, unsigned int group)
> +{
> +	struct ls1012a_pinctrl_pdata *pd = pinctrl_dev_get_drvdata(pcdev);
> +	const struct ls1012a_func_mux *fm = &ls1012a_func_mux[func][group];
> +	u32 cr0 = ls1012a_read_cr0(pd);
> +
> +	if (!fm->cr0mask) {
> +		if ((pd->ssc & fm->sscmask) != fm->ssc)
> +			return -EOPNOTSUPP;
> +		cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_DISABLE;
> +	} else {
> +		cr0 = (cr0 & ~fm->cr0mask) | fm->cr0;
> +		if ((pd->ssc & fm->sscmask) != fm->ssc)
> +			cr0 = (cr0 & ~QSPI_MUX_OVRD_MASK) | QSPI_MUX_ENABLE;
> +	}
> +	ls1012a_write_cr0(pd, cr0);
> +	return 0;
> +}
> +
> +static void ls1012a_init_mux(struct ls1012a_pinctrl_pdata *pd)
> +{
> +	unsigned int func, group;
> +	const struct ls1012a_func_mux *fm;
> +	u32 cr0;
> +
> +	cr0 = ls1012a_read_cr0(pd);
> +	if ((cr0 & QSPI_MUX_OVRD_MASK) == QSPI_MUX_DISABLE) {
> +		/*
> +		 * Prepare a disabled MUXCR0 to have a same/similar
> +		 * configuration as RCW SSC, and leave it disabled.
> +		 */
> +		for (func = 0; func < _FUNC_max; func++) {
> +			for (group = 0; group < _GRP_max; group++) {
> +				fm = &ls1012a_func_mux[func][group];
> +				if (fm->sscmask &&
> +				    fm->ssc == (pd->ssc & fm->sscmask)) {
> +					cr0 &= ~fm->cr0mask;
> +					cr0 |= fm->cr0;
> +				}
> +			}
> +		}
> +		ls1012a_write_cr0(pd, cr0);
> +	}
> +}
> +
> +static const struct pinmux_ops ls1012a_pinmux_ops = {
> +	.get_functions_count = ls1012a_get_functions_count,
> +	.get_function_name = ls1012a_get_function_name,
> +	.get_function_groups = ls1012a_get_function_groups,
> +	.set_mux = ls1012a_set_mux,
> +};
> +
> +static struct pinctrl_desc ls1012a_pinctrl_desc = {
> +	.name = "ls1012a",
> +	.pins = ls1012a_pins,
> +	.npins = ARRAY_SIZE(ls1012a_pins),
> +	.pctlops = &ls1012a_pinctrl_ops,
> +	.pmxops = &ls1012a_pinmux_ops,
> +	.owner = THIS_MODULE,
> +};
> +
> +static int ls1012a_pinctrl_probe(struct platform_device *pdev)
> +{
> +	struct ls1012a_pinctrl_pdata *pd;
> +	int ret;
> +	u32 dcfg_ssc;
> +	struct regmap *dcfg_regmap;
> +
> +	pd = devm_kzalloc(&pdev->dev, sizeof(*pd), GFP_KERNEL);
> +	if (!pd)
> +		return -ENOMEM;
> +	platform_set_drvdata(pdev, pd);
> +
> +	pd->big_endian = device_is_big_endian(&pdev->dev);
> +
> +	/* SCFG PMUX0 */
> +	pd->cr0mem = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(pd->cr0mem))
> +		return PTR_ERR(pd->cr0mem);
> +	dev_dbg(&pdev->dev, "scfg pmuxcr0 at %px %s", pd->cr0mem,
> +		pd->big_endian ? "be" : "le");
> +
> +	/* DCFG RCW SSC */
> +	dcfg_regmap = syscon_regmap_lookup_by_phandle(
> +		dev_of_node(&pdev->dev), "dcfg-regmap");
> +	if (IS_ERR(dcfg_regmap)) {
> +		dev_err(&pdev->dev, "dcfg regmap: %pe\n", dcfg_regmap);
> +		return -EINVAL;
> +	}
> +	ret = regmap_read(dcfg_regmap, DCFG_SSC_REG, &dcfg_ssc);
> +	if (ret) {
> +		dev_err(&pdev->dev, "dcfg-regmap read: %d\n", ret);
> +		return ret;
> +	}
> +	pd->ssc = swab32(dcfg_ssc); /* untwist RCW fields */
> +
> +	dev_dbg(&pdev->dev, "dcfg ssc = %08x (grp1=%s grp2=%s grp3=%s)\n",
> +		pd->ssc,
> +		(pd->ssc & SSC_DATA0_GPIO_MASK) == SSC_DATA0_GPIO_SEL_SPI ? "spi" : "gpio",
> +		(pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_SPI ? "spi"
> +		: (pd->ssc & SSC_DATA1_GPIO_MASK) == SSC_DATA1_GPIO_SEL_GPIO ? "gpio"
> +		: (pd->ssc & SSC_DATA1_GPIO_MASK) == 0x80 ? "10" : "11",
> +		(pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_GPIO ? "gpio"
> +		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_I2C ? "i2c"
> +		: (pd->ssc & SSC_IIC2_MASK) == SSC_IIC2_SEL_SPI ? "spi"
> +		: "gpio+reset");
> +
> +	ls1012a_init_mux(pd);
> +
> +	ret = devm_pinctrl_register_and_init(&pdev->dev, &ls1012a_pinctrl_desc,
> +		pd, &pd->pctl_dev);
> +	if (ret)
> +		return dev_err_probe(&pdev->dev, ret, "Failed pinctrl init\n");
> +
> +	pinctrl_enable(pd->pctl_dev);
> +	return ret;
> +}
> +
> +static const struct of_device_id ls1012a_pinctrl_match_table[] = {
> +	{ .compatible = "fsl,ls1012a-pinctrl" },
> +	{ /* sentinel */ }
> +};
> +
> +static struct platform_driver ls1012a_pinctrl_driver = {
> +	.driver = {
> +		.name = "ls1012a_pinctrl",
> +		.of_match_table = ls1012a_pinctrl_match_table,
> +	},
> +	.probe = ls1012a_pinctrl_probe,
> +};
> +
> +builtin_platform_driver(ls1012a_pinctrl_driver)
> +
> +MODULE_DESCRIPTION("LS1012A pinctrl driver");
> +MODULE_LICENSE("GPL");
> 


-- 
TQ-Systems GmbH | Mühlstraße 2, Gut Delling | 82229 Seefeld, Germany
Amtsgericht München, HRB 105018
Geschäftsführer: Detlef Schneider, Rüdiger Stahl, Stefan Schneider
http://www.tq-group.com/



Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ