Devicetree
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Add support for LTC3208 multi-display driver
From: Jan Carlo Roleda @ 2026-04-16  2:39 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda

The LTC3208 is a multi-display LED driver, using a high-efficiency, low
noise charge pump to provide power to 5 channels (MAIN, SUB, RGB, CAM,
AUX). Current for each LED is controlled by the I2C serial interface.
Four AUX current sources can be independently assigned via the I2C port
to the CAM, SUB, MAIN, or AUX DAC controlled displays

Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
---
Changes in v4:
- Reordered commit order to match dependency order
- Updated Kconfig to be more descriptive of device
- Added led@0-7 with more complete example properties (function and
  color)
- Driver changes:
-- Removed unnecessary include headers
-- Formatted macros
-- Created helper `write_current_level` functions for LED current
  configuration, using `regmap_update_bits()`
-- Adjusted awkward tabbing issues
-- Updated variable names in probe to be more descriptive
-- Updated inline comment capitalization
-- Initialized `i` within the for loop in AUX configuration in probe
-- Refactored `update_aux_dac` function to use array pointer
-- Fixed error messages in probe 
- Link to v3: https://lore.kernel.org/r/20260406-upstream-ltc3208-v3-0-7f0b1d20ee7a@analog.com

Changes in v3:
- Edited device bindings descriptions
-- removed full stop in title
-- replaced quotes with double quotes for consistency
-- removed <dt-bindings/gpio/gpio.h> from example
-- removed led1-7 in example for brevity
- squashed maintainers commit to driver commit
- Link to v2: https://lore.kernel.org/r/20260326-upstream-ltc3208-v2-0-3dbc992b6098@analog.com

Changes in v2:
- Addressed DTSchema bot warnings and errors
-- removed extra blank lines
-- fixed $id to match current naming
- Addressed Kernel test warnings
-- fixed bounds for aux channel configurations
- Link to v0: https://lore.kernel.org/r/20260318-upstream-ltc3208-v1-0-015f1f1e9065@analog.com

---
Jan Carlo Roleda (2):
      dt-bindings: leds: Document LTC3208 Multidisplay LED Driver
      leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver

 .../devicetree/bindings/leds/adi,ltc3208.yaml      | 181 ++++++++++++++
 MAINTAINERS                                        |   7 +
 drivers/leds/Kconfig                               |  12 +
 drivers/leds/Makefile                              |   1 +
 drivers/leds/leds-ltc3208.c                        | 278 +++++++++++++++++++++
 5 files changed, 479 insertions(+)
---
base-commit: e68f95a51d1a8c1594b536c4d495cbea38d47561
change-id: 20260318-upstream-ltc3208-7cc8968bf69e

Best regards,
-- 
Jan Carlo Roleda <jancarlo.roleda@analog.com>


^ permalink raw reply

* [PATCH v4 1/2] dt-bindings: leds: Document LTC3208 Multidisplay LED Driver
From: Jan Carlo Roleda @ 2026-04-16  2:39 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda
In-Reply-To: <20260416-upstream-ltc3208-v4-0-3884ed3e49f5@analog.com>

Add Devicetree Documentation for LTC3208 Multidisplay LED Driver.

Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
---
 .../devicetree/bindings/leds/adi,ltc3208.yaml      | 181 +++++++++++++++++++++
 MAINTAINERS                                        |   7 +
 2 files changed, 188 insertions(+)

diff --git a/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml b/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
new file mode 100644
index 000000000000..0a01e07e0ab7
--- /dev/null
+++ b/Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
@@ -0,0 +1,181 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2026 Analog Devices, Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/leds/adi,ltc3208.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: LTC3208 Multidisplay LED Controller from Linear Technologies (Now Analog Devices)
+
+maintainers:
+  - Jan Carlo Roleda <jancarlo.roleda@analog.com>
+
+description:
+  The LTC3208 is a multidisplay LED controller that can support up to 1A to all
+  connected LEDs.
+
+  The datasheet for this device can be found in
+  https://www.analog.com/en/products/ltc3208.html
+
+properties:
+  compatible:
+    const: adi,ltc3208
+
+  reg:
+    maxItems: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+  adi,disable-camhl-pin:
+    type: boolean
+    description:
+      Configures whether the external CAMHL pin is disabled.
+      If disabled then the output pins associated with CAM will always select
+      the CAM register's high half-byte brightness.
+
+  adi,cfg-enrgbs-pin:
+    type: boolean
+    description:
+      Configures which channel the ENRGBS pin toggles when it receives a signal.
+      ENRGBS pin controls the SUB channel's output pins if this is set,
+      or RGB channel's output pins if this is unset.
+
+  adi,disable-rgb-aux4-dropout:
+    type: boolean
+    description:
+      Configures the RGB and AUX4 dropout signals to be disabled.
+
+  adi,aux1-channel:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      LED Channel that the AUX1 output pin mirrors its brightness level from.
+    enum: [aux, main, sub, cam]
+    default: aux
+
+  adi,aux2-channel:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      LED Channel that the AUX2 output pin mirrors its brightness level from.
+    enum: [aux, main, sub, cam]
+    default: aux
+
+  adi,aux3-channel:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      LED Channel that the AUX3 output pin mirrors its brightness level from.
+    enum: [aux, main, sub, cam]
+    default: aux
+
+  adi,aux4-channel:
+    $ref: /schemas/types.yaml#/definitions/string
+    description:
+      LED Channel that the AUX4 output pin mirrors its brightness level from.
+    enum: [aux, main, sub, cam]
+    default: aux
+
+patternProperties:
+  "^led@[0-7]$":
+    type: object
+    $ref: /schemas/leds/common.yaml#
+    unevaluatedProperties: false
+    properties:
+      reg:
+        description:
+          LED Channel Number. each channel maps to a specific channel group used
+          to configure the brightness level of the output pins corresponding to
+          the channel.
+        enum:
+          - 0 # Main Channel (8-bit brightness)
+          - 1 # Sub Channel (8-bit brightness)
+          - 2 # AUX Channel (4-bit brightness)
+          - 3 # Camera Channel, Low-side byte (4-bit brightness)
+          - 4 # Camera Channel, High-side byte (4-bit brightness)
+          - 5 # Red Channel (4-bit brightness)
+          - 6 # Blue Channel (4-bit brightness)
+          - 7 # Green Channel (4-bit brightness)
+    required:
+      - reg
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/leds/common.h>
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      led-controller@1b {
+        compatible = "adi,ltc3208";
+        reg = <0x1b>;
+        #address-cells = <1>;
+        #size-cells = <0>;
+        adi,disable-camhl-pin;
+        adi,cfg-enrgbs-pin;
+        adi,disable-rgb-aux4-dropout;
+
+        /* MAIN */
+        led@0 {
+          reg = <0>;
+          function = LED_FUNCTION_ACTIVITY;
+          color = <LED_COLOR_ID_WHITE>;
+        };
+
+        /* SUB */
+        led@1 {
+          reg = <1>;
+          function = LED_FUNCTION_ACTIVITY;
+          color = <LED_COLOR_ID_WHITE>;
+        };
+
+        /* AUX */
+        led@2 {
+          reg = <2>;
+          function = LED_FUNCTION_ACTIVITY;
+          color = <LED_COLOR_ID_WHITE>;
+        };
+
+        /* CAMLO */
+        led@3 {
+          reg = <3>;
+          function = LED_FUNCTION_FLASH;
+          color = <LED_COLOR_ID_WHITE>;
+        };
+
+        /* CAMHI */
+        led@4 {
+          reg = <4>;
+          function = LED_FUNCTION_FLASH;
+          color = <LED_COLOR_ID_WHITE>;
+        };
+
+        /* RED */
+        led@5 {
+          reg = <5>;
+          function = LED_FUNCTION_INDICATOR;
+          color = <LED_COLOR_ID_RED>;
+        };
+
+        /* BLUE */
+        led@6 {
+          reg = <6>;
+          function = LED_FUNCTION_INDICATOR;
+          color = <LED_COLOR_ID_BLUE>;
+        };
+
+        /* GREEN */
+        led@7 {
+          reg = <7>;
+          function = LED_FUNCTION_INDICATOR;
+          color = <LED_COLOR_ID_GREEN>;
+        };
+      };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 55af015174a5..19b0b84e934d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15126,6 +15126,13 @@ W:	https://ez.analog.com/linux-software-drivers
 F:	Documentation/devicetree/bindings/iio/temperature/adi,ltc2983.yaml
 F:	drivers/iio/temperature/ltc2983.c
 
+LTC3208 LED DRIVER
+M:	Jan Carlo Roleda <jancarlo.roleda@analog.com>
+L:	linux-leds@vger.kernel.org
+S:	Maintained
+W:	https://ez.analog.com/linux-software-drivers
+F:	Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
+
 LTC4282 HARDWARE MONITOR DRIVER
 M:	Nuno Sa <nuno.sa@analog.com>
 L:	linux-hwmon@vger.kernel.org

-- 
2.43.0


^ permalink raw reply related

* [PATCH v4 2/2] leds: ltc3208: Add driver for LTC3208 Multidisplay LED Driver
From: Jan Carlo Roleda @ 2026-04-16  2:39 UTC (permalink / raw)
  To: Lee Jones, Pavel Machek, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley
  Cc: linux-kernel, linux-leds, devicetree, Jan Carlo Roleda
In-Reply-To: <20260416-upstream-ltc3208-v4-0-3884ed3e49f5@analog.com>

Kernel driver implementation for LTC3208 Multidisplay LED Driver.

The LTC3208 is a Multi-display LED driver, designed to control up to
7 distinct LED channels (MAIN, SUB, AUX, CAMHI, CAMLO, RED, GREEN, BLUE),
each configurable with its own current level that is equally set to its
respective output current source pins for external LEDs.

It is programmed via the I2C serial interface.
MAIN and SUB support 8-bit current level resolution,
while AUX, CAMHI/LO, RED, GREEN, and BLUE support 4-bit levels.

The AUX LED channel can be configured to mirror the CAM, SUB, and MAIN
channel current levels, or as its own independent AUX channel.

The CAM LED channel is configured as 2 separate CAMHI and CAMLO register
sub-channels, which currnet is selected via the CAMHL pin, or set to
CAMHI register only via setting the S_CAMHILO bit high in register G (0x7).

Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
---
 MAINTAINERS                 |   2 +-
 drivers/leds/Kconfig        |  12 ++
 drivers/leds/Makefile       |   1 +
 drivers/leds/leds-ltc3208.c | 278 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 292 insertions(+), 1 deletion(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 19b0b84e934d..48bae02057d5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -15131,7 +15131,7 @@ M:	Jan Carlo Roleda <jancarlo.roleda@analog.com>
 L:	linux-leds@vger.kernel.org
 S:	Maintained
 W:	https://ez.analog.com/linux-software-drivers
-F:	Documentation/devicetree/bindings/leds/adi,ltc3208.yaml
+F:	drivers/leds/leds-ltc3208.c
 
 LTC4282 HARDWARE MONITOR DRIVER
 M:	Nuno Sa <nuno.sa@analog.com>
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 597d7a79c988..d13bbec73f06 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -1029,6 +1029,18 @@ config LEDS_ACER_A500
 	  This option enables support for the Power Button LED of
 	  Acer Iconia Tab A500.
 
+config LEDS_LTC3208
+	tristate "LED Driver for Analog Devices LTC3208"
+	depends on LEDS_CLASS && I2C
+	select REGMAP_I2C
+	help
+	  Say Y to enable the LTC3208 LED driver.
+	  This enables the LED device LTC3208, a 7-channel, 17-current source
+	  multidisplay high-current LED driver, configured via I2C.
+
+	  To compile this driver as a module, choose M here: the module will
+	  be called ltc3208.
+
 source "drivers/leds/blink/Kconfig"
 
 comment "Flash and Torch LED drivers"
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 8fdb45d5b439..b08b539112b6 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_LEDS_LP8788)		+= leds-lp8788.o
 obj-$(CONFIG_LEDS_LP8860)		+= leds-lp8860.o
 obj-$(CONFIG_LEDS_LP8864)		+= leds-lp8864.o
 obj-$(CONFIG_LEDS_LT3593)		+= leds-lt3593.o
+obj-$(CONFIG_LEDS_LTC3208)		+= leds-ltc3208.o
 obj-$(CONFIG_LEDS_MAX5970)		+= leds-max5970.o
 obj-$(CONFIG_LEDS_MAX77650)		+= leds-max77650.o
 obj-$(CONFIG_LEDS_MAX77705)		+= leds-max77705.o
