* Re: [PATCH v5 8/8] arm64: dts: imx8qxp-mek: add parallel ov5640 camera support
From: guoniu.zhou @ 2026-06-22 9:01 UTC (permalink / raw)
To: Frank.Li
Cc: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, devicetree, linux-arm-kernel
In-Reply-To: <20260617-imx8qxp_pcam-v5-8-7fa6c8e7fba7@nxp.com>
> Add parallel ov5640 nodes in imx8qxp-mek and create overlay file to enable
> it because it can work at two mode: MIPI CSI and parallel mode.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
>
> diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
> index 711e36cc2c99..f54fd4cdd926 100644
> --- a/arch/arm64/boot/dts/freescale/Makefile
> +++ b/arch/arm64/boot/dts/freescale/Makefile
> @@ -434,6 +434,9 @@ dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek-pcie-ep.dtb
> imx8qxp-mek-ov5640-csi-dtbs := imx8qxp-mek.dtb imx8qxp-mek-ov5640-csi.dtbo
> dtb-${CONFIG_ARCH_MXC} += imx8qxp-mek-ov5640-csi.dtb
>
> +imx8qxp-mek-ov5640-cpi-dtbs := imx8qxp-mek.dtb imx8qxp-mek-ov5640-cpi.dtbo
> +dtb-${CONFIG_ARCH_MXC} += imx8qxp-mek-ov5640-cpi.dtb
> +
> dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqp-mba8xx.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8qxp-tqma8xqps-mb-smarc-2.dtb
> dtb-$(CONFIG_ARCH_MXC) += imx8ulp-9x9-evk.dtb
> diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso b/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso
> new file mode 100644
> index 000000000000..9fbdd798f17d
> --- /dev/null
> +++ b/arch/arm64/boot/dts/freescale/imx8qxp-mek-ov5640-cpi.dtso
> @@ -0,0 +1,83 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright 2025 NXP
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/clock/imx8-lpcg.h>
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/media/video-interfaces.h>
> +#include <dt-bindings/pinctrl/pads-imx8qxp.h>
> +
> +&cm40_i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + ov5640_pi: camera@3c {
> + compatible = "ovti,ov5640";
> + reg = <0x3c>;
> + clocks = <&pi0_misc_lpcg IMX_LPCG_CLK_0>;
> + clock-names = "xclk";
> + assigned-clocks = <&pi0_misc_lpcg IMX_LPCG_CLK_0>;
> + assigned-clock-rates = <24000000>;
> + AVDD-supply = <®_2v8>;
> + DOVDD-supply = <®_1v8>;
> + DVDD-supply = <®_1v5>;
> + pinctrl-0 = <&pinctrl_parallel_cpi>;
> + pinctrl-names = "default";
> + powerdown-gpios = <&lsio_gpio3 2 GPIO_ACTIVE_HIGH>;
> + reset-gpios = <&lsio_gpio3 3 GPIO_ACTIVE_LOW>;
> +
> + port {
> + ov5640_pi_ep: endpoint {
> + bus-type = <MEDIA_BUS_TYPE_PARALLEL>;
> + bus-width = <8>;
> + hsync-active = <1>;
> + pclk-sample = <1>;
> + remote-endpoint = <¶llel_cpi_in>;
> + vsync-active = <0>;
> + };
> + };
> + };
> +};
> +
> +&iomuxc {
> + pinctrl_parallel_cpi: parallelcpigrp {
> + fsl,pins = <
> + IMX8QXP_CSI_D00_CI_PI_D02 0xc0000041
> + IMX8QXP_CSI_D01_CI_PI_D03 0xc0000041
> + IMX8QXP_CSI_D02_CI_PI_D04 0xc0000041
> + IMX8QXP_CSI_D03_CI_PI_D05 0xc0000041
> + IMX8QXP_CSI_D04_CI_PI_D06 0xc0000041
> + IMX8QXP_CSI_D05_CI_PI_D07 0xc0000041
> + IMX8QXP_CSI_D06_CI_PI_D08 0xc0000041
> + IMX8QXP_CSI_D07_CI_PI_D09 0xc0000041
> +
> + IMX8QXP_CSI_MCLK_CI_PI_MCLK 0xc0000041
> + IMX8QXP_CSI_PCLK_CI_PI_PCLK 0xc0000041
> + IMX8QXP_CSI_HSYNC_CI_PI_HSYNC 0xc0000041
> + IMX8QXP_CSI_VSYNC_CI_PI_VSYNC 0xc0000041
> + IMX8QXP_CSI_EN_LSIO_GPIO3_IO02 0xc0000041
> + IMX8QXP_CSI_RESET_LSIO_GPIO3_IO03 0xc0000041
> + >;
> + };
> +};
> +
> +&isi {
> + status = "okay";
> +};
> +
> +¶llel_cpi {
> + status = "okay";
> +
> + ports {
> + port@0 {
> + parallel_cpi_in: endpoint {
> + hsync-active = <1>;
> + remote-endpoint = <&ov5640_pi_ep>;
> + };
> + };
> + };
> +};
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* Re: [PATCH v5 7/8] arm64: dts: imx8: add camera parallel interface (CPI) node
From: guoniu.zhou @ 2026-06-22 9:01 UTC (permalink / raw)
To: Frank.Li
Cc: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, devicetree, linux-arm-kernel
In-Reply-To: <20260617-imx8qxp_pcam-v5-7-7fa6c8e7fba7@nxp.com>
> Add camera parallel interface (CPI) node.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
>
> diff --git a/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi b/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
> index a72b2f1c4a1b..b504f99f6acd 100644
> --- a/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8-ss-img.dtsi
> @@ -222,6 +222,19 @@ irqsteer_parallel: irqsteer@58260000 {
> status = "disabled";
> };
>
> + parallel_cpi: cpi@58261000 {
> + compatible = "fsl,imx8qxp-pcif";
> + reg = <0x58261000 0x1000>;
> + clocks = <&pi0_pxl_lpcg IMX_LPCG_CLK_0>,
> + <&pi0_ipg_lpcg IMX_LPCG_CLK_4>;
> + clock-names = "pixel", "ipg";
> + assigned-clocks = <&clk IMX_SC_R_PI_0 IMX_SC_PM_CLK_PER>;
> + assigned-clock-parents = <&clk IMX_SC_R_PI_0_PLL IMX_SC_PM_CLK_PLL>;
> + assigned-clock-rates = <160000000>;
> + power-domains = <&pd IMX_SC_R_PI_0>;
> + status = "disabled";
> + };
> +
> pi0_ipg_lpcg: clock-controller@58263004 {
> compatible = "fsl,imx8qxp-lpcg";
> reg = <0x58263004 0x4>;
> diff --git a/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi b/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
> index 232cf25dadfc..5aae15540d6c 100644
> --- a/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8qxp-ss-img.dtsi
> @@ -62,6 +62,14 @@ isi_in_2: endpoint {
> remote-endpoint = <&mipi_csi0_out>;
> };
> };
> +
> + port@4 {
> + reg = <4>;
> +
> + isi_in_4: endpoint {
> + remote-endpoint = <¶llel_cpi_out>;
> + };
> + };
> };
> };
>
> @@ -95,3 +103,22 @@ &jpegenc {
> &mipi_csi_1 {
> status = "disabled";
> };
> +
> +¶llel_cpi {
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> + };
> +
> + port@1 {
> + reg = <1>;
> +
> + parallel_cpi_out: endpoint {
> + remote-endpoint = <&isi_in_4>;
> + };
> + };
> + };
> +};
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* Re: [PATCH v5 6/8] media: nxp: add V4L2 subdev driver for camera parallel interface (CPI)
From: guoniu.zhou @ 2026-06-22 9:01 UTC (permalink / raw)
To: Frank.Li
Cc: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, devicetree, linux-arm-kernel, Alice Yuan, Robert Chiras,
Zhipeng Wang
In-Reply-To: <20260617-imx8qxp_pcam-v5-6-7fa6c8e7fba7@nxp.com>
On Wed, 17 Jun 2026 15:50:16 -0400, Frank.Li@oss.nxp.com <Frank.Li@oss.nxp.com> wrote:
> diff --git a/drivers/media/platform/nxp/imx-parallel-cpi.c b/drivers/media/platform/nxp/imx-parallel-cpi.c
> new file mode 100644
> index 000000000000..00f5d5f47644
> --- /dev/null
> +++ b/drivers/media/platform/nxp/imx-parallel-cpi.c
> @@ -0,0 +1,614 @@
> [ ... skip 245 lines ... ]
> + }
> +
> + val = CPI_CTRL_REG1_PIXEL_WIDTH(pixel_width) |
> + CPI_CTRL_REG1_VSYNC_PULSE(vsync_pulse);
> + writel(val, pcpidev->regs + pdata->interface_ctrl_reg1);
> +}
The switch statement result is overwritten.
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* Re: [PATCH v5 3/8] media: synopsys: Use v4l2_subdev_get_frame_desc_passthrough()
From: guoniu.zhou @ 2026-06-22 9:01 UTC (permalink / raw)
To: Frank.Li
Cc: Sakari Ailus, Mauro Carvalho Chehab, Michael Riesch,
Laurent Pinchart, Frank Li, Martin Kepplinger-Novakovic,
Rui Miguel Silva, Purism Kernel Team, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-media, linux-kernel,
imx, devicetree, linux-arm-kernel
In-Reply-To: <20260617-imx8qxp_pcam-v5-3-7fa6c8e7fba7@nxp.com>
> Replace the local frame descriptor callback implementation with
> v4l2_subdev_get_frame_desc_passthrough().
>
> This helper provides the same functionality while avoiding duplicate
> code and simplifying the driver implementation.
>
> Signed-off-by: Frank Li <Frank.Li@nxp.com>
>
> diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> index 41e48365167e..f51367409ff4 100644
> --- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> +++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c
> @@ -630,31 +630,11 @@ static int dw_mipi_csi2rx_disable_streams(struct v4l2_subdev *sd,
> return ret;
> }
>
> -static int
> -dw_mipi_csi2rx_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
> - struct v4l2_mbus_frame_desc *fd)
> -{
> - struct dw_mipi_csi2rx_device *csi2 = to_csi2(sd);
> - struct v4l2_subdev *remote_sd;
> - struct media_pad *remote_pad;
> -
> - remote_pad = media_pad_remote_pad_unique(&csi2->pads[DW_MIPI_CSI2RX_PAD_SINK]);
> - if (IS_ERR(remote_pad)) {
> - dev_err(csi2->dev, "can't get remote source pad\n");
> - return PTR_ERR(remote_pad);
> - }
> -
> - remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
> -
> - return v4l2_subdev_call(remote_sd, pad, get_frame_desc,
> - remote_pad->index, fd);
> -}
> -
> static const struct v4l2_subdev_pad_ops dw_mipi_csi2rx_pad_ops = {
> .enum_mbus_code = dw_mipi_csi2rx_enum_mbus_code,
> .get_fmt = v4l2_subdev_get_fmt,
> .set_fmt = dw_mipi_csi2rx_set_fmt,
> - .get_frame_desc = dw_mipi_csi2rx_get_frame_desc,
> + .get_frame_desc = v4l2_subdev_get_frame_desc_passthrough,
> .set_routing = dw_mipi_csi2rx_set_routing,
> .enable_streams = dw_mipi_csi2rx_enable_streams,
> .disable_streams = dw_mipi_csi2rx_disable_streams,
Reviewed-by: Guoniu Zhou <guoniu.zhou@nxp.com>
--
Guoniu Zhou <guoniu.zhou@oss.nxp.com>
^ permalink raw reply
* Re: [PATCH v3 09/12] iio: dac: ad5686: implement new sync() op for the spi bus
From: Rodrigo Alencar @ 2026-06-22 8:50 UTC (permalink / raw)
To: David Lechner, rodrigo.alencar, Michael Auchter, linux, linux-iio,
devicetree, linux-kernel, linux-hardening
Cc: Michael Hennerich, Jonathan Cameron, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Philipp Zabel, Kees Cook,
Gustavo A. R. Silva
In-Reply-To: <50a7e765-ba20-45c0-8a13-5e672413b600@baylibre.com>
On 20/06/26 11:33, David Lechner wrote:
> On 6/16/26 3:21 AM, Rodrigo Alencar via B4 Relay wrote:
> > From: Rodrigo Alencar <rodrigo.alencar@analog.com>
> >
> > Use of local SPI bus data to manage a collection of SPI transfers and
> > flush them to the SPI platform driver with the sync() operation. This
> > allows for faster handling of multiple channel DAC writes, avoiding kernel
> > overhead per spi_sync() call, which will be helpful when enabling
> > triggered buffer support.
...
> > +/**
> > + * struct ad5686_spi_data - SPI bus specific data
> > + * @msg: SPI message used for transfers
> > + * @size: number of transfers currently in the message
> > + * @capacity: maximum number of transfers that can be added to the message
> > + * @xfers: array of SPI transfers, allocated with the provided capacity
> > + */
> > +struct ad5686_spi_data {
> > + struct spi_message msg;
> > + unsigned int size;
> > + unsigned int capacity;
> > + struct spi_transfer xfers[] __counted_by(capacity);
> > +};
> > +
> > static int ad5686_spi_write(struct ad5686_state *st,
> > u8 cmd, u8 addr, u16 val)
> > {
> > - struct spi_device *spi = to_spi_device(st->dev);
> > - u8 tx_len, *buf;
> > + struct ad5686_spi_data *bus_data = st->bus_data;
> > + struct spi_transfer *xfer;
> >
> > + if (bus_data->size >= bus_data->capacity)
> > + return -E2BIG;
> > +
> > + if (bus_data->size)
> > + bus_data->xfers[bus_data->size - 1].cs_change = 1;
> > + else
> > + spi_message_init(&bus_data->msg);
>
> Seems odd that spi_message_init() is called conditionally. What
> prevents spi_message_add_tail() from growing the message unbounded
> on repeated calls?
The "size >= capacity" check right above this.
>
> > +
> > + xfer = &bus_data->xfers[bus_data->size];
> > switch (st->chip_info->regmap_type) {
> > case AD5310_REGMAP:
> > - st->data[0].d16 = cpu_to_be16(AD5310_CMD(cmd) |
> > - val);
> > - buf = &st->data[0].d8[0];
> > - tx_len = 2;
> > + st->data[bus_data->size].d16 =
> > + cpu_to_be16(AD5310_CMD(cmd) | val);
> > + *xfer = (struct spi_transfer) {
> > + .tx_buf = &st->data[bus_data->size].d16,
> > + .len = sizeof(st->data[bus_data->size].d16),
> > + };
> > break;
> > case AD5683_REGMAP:
> > - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
> > - AD5683_DATA(val));
> > - buf = &st->data[0].d8[1];
> > - tx_len = 3;
> > + st->data[bus_data->size].d32 =
> > + cpu_to_be32(AD5686_CMD(cmd) | AD5683_DATA(val));
> > + *xfer = (struct spi_transfer) {
> > + .tx_buf = &st->data[bus_data->size].d8[1],
> > + .len = sizeof(st->data[bus_data->size].d32) - 1,
> > + };
> > break;
> > case AD5686_REGMAP:
> > - st->data[0].d32 = cpu_to_be32(AD5686_CMD(cmd) |
> > - AD5686_ADDR(addr) |
> > - val);
> > - buf = &st->data[0].d8[1];
> > - tx_len = 3;
> > + st->data[bus_data->size].d32 =
> > + cpu_to_be32(AD5686_CMD(cmd) | AD5686_ADDR(addr) | val);
> > + *xfer = (struct spi_transfer) {
> > + .tx_buf = &st->data[bus_data->size].d8[1],
> > + .len = sizeof(st->data[bus_data->size].d32) - 1,
> > + };
> > break;
> > default:
> > return -EINVAL;
> > }
> >
> > - return spi_write(spi, buf, tx_len);
>
> If this function no longer writes, should we change the name of
> the function to something like ad5686_spi_write_prepare_msg()?
>
> > + spi_message_add_tail(xfer, &bus_data->msg);
> > + bus_data->size++;
> > +
> > + return 0;
> > +}
> > +
> > +static int ad5686_spi_sync(struct ad5686_state *st)
> > +{
> > + struct spi_device *spi = to_spi_device(st->dev);
> > + struct ad5686_spi_data *bus_data = st->bus_data;
> > +
> > + bus_data->size = 0; /* always reset, even on sync failure */
> > + return spi_sync(spi, &bus_data->msg);
> > }
> >
> > static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
> > {
> > - struct spi_transfer t[] = {
> > - {
> > - .tx_buf = &st->data[0].d8[1],
> > - .len = 3,
> > - .cs_change = 1,
> > - }, {
> > - .tx_buf = &st->data[1].d8[1],
> > - .rx_buf = &st->data[2].d8[1],
> > - .len = 3,
> > - },
> > - };
> > struct spi_device *spi = to_spi_device(st->dev);
> > + struct ad5686_spi_data *bus_data = st->bus_data;
> > + struct spi_transfer *xfer = &bus_data->xfers[0];
> > u8 cmd = 0;
> > int ret;
> >
> > @@ -85,8 +117,21 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
> > AD5686_ADDR(addr));
> > st->data[1].d32 = cpu_to_be32(AD5686_CMD(AD5686_CMD_NOOP));
> >
> > - ret = spi_sync_transfer(spi, t, ARRAY_SIZE(t));
> > - if (ret < 0)
> > + xfer[0] = (struct spi_transfer) {
> > + .tx_buf = &st->data[0].d8[1],
> > + .len = sizeof(st->data[0].d32) - 1,
>
> Would make more sense to say `sizeof(st->data[0].d8) - 1` since
> the buffer is &st->data[0].d8[1].
the buffer is d8[1], d8[2] and d8[3], skipping d8[0], for a len = 3.
> > + .cs_change = 1,
> > + };
> > + xfer[1] = (struct spi_transfer) {
> > + .tx_buf = &st->data[1].d8[1],
> > + .rx_buf = &st->data[2].d8[1],
> > + .len = sizeof(st->data[1].d32) - 1,
>
> And here.
>
> > + };
> > +
> > + spi_message_init_with_transfers(&bus_data->msg, xfer, 2);
> > +
> > + ret = spi_sync(spi, &bus_data->msg);
> > + if (ret)
> > return ret;
> >
> > return be32_to_cpu(st->data[2].d32);
> > @@ -95,12 +140,26 @@ static int ad5686_spi_read(struct ad5686_state *st, u8 addr)
> > static const struct ad5686_bus_ops ad5686_spi_ops = {
> > .write = ad5686_spi_write,
> > .read = ad5686_spi_read,
> > + .sync = ad5686_spi_sync,
> > };
> >
--
Kind regards,
Rodrigo Alencar
^ permalink raw reply
* Re: [PATCH v2 5/5] PCI: spacemit-k1: Add Spacemit K3 PCIe host controller support
From: Inochi Amaoto @ 2026-06-22 8:50 UTC (permalink / raw)
To: Alex Elder, Inochi Amaoto, Jingoo Han, Manivannan Sadhasivam,
Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Yixun Lan,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Christian Bruel, Vincent Guittot, Senchuan Zhang, Nam Cao,
Siddharth Vadapalli, Randolph Lin, Andy Shevchenko, Vidya Sagar,
Neil Armstrong, Gustavo Pimentel
Cc: linux-pci, devicetree, linux-kernel, linux-riscv, spacemit,
Yixun Lan, Longbin Li
In-Reply-To: <2dec4fe6-30d8-4949-bdc1-e32508340b87@riscstar.com>
On Tue, Jun 09, 2026 at 11:11:24AM -0500, Alex Elder wrote:
> On 5/16/26 8:48 PM, Inochi Amaoto wrote:
> > The PCIe controller on Spacemit K3 is almost a standard Synopsys
> > DesignWare PCIe IP with extra link and reset control. Unlike
> > the PCIe controller on K1, this controller supports external MSI
> > interrupt controller and can use multiple PHYs at the same time.
> >
> > Add driver to support PCIe controller on Spacemit K3 PCIe.
>
> It seems like you're creating a lot of new code for K3. In
> some cases it's very similar to K1, and it's not clear why it
> needs to be different.
>
> I'd much rather see a patch that prepares for K3 support by
> doing minor refactoring of the existing code to support K1
> in a way that will make adding K3 support more natural.
> Then a patch to enable K3 should be simpler (and can focus
> on what is truly different).
>
I can not understand what you see, the init logic of K3 is
completely different from the K1, so a new function is need.
For other logic, I have reused all things as I can.
> >
> > Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
> > ---
> > drivers/pci/controller/dwc/Kconfig | 4 +-
> > drivers/pci/controller/dwc/pcie-spacemit-k1.c | 169 ++++++++++++++++++
> > 2 files changed, 171 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> > index f2fde13107f2..fae971ecd876 100644
> > --- a/drivers/pci/controller/dwc/Kconfig
> > +++ b/drivers/pci/controller/dwc/Kconfig
> > @@ -439,7 +439,7 @@ config PCIE_SOPHGO_DW
> > Sophgo SoCs.
> > config PCIE_SPACEMIT_K1
> > - tristate "SpacemiT K1 PCIe controller (host mode)"
> > + tristate "SpacemiT K1/K3 PCIe controller (host mode)"
> > depends on ARCH_SPACEMIT || COMPILE_TEST
> > depends on HAS_IOMEM
> > select PCIE_DW_HOST
> > @@ -447,7 +447,7 @@ config PCIE_SPACEMIT_K1
> > default ARCH_SPACEMIT
> > help
> > Enables support for the DesignWare based PCIe controller in
> > - the SpacemiT K1 SoC operating in host mode. Three controllers
> > + the SpacemiT K1/K3 SoC operating in host mode. Three controllers
> > are available on the K1 SoC; the first of these shares a PHY
> > with a USB 3.0 host controller (one or the other can be used).
> > diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> > index 7f6f1df31cd8..7854d26220a9 100644
> > --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> > +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> > @@ -23,6 +23,7 @@
> > #define PCI_VENDOR_ID_SPACEMIT 0x201f
> > #define PCI_DEVICE_ID_SPACEMIT_K1 0x0001
> > +#define PCI_DEVICE_ID_SPACEMIT_K3 0x0002
> > /* Offsets and field definitions for link management registers */
> > #define K1_PHY_AHB_IRQ_EN 0x0000
> > @@ -32,8 +33,20 @@
> > #define SMLH_LINK_UP BIT(1)
> > #define RDLH_LINK_UP BIT(12)
> > +#define INTR_STATUS 0x0010
> > +
> > #define INTR_ENABLE 0x0014
> > #define MSI_CTRL_INT BIT(11)
> > +#define RDLH_LINK_UP_INT BIT(20)
> > +
> > +#define K3_PHY_AHB_IRQSTATUS_INTX 0x0008
>
> Can you add INTX support for K1 as well (perhaps in a separate
> patch)?
>
I have no knowledge about INTx support, and the vendor refuse
to provide any information about this. So no support for this.
> > +#define K3_ADDR_INTR_STATUS1 0x0018
> > +
> > +#define K3_CACHE_MSTR_AWCACHE_MODE GENMASK(14, 11)
> > +#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR 0xf
> > +
> > +#define K3_MAX_PHY_NUMBER 6
>
> You used "count" in patch 2 as the field name.
>
> > /* Some controls require APMU regmap access */
> > #define SYSCON_APMU "spacemit,apmu"
> > @@ -48,6 +61,9 @@
> > #define PCIE_CONTROL_LOGIC 0x0004
> > #define PCIE_SOFT_RESET BIT(0)
> > +#define PCIE_PERSTN_OE BIT(24)
> > +#define PCIE_PERSTN_OUT BIT(25)
> > +#define PCIE_IGNORE_PERSTN BIT(31)
> > struct k1_pcie {
> > struct dw_pcie pci;
> > @@ -262,6 +278,152 @@ static const struct dw_pcie_ops k1_pcie_ops = {
> > .stop_link = k1_pcie_stop_link,
> > };
> > +static int k3_pcie_enable_phy(struct k1_pcie *pcie)
>
> Can you just make K1's single PHY be a special case of
> having "N" PHYs? I.e., just set the phy_count for
> K1 to be 1, so this loop would work for both K1 and K3?
>
This is reasonable.
> > +{
> > + int i, ret;
> > +
> > + for (i = 0; i < pcie->phy_count; i++) {
> > + ret = phy_init(pcie->phy[i]);
> > + if (ret)
> > + goto err_phy;
> > + }
> > +
> > + return 0;
> > +
> > +err_phy:
> > + while (--i >= 0)
> > + phy_exit(pcie->phy[i]);
> > +
> > + return ret;
> > +}
> > +
> > +static int k3_pcie_init(struct dw_pcie_rp *pp)
> > +{
> > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > + struct k1_pcie *k1 = to_k1_pcie(pci);
> > + u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
> > + u32 val;
> > + int ret;
> > +
> > + regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
>
> Should the above be done for K1? Would it hurt? Handle
> both K1 and K3 the same way if possible.
>
> The next two things are identical to k1_pcie_init(). Make
> the code common if possible, so it's very obvious what
> really needs to be different between the two.
>
No, I have diff the code and find only about 40% of logic
are similar. However, these logic is fragmented, so I decide
to add a new function, which is easier to maintain.
> > +
> > + k1_pcie_toggle_soft_reset(k1);
>
> The "k1" prefix is fine for now, but if this driver gets
> used for more devices in the future, it might be worth
> renaming things to emphasize that it's not K1-specific.
>
Currently I have no knowledge on the new device and do not
think it is a good idea to change the name. Anyway, it is
possible to change to kx, but I do not think it is clear.
> > + ret = k1_pcie_enable_resources(k1);
> > + if (ret)
> > + return ret;
> > +
> > + regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
> > + regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
> > +
>
> You enable the PHY here much earlier than what's done in
> the K1 code. Should the K1 PHY be enabled earlier?
> Also, I don't really think there needs to be separate
> versions of the code that enables PHYs for K1 and K3.
>
IIRC this is a specific logic for K3.
> > + ret = k3_pcie_enable_phy(k1);
> > + if (ret) {
> > + k1_pcie_disable_resources(k1);
> > + return ret;
> > + }
> > +
> > + /* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
> > + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> > + PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> > + usleep_range(1000, 2000);
> > + regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> > +
> > + msleep(PCIE_T_PVPERL_MS);
> > +
> > + /*
> > + * Put the controller in root complex mode, and indicate that
> > + * Vaux (3.3v) is present.
> > + */
> > + regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> > + PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
> > +
> > + val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> > + val = u32_replace_bits(val, GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE,
> > + GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> > + dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> > +
>
> The following block of code (roughly) is done right after
> enabling resources in the K1 version of this function.
>
> Maybe the order you do it is better, but in that case,
> change the (existing, and soon, common) code to do it
> however is best if that's the case.
>
> You should try to factor out the common parts and minimize
> what's actually different between the two.
>
> I would also expect that the device ID would be stored in the
> platform data rather than having both init functions hard-code
> the value here.
>
> I'm going to leave it at that for now.
>
> -Alex
This first thing you should know is the init logic of K3
is totally different from K1, I have asked for the vendor
and they told me it is better to treat them differently,
even if they are using the same ip.
For the request of the device ID setup, I think I can add
a function for it.
>
> > + dw_pcie_dbi_ro_wr_en(pci);
> > + dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
> > + dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K3);
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +
> > + /* Finally, as a workaround, disable ASPM L1 */
> > + k1_pcie_disable_aspm_l1(k1);
> > +
> > + return 0;
> > +}
> > +
> > +static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
> > +{
> > + struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> > + u32 val;
> > +
> > + dw_pcie_dbi_ro_wr_en(pci);
> > +
> > + val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
> > + val |= u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
> > + K3_CACHE_MSTR_AWCACHE_MODE);
> > + dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
> > +
> > + dw_pcie_dbi_ro_wr_dis(pci);
> > +
> > + return 0;
> > +}
> > +
> > +static const struct dw_pcie_host_ops k3_pcie_host_ops = {
> > + .init = k3_pcie_init,
> > + .deinit = k1_pcie_deinit,
> > + .msi_init = k3_pcie_msi_host_init,
> > +};
> > +
> > +static const struct dw_pcie_ops k3_pcie_ops = {
> > + .link_up = k1_pcie_link_up,
> > + .start_link = k1_pcie_start_link,
> > + .stop_link = k1_pcie_stop_link,
> > +};
> > +
> > +static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
> > + u32 *status0, u32 *status1, u32 *status2)
> > +{
> > + *status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> > + *status1 = readl_relaxed(k1->link + INTR_STATUS);
> > + *status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
> > +
> > + writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> > + writel_relaxed(*status1, k1->link + INTR_STATUS);
> > + writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
> > +}
> > +
> > +static int k3_pcie_parse_port(struct k1_pcie *k1)
> > +{
> > + struct device *dev = k1->pci.dev;
> > + u32 status0, status1, status2;
> > + int i;
> > +
> > + k1->phy = devm_kmalloc_array(dev, K3_MAX_PHY_NUMBER, sizeof(*k1->phy),
> > + GFP_KERNEL);
> > + if (!k1->phy)
> > + return -ENOMEM;
> > +
> > + for (i = 0; i < K3_MAX_PHY_NUMBER; i++) {
> > + k1->phy[i] = devm_of_phy_get_by_index(dev, dev->of_node, i);
> > + if (IS_ERR(k1->phy[i])) {
> > + if (PTR_ERR(k1->phy[i]) == -ENODEV)
> > + break;
> > +
> > + return PTR_ERR(k1->phy[i]);
> > + }
> > + }
> > +
> > + k1->phy_count = i;
> > + if (k1->phy_count == 0)
> > + return -EINVAL;
> > +
> > + k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
> > +
> > + return 0;
> > +}
> > +
> > static int k1_pcie_parse_port(struct k1_pcie *k1)
> > {
> > struct device *dev = k1->pci.dev;
> > @@ -363,8 +525,15 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
> > .parse_port = k1_pcie_parse_port,
> > };
> > +static const struct k1_pcie_device_data k3_pcie_device_data = {
> > + .host_ops = &k3_pcie_host_ops,
> > + .ops = &k3_pcie_ops,
> > + .parse_port = k3_pcie_parse_port,
> > +};
> > +
> > static const struct of_device_id k1_pcie_of_match_table[] = {
> > { .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
> > + { .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
> > { }
> > };
>
^ permalink raw reply
* Re: [PATCH v2 2/2] software node: Fix software_node_get_reference_args() with index -1
From: Alban Bedel @ 2026-06-22 8:41 UTC (permalink / raw)
To: Andy Shevchenko
Cc: driver-core, devicetree, Daniel Scally, Heikki Krogerus,
Sakari Ailus, Greg Kroah-Hartman, Rafael J. Wysocki,
Danilo Krummrich, Rob Herring, Saravana Kannan, Zijun Hu,
linux-kernel, Alban Bedel
In-Reply-To: <ajQ6j5roSZ16Yb-M@black.igk.intel.com>
On Thu, 18 Jun 2026 20:35:59 +0200
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> On Thu, Jun 18, 2026 at 05:20:35PM +0200, Alban Bedel wrote:
> > The bounds check for the index passed to
> > software_node_get_reference_args() was failing when passed UINT_MAX,
> > this in turn would lead to an out of bound access in the property
> > array. Fix the bound check to also cover the UINT_MAX case.
>
> ...
>
> > - if ((index + 1) * sizeof(*ref) > prop->length)
> > + if (index >= prop->length / sizeof(*ref))
>
> It trades multiplication for division (which might be not always
> power-of-two).
This code is not really performance relevant and using a non trivial
expression lead to the currently buggy code. I find that easy to
understand and obviously correct code is better suited here.
What alternative would you suggest?
Alban
^ permalink raw reply
* Re: [PATCH 4/4] gpu: host1x: Allow limiting usable channel and syncpoint ranges
From: sashiko-bot @ 2026-06-22 8:48 UTC (permalink / raw)
To: Mikko Perttunen; +Cc: conor+dt, robh, devicetree, dri-devel
In-Reply-To: <20260622-host1x-nohv-v1-4-65bc682a617f@nvidia.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Unvalidated device tree properties allow out-of-bounds array access and memory corruption.
- [High] Unconditional hardware state reset clobbers interrupt states and wait bases for unowned syncpoints.
--
commit bdd04d3945b8f8760d8be70ce0ab1595927b08f4
Author: Mikko Perttunen <mperttunen@nvidia.com>
gpu: host1x: Allow limiting usable channel and syncpoint ranges
Allow specifying usable channel, and allocatable syncpoint ranges
through the device tree. This is necessary when Host1x resources
are shared between multiple operating systems or independent hardware
units and Linux has limited access to them.
> diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c
> index ca5d0f51cf7da..38fcdda8388ad 100644
> --- a/drivers/gpu/host1x/channel.c
> +++ b/drivers/gpu/host1x/channel.c
> @@ -121,13 +121,13 @@ EXPORT_SYMBOL(host1x_channel_put);
> static struct host1x_channel *acquire_unused_channel(struct host1x *host)
> {
> struct host1x_channel_list *chlist = &host->channel_list;
> - unsigned int max_channels = host->info->nb_channels;
> unsigned int index;
>
> mutex_lock(&chlist->lock);
>
> - index = find_first_zero_bit(chlist->allocated_channels, max_channels);
> - if (index >= max_channels) {
> + index = find_next_zero_bit(chlist->allocated_channels,
> + host->channel_end, host->channel_base);
[Severity: High]
Does this code allow out-of-bounds memory accesses if the device tree values
exceed the hardware limits?
Since chlist->channels and chlist->allocated_channels are allocated based on
host->info->nb_channels, could a large value in the nvidia,channels device
tree property cause an out-of-bounds access here when host->channel_end is
passed to find_next_zero_bit()? Should host->channel_end be validated
in host1x_get_assigned_resources()?
[ ... ]
> diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
> index 545fa2e3f180c..7103f018cb1bf 100644
> --- a/drivers/gpu/host1x/dev.c
> +++ b/drivers/gpu/host1x/dev.c
> @@ -331,6 +331,39 @@ static void host1x_setup_virtualization_tables(struct host1x *host)
> }
> }
>
> +static int host1x_get_assigned_resources(struct host1x *host)
> +{
> + struct device_node *np = host->dev->of_node;
> + u32 vals[2];
> + int err;
> +
> + err = of_property_read_u32_array(np, "nvidia,channels", vals, 2);
> + if (err == 0) {
> + host->channel_base = vals[0];
> + host->channel_end = vals[0] + vals[1];
> + } else if (err == -EINVAL) {
> + host->channel_base = 0;
> + host->channel_end = host->info->nb_channels;
> + } else {
> + dev_err(host->dev, "invalid nvidia,channels property: %d\n", err);
> + return err;
> + }
> +
> + err = of_property_read_u32_array(np, "nvidia,syncpoints", vals, 2);
> + if (err == 0) {
> + host->syncpt_base = vals[0];
> + host->syncpt_end = vals[0] + vals[1];
[Severity: High]
Similarly, could large values for nvidia,syncpoints cause out-of-bounds reads
and writes?
Arrays like host->syncpt are allocated based on host->info->nb_pts.
If host->syncpt_end exceeds this limit without validation, functions like
host1x_syncpt_alloc() that iterate up to host->syncpt_end might access
memory out of bounds.
[ ... ]
> diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c
> index acc7d82e0585e..fe27a386cc0c8 100644
> --- a/drivers/gpu/host1x/syncpt.c
> +++ b/drivers/gpu/host1x/syncpt.c
[ ... ]
> @@ -138,7 +138,7 @@ void host1x_syncpt_restore(struct host1x *host)
> struct host1x_syncpt *sp_base = host->syncpt;
> unsigned int i;
>
> - for (i = 0; i < host1x_syncpt_nb_pts(host); i++) {
> + for (i = host->syncpt_base; i < host->syncpt_end; i++) {
> /*
> * Unassign syncpt from channels for purposes of Tegra186
> * syncpoint protection. This prevents any channel from
[Severity: High]
Does this clobber the hardware state for unowned syncpoints?
Right after this loop, the code in host1x_syncpt_restore() unconditionally
restores wait bases for syncpoints 0 to nb_bases-1:
for (i = 0; i < host1x_syncpt_nb_bases(host); i++)
host1x_hw_syncpt_restore_wait_base(host, sp_base + i);
Similarly, host1x_intr_disable_all_syncpt_intrs() unconditionally disables and
clears threshold interrupts for all syncpoints across the entire hardware.
Since this patch restricts Linux to a specific range of syncpoints to allow
sharing the Host1x device, will overwriting the wait bases and interrupt states
unconditionally break synchronization for other operating systems or hardware
units sharing the device?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-host1x-nohv-v1-0-65bc682a617f@nvidia.com?part=4
^ permalink raw reply
* Re: [PATCH v2 3/3] watchdog: npcm: add bootstatus support
From: sashiko-bot @ 2026-06-22 8:42 UTC (permalink / raw)
To: Tomer Maimon; +Cc: devicetree, robh, conor+dt, linux-watchdog
In-Reply-To: <20260622083046.3189603-4-tmaimon77@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The first watchdog instance on NPCM750 clears the global RESSR register without caching it, causing subsequent watchdog instances to permanently lose their reset status.
- [High] Non-atomic read-modify-write of the shared INTCR2 register clobbers concurrent modifications and incorrectly handles W1C semantics.
--
commit dafe1267618ef0158376caf5f3acee9d7fe7b1b7
Author: Tomer Maimon <tmaimon77@gmail.com>
watchdog: npcm: add bootstatus support
The NPCM750 uses RESSR and the NPCM845 uses INTCR2 to latch reset
indications. Read those bits during probe and map them into watchdog
bootstatus flags.
> diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
> index e62ea054bc618..98660419ec3f0 100644
> --- a/drivers/watchdog/npcm_wdt.c
> +++ b/drivers/watchdog/npcm_wdt.c
[ ... ]
> @@ -169,6 +250,92 @@ static bool npcm_is_running(struct watchdog_device *wdd)
> return readl(wdt->reg) & NPCM_WTE;
> }
>
> +static void npcm_get_reset_status(struct npcm_wdt *wdt, struct device *dev,
> + const struct npcm_wdt_data *data,
> + resource_size_t start)
> +{
[ ... ]
> + if (of_device_is_compatible(dev->of_node, "nuvoton,npcm845-wdt")) {
> + ret = regmap_read(gcr_regmap, NPCM_INTCR2_OFFSET, &rstval);
> + if (ret) {
> + dev_warn(dev, "Failed to read INTCR2 reset status: %d\n",
> + ret);
> + return;
> + }
> +
> + if (rstval & NPCM8XX_RST) {
> + ret = regmap_write(gcr_regmap, NPCM_INTCR2_OFFSET,
> + rstval & ~NPCM8XX_RST);
[Severity: High]
Does this non-atomic read-modify-write risk clobbering concurrent modifications
to the shared INTCR2 register?
Since INTCR2 is a shared global control register accessed by multiple drivers,
using regmap_read() followed by regmap_write() drops the regmap lock between
operations. Any concurrent modifications to INTCR2 by other drivers could be
overwritten.
Also, if INTCR2 contains Write-1-to-Clear (W1C) status bits, writing
`rstval & ~NPCM8XX_RST` might incorrectly write 1s to all other active bits
(clearing them) and 0s to the watchdog bits.
Could regmap_update_bits() or a W1C-safe write be used here instead?
> + if (ret) {
> + dev_warn(dev,
> + "Failed to clear INTCR2 reset status: %d\n",
> + ret);
> + return;
> + }
[ ... ]
> + }
> + } else if (of_device_is_compatible(dev->of_node, "nuvoton,npcm750-wdt")) {
> + ret = regmap_read(gcr_regmap, NPCM_RESSR_OFFSET, &rstval);
> + if (ret) {
> + dev_warn(dev, "Failed to read RESSR reset status: %d\n",
> + ret);
> + return;
> + }
> +
> + ret = regmap_write(gcr_regmap, NPCM_RESSR_OFFSET, rstval);
[Severity: High]
Will the first watchdog instance on NPCM750 clear the global RESSR register
without caching it, causing subsequent instances to lose their reset status?
The NPCM750 SoC has three watchdog instances that share the global RESSR
register. When the first watchdog probes, it reads RESSR and immediately
clears it by writing the value back. Because the value is not cached
(unlike the SCRPAD10 mechanism used for NPCM845), when the remaining
watchdogs probe, they will read 0 from RESSR and permanently lose their
boot status indications.
> + if (ret) {
> + dev_warn(dev, "Failed to clear RESSR reset status: %d\n",
> + ret);
> + return;
> + }
> + }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622083046.3189603-1-tmaimon77@gmail.com?part=3
^ permalink raw reply
* Re: [PATCH v7 18/22] RISC-V: perf: Add Qemu virt machine events
From: sashiko-bot @ 2026-06-22 8:39 UTC (permalink / raw)
To: Atish Patra; +Cc: robh, linux-perf-users, devicetree, conor+dt
In-Reply-To: <20260622-counter_delegation-v7-18-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Using mvendorid=0, marchid=0, and mimpid=0 to uniquely identify QEMU virt incorrectly hijacks PMU event mappings for all non-commercial RISC-V cores.
--
commit 6c37953807499d33e32d891aa7fbc5980f5e88bb
Author: Atish Patra <atishp@rivosinc.com>
Subject: RISC-V: perf: Add Qemu virt machine events
This commit adds a set of legacy perf events for the Qemu virt machine to
the vendor table, allowing users to use them when counter delegation is
enabled.
> diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h
> --- a/arch/riscv/include/asm/vendorid_list.h
> +++ b/arch/riscv/include/asm/vendorid_list.h
> @@ -11,4 +11,8 @@
> #define SIFIVE_VENDOR_ID 0x489
> #define THEAD_VENDOR_ID 0x5b7
>
> +#define QEMU_VIRT_VENDOR_ID 0x000
> +#define QEMU_VIRT_IMPL_ID 0x000
> +#define QEMU_VIRT_ARCH_ID 0x000
[ ... ]
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
[ ... ]
> static struct riscv_vendor_pmu_events pmu_vendor_events_table[] = {
> + RISCV_VENDOR_PMU_EVENTS(QEMU_VIRT_VENDOR_ID, QEMU_VIRT_ARCH_ID, QEMU_VIRT_IMPL_ID,
> + qemu_virt_hw_event_map, qemu_virt_cache_event_map,
> + qemu_virt_event_group)
> };
[Severity: High]
Will this apply QEMU's limited PMU mappings to all non-commercial
implementations?
The RISC-V privileged specification defines mvendorid=0, marchid=0, and
mimpid=0 as indicating a non-commercial implementation or that the field
is unimplemented. Academic cores and FPGA soft-cores (like BOOM or CVA6)
legitimately return 0 for these IDs.
Registering QEMU's specific legacy PMU event encodings against these generic
0x000 IDs could incorrectly apply them to actual physical hardware that
implements counter delegation. This might force compliant open-source cores
to be restricted to QEMU's limited 5-event map, and write QEMU's raw event
encodings to physical cores' mhpmeventX CSRs, potentially causing silent
measurement corruption or illegal instruction traps.
Would it be safer to identify QEMU virt via device tree machine compat
strings instead, such as checking of_machine_is_compatible("qemu,riscv-virt")?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=18
^ permalink raw reply
* [PATCH v3 2/2] pinctrl: qcom: Add the tlmm driver for Maili platform
From: Jingyi Wang @ 2026-06-22 8:35 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: aiqun.yu, tingwei.zhang, trilok.soni, yijie.yang, linux-arm-msm,
linux-gpio, devicetree, linux-kernel, Jingyi Wang,
Dmitry Baryshkov, Konrad Dybcio
In-Reply-To: <20260622-maili-pinctrl-v3-0-9724e1000471@oss.qualcomm.com>
Add support for Maili TLMM configuration and control via the pinctrl
framework.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Signed-off-by: Jingyi Wang <jingyi.wang@oss.qualcomm.com>
---
drivers/pinctrl/qcom/Kconfig.msm | 10 +
drivers/pinctrl/qcom/Makefile | 1 +
drivers/pinctrl/qcom/pinctrl-maili.c | 1625 ++++++++++++++++++++++++++++++++++
3 files changed, 1636 insertions(+)
diff --git a/drivers/pinctrl/qcom/Kconfig.msm b/drivers/pinctrl/qcom/Kconfig.msm
index 9409e678ec6d..42875457b5fc 100644
--- a/drivers/pinctrl/qcom/Kconfig.msm
+++ b/drivers/pinctrl/qcom/Kconfig.msm
@@ -153,6 +153,16 @@ config PINCTRL_KAANAPALI
Qualcomm Technologies Inc TLMM block found on the Qualcomm
Technologies Inc Kaanapali platform.
+config PINCTRL_MAILI
+ tristate "Qualcomm Technologies Inc Maili pin controller driver"
+ depends on ARM64 || COMPILE_TEST
+ default ARCH_QCOM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm Technologies Inc TLMM block found on the Maili platform.
+ Say Y here to compile statically, or M here to compile it as a module.
+ If unsure, say N.
+
config PINCTRL_MSM8226
tristate "Qualcomm 8226 pin controller driver"
depends on ARM || COMPILE_TEST
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 93cc4e7965ca..43ecd246afe8 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_IPQ6018) += pinctrl-ipq6018.o
obj-$(CONFIG_PINCTRL_IPQ9574) += pinctrl-ipq9574.o
obj-$(CONFIG_PINCTRL_IPQ9650) += pinctrl-ipq9650.o
obj-$(CONFIG_PINCTRL_KAANAPALI) += pinctrl-kaanapali.o
+obj-$(CONFIG_PINCTRL_MAILI) += pinctrl-maili.o
obj-$(CONFIG_PINCTRL_MSM8226) += pinctrl-msm8226.o
obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
diff --git a/drivers/pinctrl/qcom/pinctrl-maili.c b/drivers/pinctrl/qcom/pinctrl-maili.c
new file mode 100644
index 000000000000..ffa084cfad64
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-maili.c
@@ -0,0 +1,1625 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-msm.h"
+
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
+ { \
+ .grp = PINCTRL_PINGROUP("gpio" #id, \
+ gpio##id##_pins, \
+ ARRAY_SIZE(gpio##id##_pins)), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9, \
+ msm_mux_##f10, \
+ msm_mux_##f11 /* egpio mode */ \
+ }, \
+ .nfuncs = 12, \
+ .ctl_reg = REG_SIZE * id, \
+ .io_reg = 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = 0x8 + REG_SIZE * id, \
+ .intr_status_reg = 0xc + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .egpio_enable = 12, \
+ .egpio_present = 11, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_wakeup_present_bit = 6, \
+ .intr_wakeup_enable_bit = 7, \
+ .intr_target_bit = 8, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+#define UFS_RESET(pg_name, ctl, io) \
+ { \
+ .grp = PINCTRL_PINGROUP(#pg_name, \
+ pg_name##_pins, \
+ ARRAY_SIZE(pg_name##_pins)), \
+ .ctl_reg = ctl, \
+ .io_reg = io, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = 3, \
+ .drv_bit = 0, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = 0, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+static const struct pinctrl_pin_desc maili_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "GPIO_150"),
+ PINCTRL_PIN(151, "GPIO_151"),
+ PINCTRL_PIN(152, "GPIO_152"),
+ PINCTRL_PIN(153, "GPIO_153"),
+ PINCTRL_PIN(154, "GPIO_154"),
+ PINCTRL_PIN(155, "GPIO_155"),
+ PINCTRL_PIN(156, "GPIO_156"),
+ PINCTRL_PIN(157, "GPIO_157"),
+ PINCTRL_PIN(158, "GPIO_158"),
+ PINCTRL_PIN(159, "GPIO_159"),
+ PINCTRL_PIN(160, "GPIO_160"),
+ PINCTRL_PIN(161, "GPIO_161"),
+ PINCTRL_PIN(162, "GPIO_162"),
+ PINCTRL_PIN(163, "GPIO_163"),
+ PINCTRL_PIN(164, "GPIO_164"),
+ PINCTRL_PIN(165, "GPIO_165"),
+ PINCTRL_PIN(166, "GPIO_166"),
+ PINCTRL_PIN(167, "GPIO_167"),
+ PINCTRL_PIN(168, "GPIO_168"),
+ PINCTRL_PIN(169, "GPIO_169"),
+ PINCTRL_PIN(170, "GPIO_170"),
+ PINCTRL_PIN(171, "GPIO_171"),
+ PINCTRL_PIN(172, "GPIO_172"),
+ PINCTRL_PIN(173, "GPIO_173"),
+ PINCTRL_PIN(174, "GPIO_174"),
+ PINCTRL_PIN(175, "GPIO_175"),
+ PINCTRL_PIN(176, "GPIO_176"),
+ PINCTRL_PIN(177, "GPIO_177"),
+ PINCTRL_PIN(178, "GPIO_178"),
+ PINCTRL_PIN(179, "GPIO_179"),
+ PINCTRL_PIN(180, "GPIO_180"),
+ PINCTRL_PIN(181, "GPIO_181"),
+ PINCTRL_PIN(182, "GPIO_182"),
+ PINCTRL_PIN(183, "GPIO_183"),
+ PINCTRL_PIN(184, "GPIO_184"),
+ PINCTRL_PIN(185, "GPIO_185"),
+ PINCTRL_PIN(186, "GPIO_186"),
+ PINCTRL_PIN(187, "GPIO_187"),
+ PINCTRL_PIN(188, "GPIO_188"),
+ PINCTRL_PIN(189, "GPIO_189"),
+ PINCTRL_PIN(190, "GPIO_190"),
+ PINCTRL_PIN(191, "GPIO_191"),
+ PINCTRL_PIN(192, "GPIO_192"),
+ PINCTRL_PIN(193, "GPIO_193"),
+ PINCTRL_PIN(194, "GPIO_194"),
+ PINCTRL_PIN(195, "GPIO_195"),
+ PINCTRL_PIN(196, "GPIO_196"),
+ PINCTRL_PIN(197, "GPIO_197"),
+ PINCTRL_PIN(198, "GPIO_198"),
+ PINCTRL_PIN(199, "GPIO_199"),
+ PINCTRL_PIN(200, "GPIO_200"),
+ PINCTRL_PIN(201, "GPIO_201"),
+ PINCTRL_PIN(202, "GPIO_202"),
+ PINCTRL_PIN(203, "GPIO_203"),
+ PINCTRL_PIN(204, "GPIO_204"),
+ PINCTRL_PIN(205, "GPIO_205"),
+ PINCTRL_PIN(206, "GPIO_206"),
+ PINCTRL_PIN(207, "GPIO_207"),
+ PINCTRL_PIN(208, "GPIO_208"),
+ PINCTRL_PIN(209, "GPIO_209"),
+ PINCTRL_PIN(210, "GPIO_210"),
+ PINCTRL_PIN(211, "GPIO_211"),
+ PINCTRL_PIN(212, "GPIO_212"),
+ PINCTRL_PIN(213, "GPIO_213"),
+ PINCTRL_PIN(214, "GPIO_214"),
+ PINCTRL_PIN(215, "GPIO_215"),
+ PINCTRL_PIN(216, "GPIO_216"),
+ PINCTRL_PIN(217, "GPIO_217"),
+ PINCTRL_PIN(218, "GPIO_218"),
+ PINCTRL_PIN(219, "GPIO_219"),
+ PINCTRL_PIN(220, "GPIO_220"),
+ PINCTRL_PIN(221, "GPIO_221"),
+ PINCTRL_PIN(222, "GPIO_222"),
+ PINCTRL_PIN(223, "GPIO_223"),
+ PINCTRL_PIN(224, "GPIO_224"),
+ PINCTRL_PIN(225, "GPIO_225"),
+ PINCTRL_PIN(226, "UFS_RESET"),
+ PINCTRL_PIN(227, "SDC2_CLK"),
+ PINCTRL_PIN(228, "SDC2_CMD"),
+ PINCTRL_PIN(229, "SDC2_DATA"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+DECLARE_MSM_GPIO_PINS(150);
+DECLARE_MSM_GPIO_PINS(151);
+DECLARE_MSM_GPIO_PINS(152);
+DECLARE_MSM_GPIO_PINS(153);
+DECLARE_MSM_GPIO_PINS(154);
+DECLARE_MSM_GPIO_PINS(155);
+DECLARE_MSM_GPIO_PINS(156);
+DECLARE_MSM_GPIO_PINS(157);
+DECLARE_MSM_GPIO_PINS(158);
+DECLARE_MSM_GPIO_PINS(159);
+DECLARE_MSM_GPIO_PINS(160);
+DECLARE_MSM_GPIO_PINS(161);
+DECLARE_MSM_GPIO_PINS(162);
+DECLARE_MSM_GPIO_PINS(163);
+DECLARE_MSM_GPIO_PINS(164);
+DECLARE_MSM_GPIO_PINS(165);
+DECLARE_MSM_GPIO_PINS(166);
+DECLARE_MSM_GPIO_PINS(167);
+DECLARE_MSM_GPIO_PINS(168);
+DECLARE_MSM_GPIO_PINS(169);
+DECLARE_MSM_GPIO_PINS(170);
+DECLARE_MSM_GPIO_PINS(171);
+DECLARE_MSM_GPIO_PINS(172);
+DECLARE_MSM_GPIO_PINS(173);
+DECLARE_MSM_GPIO_PINS(174);
+DECLARE_MSM_GPIO_PINS(175);
+DECLARE_MSM_GPIO_PINS(176);
+DECLARE_MSM_GPIO_PINS(177);
+DECLARE_MSM_GPIO_PINS(178);
+DECLARE_MSM_GPIO_PINS(179);
+DECLARE_MSM_GPIO_PINS(180);
+DECLARE_MSM_GPIO_PINS(181);
+DECLARE_MSM_GPIO_PINS(182);
+DECLARE_MSM_GPIO_PINS(183);
+DECLARE_MSM_GPIO_PINS(184);
+DECLARE_MSM_GPIO_PINS(185);
+DECLARE_MSM_GPIO_PINS(186);
+DECLARE_MSM_GPIO_PINS(187);
+DECLARE_MSM_GPIO_PINS(188);
+DECLARE_MSM_GPIO_PINS(189);
+DECLARE_MSM_GPIO_PINS(190);
+DECLARE_MSM_GPIO_PINS(191);
+DECLARE_MSM_GPIO_PINS(192);
+DECLARE_MSM_GPIO_PINS(193);
+DECLARE_MSM_GPIO_PINS(194);
+DECLARE_MSM_GPIO_PINS(195);
+DECLARE_MSM_GPIO_PINS(196);
+DECLARE_MSM_GPIO_PINS(197);
+DECLARE_MSM_GPIO_PINS(198);
+DECLARE_MSM_GPIO_PINS(199);
+DECLARE_MSM_GPIO_PINS(200);
+DECLARE_MSM_GPIO_PINS(201);
+DECLARE_MSM_GPIO_PINS(202);
+DECLARE_MSM_GPIO_PINS(203);
+DECLARE_MSM_GPIO_PINS(204);
+DECLARE_MSM_GPIO_PINS(205);
+DECLARE_MSM_GPIO_PINS(206);
+DECLARE_MSM_GPIO_PINS(207);
+DECLARE_MSM_GPIO_PINS(208);
+DECLARE_MSM_GPIO_PINS(209);
+DECLARE_MSM_GPIO_PINS(210);
+DECLARE_MSM_GPIO_PINS(211);
+DECLARE_MSM_GPIO_PINS(212);
+DECLARE_MSM_GPIO_PINS(213);
+DECLARE_MSM_GPIO_PINS(214);
+DECLARE_MSM_GPIO_PINS(215);
+DECLARE_MSM_GPIO_PINS(216);
+DECLARE_MSM_GPIO_PINS(217);
+DECLARE_MSM_GPIO_PINS(218);
+DECLARE_MSM_GPIO_PINS(219);
+DECLARE_MSM_GPIO_PINS(220);
+DECLARE_MSM_GPIO_PINS(221);
+DECLARE_MSM_GPIO_PINS(222);
+DECLARE_MSM_GPIO_PINS(223);
+DECLARE_MSM_GPIO_PINS(224);
+DECLARE_MSM_GPIO_PINS(225);
+
+static const unsigned int ufs_reset_pins[] = { 226 };
+static const unsigned int sdc2_clk_pins[] = { 227 };
+static const unsigned int sdc2_cmd_pins[] = { 228 };
+static const unsigned int sdc2_data_pins[] = { 229 };
+
+enum maili_functions {
+ msm_mux_gpio,
+ msm_mux_aoss_cti,
+ msm_mux_atest_char,
+ msm_mux_atest_usb,
+ msm_mux_audio_ext_mclk,
+ msm_mux_audio_ref_clk,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async_in,
+ msm_mux_cci_i2c0,
+ msm_mux_cci_i2c1,
+ msm_mux_cci_i2c2,
+ msm_mux_cci_i2c3,
+ msm_mux_cci_timer,
+ msm_mux_coex_espmi,
+ msm_mux_coex_uart1_rx,
+ msm_mux_coex_uart1_tx,
+ msm_mux_dbg_out_clk,
+ msm_mux_ddr_bist,
+ msm_mux_ddr_pxi,
+ msm_mux_dp_hot,
+ msm_mux_egpio,
+ msm_mux_gcc_gp,
+ msm_mux_gnss_adc,
+ msm_mux_host2wlan_sol,
+ msm_mux_host_rst,
+ msm_mux_i2chub0_se0,
+ msm_mux_i2chub0_se1,
+ msm_mux_i2chub0_se2,
+ msm_mux_i2chub0_se3,
+ msm_mux_i2chub0_se4,
+ msm_mux_i2s0,
+ msm_mux_i2s1,
+ msm_mux_ibi_i3c,
+ msm_mux_ibi_i3c_qup5_se0,
+ msm_mux_jitter_bist,
+ msm_mux_mdp_esync0,
+ msm_mux_mdp_esync1,
+ msm_mux_mdp_esync2,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync_e,
+ msm_mux_mdp_vsync_p,
+ msm_mux_mdp_vsync0_out,
+ msm_mux_mdp_vsync1_out,
+ msm_mux_mdp_vsync2_out,
+ msm_mux_mdp_vsync3_out,
+ msm_mux_mdp_vsync5_out,
+ msm_mux_modem_pps_in,
+ msm_mux_modem_pps_out,
+ msm_mux_nav_gpio,
+ msm_mux_nav_gpio0,
+ msm_mux_nav_gpio3,
+ msm_mux_nav_rffe,
+ msm_mux_pcie0_clk_req_n,
+ msm_mux_pcie1_clk_req_n,
+ msm_mux_pcie1_rst_n,
+ msm_mux_phase_flag,
+ msm_mux_pll_bist_sync,
+ msm_mux_pll_clk_aux,
+ msm_mux_qdss_cti,
+ msm_mux_qlink,
+ msm_mux_qspi,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qup1_se0,
+ msm_mux_qup1_se1,
+ msm_mux_qup1_se2,
+ msm_mux_qup1_se3,
+ msm_mux_qup1_se4,
+ msm_mux_qup1_se5,
+ msm_mux_qup1_se6,
+ msm_mux_qup1_se7,
+ msm_mux_qup2_se0,
+ msm_mux_qup2_se1,
+ msm_mux_qup2_se2,
+ msm_mux_qup2_se3,
+ msm_mux_qup2_se4_01,
+ msm_mux_qup2_se4_23,
+ msm_mux_qup3_se0,
+ msm_mux_qup3_se1,
+ msm_mux_qup3_se2,
+ msm_mux_qup3_se3,
+ msm_mux_qup3_se4,
+ msm_mux_qup3_se5,
+ msm_mux_qup4_se0,
+ msm_mux_qup4_se1,
+ msm_mux_qup4_se2,
+ msm_mux_qup4_se3_01,
+ msm_mux_qup4_se3_23,
+ msm_mux_qup4_se3_l3,
+ msm_mux_qup4_se4_01,
+ msm_mux_qup4_se4_23,
+ msm_mux_qup4_se4_l3,
+ msm_mux_qup5_se0,
+ msm_mux_rng_rosc,
+ msm_mux_sd_write_protect,
+ msm_mux_sdc2_clk,
+ msm_mux_sdc2_cmd,
+ msm_mux_sdc2_data,
+ msm_mux_sdc2_rclk,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_sdc4_data,
+ msm_mux_sys_throttle,
+ msm_mux_tb_trig_sdc,
+ msm_mux_tmess_rng,
+ msm_mux_tsense_clm,
+ msm_mux_tsense_pwm,
+ msm_mux_uim0,
+ msm_mux_uim1,
+ msm_mux_usb0_hs,
+ msm_mux_usb_phy,
+ msm_mux_vfr,
+ msm_mux_vsense_trigger_mirnat,
+ msm_mux_wcn_sw,
+ msm_mux__,
+};
+
+static const char *const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5",
+ "gpio6", "gpio7", "gpio8", "gpio9", "gpio10", "gpio11",
+ "gpio12", "gpio13", "gpio14", "gpio15", "gpio16", "gpio17",
+ "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", "gpio23",
+ "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41",
+ "gpio42", "gpio43", "gpio44", "gpio45", "gpio46", "gpio47",
+ "gpio48", "gpio49", "gpio50", "gpio51", "gpio52", "gpio53",
+ "gpio54", "gpio55", "gpio56", "gpio57", "gpio58", "gpio59",
+ "gpio60", "gpio61", "gpio62", "gpio63", "gpio64", "gpio65",
+ "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", "gpio71",
+ "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+ "gpio84", "gpio85", "gpio86", "gpio87", "gpio88", "gpio89",
+ "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95",
+ "gpio96", "gpio97", "gpio98", "gpio99", "gpio100", "gpio101",
+ "gpio102", "gpio103", "gpio104", "gpio105", "gpio106", "gpio107",
+ "gpio108", "gpio109", "gpio110", "gpio111", "gpio112", "gpio113",
+ "gpio114", "gpio115", "gpio116", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+ "gpio126", "gpio127", "gpio128", "gpio129", "gpio130", "gpio131",
+ "gpio132", "gpio133", "gpio134", "gpio135", "gpio136", "gpio137",
+ "gpio138", "gpio139", "gpio140", "gpio141", "gpio142", "gpio143",
+ "gpio144", "gpio145", "gpio146", "gpio147", "gpio148", "gpio149",
+ "gpio150", "gpio151", "gpio152", "gpio153", "gpio154", "gpio155",
+ "gpio156", "gpio157", "gpio158", "gpio159", "gpio160", "gpio161",
+ "gpio162", "gpio163", "gpio164", "gpio165", "gpio166", "gpio167",
+ "gpio168", "gpio169", "gpio170", "gpio171", "gpio172", "gpio173",
+ "gpio174", "gpio175", "gpio176", "gpio177", "gpio178", "gpio179",
+ "gpio180", "gpio181", "gpio182", "gpio183", "gpio184", "gpio185",
+ "gpio186", "gpio187", "gpio188", "gpio189", "gpio190", "gpio191",
+ "gpio192", "gpio193", "gpio194", "gpio195", "gpio196", "gpio197",
+ "gpio198", "gpio199", "gpio200", "gpio201", "gpio202", "gpio203",
+ "gpio204", "gpio205", "gpio206", "gpio207", "gpio208", "gpio209",
+ "gpio210", "gpio211", "gpio212", "gpio213", "gpio214", "gpio215",
+ "gpio216", "gpio217", "gpio218", "gpio219", "gpio220", "gpio221",
+ "gpio222", "gpio223", "gpio224", "gpio225",
+};
+
+static const char *const aoss_cti_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77",
+};
+
+static const char *const atest_char_groups[] = {
+ "gpio126", "gpio127", "gpio128", "gpio129", "gpio133",
+};
+
+static const char *const atest_usb_groups[] = {
+ "gpio78", "gpio79", "gpio102", "gpio103", "gpio104",
+};
+
+static const char *const audio_ext_mclk_groups[] = {
+ "gpio120", "gpio121",
+};
+
+static const char *const audio_ref_clk_groups[] = {
+ "gpio120",
+};
+
+static const char *const cam_mclk_groups[] = {
+ "gpio90", "gpio91", "gpio92", "gpio93", "gpio94", "gpio95",
+};
+
+static const char *const cci_async_in_groups[] = {
+ "gpio15", "gpio109", "gpio110",
+};
+
+static const char *const cci_i2c0_groups[] = {
+ "gpio109", "gpio110",
+};
+
+static const char *const cci_i2c1_groups[] = {
+ "gpio111", "gpio112",
+};
+
+static const char *const cci_i2c2_groups[] = {
+ "gpio113", "gpio114",
+};
+
+static const char *const cci_i2c3_groups[] = {
+ "gpio107", "gpio160",
+};
+
+static const char *const cci_timer_groups[] = {
+ "gpio105", "gpio106", "gpio107", "gpio159", "gpio160",
+};
+
+static const char *const coex_espmi_groups[] = {
+ "gpio144", "gpio145",
+};
+
+static const char *const coex_uart1_rx_groups[] = {
+ "gpio144",
+};
+
+static const char *const coex_uart1_tx_groups[] = {
+ "gpio145",
+};
+
+static const char *const dbg_out_clk_groups[] = {
+ "gpio82",
+};
+
+static const char *const ddr_bist_groups[] = {
+ "gpio40", "gpio41", "gpio44", "gpio45",
+};
+
+static const char *const ddr_pxi_groups[] = {
+ "gpio66", "gpio67", "gpio68", "gpio69", "gpio70", "gpio71", "gpio72", "gpio73",
+};
+
+static const char *const dp_hot_groups[] = {
+ "gpio47",
+};
+
+static const char *const egpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5",
+ "gpio6", "gpio7", "gpio28", "gpio29", "gpio30", "gpio31",
+ "gpio48", "gpio49", "gpio50", "gpio51", "gpio163", "gpio164",
+ "gpio165", "gpio166", "gpio167", "gpio168", "gpio169", "gpio170",
+ "gpio171", "gpio172", "gpio173", "gpio174", "gpio175", "gpio176",
+ "gpio177", "gpio178", "gpio179", "gpio180", "gpio181", "gpio182",
+ "gpio183", "gpio184", "gpio185", "gpio186", "gpio187", "gpio188",
+ "gpio189", "gpio190", "gpio191", "gpio192", "gpio193", "gpio194",
+ "gpio195", "gpio196", "gpio197", "gpio198", "gpio199", "gpio200",
+ "gpio201", "gpio202", "gpio203", "gpio204", "gpio205", "gpio206",
+ "gpio207", "gpio208", "gpio209", "gpio212", "gpio213", "gpio214",
+ "gpio215", "gpio216", "gpio217", "gpio218",
+};
+
+static const char *const gcc_gp_groups[] = {
+ "gpio17", "gpio86", "gpio87", "gpio97", "gpio155", "gpio156",
+};
+
+static const char *const gnss_adc_groups[] = {
+ "gpio18", "gpio19", "gpio20", "gpio23",
+};
+
+static const char *const host2wlan_sol_groups[] = {
+ "gpio204",
+};
+
+static const char *const host_rst_groups[] = {
+ "gpio106",
+};
+
+static const char *const i2chub0_se0_groups[] = {
+ "gpio66", "gpio67",
+};
+
+static const char *const i2chub0_se1_groups[] = {
+ "gpio78", "gpio79",
+};
+
+static const char *const i2chub0_se2_groups[] = {
+ "gpio68", "gpio69",
+};
+
+static const char *const i2chub0_se3_groups[] = {
+ "gpio70", "gpio71",
+};
+
+static const char *const i2chub0_se4_groups[] = {
+ "gpio72", "gpio73",
+};
+
+static const char *const i2s0_groups[] = {
+ "gpio46", "gpio84", "gpio161", "gpio162",
+};
+
+static const char *const i2s1_groups[] = {
+ "gpio222", "gpio223", "gpio224", "gpio225",
+};
+
+static const char *const ibi_i3c_groups[] = {
+ "gpio0", "gpio1", "gpio4", "gpio5", "gpio8", "gpio9",
+ "gpio12", "gpio13", "gpio24", "gpio25", "gpio28", "gpio29",
+ "gpio32", "gpio33", "gpio36", "gpio37", "gpio48", "gpio49",
+ "gpio60", "gpio61", "gpio64", "gpio65", "gpio85", "gpio89",
+ "gpio117", "gpio118",
+};
+
+static const char *const ibi_i3c_qup5_se0_groups[] = {
+ "gpio8", "gpio9",
+};
+
+static const char *const jitter_bist_groups[] = {
+ "gpio73",
+};
+
+static const char *const mdp_esync0_groups[] = {
+ "gpio88", "gpio100",
+};
+
+static const char *const mdp_esync1_groups[] = {
+ "gpio86", "gpio100",
+};
+
+static const char *const mdp_esync2_groups[] = {
+ "gpio87", "gpio97",
+};
+
+static const char *const mdp_vsync_groups[] = {
+ "gpio86", "gpio87", "gpio88", "gpio97",
+};
+
+static const char *const mdp_vsync_e_groups[] = {
+ "gpio98",
+};
+
+static const char *const mdp_vsync_p_groups[] = {
+ "gpio98",
+};
+
+static const char *const mdp_vsync0_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync1_out_groups[] = {
+ "gpio86",
+};
+
+static const char *const mdp_vsync2_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync3_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const mdp_vsync5_out_groups[] = {
+ "gpio87",
+};
+
+static const char *const modem_pps_in_groups[] = {
+ "gpio151",
+};
+
+static const char *const modem_pps_out_groups[] = {
+ "gpio151",
+};
+
+static const char *const nav_gpio_groups[] = {
+ "gpio146", "gpio147", "gpio148", "gpio151",
+};
+
+static const char *const nav_gpio0_groups[] = {
+ "gpio150",
+};
+
+static const char *const nav_gpio3_groups[] = {
+ "gpio150",
+};
+
+static const char *const nav_rffe_groups[] = {
+ "gpio134", "gpio135", "gpio138", "gpio139",
+};
+
+static const char *const pcie0_clk_req_n_groups[] = {
+ "gpio103",
+};
+
+static const char *const pcie1_clk_req_n_groups[] = {
+ "gpio221",
+};
+
+static const char *const pcie1_rst_n_groups[] = {
+ "gpio220",
+};
+
+static const char *const phase_flag_groups[] = {
+ "gpio40", "gpio41", "gpio44", "gpio45", "gpio46", "gpio47", "gpio126",
+ "gpio127", "gpio128", "gpio129", "gpio130", "gpio131", "gpio132",
+ "gpio133", "gpio161", "gpio162", "gpio169", "gpio170", "gpio171",
+ "gpio174", "gpio175", "gpio178", "gpio179", "gpio180", "gpio181",
+ "gpio182", "gpio183", "gpio205", "gpio222", "gpio223", "gpio224",
+ "gpio225",
+};
+
+static const char *const pll_bist_sync_groups[] = {
+ "gpio104",
+};
+
+static const char *const pll_clk_aux_groups[] = {
+ "gpio94",
+};
+
+static const char *const qdss_cti_groups[] = {
+ "gpio72", "gpio73", "gpio82", "gpio83", "gpio222", "gpio223",
+ "gpio224", "gpio225",
+};
+
+static const char *const qlink_groups[] = {
+ "gpio152", "gpio153", "gpio154",
+};
+
+static const char *const qspi_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio147",
+};
+
+static const char *const qspi_clk_groups[] = {
+ "gpio83",
+};
+
+static const char *const qspi_cs_groups[] = {
+ "gpio146", "gpio148",
+};
+
+static const char *const qup1_se0_groups[] = {
+ "gpio222", "gpio223", "gpio224", "gpio225",
+};
+
+static const char *const qup1_se1_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77", "gpio188", "gpio189", "gpio192", "gpio193",
+};
+
+static const char *const qup1_se2_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio130", "gpio131", "gpio132",
+};
+
+static const char *const qup1_se3_groups[] = {
+ "gpio44", "gpio45", "gpio46", "gpio47",
+};
+
+static const char *const qup1_se4_groups[] = {
+ "gpio36", "gpio37", "gpio38", "gpio39",
+};
+
+static const char *const qup1_se5_groups[] = {
+ "gpio52", "gpio53", "gpio54", "gpio55",
+};
+
+static const char *const qup1_se6_groups[] = {
+ "gpio56", "gpio57", "gpio58", "gpio59",
+};
+
+static const char *const qup1_se7_groups[] = {
+ "gpio60", "gpio61", "gpio62", "gpio63",
+};
+
+static const char *const qup2_se0_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+
+static const char *const qup2_se1_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+
+static const char *const qup2_se2_groups[] = {
+ "gpio117", "gpio118", "gpio119", "gpio120",
+};
+
+static const char *const qup2_se3_groups[] = {
+ "gpio97", "gpio122", "gpio123", "gpio124", "gpio125",
+};
+
+static const char *const qup2_se4_01_groups[] = {
+ "gpio208", "gpio209",
+};
+
+static const char *const qup2_se4_23_groups[] = {
+ "gpio208", "gpio209",
+};
+
+static const char *const qup3_se0_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio82", "gpio83",
+};
+
+static const char *const qup3_se1_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio15",
+};
+
+static const char *const qup3_se2_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15",
+};
+
+static const char *const qup3_se3_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19",
+};
+
+static const char *const qup3_se4_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23",
+};
+
+static const char *const qup3_se5_groups[] = {
+ "gpio24", "gpio25", "gpio26", "gpio27",
+};
+
+static const char *const qup4_se0_groups[] = {
+ "gpio48", "gpio49", "gpio50", "gpio51",
+};
+
+static const char *const qup4_se1_groups[] = {
+ "gpio28", "gpio29", "gpio30", "gpio31",
+};
+
+static const char *const qup4_se2_groups[] = {
+ "gpio32", "gpio33", "gpio34", "gpio35",
+};
+
+static const char *const qup4_se3_01_groups[] = {
+ "gpio84", "gpio121",
+};
+
+static const char *const qup4_se3_23_groups[] = {
+ "gpio84", "gpio121",
+};
+
+static const char *const qup4_se3_l3_groups[] = {
+ "gpio98",
+};
+
+static const char *const qup4_se4_01_groups[] = {
+ "gpio161", "gpio162",
+};
+
+static const char *const qup4_se4_23_groups[] = {
+ "gpio161", "gpio162",
+};
+
+static const char *const qup4_se4_l3_groups[] = {
+ "gpio88",
+};
+
+static const char *const qup5_se0_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio16", "gpio17", "gpio85", "gpio89", "gpio100", "gpio214", "gpio215",
+};
+
+static const char *const rng_rosc_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio84",
+};
+
+static const char *const sd_write_protect_groups[] = {
+ "gpio85",
+};
+
+static const char *const sdc2_clk_groups[] = {
+ "gpio56",
+};
+
+static const char *const sdc2_cmd_groups[] = {
+ "gpio57",
+};
+
+static const char *const sdc2_data_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77",
+};
+
+static const char *const sdc2_rclk_groups[] = {
+ "gpio54",
+};
+
+static const char *const sdc4_clk_groups[] = {
+ "gpio83",
+};
+
+static const char *const sdc4_cmd_groups[] = {
+ "gpio148",
+};
+
+static const char *const sdc4_data_groups[] = {
+ "gpio80", "gpio81", "gpio82", "gpio147",
+};
+
+static const char *const sys_throttle_groups[] = {
+ "gpio99",
+};
+
+static const char *const tb_trig_sdc_groups[] = {
+ "gpio88", "gpio146",
+};
+
+static const char *const tmess_rng_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio84",
+};
+
+static const char *const tsense_clm_groups[] = {
+ "gpio87", "gpio97", "gpio98", "gpio99", "gpio105", "gpio106",
+ "gpio159",
+};
+
+static const char *const tsense_pwm_groups[] = {
+ "gpio35", "gpio38", "gpio58", "gpio87", "gpio97", "gpio98", "gpio99",
+};
+
+static const char *const uim0_groups[] = {
+ "gpio126", "gpio127", "gpio128", "gpio129",
+};
+
+static const char *const uim1_groups[] = {
+ "gpio36", "gpio37", "gpio39", "gpio54", "gpio55", "gpio56", "gpio70",
+ "gpio71", "gpio72", "gpio130", "gpio131", "gpio132", "gpio133",
+};
+
+static const char *const usb0_hs_groups[] = {
+ "gpio79",
+};
+
+static const char *const usb_phy_groups[] = {
+ "gpio59", "gpio60",
+};
+
+static const char *const vfr_groups[] = {
+ "gpio146", "gpio151",
+};
+
+static const char *const vsense_trigger_mirnat_groups[] = {
+ "gpio16",
+};
+
+static const char *const wcn_sw_groups[] = {
+ "gpio18", "gpio19", "gpio155", "gpio156",
+};
+
+static const struct pinfunction maili_functions[] = {
+ MSM_GPIO_PIN_FUNCTION(gpio),
+ MSM_PIN_FUNCTION(aoss_cti),
+ MSM_PIN_FUNCTION(atest_char),
+ MSM_PIN_FUNCTION(atest_usb),
+ MSM_PIN_FUNCTION(audio_ext_mclk),
+ MSM_PIN_FUNCTION(audio_ref_clk),
+ MSM_PIN_FUNCTION(cam_mclk),
+ MSM_PIN_FUNCTION(cci_async_in),
+ MSM_PIN_FUNCTION(cci_i2c0),
+ MSM_PIN_FUNCTION(cci_i2c1),
+ MSM_PIN_FUNCTION(cci_i2c2),
+ MSM_PIN_FUNCTION(cci_i2c3),
+ MSM_PIN_FUNCTION(cci_timer),
+ MSM_PIN_FUNCTION(coex_espmi),
+ MSM_PIN_FUNCTION(coex_uart1_rx),
+ MSM_PIN_FUNCTION(coex_uart1_tx),
+ MSM_PIN_FUNCTION(dbg_out_clk),
+ MSM_PIN_FUNCTION(ddr_bist),
+ MSM_PIN_FUNCTION(ddr_pxi),
+ MSM_PIN_FUNCTION(dp_hot),
+ MSM_PIN_FUNCTION(egpio),
+ MSM_PIN_FUNCTION(gcc_gp),
+ MSM_PIN_FUNCTION(gnss_adc),
+ MSM_PIN_FUNCTION(host2wlan_sol),
+ MSM_PIN_FUNCTION(host_rst),
+ MSM_PIN_FUNCTION(i2chub0_se0),
+ MSM_PIN_FUNCTION(i2chub0_se1),
+ MSM_PIN_FUNCTION(i2chub0_se2),
+ MSM_PIN_FUNCTION(i2chub0_se3),
+ MSM_PIN_FUNCTION(i2chub0_se4),
+ MSM_PIN_FUNCTION(i2s0),
+ MSM_PIN_FUNCTION(i2s1),
+ MSM_PIN_FUNCTION(ibi_i3c),
+ MSM_PIN_FUNCTION(ibi_i3c_qup5_se0),
+ MSM_PIN_FUNCTION(jitter_bist),
+ MSM_PIN_FUNCTION(mdp_esync0),
+ MSM_PIN_FUNCTION(mdp_esync1),
+ MSM_PIN_FUNCTION(mdp_esync2),
+ MSM_PIN_FUNCTION(mdp_vsync),
+ MSM_PIN_FUNCTION(mdp_vsync_e),
+ MSM_PIN_FUNCTION(mdp_vsync_p),
+ MSM_PIN_FUNCTION(mdp_vsync0_out),
+ MSM_PIN_FUNCTION(mdp_vsync1_out),
+ MSM_PIN_FUNCTION(mdp_vsync2_out),
+ MSM_PIN_FUNCTION(mdp_vsync3_out),
+ MSM_PIN_FUNCTION(mdp_vsync5_out),
+ MSM_PIN_FUNCTION(modem_pps_in),
+ MSM_PIN_FUNCTION(modem_pps_out),
+ MSM_PIN_FUNCTION(nav_gpio),
+ MSM_PIN_FUNCTION(nav_gpio0),
+ MSM_PIN_FUNCTION(nav_gpio3),
+ MSM_PIN_FUNCTION(nav_rffe),
+ MSM_PIN_FUNCTION(pcie0_clk_req_n),
+ MSM_PIN_FUNCTION(pcie1_clk_req_n),
+ MSM_PIN_FUNCTION(pcie1_rst_n),
+ MSM_PIN_FUNCTION(phase_flag),
+ MSM_PIN_FUNCTION(pll_bist_sync),
+ MSM_PIN_FUNCTION(pll_clk_aux),
+ MSM_PIN_FUNCTION(qdss_cti),
+ MSM_PIN_FUNCTION(qlink),
+ MSM_PIN_FUNCTION(qspi),
+ MSM_PIN_FUNCTION(qspi_clk),
+ MSM_PIN_FUNCTION(qspi_cs),
+ MSM_PIN_FUNCTION(qup1_se0),
+ MSM_PIN_FUNCTION(qup1_se1),
+ MSM_PIN_FUNCTION(qup1_se2),
+ MSM_PIN_FUNCTION(qup1_se3),
+ MSM_PIN_FUNCTION(qup1_se4),
+ MSM_PIN_FUNCTION(qup1_se5),
+ MSM_PIN_FUNCTION(qup1_se6),
+ MSM_PIN_FUNCTION(qup1_se7),
+ MSM_PIN_FUNCTION(qup2_se0),
+ MSM_PIN_FUNCTION(qup2_se1),
+ MSM_PIN_FUNCTION(qup2_se2),
+ MSM_PIN_FUNCTION(qup2_se3),
+ MSM_PIN_FUNCTION(qup2_se4_01),
+ MSM_PIN_FUNCTION(qup2_se4_23),
+ MSM_PIN_FUNCTION(qup3_se0),
+ MSM_PIN_FUNCTION(qup3_se1),
+ MSM_PIN_FUNCTION(qup3_se2),
+ MSM_PIN_FUNCTION(qup3_se3),
+ MSM_PIN_FUNCTION(qup3_se4),
+ MSM_PIN_FUNCTION(qup3_se5),
+ MSM_PIN_FUNCTION(qup4_se0),
+ MSM_PIN_FUNCTION(qup4_se1),
+ MSM_PIN_FUNCTION(qup4_se2),
+ MSM_PIN_FUNCTION(qup4_se3_01),
+ MSM_PIN_FUNCTION(qup4_se3_23),
+ MSM_PIN_FUNCTION(qup4_se3_l3),
+ MSM_PIN_FUNCTION(qup4_se4_01),
+ MSM_PIN_FUNCTION(qup4_se4_23),
+ MSM_PIN_FUNCTION(qup4_se4_l3),
+ MSM_PIN_FUNCTION(qup5_se0),
+ MSM_PIN_FUNCTION(rng_rosc),
+ MSM_PIN_FUNCTION(sd_write_protect),
+ MSM_PIN_FUNCTION(sdc2_clk),
+ MSM_PIN_FUNCTION(sdc2_cmd),
+ MSM_PIN_FUNCTION(sdc2_data),
+ MSM_PIN_FUNCTION(sdc2_rclk),
+ MSM_PIN_FUNCTION(sdc4_clk),
+ MSM_PIN_FUNCTION(sdc4_cmd),
+ MSM_PIN_FUNCTION(sdc4_data),
+ MSM_PIN_FUNCTION(sys_throttle),
+ MSM_PIN_FUNCTION(tb_trig_sdc),
+ MSM_PIN_FUNCTION(tmess_rng),
+ MSM_PIN_FUNCTION(tsense_clm),
+ MSM_PIN_FUNCTION(tsense_pwm),
+ MSM_PIN_FUNCTION(uim0),
+ MSM_PIN_FUNCTION(uim1),
+ MSM_PIN_FUNCTION(usb0_hs),
+ MSM_PIN_FUNCTION(usb_phy),
+ MSM_PIN_FUNCTION(vfr),
+ MSM_PIN_FUNCTION(vsense_trigger_mirnat),
+ MSM_PIN_FUNCTION(wcn_sw),
+};
+
+static const struct msm_pingroup maili_groups[] = {
+ [0] = PINGROUP(0, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [1] = PINGROUP(1, qup2_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [2] = PINGROUP(2, qup2_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [3] = PINGROUP(3, qup2_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [4] = PINGROUP(4, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [5] = PINGROUP(5, qup2_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [6] = PINGROUP(6, qup2_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [7] = PINGROUP(7, qup2_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [8] = PINGROUP(8, qup3_se1, ibi_i3c, qup5_se0, ibi_i3c_qup5_se0, _, _, _, _, _, _, _),
+ [9] = PINGROUP(9, qup3_se1, ibi_i3c, qup5_se0, ibi_i3c_qup5_se0, _, _, _, _, _, _, _),
+ [10] = PINGROUP(10, qup3_se1, qup5_se0, _, _, _, _, _, _, _, _, _),
+ [11] = PINGROUP(11, qup3_se1, qup5_se0, _, _, _, _, _, _, _, _, _),
+ [12] = PINGROUP(12, qup3_se2, ibi_i3c, qup3_se1, qup5_se0, _, _, _, _, _, _, _),
+ [13] = PINGROUP(13, qup3_se2, ibi_i3c, qup3_se1, qup5_se0, _, _, _, _, _, _, _),
+ [14] = PINGROUP(14, qup3_se2, qup5_se0, _, _, _, _, _, _, _, _, _),
+ [15] = PINGROUP(15, qup3_se2, cci_async_in, qup3_se1, _, _, _, _, _, _, _, _),
+ [16] = PINGROUP(16, qup3_se3, qup5_se0, _, vsense_trigger_mirnat, _, _, _, _, _, _, _),
+ [17] = PINGROUP(17, qup3_se3, qup5_se0, gcc_gp, _, _, _, _, _, _, _, _),
+ [18] = PINGROUP(18, wcn_sw, qup3_se3, _, gnss_adc, _, _, _, _, _, _, _),
+ [19] = PINGROUP(19, wcn_sw, qup3_se3, _, gnss_adc, _, _, _, _, _, _, _),
+ [20] = PINGROUP(20, qup3_se4, _, gnss_adc, _, _, _, _, _, _, _, _),
+ [21] = PINGROUP(21, qup3_se4, _, _, _, _, _, _, _, _, _, _),
+ [22] = PINGROUP(22, qup3_se4, _, _, _, _, _, _, _, _, _, _),
+ [23] = PINGROUP(23, qup3_se4, _, gnss_adc, _, _, _, _, _, _, _, _),
+ [24] = PINGROUP(24, qup3_se5, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [25] = PINGROUP(25, qup3_se5, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [26] = PINGROUP(26, qup3_se5, _, _, _, _, _, _, _, _, _, _),
+ [27] = PINGROUP(27, qup3_se5, _, _, _, _, _, _, _, _, _, _),
+ [28] = PINGROUP(28, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [29] = PINGROUP(29, qup4_se1, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [30] = PINGROUP(30, qup4_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [31] = PINGROUP(31, qup4_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [32] = PINGROUP(32, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [33] = PINGROUP(33, qup4_se2, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [34] = PINGROUP(34, qup4_se2, _, _, _, _, _, _, _, _, _, _),
+ [35] = PINGROUP(35, qup4_se2, tsense_pwm, _, _, _, _, _, _, _, _, _),
+ [36] = PINGROUP(36, qup1_se4, uim1, ibi_i3c, _, _, _, _, _, _, _, _),
+ [37] = PINGROUP(37, qup1_se4, uim1, ibi_i3c, _, _, _, _, _, _, _, _),
+ [38] = PINGROUP(38, qup1_se4, tsense_pwm, _, _, _, _, _, _, _, _, _),
+ [39] = PINGROUP(39, qup1_se4, uim1, _, _, _, _, _, _, _, _, _),
+ [40] = PINGROUP(40, qup1_se2, ddr_bist, phase_flag, _, _, _, _, _, _, _, _),
+ [41] = PINGROUP(41, qup1_se2, ddr_bist, phase_flag, _, _, _, _, _, _, _, _),
+ [42] = PINGROUP(42, qup1_se2, _, _, _, _, _, _, _, _, _, _),
+ [43] = PINGROUP(43, qup1_se2, _, _, _, _, _, _, _, _, _, _),
+ [44] = PINGROUP(44, qup1_se3, ddr_bist, phase_flag, _, _, _, _, _, _, _, _),
+ [45] = PINGROUP(45, qup1_se3, ddr_bist, phase_flag, _, _, _, _, _, _, _, _),
+ [46] = PINGROUP(46, qup1_se3, i2s0, phase_flag, _, _, _, _, _, _, _, _),
+ [47] = PINGROUP(47, qup1_se3, dp_hot, phase_flag, _, _, _, _, _, _, _, _),
+ [48] = PINGROUP(48, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [49] = PINGROUP(49, qup4_se0, ibi_i3c, _, _, _, _, _, _, _, _, egpio),
+ [50] = PINGROUP(50, qup4_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [51] = PINGROUP(51, qup4_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [52] = PINGROUP(52, qup1_se5, _, _, _, _, _, _, _, _, _, _),
+ [53] = PINGROUP(53, qup1_se5, _, _, _, _, _, _, _, _, _, _),
+ [54] = PINGROUP(54, qup1_se5, uim1, sdc2_rclk, _, _, _, _, _, _, _, _),
+ [55] = PINGROUP(55, qup1_se5, uim1, _, _, _, _, _, _, _, _, _),
+ [56] = PINGROUP(56, qup1_se6, uim1, sdc2_clk, _, _, _, _, _, _, _, _),
+ [57] = PINGROUP(57, qup1_se6, sdc2_cmd, _, _, _, _, _, _, _, _, _),
+ [58] = PINGROUP(58, qup1_se6, tsense_pwm, _, _, _, _, _, _, _, _, _),
+ [59] = PINGROUP(59, qup1_se6, usb_phy, _, _, _, _, _, _, _, _, _),
+ [60] = PINGROUP(60, qup1_se7, usb_phy, ibi_i3c, _, _, _, _, _, _, _, _),
+ [61] = PINGROUP(61, qup1_se7, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [62] = PINGROUP(62, qup1_se7, _, _, _, _, _, _, _, _, _, _),
+ [63] = PINGROUP(63, qup1_se7, _, _, _, _, _, _, _, _, _, _),
+ [64] = PINGROUP(64, qup3_se0, rng_rosc, tmess_rng, ibi_i3c, _, _, _, _, _, _, _),
+ [65] = PINGROUP(65, qup3_se0, rng_rosc, tmess_rng, ibi_i3c, _, _, _, _, _, _, _),
+ [66] = PINGROUP(66, i2chub0_se0, qup3_se0, rng_rosc, tmess_rng, _, ddr_pxi, _, _, _, _, _),
+ [67] = PINGROUP(67, i2chub0_se0, qup3_se0, _, ddr_pxi, _, _, _, _, _, _, _),
+ [68] = PINGROUP(68, i2chub0_se2, _, ddr_pxi, _, _, _, _, _, _, _, _),
+ [69] = PINGROUP(69, i2chub0_se2, _, ddr_pxi, _, _, _, _, _, _, _, _),
+ [70] = PINGROUP(70, i2chub0_se3, uim1, _, _, ddr_pxi, _, _, _, _, _, _),
+ [71] = PINGROUP(71, i2chub0_se3, uim1, _, _, ddr_pxi, _, _, _, _, _, _),
+ [72] = PINGROUP(72, i2chub0_se4, uim1, qdss_cti, _, ddr_pxi, _, _, _, _, _, _),
+ [73] = PINGROUP(73, i2chub0_se4, qdss_cti, jitter_bist, ddr_pxi, _, _, _, _, _, _, _),
+ [74] = PINGROUP(74, qup1_se1, aoss_cti, sdc2_data, _, _, _, _, _, _, _, _),
+ [75] = PINGROUP(75, qup1_se1, aoss_cti, sdc2_data, _, _, _, _, _, _, _, _),
+ [76] = PINGROUP(76, qup1_se1, aoss_cti, sdc2_data, _, _, _, _, _, _, _, _),
+ [77] = PINGROUP(77, qup1_se1, aoss_cti, sdc2_data, _, _, _, _, _, _, _, _),
+ [78] = PINGROUP(78, i2chub0_se1, _, atest_usb, _, _, _, _, _, _, _, _),
+ [79] = PINGROUP(79, i2chub0_se1, usb0_hs, _, atest_usb, _, _, _, _, _, _, _),
+ [80] = PINGROUP(80, sdc4_data, qspi, _, _, _, _, _, _, _, _, _),
+ [81] = PINGROUP(81, sdc4_data, qspi, _, _, _, _, _, _, _, _, _),
+ [82] = PINGROUP(82, sdc4_data, qdss_cti, qspi, qup3_se0, dbg_out_clk, _, _, _, _, _, _),
+ [83] = PINGROUP(83, sdc4_clk, qdss_cti, qspi_clk, qup3_se0, _, _, _, _, _, _, _),
+ [84] = PINGROUP(84, qup4_se3_01, qup4_se3_23, rng_rosc, tmess_rng, i2s0, _, _, _, _, _, _),
+ [85] = PINGROUP(85, sd_write_protect, qup5_se0, ibi_i3c, _, _, _, _, _, _, _, _),
+ [86] = PINGROUP(86, mdp_vsync, mdp_vsync0_out, mdp_vsync1_out, mdp_esync1, gcc_gp,
+ _, _, _, _, _, _),
+ [87] = PINGROUP(87, mdp_vsync, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out, mdp_esync2,
+ gcc_gp, tsense_clm, tsense_pwm, _, _, _),
+ [88] = PINGROUP(88, mdp_esync0, mdp_vsync, qup4_se4_l3, tb_trig_sdc, _, _, _, _, _, _, _),
+ [89] = PINGROUP(89, qup5_se0, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [90] = PINGROUP(90, cam_mclk, _, _, _, _, _, _, _, _, _, _),
+ [91] = PINGROUP(91, cam_mclk, _, _, _, _, _, _, _, _, _, _),
+ [92] = PINGROUP(92, cam_mclk, _, _, _, _, _, _, _, _, _, _),
+ [93] = PINGROUP(93, cam_mclk, _, _, _, _, _, _, _, _, _, _),
+ [94] = PINGROUP(94, cam_mclk, pll_clk_aux, _, _, _, _, _, _, _, _, _),
+ [95] = PINGROUP(95, cam_mclk, _, _, _, _, _, _, _, _, _, _),
+ [96] = PINGROUP(96, _, _, _, _, _, _, _, _, _, _, _),
+ [97] = PINGROUP(97, mdp_esync2, qup2_se3, mdp_vsync, gcc_gp, tsense_clm, tsense_pwm,
+ _, _, _, _, _),
+ [98] = PINGROUP(98, mdp_vsync_e, qup4_se3_l3, mdp_vsync_p, tsense_clm, tsense_pwm,
+ _, _, _, _, _, _),
+ [99] = PINGROUP(99, sys_throttle, tsense_clm, tsense_pwm, _, _, _, _, _, _, _, _),
+ [100] = PINGROUP(100, mdp_esync1, mdp_esync0, qup5_se0, _, _, _, _, _, _, _, _),
+ [101] = PINGROUP(101, _, _, _, _, _, _, _, _, _, _, _),
+ [102] = PINGROUP(102, atest_usb, _, _, _, _, _, _, _, _, _, _),
+ [103] = PINGROUP(103, pcie0_clk_req_n, atest_usb, _, _, _, _, _, _, _, _, _),
+ [104] = PINGROUP(104, pll_bist_sync, atest_usb, _, _, _, _, _, _, _, _, _),
+ [105] = PINGROUP(105, cci_timer, tsense_clm, _, _, _, _, _, _, _, _, _),
+ [106] = PINGROUP(106, host_rst, cci_timer, tsense_clm, _, _, _, _, _, _, _, _),
+ [107] = PINGROUP(107, cci_i2c3, cci_timer, _, _, _, _, _, _, _, _, _),
+ [108] = PINGROUP(108, _, _, _, _, _, _, _, _, _, _, _),
+ [109] = PINGROUP(109, cci_i2c0, cci_async_in, _, _, _, _, _, _, _, _, _),
+ [110] = PINGROUP(110, cci_i2c0, cci_async_in, _, _, _, _, _, _, _, _, _),
+ [111] = PINGROUP(111, cci_i2c1, _, _, _, _, _, _, _, _, _, _),
+ [112] = PINGROUP(112, cci_i2c1, _, _, _, _, _, _, _, _, _, _),
+ [113] = PINGROUP(113, cci_i2c2, _, _, _, _, _, _, _, _, _, _),
+ [114] = PINGROUP(114, cci_i2c2, _, _, _, _, _, _, _, _, _, _),
+ [115] = PINGROUP(115, _, _, _, _, _, _, _, _, _, _, _),
+ [116] = PINGROUP(116, _, _, _, _, _, _, _, _, _, _, _),
+ [117] = PINGROUP(117, qup2_se2, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [118] = PINGROUP(118, qup2_se2, ibi_i3c, _, _, _, _, _, _, _, _, _),
+ [119] = PINGROUP(119, qup2_se2, _, _, _, _, _, _, _, _, _, _),
+ [120] = PINGROUP(120, qup2_se2, audio_ext_mclk, audio_ref_clk, _, _, _, _, _, _, _, _),
+ [121] = PINGROUP(121, audio_ext_mclk, qup4_se3_01, qup4_se3_23, _, _, _, _, _, _, _, _),
+ [122] = PINGROUP(122, qup2_se3, _, _, _, _, _, _, _, _, _, _),
+ [123] = PINGROUP(123, qup2_se3, _, _, _, _, _, _, _, _, _, _),
+ [124] = PINGROUP(124, qup2_se3, _, _, _, _, _, _, _, _, _, _),
+ [125] = PINGROUP(125, qup2_se3, _, _, _, _, _, _, _, _, _, _),
+ [126] = PINGROUP(126, uim0, phase_flag, _, atest_char, _, _, _, _, _, _, _),
+ [127] = PINGROUP(127, uim0, phase_flag, _, atest_char, _, _, _, _, _, _, _),
+ [128] = PINGROUP(128, uim0, phase_flag, _, atest_char, _, _, _, _, _, _, _),
+ [129] = PINGROUP(129, uim0, phase_flag, _, atest_char, _, _, _, _, _, _, _),
+ [130] = PINGROUP(130, uim1, qup1_se2, _, phase_flag, _, _, _, _, _, _, _),
+ [131] = PINGROUP(131, uim1, qup1_se2, _, phase_flag, _, _, _, _, _, _, _),
+ [132] = PINGROUP(132, uim1, qup1_se2, _, phase_flag, _, _, _, _, _, _, _),
+ [133] = PINGROUP(133, uim1, phase_flag, _, atest_char, _, _, _, _, _, _, _),
+ [134] = PINGROUP(134, _, _, nav_rffe, _, _, _, _, _, _, _, _),
+ [135] = PINGROUP(135, _, _, nav_rffe, _, _, _, _, _, _, _, _),
+ [136] = PINGROUP(136, _, _, _, _, _, _, _, _, _, _, _),
+ [137] = PINGROUP(137, _, _, _, _, _, _, _, _, _, _, _),
+ [138] = PINGROUP(138, _, _, nav_rffe, _, _, _, _, _, _, _, _),
+ [139] = PINGROUP(139, _, _, nav_rffe, _, _, _, _, _, _, _, _),
+ [140] = PINGROUP(140, _, _, _, _, _, _, _, _, _, _, _),
+ [141] = PINGROUP(141, _, _, _, _, _, _, _, _, _, _, _),
+ [142] = PINGROUP(142, _, _, _, _, _, _, _, _, _, _, _),
+ [143] = PINGROUP(143, _, _, _, _, _, _, _, _, _, _, _),
+ [144] = PINGROUP(144, coex_uart1_rx, coex_espmi, _, _, _, _, _, _, _, _, _),
+ [145] = PINGROUP(145, coex_uart1_tx, coex_espmi, _, _, _, _, _, _, _, _, _),
+ [146] = PINGROUP(146, _, vfr, nav_gpio, tb_trig_sdc, qspi_cs, _, _, _, _, _, _),
+ [147] = PINGROUP(147, _, nav_gpio, sdc4_data, qspi, _, _, _, _, _, _, _),
+ [148] = PINGROUP(148, nav_gpio, _, sdc4_cmd, qspi_cs, _, _, _, _, _, _, _),
+ [149] = PINGROUP(149, _, _, _, _, _, _, _, _, _, _, _),
+ [150] = PINGROUP(150, nav_gpio0, nav_gpio3, _, _, _, _, _, _, _, _, _),
+ [151] = PINGROUP(151, nav_gpio, vfr, modem_pps_in, modem_pps_out, _, _, _, _, _, _, _),
+ [152] = PINGROUP(152, qlink, _, _, _, _, _, _, _, _, _, _),
+ [153] = PINGROUP(153, qlink, _, _, _, _, _, _, _, _, _, _),
+ [154] = PINGROUP(154, qlink, _, _, _, _, _, _, _, _, _, _),
+ [155] = PINGROUP(155, wcn_sw, gcc_gp, _, _, _, _, _, _, _, _, _),
+ [156] = PINGROUP(156, wcn_sw, gcc_gp, _, _, _, _, _, _, _, _, _),
+ [157] = PINGROUP(157, _, _, _, _, _, _, _, _, _, _, _),
+ [158] = PINGROUP(158, _, _, _, _, _, _, _, _, _, _, _),
+ [159] = PINGROUP(159, cci_timer, tsense_clm, _, _, _, _, _, _, _, _, _),
+ [160] = PINGROUP(160, cci_timer, cci_i2c3, _, _, _, _, _, _, _, _, _),
+ [161] = PINGROUP(161, qup4_se4_01, qup4_se4_23, i2s0, phase_flag, _, _, _, _, _, _, _),
+ [162] = PINGROUP(162, qup4_se4_01, qup4_se4_23, i2s0, phase_flag, _, _, _, _, _, _, _),
+ [163] = PINGROUP(163, _, _, _, _, _, _, _, _, _, _, egpio),
+ [164] = PINGROUP(164, _, _, _, _, _, _, _, _, _, _, egpio),
+ [165] = PINGROUP(165, _, _, _, _, _, _, _, _, _, _, egpio),
+ [166] = PINGROUP(166, _, _, _, _, _, _, _, _, _, _, egpio),
+ [167] = PINGROUP(167, _, _, _, _, _, _, _, _, _, _, egpio),
+ [168] = PINGROUP(168, _, _, _, _, _, _, _, _, _, _, egpio),
+ [169] = PINGROUP(169, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [170] = PINGROUP(170, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [171] = PINGROUP(171, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [172] = PINGROUP(172, _, _, _, _, _, _, _, _, _, _, egpio),
+ [173] = PINGROUP(173, _, _, _, _, _, _, _, _, _, _, egpio),
+ [174] = PINGROUP(174, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [175] = PINGROUP(175, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [176] = PINGROUP(176, _, _, _, _, _, _, _, _, _, _, egpio),
+ [177] = PINGROUP(177, _, _, _, _, _, _, _, _, _, _, egpio),
+ [178] = PINGROUP(178, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [179] = PINGROUP(179, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [180] = PINGROUP(180, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [181] = PINGROUP(181, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [182] = PINGROUP(182, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [183] = PINGROUP(183, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [184] = PINGROUP(184, _, _, _, _, _, _, _, _, _, _, egpio),
+ [185] = PINGROUP(185, _, _, _, _, _, _, _, _, _, _, egpio),
+ [186] = PINGROUP(186, _, _, _, _, _, _, _, _, _, _, egpio),
+ [187] = PINGROUP(187, _, _, _, _, _, _, _, _, _, _, egpio),
+ [188] = PINGROUP(188, qup1_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [189] = PINGROUP(189, qup1_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [190] = PINGROUP(190, _, _, _, _, _, _, _, _, _, _, egpio),
+ [191] = PINGROUP(191, _, _, _, _, _, _, _, _, _, _, egpio),
+ [192] = PINGROUP(192, qup1_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [193] = PINGROUP(193, qup1_se1, _, _, _, _, _, _, _, _, _, egpio),
+ [194] = PINGROUP(194, _, _, _, _, _, _, _, _, _, _, egpio),
+ [195] = PINGROUP(195, _, _, _, _, _, _, _, _, _, _, egpio),
+ [196] = PINGROUP(196, _, _, _, _, _, _, _, _, _, _, egpio),
+ [197] = PINGROUP(197, _, _, _, _, _, _, _, _, _, _, egpio),
+ [198] = PINGROUP(198, _, _, _, _, _, _, _, _, _, _, egpio),
+ [199] = PINGROUP(199, _, _, _, _, _, _, _, _, _, _, egpio),
+ [200] = PINGROUP(200, _, _, _, _, _, _, _, _, _, _, egpio),
+ [201] = PINGROUP(201, _, _, _, _, _, _, _, _, _, _, egpio),
+ [202] = PINGROUP(202, _, _, _, _, _, _, _, _, _, _, egpio),
+ [203] = PINGROUP(203, _, _, _, _, _, _, _, _, _, _, egpio),
+ [204] = PINGROUP(204, host2wlan_sol, _, _, _, _, _, _, _, _, _, egpio),
+ [205] = PINGROUP(205, phase_flag, _, _, _, _, _, _, _, _, _, egpio),
+ [206] = PINGROUP(206, _, _, _, _, _, _, _, _, _, _, egpio),
+ [207] = PINGROUP(207, _, _, _, _, _, _, _, _, _, _, egpio),
+ [208] = PINGROUP(208, qup2_se4_01, qup2_se4_23, _, _, _, _, _, _, _, _, egpio),
+ [209] = PINGROUP(209, qup2_se4_01, qup2_se4_23, _, _, _, _, _, _, _, _, egpio),
+ [210] = PINGROUP(210, _, _, _, _, _, _, _, _, _, _, _),
+ [211] = PINGROUP(211, _, _, _, _, _, _, _, _, _, _, _),
+ [212] = PINGROUP(212, _, _, _, _, _, _, _, _, _, _, egpio),
+ [213] = PINGROUP(213, _, _, _, _, _, _, _, _, _, _, egpio),
+ [214] = PINGROUP(214, qup5_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [215] = PINGROUP(215, qup5_se0, _, _, _, _, _, _, _, _, _, egpio),
+ [216] = PINGROUP(216, _, _, _, _, _, _, _, _, _, _, egpio),
+ [217] = PINGROUP(217, _, _, _, _, _, _, _, _, _, _, egpio),
+ [218] = PINGROUP(218, _, _, _, _, _, _, _, _, _, _, egpio),
+ [219] = PINGROUP(219, _, _, _, _, _, _, _, _, _, _, _),
+ [220] = PINGROUP(220, pcie1_rst_n, _, _, _, _, _, _, _, _, _, _),
+ [221] = PINGROUP(221, pcie1_clk_req_n, _, _, _, _, _, _, _, _, _, _),
+ [222] = PINGROUP(222, qup1_se0, i2s1, qdss_cti, phase_flag, _, _, _, _, _, _, _),
+ [223] = PINGROUP(223, qup1_se0, i2s1, qdss_cti, phase_flag, _, _, _, _, _, _, _),
+ [224] = PINGROUP(224, qup1_se0, i2s1, qdss_cti, phase_flag, _, _, _, _, _, _, _),
+ [225] = PINGROUP(225, qup1_se0, i2s1, qdss_cti, phase_flag, _, _, _, _, _, _, _),
+ [226] = UFS_RESET(ufs_reset, 0xf1004, 0xf2000),
+ [227] = SDC_QDSD_PINGROUP(sdc2_clk, 0xe6000, 14, 6),
+ [228] = SDC_QDSD_PINGROUP(sdc2_cmd, 0xe6000, 11, 3),
+ [229] = SDC_QDSD_PINGROUP(sdc2_data, 0xe6000, 9, 0),
+};
+
+static const struct msm_gpio_wakeirq_map maili_pdc_map[] = {
+ { 0, 111 }, { 3, 119 }, { 4, 112 }, { 7, 113 }, { 8, 114 }, { 11, 115 },
+ { 12, 121 }, { 15, 137 }, { 16, 122 }, { 17, 147 }, { 18, 149 }, { 19, 118 },
+ { 23, 123 }, { 24, 124 }, { 27, 125 }, { 28, 131 }, { 31, 132 }, { 32, 133 },
+ { 35, 107 }, { 36, 134 }, { 39, 135 }, { 43, 136 }, { 47, 160 }, { 48, 141 },
+ { 51, 120 }, { 55, 110 }, { 57, 142 }, { 58, 143 }, { 59, 144 }, { 60, 145 },
+ { 61, 151 }, { 63, 130 }, { 64, 116 }, { 65, 129 }, { 67, 138 }, { 68, 152 },
+ { 69, 153 }, { 75, 157 }, { 77, 154 }, { 78, 155 }, { 79, 161 }, { 80, 162 },
+ { 81, 163 }, { 82, 164 }, { 83, 171 }, { 84, 140 }, { 85, 165 }, { 86, 166 },
+ { 87, 167 }, { 88, 168 }, { 95, 169 }, { 96, 170 }, { 97, 139 }, { 98, 156 },
+ { 99, 117 }, { 100, 199 }, { 103, 173 }, { 104, 174 }, { 117, 201 }, { 120, 175 },
+ { 123, 176 }, { 125, 177 }, { 129, 159 }, { 133, 106 }, { 144, 178 }, { 146, 179 },
+ { 151, 180 }, { 152, 181 }, { 155, 128 }, { 158, 126 }, { 162, 148 }, { 164, 182 },
+ { 165, 183 }, { 167, 184 }, { 168, 185 }, { 174, 186 }, { 177, 187 }, { 179, 188 },
+ { 183, 189 }, { 184, 190 }, { 185, 191 }, { 186, 158 }, { 188, 150 }, { 202, 108 },
+ { 203, 109 }, { 205, 146 }, { 209, 192 }, { 213, 127 }, { 215, 200 }, { 216, 193 },
+ { 220, 172 }, { 221, 194 }, { 222, 195 }, { 223, 196 }, { 224, 197 }, { 225, 198 },
+};
+
+static const struct msm_pinctrl_soc_data maili_tlmm = {
+ .pins = maili_pins,
+ .npins = ARRAY_SIZE(maili_pins),
+ .functions = maili_functions,
+ .nfunctions = ARRAY_SIZE(maili_functions),
+ .groups = maili_groups,
+ .ngroups = ARRAY_SIZE(maili_groups),
+ .ngpios = 227,
+ .wakeirq_map = maili_pdc_map,
+ .nwakeirq_map = ARRAY_SIZE(maili_pdc_map),
+ .egpio_func = 11,
+};
+
+static const struct of_device_id maili_tlmm_of_match[] = {
+ { .compatible = "qcom,maili-tlmm", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, maili_tlmm_of_match);
+
+static int maili_tlmm_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &maili_tlmm);
+}
+
+static struct platform_driver maili_tlmm_driver = {
+ .driver = {
+ .name = "maili-tlmm",
+ .of_match_table = maili_tlmm_of_match,
+ },
+ .probe = maili_tlmm_probe,
+};
+
+static int __init maili_tlmm_init(void)
+{
+ return platform_driver_register(&maili_tlmm_driver);
+}
+arch_initcall(maili_tlmm_init);
+
+static void __exit maili_tlmm_exit(void)
+{
+ platform_driver_unregister(&maili_tlmm_driver);
+}
+module_exit(maili_tlmm_exit);
+
+MODULE_DESCRIPTION("Qualcomm Maili TLMM driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: pinctrl: qcom: Describe Maili TLMM block
From: Jingyi Wang @ 2026-06-22 8:35 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: aiqun.yu, tingwei.zhang, trilok.soni, yijie.yang, linux-arm-msm,
linux-gpio, devicetree, linux-kernel, Jingyi Wang,
Krzysztof Kozlowski
In-Reply-To: <20260622-maili-pinctrl-v3-0-9724e1000471@oss.qualcomm.com>
The Top Level Mode Multiplexer (TLMM) in the Qualcomm Maili SoC provides
GPIO and pinctrl functionality for UFS, SDC and 226 GPIO pins.
Add a DeviceTree binding to describe the TLMM block on Qualcomm's Maili
SoC.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Jingyi Wang <jingyi.wang@oss.qualcomm.com>
---
.../bindings/pinctrl/qcom,maili-tlmm.yaml | 120 +++++++++++++++++++++
1 file changed, 120 insertions(+)
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,maili-tlmm.yaml b/Documentation/devicetree/bindings/pinctrl/qcom,maili-tlmm.yaml
new file mode 100644
index 000000000000..64fe90b2391b
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,maili-tlmm.yaml
@@ -0,0 +1,120 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/qcom,maili-tlmm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm Technologies, Inc. Maili TLMM block
+
+maintainers:
+ - Jingyi Wang <jingyi.wang@oss.qualcomm.com>
+
+description:
+ Top Level Mode Multiplexer pin controller in Qualcomm Maili SoC.
+
+allOf:
+ - $ref: /schemas/pinctrl/qcom,tlmm-common.yaml#
+
+properties:
+ compatible:
+ const: qcom,maili-tlmm
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ gpio-reserved-ranges:
+ minItems: 1
+ maxItems: 113
+
+ gpio-line-names:
+ maxItems: 226
+
+patternProperties:
+ "-state$":
+ oneOf:
+ - $ref: "#/$defs/qcom-maili-tlmm-state"
+ - patternProperties:
+ "-pins$":
+ $ref: "#/$defs/qcom-maili-tlmm-state"
+ additionalProperties: false
+
+$defs:
+ qcom-maili-tlmm-state:
+ type: object
+ description:
+ Pinctrl node's client devices use subnodes for desired pin configuration.
+ Client device subnodes use below standard properties.
+ $ref: qcom,tlmm-common.yaml#/$defs/qcom-tlmm-state
+ unevaluatedProperties: false
+
+ properties:
+ pins:
+ description:
+ List of gpio pins affected by the properties specified in this
+ subnode.
+ items:
+ oneOf:
+ - pattern: "^gpio([0-9]|[1-9][0-9]|1[0-9][0-9]|20[0-9]|21[0-9]|22[0-5])$"
+ - enum: [ ufs_reset, sdc2_clk, sdc2_cmd, sdc2_data ]
+ minItems: 1
+ maxItems: 36
+
+ function:
+ description:
+ Specify the alternative function to be configured for the specified
+ pins.
+ enum: [ gpio, aoss_cti, atest_char, atest_usb, audio_ext_mclk,
+ audio_ref_clk, cam_mclk, cci_async_in, cci_i2c0, cci_i2c1,
+ cci_i2c2, cci_i2c3, cci_timer, coex_espmi, coex_uart1_rx,
+ coex_uart1_tx, dbg_out_clk, ddr_bist, ddr_pxi, dp_hot, egpio,
+ gcc_gp, gnss_adc, host2wlan_sol, host_rst, i2chub0_se0,
+ i2chub0_se1, i2chub0_se2, i2chub0_se3, i2chub0_se4, i2s0, i2s1,
+ ibi_i3c, ibi_i3c_qup5_se0, jitter_bist, mdp_esync0, mdp_esync1,
+ mdp_esync2, mdp_vsync, mdp_vsync_e, mdp_vsync_p, mdp_vsync0_out,
+ mdp_vsync1_out, mdp_vsync2_out, mdp_vsync3_out, mdp_vsync5_out,
+ modem_pps_in, modem_pps_out, nav_gpio, nav_gpio0, nav_gpio3,
+ nav_rffe, pcie0_clk_req_n, pcie1_clk_req_n, pcie1_rst_n,
+ phase_flag, pll_bist_sync, pll_clk_aux, qdss_cti, qlink, qspi,
+ qspi_clk, qspi_cs, qup1_se0, qup1_se1, qup1_se2, qup1_se3,
+ qup1_se4, qup1_se5, qup1_se6, qup1_se7, qup2_se0, qup2_se1,
+ qup2_se2, qup2_se3, qup2_se4_01, qup2_se4_23, qup3_se0,
+ qup3_se1, qup3_se2, qup3_se3, qup3_se4, qup3_se5, qup4_se0,
+ qup4_se1, qup4_se2, qup4_se3_01, qup4_se3_23, qup4_se3_l3,
+ qup4_se4_01, qup4_se4_23, qup4_se4_l3, qup5_se0, rng_rosc,
+ sd_write_protect, sdc2_clk, sdc2_cmd, sdc2_data, sdc2_rclk,
+ sdc4_clk, sdc4_cmd, sdc4_data, sys_throttle, tb_trig_sdc,
+ tmess_rng, tsense_clm, tsense_pwm, uim0, uim1, usb0_hs, usb_phy,
+ vfr, vsense_trigger_mirnat, wcn_sw ]
+
+ required:
+ - pins
+
+required:
+ - compatible
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ tlmm: pinctrl@f100000 {
+ compatible = "qcom,maili-tlmm";
+ reg = <0x0f100000 0x300000>;
+ interrupts = <GIC_ESPI 272 IRQ_TYPE_LEVEL_HIGH>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&tlmm 0 0 227>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ qup-uart7-state {
+ pins = "gpio62", "gpio63";
+ function = "qup1_se7";
+ };
+ };
+...
--
2.34.1
^ permalink raw reply related
* [PATCH v3 0/2] pinctrl: qcom: Introduce Pinctrl for the upcoming Maili SoC
From: Jingyi Wang @ 2026-06-22 8:35 UTC (permalink / raw)
To: Bjorn Andersson, Linus Walleij, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: aiqun.yu, tingwei.zhang, trilok.soni, yijie.yang, linux-arm-msm,
linux-gpio, devicetree, linux-kernel, Jingyi Wang,
Krzysztof Kozlowski, Dmitry Baryshkov, Konrad Dybcio
Introduce Top Level Mode Multiplexer dt-binding and driver for the
upcoming Qualcomm Maili SoC. Maili is the new mobile SoC, and its DTS
will be upstreamed later.
Signed-off-by: Jingyi Wang <jingyi.wang@oss.qualcomm.com>
---
Changes in v3:
- add reviewed-by tag
- remove comments before msm_pingroup
- Link to v2: https://lore.kernel.org/r/20260614-maili-pinctrl-v2-0-0db5bfc23d64@oss.qualcomm.com
Changes in v2:
- Move MODULE_DEVICE_TABLE next to the table itself
- Update gpio function to MSM_GPIO_PIN_FUNCTION
- Link to v1: https://lore.kernel.org/r/20260522-maili-pinctrl-v1-0-0a6636f5c277@oss.qualcomm.com
---
Jingyi Wang (2):
dt-bindings: pinctrl: qcom: Describe Maili TLMM block
pinctrl: qcom: Add the tlmm driver for Maili platform
.../bindings/pinctrl/qcom,maili-tlmm.yaml | 120 ++
drivers/pinctrl/qcom/Kconfig.msm | 10 +
drivers/pinctrl/qcom/Makefile | 1 +
drivers/pinctrl/qcom/pinctrl-maili.c | 1625 ++++++++++++++++++++
4 files changed, 1756 insertions(+)
---
base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b
change-id: 20260614-maili-pinctrl-230a8ce90bcd
Best regards,
--
Jingyi Wang <jingyi.wang@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v7 22/22] TEST(do-not-upstream): fake qemu vendor JSON + mapfile entry for CounterIDMask path
From: sashiko-bot @ 2026-06-22 8:35 UTC (permalink / raw)
To: Atish Patra; +Cc: conor+dt, devicetree, linux-perf-users, robh
In-Reply-To: <20260622-counter_delegation-v7-22-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The commit is explicitly marked as 'do-not-upstream' and introduces artificial test data into the perf tool's PMU events database.
--
commit 845c89532d7f6f6ae99c8ce7e80ef23f83afdd90
Author: Atish Patra <atishp@meta.com>
TEST(do-not-upstream): fake qemu vendor JSON + mapfile entry for CounterIDMask path
This commit adds fake JSON events for qemu/virt to the PMU events database.
It exercises jevents CounterIDMask handling locally and is explicitly
marked as not for upstreaming.
> diff --git a/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json b/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json
> new file mode 100644
> index 0000000000000..294c4ed645f67
> --- /dev/null
> +++ b/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json
> @@ -0,0 +1,26 @@
> +[
> + {
> + "EventName": "fake-json-any",
[Severity: Medium]
Since the commit subject specifies this is for testing and should not be
upstreamed, does this patch need to be dropped from the series before it
is merged?
Merging this into the mainline kernel would pollute the production PMU events
database with artificial test events that have no meaning on real hardware.
> + "EventCode": "0xF10",
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=22
^ permalink raw reply
* Re: [PATCH v2 2/3] docs: watchdog: npcm: Add reset status description
From: sashiko-bot @ 2026-06-22 8:34 UTC (permalink / raw)
To: Tomer Maimon; +Cc: robh, conor+dt, devicetree, linux-watchdog
In-Reply-To: <20260622083046.3189603-3-tmaimon77@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] UAPI Semantic Violation: Overloading generic watchdog bootstatus flags with unrelated platform-specific reset causes.
--
commit 622b044102abac9e6e33a21b4739ad90ba16eec5
Author: Tomer Maimon <tmaimon77@gmail.com>
docs: watchdog: npcm: Add reset status description
This commit adds documentation describing how the NPCM watchdog driver
reports reset causes through bootstatus on NPCM750 and NPCM845 systems. It
documents the fixed reset flag mapping, watchdog instance mapping, and
sysfs reporting behavior.
> diff --git a/Documentation/watchdog/npcm_wdt.rst b/Documentation/watchdog/npcm_wdt.rst
> new file mode 100644
> index 0000000000000..48f0c7920c112
> --- /dev/null
> +++ b/Documentation/watchdog/npcm_wdt.rst
[ ... ]
> +.. list-table:: Reset-cause mapping
> + :header-rows: 1
> +
> + * - Platform
> + - Reset indication
> + - Bootstatus flag
> + - Reported meaning
> + * - NPCM750 and NPCM845
> + - ``PORST``
> + - ``WDIOF_OVERHEAT``
> + - power-on reset
> + * - NPCM750 and NPCM845
> + - ``CORST``
> + - ``WDIOF_FANFAULT``
> + - core reset
[Severity: High]
Is it intentional to overload standard watchdog UAPI flags with unrelated
platform-specific reset causes?
Mapping "power-on reset" (NPCM_PORST) to WDIOF_OVERHEAT ("Reset due to CPU
overheat") and "core reset" (NPCM_CORST) to WDIOF_FANFAULT ("Fan failed") will
cause generic userspace applications, system managers, and monitoring tools to
misinterpret the values. This could lead to false reports of CPU overheating
or fan failures during normal cold boots.
Should these hardware-specific reset reasons be exposed via a dedicated
reset-reason framework or custom sysfs attributes instead of redefining
standardized generic UAPI flags?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622083046.3189603-1-tmaimon77@gmail.com?part=2
^ permalink raw reply
* Re: [PATCH v7 19/22] tools/perf: Support event code for arch standard events
From: sashiko-bot @ 2026-06-22 8:34 UTC (permalink / raw)
To: Atish Patra; +Cc: robh, conor+dt, devicetree, linux-perf-users
In-Reply-To: <20260622-counter_delegation-v7-19-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] Logic error in preserving event encodings for architecture standard events: the script silently discards valid `EventCode: 0`, alternate encodings (e.g., `ConfigCode`), and all associated modifiers (e.g., `UMask`, `CounterIDMask`).
--
commit 49dcf2f5443f8355e35a6c0465204600a8115b63
Author: Atish Patra <atishp@rivosinc.com>
tools/perf: Support event code for arch standard events
This commit modifies the perf tool's json event parsing to preserve the event
encoding of architecture standard events. It skips overwriting the event code
if one is already provided in the json file.
> diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
> index 3a1bcdcdc685f..457fce7a59820 100755
> --- a/tools/perf/pmu-events/jevents.py
> +++ b/tools/perf/pmu-events/jevents.py
> @@ -413,7 +413,11 @@ class JsonEvent:
> self.long_desc = None
> if arch_std:
> if arch_std.lower() in _arch_std_events:
> - event = _arch_std_events[arch_std.lower()].event
> + # If the JSON event already specified an event code, the encoding has
> + # been set above; don't overwrite it with the arch standard event or
> + # the event encoding would be lost.
> + if not eventcode:
> + event = _arch_std_events[arch_std.lower()].event
[Severity: High]
Does this check properly handle an event code of 0 or alternate encodings?
If EventCode is explicitly 0, or if an alternate encoding like ConfigCode
is used (leaving eventcode as 0), the truthiness check will evaluate to true.
This would cause JsonEvent.__init__ to overwrite the newly constructed event
string with the base architecture standard event string, silently discarding
the explicit 0 encoding or alternate encodings, as well as any modifiers
appended beforehand like UMask.
Would it be safer to check dictionary membership directly, or initialize
eventcode to None to distinguish between an explicit 0 and an unset value?
> # Copy from the architecture standard event to self for undefined fields.
> for attr, value in _arch_std_events[arch_std.lower()].__dict__.items():
> if hasattr(self, attr) and not getattr(self, attr):
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=19
^ permalink raw reply
* Re: [PATCH v7 14/22] RISC-V: perf: Implement supervisor counter delegation support
From: sashiko-bot @ 2026-06-22 8:33 UTC (permalink / raw)
To: Atish Patra; +Cc: robh, devicetree, linux-perf-users, conor+dt
In-Reply-To: <20260622-counter_delegation-v7-14-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [Critical] Unconditionally setting the HPMEVENT_OF bit and failing to clear it due to early returns in `rvpmu_deleg_ctr_enable_irq` guarantees an inescapable infinite interrupt storm.
- [High] The driver incorrectly falls back to SBI snapshot logic for delegated counters when both counter delegation and SBI PMU snapshots are available.
- [High] On 32-bit RISC-V, `firmware_cmask` causes undefined behavior when populated, and incorrectly stops hardware counters instead of firmware counters during CPU hotplug.
- [High] In `rvpmu_sbi_start_ovf_ctrs_snapshot()`, an invalid `counter_idx_base` is passed to the SBI call and incorrect indices are used to write snapshot data.
- [Medium] On 32-bit RISC-V, `update_deleg_hpmevent` drops privilege mode filtering bits for fixed counters if `Smcntrpmf` is present but `Sscofpmf` is not.
--
commit 65245d6fdd7f56371717df02024d346e436c2c26
Author: Atish Patra <atishp@rivosinc.com>
RISC-V: perf: Implement supervisor counter delegation support
This commit introduces support for RISC-V supervisor counter delegation.
It detects relevant ISA extensions at runtime to program counters directly
from S-mode, falling back to the SBI PMU extension for firmware counters
or when user-requested.
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 1c0961e09b15f..6407e229c2c3c 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
[ ... ]
> @@ -821,7 +968,7 @@ static int pmu_sbi_snapshot_setup(struct riscv_pmu *pmu, int cpu)
> return 0;
> }
>
> -static u64 rvpmu_sbi_ctr_read(struct perf_event *event)
> +static u64 rvpmu_ctr_read(struct perf_event *event)
> {
[Severity: High]
Does this code inadvertently read stale or zero values for delegated
counters?
If both counter delegation and SBI PMU snapshots are available,
sbi_pmu_snapshot_available() will be true. The early return in
rvpmu_ctr_read() will read from the snapshot shared memory, bypassing
hardware CSRs. However, stopped delegated counters are stopped locally
and won't update the SBI shared memory, resulting in an incorrect read.
[ ... ]
> +static void rvpmu_deleg_ctr_enable_irq(struct perf_event *event)
> +{
> + unsigned long hpmevent_curr;
> + unsigned long of_mask;
> + struct hw_perf_event *hwc = &event->hw;
> + int counter_idx = hwc->idx;
> + unsigned long sip_val = csr_read(CSR_SIP);
> +
> + if (!is_sampling_event(event) || (sip_val & SIP_LCOFIP))
> + return;
[Severity: Critical]
Does this early return guarantee an inescapable infinite interrupt storm
for non-sampling events?
When rvpmu_deleg_ctr_start() is called for a non-sampling event, this
returns early without clearing the HPMEVENT_OF bit. When scountinhibit
is subsequently cleared, the active OF bit will immediately trigger a
local counter overflow interrupt. Since rvpmu_ovf_handler() skips
non-sampling events, the OF bit is never cleared, trapping the system
in an interrupt loop.
[ ... ]
> -static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
> - u64 ctr_ovf_mask)
> +static void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
> + u64 ctr_ovf_mask)
> {
> int i, idx = 0;
> struct perf_event *event;
[Severity: High]
Does this function use an invalid base index and incorrect array indices?
The inner loop for_each_set_bit(idx, &cpu_hw_evt->used_hw_ctrs[i],
BITS_PER_LONG) completes with idx equal to BITS_PER_LONG. The subsequent
call to sbi_ecall() then uses idx * BITS_PER_LONG as the base index,
passing 1024 or 4096 instead of i * BITS_PER_LONG, which causes the SBI
call to fail.
Additionally, the assignment to sdata->ctr_values[idx] uses the relative
word index instead of adding the word offset. On 32-bit architectures,
this overwrites elements 0-31 instead of updating elements 32-63,
corrupting the snapshot memory.
[ ... ]
> @@ -1116,15 +1269,53 @@ static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_h
> }
> }
>
> -/*
> - * This function starts all the used counters in two step approach.
> - * Any counter that did not overflow can be start in a single step
> - * while the overflowed counters need to be started with updated initialization
> - * value.
> - */
> -static void rvpmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
> - u64 ctr_ovf_mask)
> +static void rvpmu_start_overflow_mask(struct riscv_pmu *pmu, u64 ctr_ovf_mask)
> {
> + int idx = 0, i;
> + struct perf_event *event;
> + unsigned long ctr_start_mask = 0;
> + u64 max_period, init_val = 0;
> + struct hw_perf_event *hwc;
> struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
>
> if (sbi_pmu_snapshot_available())
> - rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
> - else
> - rvpmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
> + return rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
[Severity: High]
Does this code incorrectly fall back to SBI PMU snapshot restart logic
for delegated counters?
Since sbi_pmu_snapshot_available() and riscv_pmu_cdeleg_available() can
both be true simultaneously, checking sbi_pmu_snapshot_available() first
without verifying if the counter is actually delegated causes the driver
to attempt restarting delegated hardware counters via SBI PMU ECALLs
instead of direct CSR writes.
[ ... ]
> +static void update_deleg_hpmevent(int counter_idx, uint64_t event_value, uint64_t filter_bits)
> +{
> + u64 hpmevent_value = 0;
> +
> + /* OF bit should be enable during the start if sampling is requested */
> + hpmevent_value = (event_value & ~HPMEVENT_MASK) | filter_bits | HPMEVENT_OF;
[Severity: Critical]
Does unconditionally setting HPMEVENT_OF cause an inescapable interrupt
loop when combined with the early return in rvpmu_deleg_ctr_enable_irq()?
Setting the HPMEVENT_OF bit here guarantees a pending overflow interrupt
will be asserted once scountinhibit is cleared. If the event is
non-sampling, the early return in rvpmu_deleg_ctr_enable_irq() skips
clearing this bit, resulting in an infinite interrupt storm.
> +#if defined(CONFIG_32BIT)
> + csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_value & 0xFFFFFFFF);
> + if (riscv_isa_extension_available(NULL, SSCOFPMF))
> + csr_ind_write(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx,
> + hpmevent_value >> BITS_PER_LONG);
[Severity: Medium]
On 32-bit RISC-V, does this check inadvertently drop privilege mode
filtering bits for fixed counters?
Fixed counters rely on the Smcntrpmf extension for filtering bits. If a
system implements Smcntrpmf and counter delegation but lacks Sscofpmf,
the upper 32 bits (which contain the privilege mode filtering bits) are
skipped, and the privilege filter configuration is silently dropped.
[ ... ]
> @@ -1323,7 +1681,16 @@ static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
> csr_write(CSR_SCOUNTEREN, 0x2);
>
> /* Stop all the counters so that they can be enabled from perf */
> - rvpmu_sbi_stop_all(pmu);
> + if (riscv_pmu_cdeleg_available()) {
> + rvpmu_deleg_ctr_stop_mask(cmask);
> + if (riscv_pmu_sbi_available()) {
> + /* Stop the firmware counters as well */
> + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, 0, firmware_cmask,
> + 0, 0, 0, 0);
> + }
[Severity: High]
Does this code inadvertently invoke undefined behavior and stop the wrong
counters on 32-bit architectures?
firmware_cmask is defined as an unsigned long. Since firmware counters
occupy indices 32-63, populating firmware_cmask via BIT(i) where i >= 32
invokes undefined behavior on 32-bit architectures by wrapping the
shift, which corrupts the mask.
When sbi_ecall() is invoked here with base index 0 and the corrupted
firmware_cmask, it instructs the SBI firmware to stop hardware counters
(0-31) that map to the wrapped bits, while failing to stop the actual
firmware counters.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=14
^ permalink raw reply
* Re: [PATCH v7 21/22] TEST(do-not-upstream): fake qemu-virt PMU events for cdeleg counter-mask testing
From: sashiko-bot @ 2026-06-22 8:32 UTC (permalink / raw)
To: Atish Patra; +Cc: conor+dt, devicetree, linux-perf-users, robh
In-Reply-To: <20260622-counter_delegation-v7-21-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] The patch introduces fake PMU events intended solely for testing and unconditionally pollutes the production sysfs ABI.
--
commit 4ceddd2e5a59573074b3f2f8f712ad1f99946ae0
Author: Atish Patra <atishp@meta.com>
TEST(do-not-upstream): fake qemu-virt PMU events for cdeleg counter-mask testing
This commit adds fake PMU event codes to exercise counter-delegation allocation
and counter-mask constraints in QEMU. It unconditionally exposes these test
events to the user by adding them to the driver's event group.
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 3cb7a1f4035ef..13a9f1fe42936 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
[ ... ]
> @@ -499,6 +505,9 @@ static struct attribute *qemu_virt_event_group[] = {
> RVPMU_EVENT_ATTR_PTR(dTLB_load_miss),
> RVPMU_EVENT_ATTR_PTR(dTLB_store_miss),
> RVPMU_EVENT_ATTR_PTR(iTLB_load_miss),
> + RVPMU_EVENT_ATTR_PTR(fake_any),
> + RVPMU_EVENT_ATTR_PTR(fake_ctr3),
> + RVPMU_EVENT_ATTR_PTR(fake_ctr34),
[Severity: Medium]
Is it intended to leave these test-only events unconditionally exposed in the
production sysfs ABI?
Although the patch is explicitly marked as do-not-upstream, these fake events
are added directly to qemu_virt_event_group without being cleaned up later in
the series. This will visibly alter userspace tools like perf list on standard
RISC-V virtual workloads.
Could these test artifacts be separated from the mainline driver or removed
entirely if this series is routed upstream?
> NULL,
> };
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=21
^ permalink raw reply
* [PATCH v2 3/3] watchdog: npcm: add bootstatus support
From: Tomer Maimon @ 2026-06-22 8:30 UTC (permalink / raw)
To: andrew, wim, linux, robh, krzk+dt, conor+dt
Cc: openbmc, linux-watchdog, linux-doc, devicetree, linux-kernel,
avifishman70, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, corbet, skhan, joel
In-Reply-To: <20260622083046.3189603-1-tmaimon77@gmail.com>
The NPCM750 uses RESSR and the NPCM845 uses INTCR2 to latch reset
indications. Read those bits during probe and map them into watchdog
bootstatus flags.
For NPCM845, cache the sampled INTCR2 state in SCRPAD10 after the reset
status bits are cleared so later probes can report the same boot-time
state. Also report WDIOF_CARDRESET for the watchdog instance whose reset
bit is latched, while leaving WPCM450 behavior unchanged.
Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
drivers/watchdog/npcm_wdt.c | 197 +++++++++++++++++++++++++++++++++++-
1 file changed, 195 insertions(+), 2 deletions(-)
diff --git a/drivers/watchdog/npcm_wdt.c b/drivers/watchdog/npcm_wdt.c
index e62ea054bc61..98660419ec3f 100644
--- a/drivers/watchdog/npcm_wdt.c
+++ b/drivers/watchdog/npcm_wdt.c
@@ -7,14 +7,51 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/watchdog.h>
#define NPCM_WTCR 0x1C
+/* NPCM GCR module */
+#define NPCM_RESSR_OFFSET 0x6C
+#define NPCM_INTCR2_OFFSET 0x60
+#define NPCM8XX_SCRPAD10_OFFSET 0xE28
+
+#define NPCM_PORST BIT(31)
+#define NPCM_CORST BIT(30)
+#define NPCM_WD0RST BIT(29)
+#define NPCM_SWR1RST BIT(28)
+#define NPCM_SWR2RST BIT(27)
+#define NPCM_SWR3RST BIT(26)
+#define NPCM_SWR4RST BIT(25)
+#define NPCM_WD1RST BIT(24)
+#define NPCM_WD2RST BIT(23)
+#define NPCM8XX_RST (GENMASK(31, 23) | GENMASK(15, 12))
+#define NPCM8XX_TIP_RESET BIT(25) /* Replaces SWRST4 on NPCM8xx */
+
+/* Per-instance mapping of MMIO base address to its RESSR/INTCR2 reset bit. */
+struct npcm_wdt_rst_map {
+ phys_addr_t base;
+ u32 rst_bit;
+};
+
+struct npcm_wdt_status_map {
+ u32 rst_bit;
+ u32 wdiof_flag;
+};
+
+struct npcm_wdt_data {
+ const struct npcm_wdt_rst_map *rst_map;
+ unsigned int rst_map_size;
+ const struct npcm_wdt_status_map *status_map;
+ unsigned int status_map_size;
+};
+
#define NPCM_WTCLK (BIT(10) | BIT(11)) /* Clock divider */
#define NPCM_WTE BIT(7) /* Enable */
#define NPCM_WTIE BIT(6) /* Enable irq */
@@ -47,6 +84,50 @@ struct npcm_wdt {
struct clk *clk;
};
+static const struct npcm_wdt_rst_map npcm750_rst_map[] = {
+ { 0xf000801c, NPCM_WD0RST },
+ { 0xf000901c, NPCM_WD1RST },
+ { 0xf000a01c, NPCM_WD2RST },
+};
+
+static const struct npcm_wdt_status_map npcm750_status_map[] = {
+ { NPCM_PORST, WDIOF_OVERHEAT },
+ { NPCM_CORST, WDIOF_FANFAULT },
+ { NPCM_SWR1RST, WDIOF_EXTERN1 },
+ { NPCM_SWR2RST, WDIOF_EXTERN2 },
+ { NPCM_SWR3RST, WDIOF_POWERUNDER },
+ { NPCM_SWR4RST, WDIOF_POWEROVER },
+};
+
+static const struct npcm_wdt_data npcm750_data = {
+ .rst_map = npcm750_rst_map,
+ .rst_map_size = ARRAY_SIZE(npcm750_rst_map),
+ .status_map = npcm750_status_map,
+ .status_map_size = ARRAY_SIZE(npcm750_status_map),
+};
+
+static const struct npcm_wdt_rst_map npcm845_rst_map[] = {
+ { 0xf000801c, NPCM_WD0RST },
+ { 0xf000901c, NPCM_WD1RST },
+ { 0xf000a01c, NPCM_WD2RST },
+};
+
+static const struct npcm_wdt_status_map npcm845_status_map[] = {
+ { NPCM_PORST, WDIOF_OVERHEAT },
+ { NPCM_CORST, WDIOF_FANFAULT },
+ { NPCM_SWR1RST, WDIOF_EXTERN1 },
+ { NPCM_SWR2RST, WDIOF_EXTERN2 },
+ { NPCM_SWR3RST, WDIOF_POWERUNDER },
+ { NPCM8XX_TIP_RESET, WDIOF_POWEROVER },
+};
+
+static const struct npcm_wdt_data npcm845_data = {
+ .rst_map = npcm845_rst_map,
+ .rst_map_size = ARRAY_SIZE(npcm845_rst_map),
+ .status_map = npcm845_status_map,
+ .status_map_size = ARRAY_SIZE(npcm845_status_map),
+};
+
static inline struct npcm_wdt *to_npcm_wdt(struct watchdog_device *wdd)
{
return container_of(wdd, struct npcm_wdt, wdd);
@@ -169,6 +250,92 @@ static bool npcm_is_running(struct watchdog_device *wdd)
return readl(wdt->reg) & NPCM_WTE;
}
+static void npcm_get_reset_status(struct npcm_wdt *wdt, struct device *dev,
+ const struct npcm_wdt_data *data,
+ resource_size_t start)
+{
+ struct regmap *gcr_regmap;
+ u32 rstval = 0;
+ unsigned int i;
+ int ret;
+
+ if (!data)
+ return;
+
+ gcr_regmap = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "nuvoton,sysgcr");
+ if (IS_ERR(gcr_regmap)) {
+ dev_warn(dev,
+ "Failed to find nuvoton,sysgcr, WD reset status not supported\n");
+ return;
+ }
+
+ if (of_device_is_compatible(dev->of_node, "nuvoton,npcm845-wdt")) {
+ ret = regmap_read(gcr_regmap, NPCM_INTCR2_OFFSET, &rstval);
+ if (ret) {
+ dev_warn(dev, "Failed to read INTCR2 reset status: %d\n",
+ ret);
+ return;
+ }
+
+ if (rstval & NPCM8XX_RST) {
+ ret = regmap_write(gcr_regmap, NPCM_INTCR2_OFFSET,
+ rstval & ~NPCM8XX_RST);
+ if (ret) {
+ dev_warn(dev,
+ "Failed to clear INTCR2 reset status: %d\n",
+ ret);
+ return;
+ }
+
+ ret = regmap_write(gcr_regmap, NPCM8XX_SCRPAD10_OFFSET,
+ rstval);
+ if (ret) {
+ dev_warn(dev,
+ "Failed to cache reset status in SCRPAD10: %d\n",
+ ret);
+ return;
+ }
+ } else {
+ ret = regmap_read(gcr_regmap, NPCM8XX_SCRPAD10_OFFSET,
+ &rstval);
+ if (ret) {
+ dev_warn(dev,
+ "Failed to read cached reset status from SCRPAD10: %d\n",
+ ret);
+ return;
+ }
+ }
+ } else if (of_device_is_compatible(dev->of_node, "nuvoton,npcm750-wdt")) {
+ ret = regmap_read(gcr_regmap, NPCM_RESSR_OFFSET, &rstval);
+ if (ret) {
+ dev_warn(dev, "Failed to read RESSR reset status: %d\n",
+ ret);
+ return;
+ }
+
+ ret = regmap_write(gcr_regmap, NPCM_RESSR_OFFSET, rstval);
+ if (ret) {
+ dev_warn(dev, "Failed to clear RESSR reset status: %d\n",
+ ret);
+ return;
+ }
+ }
+
+ for (i = 0; i < data->status_map_size; i++) {
+ if (rstval & data->status_map[i].rst_bit)
+ wdt->wdd.bootstatus |= data->status_map[i].wdiof_flag;
+ }
+
+ for (i = 0; i < data->rst_map_size; i++) {
+ if (data->rst_map[i].base == start &&
+ rstval & data->rst_map[i].rst_bit) {
+ wdt->wdd.bootstatus |= WDIOF_CARDRESET;
+ break;
+ }
+ }
+}
+
static const struct watchdog_info npcm_wdt_info = {
.identity = KBUILD_MODNAME,
.options = WDIOF_SETTIMEOUT
@@ -176,6 +343,20 @@ static const struct watchdog_info npcm_wdt_info = {
| WDIOF_MAGICCLOSE,
};
+static const struct watchdog_info npcm_wdt_rst_info = {
+ .identity = KBUILD_MODNAME,
+ .options = WDIOF_SETTIMEOUT
+ | WDIOF_KEEPALIVEPING
+ | WDIOF_MAGICCLOSE
+ | WDIOF_CARDRESET
+ | WDIOF_OVERHEAT
+ | WDIOF_FANFAULT
+ | WDIOF_EXTERN1
+ | WDIOF_EXTERN2
+ | WDIOF_POWERUNDER
+ | WDIOF_POWEROVER,
+};
+
static const struct watchdog_ops npcm_wdt_ops = {
.owner = THIS_MODULE,
.start = npcm_wdt_start,
@@ -188,7 +369,10 @@ static const struct watchdog_ops npcm_wdt_ops = {
static int npcm_wdt_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ const struct npcm_wdt_data *data = device_get_match_data(dev);
+ struct resource *res;
struct npcm_wdt *wdt;
+ resource_size_t start;
int irq;
int ret;
@@ -196,10 +380,16 @@ static int npcm_wdt_probe(struct platform_device *pdev)
if (!wdt)
return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
wdt->reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(wdt->reg))
return PTR_ERR(wdt->reg);
+ start = res->start;
+
wdt->clk = devm_clk_get_optional(&pdev->dev, NULL);
if (IS_ERR(wdt->clk))
return PTR_ERR(wdt->clk);
@@ -208,7 +398,7 @@ static int npcm_wdt_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- wdt->wdd.info = &npcm_wdt_info;
+ wdt->wdd.info = data ? &npcm_wdt_rst_info : &npcm_wdt_info;
wdt->wdd.ops = &npcm_wdt_ops;
wdt->wdd.min_timeout = 1;
wdt->wdd.max_timeout = 2750;
@@ -220,6 +410,8 @@ static int npcm_wdt_probe(struct platform_device *pdev)
/* Ensure timeout is able to be represented by the hardware */
npcm_wdt_set_timeout(&wdt->wdd, wdt->wdd.timeout);
+ npcm_get_reset_status(wdt, dev, data, start);
+
if (npcm_is_running(&wdt->wdd)) {
/* Restart with the default or device-tree specified timeout */
npcm_wdt_start(&wdt->wdd);
@@ -243,7 +435,8 @@ static int npcm_wdt_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id npcm_wdt_match[] = {
{.compatible = "nuvoton,wpcm450-wdt"},
- {.compatible = "nuvoton,npcm750-wdt"},
+ {.compatible = "nuvoton,npcm750-wdt", .data = &npcm750_data},
+ {.compatible = "nuvoton,npcm845-wdt", .data = &npcm845_data},
{},
};
MODULE_DEVICE_TABLE(of, npcm_wdt_match);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/3] docs: watchdog: npcm: Add reset status description
From: Tomer Maimon @ 2026-06-22 8:30 UTC (permalink / raw)
To: andrew, wim, linux, robh, krzk+dt, conor+dt
Cc: openbmc, linux-watchdog, linux-doc, devicetree, linux-kernel,
avifishman70, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, corbet, skhan, joel
In-Reply-To: <20260622083046.3189603-1-tmaimon77@gmail.com>
Add documentation describing how the NPCM watchdog driver reports reset
causes through bootstatus on NPCM750 and NPCM845 systems.
Document the reset flag mapping, the watchdog instance mapping for
WDIOF_CARDRESET, and the NPCM750/NPCM845 latch handling. Also mention
sysfs bootstatus reporting when watchdog sysfs support is enabled.
Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
Documentation/watchdog/index.rst | 1 +
Documentation/watchdog/npcm_wdt.rst | 70 +++++++++++++++++++++++++++++
2 files changed, 71 insertions(+)
create mode 100644 Documentation/watchdog/npcm_wdt.rst
diff --git a/Documentation/watchdog/index.rst b/Documentation/watchdog/index.rst
index 1cea24681e6b..ef29e861e837 100644
--- a/Documentation/watchdog/index.rst
+++ b/Documentation/watchdog/index.rst
@@ -9,6 +9,7 @@ Watchdog Support
hpwdt
mlx-wdt
+ npcm_wdt
pcwd-watchdog
watchdog-api
watchdog-kernel-api
diff --git a/Documentation/watchdog/npcm_wdt.rst b/Documentation/watchdog/npcm_wdt.rst
new file mode 100644
index 000000000000..48f0c7920c11
--- /dev/null
+++ b/Documentation/watchdog/npcm_wdt.rst
@@ -0,0 +1,70 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============
+NPCM Watchdog
+=============
+
+The NPCM watchdog driver can report reset-cause information on
+``nuvoton,npcm750-wdt`` and ``nuvoton,npcm845-wdt`` systems.
+
+Userspace can read the latched reset cause through
+``WDIOC_GETBOOTSTATUS``. When ``CONFIG_WATCHDOG_SYSFS`` is enabled, the
+same value is also visible through ``/sys/class/watchdog/watchdogN/bootstatus``.
+
+The mapping is fixed in the driver. It exposes the SoC reset indications
+through the generic watchdog bootstatus flags and is not configurable from
+Device Tree.
+
+.. list-table:: Reset-cause mapping
+ :header-rows: 1
+
+ * - Platform
+ - Reset indication
+ - Bootstatus flag
+ - Reported meaning
+ * - NPCM750 and NPCM845
+ - ``PORST``
+ - ``WDIOF_OVERHEAT``
+ - power-on reset
+ * - NPCM750 and NPCM845
+ - ``CORST``
+ - ``WDIOF_FANFAULT``
+ - core reset
+ * - NPCM750 and NPCM845
+ - ``SWR1RST``
+ - ``WDIOF_EXTERN1``
+ - software reset source 1
+ * - NPCM750 and NPCM845
+ - ``SWR2RST``
+ - ``WDIOF_EXTERN2``
+ - software reset source 2
+ * - NPCM750 and NPCM845
+ - ``SWR3RST``
+ - ``WDIOF_POWERUNDER``
+ - software reset source 3
+ * - NPCM750
+ - ``SWR4RST``
+ - ``WDIOF_POWEROVER``
+ - software reset source 4
+ * - NPCM845
+ - ``TIP reset`` (``INTCR2[25]``)
+ - ``WDIOF_POWEROVER``
+ - TIP reset
+
+``WDIOF_CARDRESET`` is reported only for the watchdog instance whose own
+reset-status bit is latched. On systems with three watchdog instances, this
+maps ``WD0RST``, ``WD1RST``, and ``WD2RST`` to ``watchdog0``, ``watchdog1``,
+and ``watchdog2`` respectively.
+
+The driver may report ``WDIOF_CARDRESET`` together with one or more of the
+reset-cause flags listed above.
+
+On NPCM750, the driver samples ``RESSR`` and clears the latched reset bits
+after reading them.
+
+On NPCM845, the driver samples ``INTCR2``. When reset bits are still latched,
+it clears them and stores the sampled value in ``SCRPAD10`` so later watchdog
+probes can report the same boot-time state.
+
+The WPCM450 watchdog continues to operate without this reset-indication
+mapping.
--
2.34.1
^ permalink raw reply related
* [PATCH v2 1/3] dt-bindings: watchdog: npcm: add GCR syscon property
From: Tomer Maimon @ 2026-06-22 8:30 UTC (permalink / raw)
To: andrew, wim, linux, robh, krzk+dt, conor+dt
Cc: openbmc, linux-watchdog, linux-doc, devicetree, linux-kernel,
avifishman70, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, corbet, skhan, joel
In-Reply-To: <20260622083046.3189603-1-tmaimon77@gmail.com>
Describe syscon property that handles general control registers (GCR) in
Nuvoton BMC NPCM watchdog driver.
Signed-off-by: Tomer Maimon <tmaimon77@gmail.com>
---
.../devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
index 7aa30f5b5c49..4f00f099b2d2 100644
--- a/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
+++ b/Documentation/devicetree/bindings/watchdog/nuvoton,npcm750-wdt.yaml
@@ -40,6 +40,12 @@ properties:
clock-frequency:
description: Frequency in Hz of the clock that drives the NPCM timer.
+ nuvoton,sysgcr:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ a phandle to access GCR registers on NPCM750 and NPCM845 watchdog
+ instances.
+
required:
- compatible
- reg
--
2.34.1
^ permalink raw reply related
* [PATCH v2 0/3] watchdog: npcm: Add reset status detection support
From: Tomer Maimon @ 2026-06-22 8:30 UTC (permalink / raw)
To: andrew, wim, linux, robh, krzk+dt, conor+dt
Cc: openbmc, linux-watchdog, linux-doc, devicetree, linux-kernel,
avifishman70, tmaimon77, tali.perry1, venture, yuenn,
benjaminfair, corbet, skhan, joel
This series documents and implements reset indication reporting for the
NPCM watchdog driver on NPCM7xx and NPCM8xx systems, and documents the
optional GCR syscon property used by that support.
Patch 1 updates the watchdog binding to allow the optional
``nuvoton,sysgcr`` property used for reset-cause reporting.
Patch 2 adds watchdog documentation that describes the bootstatus
mapping.
Patch 3 reads the SoC reset indication bits and maps them into the
existing watchdog bootstatus flags for NPCM750 and NPCM845, while
leaving WPCM450 unchanged.
Addressed comments from:
- Krzysztof Kozlowski: https://patchwork.ozlabs.org/project/openbmc/patch/20260210133843.1078463-2-tmaimon77@gmail.com/
- Guenter Roeck: https://patchwork.ozlabs.org/project/openbmc/patch/20260210133843.1078463-3-tmaimon77@gmail.com/
Changes since version 1:
- Modify reset detection handle in the watchodg.
- reword patch 1 to use the GCR syscon-property wording from the
applied NPCM reset binding update and drop the optional property from
the binding example.
- reword the patch subjects and commit message bodies to match current
kernel dt-bindings, docs, and watchdog style.
Tomer Maimon (3):
dt-bindings: watchdog: npcm: add GCR syscon property
docs: watchdog: npcm: Add reset status description
watchdog: npcm: add bootstatus support
.../watchdog/nuvoton,npcm750-wdt.yaml | 6 +
Documentation/watchdog/index.rst | 1 +
Documentation/watchdog/npcm_wdt.rst | 70 +++++++
drivers/watchdog/npcm_wdt.c | 197 +++++++++++++++++-
4 files changed, 272 insertions(+), 2 deletions(-)
create mode 100644 Documentation/watchdog/npcm_wdt.rst
--
2.34.1
^ permalink raw reply
* Re: [PATCH v7 16/22] RISC-V: perf: Use config2/vendor table for event to counter mapping
From: sashiko-bot @ 2026-06-22 8:30 UTC (permalink / raw)
To: Atish Patra; +Cc: conor+dt, robh, devicetree, linux-perf-users
In-Reply-To: <20260622-counter_delegation-v7-16-0ba2fd34614e@meta.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Generic legacy hardware events (e.g. `cycles`) on the host cannot use fixed counters, contradicting the commit message and breaking standard profiling APIs.
- [High] Arbitrary events can be forced to silently count CPU cycles or instructions by setting `config2`, leading to silent data corruption.
--
commit d9b0aaf40875147c7d5a4d9a313b2c33198f256f
Author: Atish Patra <atishp@rivosinc.com>
RISC-V: perf: Use config2/vendor table for event to counter mapping
This commit allows platform vendors to define custom mappings between
events and hpmcounters by passing counter restrictions from the json file
to drivers via the config2 parameter. It also aims to let vendors specify
if fixed cycle and instruction counters should be used for legacy events.
> diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
> index 4f3a30143db11..1c846cdc96cf4 100644
> --- a/drivers/perf/riscv_pmu_sbi.c
> +++ b/drivers/perf/riscv_pmu_sbi.c
[ ... ]
> @@ -1501,24 +1503,85 @@ static int rvpmu_deleg_find_ctrs(void)
> return num_hw_ctr;
> }
>
> +/*
> + * The json file must correctly specify counter 0 or counter 2 is available
> + * in the counter lists for cycle/instret events. Otherwise, the drivers have
> + * no way to figure out if a fixed counter must be used and pick a programmable
> + * counter if available.
> + */
> static int get_deleg_fixed_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
> {
> - return -EINVAL;
> + bool guest_events = event->attr.config1 & RISCV_PMU_CONFIG1_GUEST_EVENTS;
> + int idx;
> +
> + /* event_base is 0 on the delegation path; match via the original perf attrs. */
> + if (guest_events) {
> + if (event->attr.type != PERF_TYPE_HARDWARE)
> + return -EINVAL;
> + if (event->attr.config == PERF_COUNT_HW_CPU_CYCLES)
> + idx = 0; /* CY counter */
> + else if (event->attr.config == PERF_COUNT_HW_INSTRUCTIONS)
> + idx = 2; /* IR counter */
> + else
> + return -EINVAL;
> + } else if (event->attr.config2 & RISCV_PMU_CYCLE_FIXED_CTR_MASK) {
> + idx = 0; /* CY counter */
> + } else if (event->attr.config2 & RISCV_PMU_INSTRUCTION_FIXED_CTR_MASK) {
> + idx = 2; /* IR counter */
> + } else {
[Severity: High]
Here config2 is evaluated without validating that the event is actually a
cycle/instruction event, or at least a PERF_TYPE_RAW event.
Since counterid_mask exposes config2:0-31 to userspace, what happens if a
user passes counterid_mask=1 for ANY event type, such as PERF_TYPE_HW_CACHE?
Will the kernel see bit 0 set, map the event to the fixed cycle counter
(idx 0), and silently return CPU cycle counts instead of rejecting the
invalid counter constraint?
> + return -EINVAL;
> + }
> +
> + /* Take the fixed counter only if delegated and free, else fall back. */
> + if (!(cmask & BIT(idx)) || test_bit(idx, cpuc->used_hw_ctrs))
> + return -EINVAL;
> +
> + return idx;
> }
>
> static int get_deleg_next_hpm_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
> {
> - unsigned long hw_ctr_mask = 0;
> + u32 hw_ctr_mask = 0, temp_mask = 0;
> + u32 type = event->attr.type;
> + u64 config = event->attr.config;
> + int ret;
>
> - /*
> - * TODO: Treat every hpmcounter can monitor every event for now.
> - * The event to counter mapping should come from the json file.
> - * The mapping should also tell if sampling is supported or not.
> - */
> + /* Select only available hpmcounters */
> + hw_ctr_mask = cmask & (~0x7) & ~(cpuc->used_hw_ctrs[0]);
[Severity: High]
For host events, get_deleg_fixed_hw_idx() above allocates fixed counters
solely based on event->attr.config2. If a standard tool requests
PERF_TYPE_HARDWARE (like generic cycles) where config2=0, won't it fall
back here?
Then in get_deleg_next_hpm_hw_idx(), the fixed counters are explicitly
masked out (~0x7). If a vendor correctly maps cycles exclusively to the
fixed counter in the driver table, the fallback path results in a mask
of 0, returning -EINVAL.
Does this prevent generic legacy hardware events from using fixed
counters on the host, contrary to the commit message?
> +
> + switch (type) {
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-counter_delegation-v7-0-0ba2fd34614e@meta.com?part=16
^ permalink raw reply
* Re: [PATCH v11 2/2] media: i2c: add Himax HM1246 image sensor driver
From: sashiko-bot @ 2026-06-22 8:29 UTC (permalink / raw)
To: Matthias Fend; +Cc: conor+dt, devicetree, robh
In-Reply-To: <20260622-hm1246-v11-2-c62ef9516ab1@emfend.at>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] Incorrect handling of negative error codes from pm_runtime_get_if_active() leads to usage counter underflow and invalid hardware access.
- [High] Integer overflow in vco_out calculation and logical flaw completely break PLL configuration for high link frequencies.
- [High] Use-After-Free race condition during device removal due to incorrect cleanup ordering.
- [Medium] Active subdev format code is not updated when modifying HFLIP or VFLIP controls.
--
commit afbc7b4c289cadb0abe3caa02a219adf435617bf
Author: Matthias Fend <matthias.fend@emfend.at>
Subject: media: i2c: add Himax HM1246 image sensor driver
This commit adds a V4L2 sub-device driver for the Himax HM1246 image sensor,
supporting raw mode operations through an I2C interface.
> diff --git a/drivers/media/i2c/hm1246.c b/drivers/media/i2c/hm1246.c
> new file mode 100644
> index 0000000000000..f87ccb9b5a560
> --- /dev/null
> +++ b/drivers/media/i2c/hm1246.c
> @@ -0,0 +1,1285 @@
[ ... ]
> +static int hm1246_calc_pll(u32 xclk, u32 link_freq, u32 clocks_per_pixel,
> + u8 *pll1, u8 *pll2, u8 *pll3)
> +{
[ ... ]
> + /* Determine an appropriate post divider. */
> + for (post_div_index = 0; post_div_index < ARRAY_SIZE(post_div_table);
> + post_div_index++) {
> + vco_out = pclk * pclk_div_table[pclk_div_index] *
> + post_div_table[post_div_index];
> +
> + if (vco_out >= HM1246_PLL_VCO_MIN &&
> + vco_out <= HM1246_PLL_VCO_MAX)
> + break;
> + }
[Severity: High]
Does this calculation overflow the 32-bit vco_out variable for high link
frequencies?
For a maximum allowed link frequency of 96MHz, pclk would be 192MHz. The
product of pclk (192,000,000) * pclk_div (6) * post_div (8) is 9,216,000,000,
which overflows the 32-bit u32 variable. This overflowed garbage value could
falsely fall within the valid VCO bounds, causing the loop to succeed and
the configuration to ultimately fail later with -EINVAL.
[ ... ]
> +static int hm1246_set_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct hm1246 *hm1246 =
> + container_of_const(ctrl->handler, struct hm1246, ctrls);
> + struct v4l2_subdev_state *state;
> + const struct v4l2_mbus_framefmt *format;
> + u32 val;
> + bool needs_cmu_update = true;
> + int ret;
> +
> + state = v4l2_subdev_get_locked_active_state(&hm1246->sd);
> + format = v4l2_subdev_state_get_format(state, 0);
> +
> + if (ctrl->id == V4L2_CID_VBLANK) {
> + s64 exposure_max;
> +
> + exposure_max =
> + format->height + ctrl->val - HM1246_COARSE_INTG_MARGIN;
> + ret = __v4l2_ctrl_modify_range(hm1246->exposure_ctrl,
> + hm1246->exposure_ctrl->minimum,
> + exposure_max,
> + hm1246->exposure_ctrl->step,
> + exposure_max);
> +
> + if (ret) {
> + dev_err(hm1246->dev, "exposure ctrl range update failed\n");
> + return ret;
> + }
> + }
> +
> + if (!pm_runtime_get_if_active(hm1246->dev))
> + return 0;
[Severity: High]
Could this condition mishandle negative error codes returned from the
Runtime PM core?
The function pm_runtime_get_if_active() returns 1 if active, 0 if suspended,
and a negative error code (like -EINVAL) if disabled. If it returns a
negative error code, this check is bypassed. This might allow the driver
to attempt hardware register accesses on unpowered hardware. In addition,
since the usage count wasn't incremented on error, the subsequent call to
pm_runtime_put() at the end of the function could cause a usage counter
underflow. Checking for (ret <= 0) might be safer here.
> +
> + ret = 0;
> + switch (ctrl->id) {
> + case V4L2_CID_EXPOSURE:
> + cci_write(hm1246->regmap, HM1246_COARSE_INTG_REG, ctrl->val,
> + &ret);
> + break;
> +
> + case V4L2_CID_ANALOGUE_GAIN:
> + cci_write(hm1246->regmap, HM1246_ANALOG_GLOBAL_GAIN_REG,
> + ctrl->val, &ret);
> + break;
> +
> + case V4L2_CID_VBLANK:
> + val = format->height + ctrl->val;
> + cci_write(hm1246->regmap, HM1246_FRAME_LENGTH_LINES_REG, val,
> + &ret);
> + break;
> +
> + case V4L2_CID_HFLIP:
> + case V4L2_CID_VFLIP:
> + val = 0;
> + if (hm1246->hflip_ctrl->val)
> + val |= HM1246_IMAGE_ORIENTATION_HFLIP;
> + if (hm1246->vflip_ctrl->val)
> + val |= HM1246_IMAGE_ORIENTATION_VFLIP;
> +
> + cci_write(hm1246->regmap, HM1246_IMAGE_ORIENTATION_REG, val,
> + &ret);
> + break;
[Severity: Medium]
Should the active subdev format code be updated here to reflect the new
pixel layout?
Since V4L2_CID_HFLIP and V4L2_CID_VFLIP change the sensor's Bayer color
pattern and are registered with V4L2_CTRL_FLAG_MODIFY_LAYOUT, leaving the
active state's pixel format un-updated could cause subsequent
VIDIOC_SUBDEV_G_FMT ioctls to return stale format information.
[ ... ]
> +static void hm1246_remove(struct i2c_client *client)
> +{
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct hm1246 *hm1246 = to_hm1246(sd);
> +
> + v4l2_async_unregister_subdev(&hm1246->sd);
> + v4l2_subdev_cleanup(sd);
> + media_entity_cleanup(&hm1246->sd.entity);
> + v4l2_ctrl_handler_free(&hm1246->ctrls);
[Severity: High]
Could the order of these cleanup calls lead to a use-after-free?
Calling v4l2_subdev_cleanup() frees the subdevice's active state memory
before v4l2_ctrl_handler_free() destroys the controls. If a concurrent
VIDIOC_S_CTRL ioctl is executing hm1246_set_ctrl(), it could safely
dereference the active state via v4l2_subdev_get_locked_active_state()
since the control handler is still active. If the state is freed underneath
it during removal, this would cause a use-after-free.
> +
> + pm_runtime_disable(&client->dev);
> + if (!pm_runtime_status_suspended(&client->dev)) {
> + hm1246_power_off(hm1246->dev);
> + pm_runtime_set_suspended(&client->dev);
> + }
> +}
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260622-hm1246-v11-0-c62ef9516ab1@emfend.at?part=2
^ permalink raw reply
* Re: [PATCH 0/5] Shikra: Add DT support for ice, rng and qce
From: Bartosz Golaszewski @ 2026-06-22 8:25 UTC (permalink / raw)
To: Eric Biggers
Cc: Herbert Xu, David S. Miller, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Vinod Koul, Thara Gopinath,
Konrad Dybcio, Frank Li, Andy Gross, Harshal Dev, linux-arm-msm,
linux-crypto, devicetree, linux-kernel, dmaengine, Kuldeep Singh
In-Reply-To: <20260619164506.GA3223@sol>
On Fri, 19 Jun 2026 18:45:06 +0200, Eric Biggers <ebiggers@kernel.org> said:
> On Fri, Jun 19, 2026 at 02:13:28PM +0530, Kuldeep Singh wrote:
>> On 21-05-2026 18:47, Kuldeep Singh wrote:
>> > This patchseries attempt to enable sdhc-ice, rng and qce on shikra
>> > platform similar to other platforms.
>> >
>> > Previously, the 3 dt-bindigs/DT changes were sent as individual series
>> > and with feedback received, clubbed them together as all belong to same
>> > crypto subsystem.
>> >
>> > Here's link to old patchsets.
>> > QCE: https://lore.kernel.org/lkml/20260515-shikra_qcrypto-v1-0-80f07b345c29@oss.qualcomm.com/
>>
>> Hi Eric,
>>
>> As selftests issues for QCE are now fixed[1], so shikra series should be
>> good to proceed? as your concerns[2] are now addressed.
>> I am waiting for merge window to end and will send next rev post that.
>>
>> [1]
>> https://lore.kernel.org/linux-arm-msm/20260617-qce-fix-self-tests-v3-0-ecc2b4dedcfd@oss.qualcomm.com/
>> [2] https://lore.kernel.org/lkml/20260522024912.GC5937@quark/
>
> If you think that then it sounds like you need to read what I actually
> said. The fixes are appreciated but don't change the big picture.
>
> - Eric
>
Eric,
I mentioned it in another thread[1]. This series is not adding any new features
to the QCE driver, it describes the hardware. The SoC *does have* this IP and
no matter the state of the support in the kernel, there's nothing wrong in
extending the existing bindings and adding new dts nodes.
Thanks,
Bartosz
[1] https://lore.kernel.org/all/CAMRc=MfY-tmMCdw9FVBgfkX-FvB5Nx2X06S023GhASenSCQSNA@mail.gmail.com/
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox