Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v5 07/12] clk: zte: Add regmap based clocks
From: Stefan Dösinger @ 2026-06-28 19:59 UTC (permalink / raw)
  To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Brian Masney
  Cc: linux-clk, devicetree, linux-kernel, linux-arm-kernel,
	Stefan Dösinger
In-Reply-To: <20260628-zx29clk-v5-0-79ff044e4192@gmail.com>

This is based on meson/clk-regmap.c, although slightly simplified. I
have kept the copyright lines at the top of the file to indicate its
origin.

I see that numerous clock drivers have their own incarnation of regmap
based mux/div/gate clocks. If there is any version of it that is likely
to be elevated to shared code liks clk-gate.c I'll copy that and try to
use it as unmodified as possible.

Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>

---

Version 5: Use regmap_test_bits in zte_clk_regmap_gate_is_enabled
---
 drivers/clk/zte/clk-regmap.c | 221 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 218 insertions(+), 3 deletions(-)

diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c
index 7908f1562f63..903998ca9508 100644
--- a/drivers/clk/zte/clk-regmap.c
+++ b/drivers/clk/zte/clk-regmap.c
@@ -6,25 +6,240 @@
  * Author: Stefan Dösinger <stefandoesinger@gmail.com>
  */
 
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+
 #include "clk-zx.h"
 
+struct zte_clk_regmap {
+	struct clk_hw	hw;
+	struct regmap	*map;
+	u16		reg;
+	u8		shift;
+	u8		size;
+};
+
+static inline struct zte_clk_regmap *to_zte_clk_regmap(struct clk_hw *hw)
+{
+	return container_of(hw, struct zte_clk_regmap, hw);
+}
+
+static int zte_clk_regmap_gate_enable(struct clk_hw *hw)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+	return regmap_set_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static void zte_clk_regmap_gate_disable(struct clk_hw *hw)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+	regmap_clear_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static int zte_clk_regmap_gate_is_enabled(struct clk_hw *hw)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+	return regmap_test_bits(clk->map, clk->reg, BIT(clk->shift));
+}
+
+static const struct clk_ops zte_clk_regmap_gate_ops = {
+	.enable		= zte_clk_regmap_gate_enable,
+	.disable	= zte_clk_regmap_gate_disable,
+	.is_enabled	= zte_clk_regmap_gate_is_enabled,
+};
+
 int zx_clk_register_gates(struct device *dev, struct regmap *regmap,
 			  const struct zx_gate_desc *desc, unsigned int num,
 			  struct clk_hw_onecell_data *clocks)
 {
-	return -ENODEV;
+	struct zte_clk_regmap *clk;
+	unsigned int i;
+	int res;
+
+	for (i = 0; i < num; ++i) {
+		struct clk_init_data init = {};
+
+		clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+		if (!clk)
+			return -ENOMEM;
+
+		init.name = desc[i].name;
+		init.ops = &zte_clk_regmap_gate_ops;
+		init.parent_names = &desc[i].parent;
+		init.num_parents = 1;
+		init.flags = CLK_SET_RATE_PARENT | desc[i].flags;
+		clk->hw.init = &init;
+		clk->map = regmap;
+		clk->reg = desc[i].reg;
+		clk->shift = desc[i].shift;
+		clk->size = 1;
+
+		res = devm_clk_hw_register(dev, &clk->hw);
+		if (res)
+			return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+		if (desc[i].id)
+			clocks->hws[desc[i].id] = &clk->hw;
+	}
+
+	return 0;
+}
+
+static unsigned long zte_clk_regmap_div_recalc_rate(struct clk_hw *hw,
+						unsigned long prate)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(clk->map, clk->reg, &val);
+	if (ret)
+		/* Gives a hint that something is wrong */
+		return 0;
+
+	val >>= clk->shift;
+	val &= clk_div_mask(clk->size);
+	return divider_recalc_rate(hw, prate, val, NULL, 0, clk->size);
 }
 
+static int zte_clk_regmap_div_determine_rate(struct clk_hw *hw,
+					 struct clk_rate_request *req)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+
+	return divider_determine_rate(hw, req, NULL, clk->size, 0);
+}
+
+static int zte_clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+	unsigned int val;
+	int ret;
+
+	ret = divider_get_val(rate, parent_rate, NULL, clk->size, 0);
+	if (ret < 0)
+		return ret;
+
+	val = (unsigned int)ret << clk->shift;
+	return regmap_update_bits(clk->map, clk->reg, clk_div_mask(clk->size) << clk->shift, val);
+};
+
+static const struct clk_ops zte_clk_regmap_divider_ops = {
+	.recalc_rate = zte_clk_regmap_div_recalc_rate,
+	.determine_rate = zte_clk_regmap_div_determine_rate,
+	.set_rate = zte_clk_regmap_div_set_rate,
+};
+
 int zx_clk_register_dividers(struct device *dev, struct regmap *regmap,
 			     const struct zx_div_desc *desc, unsigned int num,
 			     struct clk_hw_onecell_data *clocks)
 {
-	return -ENODEV;
+	struct zte_clk_regmap *clk;
+	unsigned int i;
+	int res;
+
+	for (i = 0; i < num; ++i) {
+		struct clk_init_data init = {};
+
+		clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+		if (!clk)
+			return -ENOMEM;
+
+		init.name = desc[i].name;
+		init.ops = &zte_clk_regmap_divider_ops;
+		init.parent_names = &desc[i].parent;
+		init.num_parents = 1;
+		init.flags = CLK_SET_RATE_PARENT;
+		clk->hw.init = &init;
+		clk->map = regmap;
+		clk->reg = desc[i].reg;
+		clk->shift = desc[i].shift;
+		clk->size = desc[i].size;
+
+		res = devm_clk_hw_register(dev, &clk->hw);
+		if (res)
+			return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+		if (desc[i].id)
+			clocks->hws[desc[i].id] = &clk->hw;
+	}
+
+	return 0;
 }
 
+static u8 zte_clk_regmap_mux_get_parent(struct clk_hw *hw)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(clk->map, clk->reg, &val);
+	if (ret)
+		return 0xff;
+
+	val >>= clk->shift;
+	val &= GENMASK(clk->size - 1, 0);
+	return clk_mux_val_to_index(hw, NULL, 0, val);
+}
+
+static int zte_clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct zte_clk_regmap *clk = to_zte_clk_regmap(hw);
+	unsigned int val = clk_mux_index_to_val(NULL, 0, index);
+
+	return regmap_update_bits(clk->map, clk->reg,
+				  GENMASK(clk->size - 1, 0) << clk->shift,
+				  val << clk->shift);
+}
+
+static int zte_clk_regmap_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+	return clk_mux_determine_rate_flags(hw, req, 0);
+}
+
+static const struct clk_ops zte_clk_regmap_mux_ops = {
+	.get_parent = zte_clk_regmap_mux_get_parent,
+	.set_parent = zte_clk_regmap_mux_set_parent,
+	.determine_rate = zte_clk_regmap_mux_determine_rate,
+};
+
 int zx_clk_register_muxes(struct device *dev, struct regmap *regmap,
 			  const struct zx_mux_desc *desc, unsigned int num,
 			  struct clk_hw_onecell_data *clocks)
 {
-	return -ENODEV;
+	struct zte_clk_regmap *clk;
+	unsigned int i;
+	int res;
+
+	for (i = 0; i < num; ++i) {
+		struct clk_init_data init = {};
+
+		clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL);
+		if (!clk)
+			return -ENOMEM;
+
+		init.name = desc[i].name;
+		init.ops = &zte_clk_regmap_mux_ops;
+		init.parent_names = desc[i].parents;
+		init.num_parents = desc[i].num_parents;
+		clk->hw.init = &init;
+		clk->map = regmap;
+		clk->reg = desc[i].reg;
+		clk->shift = desc[i].shift;
+		clk->size = desc[i].size;
+
+		res = devm_clk_hw_register(dev, &clk->hw);
+		if (res)
+			return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].name);
+
+		if (desc[i].id)
+			clocks->hws[desc[i].id] = &clk->hw;
+	}
+
+	return 0;
 }

-- 
2.53.0



^ permalink raw reply related

* [PATCH v3] irqchip/gic-v3-its: Fix OF node reference leak
From: Yuho Choi @ 2026-06-28 22:07 UTC (permalink / raw)
  To: Marc Zyngier, Thomas Gleixner; +Cc: linux-arm-kernel, Yuho Choi

of_get_cpu_node() returns a referenced device node. In
its_cpu_init_collection(), the Cavium 23144 workaround only uses the
node to compare the CPU NUMA node, but the reference is never dropped.

Use the device_node cleanup helper for the CPU node reference so it is
released when leaving the workaround block, including the NUMA mismatch
return path.

Fixes: fbf8f40e1658 ("irqchip/gicv3-its: numa: Enable workaround for Cavium thunderx erratum 23144")
Signed-off-by: Yuho Choi <dbgh9129@gmail.com>
Acked-by: Marc Zyngier <maz@kernel.org>
---
Changes in v3:
- Keep the __free(device_node) assignment on a single line.
- Fix indentation in the Cavium 23144 workaround block.
- Add Marc's Acked-by.
Changes in v2:
- Use __free(device_node) for the CPU node reference.
- Correct the Fixes tag to fbf8f40e1658.
 drivers/irqchip/irq-gic-v3-its.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index b57d81ad33a0..6f5811aae59c 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -3290,11 +3290,9 @@ static void its_cpu_init_collection(struct its_node *its)
 
 	/* avoid cross node collections and its mapping */
 	if (its->flags & ITS_FLAGS_WORKAROUND_CAVIUM_23144) {
-		struct device_node *cpu_node;
+		struct device_node *cpu_node __free(device_node) = of_get_cpu_node(cpu, NULL);
 
-		cpu_node = of_get_cpu_node(cpu, NULL);
-		if (its->numa_node != NUMA_NO_NODE &&
-			its->numa_node != of_node_to_nid(cpu_node))
+		if (its->numa_node != NUMA_NO_NODE && its->numa_node != of_node_to_nid(cpu_node))
 			return;
 	}
 
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH v3 1/5] dmaengine: sun6i-dma: Refactor to support A733 interrupt and register handling
From: Andre Przywara @ 2026-06-28 22:35 UTC (permalink / raw)
  To: Yuanshen Cao
  Cc: conor+dt, mripard, krzk+dt, robh, samuel, wens, jernej.skrabec,
	Frank.Li, vkoul, dmaengine, linux-arm-kernel, linux-sunxi,
	devicetree, linux-kernel, Frank Li
In-Reply-To: <20260622-sun60i-a733-dma-v3-1-f697ef296cbc@gmail.com>

On Mon, 22 Jun 2026 01:36:23 +0000
Yuanshen Cao <alex.caoys@gmail.com> wrote:

Hi,

first, many thanks for sending this, also for structuring the changes
nicely, so that they remain reviewable!

> Refactor to support the Allwinner A733 DMA controller. Currently, the
> `sun6i-dma` driver has several functions related to interrupt handling
> (reading/writing interrupt enable and status registers) and register
> dumping that are hardcoded.
> 
> To support the A733, which has different register layouts and interrupt
> handling logic, these functions are being moved into the
> `sun6i_dma_config` structure as function pointers.

So I see that this driver already makes use of per-device function
pointer, though personally I don't like this approach very much, as it
decreases the readability, and suggests significant differences between
the SoC generations that are not really there: each function just reads
or write an MMIO register, it's just the offset that differs.

So I think it's better to express the differences through data
entries in the config struct, for the IRQ enable/stat functions I think
this should be something like this:

struct sun6i_dma_config {
	...
	u32	irq_stride;
	u32	irq_en_offset;
	u32	irq_stat_offset;
	...
};

-	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
+	irq_val = readl(sdev->base + sdev->cfg->irq_en_offset + irq_reg * sdev->cfg->irq_stride);

the existing configs set .stride to 0x04, and .en_offset to 0x0, the
A733 later uses .stride = 0x40 and .en_offset = 0x134.
Maybe we still move that now longish line into a helper function, but
not a config specific one. 

I think that's more readable, and avoids unnecessary redirections and
potential pipeline stalls.

dump_com_regs is a different story, since the two instances of that
function are significantly different.

What do you think?

> This allows the
> driver to use a polymorphic approach where the specific implementation
> is determined by the hardware configuration assigned during device
> probing.
> 
> Changes:
> - Added function pointers to `struct sun6i_dma_config` for:

By the way: the preferred style to list changes in commit messages in
imperative mood [1], not in past tense. Think about you ask the
code base what to change:

Add function pointers to ...
Implement generic functions ...

Cheers,
Andre