diff --git a/drivers/leds/leds-ltc3208.c b/drivers/leds/leds-ltc3208.c
new file mode 100644
index 000000000000..9da8f4b359e3
--- /dev/null
+++ b/drivers/leds/leds-ltc3208.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * LED driver for Analog Devices LTC3208 Multi-Display Driver
+ *
+ * Copyright 2026 Analog Devices Inc.
+ *
+ * Author: Jan Carlo Roleda <jancarlo.roleda@analog.com>
+ */
+#include <linux/bitfield.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define LTC3208_LED_SET_HIGH_BYTE_DATA	GENMASK(7, 4)
+#define LTC3208_LED_SET_LOW_BYTE_DATA	GENMASK(3, 0)
+
+/* Registers */
+#define LTC3208_REG_A_GRNRED		0x1 /* Green (High half-byte) */
+					/* and Red (Low half-byte) current DAC*/
+#define LTC3208_REG_B_AUXBLU		0x2 /* AUX (High half-byte) */
+					/* and Blue (Low half-byte) current DAC*/
+#define LTC3208_REG_C_MAIN		0x3 /* Main current DAC */
+#define LTC3208_REG_D_SUB		0x4 /* Sub current DAC */
+#define LTC3208_REG_E_AUX_SELECT	0x5 /* AUX DAC Select */
+#define  LTC3208_AUX1_MASK		GENMASK(1, 0)
+#define  LTC3208_AUX2_MASK		GENMASK(3, 2)
+#define  LTC3208_AUX3_MASK		GENMASK(5, 4)
+#define  LTC3208_AUX4_MASK		GENMASK(7, 6)
+#define LTC3208_REG_F_CAM		0x6 /* CAM (High half-byte and Low half-byte) current DAC*/
+#define LTC3208_REG_G_OPT		0x7 /* Device Options */
+#define  LTC3208_OPT_CPO_MASK		GENMASK(7, 6)
+#define  LTC3208_OPT_DIS_RGBDROP	BIT(3)
+#define  LTC3208_OPT_DIS_CAMHILO	BIT(2)
+#define  LTC3208_OPT_EN_RGBS		BIT(1)
+
+#define LTC3208_MAX_BRIGHTNESS_4BIT	0xF
+#define LTC3208_MAX_BRIGHTNESS_8BIT	0xFF
+
+#define LTC3208_NUM_LED_GRPS		8
+#define LTC3208_NUM_AUX_LEDS		4
+
+#define LTC3208_NUM_AUX_OPT		4
+#define LTC3208_MAX_CPO_OPT		3
+
+enum ltc3208_aux_channel {
+	LTC3208_AUX_CHAN_AUX = 0,
+	LTC3208_AUX_CHAN_MAIN,
+	LTC3208_AUX_CHAN_SUB,
+	LTC3208_AUX_CHAN_CAM
+};
+
+enum ltc3208_channel {
+	LTC3208_CHAN_MAIN = 0,
+	LTC3208_CHAN_SUB,
+	LTC3208_CHAN_AUX,
+	LTC3208_CHAN_CAML,
+	LTC3208_CHAN_CAMH,
+	LTC3208_CHAN_RED,
+	LTC3208_CHAN_BLUE,
+	LTC3208_CHAN_GREEN
+};
+
+static const char * const ltc3208_dt_aux_channels[] = {
+	"adi,aux1-channel", "adi,aux2-channel",
+	"adi,aux3-channel", "adi,aux4-channel"
+};
+
+static const char * const ltc3208_aux_opt[] = {
+	"aux", "main", "sub", "cam"
+};
+
+struct ltc3208_led {
+	struct led_classdev cdev;
+	struct i2c_client *client;
+	enum ltc3208_channel channel;
+};
+
+struct ltc3208_dev {
+	struct i2c_client *client;
+	struct regmap *map;
+	struct ltc3208_led *leds;
+};
+
+static const struct regmap_config ltc3208_regmap_cfg = {
+	.reg_bits = 8,
+	.val_bits = 8,
+};
+
+static int ltc3208_led_set_current_low(struct regmap *regmap, u8 reg, u8 level)
+{
+	return regmap_update_bits(regmap, reg, LTC3208_LED_SET_LOW_BYTE_DATA, level);
+}
+
+static int ltc3208_led_set_current_high(struct regmap *regmap, u8 reg, u8 level)
+{
+	return regmap_update_bits(regmap, reg, LTC3208_LED_SET_HIGH_BYTE_DATA, level);
+}
+
+static int ltc3208_led_set_brightness(struct led_classdev *led_cdev, enum led_brightness brightness)
+{
+	struct ltc3208_led *led = container_of(led_cdev, struct ltc3208_led, cdev);
+	struct i2c_client *client = led->client;
+	struct ltc3208_dev *dev = i2c_get_clientdata(client);
+	struct regmap *regmap = dev->map;
+	u8 current_level = brightness;
+
+	switch (led->channel) {
+	case LTC3208_CHAN_MAIN:
+		return regmap_write(regmap, LTC3208_REG_C_MAIN, current_level);
+	case LTC3208_CHAN_SUB:
+		return regmap_write(regmap, LTC3208_REG_D_SUB, current_level);
+	case LTC3208_CHAN_AUX:
+		return ltc3208_led_set_current_high(regmap, LTC3208_REG_B_AUXBLU, current_level);
+	case LTC3208_CHAN_BLUE:
+		return ltc3208_led_set_current_low(regmap, LTC3208_REG_B_AUXBLU, current_level);
+	case LTC3208_CHAN_CAMH:
+		return ltc3208_led_set_current_high(regmap, LTC3208_REG_F_CAM, current_level);
+	case LTC3208_CHAN_CAML:
+		return ltc3208_led_set_current_low(regmap, LTC3208_REG_F_CAM, current_level);
+	case LTC3208_CHAN_GREEN:
+		return ltc3208_led_set_current_high(regmap, LTC3208_REG_A_GRNRED, current_level);
+	case LTC3208_CHAN_RED:
+		return ltc3208_led_set_current_low(regmap, LTC3208_REG_A_GRNRED, current_level);
+	default:
+		dev_err(&client->dev, "Invalid LED Channel\n");
+		return -EINVAL;
+	}
+}
+
+static int ltc3208_update_options(struct ltc3208_dev *dev,
+				  bool is_sub, bool is_cam_hi, bool is_rgb_drop)
+{
+	struct regmap *map = dev->map;
+	u8 val;
+
+	val =	FIELD_PREP(LTC3208_OPT_EN_RGBS, is_sub) |
+		FIELD_PREP(LTC3208_OPT_DIS_CAMHILO, is_cam_hi) |
+		FIELD_PREP(LTC3208_OPT_DIS_RGBDROP, is_rgb_drop);
+
+	return regmap_write(map, LTC3208_REG_G_OPT, val);
+}
+
+static int ltc3208_update_aux_dac(struct ltc3208_dev *dev, enum ltc3208_aux_channel *aux_chan)
+{
+	struct regmap *map = dev->map;
+	u8 val;
+
+	val =	FIELD_PREP(LTC3208_AUX1_MASK, aux_chan[0]) |
+		FIELD_PREP(LTC3208_AUX2_MASK, aux_chan[1]) |
+		FIELD_PREP(LTC3208_AUX3_MASK, aux_chan[2]) |
+		FIELD_PREP(LTC3208_AUX4_MASK, aux_chan[3]);
+
+	return regmap_write(map, LTC3208_REG_E_AUX_SELECT, val);
+}
+
+static int ltc3208_probe(struct i2c_client *client)
+{
+	enum ltc3208_aux_channel aux_channels[LTC3208_NUM_AUX_LEDS];
+	struct ltc3208_dev *dev_data;
+	struct ltc3208_led *leds;
+	struct regmap *regmap;
+	int ret;
+	u32 val;
+	bool dropdis_rgb_aux4;
+	bool dis_camhl;
+	bool en_rgbs;
+
+	regmap = devm_regmap_init_i2c(client, &ltc3208_regmap_cfg);
+	if (IS_ERR(regmap))
+		return dev_err_probe(&client->dev, PTR_ERR(regmap),
+				     "Failed to initialize regmap\n");
+
+	dev_data = devm_kzalloc(&client->dev, sizeof(*dev_data), GFP_KERNEL);
+	if (!dev_data)
+		return -ENOMEM;
+
+	leds = devm_kcalloc(&client->dev, LTC3208_NUM_LED_GRPS,
+			    sizeof(struct ltc3208_led), GFP_KERNEL);
+	if (!leds)
+		return -ENOMEM;
+
+	dev_data->client = client;
+	dev_data->map = regmap;
+
+	dis_camhl = device_property_read_bool(&client->dev, "adi,disable-camhl-pin");
+	en_rgbs = device_property_read_bool(&client->dev, "adi,cfg-enrgbs-pin");
+	dropdis_rgb_aux4 = device_property_read_bool(&client->dev, "adi,disable-rgb-aux4-dropout");
+
+	ret = ltc3208_update_options(dev_data, en_rgbs, dis_camhl,
+				     dropdis_rgb_aux4);
+	if (ret)
+		return dev_err_probe(&client->dev, ret, "error writing to options register\n");
+
+	/* Initialize aux channel configurations from devicetree */
+	for (int i = 0; i < LTC3208_NUM_AUX_LEDS; i++) {
+		ret = device_property_match_property_string(&client->dev,
+							    ltc3208_dt_aux_channels[i],
+							    ltc3208_aux_opt,
+							    LTC3208_NUM_AUX_OPT);
+		/* Use default value if absent in devicetree */
+		if (ret == -EINVAL)
+			aux_channels[i] = LTC3208_AUX_CHAN_AUX;
+		else if (ret >= 0)
+			aux_channels[i] = ret;
+		else
+			return dev_err_probe(&client->dev, ret,
+					     "Failed getting aux-channel %d\n", i);
+	}
+
+	ret = ltc3208_update_aux_dac(dev_data, aux_channels);
+	if (ret)
+		return dev_err_probe(&client->dev, ret, "error writing to aux channel register.\n");
+
+	i2c_set_clientdata(client, dev_data);
+
+	device_for_each_child_node_scoped(&client->dev, child) {
+		struct ltc3208_led *led;
+		struct led_init_data init_data = {};
+
+		ret = fwnode_property_read_u32(child, "reg", &val);
+		if (ret)
+			return dev_err_probe(&client->dev, -EINVAL,
+					     "Failed to get reg value of LED.\n");
+		else if (val >= LTC3208_NUM_LED_GRPS)
+			return dev_err_probe(&client->dev, -EINVAL,
+					     "LED reg value not supported.\n");
+
+		led = &leds[val];
+		led->client = client;
+		led->channel = val;
+		led->cdev.brightness_set_blocking = ltc3208_led_set_brightness;
+		led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_4BIT;
+		if (val == LTC3208_CHAN_MAIN || val == LTC3208_CHAN_SUB)
+			led->cdev.max_brightness = LTC3208_MAX_BRIGHTNESS_8BIT;
+
+		init_data.fwnode = child;
+
+		ret = devm_led_classdev_register_ext(&client->dev, &led->cdev,
+			&init_data);
+		if (ret)
+			return dev_err_probe(&client->dev, ret, "Failed to register LED %u\n", val);
+	}
+
+	dev_data->leds = leds;
+
+	return 0;
+}
+
+static const struct of_device_id ltc3208_match_table[] = {
+	{.compatible = "adi,ltc3208"},
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ltc3208_match_table);
+
+static const struct i2c_device_id ltc3208_idtable[] = {
+	{ "ltc3208" },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3208_idtable);
+
+static struct i2c_driver ltc3208_driver = {
+	.driver = {
+		.name = "ltc3208",
+		.of_match_table = ltc3208_match_table,
+	},
+	.id_table = ltc3208_idtable,
+	.probe = ltc3208_probe,
+};
+module_i2c_driver(ltc3208_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Carlo Roleda <jancarlo.roleda@analog.com>");
+MODULE_DESCRIPTION("LTC3208 LED Driver");

-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v3 1/5] dt-bindings: phy: qcom,sc8280xp-qmp-pcie-phy: Add support for glymur Gen5 x8 bifurcation mode
From: Qiang Yu @ 2026-04-16  2:58 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Bjorn Andersson, Konrad Dybcio,
	linux-arm-msm, linux-phy, devicetree, linux-kernel
In-Reply-To: <20260415-wooden-prawn-of-lightning-dc1ddc@quoll>

On Wed, Apr 15, 2026 at 09:50:28AM +0200, Krzysztof Kozlowski wrote:
> On Sun, Apr 12, 2026 at 11:25:56PM -0700, Qiang Yu wrote:
> > The Glymur SoC has pcie3a and pcie3b PHYs that can operate in two modes:
> > 
> > 1. Independent 4-lane mode: Each PHY operates as a separate PCIe Gen5
> >    4-lane interface, compatible with qcom,glymur-qmp-gen5x4-pcie-phy
> > 2. Bifurcation mode (8-lane): pcie3a phy acts as leader and pcie3b phy as
> >    follower to form a single 8-lane PCIe Gen5 interface
> > 
> > In bifurcation mode, the hardware design requires controlling additional
> > resources beyond the standard pcie3a PHY configuration:
> > 
> > - pcie3b's aux_clk (phy_b_aux)
> > - pcie3b's phy_gdsc power domain
> > - pcie3b's bcr/nocsr reset
> > 
> > Add qcom,glymur-qmp-gen5x8-pcie-phy compatible string to document this
> > 8-lane bifurcation configuration.
> 
> Do you describe PCI3A or PCI3B or something combined PCI3?

I describe a single x8 PHY with resources from both the pcie3a and pcie3b
PHY blocks for x8 operation.

> 
> > 
> > The phy_b_aux clock is used as the 6th clock instead of pipediv2,
> > requiring the clock-names enum to be extended to support both
> > [phy_b_aux, pipediv2] options at index 5. This follows the existing
> > pattern used for [rchng, refgen] clocks at index 3.
> > 
> > Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
> > ---
> >  .../bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml   | 53 ++++++++++++++++++----
> >  1 file changed, 45 insertions(+), 8 deletions(-)
> > 
> > diff --git a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
> > index 3a35120a77ec0ceb814a1cdcacff32fef32b4f7b..14eba5d705b1956c1bb00cc8c95171ed6488299b 100644
> > --- a/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
> > +++ b/Documentation/devicetree/bindings/phy/qcom,sc8280xp-qmp-pcie-phy.yaml
> > @@ -18,6 +18,7 @@ properties:
> >      enum:
> >        - qcom,glymur-qmp-gen4x2-pcie-phy
> >        - qcom,glymur-qmp-gen5x4-pcie-phy
> > +      - qcom,glymur-qmp-gen5x8-pcie-phy
> 
> That's the same device as 5x4, no? One device, one compatible and this
> suggests you will have three PCI phys in the DT - two 5x4 and one 5x8?
> 

It is not the same as the 5x4 PHY. In DT, we model three PHY nodes:
phy_3a (1x4), phy_3b (1x4), and a separate phy_1x8 node for x8 mode.

> 
> >        - qcom,kaanapali-qmp-gen3x2-pcie-phy
> >        - qcom,qcs615-qmp-gen3x1-pcie-phy
> >        - qcom,qcs8300-qmp-gen4x2-pcie-phy
> > @@ -68,20 +69,27 @@ properties:
> >        - const: ref
> >        - enum: [rchng, refgen]
> >        - const: pipe
> > -      - const: pipediv2
> > +      - enum: [phy_b_aux, pipediv2]
> >  
> >    power-domains:
> > -    maxItems: 1
> > +    minItems: 1
> > +    items:
> > +      - description: PCIe PHY power domain. For PHYs supporting
> > +          bifurcation mode, this is the leader PHY power domain.
> > +      - description: Additional PCIe PHY power domain for PHYs supporting
> > +          bifurcation mode, used by the follower PHY.
> >  
> >    resets:
> >      minItems: 1
> > -    maxItems: 2
> > +    maxItems: 4
> >  
> >    reset-names:
> >      minItems: 1
> >      items:
> >        - const: phy
> >        - const: phy_nocsr
> > +      - const: phy_b
> > +      - const: phy_b_nocsr
> 
> And now I doubt that all the changes here are for duplicated node.
>

All the changes here are for 1x8 PHY node.

> Maybe just the commit msg is confusing and instead of describing some
> node which combines two other phys just say what device is here being
> described.
>

Okay, I will focus on describing the required resources. Is the
description below clearer?

Glymur has two physical Gen5x4 PCIe PHY blocks: pcie3a phy and pcie3b phy.

Besides the independent 2x4 topology, Glymur also supports an x8 topology
that is described as a dedicated 1x8 PHY DT node. In this topology, the
x8 PHY uses resources from both PHY blocks: pcie3a (leader) and pcie3b
(follower) resources.

Add qcom,glymur-qmp-gen5x8-pcie-phy to describe this x8 PHY node and
document its extra required resources:
- pcie3b PHY aux clock (phy_b_aux)
- pcie3b PHY power domain
- pcie3b PHY BCR/NOCSR resets

The phy_b_aux clock is used as the 6th clock instead of pipediv2,
requiring the clock-names enum to be extended to support both
[phy_b_aux, pipediv2] options at index 5. This follows the existing
pattern used for [rchng, refgen] clocks at index 3.

- Qiang Yu

> Best regards,
> Krzysztof
> 

^ permalink raw reply

* Re: [PATCH v3 3/5] phy: qcom: qmp-pcie: Support multiple nocsr resets
From: Qiang Yu @ 2026-04-16  3:02 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bjorn Andersson, Konrad Dybcio, linux-arm-msm,
	linux-phy, devicetree, linux-kernel
In-Reply-To: <2675a315153c83c14d1581e019fdddb611139da7.camel@pengutronix.de>

On Mon, Apr 13, 2026 at 10:10:31AM +0200, Philipp Zabel wrote:
> On So, 2026-04-12 at 23:25 -0700, Qiang Yu wrote:
> > Refactor nocsr reset handling to support multiple nocsr resets required
> > for PHY configurations with bifurcated operation modes.
> > 
> > The Glymur SoC's 3rd PCIe instance supports 8-lane mode using two PHYs
> > in bifurcation, where each PHY requires its own nocsr reset to be
> > controlled simultaneously. The current implementation only supports a
> > single nocsr reset per PHY configuration.
> > 
> > Add num_nocsr and nocsr_list fields to struct qmp_phy_cfg to represent the
> > number and names of a group of nocsr reset names. Initialize these fields
> > for all PHYs that have nocsr resets, allowing the driver to correctly
> > acquire multiple nocsr resets during probe and control them as an array
> > by using reset_control_bulk APIs.
> > 
> > The refactoring maintains backward compatibility for existing single
> > nocsr reset configurations while enabling support for multi-PHY
> > scenarios like Glymur's 8-lane bifurcation mode.
> > 
> > Additionally, introduces x1e80100_qmp_gen3x2_pciephy_cfg as a separate
> > configuration from sm8550_qmp_gen3x2_pciephy_cfg since the x1e80100 Gen3x2
> > PHY requires nocsr reset support while the sm8550 Gen3x2 PHY does not.
> > 
> > Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
> > ---
> >  drivers/phy/qualcomm/phy-qcom-qmp-pcie.c | 87 ++++++++++++++++++++++++++++----
> >  1 file changed, 77 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> > index 424c935e27a8766e1e26762bd3d7df527c1520e3..51db9eea41255bad0034bbcfbfdc36894c2bc95f 100644
> > --- a/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> > +++ b/drivers/phy/qualcomm/phy-qcom-qmp-pcie.c
> [...]
> > @@ -4998,14 +5054,25 @@ static int qmp_pcie_reset_init(struct qmp_pcie *qmp)
> >  	for (i = 0; i < cfg->num_resets; i++)
> >  		qmp->resets[i].id = cfg->reset_list[i];
> >  
> > -	ret = devm_reset_control_bulk_get_exclusive(dev, cfg->num_resets, qmp->resets);
> > +	ret = devm_reset_control_bulk_get_exclusive(dev, cfg->num_resets,
> > +						    qmp->resets);
> 
> Unrelated and unnecessary change.

Ohk, I changed it by mistake.

> 
> >  	if (ret)
> >  		return dev_err_probe(dev, ret, "failed to get resets\n");
> >  
> > -	qmp->nocsr_reset = devm_reset_control_get_optional_exclusive(dev, "phy_nocsr");
> > -	if (IS_ERR(qmp->nocsr_reset))
> > -		return dev_err_probe(dev, PTR_ERR(qmp->nocsr_reset),
> > -							"failed to get no-csr reset\n");
> > +	if (!cfg->num_nocsr_resets)
> > +		return 0;
> > +	qmp->nocsr_reset = devm_kcalloc(dev, cfg->num_nocsr_resets,
> > +				   sizeof(*qmp->nocsr_reset), GFP_KERNEL);
> > +	if (!qmp->nocsr_reset)
> > +		return -ENOMEM;
> > +
> > +	for (i = 0; i < cfg->num_nocsr_resets; i++)
> > +		qmp->nocsr_reset[i].id = cfg->nocsr_reset_list[i];
> > +
> > +	ret = devm_reset_control_bulk_get_exclusive(dev, cfg->num_nocsr_resets,
> > +						    qmp->nocsr_reset);
> 
> Should this be devm_reset_control_bulk_get_optional_exclusive()?
> 

I have get the num_nocsr_resets previously, so don't need to use
devm_reset_control_bulk_get_optional_exclusive.

- Qiang Yu
> regards
> Philipp

^ permalink raw reply

* [PATCH v3 0/6] soc: mediatek: Add devapc support
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group,
	Xiaoshun Xu

From: Xiaoshun Xu <xiaoshun.xu@mediatek.corp-partner.google.com>

Based on tag: next-20260415, linux-next/master

This series of patches add support for Mediatek devapc of MT8189 and
MT8196 soc.

Xiaoshun Xu (6):
  soc: mediatek: mtk-devapc: refine devapc interrupt handler
  soc: mediatek: mtk-devapc: refine DEVAPC clock control
  soc: mediatek: mtk-devapc: Add support for MT8189 DEVAPC
  dt-bindings: soc: mediatek: devapc: Add bindings for MT8189
  soc: mediatek: mtk-devapc: Add support for MT8196 DEVAPC
  dt-bindings: soc: mediatek: devapc: Add bindings for MT8196

Changes in v3:
  - Add support for MT8196 devapc
  - Updated yaml for dt-bindings

Changes in v2:
  - Updated cover letter subject
  - Updated yaml for dt-bindings
  - Add support for MT8189 devapc
  - Refine devapc clock control flow
  - Refine devapc interrupt handler

Changes in v1:
  - Add support for MT8189 devapc
  - Updated yaml for MT8189

 .../bindings/soc/mediatek/devapc.yaml         |  11 +-
 drivers/soc/mediatek/mtk-devapc.c             | 197 ++++++++++++++----
 2 files changed, 168 insertions(+), 40 deletions(-)

-- 
2.45.2


^ permalink raw reply

* [PATCH v3 1/6] soc: mediatek: mtk-devapc: refine devapc interrupt handler
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Because the violation IRQ uses a while loop, it might cause the
system to remain in the interrupt handler indefinitely. We are
currently optimizing this part of the process to handle only 20
violations for debug violation issues, and then exit the loop

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index f54c966138b5..c9e1401315ad 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -12,6 +12,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
 
+#define MAX_VIO_NUM 20
 #define VIO_MOD_TO_REG_IND(m)	((m) / 32)
 #define VIO_MOD_TO_REG_OFF(m)	((m) % 32)
 
@@ -188,13 +189,18 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
  */
 static irqreturn_t devapc_violation_irq(int irq_number, void *data)
 {
+	u32 vio_num = 0;
 	struct mtk_devapc_context *ctx = data;
 
-	while (devapc_sync_vio_dbg(ctx))
+	mask_module_irq(ctx, true);
+
+	for (vio_num = 0; (vio_num < MAX_VIO_NUM) && (devapc_sync_vio_dbg(ctx)); ++vio_num)
 		devapc_extract_vio_dbg(ctx);
 
 	clear_vio_status(ctx);
 
+	mask_module_irq(ctx, false);
+
 	return IRQ_HANDLED;
 }
 
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 3/6] soc: mediatek: mtk-devapc: Add support for MT8189 DEVAPC
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Add support for MT8189 DEVAPC, DEVAPC debug registers have new version,
so refine the structure of devapc_regs_ofs_xxxx to devapc_regs_ofs_verX,
and rename the infra_base to base in mtk_devapc_context because devapc
not only access the infra_base to dump debug information when violation
happens

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 171 +++++++++++++++++++++++-------
 1 file changed, 134 insertions(+), 37 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index f54e310791e5..824b49613c5a 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -27,9 +27,19 @@ struct mtk_devapc_vio_dbgs {
 			u32 addr_h:4;
 			u32 resv:4;
 		} dbg0_bits;
+
+		struct {
+			u32 dmnid:6;
+			u32 vio_w:1;
+			u32 vio_r:1;
+			u32 addr_h:4;
+			u32 resv:20;
+		} dbg0_bits_ver2;
 	};
 
 	u32 vio_dbg1;
+	u32 vio_dbg2;
+	u32 vio_dbg3;
 };
 
 struct mtk_devapc_regs_ofs {
@@ -38,6 +48,8 @@ struct mtk_devapc_regs_ofs {
 	u32 vio_sta_offset;
 	u32 vio_dbg0_offset;
 	u32 vio_dbg1_offset;
+	u32 vio_dbg2_offset;
+	u32 vio_dbg3_offset;
 	u32 apc_con_offset;
 	u32 vio_shift_sta_offset;
 	u32 vio_shift_sel_offset;
@@ -45,16 +57,20 @@ struct mtk_devapc_regs_ofs {
 };
 
 struct mtk_devapc_data {
-	/* numbers of violation index */
-	u32 vio_idx_num;
+	u32 version;
+	/* Default numbers of violation index */
+	u32 default_vio_idx_num;
 	const struct mtk_devapc_regs_ofs *regs_ofs;
 };
 
 struct mtk_devapc_context {
 	struct device *dev;
-	void __iomem *infra_base;
+	void __iomem *base;
 	struct clk *infra_clk;
 	const struct mtk_devapc_data *data;
+
+	/* numbers of violation index */
+	u32 vio_idx_num;
 };
 
 static void clear_vio_status(struct mtk_devapc_context *ctx)
@@ -62,12 +78,12 @@ static void clear_vio_status(struct mtk_devapc_context *ctx)
 	void __iomem *reg;
 	int i;
 
-	reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
+	reg = ctx->base + ctx->data->regs_ofs->vio_sta_offset;
 
-	for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+	for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
 		writel(GENMASK(31, 0), reg + 4 * i);
 
-	writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
+	writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1), 0),
 	       reg + 4 * i);
 }
 
@@ -77,22 +93,22 @@ static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
 	u32 val;
 	int i;
 
-	reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
+	reg = ctx->base + ctx->data->regs_ofs->vio_mask_offset;
 
 	if (mask)
 		val = GENMASK(31, 0);
 	else
 		val = 0;
 
-	for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+	for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->vio_idx_num - 1); i++)
 		writel(val, reg + 4 * i);
 
 	val = readl(reg + 4 * i);
 	if (mask)
-		val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+		val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
 			       0);
 	else
-		val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+		val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->vio_idx_num - 1),
 				0);
 
 	writel(val, reg + 4 * i);
@@ -119,11 +135,11 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
 	int ret;
 	u32 val;
 
-	pd_vio_shift_sta_reg = ctx->infra_base +
+	pd_vio_shift_sta_reg = ctx->base +
 			       ctx->data->regs_ofs->vio_shift_sta_offset;
-	pd_vio_shift_sel_reg = ctx->infra_base +
+	pd_vio_shift_sel_reg = ctx->base +
 			       ctx->data->regs_ofs->vio_shift_sel_offset;
-	pd_vio_shift_con_reg = ctx->infra_base +
+	pd_vio_shift_con_reg = ctx->base +
 			       ctx->data->regs_ofs->vio_shift_con_offset;
 
 	/* Find the minimum shift group which has violation */
@@ -134,7 +150,7 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
 	min_shift_group = __ffs(val);
 
 	/* Assign the group to sync */
-	writel(0x1 << min_shift_group, pd_vio_shift_sel_reg);
+	writel(BIT(min_shift_group), pd_vio_shift_sel_reg);
 
 	/* Start syncing */
 	writel(0x1, pd_vio_shift_con_reg);
@@ -150,7 +166,7 @@ static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
 	writel(0x0, pd_vio_shift_con_reg);
 
 	/* Write clear */
-	writel(0x1 << min_shift_group, pd_vio_shift_sta_reg);
+	writel(BIT(min_shift_group), pd_vio_shift_sta_reg);
 
 	return true;
 }
@@ -164,22 +180,52 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
 	struct mtk_devapc_vio_dbgs vio_dbgs;
 	void __iomem *vio_dbg0_reg;
 	void __iomem *vio_dbg1_reg;
+	void __iomem *vio_dbg2_reg;
+	void __iomem *vio_dbg3_reg;
+	u32 vio_addr_l, vio_addr_h, bus_id, domain_id;
+	u32 vio_w, vio_r;
+	u64 vio_addr;
 
-	vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
-	vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+	vio_dbg0_reg = ctx->base + ctx->data->regs_ofs->vio_dbg0_offset;
+	vio_dbg1_reg = ctx->base + ctx->data->regs_ofs->vio_dbg1_offset;
+	vio_dbg2_reg = ctx->base + ctx->data->regs_ofs->vio_dbg2_offset;
+	vio_dbg3_reg = ctx->base + ctx->data->regs_ofs->vio_dbg3_offset;
 
 	vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
 	vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+	if (ctx->data->version >= 2U)
+		vio_dbgs.vio_dbg2 = readl(vio_dbg2_reg);
+	if (ctx->data->version == 3U)
+		vio_dbgs.vio_dbg3 = readl(vio_dbg3_reg);
+
+	if (ctx->data->version == 1U) {
+		/* arch version 1 */
+		bus_id = vio_dbgs.dbg0_bits.mstid;
+		vio_addr = vio_dbgs.vio_dbg1;
+		domain_id = vio_dbgs.dbg0_bits.dmnid;
+		vio_w = vio_dbgs.dbg0_bits.vio_w;
+		vio_r = vio_dbgs.dbg0_bits.vio_r;
+	} else {
+		/* arch version 2 & 3 */
+		bus_id = vio_dbgs.vio_dbg1;
+
+		vio_addr_l = vio_dbgs.vio_dbg2;
+		vio_addr_h = ctx->data->version == 2U ? vio_dbgs.dbg0_bits_ver2.addr_h :
+							vio_dbgs.vio_dbg3;
+		vio_addr = ((u64)vio_addr_h << 32) + vio_addr_l;
+		domain_id = vio_dbgs.dbg0_bits_ver2.dmnid;
+		vio_w = vio_dbgs.dbg0_bits_ver2.vio_w;
+		vio_r = vio_dbgs.dbg0_bits_ver2.vio_r;
+	}
 
 	/* Print violation information */
