Devicetree
 help / color / mirror / Atom feed
* RE: [PATCH v4 3/5] dt-bindings: clock: cix,sky1-audss-clock: add audss clock controller
From: Joakim  Zhang @ 2026-06-18  9:27 UTC (permalink / raw)
  To: Philipp Zabel, Conor Dooley
  Cc: mturquette@baylibre.com, sboyd@kernel.org, bmasney@redhat.com,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Gary Yang, cix-kernel-upstream, linux-clk@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <cd63c1ab9831fdfd39aad8d1a40c4702a9cbb158.camel@pengutronix.de>


Hello,


> -----Original Message-----
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Sent: Thursday, June 18, 2026 4:30 PM
> To: Joakim Zhang <joakim.zhang@cixtech.com>; Conor Dooley
> <conor@kernel.org>
> Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; Gary Yang
> <Gary.Yang@cixtech.com>; cix-kernel-upstream <cix-kernel-
> upstream@cixtech.com>; linux-clk@vger.kernel.org;
> devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
> kernel@lists.infradead.org
> Subject: Re: [PATCH v4 3/5] dt-bindings: clock: cix,sky1-audss-clock: add audss
> clock controller
> 
> EXTERNAL EMAIL
> 
> CAUTION: Suspicious Email from unusual domain.
> 
> On Do, 2026-06-18 at 01:43 +0000, Joakim  Zhang wrote:
> > Hello,
> >
> >
> > > -----Original Message-----
> > > From: Conor Dooley <conor@kernel.org>
> > > Sent: Wednesday, June 17, 2026 11:56 PM
> > > To: Joakim Zhang <joakim.zhang@cixtech.com>
> > > Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> > > robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> > > p.zabel@pengutronix.de; Gary Yang <gary.yang@cixtech.com>;
> > > cix-kernel- upstream <cix-kernel-upstream@cixtech.com>;
> > > linux-clk@vger.kernel.org; devicetree@vger.kernel.org;
> > > linux-kernel@vger.kernel.org; linux-arm- kernel@lists.infradead.org
> > > Subject: Re: [PATCH v4 3/5] dt-bindings: clock:
> > > cix,sky1-audss-clock: add audss clock controller
> > >
> > > On Wed, Jun 17, 2026 at 02:04:35PM +0800, joakim.zhang@cixtech.com
> wrote:
> > > > From: Joakim Zhang <joakim.zhang@cixtech.com>
> > > >
> > > > The AUDSS CRU contains an internal clock tree of muxes, dividers
> > > > and gates for DSP, I2S, HDA, DMAC and related blocks. The clock
> > > > provider is a child node of the cix,sky1-audss-system-control
> > > > syscon and accesses registers through the parent MMIO region.
> > >
> > > Why can this not just be part of the parent syscon node?
> >
> > The clock and reset blocks are handled by different subsystems and
> maintainers (clk vs reset). Putting the clock provider on the parent syscon node
> would mean a single driver has to register both the reset controller and the
> clock provider on one device, which doesn't fit well.
> 
> There are many examples of clock and reset drivers sharing the same node, by
> using platform_driver for one (usually clk) and auxiliary_driver for the other
> (usually reset).

OK, I will have a look.  If you are also prefer to this, I will refactor the patch.

Thanks,
Joakim

^ permalink raw reply

* Re: [PATCH v2 2/6] iommu/arm-smmu: Add interconnect bandwidth voting support
From: Konrad Dybcio @ 2026-06-18  9:28 UTC (permalink / raw)
  To: Bibek Kumar Patro, Dmitry Baryshkov
  Cc: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
	linux-arm-kernel, iommu, devicetree, linux-kernel, linux-arm-msm
In-Reply-To: <ea345832-711d-4e32-af0f-bc74d8646aef@oss.qualcomm.com>

On 6/17/26 4:26 PM, Bibek Kumar Patro wrote:
> 
> 
> On 6/16/2026 5:51 AM, Dmitry Baryshkov wrote:
>> On Mon, Jun 15, 2026 at 06:36:51PM +0530, Bibek Kumar Patro wrote:
>>>
>>>
>>> On 6/8/2026 7:25 PM, Dmitry Baryshkov wrote:
>>>> On Tue, May 26, 2026 at 08:12:03PM +0530, Bibek Kumar Patro wrote:
>>>>> On some SoCs the SMMU registers require an active interconnect
>>>>> bandwidth vote to be accessible. While other clients typically
>>>>> satisfy this requirement implicitly, certain corner cases (e.g.
>>>>> during sleep/wakeup transitions) can leave the SMMU without a
>>>>> vote, causing intermittent register access failures.
>>>>>
>>>>> Add support for an optional interconnect path to the arm-smmu
>>>>> driver and vote for bandwidth while the SMMU is active. The path
>>>>> is acquired from DT if present and ignored otherwise.
>>>>>
>>>>> The bandwidth vote is enabled before accessing SMMU registers
>>>>> during probe and runtime resume, and released during runtime
>>>>> suspend and on error paths.
>>>>>
>>>>> Generally, from an architectural perspective, GEM_NOC and DDR are
>>>>> expected to have an active vote whenever the adreno_smmu block is
>>>>> powered on. In most common use cases, this requirement is implicitly
>>>>> satisfied because other GPU-related clients (for example, the GMU
>>>>> device) already hold a GEM_NOC vote when adreno_smmu is enabled.
>>>>>
>>>>> However, there are certain corner cases, such as during sleep/wakeup
>>>>> transitions, where the GEM_NOC vote can be removed before adreno_smmu
>>>>> is powered down. If adreno_smmu is then accessed while the interconnect
>>>>> vote is missing, it can lead to the observed failures. Because of the
>>>>> precise ordering involved, this scenario is difficult to reproduce
>>>>> consistently.
>>>>> (also GDSC is involved in adreno usecases can have an independent vote)
>>>>>
>>>>> Signed-off-by: Bibek Kumar Patro <bibek.patro@oss.qualcomm.com>
>>>>> ---
>>>>>    drivers/iommu/arm/arm-smmu/arm-smmu.c | 57 +++++++++++++++++++++++++++++++++--
>>>>>    drivers/iommu/arm/arm-smmu/arm-smmu.h |  2 ++
>>>>>    2 files changed, 57 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/drivers/iommu/arm/arm-smmu/arm-smmu.c b/drivers/iommu/arm/arm-smmu/arm-smmu.c
>>>>> index 0bd21d206eb3e75c3b9fb1364cdc92e82c5aa499..07c7e44ec6a5bd1488f00f87d859a20495e46601 100644
>>>>> --- a/drivers/iommu/arm/arm-smmu/arm-smmu.c
>>>>> +++ b/drivers/iommu/arm/arm-smmu/arm-smmu.c
>>>>> @@ -53,6 +53,11 @@
>>>>>    #define MSI_IOVA_BASE            0x8000000
>>>>>    #define MSI_IOVA_LENGTH            0x100000
>>>>> +/* Interconnect bandwidth vote values for the SMMU register access path */
>>>>> +#define ARM_SMMU_ICC_AVG_BW        0
>>>>> +#define ARM_SMMU_ICC_PEAK_BW_HIGH    1000
>>>>
>>>> totally random numbers, which might be different for non-Qualcomm platform.
>>>>
>>>
>>> Ideally, any non-zero value would be enough to keep the path active.
>>
>> This is true for Qualcomm devices. However, you are adding this to a
>> generic code.
>>
>>> Here 1 Would be enough to keep the path active, but might be too small to
>>> reliably keep the bus active.
>>> Other is UINT_MAX, which will reliably keep the bus active but might cause a
>>> power penalty.
>>>
>>> #define ARM_SMMU_ICC_PEAK_BW_HIGH    UINT_MAX
>>>
>>> seems to be suitable here to reliably keep the bus active by BCM
>>> for both Qualcomm and non-Qualcomm platforms (with some power penalty).
>>>
>>> LMK, if you feel otherwise.
>>
>> Shift it to the qcom instance or provide platform-specific values? (My
>> preference would be towards the first solution).
>>
> 
> 
> To support platform-specific values, we may need to introduce a LUT-based approach in the driver. (Bandwidth voting values cannot be placed in device-tree property IIRC ?)
> 
> Currently, all Qualcomm platforms use 0x1000 for SMMU ICC voting. I

(you used decimal 1000)

> can evaluate if this could be moved to a Qualcomm-specific
> implementation.

Add a vendor hook to arm_smmu_runtime_suspend/resume and handle it within
the QC driver

Konrad

^ permalink raw reply

* Re: [PATCH v7 2/3] arm64: dts: imx95: Add dma, intr, aer and pme interrupts for PCIe
From: sashiko-bot @ 2026-06-18  9:30 UTC (permalink / raw)
  To: hongxing.zhu; +Cc: linux-pci, devicetree, Frank.Li, robh, conor+dt, imx
In-Reply-To: <20260618092100.3669556-3-hongxing.zhu@oss.nxp.com>

> From: Richard Zhu <hongxing.zhu@nxp.com>
> 
> The current PCIe device tree configuration only defines the MSI
> interrupt, which is sufficient for basic PCIe operation but limits
> advanced functionality.
> 
> Add the following interrupt lines to pcie0 and pcie1 nodes:
> - dma: DMA interrupt for PCIe DMA operations
> - intr: General controller events and link state changes
> - aer: Advanced Error Reporting interrupt
> - pme: Power Management Event interrupt
> 
> This enables enhanced PCIe features and capabilities that were
> previously unavailable due to missing interrupt definitions.
> 
> Signed-off-by: Richard Zhu <hongxing.zhu@nxp.com>

Sashiko has reviewed this patch and found no issues. It looks great!

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260618092100.3669556-1-hongxing.zhu@oss.nxp.com?part=2


^ permalink raw reply

* Re: [PATCH v7 1/3] dt-bindings: imx6q-pcie: Add optional intr/aer/pme interrupts for i.MX95
From: sashiko-bot @ 2026-06-18  9:31 UTC (permalink / raw)
  To: hongxing.zhu; +Cc: robh, linux-pci, imx, conor+dt, devicetree, Frank.Li
In-Reply-To: <20260618092100.3669556-2-hongxing.zhu@oss.nxp.com>

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] Strict positional matching for optional interrupts prevents their independent omission.
--

commit 9eb344928f835976645ead8f4c2aff3678bedbd2
Author: Richard Zhu <hongxing.zhu@nxp.com>

dt-bindings: imx6q-pcie: Add optional intr/aer/pme interrupts for i.MX95

The i.MX95 PCIe controller introduces three additional dedicated hardware
interrupt lines for specific events. These interrupts are optional on i.MX95,
so the binding is updated to allow up to 5 interrupts for i.MX95 while
restricting earlier variants to a maximum of 2 interrupts.

> diff --git a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
> index e8b8131f5f23b..4f56e8e4f1008 100644
> --- a/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml
> +++ b/Documentation/devicetree/bindings/pci/fsl,imx6q-pcie.yaml

[ ... ]

>    interrupt-names:
>      minItems: 1
>      items:
>        - const: msi
>        - const: dma
> +      - const: intr
> +      - const: aer
> +      - const: pme

[Severity: Low]
Since dma and the new interrupts are optional, what happens if a valid sparse
configuration provides msi and intr, but omits dma?

The items list creates a strict positional tuple. Wouldn't a device tree
that provides msi and intr fail validation because the string intr at index 1
will be incorrectly checked against const: dma?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260618092100.3669556-1-hongxing.zhu@oss.nxp.com?part=1

^ permalink raw reply

* Re: [PATCH v7 3/3] PCI: imx6: Add root port reset to support link recovery
From: sashiko-bot @ 2026-06-18  9:34 UTC (permalink / raw)
  To: hongxing.zhu; +Cc: robh, conor+dt, Frank.Li, linux-pci, imx, devicetree
In-Reply-To: <20260618092100.3669556-4-hongxing.zhu@oss.nxp.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [High] Using read-modify-write operations on a mixed RW/W1C register unintentionally clears pending hardware interrupts.
- [High] The ISR unconditionally clears the link down status bit even if the interrupt is disabled, dropping shared link recovery events.
- [High] Unsafe, lockless iteration over the PCI bus devices list without holding pci_bus_sem.
- [High] The threaded interrupt handler is not synchronized during system shutdown, leading to a race condition with controller power-off.
- [High] Accessing shared LUT GPR registers without acquiring imx_pcie->lock causes a data race.
- [Medium] The `imx_pcie_reset_root_port` function silently ignores failures to recover the PCIe link.
- [Low] The patch references undeclared functions and undefined struct members, causing build failures.
--

commit 1a657928e9eb6aa6da8f1cc80545e5be5d066898
Author: Richard Zhu <hongxing.zhu@nxp.com>

PCI: imx6: Add root port reset to support link recovery

The PCIe link can go down due to various unexpected circumstances. Add
root port reset support to enable link recovery for the i.MX PCIe
controller when the optional "intr" interrupt is present.

> diff --git a/drivers/pci/controller/dwc/pci-imx6.c b/drivers/pci/controller/dwc/pci-imx6.c
> index 98e1db751132a..b38eb61983e15 100644
> --- a/drivers/pci/controller/dwc/pci-imx6.c
> +++ b/drivers/pci/controller/dwc/pci-imx6.c

[ ... ]

> @@ -1442,6 +1450,13 @@ static int imx_pcie_host_init(struct dw_pcie_rp *pp)
>  
>  	imx_setup_phy_mpll(imx_pcie);
>  
> +	/*
> +	 * Callback invoked by PCI core when link down is detected and
> +	 * recovery is needed.
> +	 */
> +	if (pp->bridge)
> +		pp->bridge->reset_root_port = imx_pcie_reset_root_port;

[Severity: Low]
Is reset_root_port defined in struct pci_host_bridge? Looking at
include/linux/pci.h, this member does not appear to exist in the standard
kernel. Does this patch depend on a prerequisite patch that adds it?

[ ... ]

> @@ -1774,6 +1795,86 @@ static const struct dev_pm_ops imx_pcie_pm_ops = {
>  				  imx_pcie_resume_noirq)
>  };
>  
> +static irqreturn_t imx_pcie_lnk_irq_isr(int irq, void *priv)
> +{
> +	struct imx_pcie *imx_pcie = priv;
> +	struct dw_pcie *pci = imx_pcie->pci;
> +	struct device *dev = pci->dev;
> +	u32 val;
> +
> +	regmap_read(imx_pcie->iomuxc_gpr, IMX95_LINK_INT_CTRL_STS, &val);
> +	if (val & IMX95_LINK_DOWN_INT_STS) {
> +		dev_dbg(dev, "PCIe link down detected, initiating recovery\n");
> +		/* Clear link down interrupt status by writing 1b'1 to it */
> +		regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_LINK_INT_CTRL_STS,
> +				IMX95_LINK_DOWN_INT_STS);
> +		if (!(val & IMX95_LINK_DOWN_INT_EN))
> +			return IRQ_NONE;

[Severity: High]
If this interrupt is shared and masked during thread execution, could this
unconditionally clear a new link down event?

Since the status is cleared before checking IMX95_LINK_DOWN_INT_EN, if a new
event triggers concurrently with the threaded handler, it appears the event
will be cleared and then discarded when the ISR returns IRQ_NONE.

> +		regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_LINK_INT_CTRL_STS,
> +				  IMX95_LINK_DOWN_INT_EN);
> +
> +		return IRQ_WAKE_THREAD;
> +	}
> +
> +	regmap_read(imx_pcie->iomuxc_gpr, IMX95_PE0_INT_STS, &val);
> +	if (unlikely(val))
> +		regmap_write(imx_pcie->iomuxc_gpr, IMX95_PE0_INT_STS, val);
> +
> +	return IRQ_NONE;
> +}
> +
> +static irqreturn_t imx_pcie_lnk_irq_thread(int irq, void *priv)
> +{
> +	struct imx_pcie *imx_pcie = priv;
> +	struct dw_pcie *pci = imx_pcie->pci;
> +	struct dw_pcie_rp *pp = &pci->pp;
> +	struct pci_dev *port;
> +
> +	for_each_pci_bridge(port, pp->bridge->bus)
> +		if (pci_pcie_type(port) == PCI_EXP_TYPE_ROOT_PORT)
> +			pci_host_handle_link_down(port);

[Severity: High]
Is it safe to iterate over the PCI bus devices list asynchronously here without
holding the pci_bus_sem semaphore?

If concurrent PCI enumeration, hotplug device removal, or SR-IOV VF
modifications occur, could this result in list pointer corruption or a
use-after-free?

[Severity: Low]
Also, is pci_host_handle_link_down() declared in the standard kernel headers?
I am unable to find it in include/linux/pci.h, which might cause a build
failure without a prerequisite patch.

> +
> +	regmap_set_bits(imx_pcie->iomuxc_gpr, IMX95_LINK_INT_CTRL_STS,
> +			IMX95_LINK_DOWN_INT_EN);

[Severity: High]
Can regmap_set_bits() unintentionally clear pending hardware interrupts here?

Since regmap_set_bits() performs a read-modify-write, and the
IMX95_LINK_DOWN_INT_STS (BIT 11) is a write-1-to-clear bit, could it
accidentally write back a 1 for a newly arrived link down event and
permanently lose that event?

> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int imx_pcie_reset_root_port(struct pci_host_bridge *bridge,
> +				    struct pci_dev *pdev)
> +{
> +	struct pci_bus *bus = bridge->bus;
> +	struct dw_pcie_rp *pp = bus->sysdata;
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct imx_pcie *imx_pcie = to_imx_pcie(pci);
> +	int ret;
> +
> +	imx_pcie_msi_save_restore(imx_pcie, true);
> +	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
> +		imx_pcie_lut_save(imx_pcie);

[Severity: High]
Does imx_pcie_lut_save() need to acquire the imx_pcie->lock?

Since imx_pcie_reset_root_port() runs asynchronously in the recovery thread,
could this cause a data race on the shared IMX95_PE0_LUT_ACSCTRL index
register if another device probe concurrently calls imx_pcie_add_lut()?

> +	imx_pcie_stop_link(pci);
> +	imx_pcie_host_exit(pp);
> +
> +	ret = imx_pcie_host_init(pp);
> +	if (ret) {
> +		dev_err(pci->dev, "Failed to re-init PCIe\n");
> +		return ret;
> +	}
> +	ret = dw_pcie_setup_rc(pp);
> +	if (ret)
> +		return ret;
> +
> +	imx_pcie_start_link(pci);
> +	dw_pcie_wait_for_link(pci);

[Severity: Medium]
Should the return value of dw_pcie_wait_for_link() be checked and propagated?

If the link fails to come up (for example, returning -ETIMEDOUT because the
endpoint was unplugged), dropping the error allows the function to
unconditionally return 0. Could this leave the system in an inconsistent
state?

> +
> +	if (imx_check_flag(imx_pcie, IMX_PCIE_FLAG_HAS_LUT))
> +		imx_pcie_lut_restore(imx_pcie);

[Severity: High]
Similar to the save function above, does imx_pcie_lut_restore() need to
acquire imx_pcie->lock to prevent data races on the shared LUT index register
during restoration?

[ ... ]

> @@ -1973,15 +2074,46 @@ static int imx_pcie_probe(struct platform_device *pdev)

[ ... ]

>  static void imx_pcie_shutdown(struct platform_device *pdev)
>  {
>  	struct imx_pcie *imx_pcie = platform_get_drvdata(pdev);
>  
> +	if (imx_pcie->lnk_intr > 0)
> +		regmap_clear_bits(imx_pcie->iomuxc_gpr, IMX95_LINK_INT_CTRL_STS,
> +				  IMX95_LINK_DOWN_INT_EN);
>  	/* bring down link, so bootloader gets clean state in case of reboot */
>  	imx_pcie_assert_core_reset(imx_pcie);

[Severity: High]
Can a concurrent threaded interrupt handler run during this shutdown process?

Since disable_irq() is not called, if a link down event triggers just before
shutdown, could the thread access PCIe configuration space right as
pci_pwrctrl_power_off_devices() powers off the hardware, potentially causing a
synchronous external abort?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260618092100.3669556-1-hongxing.zhu@oss.nxp.com?part=3

^ permalink raw reply

* [PATCH v10 0/4] media: nxp: Add CSI Pixel Formatter support
From: guoniu.zhou @ 2026-06-18  9:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
	Michael Turquette, Stephen Boyd
  Cc: imx, linux-media, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, Guoniu Zhou, Frank Li

CSI Pixel Formatter is a module found on i.MX95. It could unpack the
pixels received by the formatter and reformat them to meet the pixel
link format requirement.

This patch series adds a new V4L2 driver for CSI Pixel Formatter.

Background
----------
The Camera CSR binding was upstreamed during the pre-silicon phase when
the hardware integration details were not fully finalized. At that time,
the syscon binding focused on the CSR's primary role as a shared register
provider for clock gating, QoS, and error handling across Camera domain IPs.

However, the Camera CSR hardware is actually a mixed-function register
container with varying control levels over different IP blocks:
- ISP/CSI: Clock gating only
- ISI: QoS configuration
- CSI: Buffer overflow handling
- LPCAC: Error handling only
- ISP: Pixel link selection
- Formatter: Complete IP control (full register set)

Why Child Nodes Now
-------------------
The CSI formatter is unique among these IPs - it's an independent hardware
block whose complete control registers reside within the CSR address
space, not just a few configuration bits. This architectural detail was
not reflected in the original binding because:

1. The pre-silicon binding focused on simple register-level controls
2. The syscon pattern for complete IP control was not initially considered

Discussion with original CSR author(Peng Fan) confirmed this reflects the
intended hardware design that wasn't fully captured during pre-silicon
upstreaming.

v4l2-compliance 1.28.1-5233, 64 bits, 64-bit time_t
v4l2-compliance SHA: fc15e229d9d3 2024-07-23 19:22:15

Compliance test for device /dev/v4l-subdev9:

Driver Info:
	Driver version   : 7.1.0
	Capabilities     : 0x00000002
		Streams Support
	Client Capabilities: 0x0000000000000003
streams interval-uses-which
Required ioctls:
	test VIDIOC_SUDBEV_QUERYCAP: OK
	test invalid ioctls: OK

Allow for multiple opens:
	test second /dev/v4l-subdev9 open: OK
	test VIDIOC_SUBDEV_QUERYCAP: OK
	test for unlimited opens: OK

Debug ioctls:
	test VIDIOC_LOG_STATUS: OK (Not Supported)

Input ioctls:
	test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
	test VIDIOC_ENUMAUDIO: OK (Not Supported)
	test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDIO: OK (Not Supported)
	Inputs: 0 Audio Inputs: 0 Tuners: 0

Output ioctls:
	test VIDIOC_G/S_MODULATOR: OK (Not Supported)
	test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
	test VIDIOC_ENUMAUDOUT: OK (Not Supported)
	test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
	test VIDIOC_G/S_AUDOUT: OK (Not Supported)
	Outputs: 0 Audio Outputs: 0 Modulators: 0

Input/Output configuration ioctls:
	test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
	test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
	test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
	test VIDIOC_G/S_EDID: OK (Not Supported)

Sub-Device routing ioctls:
	test Try VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK
	test Active VIDIOC_SUBDEV_G_ROUTING/VIDIOC_SUBDEV_S_ROUTING: OK

Control ioctls:
	test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
	test VIDIOC_QUERYCTRL: OK (Not Supported)
	test VIDIOC_G/S_CTRL: OK (Not Supported)
	test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
	test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
	test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
	Standard Controls: 0 Private Controls: 0

Format ioctls:
	test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK (Not Supported)
	test VIDIOC_G/S_PARM: OK (Not Supported)
	test VIDIOC_G_FBUF: OK (Not Supported)
	test VIDIOC_G_FMT: OK (Not Supported)
	test VIDIOC_TRY_FMT: OK (Not Supported)
	test VIDIOC_S_FMT: OK (Not Supported)
	test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
	test Cropping: OK (Not Supported)
	test Composing: OK (Not Supported)
	test Scaling: OK (Not Supported)

Codec ioctls:
	test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
	test VIDIOC_G_ENC_INDEX: OK (Not Supported)
	test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)

Buffer ioctls:
	test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK (Not Supported)
	test CREATE_BUFS maximum buffers: OK
	test VIDIOC_REMOVE_BUFS: OK
	test VIDIOC_EXPBUF: OK (Not Supported)
	test Requests: OK (Not Supported)

Total for device /dev/v4l-subdev9: 47, Succeeded: 47, Failed: 0, Warnings: 0

Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
---
Changes in v10:
- Rebase to latest media/next
- [NEW PATCH] Use single quotes consistently (Krzysztof Kozlowski)
- Drop syscon parent node from example
- Drop Reviewed-by tags from Frank and Krzysztof due to binding changes,
  requesting re-review
- Add description for reg property
- Add space after formatter@20 before opening brace in example
- Enhance the port description with more detailed information
- Delete the blank line immediately following the endpoint in example
- Use single quotes for regex pattern to be consistent (Krzysztof Kozlowski)
- Add formatter subnode binding and camera-csr syscon example
- Update commit title and message
- Use u8 for vc in csi_formatter_get_vc() and drop vc < 0 check
- Add MFD_SYSCON dependency to Kconfig
- Fix stream/VC mapping potential mismatch in start/stop_stream functions
- Link to v9: https://lore.kernel.org/r/20260526-csi_formatter-v9-0-ca3d8c334c39@oss.nxp.com

Changes in v9:
- [NEW PATCH] Fix formatter as syscon child node issue
- Link to v8: https://lore.kernel.org/r/20260525-csi_formatter-v8-0-6b646231224b@oss.nxp.com

Changes in v8:
- Rebase to latest media/next
- Use standard port reference instead of video-interfaces.yaml
- Add parent syscon node in example to show device integration
- Remove fmt field and look up format from subdev state instead
- Unify function and structure naming to use csi_formatter_ prefix
- Remove misleading alignment comment from set_fmt function
- Optimize get_frame_desc to call once per start_stream
- Replace V4L2_FRAME_DESC_ENTRY_MAX with CSI_FORMATTER_VC_NUM in loops
- Remove redundant debug message in enable_streams
- Use MEDIA_PAD_FL_MUST_CONNECT flag instead of manual link check
- Link to v7: https://lore.kernel.org/r/20260518-csi_formatter-v7-0-562b750557e3@oss.nxp.com

Changes in v7:
- Change compatible to imx95-csi-formatter as IP is i.MX95 specific per Marco's suggestion
  Link: https://lore.kernel.org/linux-media/20260511-csi_formatter-v6-0-01028e312e2b@oss.nxp.com/T/#mcd135b3de179b3cb69daa1fd6e0e8e27c85b3332
- Update references from imx9 to imx95 for consistency with dt-bindings
- Enable PM runtime before async registration
- Link to v6: https://lore.kernel.org/r/20260511-csi_formatter-v6-0-01028e312e2b@oss.nxp.com

Changes in v6:
- Rebase to latest media/next
- Update v4l2-compliace test
- Remove unused header includes
- Unify macro naming: VCx/VCX -> VC and parameter x -> vc
- Remove unused format field from csi_formatter struct
- Use compact initialization for formats array
- Make find_csi_format() return NULL instead of default format
- Use unsigned int for array index in find_csi_format()
- Add err_ prefix to error handling labels
- Add v4l2_subdev_cleanup() and reorder cleanup sequence
- Update enable_streams debug output format
- Rename VC_MAX to VC_NUM and fix boundary check
- Update CSI formatter Kconfig description
- Use v4l2_subdev_get_frame_desc_passthrough() helper
- Fix error paths in async registration and probe
- Add mutex to protect enabled_streams
- Switch to devm_pm_runtime_enable()
- Remove redundant num_routes check in set_routing
- Optimize get_index_by_dt() and add warning for unsupported type
- csi_formatter_start/stop_stream: Process all streams in mask
- Link to v5: https://lore.kernel.org/r/20260123-csi_formatter-v5-0-d5b803f867bf@nxp.com

Changes in v5:
- Remove CSI_FORMATTER_DRV_NAME macro since only use once.
- Remove sd->owner = THIS_MODULE;
- Simplify code by using DEFINE_RUNTIME_DEV_PM_OPS macro.
- Link to v4: https://lore.kernel.org/r/20260122-csi_formatter-v4-0-6f6fcad1c33a@nxp.com

Changes in v4:
- Rebase to latest media/next.
- Add comments to describe the index field in formatter_dt_to_index_map array.
- Link to v3: https://lore.kernel.org/r/20251219-csi_formatter-v3-0-8680d6d87091@nxp.com

Changes in v3:
- Rename nxp,imx9-csi-formatter.yaml to fsl,imx9-csi-formatter.yaml.
- Drop clock-names property.
- Drop macro IMX95_PD_CAMERA definition and use a constant directly.
  [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings
- Remove the assignment driver.owner = THIS_MODULE.
- Assign struct fwnode_handle *ep __free(fwnode_handle) when definition.
- Update yaml file name for csi formatter in MAINTAINERS.
  [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver
- Link to v2: https://lore.kernel.org/r/20251217-csi_formatter-v2-0-62168af80210@nxp.com

Changes in v2:
- Delete "|" for description key. 
- Add empty line between child node and property.
- Delete labels for endpoint of child nodes.
  [PATCH 1/2] media: dt-bindings: Add CSI Pixel Formatter DT bindings

- Update commit message.
- Use the value defined by bellow macros directly since they are used only once.
  #define CSI_FORMATTER_DEF_MBUS_CODE	MEDIA_BUS_FMT_UYVY8_1X16
  #define CSI_FORMATTER_DEF_PIX_WIDTH	1920U
  #define CSI_FORMATTER_DEF_PIX_HEIGHT	1080U
  #define CSI_FORMATTER_MAX_PIX_WIDTH	0xffff
  #define CSI_FORMATTER_MAX_PIX_HEIGHT	0xffff
- Use macro pm_ptr() to fix build warning when CONFIG_PM is disabled. 
- Finish route loop by break statement, instead of goto.
- Return dev_err_probe() when meet errors in probe() function instead of dev_err().
- Remove MODULE_ALIAS().
- Refine .enable(.dsable)_stream callback implementation, include bellow changes:
  Add stream checking.
  Fix potential pm runtime count unbalance issue.
  Add stop stream error handling when enabling remote subdev stream.
- Use __free(fwnode_handle) to drop reference to a device node automatically.
  [PATCH 2/2] media: nxp: Add i.MX9 CSI pixel formatter v4l2 driver

- Link to v1: https://lore.kernel.org/r/20251203-csi_formatter-v1-0-eb9e1147b49e@nxp.com

---
Guoniu Zhou (4):
      dt-bindings: clock: imx95-blk-ctl: Use single quotes consistently
      media: dt-bindings: Add CSI Pixel Formatter DT bindings
      dt-bindings: clock: imx95-blk-ctl: Define formatter child node schema
      media: nxp: Add i.MX95 CSI pixel formatter v4l2 driver

 .../bindings/clock/nxp,imx95-blk-ctl.yaml          |  66 +-
 .../bindings/media/fsl,imx95-csi-formatter.yaml    |  88 +++
 MAINTAINERS                                        |   8 +
 drivers/media/platform/nxp/Kconfig                 |  15 +
 drivers/media/platform/nxp/Makefile                |   1 +
 drivers/media/platform/nxp/imx95-csi-formatter.c   | 775 +++++++++++++++++++++
 6 files changed, 951 insertions(+), 2 deletions(-)
---
base-commit: 06cb687a5132fcffe624c0070576ab852ac6b568
change-id: 20251125-csi_formatter-e6d29316dce6

Best regards,
-- 
Guoniu Zhou <guoniu.zhou@oss.nxp.com>


^ permalink raw reply

* [PATCH v10 1/4] dt-bindings: clock: imx95-blk-ctl: Use single quotes consistently
From: guoniu.zhou @ 2026-06-18  9:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
	Michael Turquette, Stephen Boyd
  Cc: imx, linux-media, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, Guoniu Zhou
In-Reply-To: <20260618-csi_formatter-v10-0-f23830312ba5@oss.nxp.com>

From: Guoniu Zhou <guoniu.zhou@nxp.com>

Change "clocks" to 'clocks' in the description to match the quote style
used for property names like '#clock-cells' throughout the file.

Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
---
Changes in v10:
- New patch to fix inconsistent quote usage (Krzysztof Kozlowski)
---
 Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
index 27403b4c52d6..534fa219d9f9 100644
--- a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
+++ b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
@@ -36,7 +36,7 @@ properties:
     const: 1
     description:
       The clock consumer should specify the desired clock by having the clock
-      ID in its "clocks" phandle cell. See
+      ID in its 'clocks' phandle cell. See
       include/dt-bindings/clock/nxp,imx95-clock.h
 
 required:

-- 
2.34.1


^ permalink raw reply related

* [PATCH v10 2/4] media: dt-bindings: Add CSI Pixel Formatter DT bindings
From: guoniu.zhou @ 2026-06-18  9:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
	Michael Turquette, Stephen Boyd
  Cc: imx, linux-media, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, Guoniu Zhou
In-Reply-To: <20260618-csi_formatter-v10-0-f23830312ba5@oss.nxp.com>

From: Guoniu Zhou <guoniu.zhou@nxp.com>

The i.MX95 CSI pixel formatting module uses packet info, pixel and
non-pixel data from the CSI-2 host controller and reformat them to
match Pixel Link(PL) definition.

Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
---
Changes in v10:
- Drop syscon parent node from example
- Drop Reviewed-by tags from Frank and Krzysztof due to binding changes
- Add description for reg property
- Add space after formatter@20 before opening brace in example
- Enhance the port description with more detailed information
- Delete the blank line immediately following the endpoint in example

Changes in v9:
- Use direct node instead of syscon wrapper in example

Changes in v8:
- Use standard port reference instead of video-interfaces.yaml
- Add parent syscon node in example to show device integration
- Add required constraints for port@0 and port@1 in ports node

Changes in v7:
- Change compatible to imx95-csi-formatter as IP is i.MX95 specific per Marco's suggestion
  Link: https://lore.kernel.org/linux-media/20260511-csi_formatter-v6-0-01028e312e2b@oss.nxp.com/T/#mcd135b3de179b3cb69daa1fd6e0e8e27c85b3332
---
 .../bindings/media/fsl,imx95-csi-formatter.yaml    | 88 ++++++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml b/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml
new file mode 100644
index 000000000000..58c4e1cc056b
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml
@@ -0,0 +1,88 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/fsl,imx95-csi-formatter.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: i.MX95 CSI Pixel Formatter
+
+maintainers:
+  - Guoniu Zhou <guoniu.zhou@nxp.com>
+
+description:
+  The CSI pixel formatting module found on i.MX95 uses packet info, pixel
+  and non-pixel data from the CSI-2 host controller and reformat them to
+  match Pixel Link(PL) definition.
+
+properties:
+  compatible:
+    const: fsl,imx95-csi-formatter
+
+  reg:
+    maxItems: 1
+    description: Register offset and size within the parent syscon
+
+  clocks:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Input port, connects to MIPI CSI-2 receiver output (IDI interface)
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description:
+          Output port, connects to ISI input via Pixel Link (PL)
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+    formatter@20 {
+        compatible = "fsl,imx95-csi-formatter";
+        reg = <0x20 0x100>;
+        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
+        power-domains = <&scmi_devpd 3>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+
+                endpoint {
+                    remote-endpoint = <&mipi_csi_0_out>;
+                };
+            };
+
+            port@1 {
+                reg = <1>;
+
+                endpoint {
+                    remote-endpoint = <&isi_in_2>;
+                };
+            };
+        };
+    };

-- 
2.34.1


^ permalink raw reply related

* [PATCH v10 3/4] dt-bindings: clock: imx95-blk-ctl: Define formatter child node schema
From: guoniu.zhou @ 2026-06-18  9:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
	Michael Turquette, Stephen Boyd
  Cc: imx, linux-media, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, Guoniu Zhou
In-Reply-To: <20260618-csi_formatter-v10-0-f23830312ba5@oss.nxp.com>

From: Guoniu Zhou <guoniu.zhou@nxp.com>

The Camera CSR contains control registers for multiple CSI formatter IPs
at different register offsets. Each formatter is an independent hardware
block with its own clock input and media pipeline connection.

Define schema to allow formatter child nodes under nxp,imx95-camera-csr,
with 'reg' property specifying the formatter's register offset within the
CSR address space.

Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
---
Changes in v10:
- Use single quotes for regex pattern to be consistent (Krzysztof Kozlowski)
- Add formatter subnode binding and camera-csr syscon example
- Update commit title and message

Changes in v9:
- New patch to address the issue of formatter acting as a child node of syscon
---
 .../bindings/clock/nxp,imx95-blk-ctl.yaml          | 64 +++++++++++++++++++++-
 1 file changed, 63 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
index 534fa219d9f9..b4d0a7670fac 100644
--- a/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
+++ b/Documentation/devicetree/bindings/clock/nxp,imx95-blk-ctl.yaml
@@ -46,7 +46,27 @@ required:
   - power-domains
   - clocks
 
-additionalProperties: false
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            const: nxp,imx95-camera-csr
+    then:
+      properties:
+        '#address-cells':
+          const: 1
+        '#size-cells':
+          const: 1
+      required:
+        - '#address-cells'
+        - '#size-cells'
+      patternProperties:
+        '^formatter@[0-9a-f]+$':
+          type: object
+          $ref: /schemas/media/fsl,imx95-csi-formatter.yaml#
+
+unevaluatedProperties: false
 
 examples:
   - |
@@ -57,4 +77,46 @@ examples:
       clocks = <&scmi_clk 114>;
       power-domains = <&scmi_devpd 21>;
     };
+
+  - |
+    #include <dt-bindings/clock/nxp,imx95-clock.h>
+
+    syscon@4ac10000 {
+      compatible = "nxp,imx95-camera-csr", "syscon";
+      reg = <0x4ac10000 0x10000>;
+      #address-cells = <1>;
+      #size-cells = <1>;
+      #clock-cells = <1>;
+      clocks = <&scmi_clk 62>;
+      power-domains = <&scmi_devpd 3>;
+
+      formatter@20 {
+        compatible = "fsl,imx95-csi-formatter";
+        reg = <0x20 0x100>;
+        clocks = <&cameramix_csr IMX95_CLK_CAMBLK_CSI2_FOR0>;
+        power-domains = <&scmi_devpd 3>;
+
+        ports {
+          #address-cells = <1>;
+          #size-cells = <0>;
+
+          port@0 {
+            reg = <0>;
+
+            endpoint {
+              remote-endpoint = <&mipi_csi_0_out>;
+            };
+
+          };
+
+          port@1 {
+            reg = <1>;
+
+            endpoint {
+              remote-endpoint = <&isi_in_2>;
+            };
+          };
+        };
+      };
+    };
 ...

-- 
2.34.1


^ permalink raw reply related

* [PATCH v10 4/4] media: nxp: Add i.MX95 CSI pixel formatter v4l2 driver
From: guoniu.zhou @ 2026-06-18  9:41 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Laurent Pinchart, Frank Li, Abel Vesa, Peng Fan,
	Michael Turquette, Stephen Boyd
  Cc: imx, linux-media, devicetree, linux-arm-kernel, linux-kernel,
	linux-clk, Guoniu Zhou, Frank Li
In-Reply-To: <20260618-csi_formatter-v10-0-f23830312ba5@oss.nxp.com>

From: Guoniu Zhou <guoniu.zhou@nxp.com>

The CSI pixel formatter is a module found on i.MX95 used to reformat
packet info, pixel and non-pixel data from CSI-2 host controller to
match Pixel Link(PL) definition.

Add data formatting support.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Guoniu Zhou <guoniu.zhou@nxp.com>
---
Changes in v10:
- Use u8 for vc in csi_formatter_get_vc() and drop vc < 0 check
- Add MFD_SYSCON dependency to Kconfig
- Fix stream/VC mapping potential mismatch in start/stop_stream functions

Changes in v8:
- Remove fmt field and look up format from subdev state instead
- Unify function and structure naming to use csi_formatter_ prefix
- Remove misleading alignment comment from set_fmt function
- Optimize get_frame_desc to call once per start_stream
- Replace V4L2_FRAME_DESC_ENTRY_MAX with CSI_FORMATTER_VC_NUM in loops
- Remove redundant debug message in enable_streams
- Use MEDIA_PAD_FL_MUST_CONNECT flag instead of manual link check
- Fix typo: Formater -> Formatter in Kconfig help text
- Improve grammar in data type index mapping comment

Changes in v7:
- Update references from imx9 to imx95 for consistency with dt-bindings
- Enable PM runtime before async registration

Changes in v6:
- Remove unused header includes
- Unify macro naming: VCx/VCX -> VC and parameter x -> vc
- Remove unused format field from csi_formatter struct
- Use compact initialization for formats array
- Make find_csi_format() return NULL instead of default format
- Use unsigned int for array index in find_csi_format()
- Add err_ prefix to error handling labels
- Add v4l2_subdev_cleanup() and reorder cleanup sequence
- Update enable_streams debug output format
- Rename VC_MAX to VC_NUM and fix boundary check
- Update CSI formatter Kconfig description
- Use v4l2_subdev_get_frame_desc_passthrough() helper
- Fix error paths in async registration and probe
- Add mutex to protect enabled_streams
- Switch to devm_pm_runtime_enable()
- Remove redundant num_routes check in set_routing
- Optimize get_index_by_dt() and add warning for unsupported type
- csi_formatter_start/stop_stream: Process all streams in mask
---
 MAINTAINERS                                      |   8 +
 drivers/media/platform/nxp/Kconfig               |  15 +
 drivers/media/platform/nxp/Makefile              |   1 +
 drivers/media/platform/nxp/imx95-csi-formatter.c | 775 +++++++++++++++++++++++
 4 files changed, 799 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index efbf808063e5..05009228b162 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -19275,6 +19275,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/media/nxp,imx8-jpeg.yaml
 F:	drivers/media/platform/nxp/imx-jpeg
 
+NXP i.MX 95 CSI PIXEL FORMATTER V4L2 DRIVER
+M:	Guoniu Zhou <guoniu.zhou@nxp.com>
+L:	imx@lists.linux.dev
+L:	linux-media@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/media/fsl,imx95-csi-formatter.yaml
+F:	drivers/media/platform/nxp/imx95-csi-formatter.c
+
 NXP i.MX CLOCK DRIVERS
 M:	Abel Vesa <abelvesa@kernel.org>
 R:	Peng Fan <peng.fan@nxp.com>
diff --git a/drivers/media/platform/nxp/Kconfig b/drivers/media/platform/nxp/Kconfig
index 40e3436669e2..8f49908b0022 100644
--- a/drivers/media/platform/nxp/Kconfig
+++ b/drivers/media/platform/nxp/Kconfig
@@ -28,6 +28,21 @@ config VIDEO_IMX8MQ_MIPI_CSI2
 	  Video4Linux2 driver for the MIPI CSI-2 receiver found on the i.MX8MQ
 	  SoC.
 
+config VIDEO_IMX95_CSI_FORMATTER
+	tristate "NXP i.MX95 CSI Pixel Formatter driver"
+	depends on ARCH_MXC || COMPILE_TEST
+	depends on MFD_SYSCON
+	depends on VIDEO_DEV
+	select MEDIA_CONTROLLER
+	select V4L2_FWNODE
+	select VIDEO_V4L2_SUBDEV_API
+	help
+	  This driver provides support for the CSI Pixel Formatter found on
+	  i.MX95 series SoCs. This module unpacks the pixels received from the
+	  CSI-2 interface and reformats them to meet pixel link requirements.
+
+	  Say Y here to enable CSI Pixel Formatter module for i.MX95 SoC.
+
 config VIDEO_IMX_MIPI_CSIS
 	tristate "NXP MIPI CSI-2 CSIS receiver found on i.MX7 and i.MX8 models"
 	depends on ARCH_MXC || COMPILE_TEST
diff --git a/drivers/media/platform/nxp/Makefile b/drivers/media/platform/nxp/Makefile
index 4d90eb713652..6410115d870e 100644
--- a/drivers/media/platform/nxp/Makefile
+++ b/drivers/media/platform/nxp/Makefile
@@ -6,6 +6,7 @@ obj-y += imx8-isi/
 
 obj-$(CONFIG_VIDEO_IMX7_CSI) += imx7-media-csi.o
 obj-$(CONFIG_VIDEO_IMX8MQ_MIPI_CSI2) += imx8mq-mipi-csi2.o
+obj-$(CONFIG_VIDEO_IMX95_CSI_FORMATTER) += imx95-csi-formatter.o
 obj-$(CONFIG_VIDEO_IMX_MIPI_CSIS) += imx-mipi-csis.o
 obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
diff --git a/drivers/media/platform/nxp/imx95-csi-formatter.c b/drivers/media/platform/nxp/imx95-csi-formatter.c
new file mode 100644
index 000000000000..cfe448fedd37
--- /dev/null
+++ b/drivers/media/platform/nxp/imx95-csi-formatter.c
@@ -0,0 +1,775 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <media/mipi-csi2.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mc.h>
+#include <media/v4l2-subdev.h>
+
+/* CSI Pixel Formatter registers map */
+
+#define CSI_VC_INTERLACED_LINE_CNT(vc)		(0x00 + (vc) * 0x04)
+#define INTERLACED_ODD_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(13, 0), (x))
+#define INTERLACED_EVEN_LINE_CNT_SET(x)		FIELD_PREP(GENMASK(29, 16), (x))
+
+#define CSI_VC_INTERLACED_CTRL			0x20
+
+#define CSI_VC_INTERLACED_ERR			0x24
+#define CSI_VC_ERR_MASK				GENMASK(7, 0)
+#define CSI_VC_ERR(vc)				BIT((vc))
+
+#define CSI_VC_YUV420_FIRST_LINE_EVEN		0x28
+#define YUV420_FIRST_LINE_EVEN(vc)		BIT((vc))
+
+#define CSI_RAW32_CTRL				0x30
+#define CSI_VC_RAW32_MODE(vc)			BIT((vc))
+#define CSI_VC_RAW32_SWAP_MODE(vc)		BIT((vc) + 8)
+
+#define CSI_STREAM_FENCING_CTRL			0x34
+#define CSI_VC_STREAM_FENCING(vc)		BIT((vc))
+#define CSI_VC_STREAM_FENCING_RST(vc)		BIT((vc) + 8)
+
+#define CSI_STREAM_FENCING_STS			0x38
+#define CSI_STREAM_FENCING_STS_MASK		GENMASK(7, 0)
+
+#define CSI_VC_NON_PIXEL_DATA_TYPE(vc)		(0x40 + (vc) * 0x04)
+
+#define CSI_VC_PIXEL_DATA_CTRL(vc)		(0x60 + (vc) * 0x04)
+#define NEW_VC(vc)				FIELD_PREP(GENMASK(3, 1), vc)
+#define REROUTE_VC_ENABLE			BIT(0)
+
+#define CSI_VC_ROUTE_PIXEL_DATA_TYPE(vc)	(0x80 + (vc) * 0x04)
+
+#define CSI_VC_NON_PIXEL_DATA_CTRL(vc)		(0xa0 + (vc) * 0x04)
+
+#define CSI_VC_PIXEL_DATA_TYPE(vc)		(0xc0 + (vc) * 0x04)
+
+#define CSI_VC_PIXEL_DATA_TYPE_ERR(vc)		(0xe0 + (vc) * 0x04)
+
+#define CSI_FORMATTER_PAD_SINK			0
+#define CSI_FORMATTER_PAD_SOURCE		1
+#define CSI_FORMATTER_PAD_NUM			2
+
+#define CSI_FORMATTER_VC_NUM			8 /* Number of virtual channels */
+
+struct csi_formatter_pix_format {
+	u32 code;
+	u32 data_type;
+};
+
+struct csi_formatter {
+	struct device *dev;
+	struct regmap *regs;
+	struct clk *clk;
+
+	struct v4l2_subdev sd;
+	struct v4l2_subdev *csi_sd;
+	struct v4l2_async_notifier notifier;
+	struct media_pad pads[CSI_FORMATTER_PAD_NUM];
+
+	u32 remote_pad;
+	u32 reg_offset;
+
+	/* Protects enabled_streams */
+	struct mutex lock;
+	u64 enabled_streams;
+
+	u8 stream_to_vc[CSI_FORMATTER_VC_NUM];
+};
+
+struct csi_formatter_dt_index {
+	u8 dtype;
+	u8 index;
+};
+
+/*
+ * The index corresponds to the bit index in the register that enables
+ * the data type of pixel data transported by the Formatter.
+ */
+static const struct csi_formatter_dt_index formatter_dt_to_index_map[] = {
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B,        .index = 0 },
+	{ .dtype = MIPI_CSI2_DT_YUV420_8B_LEGACY, .index = 2 },
+	{ .dtype = MIPI_CSI2_DT_YUV422_8B,        .index = 6 },
+	{ .dtype = MIPI_CSI2_DT_RGB444,		  .index = 8 },
+	{ .dtype = MIPI_CSI2_DT_RGB555,           .index = 9 },
+	{ .dtype = MIPI_CSI2_DT_RGB565,           .index = 10 },
+	{ .dtype = MIPI_CSI2_DT_RGB666,           .index = 11 },
+	{ .dtype = MIPI_CSI2_DT_RGB888,           .index = 12 },
+	{ .dtype = MIPI_CSI2_DT_RAW6,             .index = 16 },
+	{ .dtype = MIPI_CSI2_DT_RAW7,             .index = 17 },
+	{ .dtype = MIPI_CSI2_DT_RAW8,             .index = 18 },
+	{ .dtype = MIPI_CSI2_DT_RAW10,            .index = 19 },
+	{ .dtype = MIPI_CSI2_DT_RAW12,            .index = 20 },
+	{ .dtype = MIPI_CSI2_DT_RAW14,            .index = 21 },
+	{ .dtype = MIPI_CSI2_DT_RAW16,            .index = 22 },
+};
+
+static const struct csi_formatter_pix_format formats[] = {
+	/* YUV formats */
+	{ MEDIA_BUS_FMT_UYVY8_1X16,	MIPI_CSI2_DT_YUV422_8B },
+	/* RGB formats */
+	{ MEDIA_BUS_FMT_RGB565_1X16,	MIPI_CSI2_DT_RGB565 },
+	{ MEDIA_BUS_FMT_RGB888_1X24,	MIPI_CSI2_DT_RGB888 },
+	/* RAW (Bayer and greyscale) formats */
+	{ MEDIA_BUS_FMT_SBGGR8_1X8,	MIPI_CSI2_DT_RAW8 },
+	{ MEDIA_BUS_FMT_SGBRG8_1X8,	MIPI_CSI2_DT_RAW8 },
+	{ MEDIA_BUS_FMT_SGRBG8_1X8,	MIPI_CSI2_DT_RAW8 },
+	{ MEDIA_BUS_FMT_SRGGB8_1X8,	MIPI_CSI2_DT_RAW8 },
+	{ MEDIA_BUS_FMT_Y8_1X8,		MIPI_CSI2_DT_RAW8 },
+	{ MEDIA_BUS_FMT_SBGGR10_1X10,	MIPI_CSI2_DT_RAW10 },
+	{ MEDIA_BUS_FMT_SGBRG10_1X10,	MIPI_CSI2_DT_RAW10 },
+	{ MEDIA_BUS_FMT_SGRBG10_1X10,	MIPI_CSI2_DT_RAW10 },
+	{ MEDIA_BUS_FMT_SRGGB10_1X10,	MIPI_CSI2_DT_RAW10 },
+	{ MEDIA_BUS_FMT_Y10_1X10,	MIPI_CSI2_DT_RAW10 },
+	{ MEDIA_BUS_FMT_SBGGR12_1X12,	MIPI_CSI2_DT_RAW12 },
+	{ MEDIA_BUS_FMT_SGBRG12_1X12,	MIPI_CSI2_DT_RAW12 },
+	{ MEDIA_BUS_FMT_SGRBG12_1X12,	MIPI_CSI2_DT_RAW12 },
+	{ MEDIA_BUS_FMT_SRGGB12_1X12,	MIPI_CSI2_DT_RAW12 },
+	{ MEDIA_BUS_FMT_Y12_1X12,	MIPI_CSI2_DT_RAW12 },
+	{ MEDIA_BUS_FMT_SBGGR14_1X14,	MIPI_CSI2_DT_RAW14 },
+	{ MEDIA_BUS_FMT_SGBRG14_1X14,	MIPI_CSI2_DT_RAW14 },
+	{ MEDIA_BUS_FMT_SGRBG14_1X14,	MIPI_CSI2_DT_RAW14 },
+	{ MEDIA_BUS_FMT_SRGGB14_1X14,	MIPI_CSI2_DT_RAW14 },
+	{ MEDIA_BUS_FMT_SBGGR16_1X16,	MIPI_CSI2_DT_RAW16 },
+	{ MEDIA_BUS_FMT_SGBRG16_1X16,	MIPI_CSI2_DT_RAW16 },
+	{ MEDIA_BUS_FMT_SGRBG16_1X16,	MIPI_CSI2_DT_RAW16 },
+	{ MEDIA_BUS_FMT_SRGGB16_1X16,	MIPI_CSI2_DT_RAW16 },
+};
+
+static const struct v4l2_mbus_framefmt formatter_default_fmt = {
+	.code = MEDIA_BUS_FMT_UYVY8_1X16,
+	.width = 1920U,
+	.height = 1080U,
+	.field = V4L2_FIELD_NONE,
+	.colorspace = V4L2_COLORSPACE_SMPTE170M,
+	.xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SMPTE170M),
+	.quantization = V4L2_QUANTIZATION_LIM_RANGE,
+};
+
+static const struct csi_formatter_pix_format *csi_formatter_find_format(u32 code)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formats); i++)
+		if (code == formats[i].code)
+			return &formats[i];
+
+	return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static inline struct csi_formatter *sd_to_formatter(struct v4l2_subdev *sdev)
+{
+	return container_of(sdev, struct csi_formatter, sd);
+}
+
+static int __csi_formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					      struct v4l2_subdev_state *state,
+					      struct v4l2_subdev_krouting *routing)
+{
+	int ret;
+
+	ret = v4l2_subdev_routing_validate(sd, routing,
+					   V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+	if (ret)
+		return ret;
+
+	return v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+						&formatter_default_fmt);
+}
+
+static int csi_formatter_subdev_init_state(struct v4l2_subdev *sd,
+					   struct v4l2_subdev_state *sd_state)
+{
+	struct v4l2_subdev_route routes[] = {
+		{
+			.sink_pad = CSI_FORMATTER_PAD_SINK,
+			.sink_stream = 0,
+			.source_pad = CSI_FORMATTER_PAD_SOURCE,
+			.source_stream = 0,
+			.flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+		},
+	};
+
+	struct v4l2_subdev_krouting routing = {
+		.num_routes = ARRAY_SIZE(routes),
+		.routes = routes,
+	};
+
+	return __csi_formatter_subdev_set_routing(sd, sd_state, &routing);
+}
+
+static int csi_formatter_subdev_enum_mbus_code(struct v4l2_subdev *sd,
+					       struct v4l2_subdev_state *sd_state,
+					       struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad == CSI_FORMATTER_PAD_SOURCE) {
+		struct v4l2_mbus_framefmt *fmt;
+
+		if (code->index > 0)
+			return -EINVAL;
+
+		fmt = v4l2_subdev_state_get_format(sd_state, code->pad,
+						   code->stream);
+		code->code = fmt->code;
+		return 0;
+	}
+
+	if (code->index >= ARRAY_SIZE(formats))
+		return -EINVAL;
+
+	code->code = formats[code->index].code;
+
+	return 0;
+}
+
+static int csi_formatter_subdev_set_fmt(struct v4l2_subdev *sd,
+					struct v4l2_subdev_state *sd_state,
+					struct v4l2_subdev_format *sdformat)
+{
+	struct csi_formatter_pix_format const *format;
+	struct v4l2_mbus_framefmt *fmt;
+
+	if (sdformat->pad == CSI_FORMATTER_PAD_SOURCE)
+		return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
+
+	format = csi_formatter_find_format(sdformat->format.code);
+	if (!format)
+		format = &formats[0];
+
+	v4l_bound_align_image(&sdformat->format.width, 1, 0xffff, 2,
+			      &sdformat->format.height, 1, 0xffff, 0, 0);
+
+	fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad,
+					   sdformat->stream);
+	*fmt = sdformat->format;
+
+	/* Set default code if user set an invalid value */
+	fmt->code = format->code;
+
+	/* Propagate the format from sink stream to source stream */
+	fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
+							   sdformat->stream);
+	if (!fmt)
+		return -EINVAL;
+
+	*fmt = sdformat->format;
+
+	return 0;
+}
+
+static int csi_formatter_subdev_set_routing(struct v4l2_subdev *sd,
+					    struct v4l2_subdev_state *state,
+					    enum v4l2_subdev_format_whence which,
+					    struct v4l2_subdev_krouting *routing)
+{
+	if (which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+	    media_entity_is_streaming(&sd->entity))
+		return -EBUSY;
+
+	return __csi_formatter_subdev_set_routing(sd, state, routing);
+}
+
+static inline void csi_formatter_write(struct csi_formatter *formatter,
+				       unsigned int reg, unsigned int value)
+{
+	u32 offset = formatter->reg_offset;
+
+	regmap_write(formatter->regs, reg + offset, value);
+}
+
+static u8 csi_formatter_get_index_by_dt(u8 data_type)
+{
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(formatter_dt_to_index_map); ++i) {
+		const struct csi_formatter_dt_index *entry =
+			&formatter_dt_to_index_map[i];
+
+		if (data_type == entry->dtype)
+			return entry->index;
+	}
+
+	pr_warn_once("Unsupported data type 0x%x, using default\n", data_type);
+
+	return formatter_dt_to_index_map[0].index;
+}
+
+static int csi_formatter_get_vc(struct csi_formatter *formatter,
+				struct v4l2_mbus_frame_desc *fd,
+				unsigned int stream)
+{
+	struct v4l2_mbus_frame_desc_entry *entry = NULL;
+	unsigned int i;
+	u8 vc;
+
+	for (i = 0; i < fd->num_entries; ++i) {
+		if (fd->entry[i].stream == stream) {
+			entry = &fd->entry[i];
+			break;
+		}
+	}
+
+	if (!entry) {
+		dev_err(formatter->dev,
+			"No frame desc entry for stream %u\n", stream);
+		return -EPIPE;
+	}
+
+	vc = entry->bus.csi2.vc;
+
+	if (vc >= CSI_FORMATTER_VC_NUM) {
+		dev_err(formatter->dev, "Invalid virtual channel %u\n", vc);
+		return -EINVAL;
+	}
+
+	return vc;
+}
+
+static void csi_formatter_stop_stream(struct csi_formatter *formatter,
+				      u64 stream_mask)
+{
+	unsigned int i;
+	u8 vc;
+
+	for (i = 0; i < CSI_FORMATTER_VC_NUM; ++i) {
+		if (!(stream_mask & BIT(i)))
+			continue;
+
+		/* Use the VC that was configured in start_stream */
+		vc = formatter->stream_to_vc[i];
+		if (vc >= CSI_FORMATTER_VC_NUM)
+			continue;
+
+		csi_formatter_write(formatter, CSI_VC_PIXEL_DATA_TYPE(vc), 0);
+
+		/* Clear after use */
+		formatter->stream_to_vc[i] = 0xff;
+	}
+}
+
+static int csi_formatter_start_stream(struct csi_formatter *formatter,
+				      struct v4l2_subdev_state *state,
+				      u64 stream_mask)
+{
+	const struct csi_formatter_pix_format *pix_fmt;
+	struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_mbus_frame_desc fd = {};
+	u64 configured_streams = 0;
+	unsigned int i;
+	u32 val;
+	int vc;
+	int ret;
+
+	ret = v4l2_subdev_call(formatter->csi_sd, pad, get_frame_desc,
+			       formatter->remote_pad, &fd);
+	if (ret < 0 && ret != -ENOIOCTLCMD) {
+		dev_err(formatter->dev, "Failed to get frame desc: %d\n", ret);
+		return ret;
+	}
+
+	for (i = 0; i < CSI_FORMATTER_VC_NUM; ++i) {
+		if (!(stream_mask & BIT(i)))
+			continue;
+
+		fmt = v4l2_subdev_state_get_format(state,
+						   CSI_FORMATTER_PAD_SINK, i);
+
+		pix_fmt = csi_formatter_find_format(fmt->code);
+
+		val = BIT(csi_formatter_get_index_by_dt(pix_fmt->data_type));
+
+		if (ret == -ENOIOCTLCMD) {
+			/*
+			 * Source doesn't implement get_frame_desc, use
+			 * default VC 0
+			 */
+			vc = 0;
+		} else {
+			vc = csi_formatter_get_vc(formatter, &fd, i);
+			if (vc < 0) {
+				ret = vc;
+				goto err_cleanup;
+			}
+		}
+
+		/* Store the stream to VC mapping for stop_stream */
+		formatter->stream_to_vc[i] = vc;
+
+		csi_formatter_write(formatter, CSI_VC_PIXEL_DATA_TYPE(vc), val);
+		configured_streams |= BIT(i);
+	}
+
+	return 0;
+
+err_cleanup:
+	csi_formatter_stop_stream(formatter, configured_streams);
+	return ret;
+}
+
+static int csi_formatter_subdev_enable_streams(struct v4l2_subdev *sd,
+					       struct v4l2_subdev_state *state,
+					       u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	struct device *dev = formatter->dev;
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	guard(mutex)(&formatter->lock);
+
+	if (!formatter->enabled_streams) {
+		ret = pm_runtime_resume_and_get(formatter->dev);
+		if (ret < 0) {
+			dev_err(dev, "Failed to resume runtime PM: %d\n", ret);
+			return ret;
+		}
+	}
+
+	ret = csi_formatter_start_stream(formatter, state, streams_mask);
+	if (ret)
+		goto err_runtime_put;
+
+	ret = v4l2_subdev_enable_streams(formatter->csi_sd,
+					 formatter->remote_pad,
+					 sink_streams);
+	if (ret)
+		goto err_stop_stream;
+
+	formatter->enabled_streams |= streams_mask;
+
+	return 0;
+
+err_stop_stream:
+	csi_formatter_stop_stream(formatter, streams_mask);
+err_runtime_put:
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+	return ret;
+}
+
+static int csi_formatter_subdev_disable_streams(struct v4l2_subdev *sd,
+						struct v4l2_subdev_state *state,
+						u32 pad, u64 streams_mask)
+{
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+	u64 sink_streams;
+	int ret;
+
+	sink_streams = v4l2_subdev_state_xlate_streams(state,
+						       CSI_FORMATTER_PAD_SOURCE,
+						       CSI_FORMATTER_PAD_SINK,
+						       &streams_mask);
+	if (!sink_streams || !streams_mask)
+		return -EINVAL;
+
+	guard(mutex)(&formatter->lock);
+
+	ret = v4l2_subdev_disable_streams(formatter->csi_sd, formatter->remote_pad,
+					  sink_streams);
+	if (ret)
+		dev_err(formatter->dev, "Failed to disable streams: %d\n", ret);
+
+	csi_formatter_stop_stream(formatter, streams_mask);
+
+	formatter->enabled_streams &= ~streams_mask;
+
+	if (!formatter->enabled_streams)
+		pm_runtime_put(formatter->dev);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_pad_ops formatter_subdev_pad_ops = {
+	.enum_mbus_code		= csi_formatter_subdev_enum_mbus_code,
+	.get_fmt		= v4l2_subdev_get_fmt,
+	.set_fmt		= csi_formatter_subdev_set_fmt,
+	.get_frame_desc		= v4l2_subdev_get_frame_desc_passthrough,
+	.set_routing		= csi_formatter_subdev_set_routing,
+	.enable_streams		= csi_formatter_subdev_enable_streams,
+	.disable_streams	= csi_formatter_subdev_disable_streams,
+};
+
+static const struct v4l2_subdev_ops formatter_subdev_ops = {
+	.pad = &formatter_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops formatter_internal_ops = {
+	.init_state = csi_formatter_subdev_init_state,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static const struct media_entity_operations formatter_entity_ops = {
+	.link_validate	= v4l2_subdev_link_validate,
+	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
+};
+
+static int csi_formatter_subdev_init(struct csi_formatter *formatter)
+{
+	struct v4l2_subdev *sd = &formatter->sd;
+	int ret;
+
+	v4l2_subdev_init(sd, &formatter_subdev_ops);
+
+	snprintf(sd->name, sizeof(sd->name), "%s", dev_name(formatter->dev));
+	sd->internal_ops = &formatter_internal_ops;
+
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+		     V4L2_SUBDEV_FL_HAS_EVENTS |
+		     V4L2_SUBDEV_FL_STREAMS;
+	sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+	sd->entity.ops = &formatter_entity_ops;
+	sd->dev = formatter->dev;
+
+	formatter->pads[CSI_FORMATTER_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+						      | MEDIA_PAD_FL_MUST_CONNECT;
+	formatter->pads[CSI_FORMATTER_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+	ret = media_entity_pads_init(&sd->entity, CSI_FORMATTER_PAD_NUM,
+				     formatter->pads);
+	if (ret) {
+		dev_err(formatter->dev, "Failed to init pads\n");
+		return ret;
+	}
+
+	ret = v4l2_subdev_init_finalize(sd);
+	if (ret)
+		media_entity_cleanup(&sd->entity);
+
+	return ret;
+}
+
+static inline struct csi_formatter *
+notifier_to_csi_formatter(struct v4l2_async_notifier *n)
+{
+	return container_of(n, struct csi_formatter, notifier);
+}
+
+static int csi_formatter_notify_bound(struct v4l2_async_notifier *notifier,
+				      struct v4l2_subdev *sd,
+				      struct v4l2_async_connection *asc)
+{
+	const unsigned int link_flags = MEDIA_LNK_FL_IMMUTABLE
+				      | MEDIA_LNK_FL_ENABLED;
+	struct csi_formatter *formatter = notifier_to_csi_formatter(notifier);
+	struct v4l2_subdev *sdev = &formatter->sd;
+	struct media_pad *sink = &sdev->entity.pads[CSI_FORMATTER_PAD_SINK];
+	struct media_pad *remote_pad;
+	int ret;
+
+	formatter->csi_sd = sd;
+
+	dev_dbg(formatter->dev, "Bound subdev: %s pad\n", sd->name);
+
+	ret = v4l2_create_fwnode_links_to_pad(sd, sink, link_flags);
+	if (ret < 0)
+		return ret;
+
+	remote_pad = media_pad_remote_pad_first(sink);
+	if (!remote_pad) {
+		dev_err(formatter->dev, "Pipe not setup correctly\n");
+		return -EPIPE;
+	}
+	formatter->remote_pad = remote_pad->index;
+
+	return 0;
+}
+
+static const struct v4l2_async_notifier_operations formatter_notify_ops = {
+	.bound = csi_formatter_notify_bound,
+};
+
+static int csi_formatter_async_register(struct csi_formatter *formatter)
+{
+	struct device *dev = formatter->dev;
+	struct v4l2_async_connection *asc;
+	int ret;
+
+	struct fwnode_handle *ep __free(fwnode_handle) =
+		fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+						FWNODE_GRAPH_ENDPOINT_NEXT);
+	if (!ep)
+		return -ENOTCONN;
+
+	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
+
+	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
+					      struct v4l2_async_connection);
+	if (IS_ERR(asc)) {
+		ret = PTR_ERR(asc);
+		goto err_cleanup_notifier;
+	}
+
+	formatter->notifier.ops = &formatter_notify_ops;
+
+	ret = v4l2_async_nf_register(&formatter->notifier);
+	if (ret)
+		goto err_cleanup_notifier;
+
+	ret = v4l2_async_register_subdev(&formatter->sd);
+	if (ret)
+		goto err_unregister_notifier;
+
+	return 0;
+
+err_unregister_notifier:
+	v4l2_async_nf_unregister(&formatter->notifier);
+err_cleanup_notifier:
+	v4l2_async_nf_cleanup(&formatter->notifier);
+	return ret;
+}
+
+static void csi_formatter_async_unregister(struct csi_formatter *formatter)
+{
+	v4l2_async_unregister_subdev(&formatter->sd);
+	v4l2_async_nf_unregister(&formatter->notifier);
+	v4l2_async_nf_cleanup(&formatter->notifier);
+}
+
+/* -----------------------------------------------------------------------------
+ * Suspend/resume
+ */
+
+static int csi_formatter_runtime_suspend(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	clk_disable_unprepare(formatter->clk);
+
+	return 0;
+}
+
+static int csi_formatter_runtime_resume(struct device *dev)
+{
+	struct v4l2_subdev *sd = dev_get_drvdata(dev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	return clk_prepare_enable(formatter->clk);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(csi_formatter_pm_ops,
+				 csi_formatter_runtime_suspend,
+				 csi_formatter_runtime_resume, NULL);
+
+static int csi_formatter_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct csi_formatter *formatter;
+	u32 val;
+	int ret;
+
+	formatter = devm_kzalloc(dev, sizeof(*formatter), GFP_KERNEL);
+	if (!formatter)
+		return -ENOMEM;
+
+	/* Initialize stream to VC mapping to invalid */
+	memset(formatter->stream_to_vc, 0xff, sizeof(formatter->stream_to_vc));
+
+	formatter->dev = dev;
+
+	ret = devm_mutex_init(dev, &formatter->lock);
+	if (ret)
+		return ret;
+
+	formatter->regs = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(formatter->regs))
+		return dev_err_probe(dev, PTR_ERR(formatter->regs),
+				     "Failed to get csi formatter regmap\n");
+
+	ret = of_property_read_u32(dev->of_node, "reg", &val);
+	if (ret < 0)
+		return dev_err_probe(dev, ret,
+				     "Failed to get csi formatter reg property\n");
+
+	formatter->reg_offset = val;
+
+	formatter->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(formatter->clk))
+		return dev_err_probe(dev, PTR_ERR(formatter->clk),
+				     "Failed to get pixel clock\n");
+
+	ret = csi_formatter_subdev_init(formatter);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to initialize formatter subdev\n");
+
+	platform_set_drvdata(pdev, &formatter->sd);
+
+	/* Enable runtime PM. */
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		goto err_cleanup_subdev;
+
+	ret = csi_formatter_async_register(formatter);
+	if (ret < 0) {
+		dev_err_probe(dev, ret, "Failed to register async subdevice\n");
+		goto err_cleanup_subdev;
+	}
+
+	return 0;
+
+err_cleanup_subdev:
+	v4l2_subdev_cleanup(&formatter->sd);
+	media_entity_cleanup(&formatter->sd.entity);
+	return ret;
+}
+
+static void csi_formatter_remove(struct platform_device *pdev)
+{
+	struct v4l2_subdev *sd = platform_get_drvdata(pdev);
+	struct csi_formatter *formatter = sd_to_formatter(sd);
+
+	csi_formatter_async_unregister(formatter);
+
+	v4l2_subdev_cleanup(&formatter->sd);
+	media_entity_cleanup(&formatter->sd.entity);
+}
+
+static const struct of_device_id csi_formatter_of_match[] = {
+	{ .compatible = "fsl,imx95-csi-formatter" },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, csi_formatter_of_match);
+
+static struct platform_driver csi_formatter_device_driver = {
+	.driver = {
+		.name           = "csi-pixel-formatter",
+		.of_match_table = csi_formatter_of_match,
+		.pm             = pm_ptr(&csi_formatter_pm_ops),
+	},
+	.probe  = csi_formatter_probe,
+	.remove = csi_formatter_remove,
+};
+
+module_platform_driver(csi_formatter_device_driver);
+
+MODULE_AUTHOR("NXP Semiconductor, Inc.");
+MODULE_DESCRIPTION("NXP i.MX95 CSI Pixel Formatter driver");
+MODULE_LICENSE("GPL");

-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH 2/9] drm/rockchip: vop2: Reset AXI and DCLK to improve robustness
From: Philipp Zabel @ 2026-06-18  9:39 UTC (permalink / raw)
  To: Cristian Ciocaltea, Sandy Huang, Heiko Stübner, Andy Yan,
	David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
	Jonas Karlman, Jernej Skrabec, Luca Ceresoli
  Cc: kernel, Andy Yan, dri-devel, devicetree, linux-arm-kernel,
	linux-rockchip, linux-kernel
In-Reply-To: <20260617-dw-hdmi-qp-yuv-v1-2-a665cfd06d7d@collabora.com>

On Mi, 2026-06-17 at 21:51 +0300, Cristian Ciocaltea wrote:
> Assert the AXI reset in the CRTC disable path, and the VP DCLK reset in
> the enable path.
> 
> These resets are intended to leave the hardware in a clean state for the
> next use, helping recover from exceptions such as IOMMU page faults, as
> well as to prevent random display output glitches, such as a blank
> image, observed when switching modes that also change the color format,
> e.g. from RGB to YUV420 and vice versa.
> 
> For now this seems to affect only the RK3588, hence the resets are
> optional and will be provided in the device tree for this SoC only.
> 
> Co-developed-by: Andy Yan <andy.yan@rock-chips.com>
> Signed-off-by: Andy Yan <andy.yan@rock-chips.com>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 35 ++++++++++++++++++++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop2.h |  4 ++++
>  2 files changed, 39 insertions(+)
> 
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> index 4cce3e336f5b..2833fb49ad81 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
> @@ -17,6 +17,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  #include <linux/regmap.h>
> +#include <linux/reset.h>
>  #include <linux/swab.h>
>  
>  #include <drm/drm.h>
> @@ -860,6 +861,26 @@ static int vop2_core_clks_prepare_enable(struct vop2 *vop2)
>  	return ret;
>  }
>  
> +static void vop2_clk_reset(struct vop2 *vop2, struct reset_control *rstc)

The _clk part of the function name is misleading ...

[...]
> @@ -938,6 +959,8 @@ static void vop2_disable(struct vop2 *vop2)
>  {
>  	rockchip_drm_dma_detach_device(vop2->drm, vop2->dev);
>  
> +	vop2_clk_reset(vop2, vop2->axi_rst);

... because this function is also called with the AXI reset control.

> +
>  	pm_runtime_put_sync(vop2->dev);
>  
>  	regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register);
> @@ -1948,6 +1971,8 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
>  
>  	vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state);
>  
> +	vop2_clk_reset(vop2, vp->dclk_rst);
> +
>  	drm_crtc_vblank_on(crtc);
>  
>  	vop2_unlock(vop2);
> @@ -2531,6 +2556,11 @@ static int vop2_create_crtcs(struct vop2 *vop2)
>  			return dev_err_probe(drm->dev, PTR_ERR(vp->dclk),
>  					     "failed to get %s\n", dclk_name);
>  
> +		vp->dclk_rst = devm_reset_control_get_optional(vop2->dev, dclk_name);

Please use devm_reset_control_get_optional_exclusive() directly.

> +		if (IS_ERR(vp->dclk_rst))
> +			return dev_err_probe(drm->dev, PTR_ERR(vp->dclk_rst),
> +					     "failed to get %s reset\n", dclk_name);
> +
>  		np = of_graph_get_remote_node(dev->of_node, i, -1);
>  		if (!np) {
>  			drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i);
> @@ -2890,6 +2920,11 @@ static int vop2_bind(struct device *dev, struct device *master, void *data)
>  		return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy1),
>  				     "failed to get pll_hdmiphy1\n");
>  
> +	vop2->axi_rst = devm_reset_control_get_optional(vop2->dev, "axi");

