Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v11 2/6] pinctrl: s32cc: remove inline specifiers
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
	Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
	Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
	Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
  Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
	Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
	NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>

Remove unnecessary inline specifiers from static functions.

Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
 drivers/pinctrl/nxp/pinctrl-s32cc.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 4f88c24e62a2..2645a92df0ba 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -131,13 +131,13 @@ s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin)
 	return NULL;
 }
 
-static inline int s32_check_pin(struct pinctrl_dev *pctldev,
-				unsigned int pin)
+static int s32_check_pin(struct pinctrl_dev *pctldev,
+			 unsigned int pin)
 {
 	return s32_get_region(pctldev, pin) ? 0 : -EINVAL;
 }
 
-static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
+static int s32_regmap_read(struct pinctrl_dev *pctldev,
 			   unsigned int pin, unsigned int *val)
 {
 	struct s32_pinctrl_mem_region *region;
@@ -153,7 +153,7 @@ static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
 	return regmap_read(region->map, offset, val);
 }
 
-static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
+static int s32_regmap_write(struct pinctrl_dev *pctldev,
 			    unsigned int pin,
 			    unsigned int val)
 {
@@ -171,7 +171,7 @@ static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
 
 }
 
-static inline int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
+static int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
 			     unsigned int mask, unsigned int val)
 {
 	struct s32_pinctrl_mem_region *region;
@@ -484,8 +484,8 @@ static int s32_get_slew_regval(int arg)
 	return -EINVAL;
 }
 
-static inline void s32_pin_set_pull(enum pin_config_param param,
-				   unsigned int *mask, unsigned int *config)
+static void s32_pin_set_pull(enum pin_config_param param,
+			     unsigned int *mask, unsigned int *config)
 {
 	switch (param) {
 	case PIN_CONFIG_BIAS_DISABLE:
-- 
2.34.1



^ permalink raw reply related

* [PATCH v11 3/6] pinctrl: s32cc: change to "devm_pinctrl_register_and_init"
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
	Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
	Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
	Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
  Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
	Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
	NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>

From: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>

Switch from "devm_pinctrl_register" to "devm_pinctrl_register_and_init"
and "pinctrl_enable" since this is the recommended way.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
 drivers/pinctrl/nxp/pinctrl-s32cc.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 2645a92df0ba..89a4eb2000ee 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -978,10 +978,10 @@ int s32_pinctrl_probe(struct platform_device *pdev,
 		return ret;
 	}
 
-	ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc,
-					    ipctl);
-	if (IS_ERR(ipctl->pctl))
-		return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl),
+	ret = devm_pinctrl_register_and_init(&pdev->dev, s32_pinctrl_desc,
+					     ipctl, &ipctl->pctl);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
 				     "Could not register s32 pinctrl driver\n");
 
 #ifdef CONFIG_PM_SLEEP
@@ -994,7 +994,12 @@ int s32_pinctrl_probe(struct platform_device *pdev,
 		return -ENOMEM;
 #endif
 
-	dev_info(&pdev->dev, "initialized s32 pinctrl driver\n");
+	ret = pinctrl_enable(ipctl->pctl);
+	if (ret)
+		return dev_err_probe(&pdev->dev, ret,
+				     "Failed to enable pinctrl\n");
+
+	dev_info(&pdev->dev, "Initialized S32 pinctrl driver\n");
 
 	return 0;
 }
-- 
2.34.1



^ permalink raw reply related

* [PATCH v11 0/6] gpio: siul2-s32g2: add initial GPIO driver
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
  To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
	Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
	Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
	Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
  Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
	Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
	NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot

This patch series adds support for basic GPIO
operations using gpio-regmap.

There are two SIUL2 hardware modules: SIUL2_0 and SIUL2_1.
However, this driver exports both as a single GPIO driver.
This is because the interrupt registers are located only
in SIUL2_1, even for GPIOs that are part of SIUL2_0.

There are two gaps in the GPIO ranges:
- 102-111(inclusive) are invalid
- 123-143(inclusive) are invalid

Writing and reading GPIO values is done via the PGPDO/PGPDI
registers(Parallel GPIO Pad Data Output/Input) which are
16 bit registers, each bit corresponding to a GPIO.

Note that the PGPDO order is similar to a big-endian grouping
of two registers:
PGPDO1, PGPDO0, PGPDO3, PGPDO2, PGPDO5, PGPDO4, gap, PGPDO6.

v11 -> v10:
- add GPIOLIB as explicit Kconfig dependency
- mark regmap config as fast_io to avoid mutex overhead
- propagate regmap errors in debug show callback and
  suspend/resume paths instead of silently discarding them
- introduce a per-range sparse flag to handle SIUL2 instances
  with a non-linear PGPD layout
- dt-bindings: drop redundant minItems from legacy oneOf branch,
  add gpio-controller: false and related properties to prevent
  GPIO/IRQ properties without the required reg entries and
  drop maxItems from the GPIO+IRQ branch

v10 -> v9:
- implement GPIO via gpio-regmap backed by a regmap for
PGPDO/PGPDI register translation
- remove the successful probe message from the driver
- switch back to a single compatible string for both the
legacy and extended binding layout
- update binding: GPIO/IRQ properties required only
when extended reg layout is used
- remove unnecessary return value checks for MMIO
regmap operations
- replace kernel-doc style comments with regular comments
- solve relevant sashiko.dev findings
- rework GPIO request handling to preserve pinctrl ownership
- use __free(kfree) and no_free_ptr() in GPIO request path cleanup

v9 -> v8
- remove the SIUL2 syscon child nodes from the
device tree and DT bindings
- remove syscon child handling from the MFD
and pinctrl drivers
- remove the MFD driver and use a single monolithic
pinctrl/gpio/irqchip driver
- add a new compatible for the pinctrl+gpio binding
while keeping the previous compatible for the legacy
pinctrl-only binding
- update bindings to include the PGPDO/PGPDI and
IRQ register regions in the DT node for the
pinctrl/gpio/irq binding
- add IRQ-related entries in the bindings to
document the intended hierarchy; IRQ support
itself will be added in a future patch series
- update DT nodes to match the new hierarchy and
compatible scheme
- fix dtb warnings
- reorder commits: bug fixes, API changes, DT bindings,
driver implementation, DTS changes
- split commits further to separate minor
style-only adjustments

v8 -> v7
- remove all ': true' lines from properties in dt bindings
- remove NVMEM MFD cell from SIUL2 in dtsi
- remove NVMEM driver and configs
- expose SoC information via syscon cells SIUL2_0
and SIUL2_1 in MFD driver
- add SIUL2_0 and SIUL2_1 syscon nodes in dtsi
- add patternProperties for "^siul2_[0-1]$" for syscon nodes
- update example to include syscon cells with proper format
- remove `reg` property from pinctrl node in dt binding
- update Kconfig help text to reflect new syscon structure
instead of NVMEM for SoC information
- squash deprecated SIUL2 pinctrl binding with new MFD binding
- dropped "nxp,s32g3-siul2" from MFD driver match table
- fixed commit messages
- fixed dtb warnings

v7 -> v6
- fixed MAINTAINERS wrong file path
- add unevaluatedProperties, change siul2 node name, remove
  jtag_pins label in the device tree schema
- change compatible definition in schema
- change node name in dtsi
- mentioned binding deprecation in commit messages
- split mfd cell conversion commit in two: one for the
  previous refactoring, one for the mfd cell conversion
- removed Acked-by: Linus Walleij from commit:
  "pinctrl: s32: convert the driver into an mfd cell"
  because of changes to that commit
- deprecate the nxp,s32g2-siul2-pinctrl binding
- add NVMEM MFD cell for SIUL2
- made the GPIO driver not export invalid pins
  (there are some gaps 102-111, 123-143)
- removed the need for gpio-reserved-ranges
- force initialized pinctrl_desc->num_custom_params to 0

v6 -> v5
- removed description for reg in the dt-bindings and added
  maxItems
- dropped label for example in the dt-bindings
- simplified the example in the dt-bindings
- changed dt-bindings filename to nxp,s32g2-siul2.yaml
- changed title in the dt-bindings
- dropped minItmes from gpio-ranges/gpio-reserved-ranges
  and added maxItems to gpio-reserved-ranges
- added required block for -grp[0-9]$ nodes
- switch to using "" as quotes
- kernel test robot: fixed frame sizes, added description
  for reg_name, fixed typo in gpio_configs_lock, removed
  uninitialized ret variable usage
- ordered includes in nxp-siul2.c, switched to dev-err-probe
  added a mention that other commits will add nvmem functionality
  to the mfd driver
- switched spin_lock_irqsave to scoped_guard statement
- switched dev_err to dev_err_probe in pinctrl-s32cc in places
  reached during the probing part

v5 -> v4
- fixed di_div error
- fixed dt-bindings error
- added Co-developed-by tags
- added new MFD driver nxp-siul2.c
- made the old pinctrl driver an MFD cell
- added the GPIO driver in the existing SIUL2 pinctrl one
- Switch from "devm_pinctrl_register" to
  "devm_pinctrl_register_and_init"

v4 -> v3
- removed useless parentheses
- added S32G3 fallback compatible
- fixed comment alignment
- fixed dt-bindings license
- fixed modpost: "__udivdi3"
- moved MAINTAINERS entry to have the new GPIO driver
  together with other files related to S32G

v3 -> v2
- fix dt-bindings schema id
- add maxItems to gpio-ranges
- removed gpio label from dt-bindings example
- added changelog for the MAINTAINERS commit and
  added separate entry for the SIUL2 GPIO driver
- added guard(raw_spinlock_irqsave) in
  'siul2_gpio_set_direction'
- updated the description for
  'devm_platform_get_and_ioremap_resource_byname'

v2 -> v1
dt-bindings:
- changed filename to match compatible
- fixed commit messages
- removed dt-bindings unnecessary properties descriptions
- added minItems for the interrupts property
driver:
- added depends on ARCH_S32 || COMPILE_TEST to Kconfig
- added select REGMAP_MMIO to Kconfig
- remove unnecessary include
- add of_node_put after `siul2_get_gpio_pinspec`
- removed inline from function definitions
- removed match data and moved the previous platdata
  definition to the top of the file to be visible
- replace bitmap_set/clear with __clear_bit/set_bit
  and devm_bitmap_zalloc with devm_kzalloc
- switched to gpiochip_generic_request/free/config
- fixed dev_err format for size_t reported by
  kernel test robot
- add platform_get_and_ioremap_resource_byname wrapper

Andrei Stefanescu (2):
  pinctrl: s32cc: change to "devm_pinctrl_register_and_init"
  pinctrl: s32cc: implement GPIO functionality

Khristine Andreea Barbulescu (4):
  pinctrl: s32cc: add/fix some comments
  pinctrl: s32cc: remove inline specifiers
  dt-bindings: pinctrl: s32g2-siul2: describe GPIO and EIRQ resources
  arm64: dts: s32g: describe GPIO and EIRQ resources in SIUL2 pinctrl
    node

 .../pinctrl/nxp,s32g2-siul2-pinctrl.yaml      |  90 ++-
 arch/arm64/boot/dts/freescale/s32g2.dtsi      |  23 +-
 arch/arm64/boot/dts/freescale/s32g3.dtsi      |  23 +-
 drivers/pinctrl/nxp/Kconfig                   |   3 +-
 drivers/pinctrl/nxp/pinctrl-s32.h             |  35 +-
 drivers/pinctrl/nxp/pinctrl-s32cc.c           | 756 ++++++++++++++++--
 drivers/pinctrl/nxp/pinctrl-s32g2.c           |  47 +-
 7 files changed, 877 insertions(+), 100 deletions(-)

-- 
2.34.1



^ permalink raw reply

* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 13:20 UTC (permalink / raw)
  To: Will Deacon
  Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
	linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>

Hi Will,

On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>>    - A PE executes a Device-nGnR* store followed by a younger
>>      Device-nGnR* load.
>>    - The store is not a store-release.
>>    - The accesses target the same peripheral and do not overlap in bytes.
>>    - There is at most one intervening Device-nGnR* store in program
>>      order, and there are no intervening Device-nGnR* loads.
>>    - There is no DSB, and no DMB that orders loads, between the store and
>>      the load.
>>    - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.
>
>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.

Based on the existing code comments and after reviewing this path again,
__const_memcpy_toio_aligned32() and __const_memcpy_toio_aligned64()
appear to be intended for WC regions. Since the erratum is scoped to
Device-nGnR* accesses, and WC mappings are Normal-NC on arm64, I don’t
think the STLR workaround should apply to these helpers by default.

Applying it there would also break the contiguous STR grouping that
this path relies on for write combining.

-Shanker




^ permalink raw reply

* Re: [PATCH v3 0/9] ARM: dts: aspeed: anacapa: restructure devicetree for development-phase
From: Andrew Jeffery @ 2026-06-10 13:04 UTC (permalink / raw)
  To: u8813345, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Joel Stanley
  Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
	colin.huang2, Carl Lee, Rex Fu, Andy Chung, Peter Shen
In-Reply-To: <20260602-anacapa-devlop-phase-devicetree-v3-0-7c93c5df8d9b@gmail.com>

On Tue, 2026-06-02 at 21:24 +0800, Colin Huang via B4 Relay wrote:
> This series refactors the Anacapa BMC devicetree layout to better support
> development-phase hardware revisions (EVT1/EVT2/DVT) while keeping a platform
> entrypoint.
> 
> Signed-off-by: Colin Huang <u8813345@gmail.com>
> ---
> Changes in v3:
> - Restructure the EVT2 devicetree to inherit from the EVT1 devicetree, making it incremental rather than standalone.
> - Add the DVT devicetree, inheriting from the EVT2 devicetree.
> - Enable MCTP and FRU support for the NIC.
> - Align PDB fan GPIO numbering.
> - Add an EEPROM device node for the NFC adaptor board.
> - Add an additional EEPROM device node for the SCM.
> - Add shunt resistor values for HSC monitors
> - Link to v2: https://lore.kernel.org/r/20260409-anacapa-devlop-phase-devicetree-v2-0-68f328671653@gmail.com
> 

So just to check, the changes in patches 5-8 inclusive are applicable
to all of EVT1, EVT2 and DVT (given the way you've structured the
includes)?

> Changes in v2:
> - Fix dtbs_check fail.
>   Validated by following command:
>     make dt_binding_check DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml
>     make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa.dtb
>     make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa-evt1.dtb
>     make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa-evt2.dtb
> - Link to v1: https://lore.kernel.org/r/20260407-anacapa-devlop-phase-devicetree-v1-0-97b96367cac3@gmail.com
> 
> ---
> Andy Chung (1):
>       ARM: dts: aspeed: anacapa: Enable MCTP and FRU for NIC
> 
> Carl Lee (1):
>       ARM: dts: aspeed: anacapa: Add eeprom device node for NFC adaptor board
> 
> Colin Huang (5):
>       dt-bindings: arm: aspeed: add Anacapa EVT1 EVT2 DVT board
>       ARM: dts: aspeed: anacapa: add EVT1 devicetree and point wrapper to it
>       ARM: dts: aspeed: anacapa: add EVT2 devicetree inheriting EVT1
>       ARM: dts: aspeed: anacapa: add DVT devicetree inheriting EVT2
>       ARM: dts: aspeed: anacapa: add additional EEPROM node for SCM

If you need to respin this series for some reason, can you please
capitalise the first word of the short description (the bit after the
last ':') for the commits above and the one below?

> 
> Peter Shen (1):
>       ARM: dts: aspeed: anacapa: evt2: add shunt resistor values for HSC monitors
> 
> Rex Fu (1):
>       ARM: dts: aspeed: anacapa: Align PDB fan GPIO numbering
> 
>  .../devicetree/bindings/arm/aspeed/aspeed.yaml     |    3 +
>  .../dts/aspeed/aspeed-bmc-facebook-anacapa-dvt.dts |  178 +++
>  .../aspeed/aspeed-bmc-facebook-anacapa-evt1.dts    | 1179 ++++++++++++++++++++
>  .../aspeed/aspeed-bmc-facebook-anacapa-evt2.dts    |  228 ++++
>  .../dts/aspeed/aspeed-bmc-facebook-anacapa.dts     | 1077 +-----------------
>  5 files changed, 1589 insertions(+), 1076 deletions(-)
> ---
> base-commit: 7ca1caf017d34396397b19fb4de9ecef256f4acc
> change-id: 20260407-anacapa-devlop-phase-devicetree-4101d3f312c0
> 
> Best regards,

Andrew


^ permalink raw reply

* Re: [PATCH] ASoC: meson: axg-tdm-formatter: Use guard() for mutex locks
From: Jerome Brunet @ 2026-06-10 12:54 UTC (permalink / raw)
  To: phucduc.bui
  Cc: Mark Brown, Liam Girdwood, Neil Armstrong, Kevin Hilman,
	Martin Blumenstingl, Jaroslav Kysela, Takashi Iwai, linux-sound,
	linux-arm-kernel, linux-amlogic, linux-kernel
In-Reply-To: <20260610102153.83367-1-phucduc.bui@gmail.com>

On mer. 10 juin 2026 at 17:21, phucduc.bui@gmail.com wrote:

> From: bui duc phuc <phucduc.bui@gmail.com>
>
> Clean up the code using guard() for mutex locks.
> Merely code refactoring, and no behavior change.

I suppose it is OK but it does not seem to really clean anything and
make the code easier to follow in that instance, from my perspective at
least.

If there is policy to systematically use guard() whenever
possible then OK, otherwise it seems unnecessary.

>
> Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
> ---
>  sound/soc/meson/axg-tdm-formatter.c | 22 ++++++++--------------
>  1 file changed, 8 insertions(+), 14 deletions(-)
>
> diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
> index f451e4dce442..a6ba401104d5 100644
> --- a/sound/soc/meson/axg-tdm-formatter.c
> +++ b/sound/soc/meson/axg-tdm-formatter.c
> @@ -157,20 +157,19 @@ static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
>  	struct axg_tdm_stream *ts = formatter->stream;
>  	int ret = 0;
>  
> -	mutex_lock(&ts->lock);
> +	guard(mutex)(&ts->lock);
>  
>  	/* Catch up if the stream is already running when we attach */
>  	if (ts->ready) {
>  		ret = axg_tdm_formatter_enable(formatter);
>  		if (ret) {
>  			pr_err("failed to enable formatter\n");
> -			goto out;
> +			return ret;
>  		}
>  	}
>  
>  	list_add_tail(&formatter->list, &ts->formatter_list);
> -out:
> -	mutex_unlock(&ts->lock);
> +
>  	return ret;
>  }
>  
> @@ -178,9 +177,8 @@ static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
>  {
>  	struct axg_tdm_stream *ts = formatter->stream;
>  
> -	mutex_lock(&ts->lock);
> -	list_del(&formatter->list);
> -	mutex_unlock(&ts->lock);
> +	scoped_guard(mutex, &ts->lock)
> +		list_del(&formatter->list);
>  
>  	axg_tdm_formatter_disable(formatter);
>  }
> @@ -330,7 +328,7 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
>  	struct axg_tdm_formatter *formatter;
>  	int ret = 0;
>  
> -	mutex_lock(&ts->lock);
> +	guard(mutex)(&ts->lock);
>  	ts->ready = true;
>  
>  	/* Start all the formatters attached to the stream */
> @@ -338,12 +336,10 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
>  		ret = axg_tdm_formatter_enable(formatter);
>  		if (ret) {
>  			pr_err("failed to start tdm stream\n");
> -			goto out;
> +			return ret;
>  		}
>  	}
>  
> -out:
> -	mutex_unlock(&ts->lock);
>  	return ret;
>  }
>  EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
> @@ -352,15 +348,13 @@ void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
>  {
>  	struct axg_tdm_formatter *formatter;
>  
> -	mutex_lock(&ts->lock);
> +	guard(mutex)(&ts->lock);
>  	ts->ready = false;
>  
>  	/* Stop all the formatters attached to the stream */
>  	list_for_each_entry(formatter, &ts->formatter_list, list) {
>  		axg_tdm_formatter_disable(formatter);
>  	}
> -
> -	mutex_unlock(&ts->lock);
>  }
>  EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);

-- 
Jerome


^ permalink raw reply

* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 12:53 UTC (permalink / raw)
  To: Will Deacon
  Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
	linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>

Hi Will,

On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>>    - A PE executes a Device-nGnR* store followed by a younger
>>      Device-nGnR* load.
>>    - The store is not a store-release.
>>    - The accesses target the same peripheral and do not overlap in bytes.
>>    - There is at most one intervening Device-nGnR* store in program
>>      order, and there are no intervening Device-nGnR* loads.
>>    - There is no DSB, and no DMB that orders loads, between the store and
>>      the load.
>>    - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.

Thanks, Will. I’ll drop paragraph and avoid describing store-release
as an architectural ordering mechanism here.

>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.
> Sashiko points out that you're missing __const_memcpy_toio_aligned32().

I’ll also cover __const_memcpy_toio_aligned32(); it currently emits plain
STRs directly and can bypass the raw write helper workaround. I’ll audit
the aligned64 path at the same time.

>> Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
>> ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
>> parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
>> the plain str* sequence.
>>
>> Note: stlr* only supports base-register addressing, so the raw accessors
>> can no longer use the offset addressing introduced by commit d044d6ba6f02
>> ("arm64: io: permit offset addressing"). The str* and stlr* alternates
>> share a single inline-asm operand and the sequence is selected at boot,
>> so the operand form is fixed at compile time; unaffected CPUs keep using
>> str* but also revert to base-register addressing. This keeps the store
>> side as simple as the existing load-side patching (load-acquire) and
>> avoids adding complexity to the device write path; retaining offset
>> addressing only for str* would otherwise require a runtime branch on
>> every write.
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?

For the offset-addressing concern, I’ll rework the raw accessors so
unaffected CPUs keep the existing offset-addressed STR sequence, and
only CPUs with ARM64_WORKAROUND_DEVICE_STORE_RELEASE take the base-register
STLR path.

I’ll post a v3 using the patched branch from alternative_has_cap_unlikely(),
and include the memcpy_toio() aligned-helper coverage as shown below.


--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
  /*
   * Generic IO read/write.  These perform native-endian accesses.
   */
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+       return alternative_has_cap_unlikely(
+                               ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
  #define __raw_writeb __raw_writeb
  static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
  {
         volatile u8 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writeb_stlr(val, addr);
+               return;
+       }
+
         asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
  static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
  {
         volatile u16 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writew_stlr(val, addr);
+               return;
+       }
+
         asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
  static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
  {
         volatile u32 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writel_stlr(val, addr);
+               return;
+       }
+
         asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
  static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
  {
         volatile u64 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writeq_stlr(val, addr);
+               return;
+       }
+
         asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -147,6 +201,12 @@ static __always_inline void
  __const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
                               size_t count)
  {
+       if (arm64_needs_device_store_release()) {
+               while (count--)
+                       __raw_writel_stlr(*from++, to++);
+               return;
+       }
+
         switch (count) {
         case 8:
                 asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
  __const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
                               size_t count)
  {
+       if (arm64_needs_device_store_release()) {
+               while (count--)
+                       __raw_writeq_stlr(*from++, to++);
+               return;
+       }
+
         switch (count) {
         case 8:
                 asm volatile("str %x0, [%8, #8 * 0]\n"

I'll post v3 patch with jump instruction patch.

--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
  /*
   * Generic IO read/write.  These perform native-endian accesses.
   */
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+       return alternative_has_cap_unlikely(
+                               ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+                                             volatile void __iomem *addr)
+{
+       asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
  #define __raw_writeb __raw_writeb
  static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
  {
         volatile u8 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writeb_stlr(val, addr);
+               return;
+       }
+
         asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
  static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
  {
         volatile u16 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writew_stlr(val, addr);
+               return;
+       }
+
         asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
  static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
  {
         volatile u32 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writel_stlr(val, addr);
+               return;
+       }
+
         asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
  static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
  {
         volatile u64 __iomem *ptr = addr;
+
+       if (arm64_needs_device_store_release()) {
+               __raw_writeq_stlr(val, addr);
+               return;
+       }
+
         asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
  }
@@ -147,6 +201,12 @@ static __always_inline void
  __const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
                               size_t count)
  {
+       if (arm64_needs_device_store_release()) {
+               while (count--)
+                       __raw_writel_stlr(*from++, to++);
+               return;
+       }
+
         switch (count) {
         case 8:
                 asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
  __const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
                               size_t count)
  {
+       if (arm64_needs_device_store_release()) {
+               while (count--)
+                       __raw_writeq_stlr(*from++, to++);
+               return;
+       }
+
         switch (count) {
         case 8:
                 asm volatile("str %x0, [%8, #8 * 0]\n"

-Shanker



^ permalink raw reply

* Re: [PATCH v2 2/2] soc: aspeed: add host-side PCIe BMC device driver
From: Andrew Jeffery @ 2026-06-10 12:51 UTC (permalink / raw)
  To: Grégoire Layet, joel
  Cc: andrew, jacky_chou, yh_chung, ninad, linux-aspeed,
	linux-arm-kernel, linux-kernel
In-Reply-To: <13d18d25f53e0a084a8c17219804b305d4667c6b.1780929570.git.gregoire.layet@9elements.com>

On Mon, 2026-06-08 at 14:51 +0000, Grégoire Layet wrote:
> Taken from ASPEED 6.18 Kernel SDK
> 
> Add support for VUART over PCIe between BMC and host.
> This add host side driver.
> 
> Signed-off-by: Jacky Chou <jacky_chou@aspeedtech.com>
> Signed-off-by: aspeedyh <yh_chung@aspeedtech.com>
> Signed-off-by: Grégoire Layet <gregoire.layet@9elements.com>
> Tested-by: Grégoire Layet <gregoire.layet@9elements.com>
> ---
>  drivers/soc/aspeed/Kconfig               |   8 +
>  drivers/soc/aspeed/Makefile              |   1 +
>  drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++

Again, I'd rather we avoid drivers/soc/aspeed.

>  3 files changed, 258 insertions(+)
>  create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
> 
> diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
> index 3e1fcf3c3268..5deefb64e8c7 100644
> --- a/drivers/soc/aspeed/Kconfig
> +++ b/drivers/soc/aspeed/Kconfig
> @@ -11,6 +11,14 @@ config ASPEED_BMC_DEV
>  	  Enable support for the ASPEED AST2600 BMC Device.
>  	  This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
>  
> +config ASPEED_HOST_BMC_DEV
> +	tristate "ASPEED Host BMC Device"
> +	depends on PCI
> +	depends on SERIAL_8250
> +	help
> +	  Enable support for the ASPEED AST2600 BMC Device on the Host.
> +	  This configure the PCIe and setup two 8250 compatible VUART ports.
> +
>  config ASPEED_LPC_CTRL
>  	tristate "ASPEED LPC firmware cycle control"
>  	select REGMAP
> diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
> index fab0d247df66..3fd3f6d8d36e 100644
> --- a/drivers/soc/aspeed/Makefile
> +++ b/drivers/soc/aspeed/Makefile
> @@ -1,5 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
> +obj-$(CONFIG_ASPEED_HOST_BMC_DEV)	+= aspeed-host-bmc-dev.o
>  obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
>  obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
>  obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
> diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspeed-host-bmc-dev.c
> new file mode 100644
> index 000000000000..7cb52a770fb6
> --- /dev/null
> +++ b/drivers/soc/aspeed/aspeed-host-bmc-dev.c
> @@ -0,0 +1,249 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +// Copyright (C) ASPEED Technology Inc.
> +
> +#include <linux/init.h>
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/pci.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial_8250.h>
> +
> +static DEFINE_IDA(bmc_device_ida);
> +
> +#define VUART_MAX_PARMS	2

Given the one supported piece of hardware we could avoid the associated
loops and rather extract loop bodies to functions and call the function
twice.

> +#define MAX_MSI_NUM		8
> +#define BMC_MULTI_MSI	32
> +
> +#define DRIVER_NAME "aspeed-host-bmc-dev"
> +
> +enum aspeed_platform_id {
> +	ASPEED,
> +};
> +
> +enum msi_index {
> +	VUART0_MSI,
> +	VUART1_MSI,
> +};
> +
> +/* Match msi_index */
> +static int ast2600_msi_idx_table[MAX_MSI_NUM] = { 16, 15 };
> +
> +struct aspeed_platform {
> +	int (*setup)(struct pci_dev *pdev);
> +};
> +
> +struct aspeed_pci_bmc_dev {
> +	struct device *dev;
> +	struct aspeed_platform *platform;
> +	kernel_ulong_t driver_data;
> +	int id;
> +
> +	unsigned long message_bar_base;
> +	unsigned long message_bar_size;
> +	void __iomem *msg_bar_reg;
> +
> +	struct uart_8250_port uart[VUART_MAX_PARMS];
> +	int uart_line[VUART_MAX_PARMS];
> +
> +	/* Interrupt
> +	 * The index of array is using to enum msi_index
> +	 */
> +	int *msi_idx_table;
> +};
> +
> +static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +
> +	/* Assign static msi index table by platform */
> +	pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table;
> +
> +	if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)
> +		/* Set all msi index to the first vector */
> +		memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM);
> +}
> +
> +static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +	struct device *dev = &pdev->dev;
> +	u16 vuart_ioport;
> +	int ret, i;
> +
> +	for (i = 0; i < VUART_MAX_PARMS; i++) {
> +		/* Assign the line to non-exist device */
> +		pci_bmc_dev->uart_line[i] = -ENOENT;
> +		vuart_ioport = 0x3F8 - (i * 0x100);
> +		pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
> +		pci_bmc_dev->uart[i].port.uartclk = 115200 * 16;
> +		pci_bmc_dev->uart[i].port.irq =
> +			pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]);
> +		pci_bmc_dev->uart[i].port.dev = dev;
> +		pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32;
> +		pci_bmc_dev->uart[i].port.iobase = 0;
> +		pci_bmc_dev->uart[i].port.mapbase =
> +			pci_bmc_dev->message_bar_base + (vuart_ioport << 2);
> +		pci_bmc_dev->uart[i].port.membase = 0;
> +		pci_bmc_dev->uart[i].port.type = PORT_16550A;
> +		pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
> +		pci_bmc_dev->uart[i].port.regshift = 2;
> +		ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]);
> +		if (ret < 0) {
> +			dev_err_probe(dev, ret, "Can't setup PCIe VUART\n");
> +			return ret;
> +		}
> +		pci_bmc_dev->uart_line[i] = ret;
> +	}
> +	return 0;
> +}
> +
> +static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +	int i;
> +
> +	for (i = 0; i < VUART_MAX_PARMS; i++) {
> +		if (pci_bmc_dev->uart_line[i] >= 0)
> +			serial8250_unregister_port(pci_bmc_dev->uart_line[i]);
> +	}
> +}
> +
> +static int aspeed_pci_host_setup(struct pci_dev *pdev)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +	int rc = 0;
> +
> +	/* Get Message BAR */
> +	pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
> +	pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
> +	pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
> +	if (!pci_bmc_dev->msg_bar_reg)
> +		return -ENOMEM;
> +
> +	if (pdev->revision < 0x27) {
> +		/* AST2600 ERRTA40: dummy read */

Can you please rather document what problem this is actually solving.

> +		(void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
> +	} else {
> +		/* AST2700 not supported */
> +		pr_err("AST2700 detected but not supported");

This logs an error but rc = 0 on return. Perhaps drop the log message
and return an appropriate error code?

> +		goto out_free0;
> +	}
> +
> +	rc = aspeed_pci_bmc_device_setup_vuart(pdev);
> +	if (rc) {
> +		pr_err("Cannot setup Virtual UART");
> +		goto out_free0;
> +	}
> +
> +	return 0;
> +
> +out_free0:
> +	pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
> +
> +	return rc;
> +}
> +
> +static struct aspeed_platform aspeed_pcie_host[] = {
> +	{ .setup = aspeed_pci_host_setup },
> +	{ 0 }
> +};
> +
> +static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev;
> +	int rc = 0;
> +
> +	pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);

I think we could do without this.

> +
> +	pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL);
> +	if (!pci_bmc_dev)
> +		return -ENOMEM;
> +
> +	/* Get platform id */
> +	pci_bmc_dev->driver_data = ent->driver_data;
> +	pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data];
> +
> +	pci_bmc_dev->id = ida_alloc(&bmc_device_ida, GFP_KERNEL);

This seems unnecessary.

> +	if (pci_bmc_dev->id < 0)
> +		return pci_bmc_dev->id;
> +
> +	rc = pci_enable_device(pdev);
> +	if (rc) {
> +		dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
> +		return rc;
> +	}
> +
> +	pci_set_master(pdev);
> +	pci_set_drvdata(pdev, pci_bmc_dev);
> +
> +	/* Prepare IRQ resource */
> +	aspeed_pci_setup_irq_resource(pdev);
> +
> +	/* Setup BMC PCI device */
> +	rc = pci_bmc_dev->platform->setup(pdev);

As with patch 1 this indirection seems unnecessary.

> +	if (rc) {
> +		dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc);
> +		pci_free_irq_vectors(pdev);
> +		pci_disable_device(pdev);
> +		return rc;
> +	}
> +
> +	return 0;
> +}
> +
> +static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
> +{
> +	struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +
> +	if (pci_bmc_dev->driver_data == ASPEED)

This condition seems unnecessary as the value shouldn't be anything
else.

> +		aspeed_pci_host_bmc_device_release_vuart(pdev);
> +
> +	ida_free(&bmc_device_ida, pci_bmc_dev->id);
> +
> +	pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
> +
> +	pci_free_irq_vectors(pdev);
> +	pci_disable_device(pdev);
> +}
> +
> +/**
> + * This table holds the list of (VendorID,DeviceID) supported by this driver
> + *
> + */

I think that's self-evident and prefer the comment be removed.

> +static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
> +	/* ASPEED BMC Device */
> +	{ PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00,
> +	  .driver_data = ASPEED },
> +	{
> +		0,
> +	}
> +};
> +
> +MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
> +
> +static struct pci_driver aspeed_host_bmc_dev_driver = {
> +	.name		= DRIVER_NAME,
> +	.id_table	= aspeed_host_bmc_dev_pci_ids,
> +	.probe		= aspeed_pci_host_bmc_device_probe,
> +	.remove		= aspeed_pci_host_bmc_device_remove,
> +};
> +
> +static int __init aspeed_host_bmc_device_init(void)
> +{
> +	return pci_register_driver(&aspeed_host_bmc_dev_driver);
> +}
> +
> +static void aspeed_host_bmc_device_exit(void)
> +{
> +	/* unregister pci driver */
> +	pci_unregister_driver(&aspeed_host_bmc_dev_driver);
> +}
> +
> +late_initcall(aspeed_host_bmc_device_init);
> +module_exit(aspeed_host_bmc_device_exit);

module_driver() could be used here.

> +
> +MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
> +MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
> +MODULE_LICENSE("GPL");


^ permalink raw reply

* Re: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Arnd Bergmann @ 2026-06-10 12:50 UTC (permalink / raw)
  To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
	Will Deacon, linux-serial, linux-arm-kernel, devicetree,
	linux-kernel
In-Reply-To: <20260610112821.3030099-2-jason.li@cortina-access.com>

On Wed, Jun 10, 2026, at 13:28, Jason Li wrote:
> This series adds Linux kernel support for the UART controller integrated
> in Cortina-Access SoCs, with CA8289 (Venus) as the first supported device.

Hi Jason,

Thanks a lot for your submission!

I'm glad to see Cortina Access is getting back to upstreaming
this support, I see that you first tries this in 2021 but
didn't get very far at the time. The last submission was v4,
so it would make sense to cound this one as v5 and continue
with v6 next time.

You have already received a number of comments, so I'll skip
looking at the details for the moment and let you work through
them.

Regarding how to split up the patch series between uart and
soc, I think sending them together during the review phase
as you do here makes sense, but as they are loosely coupled,
I think we will likely merge them separately. For simplicity,
I would then just put the MAINTAINERS entry and the bindings
for the vendor and board into the series for the soc tree.

It would also help me if you could add some more context about
the SoC into the patch description for the patch that adds
the arm64 platform, in particular:

 - is this the only one you are planning to upstream at this
   point, or do you already have plans for other SoCs in this
   family?

 - do you expect to see full support for actual end-user
   products using these chips?

 - is there any shared lineage with the cortina-systems
   (storlink/storm, now marvell) gemini 32-bit chips that we
   already support, or with any of the Realtek SoCs that
   are also being upstreamed now?

       Arnd


^ permalink raw reply

* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Jason Gunthorpe @ 2026-06-10 12:50 UTC (permalink / raw)
  To: Will Deacon
  Cc: Shanker Donthineni, Catalin Marinas, linux-arm-kernel,
	Vladimir Murzin, Mark Rutland, linux-kernel, linux-doc,
	Vikram Sethi, Jason Sequeira
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>

On Wed, Jun 10, 2026 at 12:28:33PM +0100, Will Deacon wrote:
> > Note: stlr* only supports base-register addressing, so the raw accessors
> > can no longer use the offset addressing introduced by commit d044d6ba6f02
> > ("arm64: io: permit offset addressing"). The str* and stlr* alternates
> > share a single inline-asm operand and the sequence is selected at boot,
> > so the operand form is fixed at compile time; unaffected CPUs keep using
> > str* but also revert to base-register addressing. This keeps the store
> > side as simple as the existing load-side patching (load-acquire) and
> > avoids adding complexity to the device write path; retaining offset
> > addressing only for str* would otherwise require a runtime branch on
> > every write.
> 
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?

I think it was more a fall out of the work there, after looking at the
assembly this minor edit to the constraint made a nice codegen
impact. It is certainly a shame to loose it for this bug.

If we care about write combining we can't have a branch anyhow, but
that is most important for the specific memcpy operations (which will
need a branch)

Jason


^ permalink raw reply

* Re: [PATCH v3 2/2] clk: amlogic: Add A9 peripherals clock controller driver
From: Jerome Brunet @ 2026-06-10 12:49 UTC (permalink / raw)
  To: Jian Hu via B4 Relay
  Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao, Kevin Hilman,
	Martin Blumenstingl, jian.hu, linux-amlogic, linux-clk,
	devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20260610-a9_peripherals-v3-2-d07a78085f71@amlogic.com>

On mer. 10 juin 2026 at 16:14, Jian Hu via B4 Relay <devnull+jian.hu.amlogic.com@kernel.org> wrote:

> From: Jian Hu <jian.hu@amlogic.com>
>
> Add the peripherals clock controller driver for the Amlogic A9 SoC family.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
>  drivers/clk/meson/Kconfig          |   15 +
>  drivers/clk/meson/Makefile         |    1 +
>  drivers/clk/meson/a9-peripherals.c | 1925 ++++++++++++++++++++++++++++++++++++
>  3 files changed, 1941 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index cf8cf3f9e4ee..86d2e270e1b8 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -132,6 +132,21 @@ config COMMON_CLK_A1_PERIPHERALS
>  	  device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>  	  controller to work.
>  
> +config COMMON_CLK_A9_PERIPHERALS
> +	tristate "Amlogic A9 SoC peripherals clock controller support"
> +	depends on ARM64 || COMPILE_TEST
> +	default ARCH_MESON
> +	select COMMON_CLK_MESON_REGMAP
> +	select COMMON_CLK_MESON_CLKC_UTILS
> +	select COMMON_CLK_MESON_DUALDIV
> +	select COMMON_CLK_MESON_VID_PLL_DIV
> +	imply COMMON_CLK_SCMI
> +	imply COMMON_CLK_A9_PLL
> +	help
> +	  Support for the peripherals clock controller on Amlogic A311Y3 based
> +	  device, AKA A9. Peripherals are required by most peripheral to operate.
> +	  Say Y if you want A9 peripherals clock controller to work.
> +
>  config COMMON_CLK_C3_PLL
>  	tristate "Amlogic C3 PLL clock controller"
>  	depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index c6719694a242..bccd9ace9201 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>  obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>  obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>  obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a9-peripherals.c b/drivers/clk/meson/a9-peripherals.c
> new file mode 100644
> index 000000000000..fef48613e186
> --- /dev/null
> +++ b/drivers/clk/meson/a9-peripherals.c
> @@ -0,0 +1,1925 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
> + */
> +
> +#include <dt-bindings/clock/amlogic,a9-peripherals-clkc.h>
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +#include "vid-pll-div.h"
> +
> +#define SYS_CLK_EN0_REG0			0x30
> +#define SYS_CLK_EN0_REG1			0x34
> +#define SYS_CLK_EN0_REG2			0x38
> +#define SYS_CLK_EN0_REG3			0x3c
> +#define SD_EMMC_CLK_CTRL0			0x90
> +#define SD_EMMC_CLK_CTRL1			0x94
> +#define PWM_CLK_H_CTRL				0xbc
> +#define PWM_CLK_I_CTRL				0xc0
> +#define PWM_CLK_J_CTRL				0xc4
> +#define PWM_CLK_K_CTRL				0xc8
> +#define PWM_CLK_L_CTRL				0xcc
> +#define PWM_CLK_M_CTRL				0xd0
> +#define PWM_CLK_N_CTRL				0xd4
> +#define SPISG_CLK_CTRL				0x100
> +#define SPISG_CLK_CTRL1				0x104
> +#define SAR_CLK_CTRL				0x150
> +#define AMFC_CLK_CTRL				0x154
> +#define NNA_CLK_CTRL				0x15c
> +#define USB_CLK_CTRL				0x160
> +#define PCIE_TL_CLK_CTRL			0x164
> +#define CMPR_CLK_CTRL				0x168
> +#define DEWARP_CLK_CTRL				0x16c
> +#define SC_CLK_CTRL				0x170
> +#define DPTX_CLK_CTRL				0x178
> +#define ISP_CLK_CTRL				0x17c
> +#define CVE_CLK_CTRL				0x180
> +#define PP_CLK_CTRL				0x184
> +#define GLB_CLK_CTRL				0x188
> +#define USB_CLK_CTRL0				0x18c
> +#define USB_CLK_CTRL1				0x190
> +#define CAN_CLK_CTRL				0x194
> +#define CAN_CLK_CTRL1				0x198
> +#define I3C_CLK_CTRL				0x19c
> +#define TS_CLK_CTRL				0x1a0
> +#define ETH_CLK_CTRL				0x1a4
> +#define GEN_CLK_CTRL				0x1a8
> +#define CLK12_24_CTRL				0x1ac
> +#define MALI_CLK_CTRL				0x200
> +#define MALI_STACK_CLK_CTRL			0x204
> +#define DSPA_CLK_CTRL				0x220
> +#define HEVCF_CLK_CTRL				0x240
> +#define HCODEC_CLK_CTRL				0x244
> +#define VPU_CLK_CTRL				0x260
> +#define VAPB_CLK_CTRL				0x268
> +#define VPU_CLKB_CTRL				0x280
> +#define HDMI_CLK_CTRL				0x284
> +#define HTX_CLK_CTRL				0x28c
> +#define HTX_CLK_CTRL1				0x290
> +#define HRX_CLK_CTRL				0x294
> +#define HRX_CLK_CTRL1				0x298
> +#define HRX_CLK_CTRL2				0x29c
> +#define HRX_CLK_CTRL3				0x2a0
> +#define VID_LOCK_CLK_CTRL			0x2a4
> +#define VDIN_MEAS_CLK_CTRL			0x2a8
> +#define VID_PLL_CLK_DIV				0x2b0
> +#define VID_CLK_CTRL				0x2c0
> +#define VID_CLK_CTRL2				0x2c4
> +#define VID_CLK_DIV				0x2c8
> +#define VIID_CLK_DIV				0x2cc
> +#define VIID_CLK_CTRL				0x2d0
> +#define MIPI_CSI_PHY_CLK_CTRL			0x2e0
> +#define DSI_MEAS_CLK_CTRL			0x2f4
> +
> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \
> +	MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
> +
> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
> +	MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A9_COMP_GATE(_name, _reg, _bit, _iflags) \
> +	MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
> +
> +static const struct clk_parent_data a9_sys_pclk_parents = { .fw_name = "sys" };
> +
> +#define A9_SYS_PCLK(_name, _reg, _bit) \
> +	MESON_PCLK(a9_##_name, _reg, _bit, &a9_sys_pclk_parents, 0)
> +
> +static A9_SYS_PCLK(sys_am_axi,		SYS_CLK_EN0_REG0, 0);
> +static A9_SYS_PCLK(sys_dos,		SYS_CLK_EN0_REG0, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi,	SYS_CLK_EN0_REG0, 3);
> +static A9_SYS_PCLK(sys_eth_phy,		SYS_CLK_EN0_REG0, 4);
> +static A9_SYS_PCLK(sys_amfc,		SYS_CLK_EN0_REG0, 5);
> +static A9_SYS_PCLK(sys_mali,		SYS_CLK_EN0_REG0, 6);
> +static A9_SYS_PCLK(sys_nna,		SYS_CLK_EN0_REG0, 7);
> +static A9_SYS_PCLK(sys_eth_axi,		SYS_CLK_EN0_REG0, 8);
> +static A9_SYS_PCLK(sys_dp_apb,		SYS_CLK_EN0_REG0, 9);
> +static A9_SYS_PCLK(sys_edptx_apb,	SYS_CLK_EN0_REG0, 10);
> +static A9_SYS_PCLK(sys_u3hsg,		SYS_CLK_EN0_REG0, 11);
> +static A9_SYS_PCLK(sys_aucpu,		SYS_CLK_EN0_REG0, 14);
> +static A9_SYS_PCLK(sys_glb,		SYS_CLK_EN0_REG0, 15);
> +static A9_SYS_PCLK(sys_combo_dphy_apb,	SYS_CLK_EN0_REG0, 17);
> +static A9_SYS_PCLK(sys_hdmirx_apb,	SYS_CLK_EN0_REG0, 18);
> +static A9_SYS_PCLK(sys_hdmirx_pclk,	SYS_CLK_EN0_REG0, 19);
> +static A9_SYS_PCLK(sys_mipi_dsi_phy,	SYS_CLK_EN0_REG0, 20);
> +static A9_SYS_PCLK(sys_can0,		SYS_CLK_EN0_REG0, 21);
> +static A9_SYS_PCLK(sys_can1,		SYS_CLK_EN0_REG0, 22);
> +static A9_SYS_PCLK(sys_sd_emmc_a,	SYS_CLK_EN0_REG0, 24);
> +static A9_SYS_PCLK(sys_sd_emmc_b,	SYS_CLK_EN0_REG0, 25);
> +static A9_SYS_PCLK(sys_sd_emmc_c,	SYS_CLK_EN0_REG0, 26);
> +static A9_SYS_PCLK(sys_sc,		SYS_CLK_EN0_REG0, 27);
> +static A9_SYS_PCLK(sys_acodec,		SYS_CLK_EN0_REG0, 28);
> +static A9_SYS_PCLK(sys_mipi_isp,	SYS_CLK_EN0_REG0, 29);
> +static A9_SYS_PCLK(sys_msr,		SYS_CLK_EN0_REG0, 30);
> +static A9_SYS_PCLK(sys_audio,		SYS_CLK_EN0_REG1, 0);
> +static A9_SYS_PCLK(sys_mipi_dsi_b,	SYS_CLK_EN0_REG1, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi1_phy,	SYS_CLK_EN0_REG1, 2);
> +static A9_SYS_PCLK(sys_eth,		SYS_CLK_EN0_REG1, 3);
> +static A9_SYS_PCLK(sys_eth_1g_mac,	SYS_CLK_EN0_REG1, 4);
> +static A9_SYS_PCLK(sys_uart_a,		SYS_CLK_EN0_REG1, 5);
> +static A9_SYS_PCLK(sys_uart_f,		SYS_CLK_EN0_REG1, 10);
> +static A9_SYS_PCLK(sys_ts_a55,		SYS_CLK_EN0_REG1, 11);
> +static A9_SYS_PCLK(sys_eth_1g_axi,	SYS_CLK_EN0_REG1, 12);
> +static A9_SYS_PCLK(sys_ts_dos,		SYS_CLK_EN0_REG1, 13);
> +static A9_SYS_PCLK(sys_u3drd_b,		SYS_CLK_EN0_REG1, 14);
> +static A9_SYS_PCLK(sys_ts_core,		SYS_CLK_EN0_REG1, 15);
> +static A9_SYS_PCLK(sys_ts_pll,		SYS_CLK_EN0_REG1, 16);
> +static A9_SYS_PCLK(sys_csi_dig_clkin,	SYS_CLK_EN0_REG1, 18);
> +static A9_SYS_PCLK(sys_cve,		SYS_CLK_EN0_REG1, 19);
> +static A9_SYS_PCLK(sys_ge2d,		SYS_CLK_EN0_REG1, 20);
> +static A9_SYS_PCLK(sys_spisg,		SYS_CLK_EN0_REG1, 21);
> +static A9_SYS_PCLK(sys_u3drd_1,		SYS_CLK_EN0_REG1, 22);
> +static A9_SYS_PCLK(sys_u2h,		SYS_CLK_EN0_REG1, 23);
> +static A9_SYS_PCLK(sys_pcie_mac_a,	SYS_CLK_EN0_REG1, 24);
> +static A9_SYS_PCLK(sys_u3drd_a,		SYS_CLK_EN0_REG1, 25);
> +static A9_SYS_PCLK(sys_u2drd,		SYS_CLK_EN0_REG1, 26);
> +static A9_SYS_PCLK(sys_pcie_phy,	SYS_CLK_EN0_REG1, 27);
> +static A9_SYS_PCLK(sys_pcie_mac_b,	SYS_CLK_EN0_REG1, 28);
> +static A9_SYS_PCLK(sys_periph,		SYS_CLK_EN0_REG1, 29);
> +static A9_SYS_PCLK(sys_pio,		SYS_CLK_EN0_REG2, 0);
> +static A9_SYS_PCLK(sys_i3c,		SYS_CLK_EN0_REG2, 1);
> +static A9_SYS_PCLK(sys_i2c_m_e,		SYS_CLK_EN0_REG2, 2);
> +static A9_SYS_PCLK(sys_i2c_m_f,		SYS_CLK_EN0_REG2, 3);
> +static A9_SYS_PCLK(sys_hdmitx_apb,	SYS_CLK_EN0_REG2, 4);
> +static A9_SYS_PCLK(sys_i2c_m_i,		SYS_CLK_EN0_REG2, 5);
> +static A9_SYS_PCLK(sys_i2c_m_g,		SYS_CLK_EN0_REG2, 6);
> +static A9_SYS_PCLK(sys_i2c_m_h,		SYS_CLK_EN0_REG2, 7);
> +static A9_SYS_PCLK(sys_hdmi20_aes,	SYS_CLK_EN0_REG2, 9);
> +static A9_SYS_PCLK(sys_csi2_host,	SYS_CLK_EN0_REG2, 16);
> +static A9_SYS_PCLK(sys_csi2_adapt,	SYS_CLK_EN0_REG2, 17);
> +static A9_SYS_PCLK(sys_dspa,		SYS_CLK_EN0_REG2, 21);
> +static A9_SYS_PCLK(sys_pp_dma,		SYS_CLK_EN0_REG2, 22);
> +static A9_SYS_PCLK(sys_pp_wrapper,	SYS_CLK_EN0_REG2, 23);
> +static A9_SYS_PCLK(sys_vpu_intr,	SYS_CLK_EN0_REG2, 25);
> +static A9_SYS_PCLK(sys_csi2_phy,	SYS_CLK_EN0_REG2, 27);
> +static A9_SYS_PCLK(sys_saradc,		SYS_CLK_EN0_REG2, 28);
> +static A9_SYS_PCLK(sys_pwm_j,		SYS_CLK_EN0_REG2, 30);
> +static A9_SYS_PCLK(sys_pwm_i,		SYS_CLK_EN0_REG2, 31);
> +static A9_SYS_PCLK(sys_pwm_h,		SYS_CLK_EN0_REG3, 0);
> +static A9_SYS_PCLK(sys_pwm_n,		SYS_CLK_EN0_REG3, 8);
> +static A9_SYS_PCLK(sys_pwm_m,		SYS_CLK_EN0_REG3, 9);
> +static A9_SYS_PCLK(sys_pwm_l,		SYS_CLK_EN0_REG3, 10);
> +static A9_SYS_PCLK(sys_pwm_k,		SYS_CLK_EN0_REG3, 11);
> +
> +/* Channel 5 is unconnected. */
> +static u32 a9_sd_emmc_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 };
> +static const struct clk_parent_data a9_sd_emmc_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "gp1", },
> +	{ .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL0, 9, 0x7, a9_sd_emmc_parents,
> +		   a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL0, 0, 7);
> +static A9_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL0, 8, 0);
> +
> +static A9_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL0, 25, 0x7, a9_sd_emmc_parents,
> +		   a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL0, 16, 7);
> +static A9_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL0, 24, 0);
> +
> +static A9_COMP_SEL(sd_emmc_c, SD_EMMC_CLK_CTRL1, 9, 0x7, a9_sd_emmc_parents,
> +		   a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_c, SD_EMMC_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(sd_emmc_c, SD_EMMC_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_pwm_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", }
> +};
> +
> +static A9_COMP_SEL(pwm_h, PWM_CLK_H_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_h, PWM_CLK_H_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_h, PWM_CLK_H_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_i, PWM_CLK_I_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_i, PWM_CLK_I_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_i, PWM_CLK_I_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_j, PWM_CLK_J_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_j, PWM_CLK_J_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_j, PWM_CLK_J_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_k, PWM_CLK_K_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_k, PWM_CLK_K_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_k, PWM_CLK_K_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_l, PWM_CLK_L_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_l, PWM_CLK_L_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_l, PWM_CLK_L_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_m, PWM_CLK_M_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_m, PWM_CLK_M_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_m, PWM_CLK_M_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_n, PWM_CLK_N_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_n, PWM_CLK_N_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_n, PWM_CLK_N_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_spisg_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(spisg, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg, SPISG_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(spisg, SPISG_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(spisg1, SPISG_CLK_CTRL, 25, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg1, SPISG_CLK_CTRL, 16, 6);
> +static A9_COMP_GATE(spisg1, SPISG_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(spisg2, SPISG_CLK_CTRL1, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg2, SPISG_CLK_CTRL1, 0, 6);
> +static A9_COMP_GATE(spisg2, SPISG_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_saradc_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "sys", }
> +};
> +
> +static A9_COMP_SEL(saradc, SAR_CLK_CTRL, 9, 0x7, a9_saradc_parents, NULL);
> +static A9_COMP_DIV(saradc, SAR_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(saradc, SAR_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_amfc_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(amfc, AMFC_CLK_CTRL, 9, 0x7, a9_amfc_parents, NULL);
> +static A9_COMP_DIV(amfc, AMFC_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(amfc, AMFC_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_nna_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "gp2", },
> +	{ .fw_name = "hifi0", }
> +};
> +
> +static A9_COMP_SEL(nna, NNA_CLK_CTRL, 9, 0x7, a9_nna_parents, NULL);
> +static A9_COMP_DIV(nna, NNA_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(nna, NNA_CLK_CTRL, 8, 0);
> +
> +/* Channel 5 and 6 are unconnected. */
> +static u32 a9_usb_250m_parents_val_table[] = { 0, 1, 2, 3, 4, 7 };
> +static const struct clk_parent_data a9_usb_250m_parents[] = {
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(usb_250m, USB_CLK_CTRL, 9, 0x7, a9_usb_250m_parents,
> +		   a9_usb_250m_parents_val_table);
> +static A9_COMP_DIV(usb_250m, USB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(usb_250m, USB_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_usb_48m_pre_parents[] = {
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "gp1", },
> +	{ .fw_name = "gp2", },
> +	{ .fw_name = "fdiv2", },
> +};
> +
> +static A9_COMP_SEL(usb_48m_pre, USB_CLK_CTRL, 25, 0x3, a9_usb_48m_pre_parents,
> +		   NULL);
> +static A9_COMP_DIV(usb_48m_pre, USB_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(usb_48m_pre, USB_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_pcie_tl_parents[] = {
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(pcie_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents,
> +		   NULL);
> +static A9_COMP_DIV(pcie_tl, PCIE_TL_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(pcie_tl, PCIE_TL_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pcie1_tl, PCIE_TL_CLK_CTRL, 25, 0x7, a9_pcie_tl_parents,
> +		   NULL);
> +static A9_COMP_DIV(pcie1_tl, PCIE_TL_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(pcie1_tl, PCIE_TL_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_cmpr_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(cmpr, CMPR_CLK_CTRL, 25, 0x7, a9_cmpr_parents, NULL);
> +static A9_COMP_DIV(cmpr, CMPR_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(cmpr, CMPR_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_dewarpa_parents[] = {
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(dewarpa, DEWARP_CLK_CTRL, 9, 0x7, a9_dewarpa_parents, NULL);
> +static A9_COMP_DIV(dewarpa, DEWARP_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dewarpa, DEWARP_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_sc_parents[] = {
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(sc_pre, SC_CLK_CTRL, 9, 0x7, a9_sc_parents, NULL);
> +static A9_COMP_DIV(sc_pre, SC_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(sc_pre, SC_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_sc = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = SC_CLK_CTRL,
> +		.shift = 16,
> +		.width = 4,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("sc", &a9_sc_pre.hw,
> +				  &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_dptx_apb2_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(dptx_apb2, DPTX_CLK_CTRL, 9, 0x7, a9_dptx_apb2_parents, NULL);
> +static A9_COMP_DIV(dptx_apb2, DPTX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dptx_apb2, DPTX_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_dptx_aud_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", }
> +};
> +
> +static A9_COMP_SEL(dptx_aud, DPTX_CLK_CTRL, 25, 0x7, a9_dptx_aud_parents, NULL);
> +static A9_COMP_DIV(dptx_aud, DPTX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dptx_aud, DPTX_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_isp_parents[] = {
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(isp, ISP_CLK_CTRL, 9, 0x7, a9_isp_parents, NULL);
> +static A9_COMP_DIV(isp, ISP_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(isp, ISP_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_cve_vge_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(cve, CVE_CLK_CTRL, 9, 0x7, a9_cve_vge_parents, NULL);
> +static A9_COMP_DIV(cve, CVE_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(cve, CVE_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(vge, CVE_CLK_CTRL, 25, 0x7, a9_cve_vge_parents, NULL);
> +static A9_COMP_DIV(vge, CVE_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vge, CVE_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_pp_parents[] = {
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(pp, PP_CLK_CTRL, 9, 0x7, a9_pp_parents, NULL);
> +static A9_COMP_DIV(pp, PP_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(pp, PP_CLK_CTRL, 8, 0);
> +
> +/* Channel 6 is unconnected. */
> +static u32 a9_glb_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 7 };
> +static struct clk_regmap a9_dspa;

What is this ?

> +
> +static const struct clk_parent_data a9_glb_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a9_dspa.hw },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .hw = &a9_isp.hw },
> +	{ .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(glb, GLB_CLK_CTRL, 9, 0x7, a9_glb_parents,
> +		   a9_glb_parents_val_table);
> +static A9_COMP_DIV(glb, GLB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(glb, GLB_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_in = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = USB_CLK_CTRL,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv_in", &a9_usb_48m_pre.hw,
> +				  &clk_regmap_gate_ops, 0),

Same comment as on the AO controller

> +};
> +
> +static const struct meson_clk_dualdiv_param a9_usb_48m_dualdiv_div_table[] = {
> +	{ 733, 732, 8, 11, 1 },
> +	{ /* sentinel */ }
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_div = {
> +	.data = &(struct meson_clk_dualdiv_data) {
> +		.n1 = {
> +			.reg_off = USB_CLK_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = USB_CLK_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = USB_CLK_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = USB_CLK_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = USB_CLK_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a9_usb_48m_dualdiv_div_table,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv_div", &a9_usb_48m_dualdiv_in.hw,
> +				  &meson_clk_dualdiv_ops, 0),
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = USB_CLK_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("usb_48m_dualdiv_sel",
> +			((const struct clk_hw *[]) {
> +				&a9_usb_48m_dualdiv_in.hw,
> +				&a9_usb_48m_dualdiv_div.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = USB_CLK_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv", &a9_usb_48m_dualdiv_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_usb_48m = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = USB_CLK_CTRL1,
> +		.mask = 0x3,
> +		.shift = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("usb_48m",
> +			((const struct clk_hw *[]) {
> +				&a9_usb_48m_pre.hw,
> +				&a9_usb_48m_dualdiv.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/* Channel 3 is unconnected. */

You meant 3rd I guess but this is misleading and confusing with the
table bellow. Channel 2 would be more appropriate I think, since those
are 0-based.

> +static u32 a9_can_pe_parents_val_table[] = { 0, 1, 3 };
> +static const struct clk_parent_data a9_can_pe_parents[] = {
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(can_pe, CAN_CLK_CTRL, 9, 0x7, a9_can_pe_parents,
> +		   a9_can_pe_parents_val_table);
> +static A9_COMP_DIV(can_pe, CAN_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(can_pe, CAN_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(can1_pe, CAN_CLK_CTRL, 25, 0x7, a9_can_pe_parents,
> +		   a9_can_pe_parents_val_table);
> +static A9_COMP_DIV(can1_pe, CAN_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(can1_pe, CAN_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_can_filter_parents[] = {
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(can_filter, CAN_CLK_CTRL1, 9, 0x7, a9_can_filter_parents,
> +		   NULL);
> +static A9_COMP_DIV(can_filter, CAN_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(can_filter, CAN_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(can1_filter, CAN_CLK_CTRL1, 25, 0x7, a9_can_filter_parents,
> +		   NULL);
> +static A9_COMP_DIV(can1_filter, CAN_CLK_CTRL1, 16, 7);
> +static A9_COMP_GATE(can1_filter, CAN_CLK_CTRL1, 24, 0);
> +
> +static const struct clk_parent_data a9_i3c_parents[] = {
> +	{ .fw_name = "sys", },
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(i3c, I3C_CLK_CTRL, 9, 0x7, a9_i3c_parents, NULL);
> +static A9_COMP_DIV(i3c, I3C_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(i3c, I3C_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_ts_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = TS_CLK_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_FW_NAME("ts_div", "xtal",
> +				       &clk_regmap_divider_ops, 0),
> +};
> +
> +static struct clk_regmap a9_ts = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = TS_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ts", &a9_ts_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_eth_125m_div = {
> +	.mult = 1,
> +	.div = 8,
> +	.hw.init = CLK_HW_INIT_FW_NAME("eth_125m_div", "fdiv2",
> +				       &clk_fixed_factor_ops, 0),
> +};
> +
> +static struct clk_regmap a9_eth_125m = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.bit_idx = 7,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("eth_125m", &a9_eth_125m_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/*
> + * Channel 1, 2, 3, 4, 5 and 6 are unconnected,
> + * ext_rmii connects external PAD. Do not automatically reparent.
> + */
> +static u32 a9_eth_rmii_parents_val_table[] = { 0, 7 };
> +static const struct clk_parent_data a9_eth_rmii_parents[] = {
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "ext_rmii", }
> +};
> +
> +static struct clk_regmap a9_eth_rmii_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.mask = 0x7,
> +		.shift = 9,
> +		.table = a9_eth_rmii_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("eth_rmii_sel",
> +			a9_eth_rmii_parents,
> +			&clk_regmap_mux_ops, CLK_SET_RATE_NO_REPARENT),
> +};
> +
> +static struct clk_regmap a9_eth_rmii_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.shift = 0,
> +		.width = 7,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("eth_rmii_div", &a9_eth_rmii_sel.hw,
> +				  &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_eth_rmii = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = ETH_CLK_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("eth_rmii", &a9_eth_rmii_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/*
> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module;
> + * channel 12(msr_clk) is manged by clock measures module.
> + * channel 16(audio_dac1_clk) is manged by audio module.

Some why can't you expose those then ? gen clk is used for debugging
AFAIK. The clock above are worth debugging I think

Please be consistent with the CaSing.

> + * Channel 10, 11, 13, 14 are not connected.
> + */
> +static u32 a9_gen_parents_val_table[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9, 15, 17, 18,
> +					  19, 20, 21, 22, 23, 24, 25, 26};
> +static struct clk_regmap a9_vid_pll;
> +
> +static const struct clk_parent_data a9_gen_parents[] = {
> +	{ .fw_name = "xtal" },
> +	{ .fw_name = "rtc" },
> +	{ .fw_name = "sysplldiv16" },
> +	{ .hw = &a9_vid_pll.hw },
> +	{ .fw_name = "gp0" },
> +	{ .fw_name = "hifi1" },
> +	{ .fw_name = "hifi0" },
> +	{ .fw_name = "gp1" },
> +	{ .fw_name = "gp2" },
> +	{ .fw_name = "dsudiv16" },
> +	{ .fw_name = "cpudiv16" },
> +	{ .fw_name = "a78div16" },
> +	{ .fw_name = "fdiv2" },
> +	{ .fw_name = "fdiv2p5" },
> +	{ .fw_name = "fdiv3" },
> +	{ .fw_name = "fdiv4" },
> +	{ .fw_name = "fdiv5" },
> +	{ .fw_name = "fdiv7" },
> +	{ .fw_name = "mclk0" },
> +	{ .fw_name = "mclk1" }
> +};
> +
> +static A9_COMP_SEL(gen, GEN_CLK_CTRL, 12, 0x1f, a9_gen_parents,
> +		   a9_gen_parents_val_table);
> +static A9_COMP_DIV(gen, GEN_CLK_CTRL, 0, 11);
> +static A9_COMP_GATE(gen, GEN_CLK_CTRL, 11, 0);
> +
> +static struct clk_regmap a9_24m_in = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = CLK12_24_CTRL,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = CLK_HW_INIT_FW_NAME("24m_in", "xtal",
> +				       &clk_regmap_gate_ops, 0),
> +};
> +
> +static struct clk_regmap a9_12_24m = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = CLK12_24_CTRL,
> +		.shift = 10,
> +		.width = 1,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("12_24m", &a9_24m_in.hw,
> +				  &clk_regmap_divider_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_mali_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "gp1", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, a9_mali_parents, NULL);
> +static A9_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, a9_mali_parents, NULL);
> +static A9_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_mali = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = MALI_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("mali",
> +			((const struct clk_hw *[]) {
> +				&a9_mali_0.hw,
> +				&a9_mali_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static A9_COMP_SEL(mali_stack_0, MALI_STACK_CLK_CTRL, 9, 0x7, a9_mali_parents,
> +		   NULL);
> +static A9_COMP_DIV(mali_stack_0, MALI_STACK_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(mali_stack_0, MALI_STACK_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(mali_stack_1, MALI_STACK_CLK_CTRL, 25, 0x7, a9_mali_parents,
> +		   NULL);
> +static A9_COMP_DIV(mali_stack_1, MALI_STACK_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(mali_stack_1, MALI_STACK_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_mali_stack = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = MALI_STACK_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("mali_stack",
> +			((const struct clk_hw *[]) {
> +				&a9_mali_stack_0.hw,
> +				&a9_mali_stack_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_dspa_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "gp2", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(dspa_0, DSPA_CLK_CTRL, 9, 0x7, a9_dspa_parents, NULL);
> +static A9_COMP_DIV(dspa_0, DSPA_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dspa_0, DSPA_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(dspa_1, DSPA_CLK_CTRL, 25, 0x7, a9_dspa_parents, NULL);
> +static A9_COMP_DIV(dspa_1, DSPA_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dspa_1, DSPA_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_dspa = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = DSPA_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("dspa",
> +			((const struct clk_hw *[]) {
> +				&a9_dspa_0.hw,
> +				&a9_dspa_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hevcf_parents[] = {
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "gp1", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(hevcf_0, HEVCF_CLK_CTRL, 9, 0x7, a9_hevcf_parents, NULL);
> +static A9_COMP_DIV(hevcf_0, HEVCF_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hevcf_0, HEVCF_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(hevcf_1, HEVCF_CLK_CTRL, 25, 0x7, a9_hevcf_parents, NULL);
> +static A9_COMP_DIV(hevcf_1, HEVCF_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hevcf_1, HEVCF_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_hevcf = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HEVCF_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hevcf",
> +			((const struct clk_hw *[]) {
> +				&a9_hevcf_0.hw,
> +				&a9_hevcf_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hcodec_parents[] = {
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(hcodec_0, HCODEC_CLK_CTRL, 9, 0x7, a9_hcodec_parents, NULL);
> +static A9_COMP_DIV(hcodec_0, HCODEC_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hcodec_0, HCODEC_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(hcodec_1, HCODEC_CLK_CTRL, 25, 0x7, a9_hcodec_parents, NULL);
> +static A9_COMP_DIV(hcodec_1, HCODEC_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hcodec_1, HCODEC_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_hcodec = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HCODEC_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hcodec",
> +			((const struct clk_hw *[]) {
> +				&a9_hcodec_0.hw,
> +				&a9_hcodec_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_vpu_parents[] = {
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "vid1", },
> +	{ .fw_name = "fdiv2", },
> +	{ .hw = &a9_vid_pll.hw },
> +	{ .fw_name = "vid2", },
> +	{ .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(vpu_0, VPU_CLK_CTRL, 9, 0x7, a9_vpu_parents, NULL);
> +static A9_COMP_DIV(vpu_0, VPU_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vpu_0, VPU_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(vpu_1, VPU_CLK_CTRL, 25, 0x7, a9_vpu_parents, NULL);
> +static A9_COMP_DIV(vpu_1, VPU_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vpu_1, VPU_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_vpu = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VPU_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("vpu",
> +			((const struct clk_hw *[]) {
> +				&a9_vpu_0.hw,
> +				&a9_vpu_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_vapb_parents[] = {
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", },
> +	{ .fw_name = "fdiv2", },
> +	{ .hw = &a9_vid_pll.hw },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(vapb_0, VAPB_CLK_CTRL, 9, 0x7, a9_vapb_parents, NULL);
> +static A9_COMP_DIV(vapb_0, VAPB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vapb_0, VAPB_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(vapb_1, VAPB_CLK_CTRL, 25, 0x7, a9_vapb_parents, NULL);
> +static A9_COMP_DIV(vapb_1, VAPB_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vapb_1, VAPB_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_vapb = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VAPB_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("vapb",
> +			((const struct clk_hw *[]) {
> +				&a9_vapb_0.hw,
> +				&a9_vapb_1.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ge2d = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = VAPB_CLK_CTRL,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ge2d", &a9_vapb.hw,
> +				  &clk_regmap_gate_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_vpu_clkb_tmp_parents[] = {
> +	{ .hw = &a9_vpu.hw },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(vpu_clkb_tmp, VPU_CLKB_CTRL, 25, 0x7, a9_vpu_clkb_tmp_parents,
> +		   NULL);
> +static A9_COMP_DIV(vpu_clkb_tmp, VPU_CLKB_CTRL, 16, 4);
> +static A9_COMP_GATE(vpu_clkb_tmp, VPU_CLKB_CTRL, 24, 0);
> +
> +static struct clk_regmap a9_vpu_clkb_div = {
> +	.data = &(struct clk_regmap_div_data) {
> +		.offset = VPU_CLKB_CTRL,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vpu_clkb_div", &a9_vpu_clkb_tmp.hw,
> +				  &clk_regmap_divider_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vpu_clkb = {
> +	.data = &(struct clk_regmap_gate_data) {
> +		.offset = VPU_CLKB_CTRL,
> +		.bit_idx = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vpu_clkb", &a9_vpu_clkb_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hdmi_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(hdmitx_sys, HDMI_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_sys, HDMI_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmitx_sys, HDMI_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmitx_prif, HTX_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_prif, HTX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmitx_prif, HTX_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmitx_200m, HTX_CLK_CTRL, 25, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_200m, HTX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hdmitx_200m, HTX_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(hdmitx_aud, HTX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_aud, HTX_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(hdmitx_aud, HTX_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_5m, HRX_CLK_CTRL, 9, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_5m, HRX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmirx_5m, HRX_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_2m, HRX_CLK_CTRL, 25, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_2m, HRX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hdmirx_2m, HRX_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_cfg, HRX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_cfg, HRX_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(hdmirx_cfg, HRX_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_hdcp2x, HRX_CLK_CTRL1, 25, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_hdcp2x, HRX_CLK_CTRL1, 16, 7);
> +static A9_COMP_GATE(hdmirx_hdcp2x, HRX_CLK_CTRL1, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_acr_ref, HRX_CLK_CTRL2, 25, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_acr_ref, HRX_CLK_CTRL2, 16, 7);
> +static A9_COMP_GATE(hdmirx_acr_ref, HRX_CLK_CTRL2, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_meter, HRX_CLK_CTRL3, 9, 0x7, a9_hdmi_parents,
> +		   NULL);
> +static A9_COMP_DIV(hdmirx_meter, HRX_CLK_CTRL3, 0, 7);
> +static A9_COMP_GATE(hdmirx_meter, HRX_CLK_CTRL3, 8, 0);
> +
> +static struct clk_regmap a9_enc, a9_enc1;

What is this again ?? and please come up with better names.

> +
> +static const struct clk_parent_data a9_vid_lock_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .hw = &a9_enc.hw },
> +	{ .hw = &a9_enc1.hw }
> +};
> +
> +static A9_COMP_SEL(vid_lock, VID_LOCK_CLK_CTRL, 9, 0x7, a9_vid_lock_parents,
> +		   NULL);
> +static A9_COMP_DIV(vid_lock, VID_LOCK_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vid_lock, VID_LOCK_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_vdin_meas_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(vdin_meas, VDIN_MEAS_CLK_CTRL, 9, 0x7, a9_vdin_meas_parents,
> +		   NULL);
> +static A9_COMP_DIV(vdin_meas, VDIN_MEAS_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vdin_meas, VDIN_MEAS_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_vid_pll_div = {
> +	.data = &(struct meson_vid_pll_div_data){
> +		.val = {
> +			.reg_off = VID_PLL_CLK_DIV,
> +			.shift   = 0,
> +			.width   = 15,
> +		},
> +		.sel = {
> +			.reg_off = VID_PLL_CLK_DIV,
> +			.shift   = 16,
> +			.width   = 2,
> +		},
> +	},
> +	.hw.init = CLK_HW_INIT_FW_NAME("vid_pll_div", "hdmiout2",
> +				       &meson_vid_pll_div_ro_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vid_pll_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VID_PLL_CLK_DIV,
> +		.mask = 0x1,
> +		.shift = 18,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("vid_pll_sel",
> +			((const struct clk_parent_data []) {
> +				{ .hw = &a9_vid_pll_div.hw },
> +				{ .fw_name = "hdmiout2" }
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vid_pll = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_PLL_CLK_DIV,
> +		.bit_idx = 19,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vid_pll", &a9_vid_pll_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vid_pll_vclk = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HDMI_CLK_CTRL,
> +		.mask = 0x1,
> +		.shift = 15,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("vid_pll_vclk",
> +			((const struct clk_parent_data []) {
> +				{ .hw = &a9_vid_pll.hw },
> +				{ .fw_name = "hdmipix" }
> +			}), &clk_regmap_mux_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_vclk_parents[] = {
> +	{ .hw = &a9_vid_pll_vclk.hw },
> +	{ .fw_name = "pix0", },
> +	{ .fw_name = "vid1", },
> +	{ .fw_name = "pix1", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "vid2", }
> +};
> +
> +static struct clk_regmap a9_vclk_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VID_CLK_CTRL,
> +		.mask = 0x7,
> +		.shift = 16,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("vclk_sel", a9_vclk_parents,
> +			&clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vclk_in = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_DIV,
> +		.bit_idx = 16,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_in", &a9_vclk_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = VID_CLK_DIV,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div", &a9_vclk_in.hw,
> +				  &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 19,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk", &a9_vclk_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div1_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 0,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div1_en", &a9_vclk.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div2_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 1,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div2_en", &a9_vclk.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};

Looks to me all this div_en / div repeating pattern would be easier to review
with tiny macro .

> +
> +static struct clk_fixed_factor a9_vclk_div2 = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = CLK_HW_INIT_HW("vclk_div2", &a9_vclk_div2_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div4_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 2,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div4_en", &a9_vclk.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div4 = {
> +	.mult = 1,
> +	.div = 4,
> +	.hw.init = CLK_HW_INIT_HW("vclk_div4", &a9_vclk_div4_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div6_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 3,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div6_en", &a9_vclk.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div6 = {
> +	.mult = 1,
> +	.div = 6,
> +	.hw.init = CLK_HW_INIT_HW("vclk_div6", &a9_vclk_div6_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div12_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL,
> +		.bit_idx = 4,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk_div12_en", &a9_vclk.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div12 = {
> +	.mult = 1,
> +	.div = 12,
> +	.hw.init = CLK_HW_INIT_HW("vclk_div12", &a9_vclk_div12_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VIID_CLK_CTRL,
> +		.mask = 0x7,
> +		.shift = 16,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("vclk2_sel", a9_vclk_parents,
> +			&clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vclk2_in = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_DIV,
> +		.bit_idx = 16,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_in", &a9_vclk2_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div = {
> +	.data = &(struct clk_regmap_div_data){
> +		.offset = VIID_CLK_DIV,
> +		.shift = 0,
> +		.width = 8,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div", &a9_vclk2_in.hw,
> +				  &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 19,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2", &a9_vclk2_div.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div1_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 0,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div1_en", &a9_vclk2.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div2_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 1,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div2_en", &a9_vclk2.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div2 = {
> +	.mult = 1,
> +	.div = 2,
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div2", &a9_vclk2_div2_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div4_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 2,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div4_en", &a9_vclk2.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div4 = {
> +	.mult = 1,
> +	.div = 4,
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div4", &a9_vclk2_div4_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div6_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 3,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div6_en", &a9_vclk2.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div6 = {
> +	.mult = 1,
> +	.div = 6,
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div6", &a9_vclk2_div6_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div12_en = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VIID_CLK_CTRL,
> +		.bit_idx = 4,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div12_en", &a9_vclk2.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div12 = {
> +	.mult = 1,
> +	.div = 12,
> +	.hw.init = CLK_HW_INIT_HW("vclk2_div12", &a9_vclk2_div12_en.hw,
> +				  &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/* Channel 5, 6 and 7 are unconnected */
> +static u32 a9_vid_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
> +static const struct clk_hw *a9_vid_parents[] = {
> +	&a9_vclk_div1_en.hw,
> +	&a9_vclk_div2.hw,
> +	&a9_vclk_div4.hw,
> +	&a9_vclk_div6.hw,
> +	&a9_vclk_div12.hw,
> +	&a9_vclk2_div1_en.hw,
> +	&a9_vclk2_div2.hw,
> +	&a9_vclk2_div4.hw,
> +	&a9_vclk2_div6.hw,
> +	&a9_vclk2_div12.hw
> +};
> +
> +static struct clk_regmap a9_vdac_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VIID_CLK_DIV,
> +		.mask = 0xf,
> +		.shift = 28,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("vdac_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vdac = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 4,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("vdac", &a9_vdac_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_enc_sel = {

Should this be enc0 then ? for consistency ?
Same applies to similar instance (it is the same discussion we already
had on the T7 I believe)

> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VIID_CLK_DIV,
> +		.mask = 0xf,
> +		.shift = 12,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("enc_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_enc = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 10,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("enc", &a9_enc_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_enc1_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = VIID_CLK_DIV,
> +		.mask = 0xf,
> +		.shift = 8,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("enc1_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_enc1 = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 11,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("enc1", &a9_enc1_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx_pixel_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HDMI_CLK_CTRL,
> +		.mask = 0xf,
> +		.shift = 16,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx_pixel_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx_pixel = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 5,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("hdmitx_pixel", &a9_hdmitx_pixel_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx_fe_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HDMI_CLK_CTRL,
> +		.mask = 0xf,
> +		.shift = 20,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx_fe_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx_fe = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 9,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("hdmitx_fe", &a9_hdmitx_fe_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_pixel_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HDMI_CLK_CTRL,
> +		.mask = 0xf,
> +		.shift = 24,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx1_pixel_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_pixel = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 12,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("hdmitx1_pixel", &a9_hdmitx1_pixel_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_fe_sel = {
> +	.data = &(struct clk_regmap_mux_data){
> +		.offset = HDMI_CLK_CTRL,
> +		.mask = 0xf,
> +		.shift = 28,
> +		.table = a9_vid_parents_val_table,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx1_fe_sel", a9_vid_parents
> +			, &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_fe = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = VID_CLK_CTRL2,
> +		.bit_idx = 13,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("hdmitx1_fe", &a9_hdmitx1_fe_sel.hw,
> +				  &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_csi_phy_parents[] = {
> +	{ .fw_name = "fdiv2p5", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "hifi0", },
> +	{ .fw_name = "fdiv2", },
> +	{ .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7,
> +		   a9_csi_phy_parents, NULL);
> +static A9_COMP_DIV(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_dsi_meas_parents[] = {
> +	{ .fw_name = "xtal", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", },
> +	{ .fw_name = "fdiv5", },
> +	{ .hw = &a9_vid_pll.hw },
> +	{ .fw_name = "gp0", },
> +	{ .fw_name = "vid1", },
> +	{ .fw_name = "vid2", }
> +};
> +
> +static A9_COMP_SEL(dsi_meas, DSI_MEAS_CLK_CTRL, 9, 0x7,
> +		   a9_dsi_meas_parents, NULL);
> +static A9_COMP_DIV(dsi_meas, DSI_MEAS_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dsi_meas, DSI_MEAS_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(dsi_b_meas, DSI_MEAS_CLK_CTRL, 25, 0x7,
> +		   a9_dsi_meas_parents, NULL);
> +static A9_COMP_DIV(dsi_b_meas, DSI_MEAS_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dsi_b_meas, DSI_MEAS_CLK_CTRL, 24, 0);
> +
> +static struct clk_hw *a9_peripherals_hw_clks[] = {
> +	[CLKID_SYS_AM_AXI]		= &a9_sys_am_axi.hw,
> +	[CLKID_SYS_DOS]			= &a9_sys_dos.hw,
> +	[CLKID_SYS_MIPI_DSI]		= &a9_sys_mipi_dsi.hw,
> +	[CLKID_SYS_ETH_PHY]		= &a9_sys_eth_phy.hw,
> +	[CLKID_SYS_AMFC]		= &a9_sys_amfc.hw,
> +	[CLKID_SYS_MALI]		= &a9_sys_mali.hw,
> +	[CLKID_SYS_NNA]			= &a9_sys_nna.hw,
> +	[CLKID_SYS_ETH_AXI]		= &a9_sys_eth_axi.hw,
> +	[CLKID_SYS_DP_APB]		= &a9_sys_dp_apb.hw,
> +	[CLKID_SYS_EDPTX_APB]		= &a9_sys_edptx_apb.hw,
> +	[CLKID_SYS_U3HSG]		= &a9_sys_u3hsg.hw,
> +	[CLKID_SYS_AUCPU]		= &a9_sys_aucpu.hw,
> +	[CLKID_SYS_GLB]			= &a9_sys_glb.hw,
> +	[CLKID_SYS_COMBO_DPHY_APB]	= &a9_sys_combo_dphy_apb.hw,
> +	[CLKID_SYS_HDMIRX_APB]		= &a9_sys_hdmirx_apb.hw,
> +	[CLKID_SYS_HDMIRX_PCLK]		= &a9_sys_hdmirx_pclk.hw,
> +	[CLKID_SYS_MIPI_DSI_PHY]	= &a9_sys_mipi_dsi_phy.hw,
> +	[CLKID_SYS_CAN0]		= &a9_sys_can0.hw,
> +	[CLKID_SYS_CAN1]		= &a9_sys_can1.hw,
> +	[CLKID_SYS_SD_EMMC_A]		= &a9_sys_sd_emmc_a.hw,
> +	[CLKID_SYS_SD_EMMC_B]		= &a9_sys_sd_emmc_b.hw,
> +	[CLKID_SYS_SD_EMMC_C]		= &a9_sys_sd_emmc_c.hw,
> +	[CLKID_SYS_SC]			= &a9_sys_sc.hw,
> +	[CLKID_SYS_ACODEC]		= &a9_sys_acodec.hw,
> +	[CLKID_SYS_MIPI_ISP]		= &a9_sys_mipi_isp.hw,
> +	[CLKID_SYS_MSR]			= &a9_sys_msr.hw,
> +	[CLKID_SYS_AUDIO]		= &a9_sys_audio.hw,
> +	[CLKID_SYS_MIPI_DSI_B]		= &a9_sys_mipi_dsi_b.hw,
> +	[CLKID_SYS_MIPI_DSI1_PHY]	= &a9_sys_mipi_dsi1_phy.hw,
> +	[CLKID_SYS_ETH]			= &a9_sys_eth.hw,
> +	[CLKID_SYS_ETH_1G_MAC]		= &a9_sys_eth_1g_mac.hw,
> +	[CLKID_SYS_UART_A]		= &a9_sys_uart_a.hw,
> +	[CLKID_SYS_UART_F]		= &a9_sys_uart_f.hw,
> +	[CLKID_SYS_TS_A55]		= &a9_sys_ts_a55.hw,
> +	[CLKID_SYS_ETH_1G_AXI]		= &a9_sys_eth_1g_axi.hw,
> +	[CLKID_SYS_TS_DOS]		= &a9_sys_ts_dos.hw,
> +	[CLKID_SYS_U3DRD_B]		= &a9_sys_u3drd_b.hw,
> +	[CLKID_SYS_TS_CORE]		= &a9_sys_ts_core.hw,
> +	[CLKID_SYS_TS_PLL]		= &a9_sys_ts_pll.hw,
> +	[CLKID_SYS_CSI_DIG_CLKIN]	= &a9_sys_csi_dig_clkin.hw,
> +	[CLKID_SYS_CVE]			= &a9_sys_cve.hw,
> +	[CLKID_SYS_GE2D]		= &a9_sys_ge2d.hw,
> +	[CLKID_SYS_SPISG]		= &a9_sys_spisg.hw,
> +	[CLKID_SYS_U3DRD_1]		= &a9_sys_u3drd_1.hw,
> +	[CLKID_SYS_U2H]			= &a9_sys_u2h.hw,
> +	[CLKID_SYS_PCIE_MAC_A]		= &a9_sys_pcie_mac_a.hw,
> +	[CLKID_SYS_U3DRD_A]		= &a9_sys_u3drd_a.hw,
> +	[CLKID_SYS_U2DRD]		= &a9_sys_u2drd.hw,
> +	[CLKID_SYS_PCIE_PHY]		= &a9_sys_pcie_phy.hw,
> +	[CLKID_SYS_PCIE_MAC_B]		= &a9_sys_pcie_mac_b.hw,
> +	[CLKID_SYS_PERIPH]		= &a9_sys_periph.hw,
> +	[CLKID_SYS_PIO]			= &a9_sys_pio.hw,
> +	[CLKID_SYS_I3C]			= &a9_sys_i3c.hw,
> +	[CLKID_SYS_I2C_M_E]		= &a9_sys_i2c_m_e.hw,
> +	[CLKID_SYS_I2C_M_F]		= &a9_sys_i2c_m_f.hw,
> +	[CLKID_SYS_HDMITX_APB]		= &a9_sys_hdmitx_apb.hw,
> +	[CLKID_SYS_I2C_M_I]		= &a9_sys_i2c_m_i.hw,
> +	[CLKID_SYS_I2C_M_G]		= &a9_sys_i2c_m_g.hw,
> +	[CLKID_SYS_I2C_M_H]		= &a9_sys_i2c_m_h.hw,
> +	[CLKID_SYS_HDMI20_AES]		= &a9_sys_hdmi20_aes.hw,
> +	[CLKID_SYS_CSI2_HOST]		= &a9_sys_csi2_host.hw,
> +	[CLKID_SYS_CSI2_ADAPT]		= &a9_sys_csi2_adapt.hw,
> +	[CLKID_SYS_DSPA]		= &a9_sys_dspa.hw,
> +	[CLKID_SYS_PP_DMA]		= &a9_sys_pp_dma.hw,
> +	[CLKID_SYS_PP_WRAPPER]		= &a9_sys_pp_wrapper.hw,
> +	[CLKID_SYS_VPU_INTR]		= &a9_sys_vpu_intr.hw,
> +	[CLKID_SYS_CSI2_PHY]		= &a9_sys_csi2_phy.hw,
> +	[CLKID_SYS_SARADC]		= &a9_sys_saradc.hw,
> +	[CLKID_SYS_PWM_J]		= &a9_sys_pwm_j.hw,
> +	[CLKID_SYS_PWM_I]		= &a9_sys_pwm_i.hw,
> +	[CLKID_SYS_PWM_H]		= &a9_sys_pwm_h.hw,
> +	[CLKID_SYS_PWM_N]		= &a9_sys_pwm_n.hw,
> +	[CLKID_SYS_PWM_M]		= &a9_sys_pwm_m.hw,
> +	[CLKID_SYS_PWM_L]		= &a9_sys_pwm_l.hw,
> +	[CLKID_SYS_PWM_K]		= &a9_sys_pwm_k.hw,
> +	[CLKID_SD_EMMC_A_SEL]		= &a9_sd_emmc_a_sel.hw,
> +	[CLKID_SD_EMMC_A_DIV]		= &a9_sd_emmc_a_div.hw,
> +	[CLKID_SD_EMMC_A]		= &a9_sd_emmc_a.hw,
> +	[CLKID_SD_EMMC_B_SEL]		= &a9_sd_emmc_b_sel.hw,
> +	[CLKID_SD_EMMC_B_DIV]		= &a9_sd_emmc_b_div.hw,
> +	[CLKID_SD_EMMC_B]		= &a9_sd_emmc_b.hw,
> +	[CLKID_SD_EMMC_C_SEL]		= &a9_sd_emmc_c_sel.hw,
> +	[CLKID_SD_EMMC_C_DIV]		= &a9_sd_emmc_c_div.hw,
> +	[CLKID_SD_EMMC_C]		= &a9_sd_emmc_c.hw,
> +	[CLKID_PWM_H_SEL]		= &a9_pwm_h_sel.hw,
> +	[CLKID_PWM_H_DIV]		= &a9_pwm_h_div.hw,
> +	[CLKID_PWM_H]			= &a9_pwm_h.hw,
> +	[CLKID_PWM_I_SEL]		= &a9_pwm_i_sel.hw,
> +	[CLKID_PWM_I_DIV]		= &a9_pwm_i_div.hw,
> +	[CLKID_PWM_I]			= &a9_pwm_i.hw,
> +	[CLKID_PWM_J_SEL]		= &a9_pwm_j_sel.hw,
> +	[CLKID_PWM_J_DIV]		= &a9_pwm_j_div.hw,
> +	[CLKID_PWM_J]			= &a9_pwm_j.hw,
> +	[CLKID_PWM_K_SEL]		= &a9_pwm_k_sel.hw,
> +	[CLKID_PWM_K_DIV]		= &a9_pwm_k_div.hw,
> +	[CLKID_PWM_K]			= &a9_pwm_k.hw,
> +	[CLKID_PWM_L_SEL]		= &a9_pwm_l_sel.hw,
> +	[CLKID_PWM_L_DIV]		= &a9_pwm_l_div.hw,
> +	[CLKID_PWM_L]			= &a9_pwm_l.hw,
> +	[CLKID_PWM_M_SEL]		= &a9_pwm_m_sel.hw,
> +	[CLKID_PWM_M_DIV]		= &a9_pwm_m_div.hw,
> +	[CLKID_PWM_M]			= &a9_pwm_m.hw,
> +	[CLKID_PWM_N_SEL]		= &a9_pwm_n_sel.hw,
> +	[CLKID_PWM_N_DIV]		= &a9_pwm_n_div.hw,
> +	[CLKID_PWM_N]			= &a9_pwm_n.hw,
> +	[CLKID_SPISG_SEL]		= &a9_spisg_sel.hw,
> +	[CLKID_SPISG_DIV]		= &a9_spisg_div.hw,
> +	[CLKID_SPISG]			= &a9_spisg.hw,
> +	[CLKID_SPISG1_SEL]		= &a9_spisg1_sel.hw,
> +	[CLKID_SPISG1_DIV]		= &a9_spisg1_div.hw,
> +	[CLKID_SPISG1]			= &a9_spisg1.hw,
> +	[CLKID_SPISG2_SEL]		= &a9_spisg2_sel.hw,
> +	[CLKID_SPISG2_DIV]		= &a9_spisg2_div.hw,
> +	[CLKID_SPISG2]			= &a9_spisg2.hw,
> +	[CLKID_SARADC_SEL]		= &a9_saradc_sel.hw,
> +	[CLKID_SARADC_DIV]		= &a9_saradc_div.hw,
> +	[CLKID_SARADC]			= &a9_saradc.hw,
> +	[CLKID_AMFC_SEL]		= &a9_amfc_sel.hw,
> +	[CLKID_AMFC_DIV]		= &a9_amfc_div.hw,
> +	[CLKID_AMFC]			= &a9_amfc.hw,
> +	[CLKID_NNA_SEL]			= &a9_nna_sel.hw,
> +	[CLKID_NNA_DIV]			= &a9_nna_div.hw,
> +	[CLKID_NNA]			= &a9_nna.hw,
> +	[CLKID_USB_250M_SEL]		= &a9_usb_250m_sel.hw,
> +	[CLKID_USB_250M_DIV]		= &a9_usb_250m_div.hw,
> +	[CLKID_USB_250M]		= &a9_usb_250m.hw,
> +	[CLKID_USB_48M_PRE_SEL]		= &a9_usb_48m_pre_sel.hw,
> +	[CLKID_USB_48M_PRE_DIV]		= &a9_usb_48m_pre_div.hw,
> +	[CLKID_USB_48M_PRE]		= &a9_usb_48m_pre.hw,
> +	[CLKID_PCIE_TL_SEL]		= &a9_pcie_tl_sel.hw,
> +	[CLKID_PCIE_TL_DIV]		= &a9_pcie_tl_div.hw,
> +	[CLKID_PCIE_TL]			= &a9_pcie_tl.hw,
> +	[CLKID_PCIE1_TL_SEL]		= &a9_pcie1_tl_sel.hw,
> +	[CLKID_PCIE1_TL_DIV]		= &a9_pcie1_tl_div.hw,
> +	[CLKID_PCIE1_TL]		= &a9_pcie1_tl.hw,
> +	[CLKID_CMPR_SEL]		= &a9_cmpr_sel.hw,
> +	[CLKID_CMPR_DIV]		= &a9_cmpr_div.hw,
> +	[CLKID_CMPR]			= &a9_cmpr.hw,
> +	[CLKID_DEWARPA_SEL]		= &a9_dewarpa_sel.hw,
> +	[CLKID_DEWARPA_DIV]		= &a9_dewarpa_div.hw,
> +	[CLKID_DEWARPA]			= &a9_dewarpa.hw,
> +	[CLKID_SC_PRE_SEL]		= &a9_sc_pre_sel.hw,
> +	[CLKID_SC_PRE_DIV]		= &a9_sc_pre_div.hw,
> +	[CLKID_SC_PRE]			= &a9_sc_pre.hw,
> +	[CLKID_SC]			= &a9_sc.hw,
> +	[CLKID_DPTX_APB2_SEL]		= &a9_dptx_apb2_sel.hw,
> +	[CLKID_DPTX_APB2_DIV]		= &a9_dptx_apb2_div.hw,
> +	[CLKID_DPTX_APB2]		= &a9_dptx_apb2.hw,
> +	[CLKID_DPTX_AUD_SEL]		= &a9_dptx_aud_sel.hw,
> +	[CLKID_DPTX_AUD_DIV]		= &a9_dptx_aud_div.hw,
> +	[CLKID_DPTX_AUD]		= &a9_dptx_aud.hw,
> +	[CLKID_ISP_SEL]			= &a9_isp_sel.hw,
> +	[CLKID_ISP_DIV]			= &a9_isp_div.hw,
> +	[CLKID_ISP]			= &a9_isp.hw,
> +	[CLKID_CVE_SEL]			= &a9_cve_sel.hw,
> +	[CLKID_CVE_DIV]			= &a9_cve_div.hw,
> +	[CLKID_CVE]			= &a9_cve.hw,
> +	[CLKID_VGE_SEL]			= &a9_vge_sel.hw,
> +	[CLKID_VGE_DIV]			= &a9_vge_div.hw,
> +	[CLKID_VGE]			= &a9_vge.hw,
> +	[CLKID_PP_SEL]			= &a9_pp_sel.hw,
> +	[CLKID_PP_DIV]			= &a9_pp_div.hw,
> +	[CLKID_PP]			= &a9_pp.hw,
> +	[CLKID_GLB_SEL]			= &a9_glb_sel.hw,
> +	[CLKID_GLB_DIV]			= &a9_glb_div.hw,
> +	[CLKID_GLB]			= &a9_glb.hw,
> +	[CLKID_USB_48M_DUALDIV_IN]	= &a9_usb_48m_dualdiv_in.hw,
> +	[CLKID_USB_48M_DUALDIV_DIV]	= &a9_usb_48m_dualdiv_div.hw,
> +	[CLKID_USB_48M_DUALDIV_SEL]	= &a9_usb_48m_dualdiv_sel.hw,
> +	[CLKID_USB_48M_DUALDIV]		= &a9_usb_48m_dualdiv.hw,
> +	[CLKID_USB_48M]			= &a9_usb_48m.hw,
> +	[CLKID_CAN_PE_SEL]		= &a9_can_pe_sel.hw,
> +	[CLKID_CAN_PE_DIV]		= &a9_can_pe_div.hw,
> +	[CLKID_CAN_PE]			= &a9_can_pe.hw,
> +	[CLKID_CAN1_PE_SEL]		= &a9_can1_pe_sel.hw,
> +	[CLKID_CAN1_PE_DIV]		= &a9_can1_pe_div.hw,
> +	[CLKID_CAN1_PE]			= &a9_can1_pe.hw,
> +	[CLKID_CAN_FILTER_SEL]		= &a9_can_filter_sel.hw,
> +	[CLKID_CAN_FILTER_DIV]		= &a9_can_filter_div.hw,
> +	[CLKID_CAN_FILTER]		= &a9_can_filter.hw,
> +	[CLKID_CAN1_FILTER_SEL]		= &a9_can1_filter_sel.hw,
> +	[CLKID_CAN1_FILTER_DIV]		= &a9_can1_filter_div.hw,
> +	[CLKID_CAN1_FILTER]		= &a9_can1_filter.hw,
> +	[CLKID_I3C_SEL]			= &a9_i3c_sel.hw,
> +	[CLKID_I3C_DIV]			= &a9_i3c_div.hw,
> +	[CLKID_I3C]			= &a9_i3c.hw,
> +	[CLKID_TS_DIV]			= &a9_ts_div.hw,
> +	[CLKID_TS]			= &a9_ts.hw,
> +	[CLKID_ETH_125M_DIV]		= &a9_eth_125m_div.hw,
> +	[CLKID_ETH_125M]		= &a9_eth_125m.hw,
> +	[CLKID_ETH_RMII_SEL]		= &a9_eth_rmii_sel.hw,
> +	[CLKID_ETH_RMII_DIV]		= &a9_eth_rmii_div.hw,
> +	[CLKID_ETH_RMII]		= &a9_eth_rmii.hw,
> +	[CLKID_GEN_SEL]			= &a9_gen_sel.hw,
> +	[CLKID_GEN_DIV]			= &a9_gen_div.hw,
> +	[CLKID_GEN]			= &a9_gen.hw,
> +	[CLKID_CLK24M_IN]		= &a9_24m_in.hw,
> +	[CLKID_CLK12_24M]		= &a9_12_24m.hw,
> +	[CLKID_MALI_0_SEL]		= &a9_mali_0_sel.hw,
> +	[CLKID_MALI_0_DIV]		= &a9_mali_0_div.hw,
> +	[CLKID_MALI_0]			= &a9_mali_0.hw,
> +	[CLKID_MALI_1_SEL]		= &a9_mali_1_sel.hw,
> +	[CLKID_MALI_1_DIV]		= &a9_mali_1_div.hw,
> +	[CLKID_MALI_1]			= &a9_mali_1.hw,
> +	[CLKID_MALI]			= &a9_mali.hw,
> +	[CLKID_MALI_STACK_0_SEL]	= &a9_mali_stack_0_sel.hw,
> +	[CLKID_MALI_STACK_0_DIV]	= &a9_mali_stack_0_div.hw,
> +	[CLKID_MALI_STACK_0]		= &a9_mali_stack_0.hw,
> +	[CLKID_MALI_STACK_1_SEL]	= &a9_mali_stack_1_sel.hw,
> +	[CLKID_MALI_STACK_1_DIV]	= &a9_mali_stack_1_div.hw,
> +	[CLKID_MALI_STACK_1]		= &a9_mali_stack_1.hw,
> +	[CLKID_MALI_STACK]		= &a9_mali_stack.hw,
> +	[CLKID_DSPA_0_SEL]		= &a9_dspa_0_sel.hw,
> +	[CLKID_DSPA_0_DIV]		= &a9_dspa_0_div.hw,
> +	[CLKID_DSPA_0]			= &a9_dspa_0.hw,
> +	[CLKID_DSPA_1_SEL]		= &a9_dspa_1_sel.hw,
> +	[CLKID_DSPA_1_DIV]		= &a9_dspa_1_div.hw,
> +	[CLKID_DSPA_1]			= &a9_dspa_1.hw,
> +	[CLKID_DSPA]			= &a9_dspa.hw,
> +	[CLKID_HEVCF_0_SEL]		= &a9_hevcf_0_sel.hw,
> +	[CLKID_HEVCF_0_DIV]		= &a9_hevcf_0_div.hw,
> +	[CLKID_HEVCF_0]			= &a9_hevcf_0.hw,
> +	[CLKID_HEVCF_1_SEL]		= &a9_hevcf_1_sel.hw,
> +	[CLKID_HEVCF_1_DIV]		= &a9_hevcf_1_div.hw,
> +	[CLKID_HEVCF_1]			= &a9_hevcf_1.hw,
> +	[CLKID_HEVCF]			= &a9_hevcf.hw,
> +	[CLKID_HCODEC_0_SEL]		= &a9_hcodec_0_sel.hw,
> +	[CLKID_HCODEC_0_DIV]		= &a9_hcodec_0_div.hw,
> +	[CLKID_HCODEC_0]		= &a9_hcodec_0.hw,
> +	[CLKID_HCODEC_1_SEL]		= &a9_hcodec_1_sel.hw,
> +	[CLKID_HCODEC_1_DIV]		= &a9_hcodec_1_div.hw,
> +	[CLKID_HCODEC_1]		= &a9_hcodec_1.hw,
> +	[CLKID_HCODEC]			= &a9_hcodec.hw,
> +	[CLKID_VPU_0_SEL]		= &a9_vpu_0_sel.hw,
> +	[CLKID_VPU_0_DIV]		= &a9_vpu_0_div.hw,
> +	[CLKID_VPU_0]			= &a9_vpu_0.hw,
> +	[CLKID_VPU_1_SEL]		= &a9_vpu_1_sel.hw,
> +	[CLKID_VPU_1_DIV]		= &a9_vpu_1_div.hw,
> +	[CLKID_VPU_1]			= &a9_vpu_1.hw,
> +	[CLKID_VPU]			= &a9_vpu.hw,
> +	[CLKID_VAPB_0_SEL]		= &a9_vapb_0_sel.hw,
> +	[CLKID_VAPB_0_DIV]		= &a9_vapb_0_div.hw,
> +	[CLKID_VAPB_0]			= &a9_vapb_0.hw,
> +	[CLKID_VAPB_1_SEL]		= &a9_vapb_1_sel.hw,
> +	[CLKID_VAPB_1_DIV]		= &a9_vapb_1_div.hw,
> +	[CLKID_VAPB_1]			= &a9_vapb_1.hw,
> +	[CLKID_VAPB]			= &a9_vapb.hw,
> +	[CLKID_GE2D]			= &a9_ge2d.hw,
> +	[CLKID_VPU_CLKB_TMP_SEL]	= &a9_vpu_clkb_tmp_sel.hw,
> +	[CLKID_VPU_CLKB_TMP_DIV]	= &a9_vpu_clkb_tmp_div.hw,
> +	[CLKID_VPU_CLKB_TMP]		= &a9_vpu_clkb_tmp.hw,
> +	[CLKID_VPU_CLKB_DIV]		= &a9_vpu_clkb_div.hw,
> +	[CLKID_VPU_CLKB]		= &a9_vpu_clkb.hw,
> +	[CLKID_HDMITX_SYS_SEL]		= &a9_hdmitx_sys_sel.hw,
> +	[CLKID_HDMITX_SYS_DIV]		= &a9_hdmitx_sys_div.hw,
> +	[CLKID_HDMITX_SYS]		= &a9_hdmitx_sys.hw,
> +	[CLKID_HDMITX_PRIF_SEL]		= &a9_hdmitx_prif_sel.hw,
> +	[CLKID_HDMITX_PRIF_DIV]		= &a9_hdmitx_prif_div.hw,
> +	[CLKID_HDMITX_PRIF]		= &a9_hdmitx_prif.hw,
> +	[CLKID_HDMITX_200M_SEL]		= &a9_hdmitx_200m_sel.hw,
> +	[CLKID_HDMITX_200M_DIV]		= &a9_hdmitx_200m_div.hw,
> +	[CLKID_HDMITX_200M]		= &a9_hdmitx_200m.hw,
> +	[CLKID_HDMITX_AUD_SEL]		= &a9_hdmitx_aud_sel.hw,
> +	[CLKID_HDMITX_AUD_DIV]		= &a9_hdmitx_aud_div.hw,
> +	[CLKID_HDMITX_AUD]		= &a9_hdmitx_aud.hw,
> +	[CLKID_HDMIRX_5M_SEL]		= &a9_hdmirx_5m_sel.hw,
> +	[CLKID_HDMIRX_5M_DIV]		= &a9_hdmirx_5m_div.hw,
> +	[CLKID_HDMIRX_5M]		= &a9_hdmirx_5m.hw,
> +	[CLKID_HDMIRX_2M_SEL]		= &a9_hdmirx_2m_sel.hw,
> +	[CLKID_HDMIRX_2M_DIV]		= &a9_hdmirx_2m_div.hw,
> +	[CLKID_HDMIRX_2M]		= &a9_hdmirx_2m.hw,
> +	[CLKID_HDMIRX_CFG_SEL]		= &a9_hdmirx_cfg_sel.hw,
> +	[CLKID_HDMIRX_CFG_DIV]		= &a9_hdmirx_cfg_div.hw,
> +	[CLKID_HDMIRX_CFG]		= &a9_hdmirx_cfg.hw,
> +	[CLKID_HDMIRX_HDCP2X_SEL]	= &a9_hdmirx_hdcp2x_sel.hw,
> +	[CLKID_HDMIRX_HDCP2X_DIV]	= &a9_hdmirx_hdcp2x_div.hw,
> +	[CLKID_HDMIRX_HDCP2X]		= &a9_hdmirx_hdcp2x.hw,
> +	[CLKID_HDMIRX_ACR_REF_SEL]	= &a9_hdmirx_acr_ref_sel.hw,
> +	[CLKID_HDMIRX_ACR_REF_DIV]	= &a9_hdmirx_acr_ref_div.hw,
> +	[CLKID_HDMIRX_ACR_REF]		= &a9_hdmirx_acr_ref.hw,
> +	[CLKID_HDMIRX_METER_SEL]	= &a9_hdmirx_meter_sel.hw,
> +	[CLKID_HDMIRX_METER_DIV]	= &a9_hdmirx_meter_div.hw,
> +	[CLKID_HDMIRX_METER]		= &a9_hdmirx_meter.hw,
> +	[CLKID_VID_LOCK_SEL]		= &a9_vid_lock_sel.hw,
> +	[CLKID_VID_LOCK_DIV]		= &a9_vid_lock_div.hw,
> +	[CLKID_VID_LOCK]		= &a9_vid_lock.hw,
> +	[CLKID_VDIN_MEAS_SEL]		= &a9_vdin_meas_sel.hw,
> +	[CLKID_VDIN_MEAS_DIV]		= &a9_vdin_meas_div.hw,
> +	[CLKID_VDIN_MEAS]		= &a9_vdin_meas.hw,
> +	[CLKID_VID_PLL_DIV]		= &a9_vid_pll_div.hw,
> +	[CLKID_VID_PLL_SEL]		= &a9_vid_pll_sel.hw,
> +	[CLKID_VID_PLL]			= &a9_vid_pll.hw,
> +	[CLKID_VID_PLL_VCLK]		= &a9_vid_pll_vclk.hw,
> +	[CLKID_VCLK_SEL]		= &a9_vclk_sel.hw,
> +	[CLKID_VCLK_IN]			= &a9_vclk_in.hw,
> +	[CLKID_VCLK_DIV]		= &a9_vclk_div.hw,
> +	[CLKID_VCLK]			= &a9_vclk.hw,
> +	[CLKID_VCLK_DIV1_EN]		= &a9_vclk_div1_en.hw,
> +	[CLKID_VCLK_DIV2_EN]		= &a9_vclk_div2_en.hw,
> +	[CLKID_VCLK_DIV2]		= &a9_vclk_div2.hw,
> +	[CLKID_VCLK_DIV4_EN]		= &a9_vclk_div4_en.hw,
> +	[CLKID_VCLK_DIV4]		= &a9_vclk_div4.hw,
> +	[CLKID_VCLK_DIV6_EN]		= &a9_vclk_div6_en.hw,
> +	[CLKID_VCLK_DIV6]		= &a9_vclk_div6.hw,
> +	[CLKID_VCLK_DIV12_EN]		= &a9_vclk_div12_en.hw,
> +	[CLKID_VCLK_DIV12]		= &a9_vclk_div12.hw,
> +	[CLKID_VCLK2_SEL]		= &a9_vclk2_sel.hw,
> +	[CLKID_VCLK2_IN]		= &a9_vclk2_in.hw,
> +	[CLKID_VCLK2_DIV]		= &a9_vclk2_div.hw,
> +	[CLKID_VCLK2]			= &a9_vclk2.hw,
> +	[CLKID_VCLK2_DIV1_EN]		= &a9_vclk2_div1_en.hw,
> +	[CLKID_VCLK2_DIV2_EN]		= &a9_vclk2_div2_en.hw,
> +	[CLKID_VCLK2_DIV2]		= &a9_vclk2_div2.hw,
> +	[CLKID_VCLK2_DIV4_EN]		= &a9_vclk2_div4_en.hw,
> +	[CLKID_VCLK2_DIV4]		= &a9_vclk2_div4.hw,
> +	[CLKID_VCLK2_DIV6_EN]		= &a9_vclk2_div6_en.hw,
> +	[CLKID_VCLK2_DIV6]		= &a9_vclk2_div6.hw,
> +	[CLKID_VCLK2_DIV12_EN]		= &a9_vclk2_div12_en.hw,
> +	[CLKID_VCLK2_DIV12]		= &a9_vclk2_div12.hw,
> +	[CLKID_VDAC_SEL]		= &a9_vdac_sel.hw,
> +	[CLKID_VDAC]			= &a9_vdac.hw,
> +	[CLKID_ENC_SEL]			= &a9_enc_sel.hw,
> +	[CLKID_ENC]			= &a9_enc.hw,
> +	[CLKID_ENC1_SEL]		= &a9_enc1_sel.hw,
> +	[CLKID_ENC1]			= &a9_enc1.hw,
> +	[CLKID_HDMITX_PIXEL_SEL]	= &a9_hdmitx_pixel_sel.hw,
> +	[CLKID_HDMITX_PIXEL]		= &a9_hdmitx_pixel.hw,
> +	[CLKID_HDMITX_FE_SEL]		= &a9_hdmitx_fe_sel.hw,
> +	[CLKID_HDMITX_FE]		= &a9_hdmitx_fe.hw,
> +	[CLKID_HDMITX1_PIXEL_SEL]	= &a9_hdmitx1_pixel_sel.hw,
> +	[CLKID_HDMITX1_PIXEL]		= &a9_hdmitx1_pixel.hw,
> +	[CLKID_HDMITX1_FE_SEL]		= &a9_hdmitx1_fe_sel.hw,
> +	[CLKID_HDMITX1_FE]		= &a9_hdmitx1_fe.hw,
> +	[CLKID_CSI_PHY_SEL]		= &a9_csi_phy_sel.hw,
> +	[CLKID_CSI_PHY_DIV]		= &a9_csi_phy_div.hw,
> +	[CLKID_CSI_PHY]			= &a9_csi_phy.hw,
> +	[CLKID_DSI_MEAS_SEL]		= &a9_dsi_meas_sel.hw,
> +	[CLKID_DSI_MEAS_DIV]		= &a9_dsi_meas_div.hw,
> +	[CLKID_DSI_MEAS]		= &a9_dsi_meas.hw,
> +	[CLKID_DSI_B_MEAS_SEL]		= &a9_dsi_b_meas_sel.hw,
> +	[CLKID_DSI_B_MEAS_DIV]		= &a9_dsi_b_meas_div.hw,
> +	[CLKID_DSI_B_MEAS]		= &a9_dsi_b_meas.hw,
> +};
> +
> +static const struct meson_clkc_data a9_peripherals_clkc_data = {
> +	.hw_clks = {
> +		.hws = a9_peripherals_hw_clks,
> +		.num = ARRAY_SIZE(a9_peripherals_hw_clks),
> +	},
> +};
> +
> +static const struct of_device_id a9_peripherals_clkc_match_table[] = {
> +	{
> +		.compatible = "amlogic,a9-peripherals-clkc",
> +		.data = &a9_peripherals_clkc_data,
> +	},
> +	{ /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, a9_peripherals_clkc_match_table);
> +
> +static struct platform_driver a9_peripherals_clkc_driver = {
> +	.probe		= meson_clkc_mmio_probe,
> +	.driver		= {
> +		.name	= "a9-peripherals-clkc",
> +		.of_match_table = a9_peripherals_clkc_match_table,
> +	},
> +};
> +module_platform_driver(a9_peripherals_clkc_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A9 Peripherals Clock Controller driver");
> +MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("CLK_MESON");

-- 
Jerome


^ permalink raw reply

* Re: [PATCH v4 2/2] cpu/hotplug: Fix NULL kobject warning in cpuhp_smt_enable()
From: Catalin Marinas @ 2026-06-10 12:43 UTC (permalink / raw)
  To: Jinjie Ruan
  Cc: will, corbet, skhan, punit.agrawal, mrigendra.chaubey,
	suzuki.poulose, chenl311, fengchengwen, maz, timothy.hayes,
	lpieralisi, arnd, gshan, jic23, dietmar.eggemann, sudeep.holla,
	pierre.gondois, linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20260610075202.3597031-3-ruanjinjie@huawei.com>

On Wed, Jun 10, 2026 at 03:52:02PM +0800, Jinjie Ruan wrote:
> diff --git a/Documentation/arch/arm64/cpu-hotplug.rst b/Documentation/arch/arm64/cpu-hotplug.rst
> index 8fb438bf7781..7c3379b704aa 100644
> --- a/Documentation/arch/arm64/cpu-hotplug.rst
> +++ b/Documentation/arch/arm64/cpu-hotplug.rst
> @@ -47,11 +47,12 @@ ever have can be described at boot. There are no power-domain considerations
>  as such devices are emulated.
>  
>  CPU Hotplug on virtual systems is supported. It is distinct from physical
> -CPU Hotplug as all resources are described as ``present``, but CPUs may be
> -marked as disabled by firmware. Only the CPU's online/offline behaviour is
> -influenced by firmware. An example is where a virtual machine boots with a
> -single CPU, and additional CPUs are added once a cloud orchestrator deploys
> -the workload.
> +CPU Hotplug as all vCPU resources are statically described in the firmware
> +configuration tables (e.g. MADT), meaning their maximum possible count is
> +known at boot. However, vCPUs that are not enabled at boot are not marked
> +as ``present`` by the kernel until they are hotplugged. An example is where
> +a virtual machine boots with a single CPU, and additional CPUs are added
> +once a cloud orchestrator deploys the workload.
>  
>  For a virtual machine, the VMM (e.g. Qemu) plays the part of firmware.
>  
> @@ -60,16 +61,19 @@ brought online. Firmware can enforce its policy via PSCI's return codes. e.g.
>  ``DENIED``.
>  
>  The ACPI tables must describe all the resources of the virtual machine. CPUs
> -that firmware wishes to disable either from boot (or later) should not be
> -``enabled`` in the MADT GICC structures, but should have the ``online capable``
> -bit set, to indicate they can be enabled later. The boot CPU must be marked as
> -``enabled``.  The 'always on' GICR structure must be used to describe the
> -redistributors.
> +that are hot-pluggable must have the ``online capable`` bit set and the
> +``enabled`` bit cleared in the MADT GICC structures to indicate they can be
> +enabled later. The boot CPU must be marked as ``enabled`` with its
> +``online capable`` bit cleared. The 'always on' GICR structure must be used
> +to describe the redistributors.
>  
>  CPUs described as ``online capable`` but not ``enabled`` can be set to enabled
>  by the DSDT's Processor object's _STA method. On virtual systems the _STA method
> -must always report the CPU as ``present``. Changes to the firmware policy can
> -be notified to the OS via device-check or eject-request.
> +must always set the ``ACPI_STA_DEVICE_PRESENT`` bit, while toggling the
> +``ACPI_STA_DEVICE_ENABLED`` bit to reflect its plug status. The kernel will
> +then dynamically mark the vCPU as ``present`` within the OS when the
> +``ACPI_STA_DEVICE_ENABLED`` bit becomes set during hot-add. Changes to the
> +firmware policy can be notified to the OS via device-check or eject-request.

The doc update looks fine as well, thanks for clarifying. My reviewed-by
stands.

-- 
Catalin


^ permalink raw reply

* Re: [PATCH] bus: vexpress-config: fix device_node refcount leak in vexpress_syscfg_probe()
From: Liviu Dudau @ 2026-06-10 12:38 UTC (permalink / raw)
  To: Weigang He
  Cc: Sudeep Holla, Lorenzo Pieralisi, Rob Herring, linux-arm-kernel,
	linux-kernel
In-Reply-To: <20260610033054.2117363-1-geoffreyhe2@gmail.com>

On Wed, Jun 10, 2026 at 01:30:54PM +1000, Weigang He wrote:
> vexpress_syscfg_probe() iterates the "arm,vexpress,config-bus"
> compatible nodes and, for each one, takes a reference to the bridge
> phandle via of_parse_phandle():
> 
> 	bridge_np = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
> 
> bridge_np is only compared against pdev->dev.parent->of_node and is
> never released - neither on the "continue" path when it does not match,
> nor on the path that calls of_platform_populate() and falls through to
> the next loop iteration. Each matching iteration leaks one device_node
> reference; the leak repeats on every probe (driver bind/unbind, module
> reload, or EPROBE_DEFER retry).
> 
> This is a regression of commit 557e37c05f28 ("bus: vexpress-config: add
> missing of_node_put after calling of_parse_phandle"), which fixed the
> equivalent leak in the predecessor function vexpress_config_populate().
> Commit a5a38765ac79 ("bus: vexpress-config: simplify config bus
> probing") removed that function and inlined the loop into the probe
> routine, but did not carry over the of_node_put().
> 
> Use the __free(device_node) cleanup attribute on bridge_np so the
> reference is released automatically at the end of each loop iteration.
> 
> Found by static analysis tool CodeQL.
> 
> Fixes: a5a38765ac79 ("bus: vexpress-config: simplify config bus probing")
> Signed-off-by: Weigang He <geoffreyhe2@gmail.com>

Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>

Thanks for the fix!

Best regards,
Liviu

> ---
>  drivers/bus/vexpress-config.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c
> index 64ee920721ee7..cc247483d3823 100644
> --- a/drivers/bus/vexpress-config.c
> +++ b/drivers/bus/vexpress-config.c
> @@ -390,9 +390,9 @@ static int vexpress_syscfg_probe(struct platform_device *pdev)
>  	}
>  
>  	for_each_compatible_node(node, NULL, "arm,vexpress,config-bus") {
> -		struct device_node *bridge_np;
> +		struct device_node *bridge_np __free(device_node) =
> +			of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
>  
> -		bridge_np = of_parse_phandle(node, "arm,vexpress,config-bridge", 0);
>  		if (bridge_np != pdev->dev.parent->of_node)
>  			continue;
>  
> 
> base-commit: 0f61b1860cc3f52aef9036d7235ed1f017632193
> -- 
> 2.43.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯


^ permalink raw reply

* Re: [PATCHv2] arm64/entry: Fix arm64-specific rseq brokenness
From: Will Deacon @ 2026-06-10 12:37 UTC (permalink / raw)
  To: Mathias Stearn
  Cc: Jinjie Ruan, Mark Rutland, linux-arm-kernel, Catalin Marinas,
	Peter Zijlstra, Thomas Gleixner, ckennelly, dvyukov, linux-kernel,
	mathieu.desnoyers
In-Reply-To: <CAHnCjA1dGNH07YkWupg1THAmBhW=o4C+uhHbbcRX4edMj2rmEg@mail.gmail.com>

On Tue, Jun 09, 2026 at 02:04:23PM +0200, Mathias Stearn wrote:
> Did the arm64-specific fix to rseq not get backportted to 7.0? We just
> ran our test suite against 7.0.10 which has the other rseq fixes and
> everything was fine on x86_64, but arm64 was frequently segfaulting.
> 
> I had an AI agent look into this and it reported:
> """
> The fix (commits b9eac6a9d93c, 82f572449cfe, 99428157dcf3,
> 411c1cf43039) first appeared in v7.1-rc1 and will be included in
> v7.1.0.
> 
> The three commits backported to linux-7.0.y:
> - 663121edad54 — "rseq: Revert to historical performance killing behaviour"
> - d242126fd21a — "rseq: Implement read only ABI enforcement for
> optimized RSEQ V2 mode"
> - fb742945d61a — "rseq: Reenable performance optimizations conditionally"
> 
> The arm64-specific fix (411c1cf43039 "arm64/entry: Fix arm64-specific
> rseq brokenness") was not backported to any stable branch — it will
> only appear in v7.1.0.
> """
> 
> Is it possible to get 411c1cf43039 backported to 7.0 or was it omitted
> intentionally?

You can send a backport to the stable maintainers:

https://docs.kernel.org/process/stable-kernel-rules.html#procedure-for-submitting-patches-to-the-stable-tree

(see option 3)

Will


^ permalink raw reply

* Re: [PATCH v2 1/2] soc: aspeed: add BMC-side PCIe BMC device driver
From: Andrew Jeffery @ 2026-06-10 12:33 UTC (permalink / raw)
  To: Grégoire Layet, joel
  Cc: andrew, jacky_chou, yh_chung, ninad, linux-aspeed,
	linux-arm-kernel, linux-kernel
In-Reply-To: <af322e76d34ad504e0bdec470293a017b489cfd7.1780929570.git.gregoire.layet@9elements.com>

Hello Grégoire,

On Mon, 2026-06-08 at 14:51 +0000, Grégoire Layet wrote:
> Taken from ASPEED 6.18 Kernel SDK

It's probably best to use ASPEED's SDK as a source of inspiration for
fixing obscure bugs, but not send drivers directly extracted from it.

> 
> Add support for VUART over PCIe between BMC and host.
> This add BMC side driver.
> 
> Signed-off-by: Jacky Chou <jacky_chou@aspeedtech.com>
> Signed-off-by: aspeedyh <yh_chung@aspeedtech.com>
> Signed-off-by: Grégoire Layet <gregoire.layet@9elements.com>
> Tested-by: Grégoire Layet <gregoire.layet@9elements.com>
> ---
>  drivers/soc/aspeed/Kconfig          |   7 ++
>  drivers/soc/aspeed/Makefile         |   1 +
>  drivers/soc/aspeed/aspeed-bmc-dev.c | 187 ++++++++++++++++++++++++++++

We should avoid adding more drivers in drivers/soc/aspeed where we can.

Is this really necessary?

>  3 files changed, 195 insertions(+)
>  create mode 100644 drivers/soc/aspeed/aspeed-bmc-dev.c
> 
> diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
> index f579ee0b5afa..3e1fcf3c3268 100644
> --- a/drivers/soc/aspeed/Kconfig
> +++ b/drivers/soc/aspeed/Kconfig
> @@ -4,6 +4,13 @@ if ARCH_ASPEED || COMPILE_TEST
>  
>  menu "ASPEED SoC drivers"
>  
> +config ASPEED_BMC_DEV
> +	tristate "ASPEED BMC Device"
> +	default n
> +	help
> +	  Enable support for the ASPEED AST2600 BMC Device.
> +	  This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
> +
>  config ASPEED_LPC_CTRL
>  	tristate "ASPEED LPC firmware cycle control"
>  	select REGMAP
> diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
> index b35d74592964..fab0d247df66 100644
> --- a/drivers/soc/aspeed/Makefile
> +++ b/drivers/soc/aspeed/Makefile
> @@ -1,4 +1,5 @@
>  # SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_ASPEED_BMC_DEV)		+= aspeed-bmc-dev.o
>  obj-$(CONFIG_ASPEED_LPC_CTRL)		+= aspeed-lpc-ctrl.o
>  obj-$(CONFIG_ASPEED_LPC_SNOOP)		+= aspeed-lpc-snoop.o
>  obj-$(CONFIG_ASPEED_UART_ROUTING)	+= aspeed-uart-routing.o
> diff --git a/drivers/soc/aspeed/aspeed-bmc-dev.c b/drivers/soc/aspeed/aspeed-bmc-dev.c
> new file mode 100644
> index 000000000000..7a204b543c97
> --- /dev/null
> +++ b/drivers/soc/aspeed/aspeed-bmc-dev.c
> @@ -0,0 +1,187 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +// Copyright (C) ASPEED Technology Inc.
> +
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +
> +#include <linux/regmap.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/syscon.h>
> +
> +#define SCU_TRIGGER_MSI
> +
> +/* AST2600 SCU */
> +#define ASPEED_SCU04			0x04
> +#define AST2600A3_SCU04				0x05030303
> +#define ASPEED_SCUC20			0xC20
> +#define ASPEED_SCUC24			0xC24

These could all use properly descriptive names.

Pinctrl is an exception because of how the documentation is structured.

> +#define MSI_ROUTING_MASK			GENMASK(11, 10)
> +#define PCIDEV1_INTX_MSI_HOST2BMC_EN		BIT(18)
> +#define MSI_ROUTING_PCIe2LPC_PCIDEV0		(0x1 << 10)
> +#define MSI_ROUTING_PCIe2LPC_PCIDEV1		(0x2 << 10)
> +
> +#define ASPEED_SCU_PCIE_CONF_CTRL	0xC20
> +#define  SCU_PCIE_CONF_BMC_DEV_EN			 BIT(8)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_MMIO		 BIT(9)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_MSI		 BIT(11)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_IRQ		 BIT(13)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_DMA		 BIT(14)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_E2L		 BIT(15)
> +#define  SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE BIT(21)
> +
> +#define ASPEED_SCU_BMC_DEV_CLASS	0xC68
> +
> +
> +struct aspeed_platform {
> +	int (*init)(struct platform_device *pdev);
> +};
> +
> +struct aspeed_bmc_device {
> +	struct device *dev;
> +	int id;
> +	void __iomem *reg_base;
> +
> +	int pcie2lpc;
> +	int irq;
> +
> +	const struct aspeed_platform *platform;
> +
> +	struct regmap *scu;
> +	int pcie_irq;
> +};
> +
> +
> +static int aspeed_ast2600_init(struct platform_device *pdev)
> +{
> +	struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
> +	struct device *dev = &pdev->dev;
> +	u32 pcie_config_ctl = SCU_PCIE_CONF_BMC_DEV_EN_IRQ |
> +			      SCU_PCIE_CONF_BMC_DEV_EN_MMIO | SCU_PCIE_CONF_BMC_DEV_EN;
> +	u32 scu_id;
> +
> +	bmc_device->scu = syscon_regmap_lookup_by_phandle(dev->of_node, "aspeed,scu");

We should rather look at auxbus for the SCU.

> +	if (IS_ERR(bmc_device->scu)) {
> +		dev_err(&pdev->dev, "failed to find SCU regmap\n");
> +		return PTR_ERR(bmc_device->scu);
> +	}
> +
> +	if (bmc_device->pcie2lpc)
> +		pcie_config_ctl |= SCU_PCIE_CONF_BMC_DEV_EN_E2L |
> +				   SCU_PCIE_CONF_BMC_DEV_EN_LPC_DECODE;
> +
> +	regmap_update_bits(bmc_device->scu, ASPEED_SCU_PCIE_CONF_CTRL,
> +			   pcie_config_ctl, pcie_config_ctl);
> +
> +	/* update class code to others as it is a MFD device */
> +	regmap_write(bmc_device->scu, ASPEED_SCU_BMC_DEV_CLASS, 0xff000000);
> +
> +#ifdef SCU_TRIGGER_MSI

I don't see that this needs to be a CPP test. This could be a C test.
The construct would be optimised because of the constant and we'd get
compile time coverage of both sides without additional configuration.

Have you tested both sides?

> +	//SCUC24[17]: Enable PCI device 1 INTx/MSI from SCU560[15]. Will be added in next version
> +	regmap_update_bits(bmc_device->scu, ASPEED_SCUC20, BIT(11) | BIT(14), BIT(11) | BIT(14));

These bits need descriptive macros.

> +
> +	regmap_read(bmc_device->scu, ASPEED_SCU04, &scu_id);
> +	if (scu_id == AST2600A3_SCU04)
> +		regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
> +				   PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_MASK,
> +				   PCIDEV1_INTX_MSI_HOST2BMC_EN | MSI_ROUTING_PCIe2LPC_PCIDEV1);
> +	else
> +		regmap_update_bits(bmc_device->scu, ASPEED_SCUC24,
> +				   BIT(17) | BIT(14) | BIT(11), BIT(17) | BIT(14) | BIT(11));

As do these

> +#else
> +	//SCUC24[18]: Enable PCI device 1 INTx/MSI from Host-to-BMC controller.
> +	regmap_update_bits(bmc_device->scu, 0xc24, BIT(18) | BIT(14), BIT(18) | BIT(14));

And these.

> +#endif
> +
> +
> +	return 0;
> +}
> +
> +
> +static struct aspeed_platform ast2600_plaform = {
> +	.init = aspeed_ast2600_init
> +};
> +
> +
> +static const struct of_device_id aspeed_bmc_device_of_matches[] = {
> +	{ .compatible = "aspeed,ast2600-bmc-device", .data = &ast2600_plaform },

This compatible isn't documented in this series and isn't present in
linux-next at a87737435cfa ("Add linux-next specific files for
20260608"). You'll need to address that if it's reasonable to continue
down this path. I expect you'll want to avoid it, and define any
necessary properties on the SCU node rather than add further children.

> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, aspeed_bmc_device_of_matches);
> +
> +static int aspeed_bmc_device_probe(struct platform_device *pdev)
> +{
> +	struct aspeed_bmc_device *bmc_device;
> +	struct device *dev = &pdev->dev;

This shortcut is defined but inconsistently used.

> +	const void *md = of_device_get_match_data(dev);

I think we can do without this, see below.

> +	int ret = 0;
> +
> +	if (!md)
> +		return -ENODEV;
> +
> +	bmc_device = devm_kzalloc(&pdev->dev, sizeof(struct aspeed_bmc_device), GFP_KERNEL);
> +	if (!bmc_device)
> +		return -ENOMEM;
> +	dev_set_drvdata(dev, bmc_device);
> +
> +	bmc_device->platform = md;
> +
> +	bmc_device->id = of_alias_get_id(dev->of_node, "bmcdev");
> +	if (bmc_device->id < 0)
> +		bmc_device->id = 0;
> +
> +	bmc_device->dev = dev;
> +	bmc_device->reg_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(bmc_device->reg_base))
> +		return PTR_ERR(bmc_device->reg_base);
> +
> +	bmc_device->irq = platform_get_irq(pdev, 0);

This seems unnecessary.

> +	if (bmc_device->irq < 0) {
> +		dev_err(&pdev->dev, "platform get of irq[=%d] failed!\n", bmc_device->irq);
> +		return bmc_device->irq;
> +	}
> +
> +	if (of_property_read_bool(dev->of_node, "pcie2lpc"))

This property isn't documented.

> +		bmc_device->pcie2lpc = 1;
> +
> +	ret = bmc_device->platform->init(pdev);

The driver only supports one SoC, this indirection seems unnecessary
right now. We can add that later when there's a need to differentiate.
I'd rather you call the setup function directly for now.

> +	if (ret) {
> +		dev_err(dev, "Initialize bmc device failed\n");
> +		goto out;
> +	}
> +
> +	dev_info(dev, "aspeed bmc device: driver successfully loaded.\n");
> +
> +	return 0;
> +
> +out:
> +	dev_warn(dev, "aspeed bmc device: driver init failed (ret=%d)!\n", ret);
> +	return ret;
> +}
> +
> +static void aspeed_bmc_device_remove(struct platform_device *pdev)
> +{
> +	struct aspeed_bmc_device *bmc_device = platform_get_drvdata(pdev);
> +
> +	devm_free_irq(&pdev->dev, bmc_device->irq, bmc_device);
> +	devm_kfree(&pdev->dev, bmc_device);

These are unnecessary due to cleanup of devres on release.

Andrew


^ permalink raw reply

* Re: [PATCH v3 2/2] clk: amlogic: Add A9 AO clock controller driver
From: Jerome Brunet @ 2026-06-10 12:30 UTC (permalink / raw)
  To: Jian Hu via B4 Relay
  Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao, Kevin Hilman,
	Martin Blumenstingl, jian.hu, linux-amlogic, linux-clk,
	devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20260610-a9_aoclk-v3-2-b7592d6c31e2@amlogic.com>

On mer. 10 juin 2026 at 16:23, Jian Hu via B4 Relay <devnull+jian.hu.amlogic.com@kernel.org> wrote:

> From: Jian Hu <jian.hu@amlogic.com>
>
> Add the Always-on clock controller driver for the Amlogic A9 SoC family.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
>  drivers/clk/meson/Kconfig    |  13 ++
>  drivers/clk/meson/Makefile   |   1 +
>  drivers/clk/meson/a9-aoclk.c | 431 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 445 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index cf8cf3f9e4ee..b71299898197 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -132,6 +132,19 @@ config COMMON_CLK_A1_PERIPHERALS
>  	  device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>  	  controller to work.
>  
> +config COMMON_CLK_A9_AO
> +	tristate "Amlogic A9 SoC AO clock controller support"
> +	depends on ARM64 || COMPILE_TEST
> +	default ARCH_MESON
> +	select COMMON_CLK_MESON_REGMAP
> +	select COMMON_CLK_MESON_CLKC_UTILS
> +	select COMMON_CLK_MESON_DUALDIV
> +	imply COMMON_CLK_SCMI
> +	help
> +	  Support for the AO clock controller on Amlogic A311Y3 based
> +	  device, AKA A9.
> +	  Say Y if you want A9 AO clock controller to work.
> +
>  config COMMON_CLK_C3_PLL
>  	tristate "Amlogic C3 PLL clock controller"
>  	depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index c6719694a242..f89d027c282c 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>  obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>  obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A9_AO) += a9-aoclk.o
>  obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>  obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>  obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a9-aoclk.c b/drivers/clk/meson/a9-aoclk.c
> new file mode 100644
> index 000000000000..dd9fd8d24702
> --- /dev/null
> +++ b/drivers/clk/meson/a9-aoclk.c
> @@ -0,0 +1,431 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
> + */
> +
> +#include <dt-bindings/clock/amlogic,a9-aoclkc.h>
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +
> +#define AO_OSCIN_CTRL			0x00
> +#define AO_SYS_CLK0			0x04
> +#define AO_PWM_CLK_A_CTRL		0x1c
> +#define AO_PWM_CLK_B_CTRL		0x20
> +#define AO_PWM_CLK_C_CTRL		0x24
> +#define AO_PWM_CLK_D_CTRL		0x28
> +#define AO_PWM_CLK_E_CTRL		0x2c
> +#define AO_PWM_CLK_F_CTRL		0x30
> +#define AO_PWM_CLK_G_CTRL		0x34
> +#define AO_CEC_CTRL0			0x38
> +#define AO_CEC_CTRL1			0x3c
> +#define AO_RTC_BY_OSCIN_CTRL0		0x50
> +#define AO_RTC_BY_OSCIN_CTRL1		0x54
> +
> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
> +	MESON_COMP_SEL(a9_ao_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
> +
> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
> +	MESON_COMP_DIV(a9_ao_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A9_COMP_GATE(_name, _reg, _bit) \
> +	MESON_COMP_GATE(a9_ao_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
> +
> +static struct clk_regmap a9_ao_xtal_in = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = AO_OSCIN_CTRL,
> +		.bit_idx = 3,
> +	},
> +	.hw.init = &(struct clk_init_data) {
> +		.name = "ao_xtal_in",
> +		.ops = &clk_regmap_gate_ops,
> +		.parent_data = &(const struct clk_parent_data) {
> +			.fw_name = "xtal",
> +		},
> +		.num_parents = 1,
> +		/*
> +		 * ao_sys can select different clock sources. One possible clock path is:
> +		 *   ao_xtal_in->ao_xtal->ao_sys-> ao sys gate clocks
> +		 *
> +		 * ao_xtal_in is in the parent chain of AO sys gate clocks.
> +		 * Since some downstream clocks are marked CLK_IS_CRITICAL,
> +		 * ao_xtal_in must remain enabled and is therefore marked
> +		 * CLK_IS_CRITICAL as well.
> +		 */
> +		.flags = CLK_IS_CRITICAL,

Please allow some time for me to reply before reposting.
See my answer on v2.


> +	},
> +};
> +
> +static struct clk_regmap a9_ao_xtal = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_OSCIN_CTRL,
> +		.mask = 0x1,
> +		.shift = 0,
> +	},
> +	/* ext_32k is from external PAD, do not automatically reparent */
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("ao_xtal",
> +			((const struct clk_parent_data []) {
> +				{ .hw = &a9_ao_xtal_in.hw },
> +				{ .fw_name = "ext_32k" }
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_NO_REPARENT),

I hope my view on this is clear as well.
Let me know if it isn't 


> +};
> +
> +static struct clk_regmap a9_ao_sys = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_OSCIN_CTRL,
> +		.mask = 0x1,
> +		.shift = 1,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_DATA("ao_sys",
> +			((const struct clk_parent_data []) {
> +				{ .hw = &a9_ao_xtal.hw },
> +				{ .fw_name = "sys" }
> +			}), &clk_regmap_mux_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_ao_pclk_parents = { .hw = &a9_ao_sys.hw };
> +
> +#define A9_AO_PCLK(_name, _bit, _flags)		       \
> +	MESON_PCLK(a9_ao_sys_##_name, AO_SYS_CLK0, _bit, \
> +		   &a9_ao_pclk_parents, _flags)
> +
> +/*
> + * A9 integrates a low-power microprocessor (Always-on CPU: AOCPU). Some AO sys
> + * clocks control the AOCPU modules. Mark the AOCPU-related clocks with
> + * CLK_IS_CRITICAL to avoid them being disabled and impacting AOCPU functionality.
> + * AOCPU-related clocks list:
> + * - clktree
> + * - rst_ctrl
> + * - pad
> + * - irq
> + * - pwrctrl
> + * - aocpu
> + * - sram
> + */
> +static A9_AO_PCLK(i3c,		0,	0);
> +static A9_AO_PCLK(rtc_reg,	1,	0);
> +static A9_AO_PCLK(clktree,	2,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(rst_ctrl,	3,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pad,		4,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(rtc_dig,	5,	0);
> +static A9_AO_PCLK(irq,		6,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pwrctrl,	7,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pwm_a,	8,	0);
> +static A9_AO_PCLK(pwm_b,	9,	0);
> +static A9_AO_PCLK(pwm_c,	10,	0);
> +static A9_AO_PCLK(pwm_d,	11,	0);
> +static A9_AO_PCLK(pwm_e,	12,	0);
> +static A9_AO_PCLK(pwm_f,	13,	0);
> +static A9_AO_PCLK(pwm_g,	14,	0);
> +static A9_AO_PCLK(i2c_a,	15,	0);
> +static A9_AO_PCLK(i2c_b,	16,	0);
> +static A9_AO_PCLK(i2c_c,	17,	0);
> +static A9_AO_PCLK(i2c_d,	18,	0);
> +static A9_AO_PCLK(sed,		19,	0);
> +static A9_AO_PCLK(ir_ctrl,	20,	0);
> +static A9_AO_PCLK(uart_b,	21,	0);
> +static A9_AO_PCLK(uart_c,	22,	0);
> +static A9_AO_PCLK(uart_d,	23,	0);
> +static A9_AO_PCLK(uart_e,	24,	0);
> +static A9_AO_PCLK(spisg_0,	25,	0);
> +static A9_AO_PCLK(rtc_secure,	26,	0);
> +static A9_AO_PCLK(cec,		27,	0);
> +static A9_AO_PCLK(aocpu,	28,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(sram,		29,	CLK_IS_CRITICAL);
> +static A9_AO_PCLK(spisg_1,	30,	0);
> +static A9_AO_PCLK(spisg_2,	31,	0);
> +
> +static const struct clk_parent_data a9_ao_pwm_parents[] = {
> +	{ .hw = &a9_ao_xtal.hw },
> +	{ .fw_name = "fdiv5", },
> +	{ .fw_name = "fdiv4", },
> +	{ .fw_name = "fdiv3", }
> +};
> +
> +static A9_COMP_SEL(pwm_a, AO_PWM_CLK_A_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_a, AO_PWM_CLK_A_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_a, AO_PWM_CLK_A_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_b, AO_PWM_CLK_B_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_b, AO_PWM_CLK_B_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_b, AO_PWM_CLK_B_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_c, AO_PWM_CLK_C_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_c, AO_PWM_CLK_C_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_c, AO_PWM_CLK_C_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_d, AO_PWM_CLK_D_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_d, AO_PWM_CLK_D_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_d, AO_PWM_CLK_D_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_e, AO_PWM_CLK_E_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_e, AO_PWM_CLK_E_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_e, AO_PWM_CLK_E_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_f, AO_PWM_CLK_F_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_f, AO_PWM_CLK_F_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_f, AO_PWM_CLK_F_CTRL, 8);
> +
> +static A9_COMP_SEL(pwm_g, AO_PWM_CLK_G_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(pwm_g, AO_PWM_CLK_G_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_g, AO_PWM_CLK_G_CTRL, 8);
> +
> +static struct clk_regmap a9_ao_rtc_dualdiv_in = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = AO_RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ao_rtc_dualdiv_in", &a9_ao_xtal.hw,
> +				   &clk_regmap_gate_ops, 0),
> +};
> +
> +static const struct meson_clk_dualdiv_param a9_ao_dualdiv_table[] = {
> +	{ 733, 732, 8, 11, 1 },
> +	{ /* sentinel */ }
> +};
> +
> +static struct clk_regmap a9_ao_rtc_dualdiv_div = {
> +	.data = &(struct meson_clk_dualdiv_data){
> +		.n1 = {
> +			.reg_off = AO_RTC_BY_OSCIN_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = AO_RTC_BY_OSCIN_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = AO_RTC_BY_OSCIN_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = AO_RTC_BY_OSCIN_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = AO_RTC_BY_OSCIN_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a9_ao_dualdiv_table,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("a9_ao_rtc_dualdiv_div", &a9_ao_rtc_dualdiv_in.hw,
> +				   &meson_clk_dualdiv_ops, 0),
> +};
> +
> +static struct clk_regmap a9_ao_rtc_dualdiv_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_RTC_BY_OSCIN_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("ao_rtc_dualdiv_sel",
> +			((const struct clk_hw *[]) {
> +				&a9_ao_rtc_dualdiv_div.hw,
> +				&a9_ao_rtc_dualdiv_in.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ao_rtc_dualdiv = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = AO_RTC_BY_OSCIN_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ao_rtc_dualdiv", &a9_ao_rtc_dualdiv_sel.hw,
> +				   &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ao_rtc = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_RTC_BY_OSCIN_CTRL1,
> +		.mask = 0x1,
> +		.shift = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("ao_rtc",
> +			((const struct clk_hw *[]) {
> +				&a9_ao_xtal.hw,
> +				&a9_ao_rtc_dualdiv.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ao_cec_dualdiv_in = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = AO_CEC_CTRL0,
> +		.bit_idx = 31,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ao_cec_dualdiv_in", &a9_ao_xtal.hw,
> +				   &clk_regmap_gate_ops, 0),
> +};
> +
> +static struct clk_regmap a9_ao_cec_dualdiv_div = {
> +	.data = &(struct meson_clk_dualdiv_data){
> +		.n1 = {
> +			.reg_off = AO_CEC_CTRL0,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.n2 = {
> +			.reg_off = AO_CEC_CTRL0,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.m1 = {
> +			.reg_off = AO_CEC_CTRL1,
> +			.shift   = 0,
> +			.width   = 12,
> +		},
> +		.m2 = {
> +			.reg_off = AO_CEC_CTRL1,
> +			.shift   = 12,
> +			.width   = 12,
> +		},
> +		.dual = {
> +			.reg_off = AO_CEC_CTRL0,
> +			.shift   = 28,
> +			.width   = 1,
> +		},
> +		.table = a9_ao_dualdiv_table,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ao_cec_dualdiv_div", &a9_ao_cec_dualdiv_in.hw,
> +				   &meson_clk_dualdiv_ops, 0),
> +};
> +
> +static struct clk_regmap a9_ao_cec_dualdiv_sel = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_CEC_CTRL1,
> +		.mask = 0x1,
> +		.shift = 24,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("ao_cec_dualdiv_sel",
> +			((const struct clk_hw *[]) {
> +				&a9_ao_cec_dualdiv_div.hw,
> +				&a9_ao_cec_dualdiv_in.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ao_cec_dualdiv = {
> +	.data = &(struct clk_regmap_gate_data){
> +		.offset = AO_CEC_CTRL0,
> +		.bit_idx = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_HW("ao_cec_dualdiv", &a9_ao_cec_dualdiv_sel.hw,
> +				   &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ao_cec = {
> +	.data = &(struct clk_regmap_mux_data) {
> +		.offset = AO_CEC_CTRL1,
> +		.mask = 0x1,
> +		.shift = 30,
> +	},
> +	.hw.init = CLK_HW_INIT_PARENTS_HW("ao_cec",
> +			((const struct clk_hw *[]) {
> +				&a9_ao_cec_dualdiv.hw,
> +				&a9_ao_rtc.hw,
> +			}), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_hw *a9_ao_hw_clks[] = {
> +	[CLKID_AO_XTAL_IN]		= &a9_ao_xtal_in.hw,
> +	[CLKID_AO_XTAL]			= &a9_ao_xtal.hw,
> +	[CLKID_AO_SYS]			= &a9_ao_sys.hw,
> +	[CLKID_AO_SYS_I3C]		= &a9_ao_sys_i3c.hw,
> +	[CLKID_AO_SYS_RTC_REG]		= &a9_ao_sys_rtc_reg.hw,
> +	[CLKID_AO_SYS_CLKTREE]		= &a9_ao_sys_clktree.hw,
> +	[CLKID_AO_SYS_RST_CTRL]		= &a9_ao_sys_rst_ctrl.hw,
> +	[CLKID_AO_SYS_PAD]		= &a9_ao_sys_pad.hw,
> +	[CLKID_AO_SYS_RTC_DIG]		= &a9_ao_sys_rtc_dig.hw,
> +	[CLKID_AO_SYS_IRQ]		= &a9_ao_sys_irq.hw,
> +	[CLKID_AO_SYS_PWRCTRL]		= &a9_ao_sys_pwrctrl.hw,
> +	[CLKID_AO_SYS_PWM_A]		= &a9_ao_sys_pwm_a.hw,
> +	[CLKID_AO_SYS_PWM_B]		= &a9_ao_sys_pwm_b.hw,
> +	[CLKID_AO_SYS_PWM_C]		= &a9_ao_sys_pwm_c.hw,
> +	[CLKID_AO_SYS_PWM_D]		= &a9_ao_sys_pwm_d.hw,
> +	[CLKID_AO_SYS_PWM_E]		= &a9_ao_sys_pwm_e.hw,
> +	[CLKID_AO_SYS_PWM_F]		= &a9_ao_sys_pwm_f.hw,
> +	[CLKID_AO_SYS_PWM_G]		= &a9_ao_sys_pwm_g.hw,
> +	[CLKID_AO_SYS_I2C_A]		= &a9_ao_sys_i2c_a.hw,
> +	[CLKID_AO_SYS_I2C_B]		= &a9_ao_sys_i2c_b.hw,
> +	[CLKID_AO_SYS_I2C_C]		= &a9_ao_sys_i2c_c.hw,
> +	[CLKID_AO_SYS_I2C_D]		= &a9_ao_sys_i2c_d.hw,
> +	[CLKID_AO_SYS_SED]		= &a9_ao_sys_sed.hw,
> +	[CLKID_AO_SYS_IR_CTRL]		= &a9_ao_sys_ir_ctrl.hw,
> +	[CLKID_AO_SYS_UART_B]		= &a9_ao_sys_uart_b.hw,
> +	[CLKID_AO_SYS_UART_C]		= &a9_ao_sys_uart_c.hw,
> +	[CLKID_AO_SYS_UART_D]		= &a9_ao_sys_uart_d.hw,
> +	[CLKID_AO_SYS_UART_E]		= &a9_ao_sys_uart_e.hw,
> +	[CLKID_AO_SYS_SPISG_0]		= &a9_ao_sys_spisg_0.hw,
> +	[CLKID_AO_SYS_RTC_SECURE]	= &a9_ao_sys_rtc_secure.hw,
> +	[CLKID_AO_SYS_CEC]		= &a9_ao_sys_cec.hw,
> +	[CLKID_AO_SYS_AOCPU]		= &a9_ao_sys_aocpu.hw,
> +	[CLKID_AO_SYS_SRAM]		= &a9_ao_sys_sram.hw,
> +	[CLKID_AO_SYS_SPISG_1]		= &a9_ao_sys_spisg_1.hw,
> +	[CLKID_AO_SYS_SPISG_2]		= &a9_ao_sys_spisg_2.hw,
> +	[CLKID_AO_PWM_A_SEL]		= &a9_ao_pwm_a_sel.hw,
> +	[CLKID_AO_PWM_A_DIV]		= &a9_ao_pwm_a_div.hw,
> +	[CLKID_AO_PWM_A]		= &a9_ao_pwm_a.hw,
> +	[CLKID_AO_PWM_B_SEL]		= &a9_ao_pwm_b_sel.hw,
> +	[CLKID_AO_PWM_B_DIV]		= &a9_ao_pwm_b_div.hw,
> +	[CLKID_AO_PWM_B]		= &a9_ao_pwm_b.hw,
> +	[CLKID_AO_PWM_C_SEL]		= &a9_ao_pwm_c_sel.hw,
> +	[CLKID_AO_PWM_C_DIV]		= &a9_ao_pwm_c_div.hw,
> +	[CLKID_AO_PWM_C]		= &a9_ao_pwm_c.hw,
> +	[CLKID_AO_PWM_D_SEL]		= &a9_ao_pwm_d_sel.hw,
> +	[CLKID_AO_PWM_D_DIV]		= &a9_ao_pwm_d_div.hw,
> +	[CLKID_AO_PWM_D]		= &a9_ao_pwm_d.hw,
> +	[CLKID_AO_PWM_E_SEL]		= &a9_ao_pwm_e_sel.hw,
> +	[CLKID_AO_PWM_E_DIV]		= &a9_ao_pwm_e_div.hw,
> +	[CLKID_AO_PWM_E]		= &a9_ao_pwm_e.hw,
> +	[CLKID_AO_PWM_F_SEL]		= &a9_ao_pwm_f_sel.hw,
> +	[CLKID_AO_PWM_F_DIV]		= &a9_ao_pwm_f_div.hw,
> +	[CLKID_AO_PWM_F]		= &a9_ao_pwm_f.hw,
> +	[CLKID_AO_PWM_G_SEL]		= &a9_ao_pwm_g_sel.hw,
> +	[CLKID_AO_PWM_G_DIV]		= &a9_ao_pwm_g_div.hw,
> +	[CLKID_AO_PWM_G]		= &a9_ao_pwm_g.hw,
> +	[CLKID_AO_RTC_DUALDIV_IN]	= &a9_ao_rtc_dualdiv_in.hw,
> +	[CLKID_AO_RTC_DUALDIV_DIV]	= &a9_ao_rtc_dualdiv_div.hw,
> +	[CLKID_AO_RTC_DUALDIV_SEL]	= &a9_ao_rtc_dualdiv_sel.hw,
> +	[CLKID_AO_RTC_DUALDIV]		= &a9_ao_rtc_dualdiv.hw,
> +	[CLKID_AO_RTC]			= &a9_ao_rtc.hw,
> +	[CLKID_AO_CEC_DUALDIV_IN]	= &a9_ao_cec_dualdiv_in.hw,
> +	[CLKID_AO_CEC_DUALDIV_DIV]	= &a9_ao_cec_dualdiv_div.hw,
> +	[CLKID_AO_CEC_DUALDIV_SEL]	= &a9_ao_cec_dualdiv_sel.hw,
> +	[CLKID_AO_CEC_DUALDIV]		= &a9_ao_cec_dualdiv.hw,
> +	[CLKID_AO_CEC]			= &a9_ao_cec.hw,
> +};
> +
> +static const struct meson_clkc_data a9_ao_clkc_data = {
> +	.hw_clks = {
> +		.hws = a9_ao_hw_clks,
> +		.num = ARRAY_SIZE(a9_ao_hw_clks),
> +	},
> +};
> +
> +static const struct of_device_id a9_ao_clkc_match_table[] = {
> +	{
> +		.compatible	= "amlogic,a9-aoclkc",
> +		.data		= &a9_ao_clkc_data,
> +	},
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, a9_ao_clkc_match_table);
> +
> +static struct platform_driver a9_ao_clkc_driver = {
> +	.probe		= meson_clkc_mmio_probe,
> +	.driver		= {
> +		.name	= "a9-aoclkc",
> +		.of_match_table = a9_ao_clkc_match_table,
> +	},
> +};
> +module_platform_driver(a9_ao_clkc_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A9 Always-ON Clock Controller driver");
> +MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("CLK_MESON");

-- 
Jerome


^ permalink raw reply

* Re: [PATCH] arm64/hw_breakpoint: reject unaligned watchpoints that would truncate BAS
From: Will Deacon @ 2026-06-10 12:30 UTC (permalink / raw)
  To: Breno Leitao
  Cc: Mark Rutland, Catalin Marinas, Pratyush Anand, linux-arm-kernel,
	linux-perf-users, linux-kernel, clm, leo.bras, kernel-team
In-Reply-To: <aiaqbmQSksKB6dTZ@gmail.com>

On Mon, Jun 08, 2026 at 05:14:22AM -0700, Breno Leitao wrote:
> On Fri, May 29, 2026 at 03:53:58PM +0100, Will Deacon wrote:
> > Hi Breno,
> > 
> > Thanks for sending this out.
> > 
> > On Thu, Apr 30, 2026 at 02:40:10AM -0700, Breno Leitao wrote:
> > > hw_breakpoint_arch_parse() positions the BAS bit pattern in
> > > hw->ctrl.len with
> > > 
> > > 	offset = hw->address & alignment_mask;	/* 0..7 */
> > > 	hw->ctrl.len <<= offset;
> > > 
> > > ctrl.len is an 8-bit bitfield (struct arch_hw_breakpoint_ctrl::len is
> > > u32 :8), so the shift silently drops any bits past bit 7.  For
> > > non-compat AArch64 watchpoints the offset is unbounded relative to
> > > ctrl.len: a perf_event_open(PERF_TYPE_BREAKPOINT) caller asking for
> > > HW_BREAKPOINT_W with bp_addr=page+1 and bp_len=HW_BREAKPOINT_LEN_8
> > > ends up with 0xff << 1 = 0x1fe, stored as 0xfe.  The kernel programs
> > > WCR.BAS=0xfe and the hardware watches bytes [1..7] instead of the
> > > requested [1..8] -- the eighth byte is silently dropped.  The
> > > syscall still returns success, leaving userspace to discover the
> > > gap by empirical probing.
> > > 
> > > The same class affects HW_BREAKPOINT_LEN_{2,4} when offset pushes the
> > > high BAS bit past bit 7 (e.g. LEN_4 with offset=5 yields 0xe0
> > > instead of 0x1e0).  No memory-safety impact -- the value is masked
> > > into 8 bits before encoding -- but debuggers and perf users observe
> > > missed events on bytes they thought they were watching.
> > > 
> > > The AArch32 branch immediately above already rejects unrepresentable
> > > (offset, len) combinations via an explicit switch.  Mirror that for
> > > the non-compat branch by checking that the shifted pattern fits in
> > > the BAS field, returning -EINVAL when it does not.
> > > 
> > > Reproducer:
> > > 
> > >   struct perf_event_attr a = {
> > >       .type = PERF_TYPE_BREAKPOINT, .size = sizeof(a),
> > >       .bp_type = HW_BREAKPOINT_W,
> > >       .bp_addr = (uintptr_t)(buf + 1),
> > >       .bp_len = HW_BREAKPOINT_LEN_8,
> > >       .exclude_kernel = 1, .exclude_hv = 1,
> > >   };
> > >   int fd = perf_event_open(&a, 0, -1, -1, 0);
> > >   /* before this fix: succeeds, watches 7 bytes (buf+1..buf+7)   */
> > >   /* after  this fix: fails with EINVAL                          */
> > > 
> > > Signed-off-by: Breno Leitao <leitao@debian.org>
> > > Fixes: b08fb180bb88 ("arm64: Allow hw watchpoint at varied offset from base address")
> > 
> > Oh man, this has been broken for nearly a decade :/
> > 
> > I think we probably should've stuck with the old behaviour of rejecting
> > unaligned base addresses, but it's too late now. Damn.
> > 
> > >  arch/arm64/kernel/hw_breakpoint.c | 9 +++++++++
> > >  1 file changed, 9 insertions(+)
> > > 
> > > diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c
> > > index ab76b36dce820..b8a1402119f3a 100644
> > > --- a/arch/arm64/kernel/hw_breakpoint.c
> > > +++ b/arch/arm64/kernel/hw_breakpoint.c
> > > @@ -559,6 +559,15 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
> > >  		else
> > >  			alignment_mask = 0x7;
> > >  		offset = hw->address & alignment_mask;
> > > +
> > > +		/*
> > > +		 * BAS is an 8-bit field in WCR/BCR; the shift below would
> > > +		 * silently drop the high bits of ctrl.len when offset + len
> > > +		 * exceeds 8, programming hardware to watch fewer bytes than
> > > +		 * the user requested.
> > > +		 */
> > > +		if (((u32)hw->ctrl.len << offset) > 0xff)
> > 
> > nit: Use ARM_BREAKPOINT_LEN_8 instead of 0xff
> > 
> > > +			return -EINVAL;
> > >  	}
> > 
> > I must confess, I'm very nervous about breaking userspace here. If GDB
> > is triggering this path, then this patch will change an unreliable
> > watchpoint into a hard error (which probably means GDB exits). Have you
> > looked to see what GDB and/or any other debuggers do?
> > 
> > I had a quick peek and found the bugzilla entry which motivated the
> > buggy change in the first place:
> > 
> > https://sourceware.org/bugzilla/show_bug.cgi?id=20207
> > 
> > and it looks like the aarch64_align_watchpoint() function does try to
> > spill into multiple watchpoints, so perhaps your patch is ok. I'd
> > appreciate your opinion, though.
> 
> It won't, for two independent reasons.

Sorry, not sure I understand you here when you say "it won't". GDB won't
spill or something else?

> The new -EINVAL is unreachable from GDB; only a raw perf_event_open() passing
> an unaligned base with an oversized bp_len hits it, which is the bug.

Why isn't it reachable via hw_break_set() => {ptrace_hbp_set_addr(),
ptrace_hbp_set_ctrl()} ?

> Second, even if a debugger did hand the kernel such a request, GDB
> already treats EINVAL on NT_ARM_HW_WATCH as a downgrade signal, not a
> fatal error. aarch64_linux_set_debug_regs() catches it, clears
> kernel_supports_any_contiguous_range, calls aarch64_downgrade_regs()
> (which rounds the BAS up to a legacy 0x01/03/0f/ff mask and aligns the
> base down), and retries. That fallback is exactly the PR-20207 path.
> 
> Confirmed on a Grace box: with the patch applied (under virtme-ng), the
> reproducer's unaligned LEN_8 now returns -EINVAL while aligned LEN_8
> still succeeds, and GDB still inserts the watchpoint and it still fires
> on every write.

Thanks for testing it, that's somewhat reassuring.

> GDB in fact downgrades on the current kernel independently of this patch, so
> behaviour is unchanged for it.

That sounds like a bug?

Will


^ permalink raw reply

* Re: [PATCH v2 2/2] clk: amlogic: Add A9 AO clock controller driver
From: Jerome Brunet @ 2026-06-10 12:26 UTC (permalink / raw)
  To: Jian Hu
  Cc: Jian Hu via B4 Relay, Neil Armstrong, Michael Turquette,
	Stephen Boyd, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Xianwei Zhao, Kevin Hilman, Martin Blumenstingl, linux-amlogic,
	linux-clk, devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <67fcf9bc-0ac7-4812-aa7c-4d42d8f1c162@amlogic.com>

On mer. 10 juin 2026 at 12:18, Jian Hu <jian.hu@amlogic.com> wrote:

> Hi Jerome,
>
> Thanks for your review
>
> On 6/3/2026 10:29 PM, Jerome Brunet wrote:
>> [ EXTERNAL EMAIL ]
>>
>> On Wed 03 Jun 2026 at 20:17, Jian Hu via B4 Relay <devnull+jian.hu.amlogic.com@kernel.org> wrote:
>>
>>> From: Jian Hu <jian.hu@amlogic.com>
>>>
>>> Add the Always-on clock controller driver for the Amlogic A9 SoC family.
>>>
>>> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
>>> ---
>>>   drivers/clk/meson/Kconfig    |  13 ++
>>>   drivers/clk/meson/Makefile   |   1 +
>>>   drivers/clk/meson/a9-aoclk.c | 419 +++++++++++++++++++++++++++++++++++++++++++
>>>   3 files changed, 433 insertions(+)
>>>
>>> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
>>> index cf8cf3f9e4ee..625e6788b940 100644
>>> --- a/drivers/clk/meson/Kconfig
>>> +++ b/drivers/clk/meson/Kconfig
>>> @@ -132,6 +132,19 @@ config COMMON_CLK_A1_PERIPHERALS
>>>          device, A1 SoC Family. Say Y if you want A1 Peripherals clock
>>>          controller to work.
>>>
>>> +config COMMON_CLK_A9_AO
>>> +     tristate "Amlogic A9 SoC AO clock controller support"
>>> +     depends on ARM64
>>> +     default ARCH_MESON || COMPILE_TEST
>>> +     select COMMON_CLK_MESON_REGMAP
>>> +     select COMMON_CLK_MESON_CLKC_UTILS
>>> +     select COMMON_CLK_MESON_DUALDIV
>>> +     imply COMMON_CLK_SCMI
>>> +     help
>>> +       Support for the AO clock controller on Amlogic A311Y3 based
>>> +       device, AKA A9.
>>> +       Say Y if you want A9 AO clock controller to work.
>>> +
>>>   config COMMON_CLK_C3_PLL
>>>        tristate "Amlogic C3 PLL clock controller"
>>>        depends on ARM64
>>> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
>>> index c6719694a242..f89d027c282c 100644
>>> --- a/drivers/clk/meson/Makefile
>>> +++ b/drivers/clk/meson/Makefile
>>> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
>>>   obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
>>>   obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
>>>   obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
>>> +obj-$(CONFIG_COMMON_CLK_A9_AO) += a9-aoclk.o
>>>   obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
>>>   obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
>>>   obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
>>> diff --git a/drivers/clk/meson/a9-aoclk.c b/drivers/clk/meson/a9-aoclk.c
>>> new file mode 100644
>>> index 000000000000..b7b3ca231a42
>>> --- /dev/null
>>> +++ b/drivers/clk/meson/a9-aoclk.c
>>> @@ -0,0 +1,419 @@
>>> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
>>> +/*
>>> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
>>> + */
>>> +
>>> +#include <dt-bindings/clock/amlogic,a9-aoclkc.h>
>>> +#include <linux/clk-provider.h>
>>> +#include <linux/platform_device.h>
>>> +#include "clk-regmap.h"
>>> +#include "clk-dualdiv.h"
>>> +#include "meson-clkc-utils.h"
>>> +
>>> +#define AO_OSCIN_CTRL                        0x00
>>> +#define AO_SYS_CLK0                  0x04
>>> +#define AO_PWM_CLK_A_CTRL            0x1c
>>> +#define AO_PWM_CLK_B_CTRL            0x20
>>> +#define AO_PWM_CLK_C_CTRL            0x24
>>> +#define AO_PWM_CLK_D_CTRL            0x28
>>> +#define AO_PWM_CLK_E_CTRL            0x2c
>>> +#define AO_PWM_CLK_F_CTRL            0x30
>>> +#define AO_PWM_CLK_G_CTRL            0x34
>>> +#define AO_CEC_CTRL0                 0x38
>>> +#define AO_CEC_CTRL1                 0x3c
>>> +#define AO_RTC_BY_OSCIN_CTRL0                0x50
>>> +#define AO_RTC_BY_OSCIN_CTRL1                0x54
>>> +
>>> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
>>> +     MESON_COMP_SEL(a9_ao_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
>>> +
>>> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
>>> +     MESON_COMP_DIV(a9_ao_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
>>> +
>>> +#define A9_COMP_GATE(_name, _reg, _bit) \
>>> +     MESON_COMP_GATE(a9_ao_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
>>> +
>>> +static struct clk_regmap a9_ao_xtal_in = {
>>> +     .data = &(struct clk_regmap_gate_data){
>>> +             .offset = AO_OSCIN_CTRL,
>>> +             .bit_idx = 3,
>>> +     },
>>> +     /*
>>> +      * It may be ao_sys's parent clock, its child clocks mark
>>> +      * CLK_IS_CRITICAL, So mark CLK_IS_CRITICAL for it.
>>> +      */
>> I don't really get what you mean ... Could you rephrase ?
>
>
> The AO sys gate clock chain may be:
>
> ao_xtal_in->ao_xtal->ao_sys-> AO sys gate clocks
>
> "ao_xtal_in" is part of the parent chain of the AO sys gate clocks.
>
> Some of its downstream clocks are marked with CLK_IS_CRITICAL. To ensure
> those clocks remain functional, ao_xtal_in must not be disabled and is
> therefore marked as CLK_IS_CRITICAL as well.

If any of the downstream clocks are critical and marked as such, there is not
need to mark this one as well.

You should only mark the clocks that are actually critical with the flag
and let CCF figure out the dependencies.

>
>
> I will rephrase it like this in the next version:
>
>         /*
>          * ao_sys can select different clock sources. One possible clock
> path is:
>          *      ao_xtal_in->ao_xtal->ao_sys-> ao sys gate clocks
>          *
>          * ao_xtal_in is in the parent chain of AO sys gate clocks.
>          * Since some downstream clocks are marked CLK_IS_CRITICAL,
>          * ao_xtal_in must remain enabled and is therefore marked
>          * CLK_IS_CRITICAL as well.
>          */
>
>>> +     .hw.init = CLK_HW_INIT_FW_NAME("ao_xtal_in", "xtal",
>>> +                                    &clk_regmap_gate_ops, CLK_IS_CRITICAL),
>> I'm honestly not sure about this. It is correct, sure and the macro exist to be
>> used but ... It does not really help readability here, does it ?
>>
>> (I know that was a feedback you've got on v1)
>>
>> Other than that, this looks good to me.
>>
> Ok, I will use the original clk_init_data for this one.

Well my comment applies to whole thing really.

There are surely ways in which the macro but the way we statically
declare things, it adds a level of indirection that makes things harder
to review IMO.

>
>
> [ ... ]
>
>> --
>> Jerome

-- 
Jerome


^ permalink raw reply

* Re: [PATCH v2 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone
From: Will Deacon @ 2026-06-10 12:23 UTC (permalink / raw)
  To: Vincent Donnefort
  Cc: Sebastian Ene, catalin.marinas, maz, oupton, joey.gouly, korneld,
	kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
	mrigendra.chaubey, perlarsen, suzuki.poulose, yuzenghui
In-Reply-To: <ailVcN-bxY30-XBF@google.com>

On Wed, Jun 10, 2026 at 01:15:44PM +0100, Vincent Donnefort wrote:
> On Wed, Jun 10, 2026 at 11:15:14AM +0100, Will Deacon wrote:
> > On Wed, Jun 10, 2026 at 10:26:59AM +0100, Vincent Donnefort wrote:
> > > On Mon, Jun 08, 2026 at 04:55:42PM +0000, Sebastian Ene wrote:
> > > > Remove the FFA_NOTIFICATION* calls from the blocklist used by the pKVM
> > > > FF-A proxy. This restriction was preventing the use of asynchronous
> > > > signaling mechanisms defined by the Arm FF-A specification to
> > > > communicate with the secure services.
> > > > While these calls are markes as optional, there is no reason why the
> > > > hypervisor proxy would block them because:
> > > > 
> > > > 1. Host is the Sole Non-Secure Endpoint: The Host operates as the
> > > >    only Non-Secure VM ID (VM ID 0) recognized by the Secure World.
> > > >    Because all forwarded notifications are inherently attributed to
> > > >    the Host by the SPMC, there is no risk of VM ID spoofing
> > > >    originating from the Normal World.
> > > > 
> > > > 2. No Memory Pointers or Addresses: The FFA_NOTIFICATION_* ABIs
> > > >    operate strictly via register-based parameters, passing only
> > > >    VM IDs, VCPU IDs, flags, and bitmaps. Because these calls do
> > > >    not contain memory addresses, offsets, or pointers, forwarding
> > > >    them doesn't pose a risk of memory-based confused deputy attack
> > > >    (e.g., tricking the SPMC into overwriting protected memory).
> > > > 
> > > > While the pKVM proxy behaves as a relayer, it doesn't currently have its
> > > > own FF-A ID(only the host has the ID 0). The behavior of the setup
> > > > flow is covered by the spec in the: '10.9 Notification support without
> > > > a Hypervisor'.
> > > 
> > > As it is only a relayer. Is it really important to check SBZ arguments and
> > > fields on behalf of Trustzone? It doesn't feel it brings any security. If the
> > > host passes broken arguments, I don't believe this puts pKVM at risk. Does it? 
> > 
> > I think the problem would be if an update to FF-A allocated some of the
> > currently SBZ bits to implement some functionality that we would want
> > to filter at EL2.
> 
> I suppose that would bump the FF-A version and the proxy would reject it?

Maybe? I don't think they'd _have_ to bump the version number.

> If we really want to check for those arguments to be 0:
> 
>  * Shouldn't we extend this check to other FF-A invocations?

yes, that's what the diff was doing in the reply here:

https://lore.kernel.org/all/af3fW468-f1KXCrC@google.com/

but, as I said here:

https://lore.kernel.org/all/ahmxiFXXTupafbXw@willie-the-truck/

I don't particularly like the table-driven indirection (the checks
should just be inlined).

>  * Do we really want to also look into the !SBZ arguments to verify what we can?
>    (I'm thinking about the checks on flags)

For known arguments, we only need to verify things that can affect EL2.
I suspect we don't care about a bunch of it.

Will


^ permalink raw reply

* Re: [PATCH v2 0/7] KVM: arm64: Forward FFA_NOTIFICATION* calls to TrustZone
From: Vincent Donnefort @ 2026-06-10 12:15 UTC (permalink / raw)
  To: Will Deacon
  Cc: Sebastian Ene, catalin.marinas, maz, oupton, joey.gouly, korneld,
	kvmarm, linux-arm-kernel, linux-kernel, android-kvm,
	mrigendra.chaubey, perlarsen, suzuki.poulose, yuzenghui
In-Reply-To: <aik5MtvOlnQDmzjr@willie-the-truck>

On Wed, Jun 10, 2026 at 11:15:14AM +0100, Will Deacon wrote:
> On Wed, Jun 10, 2026 at 10:26:59AM +0100, Vincent Donnefort wrote:
> > On Mon, Jun 08, 2026 at 04:55:42PM +0000, Sebastian Ene wrote:
> > > Remove the FFA_NOTIFICATION* calls from the blocklist used by the pKVM
> > > FF-A proxy. This restriction was preventing the use of asynchronous
> > > signaling mechanisms defined by the Arm FF-A specification to
> > > communicate with the secure services.
> > > While these calls are markes as optional, there is no reason why the
> > > hypervisor proxy would block them because:
> > > 
> > > 1. Host is the Sole Non-Secure Endpoint: The Host operates as the
> > >    only Non-Secure VM ID (VM ID 0) recognized by the Secure World.
> > >    Because all forwarded notifications are inherently attributed to
> > >    the Host by the SPMC, there is no risk of VM ID spoofing
> > >    originating from the Normal World.
> > > 
> > > 2. No Memory Pointers or Addresses: The FFA_NOTIFICATION_* ABIs
> > >    operate strictly via register-based parameters, passing only
> > >    VM IDs, VCPU IDs, flags, and bitmaps. Because these calls do
> > >    not contain memory addresses, offsets, or pointers, forwarding
> > >    them doesn't pose a risk of memory-based confused deputy attack
> > >    (e.g., tricking the SPMC into overwriting protected memory).
> > > 
> > > While the pKVM proxy behaves as a relayer, it doesn't currently have its
> > > own FF-A ID(only the host has the ID 0). The behavior of the setup
> > > flow is covered by the spec in the: '10.9 Notification support without
> > > a Hypervisor'.
> > 
> > As it is only a relayer. Is it really important to check SBZ arguments and
> > fields on behalf of Trustzone? It doesn't feel it brings any security. If the
> > host passes broken arguments, I don't believe this puts pKVM at risk. Does it? 
> 
> I think the problem would be if an update to FF-A allocated some of the
> currently SBZ bits to implement some functionality that we would want
> to filter at EL2.

I suppose that would bump the FF-A version and the proxy would reject it?

If we really want to check for those arguments to be 0:

 * Shouldn't we extend this check to other FF-A invocations?

 * Do we really want to also look into the !SBZ arguments to verify what we can?
   (I'm thinking about the checks on flags)

> 
> Will


^ permalink raw reply

* Re: [PATCH v1] arm64: errata: Mitigate TLBI errata on NVIDIA Olympus CPU
From: Will Deacon @ 2026-06-10 12:14 UTC (permalink / raw)
  To: Catalin Marinas, linux-arm-kernel, Mark Rutland,
	Shanker Donthineni
  Cc: kernel-team, Will Deacon, linux-kernel, linux-doc, Vikram Sethi,
	Jason Sequeira, Alok Mooley, Rich Wiley
In-Reply-To: <20260609234044.3945938-1-sdonthineni@nvidia.com>

On Tue, 09 Jun 2026 18:40:44 -0500, Shanker Donthineni wrote:
> NVIDIA Olympus cores are affected by the TLBI completion issue tracked as
> CVE-2025-10263. The existing ARM64_ERRATUM_4118414 handling already uses
> ARM64_WORKAROUND_REPEAT_TLBI to issue an additional broadcast TLBI;DSB
> sequence and ensure affected memory write effects are globally observed.
> 
> Add MIDR_NVIDIA_OLYMPUS to the repeat-TLBI match list so the same
> mitigation is enabled on affected Olympus systems. Also document the
> NVIDIA Olympus erratum in the arm64 silicon errata table and list it in
> the Kconfig help text.
> 
> [...]

Applied to arm64 (for-next/errata), thanks!

[1/1] arm64: errata: Mitigate TLBI errata on NVIDIA Olympus CPU
      https://git.kernel.org/arm64/c/ec7216f92e4e

Cheers,
-- 
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev


^ permalink raw reply

* Re: [PATCH 0/3] arm64: errata: Mitigate TLBI errata on various Arm CPUs
From: Will Deacon @ 2026-06-10 12:14 UTC (permalink / raw)
  To: linux-arm-kernel, Mark Rutland
  Cc: catalin.marinas, kernel-team, Will Deacon, easwar.hariharan
In-Reply-To: <20260609101203.1512409-1-mark.rutland@arm.com>

On Tue, 09 Jun 2026 11:12:00 +0100, Mark Rutland wrote:
> A number of CPUs developed by Arm suffer from errata whereby a broadcast
> TLBI;DSB sequence may complete before the global observation of writes
> which are translated by an affected TLB entry.
> 
> The ARM64_WORKAROUND_REPEAT_TLBI workaround is sufficient to mitigate
> the issue. This series enables the workaround on affected parts,
> requiring the addition of MIDR values for C1-Ultra and C1-Premium.
> 
> [...]

Applied to arm64 (for-next/errata), thanks!

[1/3] arm64: cputype: Add C1-Ultra definitions
      https://git.kernel.org/arm64/c/60349e64a6c6
[2/3] arm64: cputype: Add C1-Premium definitions
      https://git.kernel.org/arm64/c/d28413bfc5a2
[3/3] arm64: errata: Mitigate TLBI errata on various Arm CPUs
      https://git.kernel.org/arm64/c/cfd391e74134

I also pushed a patch on top to enable the workaround for Microsoft
Azure Cobalt 100 CPUs, as fb091ff39479 claims that is bug-compatible
with N2 r0p0 (+Easwar in case I got the erratum number wrong in the
documentation).

Cheers,
-- 
Will

https://fixes.arm64.dev
https://next.arm64.dev
https://will.arm64.dev


^ permalink raw reply

* [PATCH v2] usb: gadget: aspeed_udc: check endpoint DMA allocation
From: Ruoyu Wang @ 2026-06-10 12:10 UTC (permalink / raw)
  To: Neal Liu, Greg Kroah-Hartman
  Cc: Joel Stanley, Andrew Jeffery, linux-aspeed, linux-usb,
	linux-arm-kernel, linux-kernel, Ruoyu Wang
In-Reply-To: <20260608081948.3-1-ruoyuw560@gmail.com>

ast_udc_probe() allocates a coherent DMA buffer used as the backing store
for endpoint buffers. ast_udc_init_ep() derives per-endpoint buffer
pointers from udc->ep0_buf, so a failed allocation is dereferenced during
probe.

Check the allocation before endpoint setup. The existing probe error path
called ast_udc_remove(), which unregisters the gadget unconditionally and
is not safe before usb_add_gadget_udc() succeeds. Add a local cleanup
helper for probe failures so pre-registration failures only unwind the
resources that were actually initialized.

This was found by a local static analysis checker for unchecked allocator
returns while scanning Linux 6.16. The change was checked by applying it
to current mainline and by running checkpatch. I do not have access to
Aspeed UDC hardware, so no runtime testing was performed.

Fixes: 055276c13205 ("usb: gadget: add Aspeed ast2600 udc driver")
Signed-off-by: Ruoyu Wang <ruoyuw560@gmail.com>
---
Note: a 2022 patch attempted to add only a NULL check for this
allocation:
https://lore.kernel.org/all/20221213025120.23149-1-jiasheng@iscas.ac.cn/

This version also fixes the probe unwind path so the clock is disabled
on allocation failure and usb_del_gadget_udc() is not called before the
gadget has been registered.

v1:
https://lore.kernel.org/all/20260608081948.3-1-ruoyuw560@gmail.com/

Changes in v2:
- Simplify the allocation-failure cleanup path as suggested by Andrew
  Jeffery: disable the clock in the allocation-failure branch and let
  err_cleanup fall through to err.

diff --git a/drivers/usb/gadget/udc/aspeed_udc.c b/drivers/usb/gadget/udc/aspeed_udc.c
--- a/drivers/usb/gadget/udc/aspeed_udc.c
+++ b/drivers/usb/gadget/udc/aspeed_udc.c
@@ -1434,25 +1434,12 @@ static void ast_udc_init_hw(struct ast_u
 	ast_udc_write(udc, 0, AST_UDC_EP0_CTRL);
 }
 
-static void ast_udc_remove(struct platform_device *pdev)
+static void ast_udc_cleanup(struct platform_device *pdev)
 {
 	struct ast_udc_dev *udc = platform_get_drvdata(pdev);
 	unsigned long flags;
 	u32 ctrl;
 
-	usb_del_gadget_udc(&udc->gadget);
-	if (udc->driver) {
-		/*
-		 * This is broken as only some cleanup is skipped, *udev is
-		 * freed and the register mapping goes away. Any further usage
-		 * probably crashes. Also the device is unbound, so the skipped
-		 * cleanup is never catched up later.
-		 */
-		dev_alert(&pdev->dev,
-			  "Driver is busy and still going away. Fasten your seat belts!\n");
-		return;
-	}
-
 	spin_lock_irqsave(&udc->lock, flags);
 
 	/* Disable upstream port connection */
@@ -1472,6 +1459,26 @@ static void ast_udc_remove(struct platfo
 	udc->ep0_buf = NULL;
 }
 
+static void ast_udc_remove(struct platform_device *pdev)
+{
+	struct ast_udc_dev *udc = platform_get_drvdata(pdev);
+
+	usb_del_gadget_udc(&udc->gadget);
+	if (udc->driver) {
+		/*
+		 * This is broken as only some cleanup is skipped, *udev is
+		 * freed and the register mapping goes away. Any further usage
+		 * probably crashes. Also the device is unbound, so the skipped
+		 * cleanup is never catched up later.
+		 */
+		dev_alert(&pdev->dev,
+			  "Driver is busy and still going away. Fasten your seat belts!\n");
+		return;
+	}
+
+	ast_udc_cleanup(pdev);
+}
+
 static int ast_udc_probe(struct platform_device *pdev)
 {
 	enum usb_device_speed max_speed;
@@ -1524,6 +1531,12 @@ static int ast_udc_probe(struct platform
 					  AST_UDC_NUM_ENDPOINTS,
 					  &udc->ep0_buf_dma, GFP_KERNEL);
 
+	if (!udc->ep0_buf) {
+		clk_disable_unprepare(udc->clk);
+		rc = -ENOMEM;
+		goto err;
+	}
+
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
 	udc->gadget.max_speed = USB_SPEED_HIGH;
 	udc->creq = udc->reg + AST_UDC_SETUP0;
@@ -1553,20 +1566,20 @@ static int ast_udc_probe(struct platform
 	udc->irq = platform_get_irq(pdev, 0);
 	if (udc->irq < 0) {
 		rc = udc->irq;
-		goto err;
+		goto err_cleanup;
 	}
 
 	rc = devm_request_irq(&pdev->dev, udc->irq, ast_udc_isr, 0,
 			      KBUILD_MODNAME, udc);
 	if (rc) {
 		dev_err(&pdev->dev, "Failed to request interrupt\n");
-		goto err;
+		goto err_cleanup;
 	}
 
 	rc = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (rc) {
 		dev_err(&pdev->dev, "Failed to add gadget udc\n");
-		goto err;
+		goto err_cleanup;
 	}
 
 	dev_info(&pdev->dev, "Initialized udc in USB%s mode\n",
@@ -1574,9 +1587,10 @@ static int ast_udc_probe(struct platform
 
 	return 0;
 
+err_cleanup:
+	ast_udc_cleanup(pdev);
 err:
 	dev_err(&pdev->dev, "Failed to udc probe, rc:0x%x\n", rc);
-	ast_udc_remove(pdev);
 
 	return rc;
 }


^ permalink raw reply

* Re: [PATCH v2 1/7] KVM: arm64: Support FFA_NOTIFICATION_BITMAP_CREATE in host handler
From: Vincent Donnefort @ 2026-06-10 11:59 UTC (permalink / raw)
  To: Sebastian Ene
  Cc: catalin.marinas, maz, oupton, will, joey.gouly, korneld, kvmarm,
	linux-arm-kernel, linux-kernel, android-kvm, mrigendra.chaubey,
	perlarsen, suzuki.poulose, yuzenghui
In-Reply-To: <aiklq5QvztNk8FZR@google.com>

On Wed, Jun 10, 2026 at 09:51:55AM +0100, Vincent Donnefort wrote:
> Hi Seb,
> 
> On Mon, Jun 08, 2026 at 04:55:43PM +0000, Sebastian Ene wrote:
> > Allow FF-A notification bitmap creation messages to be forwarded to
> > Trustzone from the host and introduce a helper to check for SBZ
> > register fields.
> > 
> > Signed-off-by: Sebastian Ene <sebastianene@google.com>
> > ---
> >  arch/arm64/kvm/hyp/nvhe/ffa.c | 36 ++++++++++++++++++++++++++++++++++-
> >  1 file changed, 35 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/kvm/hyp/nvhe/ffa.c b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > index 1af722771178..c20d45191085 100644
> > --- a/arch/arm64/kvm/hyp/nvhe/ffa.c
> > +++ b/arch/arm64/kvm/hyp/nvhe/ffa.c
> > @@ -71,6 +71,18 @@ static u32 hyp_ffa_version;
> >  static bool has_version_negotiated;
> >  static hyp_spinlock_t version_lock;
> >  
> > +static bool ffa_check_unused_args_sbz(struct kvm_cpu_context *ctxt, int first_reg)
> > +{
> > +	int reg;
> > +
> > +	for (reg = first_reg; reg < 17; reg++) {
> 
> The upper limit should probably be something like ARRAY_SIZE(ctx->regs.regs) - first_reg?

I wasn't really inspired this morning on the cruiser...

But nonetheless, that 17 should probably be a #define somewhere?
> 
> > +		if (cpu_reg(ctxt, reg))
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> >  static void ffa_to_smccc_error(struct arm_smccc_1_2_regs *res, u64 ffa_errno)
> >  {
> >  	*res = (struct arm_smccc_1_2_regs) {
> > @@ -676,7 +688,6 @@ static bool ffa_call_supported(u64 func_id)
> >  	case FFA_MEM_DONATE:
> >  	case FFA_MEM_RETRIEVE_REQ:
> >         /* Optional notification interfaces added in FF-A 1.1 */
> > -	case FFA_NOTIFICATION_BITMAP_CREATE:
> >  	case FFA_NOTIFICATION_BITMAP_DESTROY:
> >  	case FFA_NOTIFICATION_BIND:
> >  	case FFA_NOTIFICATION_UNBIND:
> > @@ -862,6 +873,26 @@ static void do_ffa_part_get(struct arm_smccc_1_2_regs *res,
> >  	hyp_spin_unlock(&host_buffers.lock);
> >  }
> >  
> > +static void do_ffa_notif_bitmap_create(struct arm_smccc_1_2_regs *res,
> > +				       struct kvm_cpu_context *ctxt)
> > +{
> > +	DECLARE_REG(u32, vmid, ctxt, 1);
> > +	struct arm_smccc_1_2_regs *args;
> > +
> > +	if (ffa_check_unused_args_sbz(ctxt, 3)) {
> 
> Is that expected we start at 3 but only read 0 and 1?

Ha, we do not read 2 but nonetheless it is useful!

> 
> > +		ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > +		return;
> > +	}
> > +
> > +	if (vmid != HOST_FFA_ID) {
> > +		ffa_to_smccc_res(res, FFA_RET_INVALID_PARAMETERS);
> > +		return;
> > +	}
> > +
> > +	args = (void *)&ctxt->regs.regs[0];
> > +	arm_smccc_1_2_smc(args, res);
> 
> Should be hyp_smccc_1_2_smc()
> 
> > +}
> > +
> >  bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> >  {
> >  	struct arm_smccc_1_2_regs res;
> > @@ -920,6 +951,9 @@ bool kvm_host_ffa_handler(struct kvm_cpu_context *host_ctxt, u32 func_id)
> >  	case FFA_PARTITION_INFO_GET:
> >  		do_ffa_part_get(&res, host_ctxt);
> >  		goto out_handled;
> > +	case FFA_NOTIFICATION_BITMAP_CREATE:
> > +		do_ffa_notif_bitmap_create(&res, host_ctxt);
> > +		goto out_handled;
> >  	}
> >  
> >  	if (ffa_call_supported(func_id))
> > -- 
> > 2.54.0.1064.gd145956f57-goog
> > 


^ permalink raw reply

* iio: adc: KASAN wild-memory-access in complete() on early IRQ
From: Jaeyoung Chung @ 2026-06-10 11:57 UTC (permalink / raw)
  To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Vladimir Zapolskiy, Piotr Wojtaszczyk
  Cc: Jaeyoung Chung, linux-iio, linux-arm-kernel, linux-kernel,
	Sangyun Kim, Kyungwook Boo

Hi,

lpc32xx_adc_probe() in drivers/iio/adc/lpc32xx_adc.c and
spear_adc_probe() in drivers/iio/adc/spear_adc.c register their
interrupt handler with devm_request_irq() before they initialize
st->completion with init_completion(). If an interrupt arrives after
devm_request_irq() and before init_completion(), the handler calls
complete() on an uninitialized completion, causing a kernel panic.

The probe path, in lpc32xx_adc_probe():

    iodev = devm_iio_device_alloc(&pdev->dev, sizeof(*st)); /* st kzalloc-zeroed */
    ...
    retval = devm_request_irq(&pdev->dev, irq, lpc32xx_adc_isr, 0,
                              LPC32XXAD_NAME, st);           /* register handler */
    ...
    init_completion(&st->completion);                       /* initialize completion */

spear_adc_probe() has the same ordering: devm_request_irq() for
spear_adc_isr() before init_completion(&st->completion).

Both interrupt handlers, lpc32xx_adc_isr() and spear_adc_isr(), call
complete():

    complete(&st->completion);

If the device raises an interrupt before init_completion() runs,
complete() acquires the uninitialized wait.lock and walks the zeroed
task_list in swake_up_locked(). The zeroed task_list makes list_empty()
return false, so swake_up_locked() dereferences a NULL list entry,
triggering a KASAN wild-memory-access.

Suggested fix: move init_completion(&st->completion) above
devm_request_irq(), so the completion is valid before the handler can run.

Reported-by: Sangyun Kim <sangyun.kim@snu.ac.kr>
Reported-by: Kyungwook Boo <bookyungwook@gmail.com>

Thanks,
Jaeyoung Chung


^ 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