-	if (vio_dbgs.dbg0_bits.vio_w)
+	if (vio_w)
 		dev_info(ctx->dev, "Write Violation\n");
-	else if (vio_dbgs.dbg0_bits.vio_r)
+	else if (vio_r)
 		dev_info(ctx->dev, "Read Violation\n");
 
-	dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
-		 vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
-		 vio_dbgs.vio_dbg1);
+	dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%llx\n",
+		 bus_id, domain_id, vio_addr);
 }
 
 /*
@@ -209,7 +255,8 @@ static irqreturn_t devapc_violation_irq(int irq_number, void *data)
  */
 static void start_devapc(struct mtk_devapc_context *ctx)
 {
-	writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+
+	writel(BIT(31), ctx->base + ctx->data->regs_ofs->apc_con_offset);
 
 	mask_module_irq(ctx, false);
 }
@@ -221,28 +268,60 @@ static void stop_devapc(struct mtk_devapc_context *ctx)
 {
 	mask_module_irq(ctx, true);
 
-	writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+	writel(BIT(2), ctx->base + ctx->data->regs_ofs->apc_con_offset);
 }
 
-static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver1 = {
+	.vio_mask_offset = 0x0,
+	.vio_sta_offset = 0x400,
+	.vio_dbg0_offset = 0x900,
+	.vio_dbg1_offset = 0x904,
+	.apc_con_offset = 0xf00,
+	.vio_shift_sta_offset = 0xf10,
+	.vio_shift_sel_offset = 0xf14,
+	.vio_shift_con_offset = 0xf20,
+};
+
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver2 = {
 	.vio_mask_offset = 0x0,
 	.vio_sta_offset = 0x400,
 	.vio_dbg0_offset = 0x900,
 	.vio_dbg1_offset = 0x904,
-	.apc_con_offset = 0xF00,
-	.vio_shift_sta_offset = 0xF10,
-	.vio_shift_sel_offset = 0xF14,
-	.vio_shift_con_offset = 0xF20,
+	.vio_dbg2_offset = 0x908,
+	.apc_con_offset = 0xf00,
+	.vio_shift_sta_offset = 0xf20,
+	.vio_shift_sel_offset = 0xf30,
+	.vio_shift_con_offset = 0xf10,
+};
+
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_ver3 = {
+	.vio_mask_offset = 0x0,
+	.vio_sta_offset = 0x400,
+	.vio_dbg0_offset = 0x900,
+	.vio_dbg1_offset = 0x904,
+	.vio_dbg2_offset = 0x908,
+	.vio_dbg3_offset = 0x90c,
+	.apc_con_offset = 0xf00,
+	.vio_shift_sta_offset = 0xf20,
+	.vio_shift_sel_offset = 0xf30,
+	.vio_shift_con_offset = 0xf10,
 };
 
 static const struct mtk_devapc_data devapc_mt6779 = {
-	.vio_idx_num = 511,
-	.regs_ofs = &devapc_regs_ofs_mt6779,
+	.version = 1,
+	.default_vio_idx_num = 511,
+	.regs_ofs = &devapc_regs_ofs_ver1,
 };
 
 static const struct mtk_devapc_data devapc_mt8186 = {
-	.vio_idx_num = 519,
-	.regs_ofs = &devapc_regs_ofs_mt6779,
+	.version = 1,
+	.default_vio_idx_num = 519,
+	.regs_ofs = &devapc_regs_ofs_ver1,
+};
+
+static const struct mtk_devapc_data devapc_mt8189 = {
+	.version = 3,
+	.regs_ofs = &devapc_regs_ofs_ver3,
 };
 
 static const struct of_device_id mtk_devapc_dt_match[] = {
@@ -252,6 +331,9 @@ static const struct of_device_id mtk_devapc_dt_match[] = {
 	}, {
 		.compatible = "mediatek,mt8186-devapc",
 		.data = &devapc_mt8186,
+	}, {
+		.compatible = "mediatek,mt8189-devapc",
+		.data = &devapc_mt8189,
 	}, {
 	},
 };
@@ -274,9 +356,24 @@ static int mtk_devapc_probe(struct platform_device *pdev)
 	ctx->data = of_device_get_match_data(&pdev->dev);
 	ctx->dev = &pdev->dev;
 
-	ctx->infra_base = of_iomap(node, 0);
-	if (!ctx->infra_base)
+	ctx->base = of_iomap(node, 0);
+	if (!ctx->base) {
+		dev_err(ctx->dev, "Failed to map devapc registers\n");
 		return -EINVAL;
+	}
+
+	/*
+	 * Set effective vio_idx_num from default value.
+	 * If vio_idx_num is 0, get the info from DT.
+	 */
+	ctx->vio_idx_num = ctx->data->default_vio_idx_num;
+	if (ctx->vio_idx_num == 0)
+		if (of_property_read_u32(node,
+					 "vio-idx-num",
+					 &ctx->vio_idx_num)) {
+			ret = -EINVAL;
+			goto err;
+		}
 
 	devapc_irq = irq_of_parse_and_map(node, 0);
 	if (!devapc_irq) {
@@ -314,7 +411,7 @@ static int mtk_devapc_probe(struct platform_device *pdev)
 	return 0;
 
 err:
-	iounmap(ctx->infra_base);
+	iounmap(ctx->base);
 	return ret;
 }
 
@@ -326,7 +423,7 @@ static void mtk_devapc_remove(struct platform_device *pdev)
 
 	clk_disable_unprepare(ctx->infra_clk);
 
-	iounmap(ctx->infra_base);
+	iounmap(ctx->base);
 }
 
 static struct platform_driver mtk_devapc_driver = {
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 2/6] soc: mediatek: mtk-devapc: refine DEVAPC clock control
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Because the new DEVAPC design, DEVAPC clock is controlled by
HW power domains, the control flow of DEVAPC clock is not
necessary, but to maintain compatibility with legacy ICs,
keep this part of code.

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 25 ++++++++++++++++++++-----
 1 file changed, 20 insertions(+), 5 deletions(-)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index c9e1401315ad..f54e310791e5 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -284,16 +284,28 @@ static int mtk_devapc_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+	/*
+	 * The new design of DAPC clock is controlled by HW power domains,
+	 * making it unnecessary to provide the clock control driver.
+	 */
+	ctx->infra_clk = devm_clk_get_optional(&pdev->dev, "devapc-infra-clock");
 	if (IS_ERR(ctx->infra_clk)) {
-		ret = -EINVAL;
-		goto err;
+		dev_err(ctx->dev, "Cannot get devapc clock from CCF\n");
+		ctx->infra_clk = NULL;
+	} else {
+		if (clk_prepare_enable(ctx->infra_clk)) {
+			ret = -EINVAL;
+			goto err;
+		}
 	}
 
 	ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
-			       IRQF_TRIGGER_NONE, "devapc", ctx);
-	if (ret)
+			       IRQF_TRIGGER_NONE | IRQF_SHARED, "devapc", ctx);
+	if (ret) {
+		if (ctx->infra_clk)
+			clk_disable_unprepare(ctx->infra_clk);
 		goto err;
+	}
 
 	platform_set_drvdata(pdev, ctx);
 
@@ -311,6 +323,9 @@ static void mtk_devapc_remove(struct platform_device *pdev)
 	struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
 
 	stop_devapc(ctx);
+
+	clk_disable_unprepare(ctx->infra_clk);
+
 	iounmap(ctx->infra_base);
 }
 
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 4/6] dt-bindings: soc: mediatek: devapc: Add bindings for MT8189
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Extend the devapc device tree bindings to support the MediaTek MT8189
SoC. This includes:

- Adding "mediatek,mt8189-devapc" to the list of compatible strings.
- Introducing the "vio-idx-num" property to specify the number of bus
  slaves managed by devapc.

These changes enable proper configuration and integration of devapc on
MT8189 platforms, ensuring accurate device matching and resource
allocation in the device tree.

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 .../devicetree/bindings/soc/mediatek/devapc.yaml       | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
index 99e2caafeadf..06a096440331 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
@@ -14,13 +14,14 @@ description: |
   analysis and countermeasures.
 
 maintainers:
-  - Neal Liu <neal.liu@mediatek.com>
+  - Xiaoshun Xu <xiaoshun.xu@mediatek.com>
 
 properties:
   compatible:
     enum:
       - mediatek,mt6779-devapc
       - mediatek,mt8186-devapc
+      - mediatek,mt8189-devapc
 
   reg:
     description: The base address of devapc register bank
@@ -30,6 +31,10 @@ properties:
     description: A single interrupt specifier
     maxItems: 1
 
+  vio-idx-num:
+    description: Describe the number of bus slaves controlled by devapc
+    $ref: /schemas/types.yaml#/definitions/uint32
+
   clocks:
     description: Contains module clock source and clock names
     maxItems: 1
@@ -42,8 +47,6 @@ required:
   - compatible
   - reg
   - interrupts
-  - clocks
-  - clock-names
 
 additionalProperties: false
 
@@ -55,6 +58,7 @@ examples:
     devapc: devapc@10207000 {
       compatible = "mediatek,mt6779-devapc";
       reg = <0x10207000 0x1000>;
+      vio-idx-num = <132>;
       interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_LOW>;
       clocks = <&infracfg_ao CLK_INFRA_DEVICE_APC>;
       clock-names = "devapc-infra-clock";
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 5/6] soc: mediatek: mtk-devapc: Add support for MT8196 DEVAPC
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Add support for MT8196 DEVAPC, MT8196 DEVAPC debug registers are
version 3 and add compatible for MT8196

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 drivers/soc/mediatek/mtk-devapc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
index 824b49613c5a..0f828028bdb4 100644
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -324,6 +324,11 @@ static const struct mtk_devapc_data devapc_mt8189 = {
 	.regs_ofs = &devapc_regs_ofs_ver3,
 };
 
+static const struct mtk_devapc_data devapc_mt8196 = {
+	.version = 3,
+	.regs_ofs = &devapc_regs_ofs_ver3,
+};
+
 static const struct of_device_id mtk_devapc_dt_match[] = {
 	{
 		.compatible = "mediatek,mt6779-devapc",
@@ -334,6 +339,9 @@ static const struct of_device_id mtk_devapc_dt_match[] = {
 	}, {
 		.compatible = "mediatek,mt8189-devapc",
 		.data = &devapc_mt8189,
+	}, {
+		.compatible = "mediatek,mt8196-devapc",
+		.data = &devapc_mt8196,
 	}, {
 	},
 };
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 6/6] dt-bindings: soc: mediatek: devapc: Add bindings for MT8196
From: Xiaoshun Xu @ 2026-04-16  3:12 UTC (permalink / raw)
  To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Xiaoshun Xu
  Cc: devicetree, linux-kernel, linux-arm-kernel, linux-mediatek,
	Sirius Wang, Vince-wl Liu, Project_Global_Chrome_Upstream_Group
In-Reply-To: <20260416031231.2932493-1-xiaoshun.xu@mediatek.com>

Extend the devapc device tree bindings to support the MediaTek MT8196
SoC. This includes:

- Adding "mediatek,mt8196-devapc" to the list of compatible strings.

These changes enable proper configuration and integration of devapc on
MT8196 platforms, ensuring accurate device matching and resource
allocation in the device tree.

Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
---
 Documentation/devicetree/bindings/soc/mediatek/devapc.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
index 06a096440331..5eb260bf3dde 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
+++ b/Documentation/devicetree/bindings/soc/mediatek/devapc.yaml
@@ -22,6 +22,7 @@ properties:
       - mediatek,mt6779-devapc
       - mediatek,mt8186-devapc
       - mediatek,mt8189-devapc
+      - mediatek,mt8196-devapc
 
   reg:
     description: The base address of devapc register bank
-- 
2.45.2


^ permalink raw reply related

* Re: [PATCH v3 5/5] arch: arm64: dts: qcom: Add support for PCIe3a
From: Qiang Yu @ 2026-04-16  3:24 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Bjorn Andersson, Konrad Dybcio,
	linux-arm-msm, linux-phy, devicetree, linux-kernel
In-Reply-To: <20260415-pragmatic-termite-of-attraction-3dbab5@quoll>

On Wed, Apr 15, 2026 at 09:44:15AM +0200, Krzysztof Kozlowski wrote:
> On Sun, Apr 12, 2026 at 11:26:00PM -0700, Qiang Yu wrote:
> > Describe PCIe3a controller and PHY. Also add required system resources
> > like regulators, clocks, interrupts and registers configuration for PCIe3a.
> > 
> > Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
> 
> subject: drop arch.
> 
> Please use subject prefixes matching the subsystem. You can get them for
> example with 'git log --oneline -- DIRECTORY_OR_FILE' on the directory
> your patch is touching. For bindings, the preferred subjects are
> explained here:
> https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
>

Thanks for pointing me the link. I’ll drop arch: in next version.

> > ---
> >  arch/arm64/boot/dts/qcom/glymur.dtsi | 316 ++++++++++++++++++++++++++++++++++-
> >  1 file changed, 315 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
> > index f23cf81ddb77a4138deeb4e00dd8b316930a2feb..c15f87c37ecbad72076a6c731f4959a1a8bd8425 100644
> > --- a/arch/arm64/boot/dts/qcom/glymur.dtsi
> > +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
> > @@ -736,7 +736,7 @@ gcc: clock-controller@100000 {
> >  				 <0>,				/* USB 2 Phy PCIE PIPEGMUX */
> >  				 <0>,				/* USB 2 Phy PIPEGMUX */
> >  				 <0>,				/* USB 2 Phy SYS PCIE PIPEGMUX */
> > -				 <0>,				/* PCIe 3a */
> > +				 <&pcie3a_phy>,			/* PCIe 3a */
> >  				 <&pcie3b_phy>,			/* PCIe 3b */
> >  				 <&pcie4_phy>,			/* PCIe 4 */
> >  				 <&pcie5_phy>,			/* PCIe 5 */
> > @@ -3640,6 +3640,320 @@ pcie3b_port0: pcie@0 {
> >  			};
> 
> ...
> 
> > > +		pcie3a_phy: phy@f00000 {
> 
> Same comment as before.
>

The existing PCIe/PHY nodes are not strictly ordered by address. Current
order is:

- pcie4: pci@1bf0000
- pcie4_phy: phy@1bf6000
- pcie5: pci@1b40000
- pcie5_phy: phy@1b50000
- pcie6: pci@1c00000
- pcie6_phy: phy@1c06000
- pcie3b: pci@1b80000
- pcie3a: pci@1c10000 (added in this patch)
- pcie3a_phy: phy@f00000 (added in this patch)
- pcie3b_phy: phy@f10000

Do you want me to reorder these nodes to follow strict address order?

- Qiang Yu

> Best regards,
> Krzysztof
> 

^ permalink raw reply

* Re: [PATCH v13 3/3] of: Respect #{iommu,msi}-cells in maps
From: Vijayanand Jitta @ 2026-04-16  3:26 UTC (permalink / raw)
  To: Nipun Gupta, Nikhil Agarwal, Joerg Roedel, Will Deacon,
	Robin Murphy, Marc Zyngier, Lorenzo Pieralisi, Thomas Gleixner,
	Saravana Kannan, Richard Zhu, Lucas Stach,
	Krzysztof Wilczyński, Manivannan Sadhasivam, Bjorn Helgaas,
	Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Juergen Gross, Stefano Stabellini, Oleksandr Tyshchenko,
	Dmitry Baryshkov, Konrad Dybcio, Bjorn Andersson, Rob Herring,
	Conor Dooley, Krzysztof Kozlowski, Prakash Gupta, Vikash Garodia
  Cc: linux-kernel, iommu, linux-arm-kernel, devicetree, linux-pci, imx,
	xen-devel, linux-arm-msm, Charan Teja Kalla
In-Reply-To: <20260408-parse_iommu_cells-v13-3-fa921e92661b@oss.qualcomm.com>



On 4/8/2026 3:33 PM, Vijayanand Jitta wrote:
> From: Robin Murphy <robin.murphy@arm.com>
> 
> So far our parsing of {iommu,msi}-map properties has always blindly
> assumed that the output specifiers will always have exactly 1 cell.
> This typically does happen to be the case, but is not actually enforced
> (and the PCI msi-map binding even explicitly states support for 0 or 1
> cells) - as a result we've now ended up with dodgy DTs out in the field
> which depend on this behaviour to map a 1-cell specifier for a 2-cell
> provider, despite that being bogus per the bindings themselves.
> 
> Since there is some potential use in being able to map at least single
> input IDs to multi-cell output specifiers (and properly support 0-cell
> outputs as well), add support for properly parsing and using the target
> nodes' #cells values, albeit with the unfortunate complication of still
> having to work around expectations of the old behaviour too.
> 
> Since there are multi-cell output specifiers, the callers of of_map_id()
> may need to get the exact cell output value for further processing.
> Update of_map_id() to set args_count in the output to reflect the actual
> number of output specifier cells.
> 
> Signed-off-by: Robin Murphy <robin.murphy@arm.com>
> Signed-off-by: Charan Teja Kalla <charan.kalla@oss.qualcomm.com>
> Signed-off-by: Vijayanand Jitta <vijayanand.jitta@oss.qualcomm.com>
> ---
>  drivers/of/base.c  | 157 +++++++++++++++++++++++++++++++++++++++++------------
>  include/linux/of.h |   6 +-
>  2 files changed, 125 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index b3d002015192..2554e4f1a181 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -2096,18 +2096,48 @@ int of_find_last_cache_level(unsigned int cpu)
>  	return cache_level;
>  }
>  
> +/*
> + * Some DTs have an iommu-map targeting a 2-cell IOMMU node while
> + * specifying only 1 cell. Fortunately they all consist of value '1'
> + * as the 2nd cell entry with the same target, so check for that pattern.
> + *
> + * Example:
> + *	IOMMU node:
> + *		#iommu-cells = <2>;
> + *
> + *	Device node:
> + *		iommu-map = <0x0000 &smmu 0x0000 0x1>,
> + *			    <0x0100 &smmu 0x0100 0x1>;
> + */
> +static bool of_check_bad_map(const __be32 *map, int len)
> +{
> +	__be32 phandle = map[1];
> +
> +	if (len % 4)
> +		return false;
> +	for (int i = 0; i < len; i += 4) {
> +		if (map[i + 1] != phandle || map[i + 3] != cpu_to_be32(1))
> +			return false;
> +	}
> +	return true;
> +}
> +
>  /**
>   * of_map_id - Translate an ID through a downstream mapping.
>   * @np: root complex device node.
>   * @id: device ID to map.
>   * @map_name: property name of the map to use.
> + * @cells_name: property name of target specifier cells.
>   * @map_mask_name: optional property name of the mask to use.
>   * @filter_np: optional device node to filter matches by, or NULL to match any.
>   *	If non-NULL, only map entries targeting this node will be matched.
>   * @arg: pointer to a &struct of_phandle_args for the result. On success,
> - *	@arg->args[0] will contain the translated ID. If a map entry was
> - *	matched, @arg->np will be set to the target node with a reference
> - *	held that the caller must release with of_node_put().
> + *	@arg->args_count will be set to the number of output specifier cells
> + *	as defined by @cells_name in the target node, and
> + *	@arg->args[0..args_count-1] will contain the translated output
> + *	specifier values. If a map entry was matched, @arg->np will be set
> + *	to the target node with a reference held that the caller must release
> + *	with of_node_put().
>   *
>   * Given a device ID, look up the appropriate implementation-defined
>   * platform ID and/or the target device which receives transactions on that
> @@ -2116,17 +2146,19 @@ int of_find_last_cache_level(unsigned int cpu)
>   * Return: 0 on success or a standard error code on failure.
>   */
>  int of_map_id(const struct device_node *np, u32 id,
> -	       const char *map_name, const char *map_mask_name,
> +	       const char *map_name, const char *cells_name,
> +	       const char *map_mask_name,
>  	       const struct device_node *filter_np, struct of_phandle_args *arg)
>  {
>  	u32 map_mask, masked_id;
> -	int map_len;
> +	int map_bytes, map_len, offset = 0;
> +	bool bad_map = false;
>  	const __be32 *map = NULL;
>  
>  	if (!np || !map_name || !arg)
>  		return -EINVAL;
>  
> -	map = of_get_property(np, map_name, &map_len);
> +	map = of_get_property(np, map_name, &map_bytes);
>  	if (!map) {
>  		if (filter_np)
>  			return -ENODEV;
> @@ -2136,11 +2168,9 @@ int of_map_id(const struct device_node *np, u32 id,
>  		return 0;
>  	}
>  
> -	if (!map_len || map_len % (4 * sizeof(*map))) {
> -		pr_err("%pOF: Error: Bad %s length: %d\n", np,
> -			map_name, map_len);
> -		return -EINVAL;
> -	}
> +	if (map_bytes % sizeof(*map))
> +		goto err_map_len;
> +	map_len = map_bytes / sizeof(*map);
>  
>  	/* The default is to select all bits. */
>  	map_mask = 0xffffffff;
> @@ -2153,39 +2183,84 @@ int of_map_id(const struct device_node *np, u32 id,
>  		of_property_read_u32(np, map_mask_name, &map_mask);
>  
>  	masked_id = map_mask & id;
> -	for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) {
> +
> +	while (offset < map_len) {
>  		struct device_node *phandle_node;
> -		u32 id_base = be32_to_cpup(map + 0);
> -		u32 phandle = be32_to_cpup(map + 1);
> -		u32 out_base = be32_to_cpup(map + 2);
> -		u32 id_len = be32_to_cpup(map + 3);
> +		u32 id_base, phandle, id_len, id_off, cells = 0;
> +		const __be32 *out_base;
> +
> +		if (map_len - offset < 2)
> +			goto err_map_len;
> +
> +		id_base = be32_to_cpup(map + offset);
>  
>  		if (id_base & ~map_mask) {
> -			pr_err("%pOF: Invalid %s translation - %s-mask (0x%x) ignores id-base (0x%x)\n",
> -				np, map_name, map_name,
> -				map_mask, id_base);
> +			pr_err("%pOF: Invalid %s translation - %s (0x%x) ignores id-base (0x%x)\n",
> +			       np, map_name, map_mask_name, map_mask, id_base);
>  			return -EFAULT;
>  		}
>  
> -		if (masked_id < id_base || masked_id >= id_base + id_len)
> -			continue;
> -
> +		phandle = be32_to_cpup(map + offset + 1);
>  		phandle_node = of_find_node_by_phandle(phandle);
>  		if (!phandle_node)
>  			return -ENODEV;
>  
> +		if (bad_map) {
> +			cells = 1;
> +		} else if (of_property_read_u32(phandle_node, cells_name, &cells)) {
> +			pr_err("%pOF: missing %s property\n", phandle_node, cells_name);
> +			of_node_put(phandle_node);
> +			return -EINVAL;
> +		}
> +
> +		if (map_len - offset < 3 + cells) {
> +			of_node_put(phandle_node);
> +			goto err_map_len;
> +		}
> +
> +		if (offset == 0 && cells == 2) {
> +			bad_map = of_check_bad_map(map, map_len);
> +			if (bad_map) {
> +				pr_warn_once("%pOF: %s mismatches target %s, assuming extra cell of 0\n",
> +					     np, map_name, cells_name);
> +				cells = 1;
> +			}
> +		}
> +
> +		out_base = map + offset + 2;
> +		offset += 3 + cells;
> +
> +		id_len = be32_to_cpup(map + offset - 1);
> +		if (id_len > 1 && cells > 1) {
> +			/*
> +			 * With 1 output cell we reasonably assume its value
> +			 * has a linear relationship to the input; with more,
> +			 * we'd need help from the provider to know what to do.
> +			 */
> +			pr_err("%pOF: Unsupported %s - cannot handle %d-ID range with %d-cell output specifier\n",
> +			       np, map_name, id_len, cells);
> +			of_node_put(phandle_node);
> +			return -EINVAL;
> +		}
> +		id_off = masked_id - id_base;
> +		if (masked_id < id_base || id_off >= id_len) {
> +			of_node_put(phandle_node);
> +			continue;
> +		}
> +
>  		if (filter_np && filter_np != phandle_node) {
>  			of_node_put(phandle_node);
>  			continue;
>  		}
>  
>  		arg->np = phandle_node;
> -		arg->args[0] = masked_id - id_base + out_base;
> -		arg->args_count = 1;
> +		for (int i = 0; i < cells; i++)
> +			arg->args[i] = id_off + be32_to_cpu(out_base[i]);
> +		arg->args_count = cells;
>  
>  		pr_debug("%pOF: %s, using mask %08x, id-base: %08x, out-base: %08x, length: %08x, id: %08x -> %08x\n",
> -			np, map_name, map_mask, id_base, out_base,
> -			id_len, id, masked_id - id_base + out_base);
> +			np, map_name, map_mask, id_base, be32_to_cpup(out_base),
> +			id_len, id, id_off + be32_to_cpup(out_base));
>  		return 0;
>  	}
>  
> @@ -2196,6 +2271,10 @@ int of_map_id(const struct device_node *np, u32 id,
>  	arg->args[0] = id;
>  	arg->args_count = 1;
>  	return 0;
> +
> +err_map_len:
> +	pr_err("%pOF: Error: Bad %s length: %d\n", np, map_name, map_bytes);
> +	return -EINVAL;
>  }
>  EXPORT_SYMBOL_GPL(of_map_id);
>  
> @@ -2205,18 +2284,21 @@ EXPORT_SYMBOL_GPL(of_map_id);
>   * @id: Requester ID of the device (e.g. PCI RID/BDF or a platform
>   *      stream/device ID) used as the lookup key in the iommu-map table.
>   * @arg: pointer to a &struct of_phandle_args for the result. On success,
> - *	@arg->args[0] contains the translated ID. If a map entry was matched,
> - *	@arg->np holds a reference to the target node that the caller must
> - *	release with of_node_put().
> + *	@arg->args_count will be set to the number of output specifier cells
> + *	and @arg->args[0..args_count-1] will contain the translated output
> + *	specifier values. If a map entry was matched, @arg->np holds a
> + *	reference to the target node that the caller must release with
> + *	of_node_put().
>   *
> - * Convenience wrapper around of_map_id() using "iommu-map" and "iommu-map-mask".
> + * Convenience wrapper around of_map_id() using "iommu-map", "#iommu-cells",
> + * and "iommu-map-mask".
>   *
>   * Return: 0 on success or a standard error code on failure.
>   */
>  int of_map_iommu_id(const struct device_node *np, u32 id,
>  		    struct of_phandle_args *arg)
>  {
> -	return of_map_id(np, id, "iommu-map", "iommu-map-mask", NULL, arg);
> +	return of_map_id(np, id, "iommu-map", "#iommu-cells", "iommu-map-mask", NULL, arg);
>  }
>  EXPORT_SYMBOL_GPL(of_map_iommu_id);
>  
> @@ -2229,17 +2311,20 @@ EXPORT_SYMBOL_GPL(of_map_iommu_id);
>   *	to match any. If non-NULL, only map entries targeting this node will
>   *	be matched.
>   * @arg: pointer to a &struct of_phandle_args for the result. On success,
> - *	@arg->args[0] contains the translated ID. If a map entry was matched,
> - *	@arg->np holds a reference to the target node that the caller must
> - *	release with of_node_put().
> + *	@arg->args_count will be set to the number of output specifier cells
> + *	and @arg->args[0..args_count-1] will contain the translated output
> + *	specifier values. If a map entry was matched, @arg->np holds a
> + *	reference to the target node that the caller must release with
> + *	of_node_put().
>   *
> - * Convenience wrapper around of_map_id() using "msi-map" and "msi-map-mask".
> + * Convenience wrapper around of_map_id() using "msi-map", "#msi-cells",
> + * and "msi-map-mask".
>   *
>   * Return: 0 on success or a standard error code on failure.
>   */
>  int of_map_msi_id(const struct device_node *np, u32 id,
>  		  const struct device_node *filter_np, struct of_phandle_args *arg)
>  {
> -	return of_map_id(np, id, "msi-map", "msi-map-mask", filter_np, arg);
> +	return of_map_id(np, id, "msi-map", "#msi-cells", "msi-map-mask", filter_np, arg);
>  }
>  EXPORT_SYMBOL_GPL(of_map_msi_id);
> diff --git a/include/linux/of.h b/include/linux/of.h
> index 8548cd9eb4f1..51ac8539f2c3 100644
> --- a/include/linux/of.h
> +++ b/include/linux/of.h
> @@ -462,7 +462,8 @@ const char *of_prop_next_string(const struct property *prop, const char *cur);
>  bool of_console_check(const struct device_node *dn, char *name, int index);
>  
>  int of_map_id(const struct device_node *np, u32 id,
> -	       const char *map_name, const char *map_mask_name,
> +	       const char *map_name, const char *cells_name,
> +	       const char *map_mask_name,
>  	       const struct device_node *filter_np, struct of_phandle_args *arg);
>  
>  int of_map_iommu_id(const struct device_node *np, u32 id,
> @@ -934,7 +935,8 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag
>  }
>  
>  static inline int of_map_id(const struct device_node *np, u32 id,
> -			     const char *map_name, const char *map_mask_name,
> +			     const char *map_name, const char *cells_name,
> +			     const char *map_mask_name,
>  			     const struct device_node *filter_np,
>  			     struct of_phandle_args *arg)
>  {
> 

Gentle ping.

Thanks,
Vijay

^ permalink raw reply

* Re: [PATCH v3 1/6] soc: mediatek: mtk-devapc: refine devapc interrupt handler
From: CK Hu (胡俊光) @ 2026-04-16  3:45 UTC (permalink / raw)
  To: robh@kernel.org, Xiaoshun Xu (徐晓顺),
	krzk+dt@kernel.org, conor+dt@kernel.org, matthias.bgg@gmail.com,
	AngeloGioacchino Del Regno
  Cc: linux-arm-kernel@lists.infradead.org,
	linux-mediatek@lists.infradead.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org,
	Sirius Wang (王皓昱),
	Project_Global_Chrome_Upstream_Group,
	Vince-WL Liu (劉文龍)
In-Reply-To: <20260416031231.2932493-2-xiaoshun.xu@mediatek.com>

On Thu, 2026-04-16 at 11:12 +0800, Xiaoshun Xu wrote:
> Because the violation IRQ uses a while loop, it might cause the
> system to remain in the interrupt handler indefinitely. We are
> currently optimizing this part of the process to handle only 20
> violations for debug violation issues, and then exit the loop
> 
> Signed-off-by: Xiaoshun Xu <xiaoshun.xu@mediatek.com>
> ---
>  drivers/soc/mediatek/mtk-devapc.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c
> index f54c966138b5..c9e1401315ad 100644
> --- a/drivers/soc/mediatek/mtk-devapc.c
> +++ b/drivers/soc/mediatek/mtk-devapc.c
> @@ -12,6 +12,7 @@
>  #include <linux/of_irq.h>
>  #include <linux/of_address.h>
>  
> +#define MAX_VIO_NUM 20
>  #define VIO_MOD_TO_REG_IND(m)	((m) / 32)
>  #define VIO_MOD_TO_REG_OFF(m)	((m) % 32)
>  
> @@ -188,13 +189,18 @@ static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
>   */
>  static irqreturn_t devapc_violation_irq(int irq_number, void *data)
>  {
> +	u32 vio_num = 0;
>  	struct mtk_devapc_context *ctx = data;
>  
> -	while (devapc_sync_vio_dbg(ctx))
> +	mask_module_irq(ctx, true);

mask irq is not related to this patch. This patch care about the infinite loop.
So separate mask irq part to an independent patch and describe why do this.

Regards,
CK

> +
> +	for (vio_num = 0; (vio_num < MAX_VIO_NUM) && (devapc_sync_vio_dbg(ctx)); ++vio_num)
>  		devapc_extract_vio_dbg(ctx);
>  
>  	clear_vio_status(ctx);
>  
> +	mask_module_irq(ctx, false);
> +
>  	return IRQ_HANDLED;
>  }
>  


^ permalink raw reply

* Re: [PATCH RFC 3/4] clk: qcom: tcsrcc-glymur: Migrate tcsr_pcie_N_clkref_en to clk_ref common helper
From: Qiang Yu @ 2026-04-16  3:56 UTC (permalink / raw)
  To: Konrad Dybcio, Wesley Cheng
  Cc: Bjorn Andersson, Taniya Das, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Konrad Dybcio,
	johan, linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <3d4a12f1-a9ba-4955-b018-f1c271aab766@oss.qualcomm.com>

++ Wesley Cheng

On Mon, Apr 13, 2026 at 01:18:16PM +0200, Konrad Dybcio wrote:
> On 4/13/26 9:06 AM, Qiang Yu wrote:
> > On Thu, Apr 09, 2026 at 08:19:41AM -0500, Bjorn Andersson wrote:
> >> On Wed, Apr 01, 2026 at 09:47:38PM -0700, Qiang Yu wrote:
> >>> On Wed, Apr 01, 2026 at 10:05:12PM +0530, Taniya Das wrote:
> >>>> On 4/1/2026 12:05 PM, Qiang Yu wrote:
> >>>>> diff --git a/drivers/clk/qcom/tcsrcc-glymur.c b/drivers/clk/qcom/tcsrcc-glymur.c
> >> [..]
> >>>>> +static const char * const tcsr_pcie_4_regulators[] = {
> >>>>> +	"vdda-refgen-0p9",
> >>>>> +	"vdda-refgen-1p2",
> >>>>> +	"vdda-qreftx1-0p9",
> >>>>> +	"vdda-qrefrpt0-0p9",
> >>>>> +	"vdda-qrefrpt1-0p9",
> >>>>> +	"vdda-qrefrpt2-0p9",
> >>>>> +	"vdda-qrefrx2-0p9",
> >>>>> +};
> >>>>> +
> >>>>
> >>>> TCSR clock refs are just not for PCIe alone, they would have supplies
> >>>> for all the ref clocks. These supplies can also be shared across other
> >>>> clock refs. I think it is not the correct way to handle the supplies, as
> >>>> TCSR does not have the complete supplies map.
> >>>>
> >>> We have complete supplies map. You can get it on ipcatlog. Here is example
> >>> for other instances eg USB and EDP:
> >>> - Glymur (eDP): CXO PAD -> TX0 -> RPT0 -> RX0 -> eDP
> >>> - Glymur (USB4_2): CXO PAD -> TX0 -> RPT0 -> RPT1 -> RX1 -> USB4_2
> >>> - Glymur (USB3): CXO PAD -> TX0 -> RPT3 -> RPT4 -> RX4 -> USB3_SS3
> >>>
> >>> I only add supplies for PCIe in this series because USB and EDP vote these
> >>> LDO in their PHY driver. They can remove them in PHY dts node and add same
> >>> regulator list here.
> >>>
> >>
> >> The regulators are reference counted. Can't we add the USB and eDP
> >> handling here as well now, and then after they are voted here we remove
> >> them from the PHY?
> >>
> > 
> > For USB, I’m not yet sure which tcsr_*_clkref_en each USB instance in the
> > QREF diagram is tied to. I need to confirm that mapping first, I'm
> > checking with Wesley Cheng.
> 
> I think on at least some platforms the reference clock for the primary
> USB controller is not sw-controllable (so we wouldn't get a handle to
> toggle the regulator this way).. please check that
> 
> Konrad

^ permalink raw reply

* Re: [PATCH] arm64: dts: qcom: kaanapali: Enable cpufreq cooling devices
From: Gaurav Kohli @ 2026-04-16  5:14 UTC (permalink / raw)
  To: Konrad Dybcio, dipa.mantre, Bjorn Andersson, Konrad Dybcio,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-msm, devicetree, linux-kernel
In-Reply-To: <020442d5-5697-476b-a96a-6e96ce054363@oss.qualcomm.com>



On 4/15/2026 4:31 PM, Konrad Dybcio wrote:
> On 4/15/26 12:57 PM, Dipa Mantre via B4 Relay wrote:
>> From: Dipa Mantre <dipa.mantre@oss.qualcomm.com>
>>
>> Add cooling-cells property to the CPU nodes to support cpufreq
>> cooling devices.
>>
>> Signed-off-by: Dipa Mantre <dipa.mantre@oss.qualcomm.com>
>> ---
> 
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> 
> Konrad
> 

thanks for this change:
Reviewed-by: Gaurav Kohli <gaurav.kohli@oss.qualcomm.com>

^ permalink raw reply

* RE: [PATCH v4 3/9] media: chips-media: wave6: Add Wave6 VPU interface
From: Nas Chung @ 2026-04-16  5:25 UTC (permalink / raw)
  To: Nicolas Dufresne, mchehab@kernel.org, hverkuil@xs4all.nl,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	shawnguo@kernel.org, s.hauer@pengutronix.de
  Cc: linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-imx@nxp.com,
	linux-arm-kernel@lists.infradead.org, jackson.lee, lafley.kim,
	marek.vasut@mailbox.org, Ming Qian
In-Reply-To: <7306c00b626f4030d92b908022b9a39669b07bb7.camel@ndufresne.ca>

Hi, Nicolas.

Sorry, I just realized that I never replied to your earlier email.

>-----Original Message-----
>From: Nicolas Dufresne <nicolas@ndufresne.ca>
>Sent: Thursday, December 11, 2025 4:54 AM
>To: Nas Chung <nas.chung@chipsnmedia.com>; mchehab@kernel.org;
>hverkuil@xs4all.nl; robh@kernel.org; krzk+dt@kernel.org;
>conor+dt@kernel.org; shawnguo@kernel.org; s.hauer@pengutronix.de
>Cc: linux-media@vger.kernel.org; devicetree@vger.kernel.org; linux-
>kernel@vger.kernel.org; linux-imx@nxp.com; linux-arm-
>kernel@lists.infradead.org; jackson.lee <jackson.lee@chipsnmedia.com>;
>lafley.kim <lafley.kim@chipsnmedia.com>; marek.vasut@mailbox.org; Ming Qian
><ming.qian@oss.nxp.com>
>Subject: Re: [PATCH v4 3/9] media: chips-media: wave6: Add Wave6 VPU
>interface
>
>Hi,
>
>Le mercredi 22 octobre 2025 à 16:47 +0900, Nas Chung a écrit :
>> Add an interface layer to manage hardware register configuration
>> and communication with the Chips&Media Wave6 video codec IP.
>>
>> The interface provides low-level helper functions used by the
>> Wave6 core driver to implement video encoding and decoding operations.
>> It handles command submission to the firmware via MMIO registers,
>> and waits for a response by polling the firmware busy flag.
>>
>> Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
>> Tested-by: Ming Qian <ming.qian@oss.nxp.com>
>> Tested-by: Marek Vasut <marek.vasut@mailbox.org>
>> ---

[...]

>
>[...]
>
>stopping there for now. I feel like we did a big mistake in wave5 by
>allowing a
>heavy abstraction, its a lot harder to fix and it served no purpose since
>you
>went for a fresh driver for wave6. I think its proper to ask for a slimmer
>interface.
>
>The V4L2 API is the front-end, and where all the validation should take
>place.
>The HW interface should simply manage the HW in a readable and non-
>redundant
>way. In V4L2, strides and buffer size are part of the try/s/g_fmt API, so
>these
>should not be duplicated here and they should clearly use the common code.

I agree that the HW interface should be slimmer and should not duplicate
validation handled in the V4L2 layer.

>
>I know its painful to ear, but you will be remove 50% of the code, which
>long
>term will be a massive win on maintenance.

I am reworking the series to address your earlier feedback as well, and I will
include that in the next patch version.

Thanks again for your feedback.

Thanks.
Nas.

>
>regards,
>Nicolas

^ permalink raw reply

* Re: [PATCH v8 08/10] ASoC: mediatek: mt8196: add platform driver
From: Cyril Chao (钞悦) @ 2026-04-16  5:53 UTC (permalink / raw)
  To: broonie@kernel.org
  Cc: linux-kernel@vger.kernel.org, linux-mediatek@lists.infradead.org,
	devicetree@vger.kernel.org, Darren Ye (叶飞),
	linux-sound@vger.kernel.org, conor+dt@kernel.org, tiwai@suse.com,
	robh@kernel.org, lgirdwood@gmail.com,
	linux-arm-kernel@lists.infradead.org,
	Project_Global_Chrome_Upstream_Group, matthias.bgg@gmail.com,
	krzk+dt@kernel.org, perex@perex.cz, AngeloGioacchino Del Regno
In-Reply-To: <892468cc-7eb4-411e-b91b-f14789d8da0c@sirena.org.uk>

Thank you for your assistance in reviewing. Could you please also
review the modifications in the diff? If everything is okay, I will
include them in v9 in the next update.


diff --git a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
index 3d3174cd8efb..ff7aa89e4779 100644
--- a/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
+++ b/sound/soc/mediatek/mt8196/mt8196-afe-pcm.c
@@ -90,9 +90,20 @@ static int mt8196_set_cm(struct mtk_base_afe *afe,
int id,
 	struct mt8196_afe_private *afe_priv = afe->platform_priv;
 	unsigned int rate = afe_priv->cm_rate[id];
 	unsigned int rate_val = mt8196_rate_transform(afe->dev, rate);
-	unsigned int update_val = update ? ((((26000000 / rate) - 10) /
(ch / 2)) - 1) : 0x64;
+	unsigned int ch_pair = ch / 2;
+	unsigned int update_val;
 	int reg = AFE_CM0_CON0 + 0x10 * id;
 
+	if (update) {
+		if (ch_pair == 0) {
+			dev_err(afe->dev, "CM%d: invalid channel count
%u\n", id, ch);
+			return -EINVAL;
+		}
+		update_val = (26000000 / rate - 10) / ch_pair - 1;
+	} else {
+		update_val = 0x64;
+	}
+
 	dev_dbg(afe->dev, "CM%d, rate %d, update %d, swap %d, ch %d\n",
 		id, rate, update, swap, ch);
 
@@ -471,6 +482,7 @@ static int ul_cm0_event(struct snd_soc_dapm_widget
*w,
 	struct mtk_base_afe *afe =
snd_soc_component_get_drvdata(cmpnt);
 	struct mt8196_afe_private *afe_priv = afe->platform_priv;
 	unsigned int channels = afe_priv->cm_channels;
+	int ret;
 
 	dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
 		event, w->name, channels);
@@ -478,7 +490,9 @@ static int ul_cm0_event(struct snd_soc_dapm_widget
*w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		mt8196_enable_cm_bypass(afe, CM0, false);
-		mt8196_set_cm(afe, CM0, true, false, channels);
+		ret = mt8196_set_cm(afe, CM0, true, false, channels);
+		if (ret)
+			return ret;
 		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 				   PDN_CM0_MASK_SFT, 0 << PDN_CM0_SFT);
 		break;
@@ -502,6 +516,7 @@ static int ul_cm1_event(struct snd_soc_dapm_widget
*w,
 	struct mtk_base_afe *afe =
snd_soc_component_get_drvdata(cmpnt);
 	struct mt8196_afe_private *afe_priv = afe->platform_priv;
 	unsigned int channels = afe_priv->cm_channels;
+	int ret;
 
 	dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
 		event, w->name, channels);
@@ -509,7 +524,9 @@ static int ul_cm1_event(struct snd_soc_dapm_widget
*w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		mt8196_enable_cm_bypass(afe, CM1, false);
-		mt8196_set_cm(afe, CM1, true, false, channels);
+		ret = mt8196_set_cm(afe, CM1, true, false, channels);
+		if (ret)
+			return ret;
 		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 				   PDN_CM1_MASK_SFT, 0 << PDN_CM1_SFT);
 		break;
@@ -533,6 +550,7 @@ static int ul_cm2_event(struct snd_soc_dapm_widget
*w,
 	struct mtk_base_afe *afe =
snd_soc_component_get_drvdata(cmpnt);
 	struct mt8196_afe_private *afe_priv = afe->platform_priv;
 	unsigned int channels = afe_priv->cm_channels;
+	int ret;
 
 	dev_dbg(afe->dev, "event 0x%x, name %s, channels %u\n",
 		event, w->name, channels);
@@ -540,7 +558,9 @@ static int ul_cm2_event(struct snd_soc_dapm_widget
*w,
 	switch (event) {
 	case SND_SOC_DAPM_PRE_PMU:
 		mt8196_enable_cm_bypass(afe, CM2, false);
-		mt8196_set_cm(afe, CM2, true, false, channels);
+		ret = mt8196_set_cm(afe, CM2, true, false, channels);
+		if (ret)
+			return ret;
 		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 				   PDN_CM2_MASK_SFT, 0 << PDN_CM2_SFT);
 		break;

Best Regards
Cyril Chao


On Fri, 2026-04-03 at 15:07 +0100, Mark Brown wrote:
> On Tue, Mar 24, 2026 at 09:56:49AM +0800, Cyril Chao wrote:
> 
> > +static int mt8196_set_cm(struct mtk_base_afe *afe, int id,
> > +			 bool update, bool swap, unsigned int ch)
> > +{
> > +	struct mt8196_afe_private *afe_priv = afe->platform_priv;
> > +	unsigned int rate = afe_priv->cm_rate[id];
> > +	unsigned int rate_val = mt8196_rate_transform(afe->dev, rate);
> > +	unsigned int update_val = update ? ((((26000000 / rate) - 10) /
> > (ch / 2)) - 1) : 0x64;
> > +	int reg = AFE_CM0_CON0 + 0x10 * id;
> 
> The driver looks like it supports mono so won't this trigger divide
> by
> zero?
> 
> Also please write normal conditional statements, it's much more
> leigible.

^ permalink raw reply related

* Re: [PATCH v2 2/3] dt-bindings: gpio: Add EIO GPIO compatible to gpio-zynq
From: Michal Simek @ 2026-04-16  5:58 UTC (permalink / raw)
  To: Conor Dooley, Shubhrajyoti Datta
  Cc: linux-kernel, git, shubhrajyoti.datta, Srinivas Neeli,
	Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-gpio, devicetree,
	linux-arm-kernel
In-Reply-To: <20260415-rectal-visible-a8ccb534a176@spud>



On 4/15/26 17:01, Conor Dooley wrote:
> On Wed, Apr 15, 2026 at 04:26:27PM +0530, Shubhrajyoti Datta wrote:
>> EIO (Extended IO) is a GPIO block found on xa2ve3288 silicon..
> 
> 
> Why does the compatible have a "1.0" when it is in silicon?

Sorry not following what the problem is. Yes this is hard block in silicon
and it is silicon v1.

> Why doesn't the compatible contain "xa2ve3288"?

This unit can be used on different silicons too.

> Why is this device not compatible with existing ones, since
> gpio-lines-names appears to be the sole difference?

There is no way how to detect gpio width.
Pretty much soc_device_match() to some extend could be use to detect which 
silicon it runs but on this particular one you have 3 gpio controllers described 
by this binding (pmc, versal and eio).

Thanks,
Michal


^ permalink raw reply

* Re: [PATCH v2 2/2] riscv: dts: spacemit: Add cpu scaling for K1 SoC
From: Shuwei Wu @ 2026-04-16  5:59 UTC (permalink / raw)
  To: Anand Moon
  Cc: Rafael J. Wysocki, Viresh Kumar, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Yixun Lan, linux-pm, linux-kernel, linux-riscv,
	spacemit, devicetree
In-Reply-To: <CANAwSgSNHO3MNewNzpYbhuj4K3NTdfzDC9KPoUHbFH97P4M_UQ@mail.gmail.com>

On Tue Apr 14, 2026 at 9:25 PM CST, Anand Moon wrote:
> Hi Shuwei,
>
> On Fri, 10 Apr 2026 at 13:30, Shuwei Wu <shuwei.wu@mailbox.org> wrote:
>>
>> Add Operating Performance Points (OPP) tables and CPU clock properties
>> for the two clusters in the SpacemiT K1 SoC.
>>
>> Also assign the CPU power supply (cpu-supply) for the Banana Pi BPI-F3
>> board to fully enable CPU DVFS.
>>
>> Signed-off-by: Shuwei Wu <shuwei.wu@mailbox.org>
>>
>> ---
>> Changes in v2:
>> - Add k1-opp.dtsi with OPP tables for both CPU clusters
>> - Assign CPU supplies and include OPP table for Banana Pi BPI-F3
>> ---
>>  arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts |  35 +++++++-
>>  arch/riscv/boot/dts/spacemit/k1-opp.dtsi        | 105 ++++++++++++++++++++++++
>>  arch/riscv/boot/dts/spacemit/k1.dtsi            |   8 ++
>>  3 files changed, 147 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
>> index 444c3b1e6f44..3780593f610d 100644
>> --- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
>> +++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
>> @@ -5,6 +5,7 @@
>>
>>  #include "k1.dtsi"
>>  #include "k1-pinctrl.dtsi"
>> +#include "k1-opp.dtsi"
>>
>>  / {
>>         model = "Banana Pi BPI-F3";
>> @@ -86,6 +87,38 @@ &combo_phy {
>>         status = "okay";
>>  };
>>
>> +&cpu_0 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_1 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_2 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_3 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_4 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_5 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_6 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>> +&cpu_7 {
>> +       cpu-supply = <&buck1_3v45>;
>> +};
>> +
>>  &emmc {
>>         bus-width = <8>;
>>         mmc-hs400-1_8v;
>> @@ -201,7 +234,7 @@ pmic@41 {
>>                 dldoin2-supply = <&buck5>;
>>
>>                 regulators {
>> -                       buck1 {
>> +                       buck1_3v45: buck1 {
>>                                 regulator-min-microvolt = <500000>;
>>                                 regulator-max-microvolt = <3450000>;
>>                                 regulator-ramp-delay = <5000>;
>> diff --git a/arch/riscv/boot/dts/spacemit/k1-opp.dtsi b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
>> new file mode 100644
>> index 000000000000..768ae390686d
>> --- /dev/null
>> +++ b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
>> @@ -0,0 +1,105 @@
>> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> +
>> +/ {
>> +       cluster0_opp_table: opp-table-cluster0 {
>> +               compatible = "operating-points-v2";
>> +               opp-shared;
>> +
>> +               opp-614400000 {
>> +                       opp-hz = /bits/ 64 <614400000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-819000000 {
>> +                       opp-hz = /bits/ 64 <819000000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1000000000 {
>> +                       opp-hz = /bits/ 64 <1000000000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1228800000 {
>> +                       opp-hz = /bits/ 64 <1228800000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1600000000 {
>> +                       opp-hz = /bits/ 64 <1600000000>;
>> +                       opp-microvolt = <1050000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +       };
>> +
>> +       cluster1_opp_table: opp-table-cluster1 {
>> +               compatible = "operating-points-v2";
>> +               opp-shared;
>> +
>> +               opp-614400000 {
>> +                       opp-hz = /bits/ 64 <614400000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-819000000 {
>> +                       opp-hz = /bits/ 64 <819000000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1000000000 {
>> +                       opp-hz = /bits/ 64 <1000000000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1228800000 {
>> +                       opp-hz = /bits/ 64 <1228800000>;
>> +                       opp-microvolt = <950000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +
>> +               opp-1600000000 {
>> +                       opp-hz = /bits/ 64 <1600000000>;
>> +                       opp-microvolt = <1050000>;
>> +                       clock-latency-ns = <200000>;
>> +               };
>> +       };
>> +};
>> +
>> +&cpu_0 {
>> +       operating-points-v2 = <&cluster0_opp_table>;
>> +};
>> +
>> +&cpu_1 {
>> +       operating-points-v2 = <&cluster0_opp_table>;
>> +};
>> +
>> +&cpu_2 {
>> +       operating-points-v2 = <&cluster0_opp_table>;
>> +};
>> +
>> +&cpu_3 {
>> +       operating-points-v2 = <&cluster0_opp_table>;
>> +};
>> +
>> +&cpu_4 {
>> +       operating-points-v2 = <&cluster1_opp_table>;
>> +};
>> +
>> +&cpu_5 {
>> +       operating-points-v2 = <&cluster1_opp_table>;
>> +};
>> +
>> +&cpu_6 {
>> +       operating-points-v2 = <&cluster1_opp_table>;
>> +};
>> +
>> +&cpu_7 {
>> +       operating-points-v2 = <&cluster1_opp_table>;
>> +};
>> diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
>> index 529ec68e9c23..bdd109b81730 100644
>> --- a/arch/riscv/boot/dts/spacemit/k1.dtsi
>> +++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
>> @@ -54,6 +54,7 @@ cpu_0: cpu@0 {
>>                         compatible = "spacemit,x60", "riscv";
>>                         device_type = "cpu";
>>                         reg = <0>;
>> +                       clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
>>                         riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
>>                         riscv,isa-base = "rv64i";
>>                         riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
>> @@ -84,6 +85,7 @@ cpu_1: cpu@1 {
>>                         compatible = "spacemit,x60", "riscv";
>>                         device_type = "cpu";
>>                         reg = <1>;
>> +                       clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
>
> Based on the Spacemit kernel source, the k1-x_opp_table.dtsi file
> defines several additional clocks for the Operating Performance Points
> (OPP) table:
>
>  clocks = <&ccu CLK_CPU_C0_ACE>, <&ccu CLK_CPU_C1_ACE>, <&ccu CLK_CPU_C0_TCM>,
>                         <&ccu CLK_CCI550>, <&ccu CLK_PLL3>, <&ccu
> CLK_CPU_C0_HI>, <&ccu CLK_CPU_C1_HI>;
>                 clock-names = "ace0","ace1","tcm","cci","pll3", "c0hi", "c1hi";
>
> These hardware clocks are also explicitly registered in the APMU clock driver
> via the k1_ccu_apmu_hws array, confirming their availability for frequency
> and voltage scaling on the K1-X SoC.
>
> static struct clk_hw *k1_ccu_apmu_hws[] = {
>         [CLK_CCI550]            = &cci550_clk.common.hw,
>         [CLK_CPU_C0_HI]         = &cpu_c0_hi_clk.common.hw,
>         [CLK_CPU_C0_CORE]       = &cpu_c0_core_clk.common.hw,
>         [CLK_CPU_C0_ACE]        = &cpu_c0_ace_clk.common.hw,
>         [CLK_CPU_C0_TCM]        = &cpu_c0_tcm_clk.common.hw,
>         [CLK_CPU_C1_HI]         = &cpu_c1_hi_clk.common.hw,
>         [CLK_CPU_C1_CORE]       = &cpu_c1_core_clk.common.hw,
>         [CLK_CPU_C1_ACE]        = &cpu_c1_ace_clk.common.hw,
>
> Yes, it is possible to add these clocks for DVFS to work correctly,
> provided they are managed by the appropriate driver and declared in
> the Device Tree (DT).
>
> Thanks
> -Anand

Thanks for your review and for pointing this out.

Regarding the clocks you mentioned, I'd like to clarify their roles based on
the K1 datasheet. Taking Cluster 0 as an example, c0_core_clk is the primary
clock for the cluster. c0_ace_clk and c0_tcm_clk are children derived from it,
defaulting to half the frequency of their parent core clock, while c0_hi_clk
represents the high-speed path selection.
Cluster 1 follows the same structure.

Based on the official SpacemiT Bianbu OS source, the spacemit-cpufreq.c driver
mainly performs the following tasks:
1. Sets the CCI550 clock frequency to 614MHz.
2. Sets the clock frequencies of c0_ace_clk, c1_ace1_clk, and c0_tcm_clk to half
the frequency of their parent clock.
3. For the 1.6GHz OPP, it sets the PLL3 frequency to 3.2GHz and the
c0_hi_clk/c1_hi_clk frequencies to 1.6GHz.

I booted with the manufacturer's OpenWRT image and used debugfs to confirm that
the clock states are exactly as described above.

At 1.6GHz:
Clock Source & Tree           Rate (Hz)      HW Enable  Consumer
---------------------------------------------------------------------------
pll3                          3,200,000,000      Y      deviceless
 └─ pll3_d2                   1,600,000,000      Y      deviceless
     ├─ cpu_c1_hi_clk         1,600,000,000      Y      deviceless
     │   └─ cpu_c1_pclk       1,600,000,000      Y      cpu0
     │       └─ cpu_c1_ace_clk  800,000,000      Y      deviceless
     └─ cpu_c0_hi_clk         1,600,000,000      Y      deviceless
         └─ cpu_c0_core_clk   1,600,000,000      Y      cpu0
             ├─ cpu_c0_tcm_clk  800,000,000      Y      deviceless
             └─ cpu_c0_ace_clk  800,000,000      Y      deviceless

pll1_2457p6_vco               2,457,600,000      Y      deviceless
 └─ pll1_d4                     614,400,000      Y      deviceless
     └─ pll1_d4_614p4           614,400,000      Y      deviceless
         └─ cci550_clk          614,400,000      Y      deviceless

At 1.228GHz:
Clock Source & Tree           Rate (Hz)      HW Enable  Consumer
---------------------------------------------------------------------------
pll1_2457p6_vco               2,457,600,000      Y      deviceless
 └─ pll1_d2                   1,228,800,000      Y      deviceless
     └─ pll1_d2_1228p8        1,228,800,000      Y      deviceless
         ├─ cpu_c0_core_clk   1,228,800,000      Y      cpu0
         │   ├─ cpu_c0_tcm_clk  614,400,000      Y      deviceless
         │   └─ cpu_c0_ace_clk  614,400,000      Y      deviceless
         └─ cpu_c1_pclk       1,228,800,000      Y      cpu0
             └─ cpu_c1_ace_clk  614,400,000      Y      deviceless
  └─ pll1_d4                     614,400,000      Y      deviceless
     └─ pll1_d4_614p4           614,400,000      Y      deviceless
         └─ cci550_clk          614,400,000      Y      deviceless

pll3                          3,200,000,000      Y      deviceless
 └─ pll3_d2                   1,600,000,000      Y      deviceless
     ├─ cpu_c1_hi_clk         1,600,000,000      Y      deviceless
     └─ cpu_c0_hi_clk         1,600,000,000      Y      deviceless
 └─ pll3_d3                   1,066,666,666      Y      deviceless

Regarding the necessity of listing these clocks in the DT, my analysis is as follows:
1. For CCI550, I did not find a clear definition of this clock's specific role
in the SoC datasheet. Although the vendor kernel increases its frequency,
my benchmarks show that maintaining the mainline default (245.76MHz) has a
negligible impact on CPU performance.
2. For ACE and TCM clocks, they function as synchronous children of the core
clock with a default divide-by-2 ratio. Since they scale automatically relative
to c0_core_clk/c1_core_clk and no other peripherals depend on them, they do not
require manual management in the OPP table.
3. For the high-speed path, the underlying clock controller logic already handles
the parent MUX switching and PLL3 scaling automatically when clk_set_rate()
is called on the core clock.

I have verified this by checking the hardware state in the mainline kernel.
The clock tree matches the vendor kernel's configuration:

At 1.6GHz:
Clock Source & Tree           Rate (Hz)      HW Enable  Consumer
---------------------------------------------------------------------------
pll3                          3,200,000,000      Y      deviceless
 └─ pll3_d2                   1,600,000,000      Y      deviceless
     ├─ cpu_c1_hi_clk         1,600,000,000      Y      deviceless
     │   └─ cpu_c1_core_clk   1,600,000,000      Y      cpu4
     │       └─ cpu_c1_ace_clk  800,000,000      Y      deviceless
     └─ cpu_c0_hi_clk         1,600,000,000      Y      deviceless
         └─ cpu_c0_core_clk   1,600,000,000      Y      cpu0
             ├─ cpu_c0_tcm_clk  800,000,000      Y      deviceless
             └─ cpu_c0_ace_clk  800,000,000      Y      deviceless

pll1                          2,457,600,000      Y      deviceless
 └─ pll1_d5                     491,520,000      Y      deviceless
     └─ pll1_d5_491p52          491,520,000      Y      deviceless
         └─ cci550_clk          245,760,000      Y      deviceless

At 1.228GHz:
Clock Source & Tree           Rate (Hz)      HW Enable  Consumer
---------------------------------------------------------------------------
pll1                          2,457,600,000      Y      deviceless
 ├─ pll1_d5                     491,520,000      Y      deviceless
 │   └─ pll1_d5_491p52          491,520,000      Y      deviceless
 │       └─ cci550_clk          245,760,000      Y      deviceless
 └─ pll1_d2                   1,228,800,000      Y      deviceless
     └─ pll1_d2_1228p8        1,228,800,000      Y      deviceless
         └─ cpu_c0_core_clk   1,228,800,000      Y      cpu0
             ├─ cpu_c0_tcm_clk  614,400,000      Y      deviceless
             └─ cpu_c0_ace_clk  614,400,000      Y      deviceless

pll3                          3,200,000,000      Y      deviceless
 └─ pll3_d2                   1,600,000,000      Y      deviceless
     └─ cpu_c1_hi_clk         1,600,000,000      Y      deviceless
         └─ cpu_c1_core_clk   1,600,000,000      Y      cpu4
             └─ cpu_c1_ace_clk  800,000,000      Y      deviceless

Performance benchmarks also confirm that the current configuration is sufficient:
Benchmark (AWK computation): time awk 'BEGIN{for(i=0;i<10000000;i++) sum+=i}'
----------------------------------------------------------------------------
Frequency    |      Mainline Linux (s)       |        OpenWrt (s)          
(kHz)        |  Real (Total) |  User (CPU)   |  Real (Total) |  User (CPU) )
-------------+---------------+---------------+---------------+--------------
1,600,000    |     1.82s     |     1.81s     |     1.73s     |    1.73s    
1,228,800    |     2.34s     |     2.33s     |     2.26s     |    2.26s    
1,000,000    |     2.94s     |     2.86s     |     2.78s     |    2.78s    
  819,000    |     3.54s     |     3.53s     |     3.39s     |    3.39s    
  614,400    |     4.73s     |     4.71s     |     4.51s     |    4.51s    
----------------------------------------------------------------------------

In summary, because the clock controller correctly handles the internal dividers
and parent switching, declaring only the primary core clock for each CPU node is
sufficient for functional DVFS.

-- 
Best regards,
Shuwei Wu

^ permalink raw reply

* Re: [PATCH v3 5/5] arch: arm64: dts: qcom: Add support for PCIe3a
From: Krzysztof Kozlowski @ 2026-04-16  6:19 UTC (permalink / raw)
  To: Qiang Yu
  Cc: Vinod Koul, Neil Armstrong, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Philipp Zabel, Bjorn Andersson, Konrad Dybcio,
	linux-arm-msm, linux-phy, devicetree, linux-kernel
In-Reply-To: <aeBWfv1oXnSQC454@hu-qianyu-lv.qualcomm.com>

On 16/04/2026 05:24, Qiang Yu wrote:
> On Wed, Apr 15, 2026 at 09:44:15AM +0200, Krzysztof Kozlowski wrote:
>> On Sun, Apr 12, 2026 at 11:26:00PM -0700, Qiang Yu wrote:
>>> Describe PCIe3a controller and PHY. Also add required system resources
>>> like regulators, clocks, interrupts and registers configuration for PCIe3a.
>>>
>>> Signed-off-by: Qiang Yu <qiang.yu@oss.qualcomm.com>
>>
>> subject: drop arch.
>>
>> Please use subject prefixes matching the subsystem. You can get them for
>> example with 'git log --oneline -- DIRECTORY_OR_FILE' on the directory
>> your patch is touching. For bindings, the preferred subjects are
>> explained here:
>> https://www.kernel.org/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters
>>
> 
> Thanks for pointing me the link. I’ll drop arch: in next version.
> 
>>> ---
>>>  arch/arm64/boot/dts/qcom/glymur.dtsi | 316 ++++++++++++++++++++++++++++++++++-
>>>  1 file changed, 315 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm64/boot/dts/qcom/glymur.dtsi b/arch/arm64/boot/dts/qcom/glymur.dtsi
>>> index f23cf81ddb77a4138deeb4e00dd8b316930a2feb..c15f87c37ecbad72076a6c731f4959a1a8bd8425 100644
>>> --- a/arch/arm64/boot/dts/qcom/glymur.dtsi
>>> +++ b/arch/arm64/boot/dts/qcom/glymur.dtsi
>>> @@ -736,7 +736,7 @@ gcc: clock-controller@100000 {
>>>  				 <0>,				/* USB 2 Phy PCIE PIPEGMUX */
>>>  				 <0>,				/* USB 2 Phy PIPEGMUX */
>>>  				 <0>,				/* USB 2 Phy SYS PCIE PIPEGMUX */
>>> -				 <0>,				/* PCIe 3a */
>>> +				 <&pcie3a_phy>,			/* PCIe 3a */
>>>  				 <&pcie3b_phy>,			/* PCIe 3b */
>>>  				 <&pcie4_phy>,			/* PCIe 4 */
>>>  				 <&pcie5_phy>,			/* PCIe 5 */
>>> @@ -3640,6 +3640,320 @@ pcie3b_port0: pcie@0 {
>>>  			};
>>
>> ...
>>
>>>> +		pcie3a_phy: phy@f00000 {
>>
>> Same comment as before.
>>
> 
> The existing PCIe/PHY nodes are not strictly ordered by address. Current
> order is:

Obviously we cannot even keep order of nodes when creating a new DTSI
file from scratch.

But adding @f00000 after @1c10000 makes even less sense, regardless how
bad existing code is. Don't make it worse!

This goes before phy@fa0000

> 
> - pcie4: pci@1bf0000
> - pcie4_phy: phy@1bf6000
> - pcie5: pci@1b40000
> - pcie5_phy: phy@1b50000
> - pcie6: pci@1c00000
> - pcie6_phy: phy@1c06000
> - pcie3b: pci@1b80000
> - pcie3a: pci@1c10000 (added in this patch)
> - pcie3a_phy: phy@f00000 (added in this patch)
> - pcie3b_phy: phy@f10000
> 
> Do you want me to reorder these nodes to follow strict address order?

No, but don't add nodes randomly or following the previous broken order.

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH v3 3/3] dt-bindings: i3c: Add AST2600 I3C global registers
From: Krzysztof Kozlowski @ 2026-04-16  6:21 UTC (permalink / raw)
  To: Dawid Glazik
  Cc: Alexandre Belloni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Joel Stanley, Andrew Jeffery, linux-aspeed, linux-i3c, devicetree,
	linux-arm-kernel, Frank Li, Maciej Lawniczak
In-Reply-To: <cb0d16bf-988d-403e-8a8e-c85bf2a208d0@linux.intel.com>

On 15/04/2026 20:21, Dawid Glazik wrote:
> On 4/9/2026 9:30 AM, Krzysztof Kozlowski wrote:
>> On 09/04/2026 09:28, Krzysztof Kozlowski wrote:
>>> On Wed, Apr 08, 2026 at 10:34:35PM +0200, Dawid Glazik wrote:
>>>> Introduce the device-tree bindings for I3C global registers found on
>>>> AST2600 SoCs.
>>>>
>>>> Signed-off-by: Dawid Glazik <dawid.glazik@linux.intel.com>
>>>> ---
>>>> I wasn't sure if I should add newline at the end of the
>>>> file or not so I took
>>>> https://github.com/torvalds/linux/tree/master/Documentation/devicetree/bindings/i3c
>>>> as an example.
>>>
>>> Answer is: you cannot have patch warnings.
>>>
>>> Documentation/devicetree/bindings/i3c does not have patch warning, does
>>> it?
>>
>> And if you tested this code with standard tools, you would see that...
>>
>> Best regards,
>> Krzysztof
> 
> Thank you for the review and feedback. This is my first contribution to 
> Linux kernel so I'm still learning the process and toolchain. I 
> apologize for the rookie mistakes. I will address all the issues you've 
> pointed out and resubmit the series.


So get the patch reviewed by Intel colleagues which would tell you what
tools you must run and what warnings are accepted or not (and patch
warning is never accepted).

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 2/5] clk: qcom: add Global Clock controller (GCC) driver for IPQ9650 SoC
From: Krzysztof Kozlowski @ 2026-04-16  6:34 UTC (permalink / raw)
  To: Kathiravan Thirumoorthy, Bjorn Andersson, Michael Turquette,
	Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Philipp Zabel, Konrad Dybcio
  Cc: linux-arm-msm, linux-clk, devicetree, linux-kernel
In-Reply-To: <20260415-ipq9650_boot_to_shell-v1-2-b37eb4c3a1d1@oss.qualcomm.com>

On 15/04/2026 15:33, Kathiravan Thirumoorthy wrote:
> Add support for the global clock controller found on IPQ9650 SoC.
> 
> Signed-off-by: Kathiravan Thirumoorthy <kathiravan.thirumoorthy@oss.qualcomm.com>
> ---
>  drivers/clk/qcom/Kconfig       |    8 +
>  drivers/clk/qcom/Makefile      |    1 +
>  drivers/clk/qcom/gcc-ipq9650.c | 3794 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 3803 insertions(+)
> 
> diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
> index df21ef5ffd68..ed4c5765557b 100644
> --- a/drivers/clk/qcom/Kconfig
> +++ b/drivers/clk/qcom/Kconfig
> @@ -434,6 +434,14 @@ config IPQ_GCC_9574
>  	  i2c, USB, SD/eMMC, etc. Select this for the root clock
>  	  of ipq9574.
>  
> +config IPQ_GCC_9650
> +	tristate "IPQ9650 Global Clock Controller"

And the soc is for ARM64? Add proper dependency.

> +	help
> +	  Support for global clock controller on ipq9650 devices.
> +	  Say Y if you want to use peripheral devices such as UART, SPI,
> +	  i2c, USB, SD/eMMC, etc. Select this for the root clock
> +	  of ipq9650.
> +
Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH 0/7] TQMLX2160A-MBLS2160A DT fixes/updates
From: Alexander Stein @ 2026-04-16  6:39 UTC (permalink / raw)
  To: Frank Li, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Shawn Guo
  Cc: linux-arm-kernel, linux, devicetree, linux-kernel, Nora Schiffer
In-Reply-To: <20260331141915.2918927-1-alexander.stein@ew.tq-group.com>

Hi Frank,

Am Dienstag, 31. März 2026, 16:19:01 CEST schrieb Alexander Stein:
> Hi,
> 
> this series adds small fixes and improvements for TQMLX2160A DTs.
> The DT overlays address specific hardware behaviour when serdes is configured
> differently.

Any feedback here?

Thanks and best regards
Alexander

> 
> Best regards,
> Alexander
> 
> Alexander Stein (1):
>   arm64: dts: fsl-lx2160a-tqmlx2160a: Remove deprecated properties
> 
> Nora Schiffer (6):
>   arm64: dts: fsl-lx2160a-tqmlx2160a: fix LED polarity
>   arm64: dts: fsl-lx2160a-tqmlx2160a-mblx2160a: use DPMAC 17 and 18 for
>     SGMII in SERDES2 configs 7 and 11
>   arm64: dts: fsl-lx2160a-tqmlx2160a: add aliases for all 18 DPMAC
>     instances
>   arm64: dts: fsl-lx2160a-tqmlx2160a-mbls2160a: add various GPIO hogs
>   arm64: dts: fsl-lx2160a-tqmlx2160a-mbls2160a: enable pcs_mdio17 and
>     pcs_mdio18 in appropriate overlays
>   arm64: dts: fsl-lx2160a-tqmlx2160a-mbls2160a: specify Ethernet PHY
>     reset GPIOs
> 
>  .../fsl-lx2160a-tqmlx2160a-mblx2160a.dts      | 306 +++++++++++++++++-
>  ...l-lx2160a-tqmlx2160a-mblx2160a_x_11_x.dtso |  20 ++
>  ...sl-lx2160a-tqmlx2160a-mblx2160a_x_7_x.dtso |  20 ++
>  .../dts/freescale/fsl-lx2160a-tqmlx2160a.dtsi |  23 +-
>  4 files changed, 357 insertions(+), 12 deletions(-)
> 
> 


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



^ permalink raw reply


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