Same as above, devm_reset_control_get_optional_exclusive().

regards
Philipp

^ permalink raw reply

* Re: [PATCH] media: ti: j721e-csi2rx: Minor cleanup of loop variables
From: Tomi Valkeinen @ 2026-06-18  9:40 UTC (permalink / raw)
  To: Rishikesh Donadkar
  Cc: y-abhilashchandra, devarsht, s-jain1, vigneshr, mchehab, robh,
	krzk+dt, p.zabel, conor+dt, sakari.ailus, hverkuil-cisco,
	jai.luthra, changhuang.liang, jack.zhu, sjoerd, dan.carpenter,
	hverkuil+cisco, linux-kernel, linux-media, devicetree, jai.luthra,
	laurent.pinchart, mripard
In-Reply-To: <20260520135705.661455-1-r-donadkar@ti.com>

Hi,

On 20/05/2026 16:57, Rishikesh Donadkar wrote:
> Replace open-coded `i--; for (; i >= 0; i--)` patterns with the
> idiomatic `while (i--)` in the error unwind paths of
> csi_async_notifier_complete() and ti_csi2rx_probe().
> 
> Also scope loop variables directly in the for statement instead of
> declaring them at the top of the function in ti_csi2rx_suspend(),
> ti_csi2rx_resume() and ti_csi2rx_remove(). Change the type to
> unsigned int in the first two to match csi->num_ctx.
> 
> Signed-off-by: Rishikesh Donadkar <r-donadkar@ti.com>

Reviewed-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

  Tomi

> ---
> This patch depends on [1]
> 
> [1]: https://lore.kernel.org/all/20260520120022.539913-1-r-donadkar@ti.com/
> 
>   .../platform/ti/j721e-csi2rx/j721e-csi2rx.c     | 17 +++++++----------
>   1 file changed, 7 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
> index 21388284cbaa..ef74e2da19b6 100644
> --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
> +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
> @@ -485,8 +485,7 @@ static int csi_async_notifier_complete(struct v4l2_async_notifier *notifier)
>   	return 0;
>   
>   unregister_dev:
> -	i--;
> -	for (; i >= 0; i--) {
> +	while (i--) {
>   		media_entity_remove_links(&csi->ctx[i].vdev.entity);
>   		video_unregister_device(&csi->ctx[i].vdev);
>   	}
> @@ -1552,7 +1551,7 @@ static int ti_csi2rx_suspend(struct device *dev)
>   	struct ti_csi2rx_ctx *ctx;
>   	struct ti_csi2rx_dma *dma;
>   	unsigned long flags = 0;
> -	int i, ret = 0;
> +	int ret = 0;
>   
>   	/* If device was not in use we can simply suspend */
>   	if (pm_runtime_status_suspended(dev))
> @@ -1564,7 +1563,7 @@ static int ti_csi2rx_suspend(struct device *dev)
>   	 */
>   	writel(0, csi->shim + SHIM_CNTL);
>   
> -	for (i = 0; i < csi->num_ctx; i++) {
> +	for (unsigned int i = 0; i < csi->num_ctx; i++) {
>   		ctx = &csi->ctx[i];
>   		dma = &ctx->dma;
>   
> @@ -1604,7 +1603,7 @@ static int ti_csi2rx_resume(struct device *dev)
>   	struct ti_csi2rx_buffer *buf;
>   	unsigned long flags = 0;
>   	unsigned int reg;
> -	int i, ret = 0;
> +	int ret = 0;
>   
>   	/* If device was not in use, we can simply wakeup */
>   	if (pm_runtime_status_suspended(dev))
> @@ -1614,7 +1613,7 @@ static int ti_csi2rx_resume(struct device *dev)
>   	reg = SHIM_CNTL_PIX_RST;
>   	writel(reg, csi->shim + SHIM_CNTL);
>   
> -	for (i = 0; i < csi->num_ctx; i++) {
> +	for (unsigned int i = 0; i < csi->num_ctx; i++) {
>   		ctx = &csi->ctx[i];
>   		dma = &ctx->dma;
>   		spin_lock_irqsave(&dma->lock, flags);
> @@ -1755,8 +1754,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev)
>   err_notifier:
>   	ti_csi2rx_cleanup_notifier(csi);
>   err_ctx:
> -	i--;
> -	for (; i >= 0; i--)
> +	while (i--)
>   		ti_csi2rx_cleanup_ctx(&csi->ctx[i]);
>   	ti_csi2rx_cleanup_v4l2(csi);
>   err_dma_chan:
> @@ -1768,12 +1766,11 @@ static int ti_csi2rx_probe(struct platform_device *pdev)
>   static void ti_csi2rx_remove(struct platform_device *pdev)
>   {
>   	struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev);
> -	unsigned int i;
>   
>   	if (!pm_runtime_status_suspended(&pdev->dev))
>   		pm_runtime_set_suspended(&pdev->dev);
>   
> -	for (i = 0; i < csi->num_ctx; i++)
> +	for (unsigned int i = 0; i < csi->num_ctx; i++)
>   		ti_csi2rx_cleanup_ctx(&csi->ctx[i]);
>   
>   	ti_csi2rx_cleanup_notifier(csi);


^ permalink raw reply

* Re: [PATCH v4 3/5] dt-bindings: clock: cix,sky1-audss-clock: add audss clock controller
From: Philipp Zabel @ 2026-06-18  9:45 UTC (permalink / raw)
  To: Joakim Zhang, Conor Dooley
  Cc: mturquette@baylibre.com, sboyd@kernel.org, bmasney@redhat.com,
	robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org,
	Gary Yang, cix-kernel-upstream, linux-clk@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <SEYPR06MB6226B25BA7652287C752E4C782E32@SEYPR06MB6226.apcprd06.prod.outlook.com>

On Do, 2026-06-18 at 09:27 +0000, Joakim  Zhang wrote:
> Hello,
> 
> 
> > -----Original Message-----
> > From: Philipp Zabel <p.zabel@pengutronix.de>
> > Sent: Thursday, June 18, 2026 4:30 PM
> > To: Joakim Zhang <joakim.zhang@cixtech.com>; Conor Dooley
> > <conor@kernel.org>
> > Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> > robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org; Gary Yang
> > <Gary.Yang@cixtech.com>; cix-kernel-upstream <cix-kernel-
> > upstream@cixtech.com>; linux-clk@vger.kernel.org;
> > devicetree@vger.kernel.org; linux-kernel@vger.kernel.org; linux-arm-
> > kernel@lists.infradead.org
> > Subject: Re: [PATCH v4 3/5] dt-bindings: clock: cix,sky1-audss-clock: add audss
> > clock controller
> > 
> > EXTERNAL EMAIL
> > 
> > CAUTION: Suspicious Email from unusual domain.
> > 
> > On Do, 2026-06-18 at 01:43 +0000, Joakim  Zhang wrote:
> > > Hello,
> > > 
> > > 
> > > > -----Original Message-----
> > > > From: Conor Dooley <conor@kernel.org>
> > > > Sent: Wednesday, June 17, 2026 11:56 PM
> > > > To: Joakim Zhang <joakim.zhang@cixtech.com>
> > > > Cc: mturquette@baylibre.com; sboyd@kernel.org; bmasney@redhat.com;
> > > > robh@kernel.org; krzk+dt@kernel.org; conor+dt@kernel.org;
> > > > p.zabel@pengutronix.de; Gary Yang <gary.yang@cixtech.com>;
> > > > cix-kernel- upstream <cix-kernel-upstream@cixtech.com>;
> > > > linux-clk@vger.kernel.org; devicetree@vger.kernel.org;
> > > > linux-kernel@vger.kernel.org; linux-arm- kernel@lists.infradead.org
> > > > Subject: Re: [PATCH v4 3/5] dt-bindings: clock:
> > > > cix,sky1-audss-clock: add audss clock controller
> > > > 
> > > > On Wed, Jun 17, 2026 at 02:04:35PM +0800, joakim.zhang@cixtech.com
> > wrote:
> > > > > From: Joakim Zhang <joakim.zhang@cixtech.com>
> > > > > 
> > > > > The AUDSS CRU contains an internal clock tree of muxes, dividers
> > > > > and gates for DSP, I2S, HDA, DMAC and related blocks. The clock
> > > > > provider is a child node of the cix,sky1-audss-system-control
> > > > > syscon and accesses registers through the parent MMIO region.
> > > > 
> > > > Why can this not just be part of the parent syscon node?
> > > 
> > > The clock and reset blocks are handled by different subsystems and
> > maintainers (clk vs reset). Putting the clock provider on the parent syscon node
> > would mean a single driver has to register both the reset controller and the
> > clock provider on one device, which doesn't fit well.
> > 
> > There are many examples of clock and reset drivers sharing the same node, by
> > using platform_driver for one (usually clk) and auxiliary_driver for the other
> > (usually reset).
> 
> OK, I will have a look.  If you are also prefer to this, I will refactor the patch.

The hardware should dictate this, not the driver/subsystem/maintainer
boundaries. Looking at the register numbers used by the drivers, and
assuming that the audss_cru label in the dts patch means the TRM also
calls this a single Clock-Reset-Unit, I'd say Conor has a point.

regards
Philipp

^ permalink raw reply

* Re: [PATCH v8 4/7] input: keyboard: Add driver for ASUS Transformer dock multimedia keys
From: Svyatoslav Ryhel @ 2026-06-18  9:45 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lee Jones,
	Pavel Machek, Sebastian Reichel, Ion Agorria,
	Michał Mirosław, devicetree, linux-kernel, linux-input,
	linux-leds, linux-pm
In-Reply-To: <CAPVz0n0r-1SXH_dfS9HkQJrF7e-6+O5Me2bPjcscnizmfTfjZg@mail.gmail.com>

чт, 18 черв. 2026 р. о 12:18 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> ср, 17 черв. 2026 р. о 00:23 Dmitry Torokhov <dmitry.torokhov@gmail.com> пише:
> >
> > On Tue, Jun 16, 2026 at 09:25:25AM +0300, Svyatoslav Ryhel wrote:
> > > вт, 16 черв. 2026 р. о 07:26 Dmitry Torokhov <dmitry.torokhov@gmail.com> пише:
> > > >
> > > > Hi Svyatoslav,
> > > >
> > > > On Thu, May 28, 2026 at 08:32:00AM +0300, Svyatoslav Ryhel wrote:
> > > > > From: Michał Mirosław <mirq-linux@rere.qmqm.pl>
> > > > >
> > > > > Add support for multimedia top button row of ASUS Transformer's Mobile
> > > > > Dock keyboard. Driver is made that function keys (F1-F12) are used by
> > > > > default which suits average Linux use better and with pressing
> > > > > ScreenLock + AltGr function keys layout is switched to multimedia keys.
> > > > > Since this only modifies codes sent by asus-ec-keys it doesn't affect
> > > > > normal keyboards at all.
> > > >
> > > > I think using input handler to intercept ScreenLock + AltGr is quite
> > > > awkward. I think this also passes the original key events (unless you
> > > > make it a filter not a regular handler).
> > > >
> > > > I do not see benefit for reacting to AltGr+ScreenLock on other keyboards
> > > > to activate the special mode on this one. So given the fact that you
> > > > already mange the data stream when you split it into "serio" ports,
> > > > maybe just intercept this key combo right there and create the input
> > > > device and signal input events right there?
> > > >
> > >
> > > Though it seems awkward at a first glance, media keys are integrated
> > > with a standard keyboard in a detachable dock. It is highly unlikely
> > > that media keys will be used with a different keyboard then the one
> > > that is integrated with dock. Additionally, the ScreenLock key has a
> > > code specific to this driver and is not in general use, so even if any
> > > standard keyboard has AltGr but none has ScreenLock specific to this
> > > driver except the dock itself. Handler is also set as observer so it
> > > should not interfere with work of other input devices.
> >
> > I am not concerned about it interfering with other drivers, I am
> > concerned about it unnecessarily connecting to unrelated devices
> > (anything that declares EV_KEY).
> >

I can add check in asus_ec_input_connect() to strictly connect only to
dock keyboard, will this be sufficient?

> > Again, I think having input handler is not appropriate here. I would
> > fold this patch into the patch that introduces the 2 serio ports,
> > enhanced the data stream analysis to detect your key combo, and then
> > report through this new input device. You do not need to have the round
> > trip through atkbd and the new input handler for this.

This sounds like a load of additional work, I would rather remove
layout swapping entirely (even though it is a useful feature) then
rewrite everything from scratch.

> >
>
> I will try with filtering first if you don't mind. If that will not
> work I'll consider folding. Do you have any good examples of handler
> with filter to use as an inspiration? Thank you.
>
> > Thanks.
> >
> > --
> > Dmitry

^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: qcom: lemans-evk: Describe the PCIe M.2 Key E connector
From: Konrad Dybcio @ 2026-06-18  9:49 UTC (permalink / raw)
  To: Wei Deng, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Manivannan Sadhasivam,
	Bartosz Golaszewski
  Cc: linux-arm-msm, devicetree, linux-kernel, linux-pci, linux-pm,
	quic_chezhou, cheng.jiang, shuai.zhang, jinwang.li, xiuzhuo.shang,
	mengshi.wu
In-Reply-To: <20260608091702.3797437-3-wei.deng@oss.qualcomm.com>

On 6/8/26 11:17 AM, Wei Deng wrote:
> The lemans EVK has the PCIe M.2 Mechanical Key E connector to connect
> wireless connectivity cards over PCIe and UART interfaces. Hence,
> describe the connector node and link it with the PCIe 0 Root Port and
> UART17 nodes through graph port/endpoint.
> 
> Also add 'compatible = "pciclass,0604"' to the pcieport0 node in
> lemans.dtsi to allow the PCI subsystem to associate the DT node with
> the PCI-to-PCI bridge device.

Ideally this would be a separate change

Also, b4 can't grab this patch since there's something wrong with the
threading (multiple series in a single thread) - please switch to using
b4 for submissions yourself to avoid such mistakes.

https://b4.docs.kernel.org/en/latest/

Konrad

^ permalink raw reply

* [PATCH v4 0/2] clk: amlogic: Add A9 AO clock controller
From: Jian Hu via B4 Relay @ 2026-06-18  9:49 UTC (permalink / raw)
  To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao,
	Kevin Hilman, Martin Blumenstingl
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Jian Hu, Conor Dooley

This series adds Amlogic A9 AO clock support, including dt-binding and AO clock driver.

Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
Changes in v4:
- Drop CLK_IS_CRITICAL for ao_xtal_in clock.
- Drop CLK_HW_INIT* and revert to explicit clock declarations.
- Link to v3: https://lore.kernel.org/r/20260610-a9_aoclk-v3-0-b7592d6c31e2@amlogic.com

Changes in v3:
- Move COMPILE_TEST after 'depends on ARM64' reported by sashiko-bot.
- Rename i2c3 to i3c reported by sashiko-bot.
- Reword the comment describing ao_xtal_in's flags.
- Use struct clk_init_data to describe ao_xtal_in's hw.init.
- Link to v2: https://lore.kernel.org/r/20260603-a9_aoclk-v2-0-f47ea616ee78@amlogic.com

Changes in v2:
- Split the A9 clock driver and send the AO clock separately.
- Rename aobus to soc.
- Use CLK_HW_INIT_FW_NAME to describe clk_init_data.
- Use CLK_HW_INIT_PARENTS_DATA to describe clk_init_data.
- Use a9_ao prefix for MESON_COMP_SEL.
- Correct duandiv name.
- Fix pwm b reg.
- Link to v1: https://lore.kernel.org/all/20260511-b4-a9_clk-v1-0-41cb4071b7c9@amlogic.com/

---
Jian Hu (2):
      dt-bindings: clock: Add Amlogic A9 AO clock controller
      clk: amlogic: Add A9 AO clock controller driver

 .../bindings/clock/amlogic,a9-aoclkc.yaml          |  76 ++++
 drivers/clk/meson/Kconfig                          |  13 +
 drivers/clk/meson/Makefile                         |   1 +
 drivers/clk/meson/a9-aoclk.c                       | 488 +++++++++++++++++++++
 include/dt-bindings/clock/amlogic,a9-aoclkc.h      |  76 ++++
 5 files changed, 654 insertions(+)
---
base-commit: ca89c88bcf69daca829044c638a8163d5ce47af0
change-id: 20260603-a9_aoclk-bbf531badc63

Best regards,
-- 
Jian Hu <jian.hu@amlogic.com>



^ permalink raw reply

* [PATCH v4 2/2] clk: amlogic: Add A9 AO clock controller driver
From: Jian Hu via B4 Relay @ 2026-06-18  9:49 UTC (permalink / raw)
  To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao,
	Kevin Hilman, Martin Blumenstingl
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Jian Hu
In-Reply-To: <20260618-a9_aoclk-v4-0-569d0425e50c@amlogic.com>

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 | 488 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 502 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..88aa8cf3f5d0
--- /dev/null
+++ b/drivers/clk/meson/a9-aoclk.c
@@ -0,0 +1,488 @@
+// 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,
+	},
+};
+
+static struct clk_regmap a9_ao_xtal = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = AO_OSCIN_CTRL,
+		.mask = 0x1,
+		.shift = 0,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ao_xtal",
+		.ops = &clk_regmap_mux_ops,
+		/* ext_32k is from external PAD, do not automatically reparent */
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a9_ao_xtal_in.hw },
+			{ .fw_name = "ext_32k", },
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_NO_REPARENT,
+	},
+};
+
+static struct clk_regmap a9_ao_sys = {
+	.data = &(struct clk_regmap_mux_data) {
+		.offset = AO_OSCIN_CTRL,
+		.mask = 0x1,
+		.shift = 1,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "ao_sys",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a9_ao_xtal.hw },
+			{ .fw_name = "sys", },
+		},
+		.num_parents = 2,
+	},
+};
+
+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 = &(struct clk_init_data) {
+		.name = "ao_rtc_duandiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_xtal.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "a9_ao_rtc_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_rtc_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "ao_rtc_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_rtc_dualdiv_div.hw,
+			&a9_ao_rtc_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "ao_rtc_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_rtc_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "ao_rtc",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_xtal.hw,
+			&a9_ao_rtc_dualdiv.hw,
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "ao_cec_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_xtal.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "ao_cec_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_cec_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "ao_cec_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_cec_dualdiv_div.hw,
+			&a9_ao_cec_dualdiv_in.hw,
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "ao_cec_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_cec_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "ao_cec",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ao_cec_dualdiv.hw,
+			&a9_ao_rtc.hw,
+		},
+		.num_parents = 2,
+		.flags = 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");

-- 
2.47.1



^ permalink raw reply related

* [PATCH v4 1/2] dt-bindings: clock: Add Amlogic A9 AO clock controller
From: Jian Hu via B4 Relay @ 2026-06-18  9:49 UTC (permalink / raw)
  To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao,
	Kevin Hilman, Martin Blumenstingl
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Jian Hu, Conor Dooley
In-Reply-To: <20260618-a9_aoclk-v4-0-569d0425e50c@amlogic.com>

From: Jian Hu <jian.hu@amlogic.com>

Add the Always-On clock controller dt-bindings for the Amlogic A9
SoC family.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
 .../bindings/clock/amlogic,a9-aoclkc.yaml          | 76 ++++++++++++++++++++++
 include/dt-bindings/clock/amlogic,a9-aoclkc.h      | 76 ++++++++++++++++++++++
 2 files changed, 152 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a9-aoclkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a9-aoclkc.yaml
new file mode 100644
index 000000000000..1fa9b3a32fbb
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a9-aoclkc.yaml
@@ -0,0 +1,76 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2026 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a9-aoclkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A9 Series Always-On Clock Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+  - Jerome Brunet <jbrunet@baylibre.com>
+  - Jian Hu <jian.hu@amlogic.com>
+  - Xianwei Zhao <xianwei.zhao@amlogic.com>
+
+properties:
+  compatible:
+    const: amlogic,a9-aoclkc
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    minItems: 5
+    items:
+      - description: input oscillator
+      - description: input fclk div 3
+      - description: input fclk div 4
+      - description: input fclk div 5
+      - description: input sys clk
+      - description: external fixed 32k (optional)
+
+  clock-names:
+    minItems: 5
+    items:
+      - const: xtal
+      - const: fdiv3
+      - const: fdiv4
+      - const: fdiv5
+      - const: sys
+      - const: ext_32k
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller@0 {
+            compatible = "amlogic,a9-aoclkc";
+            reg = <0x0 0x0 0x0 0x58>;
+            #clock-cells = <1>;
+            clocks = <&xtal>,
+                     <&scmi_clk 14>,
+                     <&scmi_clk 16>,
+                     <&scmi_clk 18>,
+                     <&scmi_clk 21>;
+            clock-names = "xtal",
+                          "fdiv3",
+                          "fdiv4",
+                          "fdiv5",
+                          "sys";
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,a9-aoclkc.h b/include/dt-bindings/clock/amlogic,a9-aoclkc.h
new file mode 100644
index 000000000000..a7d704d4b58e
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a9-aoclkc.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __AMLOGIC_A9_AO_CLKC_H
+#define __AMLOGIC_A9_AO_CLKC_H
+
+#define CLKID_AO_XTAL_IN			0
+#define CLKID_AO_XTAL				1
+#define CLKID_AO_SYS				2
+#define CLKID_AO_SYS_I3C			3
+#define CLKID_AO_SYS_RTC_REG			4
+#define CLKID_AO_SYS_CLKTREE			5
+#define CLKID_AO_SYS_RST_CTRL			6
+#define CLKID_AO_SYS_PAD			7
+#define CLKID_AO_SYS_RTC_DIG			8
+#define CLKID_AO_SYS_IRQ			9
+#define CLKID_AO_SYS_PWRCTRL			10
+#define CLKID_AO_SYS_PWM_A			11
+#define CLKID_AO_SYS_PWM_B			12
+#define CLKID_AO_SYS_PWM_C			13
+#define CLKID_AO_SYS_PWM_D			14
+#define CLKID_AO_SYS_PWM_E			15
+#define CLKID_AO_SYS_PWM_F			16
+#define CLKID_AO_SYS_PWM_G			17
+#define CLKID_AO_SYS_I2C_A			18
+#define CLKID_AO_SYS_I2C_B			19
+#define CLKID_AO_SYS_I2C_C			20
+#define CLKID_AO_SYS_I2C_D			21
+#define CLKID_AO_SYS_SED			22
+#define CLKID_AO_SYS_IR_CTRL			23
+#define CLKID_AO_SYS_UART_B			24
+#define CLKID_AO_SYS_UART_C			25
+#define CLKID_AO_SYS_UART_D			26
+#define CLKID_AO_SYS_UART_E			27
+#define CLKID_AO_SYS_SPISG_0			28
+#define CLKID_AO_SYS_RTC_SECURE			29
+#define CLKID_AO_SYS_CEC			30
+#define CLKID_AO_SYS_AOCPU			31
+#define CLKID_AO_SYS_SRAM			32
+#define CLKID_AO_SYS_SPISG_1			33
+#define CLKID_AO_SYS_SPISG_2			34
+#define CLKID_AO_PWM_A_SEL			35
+#define CLKID_AO_PWM_A_DIV			36
+#define CLKID_AO_PWM_A				37
+#define CLKID_AO_PWM_B_SEL			38
+#define CLKID_AO_PWM_B_DIV			39
+#define CLKID_AO_PWM_B				40
+#define CLKID_AO_PWM_C_SEL			41
+#define CLKID_AO_PWM_C_DIV			42
+#define CLKID_AO_PWM_C				43
+#define CLKID_AO_PWM_D_SEL			44
+#define CLKID_AO_PWM_D_DIV			45
+#define CLKID_AO_PWM_D				46
+#define CLKID_AO_PWM_E_SEL			47
+#define CLKID_AO_PWM_E_DIV			48
+#define CLKID_AO_PWM_E				49
+#define CLKID_AO_PWM_F_SEL			50
+#define CLKID_AO_PWM_F_DIV			51
+#define CLKID_AO_PWM_F				52
+#define CLKID_AO_PWM_G_SEL			53
+#define CLKID_AO_PWM_G_DIV			54
+#define CLKID_AO_PWM_G				55
+#define CLKID_AO_RTC_DUALDIV_IN			56
+#define CLKID_AO_RTC_DUALDIV_DIV		57
+#define CLKID_AO_RTC_DUALDIV_SEL		58
+#define CLKID_AO_RTC_DUALDIV			59
+#define CLKID_AO_RTC				60
+#define CLKID_AO_CEC_DUALDIV_IN			61
+#define CLKID_AO_CEC_DUALDIV_DIV		62
+#define CLKID_AO_CEC_DUALDIV_SEL		63
+#define CLKID_AO_CEC_DUALDIV			64
+#define CLKID_AO_CEC				65
+
+#endif  /* __AMLOGIC_A9_AO_CLKC_H */

-- 
2.47.1



^ permalink raw reply related

* Re: [PATCH v10 4/4] media: nxp: Add i.MX95 CSI pixel formatter v4l2 driver
From: sashiko-bot @ 2026-06-18  9:51 UTC (permalink / raw)
  To: guoniu.zhou; +Cc: devicetree, imx, robh, Frank.Li, conor+dt
In-Reply-To: <20260618-csi_formatter-v10-4-f23830312ba5@oss.nxp.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:
- [Critical] SINK and SOURCE stream masks are conflated, leading to a guaranteed NULL pointer dereference.
- [Critical] Missing NULL pointer checks for `v4l2_subdev_state_get_format()` allow unprivileged userspace to trigger kernel crashes.
- [High] Direct register writes to `CSI_VC_PIXEL_DATA_TYPE` corrupt hardware state for multiplexed streams sharing the same Virtual Channel.
- [High] The driver incorrectly bounds logical stream iteration to the hardware Virtual Channel count, leading to silent stream configuration failures and out-of-bounds array access potential.
- [High] Missing `.unbind` callback in the async notifier operations leaves a dangling pointer to the remote subdevice, resulting in a Use-After-Free.
- [Medium] The driver breaks UAPI by returning `-EINVAL` when setting a format on an unrouted pad, breaking standard userspace pipeline configuration flows.
- [Medium] Mixing `goto`-based error handling with scope-based cleanup helpers (`__free()` and `guard()`).
--

commit 91d3a7fba60671cec5f0a95a21622c4761779af5
Author: Guoniu Zhou <guoniu.zhou@nxp.com>
Date:   Thu Jun 18 09:41:38 2026 +0000

    media: nxp: Add i.MX95 CSI pixel formatter v4l2 driver

This commit introduces the V4L2 driver for the i.MX95 CSI pixel formatter
module. It provides support for data formatting, unpacking pixels from the
CSI-2 interface to match Pixel Link requirements.

> diff --git a/drivers/media/platform/nxp/imx95-csi-formatter.c b/drivers/media/platform/nxp/imx95-csi-formatter.c
> new file mode 100644
> index 0000000000000..cfe448fedd37e
> --- /dev/null
> +++ b/drivers/media/platform/nxp/imx95-csi-formatter.c
> @@ -0,0 +1,775 @@
[ ... ]
> +struct csi_formatter {
> +	struct device *dev;
[ ... ]
> +	/* Protects enabled_streams */
> +	struct mutex lock;
> +	u64 enabled_streams;
> +
> +	u8 stream_to_vc[CSI_FORMATTER_VC_NUM];

[Severity: High]
Does this array statically bound logical streams to the hardware Virtual Channel
limit?

The CSI_FORMATTER_VC_NUM constant is 8, representing the number of hardware VCs.
However, this array is later indexed by a logical V4L2 stream ID, which can
validly be up to 63. If the loop limit in csi_formatter_start_stream() were
corrected to 64 to resolve the stream ID limitation without changing this array
size, it would cause out-of-bounds writes.

[ ... ]
> +static int csi_formatter_subdev_enum_mbus_code(struct v4l2_subdev *sd,
> +					       struct v4l2_subdev_state *sd_state,
> +					       struct v4l2_subdev_mbus_code_enum *code)
> +{
> +	if (code->pad == CSI_FORMATTER_PAD_SOURCE) {
> +		struct v4l2_mbus_framefmt *fmt;
> +
> +		if (code->index > 0)
> +			return -EINVAL;
> +
> +		fmt = v4l2_subdev_state_get_format(sd_state, code->pad,
> +						   code->stream);
> +		code->code = fmt->code;

[Severity: Critical]
Is it possible for v4l2_subdev_state_get_format() to return NULL here?

The V4L2 core does not pre-validate that the logical stream ID provided by
userspace exists in the active routing state. If an invalid stream ID is
requested, the format pointer will be NULL. Reading fmt->code on this NULL
pointer will cause a kernel oops, potentially enabling a local denial of service.

[ ... ]
> +static int csi_formatter_subdev_set_fmt(struct v4l2_subdev *sd,
> +					struct v4l2_subdev_state *sd_state,
> +					struct v4l2_subdev_format *sdformat)
> +{
> +	struct csi_formatter_pix_format const *format;
> +	struct v4l2_mbus_framefmt *fmt;
[ ... ]
> +	v4l_bound_align_image(&sdformat->format.width, 1, 0xffff, 2,
> +			      &sdformat->format.height, 1, 0xffff, 0, 0);
> +
> +	fmt = v4l2_subdev_state_get_format(sd_state, sdformat->pad,
> +					   sdformat->stream);
> +	*fmt = sdformat->format;

[Severity: Critical]
Could this result in a NULL pointer dereference?

Similar to csi_formatter_subdev_enum_mbus_code(), if userspace provides an
invalid stream ID, v4l2_subdev_state_get_format() returns NULL. Writing
directly to *fmt will cause a kernel oops.

> +
> +	/* Set default code if user set an invalid value */
> +	fmt->code = format->code;
> +
> +	/* Propagate the format from sink stream to source stream */
> +	fmt = v4l2_subdev_state_get_opposite_stream_format(sd_state, sdformat->pad,
> +							   sdformat->stream);
> +	if (!fmt)
> +		return -EINVAL;

[Severity: Medium]
Should the driver reject setting formats on unrouted pads?

Standard V4L2 subdevice behavior requires drivers to accept the format on the
unrouted pad and simply skip propagation if no route exists. Returning -EINVAL
here enforces a strict requirement that userspace must establish routing before
setting formats, which breaks standard pipeline configuration flows like those
used by media-ctl.

[ ... ]
> +static void csi_formatter_stop_stream(struct csi_formatter *formatter,
> +				      u64 stream_mask)
> +{
> +	unsigned int i;
> +	u8 vc;
> +
> +	for (i = 0; i < CSI_FORMATTER_VC_NUM; ++i) {
> +		if (!(stream_mask & BIT(i)))
> +			continue;
> +
> +		/* Use the VC that was configured in start_stream */
> +		vc = formatter->stream_to_vc[i];
> +		if (vc >= CSI_FORMATTER_VC_NUM)
> +			continue;
> +
> +		csi_formatter_write(formatter, CSI_VC_PIXEL_DATA_TYPE(vc), 0);

[Severity: High]
Does writing 0 abruptly terminate all multiplexed streams on this Virtual
Channel?

The MIPI CSI-2 specification allows multiple streams with different Data Types
to be multiplexed onto a single VC. The register acts as a bitmask of enabled
Data Types. Directly writing 0 here tears down all streams on the VC instead
of just the target stream, breaking hardware multiplexing.

[ ... ]
> +static int csi_formatter_start_stream(struct csi_formatter *formatter,
> +				      struct v4l2_subdev_state *state,
> +				      u64 stream_mask)
> +{
[ ... ]
> +	for (i = 0; i < CSI_FORMATTER_VC_NUM; ++i) {
> +		if (!(stream_mask & BIT(i)))
> +			continue;
> +
> +		fmt = v4l2_subdev_state_get_format(state,
> +						   CSI_FORMATTER_PAD_SINK, i);
> +
> +		pix_fmt = csi_formatter_find_format(fmt->code);

[Severity: Critical]
Will this return NULL if the source stream ID differs from the sink stream ID?

In csi_formatter_subdev_enable_streams(), the streams_mask parameter represents
the bitmask of streams on the source pad, and it is passed verbatim to this
function. 

This loop iterates over the source stream bitmask, so i is a source stream ID.
Calling v4l2_subdev_state_get_format() with CSI_FORMATTER_PAD_SINK but passing
a source stream ID will return a NULL format pointer if that stream ID does not
exist on the sink pad (e.g., sink stream 1 routed to source stream 0). The code
then unconditionally dereferences fmt->code, causing a kernel panic.

Should the driver translate and iterate over the sink_streams mask instead?

[ ... ]
> +		/* Store the stream to VC mapping for stop_stream */
> +		formatter->stream_to_vc[i] = vc;
> +
> +		csi_formatter_write(formatter, CSI_VC_PIXEL_DATA_TYPE(vc), val);

[Severity: High]
Does this direct register write clear previously enabled Data Types on the
shared Virtual Channel?

Because this uses a direct register write instead of updating bits, it will
unconditionally clear all other active Data Types previously configured for
this VC, breaking hardware multiplexing.

[ ... ]
> +static int csi_formatter_subdev_enable_streams(struct v4l2_subdev *sd,
> +					       struct v4l2_subdev_state *state,
> +					       u32 pad, u64 streams_mask)
> +{
> +	struct csi_formatter *formatter = sd_to_formatter(sd);
> +	struct device *dev = formatter->dev;
> +	u64 sink_streams;
> +	int ret;
> +
> +	sink_streams = v4l2_subdev_state_xlate_streams(state,
> +						       CSI_FORMATTER_PAD_SOURCE,
> +						       CSI_FORMATTER_PAD_SINK,
> +						       &streams_mask);
> +	if (!sink_streams || !streams_mask)
> +		return -EINVAL;
> +
> +	guard(mutex)(&formatter->lock);

[Severity: Medium]
Is it safe to mix guard(mutex) block scoping with goto labels for runtime
power management rollback?

The kernel's subsystem guidelines for cleanup functions state that the usage of
goto and cleanup helpers must never be mixed within the same function due to the
risk of confusing ownership semantics and ordering bugs.

[ ... ]
> +	ret = csi_formatter_start_stream(formatter, state, streams_mask);

[Severity: Critical]
Is the wrong stream mask passed to csi_formatter_start_stream() here?

The variable streams_mask represents the bitmask of streams on the source pad.
However, csi_formatter_start_stream() uses this mask to query formats on the
sink pad.

Should sink_streams be passed to csi_formatter_start_stream() instead to avoid
querying invalid stream IDs on the sink pad?

[ ... ]
> +static const struct v4l2_async_notifier_operations formatter_notify_ops = {
> +	.bound = csi_formatter_notify_bound,
> +};

[Severity: High]
Is an .unbind callback needed to clean up the stale remote subdevice pointer?

The driver caches a pointer to the bound source subdevice in
formatter->csi_sd during the .bound callback. However, this operations
structure does not provide an .unbind callback to set this pointer to NULL
when the remote subdevice is unbound and removed. 

If the source driver module is unloaded, the pointer becomes dangling. A
subsequent streaming operation would dereference the freed memory in
v4l2_subdev_enable_streams() and cause a kernel oops.

> +
> +static int csi_formatter_async_register(struct csi_formatter *formatter)
> +{
> +	struct device *dev = formatter->dev;
> +	struct v4l2_async_connection *asc;
> +	int ret;
> +
> +	struct fwnode_handle *ep __free(fwnode_handle) =
> +		fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
> +						FWNODE_GRAPH_ENDPOINT_NEXT);
> +	if (!ep)
> +		return -ENOTCONN;
> +
> +	v4l2_async_subdev_nf_init(&formatter->notifier, &formatter->sd);
> +
> +	asc = v4l2_async_nf_add_fwnode_remote(&formatter->notifier, ep,
> +					      struct v4l2_async_connection);
> +	if (IS_ERR(asc)) {
> +		ret = PTR_ERR(asc);
> +		goto err_cleanup_notifier;

[Severity: Medium]
Does this mix __free(fwnode_handle) with goto-based error tracking?

Using __free() alongside goto-based unwinding in the same function violates
cleanup function guidelines, which can lead to double-frees or resource leaks.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-csi_formatter-v10-0-f23830312ba5@oss.nxp.com?part=4

^ permalink raw reply

* Re: [PATCH v2] arm64: dts: qcom: talos: Add passive polling-delay for gpu-thermal zone
From: Konrad Dybcio @ 2026-06-18  9:51 UTC (permalink / raw)
  To: haritha.k, Bjorn Andersson, Konrad Dybcio, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-msm, devicetree, linux-kernel, manaf.pallikunhi,
	gaurav.kohli
In-Reply-To: <20260505-qcs615_gpu_cooling-v2-1-1ba42260b29d@oss.qualcomm.com>

On 5/5/26 1:26 PM, Haritha S K via B4 Relay wrote:
> From: Haritha S K <haritha.k@oss.qualcomm.com>
> 
> Introduce a passive polling delay to ensure more than one
> "passive" thermal point is considered when throttling the GPU
> thermal zone.
> 
> Signed-off-by: Haritha S K <haritha.k@oss.qualcomm.com>
> ---

Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>

Konrad

^ permalink raw reply

* [PATCH v4 0/2] clk: amlogic: Add A9 peripherals clock controller
From: Jian Hu via B4 Relay @ 2026-06-18  9:51 UTC (permalink / raw)
  To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao,
	Kevin Hilman, Martin Blumenstingl
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Jian Hu, Conor Dooley

This series adds Amlogic A9 peripherals clock support,
including dt-binding and peripherals clock driver.

Note that this driver depends on the A9 PLL driver, which is not yet
upstream. The Meson PLL framework is currently undergoing refactoring,
and the A9 PLL driver will be submitted as a follow-up series after
that work has been completed.

Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
Changes in v4:
- Expose channel 3 for gen_clk.
- Add suffix 0 for some clocks.
- Use helper macro for vclk clocks definitions.
- Drop forward declaration.
- Drop CLK_HW_INIT* and revert to explicit clock declarations.
- Fix can clock channel number comment.
- Rename enc clocks to encoder0/encoder1.
- Link to v3: https://lore.kernel.org/r/20260610-a9_peripherals-v3-0-d07a78085f71@amlogic.com

Changes in v3:
- Add "depend on A9 pll" instructions in the cover-letter.
- Move COMPILE_TEST after 'depends on ARM64' reported by sashiko-bot.
- Fix usb_48m_pre_sel's parent reported by sashiko-bot.
- Fix gen_div width reported by sashiko-bot.
- Fix hdmitx1_pixel's parent reported by sashiko-bot.
- Link to v2: https://lore.kernel.org/r/20260603-a9_peripherals-v2-0-ee1b8c0a1e6c@amlogic.com

Changes in v2:
- Split the A9 clock driver and send the peripherals clock separately.
- Add COMPILE_TEST in Kconfig.
- Drop the 'optional'.
- Rename apb4 to soc.
- Sort the header file.
- Rename hifi to hifi0.
- Use CLK_HW_INIT_PARENTS_DATA to describe clk_init_data.
- Use CLK_HW_INIT_HW to describe clk_init_data.
- Use CLK_HW_INIT_PARENTS_HW to describe clk_init_data.
- Link to v1: https://lore.kernel.org/all/20260511-b4-a9_clk-v1-0-41cb4071b7c9@amlogic.com/

---
Jian Hu (2):
      dt-bindings: clock: Add Amlogic A9 peripherals clock controller
      clk: amlogic: Add A9 peripherals clock controller driver

 .../clock/amlogic,a9-peripherals-clkc.yaml         |  164 ++
 drivers/clk/meson/Kconfig                          |   15 +
 drivers/clk/meson/Makefile                         |    1 +
 drivers/clk/meson/a9-peripherals.c                 | 2096 ++++++++++++++++++++
 .../clock/amlogic,a9-peripherals-clkc.h            |  352 ++++
 5 files changed, 2628 insertions(+)
---
base-commit: ca89c88bcf69daca829044c638a8163d5ce47af0
change-id: 20260603-a9_peripherals-4214e79705dc

Best regards,
-- 
Jian Hu <jian.hu@amlogic.com>



^ permalink raw reply

* [PATCH v4 1/2] dt-bindings: clock: Add Amlogic A9 peripherals clock controller
From: Jian Hu via B4 Relay @ 2026-06-18  9:51 UTC (permalink / raw)
  To: Neil Armstrong, Jerome Brunet, Michael Turquette, Stephen Boyd,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao,
	Kevin Hilman, Martin Blumenstingl
  Cc: linux-amlogic, linux-clk, devicetree, linux-kernel,
	linux-arm-kernel, Jian Hu, Conor Dooley
In-Reply-To: <20260618-a9_peripherals-v4-0-fe120de44e77@amlogic.com>

From: Jian Hu <jian.hu@amlogic.com>

Add the peripherals clock controller dt-bindings for the Amlogic A9
SoC family.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
 .../clock/amlogic,a9-peripherals-clkc.yaml         | 164 ++++++++++
 .../clock/amlogic,a9-peripherals-clkc.h            | 352 +++++++++++++++++++++
 2 files changed, 516 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a9-peripherals-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a9-peripherals-clkc.yaml
new file mode 100644
index 000000000000..f0aef005ecf3
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a9-peripherals-clkc.yaml
@@ -0,0 +1,164 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2026 Amlogic, Inc. All rights reserved
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a9-peripherals-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A9 Series Peripherals Clock Controller
+
+maintainers:
+  - Neil Armstrong <neil.armstrong@linaro.org>
+  - Jerome Brunet <jbrunet@baylibre.com>
+  - Jian Hu <jian.hu@amlogic.com>
+  - Xianwei Zhao <xianwei.zhao@amlogic.com>
+
+properties:
+  compatible:
+    const: amlogic,a9-peripherals-clkc
+
+  reg:
+    maxItems: 1
+
+  '#clock-cells':
+    const: 1
+
+  clocks:
+    minItems: 27
+    items:
+      - description: input oscillator
+      - description: input fclk div 2
+      - description: input fclk div 3
+      - description: input fclk div 4
+      - description: input fclk div 5
+      - description: input fclk div 7
+      - description: input fclk div 2p5
+      - description: input sys clk
+      - description: input gp1 pll
+      - description: input gp2 pll
+      - description: input sys pll div 16
+      - description: input cpu clk div 16
+      - description: input a78 clk div 16
+      - description: input dsu clk div 16
+      - description: input rtc clk
+      - description: input gp0 pll
+      - description: input hifi0 pll
+      - description: input hifi1 pll
+      - description: input mclk0 pll
+      - description: input mclk1 pll
+      - description: input video1 pll
+      - description: input video2 pll
+      - description: input hdmi out2 clk
+      - description: input hdmi pixel clk
+      - description: input pixel0 pll
+      - description: input pixel1 pll
+      - description: input ddr pll test clk
+      - description: external input rmii oscillator (optional)
+
+  clock-names:
+    minItems: 27
+    items:
+      - const: xtal
+      - const: fdiv2
+      - const: fdiv3
+      - const: fdiv4
+      - const: fdiv5
+      - const: fdiv7
+      - const: fdiv2p5
+      - const: sys
+      - const: gp1
+      - const: gp2
+      - const: sysplldiv16
+      - const: cpudiv16
+      - const: a78div16
+      - const: dsudiv16
+      - const: rtc
+      - const: gp0
+      - const: hifi0
+      - const: hifi1
+      - const: mclk0
+      - const: mclk1
+      - const: vid1
+      - const: vid2
+      - const: hdmiout2
+      - const: hdmipix
+      - const: pix0
+      - const: pix1
+      - const: ddr_test
+      - const: ext_rmii
+
+required:
+  - compatible
+  - reg
+  - '#clock-cells'
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        clock-controller@200 {
+            compatible = "amlogic,a9-peripherals-clkc";
+            reg = <0x0 0x200 0x0 0x2f8>;
+            #clock-cells = <1>;
+            clocks = <&xtal>,
+                     <&scmi_clk 10>,
+                     <&scmi_clk 12>,
+                     <&scmi_clk 14>,
+                     <&scmi_clk 16>,
+                     <&scmi_clk 18>,
+                     <&scmi_clk 20>,
+                     <&scmi_clk 21>,
+                     <&scmi_clk 33>,
+                     <&scmi_clk 34>,
+                     <&scmi_clk 35>,
+                     <&scmi_clk 36>,
+                     <&scmi_clk 37>,
+                     <&scmi_clk 38>,
+                     <&scmi_clk 40>,
+                     <&gp0 3>,
+                     <&hifi0 3>,
+                     <&hifi1 3>,
+                     <&mclk0 3>,
+                     <&mclk1 3>,
+                     <&vid1>,
+                     <&vid2>,
+                     <&hdmitx 10>,
+                     <&hdmitx 11>,
+                     <&pix0>,
+                     <&pix1>,
+                     <&ddr 3>;
+            clock-names = "xtal",
+                          "fdiv2",
+                          "fdiv3",
+                          "fdiv4",
+                          "fdiv5",
+                          "fdiv7",
+                          "fdiv2p5",
+                          "sys",
+                          "gp1",
+                          "gp2",
+                          "sysplldiv16",
+                          "cpudiv16",
+                          "a78div16",
+                          "dsudiv16",
+                          "rtc",
+                          "gp0",
+                          "hifi0",
+                          "hifi1",
+                          "mclk0",
+                          "mclk1",
+                          "vid1",
+                          "vid2",
+                          "hdmiout2",
+                          "hdmipix",
+                          "pix0",
+                          "pix1",
+                          "ddr_test";
+        };
+    };
diff --git a/include/dt-bindings/clock/amlogic,a9-peripherals-clkc.h b/include/dt-bindings/clock/amlogic,a9-peripherals-clkc.h
new file mode 100644
index 000000000000..50b8f96b435e
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a9-peripherals-clkc.h
@@ -0,0 +1,352 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __AMLOGIC_A9_PERIPHERALS_CLKC_H
+#define __AMLOGIC_A9_PERIPHERALS_CLKC_H
+
+#define CLKID_SYS_AM_AXI			0
+#define CLKID_SYS_DOS				1
+#define CLKID_SYS_MIPI_DSI			2
+#define CLKID_SYS_ETH_PHY			3
+#define CLKID_SYS_AMFC				4
+#define CLKID_SYS_MALI				5
+#define CLKID_SYS_NNA				6
+#define CLKID_SYS_ETH_AXI			7
+#define CLKID_SYS_DP_APB			8
+#define CLKID_SYS_EDPTX_APB			9
+#define CLKID_SYS_U3HSG				10
+#define CLKID_SYS_AUCPU				11
+#define CLKID_SYS_GLB				12
+#define CLKID_SYS_COMBO_DPHY_APB		13
+#define CLKID_SYS_HDMIRX_APB			14
+#define CLKID_SYS_HDMIRX_PCLK			15
+#define CLKID_SYS_MIPI_DSI_PHY			16
+#define CLKID_SYS_CAN0				17
+#define CLKID_SYS_CAN1				18
+#define CLKID_SYS_SD_EMMC_A			19
+#define CLKID_SYS_SD_EMMC_B			20
+#define CLKID_SYS_SD_EMMC_C			21
+#define CLKID_SYS_SC				22
+#define CLKID_SYS_ACODEC			23
+#define CLKID_SYS_MIPI_ISP			24
+#define CLKID_SYS_MSR				25
+#define CLKID_SYS_AUDIO				26
+#define CLKID_SYS_MIPI_DSI_B			27
+#define CLKID_SYS_MIPI_DSI1_PHY			28
+#define CLKID_SYS_ETH				29
+#define CLKID_SYS_ETH_1G_MAC			30
+#define CLKID_SYS_UART_A			31
+#define CLKID_SYS_UART_F			32
+#define CLKID_SYS_TS_A55			33
+#define CLKID_SYS_ETH_1G_AXI			34
+#define CLKID_SYS_TS_DOS			35
+#define CLKID_SYS_U3DRD_B			36
+#define CLKID_SYS_TS_CORE			37
+#define CLKID_SYS_TS_PLL			38
+#define CLKID_SYS_CSI_DIG_CLKIN			39
+#define CLKID_SYS_CVE				40
+#define CLKID_SYS_GE2D				41
+#define CLKID_SYS_SPISG				42
+#define CLKID_SYS_U3DRD_1			43
+#define CLKID_SYS_U2H				44
+#define CLKID_SYS_PCIE_MAC_A			45
+#define CLKID_SYS_U3DRD_A			46
+#define CLKID_SYS_U2DRD				47
+#define CLKID_SYS_PCIE_PHY			48
+#define CLKID_SYS_PCIE_MAC_B			49
+#define CLKID_SYS_PERIPH			50
+#define CLKID_SYS_PIO				51
+#define CLKID_SYS_I3C				52
+#define CLKID_SYS_I2C_M_E			53
+#define CLKID_SYS_I2C_M_F			54
+#define CLKID_SYS_HDMITX_APB			55
+#define CLKID_SYS_I2C_M_I			56
+#define CLKID_SYS_I2C_M_G			57
+#define CLKID_SYS_I2C_M_H			58
+#define CLKID_SYS_HDMI20_AES			59
+#define CLKID_SYS_CSI2_HOST			60
+#define CLKID_SYS_CSI2_ADAPT			61
+#define CLKID_SYS_DSPA				62
+#define CLKID_SYS_PP_DMA			63
+#define CLKID_SYS_PP_WRAPPER			64
+#define CLKID_SYS_VPU_INTR			65
+#define CLKID_SYS_CSI2_PHY			66
+#define CLKID_SYS_SARADC			67
+#define CLKID_SYS_PWM_J				68
+#define CLKID_SYS_PWM_I				69
+#define CLKID_SYS_PWM_H				70
+#define CLKID_SYS_PWM_N				71
+#define CLKID_SYS_PWM_M				72
+#define CLKID_SYS_PWM_L				73
+#define CLKID_SYS_PWM_K				74
+#define CLKID_SD_EMMC_A_SEL			75
+#define CLKID_SD_EMMC_A_DIV			76
+#define CLKID_SD_EMMC_A				77
+#define CLKID_SD_EMMC_B_SEL			78
+#define CLKID_SD_EMMC_B_DIV			79
+#define CLKID_SD_EMMC_B				80
+#define CLKID_SD_EMMC_C_SEL			81
+#define CLKID_SD_EMMC_C_DIV			82
+#define CLKID_SD_EMMC_C				83
+#define CLKID_PWM_H_SEL				84
+#define CLKID_PWM_H_DIV				85
+#define CLKID_PWM_H				86
+#define CLKID_PWM_I_SEL				87
+#define CLKID_PWM_I_DIV				88
+#define CLKID_PWM_I				89
+#define CLKID_PWM_J_SEL				90
+#define CLKID_PWM_J_DIV				91
+#define CLKID_PWM_J				92
+#define CLKID_PWM_K_SEL				93
+#define CLKID_PWM_K_DIV				94
+#define CLKID_PWM_K				95
+#define CLKID_PWM_L_SEL				96
+#define CLKID_PWM_L_DIV				97
+#define CLKID_PWM_L				98
+#define CLKID_PWM_M_SEL				99
+#define CLKID_PWM_M_DIV				100
+#define CLKID_PWM_M				101
+#define CLKID_PWM_N_SEL				102
+#define CLKID_PWM_N_DIV				103
+#define CLKID_PWM_N				104
+#define CLKID_SPISG0_SEL			105
+#define CLKID_SPISG0_DIV			106
+#define CLKID_SPISG0				107
+#define CLKID_SPISG1_SEL			108
+#define CLKID_SPISG1_DIV			109
+#define CLKID_SPISG1				110
+#define CLKID_SPISG2_SEL			111
+#define CLKID_SPISG2_DIV			112
+#define CLKID_SPISG2				113
+#define CLKID_SARADC_SEL			114
+#define CLKID_SARADC_DIV			115
+#define CLKID_SARADC				116
+#define CLKID_AMFC_SEL				117
+#define CLKID_AMFC_DIV				118
+#define CLKID_AMFC				119
+#define CLKID_NNA_SEL				120
+#define CLKID_NNA_DIV				121
+#define CLKID_NNA				122
+#define CLKID_USB_250M_SEL			123
+#define CLKID_USB_250M_DIV			124
+#define CLKID_USB_250M				125
+#define CLKID_USB_48M_PRE_SEL			126
+#define CLKID_USB_48M_PRE_DIV			127
+#define CLKID_USB_48M_PRE			128
+#define CLKID_PCIE0_TL_SEL			129
+#define CLKID_PCIE0_TL_DIV			130
+#define CLKID_PCIE0_TL				131
+#define CLKID_PCIE1_TL_SEL			132
+#define CLKID_PCIE1_TL_DIV			133
+#define CLKID_PCIE1_TL				134
+#define CLKID_CMPR_SEL				135
+#define CLKID_CMPR_DIV				136
+#define CLKID_CMPR				137
+#define CLKID_DEWARPA_SEL			138
+#define CLKID_DEWARPA_DIV			139
+#define CLKID_DEWARPA				140
+#define CLKID_SC_PRE_SEL			141
+#define CLKID_SC_PRE_DIV			142
+#define CLKID_SC_PRE				143
+#define CLKID_SC				144
+#define CLKID_DPTX_APB2_SEL			145
+#define CLKID_DPTX_APB2_DIV			146
+#define CLKID_DPTX_APB2				147
+#define CLKID_DPTX_AUD_SEL			148
+#define CLKID_DPTX_AUD_DIV			149
+#define CLKID_DPTX_AUD				150
+#define CLKID_ISP_SEL				151
+#define CLKID_ISP_DIV				152
+#define CLKID_ISP				153
+#define CLKID_CVE_SEL				154
+#define CLKID_CVE_DIV				155
+#define CLKID_CVE				156
+#define CLKID_VGE_SEL				157
+#define CLKID_VGE_DIV				158
+#define CLKID_VGE				159
+#define CLKID_PP_SEL				160
+#define CLKID_PP_DIV				161
+#define CLKID_PP				162
+#define CLKID_GLB_SEL				163
+#define CLKID_GLB_DIV				164
+#define CLKID_GLB				165
+#define CLKID_USB_48M_DUALDIV_IN		166
+#define CLKID_USB_48M_DUALDIV_DIV		167
+#define CLKID_USB_48M_DUALDIV_SEL		168
+#define CLKID_USB_48M_DUALDIV			169
+#define CLKID_USB_48M				170
+#define CLKID_CAN0_PE_SEL			171
+#define CLKID_CAN0_PE_DIV			172
+#define CLKID_CAN0_PE				173
+#define CLKID_CAN1_PE_SEL			174
+#define CLKID_CAN1_PE_DIV			175
+#define CLKID_CAN1_PE				176
+#define CLKID_CAN0_FILTER_SEL			177
+#define CLKID_CAN0_FILTER_DIV			178
+#define CLKID_CAN0_FILTER			179
+#define CLKID_CAN1_FILTER_SEL			180
+#define CLKID_CAN1_FILTER_DIV			181
+#define CLKID_CAN1_FILTER			182
+#define CLKID_I3C_SEL				183
+#define CLKID_I3C_DIV				184
+#define CLKID_I3C				185
+#define CLKID_TS_DIV				186
+#define CLKID_TS				187
+#define CLKID_ETH_125M_DIV			188
+#define CLKID_ETH_125M				189
+#define CLKID_ETH_RMII_SEL			190
+#define CLKID_ETH_RMII_DIV			191
+#define CLKID_ETH_RMII				192
+#define CLKID_GEN_SEL				193
+#define CLKID_GEN_DIV				194
+#define CLKID_GEN				195
+#define CLKID_CLK24M_IN				196
+#define CLKID_CLK12_24M				197
+#define CLKID_MALI_0_SEL			198
+#define CLKID_MALI_0_DIV			199
+#define CLKID_MALI_0				200
+#define CLKID_MALI_1_SEL			201
+#define CLKID_MALI_1_DIV			202
+#define CLKID_MALI_1				203
+#define CLKID_MALI				204
+#define CLKID_MALI_STACK_0_SEL			205
+#define CLKID_MALI_STACK_0_DIV			206
+#define CLKID_MALI_STACK_0			207
+#define CLKID_MALI_STACK_1_SEL			208
+#define CLKID_MALI_STACK_1_DIV			209
+#define CLKID_MALI_STACK_1			210
+#define CLKID_MALI_STACK			211
+#define CLKID_DSPA_0_SEL			212
+#define CLKID_DSPA_0_DIV			213
+#define CLKID_DSPA_0				214
+#define CLKID_DSPA_1_SEL			215
+#define CLKID_DSPA_1_DIV			216
+#define CLKID_DSPA_1				217
+#define CLKID_DSPA				218
+#define CLKID_HEVCF_0_SEL			219
+#define CLKID_HEVCF_0_DIV			220
+#define CLKID_HEVCF_0				221
+#define CLKID_HEVCF_1_SEL			222
+#define CLKID_HEVCF_1_DIV			223
+#define CLKID_HEVCF_1				224
+#define CLKID_HEVCF				225
+#define CLKID_HCODEC_0_SEL			226
+#define CLKID_HCODEC_0_DIV			227
+#define CLKID_HCODEC_0				228
+#define CLKID_HCODEC_1_SEL			229
+#define CLKID_HCODEC_1_DIV			230
+#define CLKID_HCODEC_1				231
+#define CLKID_HCODEC				232
+#define CLKID_VPU_0_SEL				233
+#define CLKID_VPU_0_DIV				234
+#define CLKID_VPU_0				235
+#define CLKID_VPU_1_SEL				236
+#define CLKID_VPU_1_DIV				237
+#define CLKID_VPU_1				238
+#define CLKID_VPU				239
+#define CLKID_VAPB_0_SEL			240
+#define CLKID_VAPB_0_DIV			241
+#define CLKID_VAPB_0				242
+#define CLKID_VAPB_1_SEL			243
+#define CLKID_VAPB_1_DIV			244
+#define CLKID_VAPB_1				245
+#define CLKID_VAPB				246
+#define CLKID_GE2D				247
+#define CLKID_VPU_CLKB_TMP_SEL			248
+#define CLKID_VPU_CLKB_TMP_DIV			249
+#define CLKID_VPU_CLKB_TMP			250
+#define CLKID_VPU_CLKB_DIV			251
+#define CLKID_VPU_CLKB				252
+#define CLKID_HDMITX_SYS_SEL			253
+#define CLKID_HDMITX_SYS_DIV			254
+#define CLKID_HDMITX_SYS			255
+#define CLKID_HDMITX_PRIF_SEL			256
+#define CLKID_HDMITX_PRIF_DIV			257
+#define CLKID_HDMITX_PRIF			258
+#define CLKID_HDMITX_200M_SEL			259
+#define CLKID_HDMITX_200M_DIV			260
+#define CLKID_HDMITX_200M			261
+#define CLKID_HDMITX_AUD_SEL			262
+#define CLKID_HDMITX_AUD_DIV			263
+#define CLKID_HDMITX_AUD			264
+#define CLKID_HDMIRX_5M_SEL			265
+#define CLKID_HDMIRX_5M_DIV			266
+#define CLKID_HDMIRX_5M				267
+#define CLKID_HDMIRX_2M_SEL			268
+#define CLKID_HDMIRX_2M_DIV			269
+#define CLKID_HDMIRX_2M				270
+#define CLKID_HDMIRX_CFG_SEL			271
+#define CLKID_HDMIRX_CFG_DIV			272
+#define CLKID_HDMIRX_CFG			273
+#define CLKID_HDMIRX_HDCP2X_SEL			274
+#define CLKID_HDMIRX_HDCP2X_DIV			275
+#define CLKID_HDMIRX_HDCP2X			276
+#define CLKID_HDMIRX_ACR_REF_SEL		277
+#define CLKID_HDMIRX_ACR_REF_DIV		278
+#define CLKID_HDMIRX_ACR_REF			279
+#define CLKID_HDMIRX_METER_SEL			280
+#define CLKID_HDMIRX_METER_DIV			281
+#define CLKID_HDMIRX_METER			282
+#define CLKID_VID_LOCK_SEL			283
+#define CLKID_VID_LOCK_DIV			284
+#define CLKID_VID_LOCK				285
+#define CLKID_VDIN_MEAS_SEL			286
+#define CLKID_VDIN_MEAS_DIV			287
+#define CLKID_VDIN_MEAS				288
+#define CLKID_VID_PLL_DIV			289
+#define CLKID_VID_PLL_SEL			290
+#define CLKID_VID_PLL				291
+#define CLKID_VID_PLL_VCLK			292
+#define CLKID_VCLK0_SEL				293
+#define CLKID_VCLK0_IN				294
+#define CLKID_VCLK0_DIV				295
+#define CLKID_VCLK0				296
+#define CLKID_VCLK0_DIV1_EN			297
+#define CLKID_VCLK0_DIV2_EN			298
+#define CLKID_VCLK0_DIV2			299
+#define CLKID_VCLK0_DIV4_EN			300
+#define CLKID_VCLK0_DIV4			301
+#define CLKID_VCLK0_DIV6_EN			302
+#define CLKID_VCLK0_DIV6			303
+#define CLKID_VCLK0_DIV12_EN			304
+#define CLKID_VCLK0_DIV12			305
+#define CLKID_VCLK1_SEL				306
+#define CLKID_VCLK1_IN				307
+#define CLKID_VCLK1_DIV				308
+#define CLKID_VCLK1				309
+#define CLKID_VCLK1_DIV1_EN			310
+#define CLKID_VCLK1_DIV2_EN			311
+#define CLKID_VCLK1_DIV2			312
+#define CLKID_VCLK1_DIV4_EN			313
+#define CLKID_VCLK1_DIV4			314
+#define CLKID_VCLK1_DIV6_EN			315
+#define CLKID_VCLK1_DIV6			316
+#define CLKID_VCLK1_DIV12_EN			317
+#define CLKID_VCLK1_DIV12			318
+#define CLKID_VDAC_SEL				319
+#define CLKID_VDAC				320
+#define CLKID_ENCODER0_SEL			321
+#define CLKID_ENCODER0				322
+#define CLKID_ENCODER1_SEL			323
+#define CLKID_ENCODER1				324
+#define CLKID_HDMITX_PIXEL_SEL			325
+#define CLKID_HDMITX_PIXEL			326
+#define CLKID_HDMITX_FE_SEL			327
+#define CLKID_HDMITX_FE				328
+#define CLKID_HDMITX1_PIXEL_SEL			329
+#define CLKID_HDMITX1_PIXEL			330
+#define CLKID_HDMITX1_FE_SEL			331
+#define CLKID_HDMITX1_FE			332
+#define CLKID_CSI_PHY_SEL			333
+#define CLKID_CSI_PHY_DIV			334
+#define CLKID_CSI_PHY				335
+#define CLKID_DSI_MEAS_SEL			336
+#define CLKID_DSI_MEAS_DIV			337
+#define CLKID_DSI_MEAS				338
+#define CLKID_DSI_B_MEAS_SEL			339
+#define CLKID_DSI_B_MEAS_DIV			340
+#define CLKID_DSI_B_MEAS			341
+
+#endif  /* __AMLOGIC_A9_PERIPHERALS_CLKC_H */

-- 
2.47.1



^ permalink raw reply related

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

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 | 2096 ++++++++++++++++++++++++++++++++++++
 3 files changed, 2112 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..8e0ae3205d77
--- /dev/null
+++ b/drivers/clk/meson/a9-peripherals.c
@@ -0,0 +1,2096 @@
+// 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(spisg0, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL);
+static A9_COMP_DIV(spisg0, SPISG_CLK_CTRL, 0, 6);
+static A9_COMP_GATE(spisg0, 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(pcie0_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents,
+		   NULL);
+static A9_COMP_DIV(pcie0_tl, PCIE_TL_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(pcie0_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 = &(struct clk_init_data) {
+		.name = "sc",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_sc_pre.hw
+		},
+		.num_parents = 1,
+		.flags = 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);
+
+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 = &(struct clk_init_data){
+		.name = "dspa",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_dspa_0.hw,
+			&a9_dspa_1.hw
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* Channel 6 is unconnected. */
+static u32 a9_glb_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 7 };
+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 = &(struct clk_init_data) {
+		.name = "usb_48m_dualdiv_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_usb_48m_pre.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data) {
+		.name = "usb_48m_dualdiv_div",
+		.ops = &meson_clk_dualdiv_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_usb_48m_dualdiv_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data) {
+		.name = "usb_48m_dualdiv_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_usb_48m_dualdiv_in.hw,
+			&a9_usb_48m_dualdiv_div.hw,
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "usb_48m_dualdiv",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_usb_48m_dualdiv_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "usb_48m",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_usb_48m_pre.hw,
+			&a9_usb_48m_dualdiv.hw,
+		},
+		.num_parents = 2,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/* Channel 2 is unconnected. */
+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(can0_pe, CAN_CLK_CTRL, 9, 0x7, a9_can_pe_parents, a9_can_pe_parents_val_table);
+static A9_COMP_DIV(can0_pe, CAN_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(can0_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(can0_filter, CAN_CLK_CTRL1, 9, 0x7, a9_can_filter_parents, NULL);
+static A9_COMP_DIV(can0_filter, CAN_CLK_CTRL1, 0, 7);
+static A9_COMP_GATE(can0_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 = &(struct clk_init_data) {
+		.name = "ts_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a9_ts = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = TS_CLK_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "ts",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_ts_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_fixed_factor a9_eth_125m_div = {
+	.mult = 1,
+	.div = 8,
+	.hw.init = &(struct clk_init_data) {
+		.name = "eth_125m_div",
+		.ops = &clk_fixed_factor_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "fdiv2",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a9_eth_125m = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = ETH_CLK_CTRL,
+		.bit_idx = 7,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "eth_125m",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_eth_125m_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * Channel 1, 2, 3, 4, 5 and 6 are unconnected,
+ * Channel 7(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 = &(struct clk_init_data){
+		.name = "eth_rmii_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = a9_eth_rmii_parents,
+		.num_parents = ARRAY_SIZE(a9_eth_rmii_parents),
+		.flags = 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 = &(struct clk_init_data){
+		.name = "eth_rmii_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_eth_rmii_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "eth_rmii",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_eth_rmii_div.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+/*
+ * Channel 12 (msr_clk) is managed by the clock measurement module and is not part of the clock
+ * tree. It depends on the measurement source selected through the measurement control registers.
+ *
+ * Channel 10, 11, 13, 14 and 16 are unconnected.
+ */
+static u32 a9_gen_parents_val_table[] = { 0, 1, 2, 3, 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" },
+	{ .fw_name = "ddr_test" },
+	{ .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 = &(struct clk_init_data) {
+		.name = "24m_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_data = &(const struct clk_parent_data) {
+			.fw_name = "xtal",
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a9_12_24m = {
+	.data = &(struct clk_regmap_div_data) {
+		.offset = CLK12_24_CTRL,
+		.shift = 10,
+		.width = 1,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "12_24m",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_24m_in.hw
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "mali",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_mali_0.hw,
+			&a9_mali_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "mali_stack",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_mali_stack_0.hw,
+			&a9_mali_stack_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hevcf",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hevcf_0.hw,
+			&a9_hevcf_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hcodec",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hcodec_0.hw,
+			&a9_hcodec_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "vpu",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vpu_0.hw,
+			&a9_vpu_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "vapb",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vapb_0.hw,
+			&a9_vapb_1.hw
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "ge2d",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vapb.hw,
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data) {
+		.name = "vpu_clkb_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vpu_clkb_tmp.hw,
+		},
+		.num_parents = 1,
+	},
+};
+
+static struct clk_regmap a9_vpu_clkb = {
+	.data = &(struct clk_regmap_gate_data) {
+		.offset = VPU_CLKB_CTRL,
+		.bit_idx = 8,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vpu_clkb",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vpu_clkb_div.hw
+		},
+		.num_parents = 1,
+		.flags = 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_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 = &(struct clk_init_data) {
+		.name = "vid_pll_div",
+		.ops = &meson_vid_pll_div_ro_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .fw_name = "hdmiout2", }
+		},
+		.num_parents = 1,
+	},
+};
+
+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 = &(struct clk_init_data){
+		.name = "vid_pll_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a9_vid_pll_div.hw },
+			{ .fw_name = "hdmiout2", }
+		},
+		.num_parents = 2,
+		.flags = 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 = &(struct clk_init_data) {
+		.name = "vid_pll",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vid_pll_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "vid_pll_vclk",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = (const struct clk_parent_data []) {
+			{ .hw = &a9_vid_pll.hw },
+			{ .fw_name = "hdmipix", }
+		},
+		.num_parents = 2,
+	},
+};
+
+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_vclk0_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = VID_CLK_CTRL,
+		.mask = 0x7,
+		.shift = 16,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk0_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = a9_vclk_parents,
+		.num_parents = ARRAY_SIZE(a9_vclk_parents),
+	},
+};
+
+static struct clk_regmap a9_vclk0_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_DIV,
+		.bit_idx = 16,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk0_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &a9_vclk0_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a9_vclk0_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = VID_CLK_DIV,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk0_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vclk0_in.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a9_vclk0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL,
+		.bit_idx = 19,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk0",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &a9_vclk0_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+#define A9_VCLK_GATE(_name, _reg, _bit,  _parent)			\
+struct clk_regmap a9_##_name##_en = {					\
+	.data = &(struct clk_regmap_gate_data) {			\
+		.offset = (_reg),					\
+		.bit_idx = (_bit),					\
+	},								\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = #_name "_en",					\
+		.ops = &clk_regmap_gate_ops,				\
+		.parent_hws = (const struct clk_hw *[]) {		\
+			&(_parent).hw					\
+		},							\
+		.num_parents = 1,					\
+		.flags = CLK_SET_RATE_PARENT,				\
+	},								\
+}
+
+#define A9_VCLK_DIV(_name, _div)					\
+struct clk_fixed_factor a9_##_name = {					\
+	.mult = 1,							\
+	.div = (_div),							\
+	.hw.init = &(struct clk_init_data) {				\
+		.name = #_name,						\
+		.ops = &clk_fixed_factor_ops,				\
+		.parent_hws = (const struct clk_hw *[]) {		\
+			&a9_##_name##_en.hw				\
+		},							\
+		.num_parents = 1,					\
+		.flags = CLK_SET_RATE_PARENT,				\
+	},								\
+}
+
+static A9_VCLK_GATE(vclk0_div1, VID_CLK_CTRL, 0, a9_vclk0);
+static A9_VCLK_GATE(vclk0_div2, VID_CLK_CTRL, 1, a9_vclk0);
+static A9_VCLK_DIV(vclk0_div2, 2);
+static A9_VCLK_GATE(vclk0_div4, VID_CLK_CTRL, 2, a9_vclk0);
+static A9_VCLK_DIV(vclk0_div4, 4);
+static A9_VCLK_GATE(vclk0_div6, VID_CLK_CTRL, 3, a9_vclk0);
+static A9_VCLK_DIV(vclk0_div6, 6);
+static A9_VCLK_GATE(vclk0_div12, VID_CLK_CTRL, 4, a9_vclk0);
+static A9_VCLK_DIV(vclk0_div12, 12);
+
+static struct clk_regmap a9_vclk1_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = VIID_CLK_CTRL,
+		.mask = 0x7,
+		.shift = 16,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk1_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_data = a9_vclk_parents,
+		.num_parents = ARRAY_SIZE(a9_vclk_parents),
+	},
+};
+
+static struct clk_regmap a9_vclk1_in = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VIID_CLK_DIV,
+		.bit_idx = 16,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk1_in",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &a9_vclk1_sel.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a9_vclk1_div = {
+	.data = &(struct clk_regmap_div_data){
+		.offset = VIID_CLK_DIV,
+		.shift = 0,
+		.width = 8,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vclk1_div",
+		.ops = &clk_regmap_divider_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vclk1_in.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a9_vclk1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VIID_CLK_CTRL,
+		.bit_idx = 19,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vclk1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) { &a9_vclk1_div.hw },
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static A9_VCLK_GATE(vclk1_div1, VIID_CLK_CTRL, 0, a9_vclk1);
+static A9_VCLK_GATE(vclk1_div2, VIID_CLK_CTRL, 1, a9_vclk1);
+static A9_VCLK_DIV(vclk1_div2, 2);
+static A9_VCLK_GATE(vclk1_div4, VIID_CLK_CTRL, 2, a9_vclk1);
+static A9_VCLK_DIV(vclk1_div4, 4);
+static A9_VCLK_GATE(vclk1_div6, VIID_CLK_CTRL, 3, a9_vclk1);
+static A9_VCLK_DIV(vclk1_div6, 6);
+static A9_VCLK_GATE(vclk1_div12, VIID_CLK_CTRL, 4, a9_vclk1);
+static A9_VCLK_DIV(vclk1_div12, 12);
+
+/* 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_vclk0_div1_en.hw,
+	&a9_vclk0_div2.hw,
+	&a9_vclk0_div4.hw,
+	&a9_vclk0_div6.hw,
+	&a9_vclk0_div12.hw,
+	&a9_vclk1_div1_en.hw,
+	&a9_vclk1_div2.hw,
+	&a9_vclk1_div4.hw,
+	&a9_vclk1_div6.hw,
+	&a9_vclk1_div12.hw
+};
+
+static struct clk_regmap a9_encoder0_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = VIID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 12,
+		.table = a9_vid_parents_val_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "encoder0_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_encoder0 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 10,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "encoder",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_encoder0_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static struct clk_regmap a9_encoder1_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = VIID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 8,
+		.table = a9_vid_parents_val_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "encoder1_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_encoder1 = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 11,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "encorder1",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_encoder1_sel.hw
+		},
+		.num_parents = 1,
+		.flags = CLK_SET_RATE_PARENT,
+	},
+};
+
+static const struct clk_parent_data a9_vid_lock_parents[] = {
+	{ .fw_name = "xtal", },
+	{ .hw = &a9_encoder0.hw },
+	{ .hw = &a9_encoder1.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_vdac_sel = {
+	.data = &(struct clk_regmap_mux_data){
+		.offset = VIID_CLK_DIV,
+		.mask = 0xf,
+		.shift = 28,
+		.table = a9_vid_parents_val_table,
+	},
+	.hw.init = &(struct clk_init_data){
+		.name = "vdac_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_vdac = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 4,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "vdac",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_vdac_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hdmitx_pixel_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_hdmitx_pixel = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 5,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hdmitx_pixel",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hdmitx_pixel_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hdmitx_fe_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_hdmitx_fe = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 9,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hdmitx_fe",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hdmitx_fe_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hdmitx1_pixel_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_hdmitx1_pixel = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 12,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hdmitx1_pixel",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hdmitx_pixel_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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 = &(struct clk_init_data){
+		.name = "hdmitx1_fe_sel",
+		.ops = &clk_regmap_mux_ops,
+		.parent_hws = a9_vid_parents,
+		.num_parents = ARRAY_SIZE(a9_vid_parents),
+	},
+};
+
+static struct clk_regmap a9_hdmitx1_fe = {
+	.data = &(struct clk_regmap_gate_data){
+		.offset = VID_CLK_CTRL2,
+		.bit_idx = 13,
+	},
+	.hw.init = &(struct clk_init_data) {
+		.name = "hdmitx1_fe",
+		.ops = &clk_regmap_gate_ops,
+		.parent_hws = (const struct clk_hw *[]) {
+			&a9_hdmitx1_fe_sel.hw
+		},
+		.num_parents = 1,
+		.flags = 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_SPISG0_SEL]		= &a9_spisg0_sel.hw,
+	[CLKID_SPISG0_DIV]		= &a9_spisg0_div.hw,
+	[CLKID_SPISG0]			= &a9_spisg0.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_PCIE0_TL_SEL]		= &a9_pcie0_tl_sel.hw,
+	[CLKID_PCIE0_TL_DIV]		= &a9_pcie0_tl_div.hw,
+	[CLKID_PCIE0_TL]		= &a9_pcie0_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_CAN0_PE_SEL]		= &a9_can0_pe_sel.hw,
+	[CLKID_CAN0_PE_DIV]		= &a9_can0_pe_div.hw,
+	[CLKID_CAN0_PE]			= &a9_can0_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_CAN0_FILTER_SEL]		= &a9_can0_filter_sel.hw,
+	[CLKID_CAN0_FILTER_DIV]		= &a9_can0_filter_div.hw,
+	[CLKID_CAN0_FILTER]		= &a9_can0_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_VCLK0_SEL]		= &a9_vclk0_sel.hw,
+	[CLKID_VCLK0_IN]		= &a9_vclk0_in.hw,
+	[CLKID_VCLK0_DIV]		= &a9_vclk0_div.hw,
+	[CLKID_VCLK0]			= &a9_vclk0.hw,
+	[CLKID_VCLK0_DIV1_EN]		= &a9_vclk0_div1_en.hw,
+	[CLKID_VCLK0_DIV2_EN]		= &a9_vclk0_div2_en.hw,
+	[CLKID_VCLK0_DIV2]		= &a9_vclk0_div2.hw,
+	[CLKID_VCLK0_DIV4_EN]		= &a9_vclk0_div4_en.hw,
+	[CLKID_VCLK0_DIV4]		= &a9_vclk0_div4.hw,
+	[CLKID_VCLK0_DIV6_EN]		= &a9_vclk0_div6_en.hw,
+	[CLKID_VCLK0_DIV6]		= &a9_vclk0_div6.hw,
+	[CLKID_VCLK0_DIV12_EN]		= &a9_vclk0_div12_en.hw,
+	[CLKID_VCLK0_DIV12]		= &a9_vclk0_div12.hw,
+	[CLKID_VCLK1_SEL]		= &a9_vclk1_sel.hw,
+	[CLKID_VCLK1_IN]		= &a9_vclk1_in.hw,
+	[CLKID_VCLK1_DIV]		= &a9_vclk1_div.hw,
+	[CLKID_VCLK1]			= &a9_vclk1.hw,
+	[CLKID_VCLK1_DIV1_EN]		= &a9_vclk1_div1_en.hw,
+	[CLKID_VCLK1_DIV2_EN]		= &a9_vclk1_div2_en.hw,
+	[CLKID_VCLK1_DIV2]		= &a9_vclk1_div2.hw,
+	[CLKID_VCLK1_DIV4_EN]		= &a9_vclk1_div4_en.hw,
+	[CLKID_VCLK1_DIV4]		= &a9_vclk1_div4.hw,
+	[CLKID_VCLK1_DIV6_EN]		= &a9_vclk1_div6_en.hw,
+	[CLKID_VCLK1_DIV6]		= &a9_vclk1_div6.hw,
+	[CLKID_VCLK1_DIV12_EN]		= &a9_vclk1_div12_en.hw,
+	[CLKID_VCLK1_DIV12]		= &a9_vclk1_div12.hw,
+	[CLKID_VDAC_SEL]		= &a9_vdac_sel.hw,
+	[CLKID_VDAC]			= &a9_vdac.hw,
+	[CLKID_ENCODER0_SEL]		= &a9_encoder0_sel.hw,
+	[CLKID_ENCODER0]		= &a9_encoder0.hw,
+	[CLKID_ENCODER1_SEL]		= &a9_encoder1_sel.hw,
+	[CLKID_ENCODER1]		= &a9_encoder1.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");

-- 
2.47.1



^ permalink raw reply related

* Re: [PATCH v9 4/5] iio: adc: versal-sysmon: add threshold event support
From: Erim, Salih @ 2026-06-18  9:53 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: jic23, andy, dlechner, nuno.sa, robh, krzk+dt, conor+dt,
	conall.ogriofa, michal.simek, linux, erimsalih, linux-iio,
	devicetree, linux-kernel
In-Reply-To: <ajOZmLSyaZuoPcbI@ashevche-desk.local>

Hi Andy,

On 18/06/2026 08:09, Andy Shevchenko wrote:
> On Wed, Jun 17, 2026 at 07:01:46PM +0100, Salih Erim wrote:
>> Add threshold event support for temperature and supply voltage
>> channels.
>>
>> Temperature events:
>>    - Rising threshold with configurable value on the device
>>      temperature channel (current max across all satellites)
>>    - Per-channel hysteresis as a millicelsius value
>>    - Event direction is IIO_EV_DIR_RISING (hysteresis mode)
>>
>> Supply voltage events:
>>    - Rising/falling threshold per supply channel
>>    - Per-channel alarm enable via alarm configuration registers
>>
>> The hardware supports both window and hysteresis alarm modes for
>> temperature. This driver uses hysteresis mode, where the upper
>> threshold triggers the alarm and the lower threshold clears it
>> (re-arm point). The hardware has a single ISR bit per temperature
>> channel with no indication of which threshold was crossed, so
>> hysteresis mode is the natural fit. The lower threshold register
>> is computed internally as (upper - hysteresis).
>>
>> Hysteresis is stored in the driver as a millicelsius value,
>> initialized from the hardware registers at probe. Writing the
>> rising threshold or hysteresis recomputes the lower register.
>> ALARM_CONFIG is hard-coded to hysteresis mode during init.
>>
>> The hardware also provides a separate over-temperature (OT)
>> threshold, but it is not exposed through IIO as it serves as a
>> hardware safety mechanism for platform shutdown. OT will be
>> exposed through the thermal framework in a follow-up series.
>>
>> The interrupt handler masks active threshold interrupts (which are
>> level-sensitive) and schedules a delayed worker to poll for condition
>> clear before unmasking. When no hardware IRQ is available, event
>> specs are not attached and interrupt init is skipped, since the
>> I2C regmap backend cannot be called from atomic context.
>>
>> When disabling a supply channel alarm, the group interrupt remains
>> active if any other channel in the same alarm group still has an
>> alarm enabled.
>>
>> A devm cleanup action masks all interrupts on driver unbind to
>> prevent unhandled interrupt storms after the IRQ handler is freed.
> 
> A couple of nit-picks below, otherwise
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>

Thank you for the review!

> 
> ...
> 
>>   #include <linux/cleanup.h>
>>   #include <linux/device.h>
>>   #include <linux/err.h>
>> +#include <linux/interrupt.h>
> 
> + limits.h // U16_MAX, et cetera

Will add.
> 
>> +#include <linux/minmax.h>
>>   #include <linux/module.h>
>>   #include <linux/overflow.h>
>>   #include <linux/property.h>
> 
> ...
> 
>> -static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev)
>> +static int sysmon_parse_fw(struct iio_dev *indio_dev, struct device *dev, int irq)
>>   {
>>        unsigned int num_chan, num_static, idx, temp_chan_idx, volt_chan_idx;
>> -     unsigned int num_supply, num_temp;
>>        struct iio_chan_spec *sysmon_channels;
>> +     unsigned int num_supply, num_temp;
> 
> Stray change, and I would expect to see all num_* on one line, and
> all *_idx on another.
> 
>          unsigned int num_chan, num_static, num_supply, num_temp;
>          unsigned int idx, temp_chan_idx, volt_chan_idx;
>          struct iio_chan_spec *sysmon_channels;
> 
> TL;DR:
> in this patch the above should not be modified as the previous one should
> provide already a nice structure.

Accepted. Will restructure in P2 so P4 inherits cleanly.

Thanks,
Salih

> 
>>        const char *label;
>>        u32 reg;
>>        int ret;
> 
> --
> With Best Regards,
> Andy Shevchenko
> 
> 


^ permalink raw reply

* Re: [PATCH 2/2] arm64: dts: qcom: lemans-evk: Describe the PCIe M.2 Key E connector
From: Manivannan Sadhasivam @ 2026-06-18  9:59 UTC (permalink / raw)
  To: Wei Deng
  Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Bartosz Golaszewski, linux-arm-msm, devicetree,
	linux-kernel, linux-pci, linux-pm, quic_chezhou, cheng.jiang,
	shuai.zhang, jinwang.li, xiuzhuo.shang, mengshi.wu
In-Reply-To: <20260608091702.3797437-3-wei.deng@oss.qualcomm.com>

On Mon, Jun 08, 2026 at 02:47:02PM +0530, Wei Deng wrote:
> The lemans EVK has the PCIe M.2 Mechanical Key E connector to connect
> wireless connectivity cards over PCIe and UART interfaces. Hence,
> describe the connector node and link it with the PCIe 0 Root Port and
> UART17 nodes through graph port/endpoint.
> 
> Also add 'compatible = "pciclass,0604"' to the pcieport0 node in
> lemans.dtsi to allow the PCI subsystem to associate the DT node with
> the PCI-to-PCI bridge device.
> 
> The M.2 Key E connector is powered by a 3.3V fixed regulator
> (vreg_wcn_3p3) which is sourced from the board's 12V DC input rail
> (vreg_dcin_12v). Both regulators are always-on and are required by the
> pcie-m2-e-connector binding.
> 
> Also add the serial1 = &uart17 alias, which is required for the
> Bluetooth serdev device to be enumerated on the UART17 interface.
> 
> Signed-off-by: Wei Deng <wei.deng@oss.qualcomm.com>

Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>

- Mani

> ---
>  arch/arm64/boot/dts/qcom/lemans-evk.dts | 75 +++++++++++++++++++++++++
>  arch/arm64/boot/dts/qcom/lemans.dtsi    |  1 +
>  2 files changed, 76 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/qcom/lemans-evk.dts b/arch/arm64/boot/dts/qcom/lemans-evk.dts
> index 34dfc8d22b6a..b2967cb53760 100644
> --- a/arch/arm64/boot/dts/qcom/lemans-evk.dts
> +++ b/arch/arm64/boot/dts/qcom/lemans-evk.dts
> @@ -21,6 +21,7 @@ aliases {
>  		ethernet0 = &ethernet0;
>  		mmc1 = &sdhc;
>  		serial0 = &uart10;
> +		serial1 = &uart17;
>  		serial2 = &uart0;
>  	};
>  
> @@ -88,6 +89,38 @@ usb2_con_hs_ep: endpoint {
>  		};
>  	};
>  
> +	connector-3 {
> +		compatible = "pcie-m2-e-connector";
> +		vpcie3v3-supply = <&vreg_wcn_3p3>;
> +
> +		ports {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +
> +			port@0 {
> +				reg = <0>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				m2_e_pcie_ep: endpoint@0 {
> +					reg = <0>;
> +					remote-endpoint = <&pcieport0_ep>;
> +				};
> +			};
> +
> +			port@3 {
> +				reg = <3>;
> +				#address-cells = <1>;
> +				#size-cells = <0>;
> +
> +				m2_e_uart_ep: endpoint@0 {
> +					reg = <0>;
> +					remote-endpoint = <&uart17_ep>;
> +				};
> +			};
> +		};
> +	};
> +
>  	edp0-connector {
>  		compatible = "dp-connector";
>  		label = "EDP0";
> @@ -178,6 +211,17 @@ vmmc_sdc: regulator-vmmc-sdc {
>  		regulator-max-microvolt = <2950000>;
>  	};
>  
> +	vreg_dcin_12v: regulator-dcin-12v {
> +		compatible = "regulator-fixed";
> +
> +		regulator-name = "VREG_DCIN_12V";
> +		regulator-min-microvolt = <12000000>;
> +		regulator-max-microvolt = <12000000>;
> +
> +		regulator-always-on;
> +		regulator-boot-on;
> +	};
> +
>  	vreg_sdc: regulator-vreg-sdc {
>  		compatible = "regulator-gpio";
>  
> @@ -191,6 +235,19 @@ vreg_sdc: regulator-vreg-sdc {
>  
>  		startup-delay-us = <100>;
>  	};
> +
> +	vreg_wcn_3p3: regulator-wcn-3p3 {
> +		compatible = "regulator-fixed";
> +
> +		regulator-name = "VREG_WCN_3P3";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +
> +		vin-supply = <&vreg_dcin_12v>;
> +
> +		regulator-always-on;
> +		regulator-boot-on;
> +	};
>  };
>  
>  &apps_rsc {
> @@ -742,6 +799,14 @@ &pcie1_phy {
>  	status = "okay";
>  };
>  
> +&pcieport0 {
> +	port {
> +		pcieport0_ep: endpoint {
> +			remote-endpoint = <&m2_e_pcie_ep>;
> +		};
> +	};
> +};
> +
>  &pmm8654au_0_pon_resin {
>  	linux,code = <KEY_VOLUMEDOWN>;
>  	status = "okay";
> @@ -970,6 +1035,16 @@ &uart10 {
>  	status = "okay";
>  };
>  
> +&uart17 {
> +	status = "okay";
> +
> +	port {
> +		uart17_ep: endpoint {
> +			remote-endpoint = <&m2_e_uart_ep>;
> +		};
> +	};
> +};
> +
>  &ufs_mem_hc {
>  	reset-gpios = <&tlmm 149 GPIO_ACTIVE_LOW>;
>  	vcc-supply = <&vreg_l8a>;
> diff --git a/arch/arm64/boot/dts/qcom/lemans.dtsi b/arch/arm64/boot/dts/qcom/lemans.dtsi
> index 353a6e6fd3ac..9afd6e8ebcdb 100644
> --- a/arch/arm64/boot/dts/qcom/lemans.dtsi
> +++ b/arch/arm64/boot/dts/qcom/lemans.dtsi
> @@ -2779,6 +2779,7 @@ pcie0: pcie@1c00000 {
>  			status = "disabled";
>  
>  			pcieport0: pcie@0 {
> +				compatible = "pciclass,0604";
>  				device_type = "pci";
>  				reg = <0x0 0x0 0x0 0x0 0x0>;
>  				bus-range = <0x01 0xff>;
> -- 
> 2.34.1
> 

-- 
மணிவண்ணன் சதாசிவம்

^ 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