[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst#n94

>     - `dump_com_regs`
>     - `read_irq_en`
>     - `write_irq_en`
>     - `read_irq_stat`
>     - `write_irq_stat`
> - Implemented generic `sun6i_read/write_irq_*` functions for existing
>   hardware.
> - Added a macro and updated existing `sun6i_dma_config` instances (A31,
>   A23, H3, A64, A100, H6, V3S) to use these new function pointers.
> 
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Yuanshen Cao <alex.caoys@gmail.com>
> ---
>  drivers/dma/sun6i-dma.c | 50 ++++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 45 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
> index a9a254dbf8cb..ef3052c4ab36 100644
> --- a/drivers/dma/sun6i-dma.c
> +++ b/drivers/dma/sun6i-dma.c
> @@ -138,6 +138,11 @@ struct sun6i_dma_config {
>  	void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst);
>  	void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq);
>  	void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode);
> +	void (*dump_com_regs)(struct sun6i_dma_dev *sdev);
> +	u32 (*read_irq_en)(struct sun6i_dma_dev *sdev, u32 irq_reg);
> +	void (*write_irq_en)(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 irq_val);
> +	u32 (*read_irq_stat)(struct sun6i_dma_dev *sdev, u32 irq_reg);
> +	void (*write_irq_stat)(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 status);
>  	u32 src_burst_lengths;
>  	u32 dst_burst_lengths;
>  	u32 src_addr_widths;
> @@ -347,6 +352,26 @@ static void sun6i_set_mode_h6(u32 *p_cfg, s8 src_mode, s8 dst_mode)
>  		  DMA_CHAN_CFG_DST_MODE_H6(dst_mode);
>  }
>  
> +static u32 sun6i_read_irq_en(struct sun6i_dma_dev *sdev, u32 irq_reg)
> +{
> +	return readl(sdev->base + DMA_IRQ_EN(irq_reg));
> +}
> +
> +static void sun6i_write_irq_en(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 irq_val)
> +{
> +	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
> +}
> +
> +static u32 sun6i_read_irq_stat(struct sun6i_dma_dev *sdev, u32 irq_reg)
> +{
> +	return readl(sdev->base + DMA_IRQ_STAT(irq_reg));
> +}
> +
> +static void sun6i_write_irq_stat(struct sun6i_dma_dev *sdev, u32 irq_reg, u32 status)
> +{
> +	writel(status, sdev->base + DMA_IRQ_STAT(irq_reg));
> +}
> +
>  static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
>  {
>  	struct sun6i_desc *txd = pchan->desc;
> @@ -460,16 +485,16 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
>  
>  	vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
>  
> -	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
> +	irq_val = sdev->cfg->read_irq_en(sdev, irq_reg);
>  	irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) <<
>  			(irq_offset * DMA_IRQ_CHAN_WIDTH));
>  	irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH);
> -	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
> +	sdev->cfg->write_irq_en(sdev, irq_reg, irq_val);
>  
>  	writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
>  	writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE);
>  
> -	sun6i_dma_dump_com_regs(sdev);
> +	sdev->cfg->dump_com_regs(sdev);
>  	sun6i_dma_dump_chan_regs(sdev, pchan);
>  
>  	return 0;
> @@ -549,14 +574,14 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
>  	u32 status;
>  
>  	for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) {
> -		status = readl(sdev->base + DMA_IRQ_STAT(i));
> +		status = sdev->cfg->read_irq_stat(sdev, i);
>  		if (!status)
>  			continue;
>  
>  		dev_dbg(sdev->slave.dev, "DMA irq status %s: 0x%x\n",
>  			str_high_low(i), status);
>  
> -		writel(status, sdev->base + DMA_IRQ_STAT(i));
> +		sdev->cfg->write_irq_stat(sdev, i, status);
>  
>  		for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
>  			pchan = sdev->pchans + j;
> @@ -1101,6 +1126,13 @@ static inline void sun6i_dma_free(struct sun6i_dma_dev *sdev)
>  	}
>  }
>  
> +#define SUN6I_DMA_IRQ_A31_COMMON_OPS	\
> +	.dump_com_regs    = sun6i_dma_dump_com_regs,	\
> +	.read_irq_en      = sun6i_read_irq_en,	\
> +	.write_irq_en     = sun6i_write_irq_en,	\
> +	.read_irq_stat    = sun6i_read_irq_stat,	\
> +	.write_irq_stat   = sun6i_write_irq_stat,
> +
>  /*
>   * For A31:
>   *
> @@ -1132,6 +1164,7 @@ static struct sun6i_dma_config sun6i_a31_dma_cfg = {
>  	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1155,6 +1188,7 @@ static struct sun6i_dma_config sun8i_a23_dma_cfg = {
>  	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
> @@ -1173,6 +1207,7 @@ static struct sun6i_dma_config sun8i_a83t_dma_cfg = {
>  	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1200,6 +1235,7 @@ static struct sun6i_dma_config sun8i_h3_dma_cfg = {
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1221,6 +1257,7 @@ static struct sun6i_dma_config sun50i_a64_dma_cfg = {
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1244,6 +1281,7 @@ static struct sun6i_dma_config sun50i_a100_dma_cfg = {
>  			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
>  	.has_high_addr = true,
>  	.has_mbus_clk = true,
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1266,6 +1304,7 @@ static struct sun6i_dma_config sun50i_h6_dma_cfg = {
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_8_BYTES),
>  	.has_mbus_clk = true,
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  /*
> @@ -1289,6 +1328,7 @@ static struct sun6i_dma_config sun8i_v3s_dma_cfg = {
>  	.dst_addr_widths   = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
>  			     BIT(DMA_SLAVE_BUSWIDTH_4_BYTES),
> +	SUN6I_DMA_IRQ_A31_COMMON_OPS
>  };
>  
>  static const struct of_device_id sun6i_dma_match[] = {
> 



^ permalink raw reply

* Re: [PATCH v3 4/8] arm64: dts: qcom: shikra: Add Adreno SMMU node
From: Dmitry Baryshkov @ 2026-06-28 22:49 UTC (permalink / raw)
  To: Akhil P Oommen
  Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson,
	Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-arm-kernel, iommu, Imran Shaik,
	Komal Bajaj
In-Reply-To: <20260628-shikra-gpu-v3-4-9b28a3b167e1@oss.qualcomm.com>

On Sun, Jun 28, 2026 at 11:53:57PM +0530, Akhil P Oommen wrote:
> From: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
> 
> Add the Adreno GPU IOMMU (adreno_smmu) node for the Shikra SoC.
> 
> Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
> Signed-off-by: Imran Shaik <imran.shaik@oss.qualcomm.com>
> Signed-off-by: Komal Bajaj <komal.bajaj@oss.qualcomm.com>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/shikra.dtsi | 29 +++++++++++++++++++++++++++++
>  1 file changed, 29 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry


^ permalink raw reply

* Re: [PATCH v3 5/8] arm64: dts: qcom: shikra: Add A704 GPU support
From: Dmitry Baryshkov @ 2026-06-28 22:50 UTC (permalink / raw)
  To: Akhil P Oommen
  Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson,
	Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-arm-kernel, iommu,
	Aditya Sherawat
In-Reply-To: <20260628-shikra-gpu-v3-5-9b28a3b167e1@oss.qualcomm.com>

On Sun, Jun 28, 2026 at 11:53:58PM +0530, Akhil P Oommen wrote:
> From: Aditya Sherawat <asherawa@qti.qualcomm.com>
> 
> Add the A704 GPU and GMU wrapper nodes with register maps, clocks,
> interconnects, IOMMU, OPP table and the zap-shader region.
> 
> Signed-off-by: Aditya Sherawat <asherawa@qti.qualcomm.com>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/shikra.dtsi | 98 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 98 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry


^ permalink raw reply

* Re: [PATCH v3 6/8] arm64: dts: qcom: shikra-cqm-evk: Enable A704 GPU
From: Dmitry Baryshkov @ 2026-06-28 22:53 UTC (permalink / raw)
  To: Akhil P Oommen
  Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson,
	Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-arm-kernel, iommu,
	Aditya Sherawat
In-Reply-To: <20260628-shikra-gpu-v3-6-9b28a3b167e1@oss.qualcomm.com>

On Sun, Jun 28, 2026 at 11:53:59PM +0530, Akhil P Oommen wrote:
> From: Aditya Sherawat <asherawa@qti.qualcomm.com>
> 
> Enable the A704 GPU and configure its zap-shader firmware on the
> Shikra CQM EVK board.
> 
> Signed-off-by: Aditya Sherawat <asherawa@qti.qualcomm.com>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/shikra-cqm-evk.dts | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry


^ permalink raw reply

* Re: [PATCH v3 7/8] arm64: dts: qcom: shikra-cqs-evk: Enable A704 GPU
From: Dmitry Baryshkov @ 2026-06-28 22:53 UTC (permalink / raw)
  To: Akhil P Oommen
  Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson,
	Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-arm-kernel, iommu,
	Aditya Sherawat
In-Reply-To: <20260628-shikra-gpu-v3-7-9b28a3b167e1@oss.qualcomm.com>

On Sun, Jun 28, 2026 at 11:54:00PM +0530, Akhil P Oommen wrote:
> From: Aditya Sherawat <asherawa@qti.qualcomm.com>
> 
> Enable the A704 GPU and configure its zap-shader firmware on the
> Shikra CQS EVK board.
> 
> Signed-off-by: Aditya Sherawat <asherawa@qti.qualcomm.com>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/shikra-cqs-evk.dts | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry


^ permalink raw reply

* [PATCH v2 3/4] arm64: dts: am62p5-var-som-symphony: add touchscreen support
From: Stefano Radaelli @ 2026-06-28 20:56 UTC (permalink / raw)
  To: linux-kernel, devicetree, linux-arm-kernel
  Cc: pierluigi.p, matthias.p, Stefano Radaelli, Nishanth Menon,
	Vignesh Raghavendra, Tero Kristo, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
In-Reply-To: <cover.1782680023.git.stefano.r@variscite.com>

From: Stefano Radaelli <stefano.r@variscite.com>

Add support for the capacitive touchscreen on the Symphony carrier
board.

Describe the FT5x06 touchscreen controller, configure its interrupt,
and mark it as a wakeup source.

Signed-off-by: Stefano Radaelli <stefano.r@variscite.com>
---
v1->v2:
 - Fix commit message

 .../dts/ti/k3-am62p5-var-som-symphony.dts     | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts b/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
index 5ba4ed56755b..5c41647ff43f 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-var-som-symphony.dts
@@ -293,6 +293,21 @@ &main_i2c1 {
 	clock-frequency = <400000>;
 	status = "okay";
 
+	/* Capacitive touch controller */
+	ft5x06_ts: touchscreen@38 {
+		compatible = "edt,edt-ft5206";
+		reg = <0x38>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_captouch_pins>;
+		interrupt-parent = <&main_gpio1>;
+		interrupts = <16 IRQ_TYPE_EDGE_FALLING>;
+		touchscreen-size-x = <800>;
+		touchscreen-size-y = <480>;
+		touchscreen-inverted-x;
+		touchscreen-inverted-y;
+		wakeup-source;
+	};
+
 	rtc@68 {
 		compatible = "dallas,ds1337";
 		reg = <0x68>;
@@ -307,6 +322,12 @@ &main_mcan0 {
 };
 
 &main_pmx0 {
+	pinctrl_captouch_pins: main-captouch-default-pins {
+		pinctrl-single,pins = <
+			AM62PX_IOPAD(0x01b8, PIN_INPUT, 7) /* (E20) SPI0_CS1.GPIO1_16 */
+		>;
+	};
+
 	pinctrl_extcon: main-extcon-pins {
 		pinctrl-single,pins = <
 			AM62PX_IOPAD(0x01a8, PIN_INPUT, 7) /* (F25) MCASP0_AFSX.GPIO1_12 */
-- 
2.47.3



^ permalink raw reply related

* [PATCH 0/4] ARM: dts: helios4: add regulator supplies and thermal cooling
From: Rosen Penev @ 2026-06-28 23:00 UTC (permalink / raw)
  To: devicetree
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dennis Gilmore,
	moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
	open list

This series adds missing vcc-supply properties to the EEPROM and GPIO
expander on the Helios4, adds SATA regulator supplies, and wires the
on-board LM75 temperature sensor into a thermal zone with active fan
cooling.

Rosen Penev (4):
  ARM: dts: helios4: add vcc-supply to EEPROM
  ARM: dts: helios4: add vcc-supply to GPIO expander
  ARM: dts: helios4: add SATA regulator supplies
  ARM: dts: helios4: wire LM75 into a thermal zone with fan cooling

 .../boot/dts/marvell/armada-388-helios4.dts   | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

-- 
2.54.0



^ permalink raw reply

* [PATCH 1/4] ARM: dts: helios4: add vcc-supply to EEPROM
From: Rosen Penev @ 2026-06-28 23:00 UTC (permalink / raw)
  To: devicetree
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dennis Gilmore,
	moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
	open list
In-Reply-To: <20260628230042.1204293-1-rosenp@gmail.com>

The at24 driver requests a 'vcc' supply for the EEPROM, producing
'supply vcc not found, using dummy regulator' at boot when the
property is missing.

The EEPROM sits on the Helios 4 and is powered by the
same always-on 3.3V rail used by other on-board I2C devices.
Add vcc-supply = <&reg_3p3v> to silence the warning.

Fixes: ced8025b569e ("ARM: dts: armada388-helios4")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 arch/arm/boot/dts/marvell/armada-388-helios4.dts | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/marvell/armada-388-helios4.dts b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
index 390e98df49c9..05540b8012c2 100644
--- a/arch/arm/boot/dts/marvell/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
@@ -201,6 +201,10 @@ temp_sensor: temp@4c {
 					reg = <0x4c>;
 					vcc-supply = <&reg_3p3v>;
 				};
+
+				eeprom@53 {
+					vcc-supply = <&reg_3p3v>;
+				};
 			};
 
 			i2c@11100 {
-- 
2.54.0



^ permalink raw reply related

* [PATCH 4/4] ARM: dts: helios4: wire LM75 into a thermal zone with fan cooling
From: Rosen Penev @ 2026-06-28 23:00 UTC (permalink / raw)
  To: devicetree
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dennis Gilmore,
	moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
	open list
In-Reply-To: <20260628230042.1204293-1-rosenp@gmail.com>

The LM75 temperature sensor on i2c0 creates a hwmon interface but was
not referenced by any thermal zone, producing:
  hwmon hwmon0: temp1_input not attached to any thermal zone

Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 .../boot/dts/marvell/armada-388-helios4.dts   | 33 +++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/arch/arm/boot/dts/marvell/armada-388-helios4.dts b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
index 626a7339a5d0..6e0452217265 100644
--- a/arch/arm/boot/dts/marvell/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
@@ -8,6 +8,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/thermal/thermal.h>
 #include "armada-388.dtsi"
 #include "armada-38x-solidrun-microsom.dtsi"
 
@@ -68,6 +69,35 @@ reg_5p0v_usb: regulator-5v-usb {
 		vin-supply = <&reg_12v>;
 	};
 
+	thermal-zones {
+		board-thermal {
+			polling-delay-passive = <2000>;
+			polling-delay = <10000>;
+			thermal-sensors = <&temp_sensor>;
+
+			trips {
+				board_alert: board-alert {
+					temperature = <55000>;
+					hysteresis = <5000>;
+					type = "passive";
+				};
+				board_crit: board-crit {
+					temperature = <85000>;
+					hysteresis = <2000>;
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&board_alert>;
+					cooling-device = <&fan1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+							 <&fan2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
 	system-leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
@@ -129,6 +159,7 @@ fan1: j10-pwm {
 		pwms = <&gpio1 9 40000>;	/* Target freq:25 kHz */
 		pinctrl-names = "default";
 		pinctrl-0 = <&helios_fan1_pins>;
+		#cooling-cells = <2>;
 	};
 
 	fan2: j17-pwm {
@@ -136,6 +167,7 @@ fan2: j17-pwm {
 		pwms = <&gpio1 23 40000>;	/* Target freq:25 kHz */
 		pinctrl-names = "default";
 		pinctrl-0 = <&helios_fan2_pins>;
+		#cooling-cells = <2>;
 	};
 
 	usb2_phy: usb2-phy {
@@ -201,6 +233,7 @@ temp_sensor: temp@4c {
 					compatible = "ti,lm75";
 					reg = <0x4c>;
 					vcc-supply = <&reg_3p3v>;
+					#thermal-sensor-cells = <0>;
 				};
 
 				eeprom@53 {
-- 
2.54.0



^ permalink raw reply related

* [PATCH 2/4] ARM: dts: helios4: add vcc-supply to GPIO expander
From: Rosen Penev @ 2026-06-28 23:00 UTC (permalink / raw)
  To: devicetree
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dennis Gilmore,
	moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
	open list
In-Reply-To: <20260628230042.1204293-1-rosenp@gmail.com>

The pca953x driver requests a 'vcc' supply, producing:
  pca953x 0-0020: supply vcc not found, using dummy regulator

The PCA9655 (PCA9555-compatible) expander is powered by the same
always-on 3.3V rail as the other I2C devices on the bus.  Add
vcc-supply = <&reg_3p3v> to silence the warning.

Fixes: ced8025b569e ("ARM: dts: armada388-helios4")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 arch/arm/boot/dts/marvell/armada-388-helios4.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/marvell/armada-388-helios4.dts b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
index 05540b8012c2..cf0432a0e71a 100644
--- a/arch/arm/boot/dts/marvell/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
@@ -169,6 +169,7 @@ expander0: gpio-expander@20 {
 					gpio-controller;
 					#gpio-cells = <2>;
 					reg = <0x20>;
+					vcc-supply = <&reg_3p3v>;
 					pinctrl-names = "default";
 					pinctrl-0 = <&pca0_pins>;
 					interrupt-parent = <&gpio0>;
-- 
2.54.0



^ permalink raw reply related

* [PATCH 3/4] ARM: dts: helios4: add SATA regulator supplies
From: Rosen Penev @ 2026-06-28 23:00 UTC (permalink / raw)
  To: devicetree
  Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Dennis Gilmore,
	moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
	open list
In-Reply-To: <20260628230042.1204293-1-rosenp@gmail.com>

The ahci-mvebu driver and libahci_platform request three supplies
on SATA controller and port nodes:
  - ahci-supply  (controller power)
  - phy-supply   (PHY power)
  - target-supply (disk power per port)

Without them the regulator core prints notices at boot, e.g.:
  supply ahci not found, using dummy regulator
  supply phy not found, using dummy regulator
  supply target not found, using dummy regulator

The SATA controller and PHY inside the Armada 388 SoC are powered
by the 3.3V I/O rail; the four disk bays are powered by the 5V HDD
rail.  Wire the existing fixed regulators accordingly.

Fixes: ced8025b569e ("ARM: dts: armada388-helios4")
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 arch/arm/boot/dts/marvell/armada-388-helios4.dts | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/marvell/armada-388-helios4.dts b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
index cf0432a0e71a..626a7339a5d0 100644
--- a/arch/arm/boot/dts/marvell/armada-388-helios4.dts
+++ b/arch/arm/boot/dts/marvell/armada-388-helios4.dts
@@ -222,13 +222,17 @@ sata@a8000 {
 				status = "okay";
 				#address-cells = <1>;
 				#size-cells = <0>;
+				ahci-supply = <&reg_3p3v>;
+				phy-supply = <&reg_3p3v>;
 
 				sata0: sata-port@0 {
 					reg = <0>;
+					target-supply = <&reg_5p0v_hdd>;
 				};
 
 				sata1: sata-port@1 {
 					reg = <1>;
+					target-supply = <&reg_5p0v_hdd>;
 				};
 			};
 
@@ -236,13 +240,17 @@ sata@e0000 {
 				status = "okay";
 				#address-cells = <1>;
 				#size-cells = <0>;
+				ahci-supply = <&reg_3p3v>;
+				phy-supply = <&reg_3p3v>;
 
 				sata2: sata-port@0 {
 					reg = <0>;
+					target-supply = <&reg_5p0v_hdd>;
 				};
 
 				sata3: sata-port@1 {
 					reg = <1>;
+					target-supply = <&reg_5p0v_hdd>;
 				};
 			};
 
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH rc v6 1/7] iommu/arm-smmu-v3: Add arm_smmu_kdump_adopt_strtab() for kdump
From: Pranjal Shrivastava @ 2026-06-28 23:00 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jgg, joro, kees, baolu.lu, kevin.tian,
	miko.lenczewski, smostafa, linux-arm-kernel, iommu, linux-kernel,
	stable, jamien
In-Reply-To: <f3d1f938a9b4d540f67d9c1ff394bd62735a4f5c.1779265413.git.nicolinc@nvidia.com>

On Wed, May 20, 2026 at 10:03:18AM -0700, Nicolin Chen wrote:

Hi Nicolin,
> When transitioning to a kdump kernel, the primary kernel might have crashed
> while endpoint devices were actively bus-mastering DMA. Currently, the SMMU
> driver aggressively resets the hardware during probe by clearing CR0_SMMUEN
> and setting the Global Bypass Attribute (GBPA) to ABORT.
> 
> In a kdump scenario, this aggressive reset is highly destructive:
> a) If GBPA is set to ABORT, in-flight DMA will be aborted, generating fatal
>    PCIe AER or SErrors that may panic the kdump kernel
> b) If GBPA is set to BYPASS, in-flight DMA targeting some IOVAs will bypass
>    the SMMU and corrupt the physical memory at those 1:1 mapped IOVAs.
> 
> To safely absorb in-flight DMAs, a kdump kernel will have to leave SMMUEN=1
> intact and avoid modifying STRTAB_BASE, allowing HW to continue translating
> in-flight DMAs reusing the crashed kernel's page tables until the endpoint
> device drivers probe and quiesce their respective hardware.
> 
> However, the ARM SMMUv3 architecture specification states that updating the
> SMMU_STRTAB_BASE register while SMMUEN == 1 is UNPREDICTABLE or ignored.
> 
> This leaves a kdump kernel no choice but to adopt the stream table from the
> crashed kernel.
> 
> Introduce ARM_SMMU_OPT_KDUMP_ADOPT and adopt functions memremapping all the
> stream tables extracted from STRTAB_BASE and STRTAB_BASE_CFG.
> 
> Note that the adoption of the crashed kernel's stream table follows certain
> strict rules, since the old stream table might be compromised. Thus, apply
> some basic validations against the values read from the registers. If tests
> fail, it means the stream table cannot be trusted, so toss it entirely. To
> avoid OOM due to a potentially corrupted stream table, the memremap for l2
> tables is done on the kdump kernel's demand.
> 
> The new option will be set in a following change.
> 
> Fixes: b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is enabled in kdump kernel")
> Cc: stable@vger.kernel.org # v6.12+
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
> ---
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |   1 +
>  drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 254 +++++++++++++++++++-
>  2 files changed, 252 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> index ef42df4753ec4..cd60b692c3901 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
> @@ -861,6 +861,7 @@ struct arm_smmu_device {
>  #define ARM_SMMU_OPT_MSIPOLL		(1 << 2)
>  #define ARM_SMMU_OPT_CMDQ_FORCE_SYNC	(1 << 3)
>  #define ARM_SMMU_OPT_TEGRA241_CMDQV	(1 << 4)
> +#define ARM_SMMU_OPT_KDUMP_ADOPT	(1 << 5)
>  	u32				options;
>  
>  	struct arm_smmu_cmdq		cmdq;
> diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> index e8d7dbe495f03..aa6837a5daa88 100644
> --- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> +++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
> @@ -2040,16 +2040,70 @@ static void arm_smmu_init_initial_stes(struct arm_smmu_ste *strtab,
>  	}
>  }
>  
> +static int arm_smmu_kdump_adopt_l2_strtab(struct arm_smmu_device *smmu, u32 sid,
> +					  phys_addr_t base, u32 span,
> +					  struct arm_smmu_strtab_l2 **l2table)
> +{
> +	struct arm_smmu_strtab_l2 *table;
> +	size_t size;
> +
> +	/*
> +	 * Only a coherent SMMU is supported at this moment. For a non-coherent
> +	 * SMMU that wants to support ARM_SMMU_OPT_KDUMP_ADOPT, try MEMREMAP_WC.
> +	 */
> +	if (WARN_ON(!(smmu->features & ARM_SMMU_FEAT_COHERENCY)))
> +		return -EOPNOTSUPP;

We already checked this in arm_smmu_kdump_adopt_strtab_2lvl() can it
change since?

> +
> +	/*
> +	 * Retest the span in case the L1 descriptor has been overwritten since
> +	 * the adopt. Reject this master's insert; panic or SMMU-disable would
> +	 * either lose the vmcore or cascade aborts. Do not try to fix it, as it
> +	 * would break all other SIDs in the same bus (PCI case). The corruption
> +	 * blast radius is already bounded to that bus range.
> +	 */
> +	if (span != STRTAB_SPLIT + 1) {
> +		dev_err(smmu->dev,
> +			"kdump: L1[%u] span %u changed since adopt (was %u)\n",
> +			arm_smmu_strtab_l1_idx(sid), span, STRTAB_SPLIT + 1);
> +		return -EINVAL;
> +	}
> +
> +	size = (1UL << (span - 1)) * sizeof(struct arm_smmu_ste);
> +
> +	table = devm_memremap(smmu->dev, base, size, MEMREMAP_WB);

Why do we use devm_memremap() here but memremap() in the rest of the
functions (even for the L1 ptr)?

> +	if (IS_ERR(table)) {
> +		dev_err(smmu->dev,
> +			"kdump: failed to adopt l2 stream table for SID %u\n",
> +			sid);
> +		return PTR_ERR(table);
> +	}
> +
> +	*l2table = table;
> +	return 0;
> +}
> +
>  static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>  {
>  	dma_addr_t l2ptr_dma;
>  	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
>  	struct arm_smmu_strtab_l2 **l2table;
> +	u32 l1_idx = arm_smmu_strtab_l1_idx(sid);
>  
> -	l2table = &cfg->l2.l2ptrs[arm_smmu_strtab_l1_idx(sid)];
> +	l2table = &cfg->l2.l2ptrs[l1_idx];
>  	if (*l2table)
>  		return 0;
>  
> +	/* Deferred adoption of the crashed kernel's L2 table */
> +	if (smmu->options & ARM_SMMU_OPT_KDUMP_ADOPT) {
> +		u64 l2ptr = le64_to_cpu(cfg->l2.l1tab[l1_idx].l2ptr);
> +		phys_addr_t base = l2ptr & STRTAB_L1_DESC_L2PTR_MASK;
> +		u32 span = FIELD_GET(STRTAB_L1_DESC_SPAN, l2ptr);
> +
> +		if (span && base)
> +			return arm_smmu_kdump_adopt_l2_strtab(smmu, sid, base,
> +							      span, l2table);
> +	}
> +
>  	*l2table = dmam_alloc_coherent(smmu->dev, sizeof(**l2table),
>  				       &l2ptr_dma, GFP_KERNEL);
>  	if (!*l2table) {
> @@ -2061,8 +2115,7 @@ static int arm_smmu_init_l2_strtab(struct arm_smmu_device *smmu, u32 sid)
>  
>  	arm_smmu_init_initial_stes((*l2table)->stes,
>  				   ARRAY_SIZE((*l2table)->stes));
> -	arm_smmu_write_strtab_l1_desc(&cfg->l2.l1tab[arm_smmu_strtab_l1_idx(sid)],
> -				      l2ptr_dma);
> +	arm_smmu_write_strtab_l1_desc(&cfg->l2.l1tab[l1_idx], l2ptr_dma);
>  	return 0;
>  }
>  
> @@ -4556,10 +4609,204 @@ static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu)
>  	return 0;
>  }
>  
> +static int arm_smmu_kdump_adopt_strtab_2lvl(struct arm_smmu_device *smmu,
> +					    u32 cfg_reg, phys_addr_t base)
> +{
> +	u32 log2size = FIELD_GET(STRTAB_BASE_CFG_LOG2SIZE, cfg_reg);
> +	u32 split = FIELD_GET(STRTAB_BASE_CFG_SPLIT, cfg_reg);
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	u32 num_l1_ents;
> +	size_t size;
> +	int i;
> +
> +	/*
> +	 * Only a coherent SMMU is supported at this moment. For a non-coherent
> +	 * SMMU that wants to support ARM_SMMU_OPT_KDUMP_ADOPT, try MEMREMAP_WC.
> +	 */
> +	if (WARN_ON(!(smmu->features & ARM_SMMU_FEAT_COHERENCY)))
> +		return -EOPNOTSUPP;
> +
> +	if (log2size < split || log2size > smmu->sid_bits) {
> +		dev_err(smmu->dev, "kdump: log2size %u out of range [%u, %u]\n",
> +			log2size, split, smmu->sid_bits);
> +		return -EINVAL;
> +	}
> +	if (split != STRTAB_SPLIT) {
> +		dev_err(smmu->dev,
> +			"kdump: unsupported STRTAB_SPLIT %u (expected %u)\n",
> +			split, STRTAB_SPLIT);
> +		return -EINVAL;
> +	}
> +
> +	num_l1_ents = 1U << (log2size - split);
> +	if (num_l1_ents > STRTAB_MAX_L1_ENTRIES) {
> +		dev_err(smmu->dev, "kdump: l1 entries %u exceeds max %u\n",
> +			num_l1_ents, STRTAB_MAX_L1_ENTRIES);
> +		return -EINVAL;
> +	}
> +
> +	cfg->l2.num_l1_ents = num_l1_ents;
> +
> +	size = num_l1_ents * sizeof(struct arm_smmu_strtab_l1);
> +	cfg->l2.l1tab = memremap(base, size, MEMREMAP_WB);
> +	if (!cfg->l2.l1tab)
> +		return -ENOMEM;

Same here (as below, sorry reviewing it as the code flows), we should
populate cfg->l2.l1_dma here to be consistent.

> +
> +	cfg->l2.l2ptrs =
> +		kcalloc(num_l1_ents, sizeof(*cfg->l2.l2ptrs), GFP_KERNEL);
> +	if (!cfg->l2.l2ptrs)
> +		return -ENOMEM;

We shuold ummap cfg->l2.l1tab before returning -ENOMEM here

> +
> +	for (i = 0; i < num_l1_ents; i++) {
> +		u64 l2ptr = le64_to_cpu(cfg->l2.l1tab[i].l2ptr);
> +		phys_addr_t l2_base = l2ptr & STRTAB_L1_DESC_L2PTR_MASK;
> +		u32 span = FIELD_GET(STRTAB_L1_DESC_SPAN, l2ptr);
> +
> +		if (!span || !l2_base)
> +			continue;
> +
> +		if (span != STRTAB_SPLIT + 1) {
> +			dev_err(smmu->dev,
> +				"kdump: L1[%u] unsupported span %u (vs %u)\n",
> +				i, span, STRTAB_SPLIT + 1);
> +			return -EINVAL;

We leak kcalloc'd mem (l2.l2ptrs) here, also we should unmap cfg->l2.l1tab

> +		}
> +
> +		/*
> +		 * If the crashed kernel's l1 descriptors are deeply corrupted,
> +		 * blindly memremapping every l2 table here could lead to OOM.
> +		 *
> +		 * Defer the l2 memremap to arm_smmu_init_l2_strtab(), so peak
> +		 * memory is bounded by the kdump kernel's actual demand.
> +		 */
> +	}
> +
> +	return 0;
> +}
> +
> +static int arm_smmu_kdump_adopt_strtab_linear(struct arm_smmu_device *smmu,
> +					      u32 cfg_reg, phys_addr_t base)
> +{
> +	u32 log2size = FIELD_GET(STRTAB_BASE_CFG_LOG2SIZE, cfg_reg);
> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	unsigned int max_log2size;
> +	size_t size;
> +
> +	/*
> +	 * Only a coherent SMMU is supported at this moment. For a non-coherent
> +	 * SMMU that wants to support ARM_SMMU_OPT_KDUMP_ADOPT, try MEMREMAP_WC.
> +	 */
> +	if (WARN_ON(!(smmu->features & ARM_SMMU_FEAT_COHERENCY)))
> +		return -EOPNOTSUPP;
> +
> +	/* Cap the size at what the kdump kernel itself would have allocated */
> +	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
> +		max_log2size =
> +			ilog2(STRTAB_MAX_L1_ENTRIES * STRTAB_NUM_L2_STES);

Looks like we'd never hit this if condition because we'd never support a
"linear" strtab if the HW supports ARM_SMMU_FEAT_2_LVL_STRTAB. Please
see arm_smmu_init_strtab:

static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
{
	int ret;

	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
		ret = arm_smmu_init_strtab_2lvl(smmu);
	else
		ret = arm_smmu_init_strtab_linear(smmu);
	if (ret)
		return ret;

	ida_init(&smmu->vmid_map);

	return 0;
}

> +	else
> +		max_log2size = smmu->sid_bits;
> +
> +	/* cfg->linear.num_ents is unsigned int, so cap log2size at 31 */
> +	max_log2size = min(max_log2size, 31U);
> +	if (log2size > max_log2size) {
> +		dev_err(smmu->dev, "kdump: unsupported log2size %u (> %u)\n",
> +			log2size, max_log2size);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * We might end up with a num_ents != sid_bits, which is fine. In the
> +	 * ARM_SMMU_OPT_KDUMP_ADOPT case, arm_smmu_write_strtab() is bypassed.
> +	 */
> +	cfg->linear.num_ents = 1U << log2size;
> +
> +	size = cfg->linear.num_ents * sizeof(struct arm_smmu_ste);
> +	cfg->linear.table = memremap(base, size, MEMREMAP_WB);
> +	if (!cfg->linear.table)
> +		return -ENOMEM;

We seem to skips initializing cfg->linear.ste_dma (it is populated in
arm_smmu_init_strtab_linear)

While the comment notes that arm_smmu_write_strtab() is bypassed in the
kdump case, leaving cfg->linear.ste_dma uninitialized seems like a 
ticking time bomb if any other part of the driver ever uses it.

> +	return 0;
> +}
> +
> +static void arm_smmu_kdump_adopt_cleanup(void *data)
> +{
> +	struct arm_smmu_device *smmu = data;
> +	u32 cfg_reg = readl_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE_CFG);

I'm worried about reading the HW register here, since this is a devres action, it
can run after arm_smmu_device_remove() or arm_smmu_device_shutdown()
(which would call rpm_put()). Please see __device_release_driver[1]:

	pm_runtime_put_sync(dev); <--- HW turned off

	device_remove(dev);

	if (dev->bus && dev->bus->dma_cleanup)
		dev->bus->dma_cleanup(dev);

	device_unbind_cleanup(dev); <--- This is where devm_release runs
	device_links_driver_cleanup(dev);

Thus, even if we call rpm_get() here it would make no sense as the 
register contents would've been lost. Can we rely on some SW state
here? smmu->features & 2LVL or maybe add an fmt in cfg? 

> +	struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg;
> +	u32 fmt = FIELD_GET(STRTAB_BASE_CFG_FMT, cfg_reg);
> +
> +	if (fmt == STRTAB_BASE_CFG_FMT_2LVL) {
> +		kfree(cfg->l2.l2ptrs);
> +		if (cfg->l2.l1tab)
> +			memunmap(cfg->l2.l1tab);
> +	} else if (fmt == STRTAB_BASE_CFG_FMT_LINEAR) {
> +		if (cfg->linear.table)
> +			memunmap(cfg->linear.table);
> +	}
> +}
> +
> +static int arm_smmu_kdump_adopt_strtab(struct arm_smmu_device *smmu)
> +{
> +	u32 cfg_reg = readl_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE_CFG);
> +	u64 base_reg = readq_relaxed(smmu->base + ARM_SMMU_STRTAB_BASE);
> +	u32 fmt = FIELD_GET(STRTAB_BASE_CFG_FMT, cfg_reg);
> +	phys_addr_t base = base_reg & STRTAB_BASE_ADDR_MASK;
> +	int ret;
> +
> +	dev_info(smmu->dev, "kdump: adopting crashed kernel's stream table\n");

Nit: Should this be dev_info? If everything goes right, the user doesn't
need to know. dev_dbg seems more appropriate. It should only be a warn or 
err if adoption fails (which is in place).

> +
> +	if (fmt == STRTAB_BASE_CFG_FMT_2LVL) {
> +		/*
> +		 * Both kernels run on the same hardware, so it's impossible for
> +		 * kdump kernel to see the support for linear stream table only.
> +		 */
> +		if (WARN_ON(!(smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)))
> +			ret = -EINVAL;
> +		else
> +			ret = arm_smmu_kdump_adopt_strtab_2lvl(smmu, cfg_reg,
> +							       base);
> +	} else if (fmt == STRTAB_BASE_CFG_FMT_LINEAR) {
> +		/*
> +		 * In case that the old kernel for some reason used the linear

Nit: This sounds a little judgemental, what if the HW only supports
linear table? Let's drop the "for some reason" part.

> +		 * format, enforce the same format to match the adopted table.
> +		 */
> +		ret = arm_smmu_kdump_adopt_strtab_linear(smmu, cfg_reg, base);
> +		if (!ret)
> +			smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;

IIRC, this should NOT be set if we selected the linear format.
Looking at arm_smmu_init_strtab(), if the HW supports 2-level tables,
the driver unconditionally selects it. What is the expected scenario
where the previous kernel would have allocated a linear table on 2-level
capable hardware? IMO, it is a bug if we see linear fmt with this
feature set. Am I missing something?

> +	} else {
> +		dev_err(smmu->dev, "kdump: invalid STRTAB format %u\n", fmt);
> +		ret = -EINVAL;
> +	}
> +
> +	if (ret) {
> +		arm_smmu_kdump_adopt_cleanup(smmu);
> +		goto err;
> +	}
> +
> +	ret = devm_add_action_or_reset(smmu->dev, arm_smmu_kdump_adopt_cleanup,
> +				       smmu);
> +	/* devm_add_action_or_reset ran the cleanup upon failure */
> +	if (ret) {
> +		dev_warn(smmu->dev, "kdump: failed to set up cleanup action\n");
> +		goto err;
> +	}
> +
> +	return 0;
> +
> +err:
> +	dev_warn(smmu->dev, "kdump: falling back to full reset\n");
> +	memset(&smmu->strtab_cfg, 0, sizeof(smmu->strtab_cfg));
> +	smmu->options &= ~ARM_SMMU_OPT_KDUMP_ADOPT;
> +	return ret;
> +}
> +
>  static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
>  {
>  	int ret;
>  
> +	if ((smmu->options & ARM_SMMU_OPT_KDUMP_ADOPT) &&
> +	    !arm_smmu_kdump_adopt_strtab(smmu))
> +		goto out;
> +
>  	if (smmu->features & ARM_SMMU_FEAT_2_LVL_STRTAB)
>  		ret = arm_smmu_init_strtab_2lvl(smmu);
>  	else
> @@ -4567,6 +4814,7 @@ static int arm_smmu_init_strtab(struct arm_smmu_device *smmu)
>  	if (ret)
>  		return ret;
>  
> +out:
>  	ida_init(&smmu->vmid_map);
>  
>  	return 0;
> -- 
> 2.43.0
> 

Thanks,
Praan

[1] https://elixir.bootlin.com/linux/v7.1.2/source/drivers/base/dd.c#L1350


^ permalink raw reply

* [PATCH] ARM: dts: BCM5301X: EA9200: fix nvram size
From: Rosen Penev @ 2026-06-28 23:10 UTC (permalink / raw)
  To: devicetree
  Cc: Florian Fainelli, Hauke Mehrtens, Rafał Miłecki,
	Broadcom internal kernel review list, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley,
	moderated list:BROADCOM BCM5301X ARM ARCHITECTURE, open list

Fixes:

[ 0.182121] WARNING: CPU: 0 PID: 1 at drivers/nvmem/brcm_nvram.c:85 brcm_nvram_probe+0x400/0x480
[ 0.182159] Unexpected (big) NVRAM size: 1056112 B

Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 arch/arm/boot/dts/broadcom/bcm4709-linksys-ea9200.dts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/broadcom/bcm4709-linksys-ea9200.dts b/arch/arm/boot/dts/broadcom/bcm4709-linksys-ea9200.dts
index af411679a14a..37593e7582ba 100644
--- a/arch/arm/boot/dts/broadcom/bcm4709-linksys-ea9200.dts
+++ b/arch/arm/boot/dts/broadcom/bcm4709-linksys-ea9200.dts
@@ -26,7 +26,7 @@ memory@0 {
 
 	nvram@1c080000 {
 		compatible = "brcm,nvram";
-		reg = <0x1c080000 0x180000>;
+		reg = <0x1c080000 0x100000>;
 
 		et2macaddr: et2macaddr {
 			#nvmem-cell-cells = <1>;
-- 
2.54.0



^ permalink raw reply related

* [PATCH] ARM: dts: BCM5301X: drop extra AXI bus ranges that break PCIe
From: Rosen Penev @ 2026-06-28 23:11 UTC (permalink / raw)
  To: devicetree
  Cc: Florian Fainelli, Hauke Mehrtens, Rafał Miłecki,
	Broadcom internal kernel review list, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley,
	moderated list:BROADCOM BCM5301X ARM ARCHITECTURE, open list

These addresses overlap with DRAM on BCM5301X/BCM470X SoCs, causing the OF
address translation code to route PCIe MMIO accesses through the AXI bus
space instead of directly to memory, breaking PCIe. Remove the extra
ranges to restore the original single-entry mapping that only covers the
AXI peripheral register space.

Assisted-by: opencode:big-pickle
Fixes: 767012397976 ("ARM: dts: BCM5301X: Describe PCIe controllers fully")
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
 arch/arm/boot/dts/broadcom/bcm-ns.dtsi | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
index bd52de0faa3e..27a97c8122de 100644
--- a/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
+++ b/arch/arm/boot/dts/broadcom/bcm-ns.dtsi
@@ -95,10 +95,7 @@ L2: cache-controller@22000 {
 	axi@18000000 {
 		compatible = "brcm,bus-axi";
 		reg = <0x18000000 0x1000>;
-		ranges = <0x00000000 0x18000000 0x00100000>,
-			 <0x08000000 0x08000000 0x08000000>,
-			 <0x20000000 0x20000000 0x08000000>,
-			 <0x28000000 0x28000000 0x08000000>;
+		ranges = <0x00000000 0x18000000 0x00100000>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH rc v6 2/7] iommu/arm-smmu-v3: Implement is_attach_deferred() for kdump
From: Pranjal Shrivastava @ 2026-06-28 23:06 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: will, robin.murphy, jgg, joro, kees, baolu.lu, kevin.tian,
	miko.lenczewski, smostafa, linux-arm-kernel, iommu, linux-kernel,
	stable, jamien
In-Reply-To: <89cbd3760a13f11cf63f6ead12f44974511f308a.1779265413.git.nicolinc@nvidia.com>

On Wed, May 20, 2026 at 10:03:19AM -0700, Nicolin Chen wrote:
> Though the kdump kernel adopts the crashed kernel's stream table, the iommu
> core will still try to attach each probed device to a default domain, which
> overwrites the adopted STE and breaks in-flight DMA from that device.
> 
> Implement an is_attach_deferred() callback to prevent this. For each device
> that has STE.V=1 and STE.Cfg!=Abort in the adopted table, defer the default
> domain attachment, until the device driver explicitly requests it.
> 
> Fixes: b63b3439b856 ("iommu/arm-smmu-v3: Abort all transactions if SMMU is enabled in kdump kernel")
> Cc: stable@vger.kernel.org # v6.12+
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>

Reviewed-by: Pranjal Shrivastava <praan@google.com>

Thanks,
Praan


^ permalink raw reply

* Re: [PATCH v3 8/8] arm64: dts: qcom: shikra-iqs-evk: Enable A704 GPU
From: Dmitry Baryshkov @ 2026-06-28 22:53 UTC (permalink / raw)
  To: Akhil P Oommen
  Cc: Rob Clark, Sean Paul, Konrad Dybcio, Dmitry Baryshkov,
	Abhinav Kumar, Jessica Zhang, Marijn Suijten, David Airlie,
	Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Will Deacon, Robin Murphy, Joerg Roedel (AMD), Bjorn Andersson,
	Bibek Kumar Patro, linux-arm-msm, dri-devel, freedreno,
	devicetree, linux-kernel, linux-arm-kernel, iommu,
	Aditya Sherawat
In-Reply-To: <20260628-shikra-gpu-v3-8-9b28a3b167e1@oss.qualcomm.com>

On Sun, Jun 28, 2026 at 11:54:01PM +0530, Akhil P Oommen wrote:
> From: Aditya Sherawat <asherawa@qti.qualcomm.com>
> 
> Enable the A704 GPU and configure its zap-shader firmware on the
> Shikra IQS EVK board.
> 
> Signed-off-by: Aditya Sherawat <asherawa@qti.qualcomm.com>
> Signed-off-by: Akhil P Oommen <akhilpo@oss.qualcomm.com>
> ---
>  arch/arm64/boot/dts/qcom/shikra-iqs-evk.dts | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>


-- 
With best wishes
Dmitry


^ permalink raw reply

* Re: [PATCH v15 1/9] drm/bridge: Implement generic USB Type-C DP HPD bridge
From: Chaoyi Chen @ 2026-06-29  1:29 UTC (permalink / raw)
  To: Xu Yang, Heikki Krogerus
  Cc: Chaoyi Chen, Greg Kroah-Hartman, Dmitry Baryshkov, Peter Chen,
	Luca Ceresoli, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Vinod Koul, Kishon Vijay Abraham I, Heiko Stuebner, Sandy Huang,
	Andy Yan, Yubing Zhang, Frank Wang, Andrzej Hajda, Neil Armstrong,
	Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Amit Sunil Dhamne, Dragan Simic, Johan Jonker,
	Diederik de Haas, Peter Robinson, Hugh Cole-Baker, linux-usb,
	devicetree, linux-kernel, linux-phy, linux-arm-kernel,
	linux-rockchip, dri-devel
In-Reply-To: <erx73m2ueuvbzjteadjli6aki5by4pr3hyertkkqqoqwhaa4v3@5cstmshcercx>

Hello Xu Yang,

On 6/26/2026 7:15 PM, Xu Yang wrote:
> On Wed, Mar 04, 2026 at 05:41:44PM +0800, Chaoyi Chen wrote:
>> From: Chaoyi Chen <chaoyi.chen@rock-chips.com>
>>
>> The HPD function of Type-C DP is implemented through
>> drm_connector_oob_hotplug_event(). For embedded DP, it is required
>> that the DRM connector fwnode corresponds to the Type-C port fwnode.
>>
>> To describe the relationship between the DP controller and the Type-C
>> port device, we usually using drm_bridge to build a bridge chain.
>>
>> Now several USB-C controller drivers have already implemented the DP
>> HPD bridge function provided by aux-hpd-bridge.c, it will build a DP
>> HPD bridge on USB-C connector port device.
>>
>> But this requires the USB-C controller driver to manually register the
>> HPD bridge. If the driver does not implement this feature, the bridge
>> will not be create.
>>
>> So this patch implements a generic DP HPD bridge based on
>> aux-hpd-bridge.c. It will monitor Type-C bus events, and when a
>> Type-C port device containing the DP svid is registered, it will
>> create an HPD bridge for it without the need for the USB-C controller
>> driver to implement it.
>>
>> Signed-off-by: Chaoyi Chen <chaoyi.chen@rock-chips.com>
>> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
>> ---
>>
>> (no changes since v14)
>>
>> Changes in v13:
>> - Only register drm dp hpd bridge for typec port altmode device.
>>
>> (no changes since v12)
>>
>> Changes in v11:
>> - Switch to using typec bus notifiers.
>>
>> (no changes since v10)
>>
>> Changes in v9:
>> - Remove the exposed DRM_AUX_HPD_BRIDGE option, and select
>> DRM_AUX_HPD_TYPEC_BRIDGE when it is available.
>> - Add more commit comment about problem background.
>>
>> Changes in v8:
>> - Merge generic DP HPD bridge into one module.
>> ---
>>
>>  drivers/gpu/drm/bridge/Kconfig                | 10 ++++
>>  drivers/gpu/drm/bridge/Makefile               |  1 +
>>  .../gpu/drm/bridge/aux-hpd-typec-dp-bridge.c  | 49 +++++++++++++++++++
>>  3 files changed, 60 insertions(+)
>>  create mode 100644 drivers/gpu/drm/bridge/aux-hpd-typec-dp-bridge.c
>>
>> diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
>> index a250afd8d662..559487aa09a9 100644
>> --- a/drivers/gpu/drm/bridge/Kconfig
>> +++ b/drivers/gpu/drm/bridge/Kconfig
>> @@ -30,6 +30,16 @@ config DRM_AUX_HPD_BRIDGE
>>  	  Simple bridge that terminates the bridge chain and provides HPD
>>  	  support.
>>  
>> +if DRM_AUX_HPD_BRIDGE
>> +config DRM_AUX_HPD_TYPEC_BRIDGE
>> +	tristate
>> +	depends on TYPEC || !TYPEC
>> +	default TYPEC
>> +	help
>> +	  Simple bridge that terminates the bridge chain and provides HPD
>> +	  support. It build bridge on each USB-C connector device node.
>> +endif
>> +
> 
> Should CONFIG_TYPEC_DP_ALTMODE select this one? Otherwise, we need to do it
> manually.
> 
> $ grep -nr --include=Kconfig "select DRM_AUX_HPD_BRIDGE" .
> ./drivers/soc/qcom/Kconfig:118: select DRM_AUX_HPD_BRIDGE
> ./drivers/usb/typec/ucsi/Kconfig:88:    select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> ./drivers/usb/typec/ucsi/Kconfig:99:    select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> ./drivers/usb/typec/tcpm/Kconfig:62:    select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> ./drivers/usb/typec/tcpm/Kconfig:85:    select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF
> 

That's a fair point. But based on the previous discussion, Heikki
point out that configurations in the TYPEC subsystem should not
select configurations from DRM.

-- 
Best, 
Chaoyi


^ permalink raw reply

* Re: [PATCH v5 3/4] drm/bridge: analogix_dp: Add validation for samsung,lane-count property
From: Damon Ding @ 2026-06-29  1:53 UTC (permalink / raw)
  To: Luca Ceresoli
  Cc: hjc, heiko, andy.yan, maarten.lankhorst, mripard, tzimmermann,
	airlied, simona, robh, krzk+dt, conor+dt, andrzej.hajda,
	neil.armstrong, rfoss, Laurent.pinchart, jonas, jernej.skrabec,
	nicolas.frattaroli, cristian.ciocaltea, sebastian.reichel,
	dmitry.baryshkov, dianders, m.szyprowski, dri-devel, devicetree,
	linux-arm-kernel, linux-rockchip, linux-kernel
In-Reply-To: <178249136513.1374898.11400378046460567437.b4-review@b4>

Hi Luca,

On 6/27/2026 12:29 AM, Luca Ceresoli wrote:
> On Thu, 04 Jun 2026 16:52:19 +0800, Damon Ding <damon.ding@rock-chips.com> wrote:
> 
> Hello Damon,
> 
>>
>> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
>> index 7a85774aaac1..e120ef3320c1 100644
>> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
>> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
>> @@ -1261,8 +1262,11 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
>>   		 */
>>   		of_property_read_u32(dp_node, "samsung,link-rate",
>>   				     &video_info->max_link_rate);
>> -		of_property_read_u32(dp_node, "samsung,lane-count",
>> -				     &video_info->max_lane_count);
>> +		ret = of_property_read_u32(dp_node, "samsung,lane-count",
>> +					   &video_info->max_lane_count);
>> +		if (ret || !drm_dp_lane_count_is_valid(video_info->max_lane_count))
>> +			return dev_err_probe(dp->dev, ret ? ret : -EINVAL,
>> +					     "failed to parse samsung,lane-count\n");
> 
> I think this report by sashiko makes sense:
> 
>    >  sashiko-bot@kernel.org <sashiko-bot@kernel.org>:
>    >
>    >  [Severity: High]
>    >  Does this make the optional and deprecated samsung,lane-count property a
>    >  strict requirement?
>    >
>    >  If samsung,lane-count is absent from the device tree, of_property_read_u32()
>    >  returns -EINVAL. This causes the condition to evaluate to true, aborting the
>    >  probe with an error.
>    >
>    >  According to the device tree bindings
>    >  (Documentation/devicetree/bindings/display/samsung/samsung,exynos5-dp.yaml),
>    >  this property is marked as deprecated and explicitly optional because the
>    >  lane count can be read from the monitor. Does this patch break compatibility
>    >  with device trees that rightfully omit this deprecated property?
> 
>   (via: https://patch.msgid.link/20260604090935.7FC051F00898@smtp.kernel.org)
> 
> Can you comment on this?
> 
> 

I was also confused about this handling at first. From commit 
0d0abd894ead ("drm: bridge: analogix/dp: add max link rate and lane 
count limit for RK3288"), its commit message does not explain why 
samsung,lane-count was changed from a mandatory to optional property.

After digging into the code flow, I found that 
analogix_dp_full_link_train() picks the smaller value between the 
platform-supported lane count and the lane count retrieved from sink 
DPCD for link training. If the samsung,lane-count property is 
missing/invalid here, link training will end up using an unexpected lane 
count configuration.

Additionally, I checked Samsung’s upstream device trees that utilize 
this DP controller, and all of them carry the lane-count property. Based 
on this observation, I believe restoring the strict mandatory 
requirement for this property makes sense.

Should I create an independent fix patch to revert these two properties 
to mandatory, instead of bundling the fix in this series?

Best regards,
Damon



^ permalink raw reply

* Re: [PATCH v2 2/2] arm64: dts: qcom: kaanapali: fix traceNoC probe issue
From: Jie Gan @ 2026-06-29  2:08 UTC (permalink / raw)
  To: Leo Yan, Suzuki K Poulose, Mike Leach, James Clark
  Cc: Konrad Dybcio, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Tingwei Zhang, Jingyi Wang,
	Abel Vesa, Yuanfang Zhang, linux-arm-msm, devicetree,
	linux-kernel, coresight, linux-arm-kernel
In-Reply-To: <20260626154949.GA1812158@e132581.arm.com>



Hi Leo/Suzuki,

On 6/26/2026 11:49 PM, Leo Yan wrote:
> On Fri, Jun 26, 2026 at 08:09:58PM +0800, Jie Gan wrote:
> 
> [...]
> 
>> I have another proposal: what if we allocate the ATID in trace_noc_id() when
>> the device does not already have a valid ATID?
>>
>> Possible scenarios:
>>
>> If the itnoc device is connected to a TPDM device (which has no ATID),
>> trace_noc_id() will be invoked via coresight_path_assign_trace_id(), and a
>> valid ATID can be allocated for the path.
>>
>> If the itnoc device is connected to sources other than TPDM, trace_noc_id()
>> will never be invoked, and therefore no ATID will be allocated for the
>> device, saving resources.
> 
> TBH, I'm not sure I can make a judgement here, as I don't have enough
> knowledge of the topology. And I'm not sure whether the listed
> connections cover all possible cases.
> 
> I also found commit 5799dee92dc2:
> 
>   | This patch adds platform driver support for the CoreSight Interconnect
>   | TNOC, Interconnect TNOC is a CoreSight link that forwards trace data
>   | from a subsystem to the Aggregator TNOC. Compared to Aggregator TNOC,
>   | it does not have aggregation and ATID functionality.
> 
> With your proposal, wouldn't ATID be allocated for the interconnect
> TNOC while being skipped for the Aggregator TNOC? That seems to
> contradict the commit log.

The ATID is allocated to the Aggregator TNOC during probe. The "WA" in 
driver definitely break the original design.


Can I fix the issue by adding "arm,primecell-periphid" property. That's 
would be the best temp solution as it avoids breaking the original 
design of both the TraceNoC AMBA driver and interconnect TraceNoC 
platform driver.

The TraceNoC device here must be treated as an AMBA device and I am 
continuing to investigate the issue with our hardware team. We aim to 
fix it from hardware perspetive for existing platforms if possible and 
ensure it is fixed in future platforms.

Thanks,
Jie

> 
> Thanks,
> Leo



^ permalink raw reply

* RE: [PATCH V3 1/8] PCI: imx6: Add skip_pwrctrl_off flag support
From: Sherry Sun @ 2026-06-29  2:32 UTC (permalink / raw)
  To: Frank Li (OSS), Sherry Sun (OSS)
  Cc: robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Frank Li, s.hauer@pengutronix.de, kernel@pengutronix.de,
	festevam@gmail.com, Amitkumar Karwar, Neeraj Sanjay Kale,
	marcel@holtmann.org, luiz.dentz@gmail.com, Hongxing Zhu,
	l.stach@pengutronix.de, lpieralisi@kernel.org,
	kwilczynski@kernel.org, mani@kernel.org, bhelgaas@google.com,
	brgl@kernel.org, imx@lists.linux.dev, linux-pci@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-bluetooth@vger.kernel.org,
	linux-pm@vger.kernel.org
In-Reply-To: <aj7VpvRQxhCyPVPg@SMW015318>

> Subject: Re: [PATCH V3 1/8] PCI: imx6: Add skip_pwrctrl_off flag support
> 
> On Fri, Jun 26, 2026 at 10:31:19AM +0800, Sherry Sun (OSS) wrote:
> > From: Sherry Sun <sherry.sun@nxp.com>
> >
> > Use dw_pcie_rp::skip_pwrctrl_off to avoid powering off devices during
> > suspend to preserve wakeup capability of the devices and also not to
> > power on the devices in the init path.
> 
> Need empty line here.

Ok, will fix.

> 
> > This allows controller power-off to be skipped when some devices(e.g.
> > M.2 cards key E without auxiliary power) required to support PCIe L2
> > link state and wake-up mechanisms.
> >
> > Move pci_pwrctrl_create_devices() to imx_pcie_probe() so that it is
> > only called once during probe, similar to other regulator_get calls.
> >
> > Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
> > ---
> >  drivers/pci/controller/dwc/pci-imx6.c | 43
> > ++++++++++++++++-----------
> >  1 file changed, 25 insertions(+), 18 deletions(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pci-imx6.c
> > b/drivers/pci/controller/dwc/pci-imx6.c
> > index 0fa716d1ed75..0685573fee71 100644
> > --- a/drivers/pci/controller/dwc/pci-imx6.c
> > +++ b/drivers/pci/controller/dwc/pci-imx6.c
> > @@ -1382,16 +1382,12 @@ static int imx_pcie_host_init(struct dw_pcie_rp
> *pp)
> >  		}
> >  	}
> >
> > -	ret = pci_pwrctrl_create_devices(dev);
> > -	if (ret) {
> > -		dev_err(dev, "failed to create pwrctrl devices\n");
> > -		goto err_reg_disable;
> > -	}
> > -
> 
> Please two patch do that. one patch move pci_pwrctrl_create_devices() to
> probe
> 
> one patch check skip_power_off.
> 
> > -	ret = pci_pwrctrl_power_on_devices(dev);
> > -	if (ret) {
> > -		dev_err(dev, "failed to power on pwrctrl devices\n");
> > -		goto err_pwrctrl_destroy;
> > +	if (!pp->skip_pwrctrl_off) {
> > +		ret = pci_pwrctrl_power_on_devices(dev);
> > +		if (ret) {
> > +			dev_err(dev, "failed to power on pwrctrl devices\n");
> > +			goto err_reg_disable;
> > +		}
> >  	}
> >
> >  	ret = imx_pcie_clk_enable(imx_pcie); @@ -1460,10 +1456,8 @@
> static
> > int imx_pcie_host_init(struct dw_pcie_rp *pp)
> >  err_clk_disable:
> >  	imx_pcie_clk_disable(imx_pcie);
> >  err_pwrctrl_power_off:
> > -	pci_pwrctrl_power_off_devices(dev);
> > -err_pwrctrl_destroy:
> > -	if (ret != -EPROBE_DEFER)
> > -		pci_pwrctrl_destroy_devices(dev);
> > +	if (!pp->skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(dev);
> >  err_reg_disable:
> >  	if (imx_pcie->vpcie)
> >  		regulator_disable(imx_pcie->vpcie);
> > @@ -1482,7 +1476,8 @@ static void imx_pcie_host_exit(struct dw_pcie_rp
> *pp)
> >  	}
> >  	imx_pcie_clk_disable(imx_pcie);
> >
> > -	pci_pwrctrl_power_off_devices(pci->dev);
> > +	if (!pci->pp.skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(pci->dev);
> >  	if (imx_pcie->vpcie)
> >  		regulator_disable(imx_pcie->vpcie);
> >  }
> > @@ -1954,11 +1949,15 @@ static int imx_pcie_probe(struct
> platform_device *pdev)
> >  	if (ret)
> >  		return ret;
> >
> > +	ret = pci_pwrctrl_create_devices(dev);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "failed to create pwrctrl
> > +devices\n");
> > +
> >  	pci->use_parent_dt_ranges = true;
> >  	if (imx_pcie->drvdata->mode == DW_PCIE_EP_TYPE) {
> >  		ret = imx_add_pcie_ep(imx_pcie, pdev);
> >  		if (ret < 0)
> > -			return ret;
> > +			goto err_pwrctrl_destroy;
> >
> >  		/*
> >  		 * FIXME: Only single Device (EPF) is supported due to the
> @@
> > -1973,7 +1972,7 @@ static int imx_pcie_probe(struct platform_device
> *pdev)
> >  		pci->pp.use_atu_msg = true;
> >  		ret = dw_pcie_host_init(&pci->pp);
> >  		if (ret < 0)
> > -			return ret;
> > +			goto err_pwrctrl_destroy;
> >
> >  		if (pci_msi_enabled()) {
> >  			u8 offset = dw_pcie_find_capability(pci,
> PCI_CAP_ID_MSI); @@
> > -1985,16 +1984,24 @@ static int imx_pcie_probe(struct platform_device
> *pdev)
> >  	}
> >
> >  	return 0;
> > +
> > +err_pwrctrl_destroy:
> > +	if (ret != -EPROBE_DEFER)
> > +		pci_pwrctrl_destroy_devices(dev);
> > +	return ret;
> 
> Mani said he will fix DEFER problem soon.

Yes, so for now I'll make a patch to move pci_pwrctrl_create_devices() into the
probe() and temporarily add the err_pwrctrl_destroy error label until Mani fixes it.
Let me know if any other suggestions, thanks!

Best Regards
Sherry

> 
> Frank
> 
> >  }
> >
> >  static void imx_pcie_shutdown(struct platform_device *pdev)  {
> >  	struct imx_pcie *imx_pcie = platform_get_drvdata(pdev);
> > +	struct dw_pcie *pci = imx_pcie->pci;
> > +	struct dw_pcie_rp *pp = &pci->pp;
> >
> >  	/* bring down link, so bootloader gets clean state in case of reboot */
> >  	imx_pcie_assert_core_reset(imx_pcie);
> >  	imx_pcie_assert_perst(imx_pcie, true);
> > -	pci_pwrctrl_power_off_devices(&pdev->dev);
> > +	if (!pp->skip_pwrctrl_off)
> > +		pci_pwrctrl_power_off_devices(&pdev->dev);
> >  	pci_pwrctrl_destroy_devices(&pdev->dev);
> >  }
> >
> > --
> > 2.50.1
> >
> >


^ permalink raw reply

* Re: [PATCH v3 2/2] iio: adc: add Axiado SARADC driver
From: Petar Stepanovic @ 2026-06-29  2:33 UTC (permalink / raw)
  To: David Lechner, Akhila Kavi, Prasad Bolisetty, Jonathan Cameron,
	Nuno Sá, Andy Shevchenko, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Harshit Shah
  Cc: linux-iio, devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <6770a7af-06cc-4240-9b20-c299e7080ab1@baylibre.com>


On 6/28/2026 1:07 AM, David Lechner wrote:
>> +#define AX_SARADC_CH(_index, _id)                                       \
>> +     {                                                               \
>> +             .type = IIO_VOLTAGE,                                    \
>> +             .indexed = 1,                                           \
>> +             .channel = (_index),                                    \
>> +             .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
>> +             .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),   \
>> +             .datasheet_name = (_id),                                \
> This could probably be:
>
>                 .datasheet_name = "adc" #_index,
>
> and avoid the need for _id.

Thanks for the review, David.
Yes, that makes sense. I will update this and remove the extra _id
argument.

>> +     }
>> +
>> +static const struct iio_chan_spec axiado_saradc_iio_channels[] = {
>> +     AX_SARADC_CH(0, "adc0"),   AX_SARADC_CH(1, "adc1"),
>> +     AX_SARADC_CH(2, "adc2"),   AX_SARADC_CH(3, "adc3"),
>> +     AX_SARADC_CH(4, "adc4"),   AX_SARADC_CH(5, "adc5"),
>> +     AX_SARADC_CH(6, "adc6"),   AX_SARADC_CH(7, "adc7"),
>> +     AX_SARADC_CH(8, "adc8"),   AX_SARADC_CH(9, "adc9"),
>> +     AX_SARADC_CH(10, "adc10"), AX_SARADC_CH(11, "adc11"),
>> +     AX_SARADC_CH(12, "adc12"), AX_SARADC_CH(13, "adc13"),
>> +     AX_SARADC_CH(14, "adc14"), AX_SARADC_CH(15, "adc15"),
> Two columns looks a bit odd.

I will also reformat the channel table to one entry per line.

>> +};
>> +
>> +static void axiado_saradc_disable(void *data)
>> +{
>> +     struct axiado_saradc *info = data;
>> +
>> +     writel(AX_SARADC_GLOBAL_CTRL_PD, info->regs + AX_SARADC_GLOBAL_CTRL_REG);
> People usual make read and write wrappers or use regmap to avoid having
> to write `info->regs + AX_SARADC_GLOBAL_CTRL_REG` so many times.

My understanding is that simple read/write wrappers are not always
preferred unless they provide additional value. Would switching the
driver to regmap be acceptable here to avoid repeating the base address
calculation?

Regards,
Petar



^ permalink raw reply

* [PATCH v4 0/2] i2c: imx: Fix slave mode corner issues
From: Liem @ 2026-06-29  2:38 UTC (permalink / raw)
  To: carlos.song
  Cc: andi.shyti, biwen.li, festevam, frank.li, frank.li, imx, kernel,
	liem16213, linux-arm-kernel, linux-i2c, linux-kernel, o.rempel,
	s.hauer, stable, wsa
In-Reply-To: <AM0PR04MB6802B863CD9B9AE1609C1785E8EB2@AM0PR04MB6802.eurprd04.prod.outlook.com>

This series fixes two issues in the i2c-imx target mode.

Patch 1 defers slave pointer assignment to after a successful resume
and protects it with the slave_lock to prevent races with the shared
IRQ handler.

Patch 2 cancels the hrtimer before clearing the slave pointer during
unregistration, preventing a potential use-after-free.

Changes in v4:
- Patch 1: reworked to avoid race with shared IRQ handler, as
  suggested by Sashiko.
- Patch 2: unchanged.

Changes in v3:
- Split the original patch into two separate patches as suggested by
  Frank Li.
- v2: https://lore.kernel.org/imx/
  20260625160219.55116-1-liem16213@gmail.com/

Liem (2):
  i2c: imx: Fix slave registration race and error handling
  i2c: imx: Cancel hrtimer before clearing slave pointer

 drivers/i2c/busses/i2c-imx.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

-- 
2.34.1



^ permalink raw reply

* [PATCH v4 1/2] i2c: imx: Fix slave registration race and error handling
From: Liem @ 2026-06-29  2:38 UTC (permalink / raw)
  To: carlos.song
  Cc: andi.shyti, biwen.li, festevam, frank.li, frank.li, imx, kernel,
	liem16213, linux-arm-kernel, linux-i2c, linux-kernel, o.rempel,
	s.hauer, stable, wsa
In-Reply-To: <20260629023829.152651-1-liem16213@gmail.com>

In i2c_imx_reg_slave(), the slave pointer was assigned before
pm_runtime_resume_and_get().  If pm_runtime_resume_and_get() failed,
the error path returned without clearing i2c_imx->slave, leaving it
non-NULL and causing all subsequent registration attempts to fail
with -EBUSY.

Additionally, because this driver uses a shared IRQ, the interrupt
handler i2c_imx_isr() can execute concurrently and, after acquiring
slave_lock, dereference i2c_imx->slave.  The previous fix attempt
added a lockless i2c_imx->slave = NULL on the error path, but that
could race with the ISR under the lock and still cause a NULL pointer
dereference.

Fix both issues by deferring the assignment of i2c_imx->slave and
i2c_imx->last_slave_event to after a successful resume, and by
performing the assignment inside the slave_lock critical section.
This guarantees that the slave pointer is never left stale on the
error path and is always valid when observed by the interrupt handler.

Fixes: f7414cd6923f ("i2c: imx: support slave mode for imx I2C driver")
Cc: stable@vger.kernel.org
Signed-off-by: Liem <liem16213@gmail.com>
---
v3 -> v4:
  - Instead of clearing the slave pointer on error, defer the
    assignment until after pm_runtime_resume_and_get() succeeds,
    and take slave_lock to avoid racing with the shared IRQ handler.
    Suggested by Sashiko and Carlos Song
---
 drivers/i2c/busses/i2c-imx.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 28313d0fad37..2398c406e913 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -930,9 +930,6 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
 	if (i2c_imx->slave)
 		return -EBUSY;
 
-	i2c_imx->slave = client;
-	i2c_imx->last_slave_event = I2C_SLAVE_STOP;
-
 	/* Resume */
 	ret = pm_runtime_resume_and_get(i2c_imx->adapter.dev.parent);
 	if (ret < 0) {
@@ -940,6 +937,11 @@ static int i2c_imx_reg_slave(struct i2c_client *client)
 		return ret;
 	}
 
+	scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) {
+		i2c_imx->slave = client;
+		i2c_imx->last_slave_event = I2C_SLAVE_STOP;
+	}
+
 	i2c_imx_slave_init(i2c_imx);
 
 	return 0;
-- 
2.34.1



^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox