* Re: [PATCH] watchdog: apple: Add "apple,t8103-wdt" compatible
From: Guenter Roeck @ 2026-05-11 14:22 UTC (permalink / raw)
To: Janne Grunau
Cc: Sven Peter, Neal Gompa, Wim Van Sebroeck, asahi, linux-arm-kernel,
linux-watchdog, linux-kernel, stable
In-Reply-To: <87766879-ca5e-44cc-a341-87b2afa70910@roeck-us.net>
On 5/11/26 07:04, Guenter Roeck wrote:
> On Wed, Dec 31, 2025 at 01:07:21PM +0100, Janne Grunau wrote:
>> After discussion with the devicetree maintainers we agreed to not extend
>> lists with the generic compatible "apple,wdt" anymore [1]. Use
>> "apple,t8103-wdt" as base compatible as it is the SoC the driver and
>> bindings were written for.
>>
>> [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/
>>
>> Fixes: 4ed224aeaf66 ("watchdog: Add Apple SoC watchdog driver")
>> Cc: stable@vger.kernel.org
>> Reviewed-by: Neal Gompa <neal@gompa.dev>
>> Signed-off-by: Janne Grunau <j@jannau.net>
>
> Applied to my hwmon-next branch.
>
watchdog-next. Sorry for the confusion.
Guenter
> Thanks,
> Guenter
>
>> ---
>> This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
>> device trees in [2].
>>
>> 2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e@jannau.net
>> ---
>> drivers/watchdog/apple_wdt.c | 1 +
>> 1 file changed, 1 insertion(+)
>>
>>
>> ---
>> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
>> change-id: 20251231-watchdog-apple-t8103-base-compat-8a623e9831b6
>>
>> Best regards,
>>
>> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
>> index 66a158f67a712bbed394d660071e02140e66c2e5..6b9b0f9b05cedfd7fc5d0d79ba19ab356dc2a080 100644
>> --- a/drivers/watchdog/apple_wdt.c
>> +++ b/drivers/watchdog/apple_wdt.c
>> @@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev)
>> static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);
>>
>> static const struct of_device_id apple_wdt_of_match[] = {
>> + { .compatible = "apple,t8103-wdt" },
>> { .compatible = "apple,wdt" },
>> {},
>> };
>
^ permalink raw reply
* Re: [PATCH v6 08/25] KVM: arm64: iommu: Shadow host stage-2 page table
From: Jason Gunthorpe @ 2026-05-11 14:22 UTC (permalink / raw)
To: Mostafa Saleh
Cc: linux-arm-kernel, linux-kernel, kvmarm, iommu, catalin.marinas,
will, maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
joro, jean-philippe, mark.rutland, qperret, tabba, vdonnefort,
sebastianene, keirf
In-Reply-To: <agG8XtrHUfWGy-kd@google.com>
On Mon, May 11, 2026 at 11:24:14AM +0000, Mostafa Saleh wrote:
> On Sat, May 09, 2026 at 08:27:14PM -0300, Jason Gunthorpe wrote:
> > On Mon, May 04, 2026 at 12:28:55PM +0000, Mostafa Saleh wrote:
> > > So far this is the list of requirements/changes needed share the
> > > stage-2 page table (besides the obvious: same page table format,
> > > granularity, endianness...)
> > >
> > > 1) HW BBM is not supported in the hypervisor page table, that’s
> > > because it can generate TLB conflict aborts, which the hypervisor
> > > can not handle because of the limited syndrome information.
> > > We can rely on FEAT_BBML3 which was newly introduced to work
> > > around that, it’s quite niche and not supported in KVM yet or
> > > have an allow list similar to the kernel
> > > (as in cpu_supports_bbml2_noabort()) which also limits the number
> > > of CPUs that can run this.
> >
> > Do you think pkvm will need BBM? Hitless replace of a PTE is already a
> > pretty advanced feature and the SMMU has its own support matrix there
> > too. Is it for shared/private conversion?
>
> Yes, we can break block on memory donation which is transfer of
> ownership to the hypervisor or a guest.
So you need BBM support on the SMMU too? That is probably a big
problem because the SMMU is often mismatched to the CPU :\
Also io-pgtable arm cannot trigger BBM behaviors, so how do you
implement it?
> > No.. once you turn on IO like this you don't have page faults
> > anymore. Everything must be permantently mapped into the SMMU view, it
> > can never be made non-present and you must run without page
> > faults. That's what you have in the io-pgtable constructed table,
> > right?
>
> Exactly, but the CPU page table doesn’t guarantee that, so we either
> have to handle page faults in the IOMMU, or completely change how KVM
> deals with stage-2 if we want to share the page table with the CPU.
So that's the real explanation, KVM cannot manage the S2 in the right
way so you can't share it. RMM/etc are managing the S2 without
pointless page faults so they can share it.
> > > Alternatively, we can pin the stage-2 pages, that would require some
> > > hypercalls, hacks to the driver/IOMMU API and possibly new semantics
> > > in the DMA-API for IDENTITY devices as they will still need to pin
> > > the pages as they are actually in stage-2 translation and not bypass.
> >
> > ?? Then how does this series work?
>
> This series works fine as it shadows the page table and doesn't share it
> with the CPU, so it fully populates the address space.
Which is why it is so weird that KVM is using a partially populated S2
when there is, and must, be a fully populated one for the SMMU. But I
understand there are reasons fo rthis.
Jason
^ permalink raw reply
* Re: [PATCH v6 06/25] iommu/io-pgtable-arm: Rework to use the iommu-pages API
From: Jason Gunthorpe @ 2026-05-11 14:18 UTC (permalink / raw)
To: Mostafa Saleh
Cc: linux-arm-kernel, linux-kernel, kvmarm, iommu, catalin.marinas,
will, maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
joro, jean-philippe, mark.rutland, qperret, tabba, vdonnefort,
sebastianene, keirf
In-Reply-To: <agG6n4CeuIMD57G1@google.com>
On Mon, May 11, 2026 at 11:16:47AM +0000, Mostafa Saleh wrote:
> > IDK, why? virt_to_phys() is part of the iommu-pages API, I'd just
> > leave it.. If you want to narrow it then #define it for pkvm when
> > compiling this file..
>
> It is not going to be part of the iommu-pages API, I meant in
> io-pgtable-arm, we will use something arm_lpae_virt_to_phys()...
> which is then implemented differently for pkvm.
Again why? I think the main goal should be to not mess up the normal
code.
#define virt_to_phys pkvm_virt_to_phys
Does that, we should be leaning into this pattern I think, not adding
unnecessary churn...
If anything is needed then it should be an iommu_pages function to
wrapper virt_to_phys() for use by iommu_pages uses but I'd rather
not..
Jason
^ permalink raw reply
* Re: [PATCH v10 15/30] KVM: arm64: Support SME control registers
From: Mark Brown @ 2026-05-11 14:17 UTC (permalink / raw)
To: Mark Rutland
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <af4bWxiOogfPz_dp@J2N7QTR9R3>
[-- Attachment #1: Type: text/plain, Size: 3635 bytes --]
On Fri, May 08, 2026 at 06:20:27PM +0100, Mark Rutland wrote:
> > +static bool access_smcr_el2(struct kvm_vcpu *vcpu,
> > + struct sys_reg_params *p,
> > + const struct sys_reg_desc *r)
> > +{
> > + vq = SYS_FIELD_GET(SMCR_ELx, LEN, smcr) + 1;
> > + vq = min(vq, vcpu_sme_max_vq(vcpu));
> > + smcr &= ~SMCR_ELx_LEN_MASK;
> > + smcr |= SYS_FIELD_PREP(SMCR_ELx, LEN, vq - 1);
> I'm not sure this sanitization is correct or necessary, and the same
> concern applies to ZCR_ELx.LEN.
> AFAICT, none of the values for the SMCR_ELx.LEN and ZCR_ELx.LEN fields
> are reserved or unallocated. Thus all the bits of those fields should be
> stateful, and a read should observe the last value written, regardless
> of the effective value of the field.
...
> Either what we're doing is wrong, or the architcture requires a
> clarification to say that values corresponding to unimplmented vector
> lengths are reserved.
> If those bit are always stateful, the the logic to sanitize the LEN
> field shouldn't live here, and that will need to happen when consuming
> the effective value.
Your understanding of how these fields work matches mine, and writing
unimplemented values is part of the documented procedure for enumerating
the set of supported vector lengths.
As you note this is duplicated from the handling of ZCR_ELx, it's not
clear to me why the code does this but I figured there must be some good
reason for doing things this way that I just wasn't seeing and that it
was safer to fit in with the existing code. The handling for vector
lengths in general and especially with NV was quite unclear,
particularly prior to your fixes in 59419f10045b (KVM: arm64: Eagerly
switch ZCR_EL{1,2}).
The changelog for b3d29a823099 ("KVM: arm64: nv: Handle ZCR_EL2 traps")
which introduced this for ZCR_ELx has a mention of mapping the requested
VL but it's not entirely clear to me what it means by that. It does
mean that we can just load guest ZCR_EL2 and get the correct behaviour
for guest EL1 and EL0 when loading the guest state so perhaps that might
be all there is to it.
My expectation would have been to restrict the guest EL1/0 VL when we
load state into the registers as you allude to, something more like the
below (off the top of my head and completely untested, I'll pull this
into a proper patch later):
diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
index 98b2976837b1..ddf8c2246139 100644
--- a/arch/arm64/kvm/hyp/include/hyp/switch.h
+++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
@@ -501,11 +501,11 @@ static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
return;
if (vcpu_has_sve(vcpu)) {
+ zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
+
/* A guest hypervisor may restrict the effective max VL. */
- if (is_nested_ctxt(vcpu))
- zcr_el2 = __vcpu_sys_reg(vcpu, ZCR_EL2);
- else
- zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
+ if (is_nested_ctxt(vcpu) && !is_hyp_ctxt(vcpu))
+ zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
write_sysreg_el2(zcr_el2, SYS_ZCR);
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 148fc3400ea8..b48f41acff82 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -2874,9 +2874,7 @@ static bool access_zcr_el2(struct kvm_vcpu *vcpu,
return true;
}
- vq = SYS_FIELD_GET(ZCR_ELx, LEN, p->regval) + 1;
- vq = min(vq, vcpu_sve_max_vq(vcpu));
- __vcpu_assign_sys_reg(vcpu, ZCR_EL2, vq - 1);
+ __vcpu_assign_sys_reg(vcpu, ZCR_EL2, p->regval);
return true;
}
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply related
* Re: [PATCH v4 0/3] ARM: dts: aspeed-g6: add AST2600 I3C nodes and bindings
From: Dawid Glazik @ 2026-05-11 14:14 UTC (permalink / raw)
To: Lee Jones, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, linux-aspeed
Cc: devicetree, linux-arm-kernel, linux-kernel, maciej.lawniczak
In-Reply-To: <cover.1777058942.git.dawid.glazik@linux.intel.com>
On 4/24/2026 10:20 PM, Dawid Glazik wrote:
> This series reworks and resubmits AST2600 I3C DTS updates that were
> originally posted in 2024, but stalled without further upstream
> progress.[1] The series was rebased onto the current tree and merge
> conflicts were resolved.
>
> The patches first move I2C controller nodes under the APB simple-bus
> for layout consistency, then document aspeed,ast2600-i3c-global in
> the syscon binding, and finally add AST2600 I3C controller nodes in
> aspeed-g6.dtsi.
>
> Jeremy agreed in a separate email thread that I can continue this
> series under my authorship.
>
> Link: https://lore.kernel.org/all/9d8c03d742fa9767f30e23d75ddf0baf4296c88e.1714647917.git.jk@codeconstruct.com.au/
>
> Dawid Glazik (3):
> ARM: dts: aspeed-g6: move i2c controllers directly into apb node
> dt-bindings: mfd: syscon: add aspeed,ast2600-i3c-global compatible
> ARM: dts: aspeed-g6: Add nodes for i3c controllers
>
> .../devicetree/bindings/mfd/syscon.yaml | 2 +
> arch/arm/boot/dts/aspeed/aspeed-g6.dtsi | 543 ++++++++++--------
> 2 files changed, 318 insertions(+), 227 deletions(-)
>
>
> base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
Hi all,
Gentle ping for this series:
https://lore.kernel.org/all/cover.1777058942.git.dawid.glazik@linux.intel.com/#t
I received Reviewed-by from Krzysztof Kozlowski (thank you).
Could I please get feedback/ack from maintainers on the remaining parts,
especially ASPEED DTS?
If preferred, I can respin/rebase the series.
Thanks,
Dawid Glazik
^ permalink raw reply
* Re: [PATCH v3 2/5] dt-bindings: watchdog: apple,wdt: Add t8122 compatible
From: Guenter Roeck @ 2026-05-11 14:07 UTC (permalink / raw)
To: Janne Grunau
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lorenzo Pieralisi,
Sven Peter, Neal Gompa, Wim Van Sebroeck, Mark Kettenis,
Sasha Finkelstein, Uwe Kleine-König, devicetree,
linux-kernel, asahi, linux-arm-kernel, linux-watchdog, linux-pwm,
Joshua Peisach
In-Reply-To: <20260511085028.GA192358@robin.jannau.net>
On 5/11/26 01:50, Janne Grunau wrote:
> On Sun, May 10, 2026 at 08:29:39AM -0700, Guenter Roeck wrote:
>> On Thu, May 07, 2026 at 09:33:08AM +0200, Janne Grunau wrote:
>>> The watchdog on the Apple silicon t8122 (M3) SoC is compatible with the
>>> existing driver. Add "apple,t8122-wdt" as SoC specific compatible under
>>> "apple,t8103-wdt" used by the driver.
>>
>> '"apple,t8103-wdt" used by the driver' is not true. The watchdog driver
>> only supports "apple,wdt".
>
> It slipped my mind that
> https://lore.kernel.org/linux-watchdog/20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net/
> wasn't picked up yet.
>
Me too. Applied both.
Thanks,
Guenter
>>
>>>
>>> Acked-by: Rob Herring (Arm) <robh@kernel.org>
>>> Reviewed-by: Joshua Peisach <jpeisach@ubuntu.com>
>>> Reviewed-by: Neal Gompa <neal@gompa.dev>
>>> Signed-off-by: Janne Grunau <j@jannau.net>
>>> ---
>>> Documentation/devicetree/bindings/watchdog/apple,wdt.yaml | 4 +++-
>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>>> index 05602678c070..845b5e8b5abc 100644
>>> --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>>> +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
>>> @@ -16,7 +16,9 @@ properties:
>>> compatible:
>>> oneOf:
>>> - items:
>>> - - const: apple,t6020-wdt
>>> + - enum:
>>> + - apple,t6020-wdt
>>> + - apple,t8122-wdt
>>> - const: apple,t8103-wdt
>>> - items:
>>> - enum:
>>
>> I second Sashiko's findings that the driver will fail to bind because it
>> only supports "apple,wdt". I would not mind and apply the patch anyway,
>> but the statement in the description is just plain wrong and thus
>> misleading. Please fix.
>
> I would prefer if the addition of the "apple,t8103-wdt" to the driver is
> picked.
>
> Thanks,
>
> Janne
>
^ permalink raw reply
* Re: [PATCH v3 2/5] dt-bindings: watchdog: apple,wdt: Add t8122 compatible
From: Guenter Roeck @ 2026-05-11 14:06 UTC (permalink / raw)
To: Janne Grunau
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Lorenzo Pieralisi,
Sven Peter, Neal Gompa, Wim Van Sebroeck, Mark Kettenis,
Sasha Finkelstein, Uwe Kleine-König, devicetree,
linux-kernel, asahi, linux-arm-kernel, linux-watchdog, linux-pwm,
Joshua Peisach
In-Reply-To: <20260507-apple-m3-initial-devicetrees-v3-2-ca07c81b5dc7@jannau.net>
On Thu, May 07, 2026 at 09:33:08AM +0200, Janne Grunau wrote:
> The watchdog on the Apple silicon t8122 (M3) SoC is compatible with the
> existing driver. Add "apple,t8122-wdt" as SoC specific compatible under
> "apple,t8103-wdt" used by the driver.
>
> Acked-by: Rob Herring (Arm) <robh@kernel.org>
> Reviewed-by: Joshua Peisach <jpeisach@ubuntu.com>
> Reviewed-by: Neal Gompa <neal@gompa.dev>
> Signed-off-by: Janne Grunau <j@jannau.net>
Applied to my watchdog-next branch.
Thanks,
Guenter
> ---
> Documentation/devicetree/bindings/watchdog/apple,wdt.yaml | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> index 05602678c070..845b5e8b5abc 100644
> --- a/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> +++ b/Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
> @@ -16,7 +16,9 @@ properties:
> compatible:
> oneOf:
> - items:
> - - const: apple,t6020-wdt
> + - enum:
> + - apple,t6020-wdt
> + - apple,t8122-wdt
> - const: apple,t8103-wdt
> - items:
> - enum:
^ permalink raw reply
* Re: [PATCH] watchdog: apple: Add "apple,t8103-wdt" compatible
From: Guenter Roeck @ 2026-05-11 14:04 UTC (permalink / raw)
To: Janne Grunau
Cc: Sven Peter, Neal Gompa, Wim Van Sebroeck, asahi, linux-arm-kernel,
linux-watchdog, linux-kernel, stable
In-Reply-To: <20251231-watchdog-apple-t8103-base-compat-v1-1-1702a02e0c45@jannau.net>
On Wed, Dec 31, 2025 at 01:07:21PM +0100, Janne Grunau wrote:
> After discussion with the devicetree maintainers we agreed to not extend
> lists with the generic compatible "apple,wdt" anymore [1]. Use
> "apple,t8103-wdt" as base compatible as it is the SoC the driver and
> bindings were written for.
>
> [1]: https://lore.kernel.org/asahi/12ab93b7-1fc2-4ce0-926e-c8141cfe81bf@kernel.org/
>
> Fixes: 4ed224aeaf66 ("watchdog: Add Apple SoC watchdog driver")
> Cc: stable@vger.kernel.org
> Reviewed-by: Neal Gompa <neal@gompa.dev>
> Signed-off-by: Janne Grunau <j@jannau.net>
Applied to my hwmon-next branch.
Thanks,
Guenter
> ---
> This is split off from the v1 series adding Apple M2 Pro/Max/Ultra
> device trees in [2].
>
> 2: https://lore.kernel.org/r/20250828-dt-apple-t6020-v1-0-507ba4c4b98e@jannau.net
> ---
> drivers/watchdog/apple_wdt.c | 1 +
> 1 file changed, 1 insertion(+)
>
>
> ---
> base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8
> change-id: 20251231-watchdog-apple-t8103-base-compat-8a623e9831b6
>
> Best regards,
>
> diff --git a/drivers/watchdog/apple_wdt.c b/drivers/watchdog/apple_wdt.c
> index 66a158f67a712bbed394d660071e02140e66c2e5..6b9b0f9b05cedfd7fc5d0d79ba19ab356dc2a080 100644
> --- a/drivers/watchdog/apple_wdt.c
> +++ b/drivers/watchdog/apple_wdt.c
> @@ -218,6 +218,7 @@ static int apple_wdt_suspend(struct device *dev)
> static DEFINE_SIMPLE_DEV_PM_OPS(apple_wdt_pm_ops, apple_wdt_suspend, apple_wdt_resume);
>
> static const struct of_device_id apple_wdt_of_match[] = {
> + { .compatible = "apple,t8103-wdt" },
> { .compatible = "apple,wdt" },
> {},
> };
^ permalink raw reply
* Re: [PATCH] irqchip/mvebu: Allow EBU irqchips to be compile-tested
From: Thomas Gleixner @ 2026-05-11 13:45 UTC (permalink / raw)
To: Rosen Penev, linux-kernel
Cc: Andrew Lunn, Gregory Clement, Sebastian Hesselbarth,
Nathan Chancellor, Nick Desaulniers, Bill Wendling, Justin Stitt,
moderated list:ARM/Marvell Kirkwood and Armada 370, 375, 38x,...,
open list:CLANG/LLVM BUILD SUPPORT:Keyword:b(?i:clang|llvm)b
In-Reply-To: <20260510195047.10143-1-rosenp@gmail.com>
On Sun, May 10 2026 at 12:50, Rosen Penev wrote:
> The Marvell EBU interrupt controller Kconfig symbols are hidden and
> selected only by platform code. This prevents build coverage for the
> drivers on other architectures even though the code only needs OF and
> MMIO support.
>
> Add COMPILE_TEST prompts and the required dependencies for the GICP,
> ICU, ODMI, PIC and SEI irqchips. While touching PIC for this coverage,
> use GENMASK() and BIT() for its masks so that 32-bit platforms can
> compile this safely without running into issues.
While touching PIC? That's related, but you want to prepare the PIC code
first in order to enable the compile test and not burry that change
within a gazillion lines of Kconfig muck.
> config MVEBU_GICP
> + bool "Marvell EBU GICP interrupt controller" if COMPILE_TEST
> + depends on OF
> + depends on HAS_IOMEM
depends on OF && HAS_IOMEM
> select IRQ_MSI_LIB
> - bool
> + help
> + Support the Marvell EBU GICP interrupt controller.
>
> config MVEBU_ICU
> - bool
> + bool "Marvell EBU ICU interrupt controller" if COMPILE_TEST
> + depends on OF
> + depends on HAS_IOMEM
> + select GENERIC_MSI_IRQ
> + help
> + Support the Marvell EBU ICU interrupt controller.
>
> config MVEBU_ODMI
> - bool
> + bool "Marvell EBU ODMI interrupt controller" if COMPILE_TEST
> + depends on OF
> + depends on HAS_IOMEM
> select IRQ_MSI_LIB
> select GENERIC_MSI_IRQ
So while at it you can mop up this too. IRQ_MSI_LIB already selects
GENERIC_MSI_IRQ
> + help
> + Support the Marvell EBU ODMI interrupt controller.
>
> config MVEBU_PIC
> - bool
> + bool "Marvell EBU PIC interrupt controller" if COMPILE_TEST
> + depends on OF
> + depends on HAS_IOMEM
> + help
> + Support the Marvell EBU PIC interrupt controller.
>
> config MVEBU_SEI
> - bool
> + bool "Marvell EBU SEI interrupt controller" if COMPILE_TEST
> + depends on OF
> + depends on HAS_IOMEM
> + help
> + Support the Marvell EBU SEI interrupt controller.
What ensures that IRQ_MSI_LIB is selected, when MVEBU_SEI is selected?
> config LS_EXTIRQ
> bool "Freescale Layerscape external IRQ support" if COMPILE_TEST
> diff --git a/drivers/irqchip/irq-mvebu-pic.c b/drivers/irqchip/irq-mvebu-pic.c
> index 10b85128183a..95090d8efc06 100644
> --- a/drivers/irqchip/irq-mvebu-pic.c
> +++ b/drivers/irqchip/irq-mvebu-pic.c
> @@ -24,7 +24,7 @@
> #define PIC_MASK 0x4
>
> #define PIC_MAX_IRQS 32
> -#define PIC_MAX_IRQ_MASK ((1UL << PIC_MAX_IRQS) - 1)
> +#define PIC_MAX_IRQ_MASK GENMASK(PIC_MAX_IRQS - 1, 0)
What guarantees that 'linux/bits.h' is included under all circumstances?
I'm really not impressed by this AI assisted slop at all.
Thanks,
tglx
^ permalink raw reply
* Re: [PATCH v3 0/4] ARM: pxa: attach software nodes to the GPIO controllers
From: Bartosz Golaszewski @ 2026-05-11 13:35 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Daniel Mack, Haojian Zhuang, Robert Jarzmik, Russell King,
Dmitry Torokhov, Arnd Bergmann, Linus Walleij, linux-arm-kernel,
linux-gpio, linux-kernel
In-Reply-To: <20260430-pxa-gpio-swnodes-v3-0-5142e95f0eca@oss.qualcomm.com>
On Thu, Apr 30, 2026 at 2:57 PM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
>
> Convert GPIO controllers and their consumers on the PXA platform to using
> "attached" software nodes. Since everything happens in a bord-file, it's
> quite straightforward. We technically now have a way of passing an
> unregistered software node to platform_device_register_full() but that
> requires using struct platform_device_info and since the existing
> platform devices are either referenced from other places or defined in a
> different compilation unit, I wanted to reduce the impact of the changes
> I can't test and went with the older method.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
If there are no other comments, can this be queued for v7.2?
Thanks,
Bartosz
^ permalink raw reply
* Re: [PATCH v7 0/3] ARM: omap1: use real firmware node lookup for GPIOs on Nokia 770
From: Bartosz Golaszewski @ 2026-05-11 13:34 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Aaro Koskinen, Janusz Krzysztofik, Tony Lindgren, Russell King,
Dmitry Torokhov, Kevin Hilman, Arnd Bergmann, driver-core,
linux-kernel, linux-acpi, linux-arm-kernel, linux-omap
In-Reply-To: <20260430-nokia770-gpio-swnodes-v7-0-c88f74c90dd6@oss.qualcomm.com>
On Thu, Apr 30, 2026 at 9:31 AM Bartosz Golaszewski
<bartosz.golaszewski@oss.qualcomm.com> wrote:
>
> This converts Nokia 770 to using real firmware node lookup for GPIOs by
> attaching the software nodes describing GPIO controllers to their target
> devices.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> ---
Hi!
Gentle ping, can this be queued now for v7.2?
Thanks,
Bart
^ permalink raw reply
* Re: [PATCH v4 2/2] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
From: Andrew Lunn @ 2026-05-11 13:29 UTC (permalink / raw)
To: Vladimir Oltean
Cc: Josua Mayer, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Shawn Guo, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Yazan Shhady, Mikhail Anikin,
Alexander Dahl, devicetree, linux-kernel, imx, linux-arm-kernel,
Conor Dooley, Krzysztof Kozlowski, netdev
In-Reply-To: <20260511112438.4fxvhelf242emzft@skbuf>
On Mon, May 11, 2026 at 02:24:38PM +0300, Vladimir Oltean wrote:
> On Mon, May 11, 2026 at 12:11:31PM +0200, Josua Mayer wrote:
> > +&eqos {
> > + /* delays are added by connected ethernet-switch cpu port */
> > + phy-mode = "rgmii";
For ethernet-phy combinations i'm pretty strict, but i'm more
forgiving when switches are involved.
If rx/tx-internal-delays-ps work, that would be better, but i'm
willing to accept this, with the comment in place.
Andrew
^ permalink raw reply
* Re: [PATCH 1/5] arm64: dts: renesas: r8a77960-ulcb: Enable GPU support
From: Geert Uytterhoeven @ 2026-05-11 13:24 UTC (permalink / raw)
To: Marek Vasut
Cc: linux-arm-kernel, Conor Dooley, Krzysztof Kozlowski, Magnus Damm,
Rob Herring, devicetree, linux-kernel, linux-renesas-soc
In-Reply-To: <CAMuHMdVwXjE0Bq1KjENkN4m2h0_nN0F2S=CC8mW3B92NdpN2_g@mail.gmail.com>
On Wed, 29 Oct 2025 at 15:51, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> On Mon, 27 Oct 2025 at 22:13, Marek Vasut
> <marek.vasut+renesas@mailbox.org> wrote:
> > Enable GPU on M3ULCB with R-Car M3-W.
> >
> > Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
>
> Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Now the crash in case of missing firmware is fixed by commit
26735dfdd8930d9e ("pmdomain: core: Fix detach procedure for virtual
devices in genpd") in v7.1-rc3, I will queue this and the other patches
in this anonymous series in renesas-devel for v7.2,
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH] iommu/arm-smmu-v3-sva: Enable Hardware Access and Hardware Dirty bits
From: Pranjal Shrivastava @ 2026-05-11 13:22 UTC (permalink / raw)
To: Nicolin Chen
Cc: Robin Murphy, Jason Gunthorpe, Will Deacon, Joerg Roedel,
Jean-Philippe Brucker, Catalin Marinas, Mikołaj Lenczewski,
linux-arm-kernel, iommu, linux-kernel
In-Reply-To: <af7oyeleKFXpcIKu@nvidia.com>
On Sat, May 09, 2026 at 12:56:57AM -0700, Nicolin Chen wrote:
> On Fri, May 08, 2026 at 03:24:32PM +0100, Robin Murphy wrote:
> > On 2026-05-08 2:57 pm, Pranjal Shrivastava wrote:
> > > I see, so IIUC, you mean if IS_ENABLED(CONFIG_ARM64_HW_AFDBM) but CPU
> > > doesn't enable HTTU, it is perfectly safe to let the SMMU do HTT updates,
> > > Since the fault handlers are already expecting HW-triggered updates?
> > >
> > > Which means our check would be something like:
> > >
> > > if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) {
> > > if (smmu->features & FEAT_HA)
> > > ...
> > > }
> > >
> > > instead of cpu_has_hw_af()?
> >
> > Hmm, looking closer, cpu_has_hw_af() is the thing which actually influences
> > mm behaviour (via arch_has_hw_pte_young and arch_wants_old_prefaulted_pte),
> > and that can still be false at runtime if ARM64_HW_AFDBM is enabled but any
> > CPU doesn't support HAFDBS, so perhaps you were right the first time :)
>
> IIUIC, v2 should be:
>
> + /*
> + * Enable Hardware Access and Dirty updates (DBM) if supported by
> + * both the SMMU and the CPU. It is unsafe to enable SMMU's HTTU,
> + * if the CPU does not support it as it bypasses mm page aging.
> + */
> + if (cpu_has_hw_af()) {
Ack, yes. IMO, this is the correct system-wide gate.
> + if (master->smmu->features & ARM_SMMU_FEAT_HA)
> + target->data[0] |= cpu_to_le64(CTXDESC_CD_0_TCR_HA);
> + if (master->smmu->features & ARM_SMMU_FEAT_HD)
> + target->data[0] |= cpu_to_le64(CTXDESC_CD_0_TCR_HD);
> + }
>
Thanks,
Praan
^ permalink raw reply
* Re: [PATCH] ARM: Do not select HAVE_RUST when KASAN is enabled
From: Christian Schrefl @ 2026-05-11 13:22 UTC (permalink / raw)
To: Nathan Chancellor, Russell King, Miguel Ojeda, Boqun Feng,
Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Danilo Krummrich
Cc: linux-arm-kernel, linux-kernel, rust-for-linux, stable
In-Reply-To: <20260511-arm-avoid-rust-with-kasan-v1-1-24d55f4a900b@kernel.org>
On 5/11/26 10:02 AM, Nathan Chancellor wrote:
> When KASAN is enabled, such as with allmodconfig, the build fails when
> building the Rust code with:
>
> error: kernel-address sanitizer is not supported for this target
>
> error: aborting due to 1 previous error
>
> make[4]: *** [rust/Makefile:654: rust/core.o] Error 1
>
> The arm-unknown-linux-gnueabi target does not support KASAN, so avoid
> saying Rust is supported when it is enabled.
>
> Cc: stable@vger.kernel.org
> Fixes: ccb8ce526807 ("ARM: 9441/1: rust: Enable Rust support for ARMv7")
> Link: https://github.com/Rust-for-Linux/linux/issues/1234
> Signed-off-by: Nathan Chancellor <nathan@kernel.org>
Seems fine to me either like this or as Alice mentioned in another reply.
Reviewed-by: Christian Schrefl <chrisi.schrefl@gmail.com>
Cheers,
Christian
^ permalink raw reply
* [PATCH v12 2/5] regulator: Add support for MediaTek MT6373 SPMI PMIC Regulators
From: AngeloGioacchino Del Regno @ 2026-05-11 10:13 UTC (permalink / raw)
To: linux-mediatek
Cc: lee, robh, krzk+dt, conor+dt, matthias.bgg,
angelogioacchino.delregno, lgirdwood, broonie, devicetree,
linux-kernel, linux-arm-kernel, kernel, wenst
In-Reply-To: <20260511101355.122478-1-angelogioacchino.delregno@collabora.com>
Add a driver for the regulators found on the MediaTek MT6373 PMIC,
fully controlled by SPMI interface.
Similarly to MT6363, this PMIC regulates voltage with input range
of 2.6-5.0V, and features 10 buck converters and 25 LDOs.
This PMIC is usually found on board designs using the MT6991 or
MT8196 SoC, in combination with the MT6363 PMIC.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/regulator/Kconfig | 10 +
drivers/regulator/Makefile | 1 +
drivers/regulator/mt6373-regulator.c | 772 +++++++++++++++++++++
include/linux/regulator/mt6373-regulator.h | 161 +++++
4 files changed, 944 insertions(+)
create mode 100644 drivers/regulator/mt6373-regulator.c
create mode 100644 include/linux/regulator/mt6373-regulator.h
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index d71dac9436e3..d1ccc1da2f32 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -991,6 +991,16 @@ config REGULATOR_MT6370
This driver supports the control for DisplayBias voltages and one
general purpose LDO which is commonly used to drive the vibrator.
+config REGULATOR_MT6373
+ tristate "MT6373 SPMI PMIC regulator driver"
+ depends on SPMI
+ select REGMAP_SPMI
+ help
+ Say Y here to enable support for buck and LDO regulators found in
+ the MediaTek MT6373 SPMI PMIC and its variants.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_MT6380
tristate "MediaTek MT6380 PMIC"
depends on MTK_PMIC_WRAP
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 35639f3115fd..a0195e28c8e6 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_REGULATOR_MT6359) += mt6359-regulator.o
obj-$(CONFIG_REGULATOR_MT6360) += mt6360-regulator.o
obj-$(CONFIG_REGULATOR_MT6363) += mt6363-regulator.o
obj-$(CONFIG_REGULATOR_MT6370) += mt6370-regulator.o
+obj-$(CONFIG_REGULATOR_MT6373) += mt6373-regulator.o
obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o
obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_MTK_DVFSRC) += mtk-dvfsrc-regulator.o
diff --git a/drivers/regulator/mt6373-regulator.c b/drivers/regulator/mt6373-regulator.c
new file mode 100644
index 000000000000..90672ae1eb80
--- /dev/null
+++ b/drivers/regulator/mt6373-regulator.c
@@ -0,0 +1,772 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Copyright (c) 2024 MediaTek Inc.
+// Copyright (c) 2025 Collabora Ltd
+// AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/spmi.h>
+
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6373-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+#define MT6373_REGULATOR_MODE_NORMAL 0
+#define MT6373_REGULATOR_MODE_FCCM 1
+#define MT6373_REGULATOR_MODE_LP 2
+#define MT6373_REGULATOR_MODE_ULP 3
+
+#define EN_SET_OFFSET 0x1
+#define EN_CLR_OFFSET 0x2
+
+#define OC_IRQ_ENABLE_DELAY_MS 10
+
+/* Unlock key for mode setting */
+#define MT6373_BUCK_TOP_UNLOCK_VALUE 0x5543
+
+enum {
+ MT6373_ID_VBUCK0,
+ MT6373_ID_VBUCK1,
+ MT6373_ID_VBUCK2,
+ MT6373_ID_VBUCK3,
+ MT6373_ID_VBUCK4,
+ MT6373_ID_VBUCK5,
+ MT6373_ID_VBUCK6,
+ MT6373_ID_VBUCK7,
+ MT6373_ID_VBUCK8,
+ MT6373_ID_VBUCK9,
+ MT6373_ID_VANT18,
+ MT6373_ID_VAUD18,
+ MT6373_ID_VAUX18,
+ MT6373_ID_VCN18IO,
+ MT6373_ID_VCN33_1,
+ MT6373_ID_VCN33_2,
+ MT6373_ID_VCN33_3,
+ MT6373_ID_VEFUSE,
+ MT6373_ID_VFP,
+ MT6373_ID_VIBR,
+ MT6373_ID_VIO28,
+ MT6373_ID_VMC,
+ MT6373_ID_VMCH,
+ MT6373_ID_VMCH_EINT_HIGH,
+ MT6373_ID_VMCH_EINT_LOW,
+ MT6373_ID_VRF09_AIF,
+ MT6373_ID_VRF12_AIF,
+ MT6373_ID_VRF13_AIF,
+ MT6373_ID_VRF18_AIF,
+ MT6373_ID_VRFIO18_AIF,
+ MT6373_ID_VSRAM_DIGRF_AIF,
+ MT6373_ID_VTP,
+ MT6373_ID_VUSB,
+};
+
+/**
+ * struct mt6373_regulator_info - MT6373 regulators information
+ * @desc: Regulator description structure
+ * @lp_mode_reg: Low Power mode register (normal/idle)
+ * @lp_mode_mask: Low Power mode regulator mask
+ * @modeset_reg: AUTO/PWM mode register
+ * @modeset_mask: AUTO/PWM regulator mask
+ * @oc_work: Delayed work for enabling overcurrent IRQ
+ * @hwirq: PMIC-Internal HW Interrupt for overcurrent event
+ * @virq: Mapped Interrupt for overcurrent event
+ */
+struct mt6373_regulator_info {
+ struct regulator_desc desc;
+ u16 lp_mode_reg;
+ u16 lp_mode_mask;
+ u16 modeset_reg;
+ u16 modeset_mask;
+ struct delayed_work oc_work;
+ u8 hwirq;
+ int virq;
+};
+
+#define MT6373_BUCK(match, vreg, min, max, step, en_reg, lp_reg, \
+ mset_reg, ocp_intn) \
+[MT6373_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = "vsys-"match, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6373_vreg_setclr_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6373_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min) / step + 1, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .enable_reg = en_reg, \
+ .enable_mask = BIT(MT6373_PMIC_RG_BUCK_##vreg##_EN_BIT),\
+ .vsel_reg = MT6373_PMIC_RG_BUCK_##vreg##_VOSEL_ADDR, \
+ .vsel_mask = MT6373_PMIC_RG_BUCK_VOSEL_MASK, \
+ .of_map_mode = mt6373_map_mode, \
+ }, \
+ .lp_mode_reg = lp_reg, \
+ .lp_mode_mask = BIT(MT6373_PMIC_RG_BUCK_##vreg##_LP_BIT), \
+ .modeset_reg = mset_reg, \
+ .modeset_mask = BIT(MT6373_PMIC_RG_##vreg##_FCCM_BIT), \
+ .hwirq = ocp_intn, \
+}
+
+
+#define MT6373_LDO_L(match, vreg, in_sup, min, max, step, ocp_intn) \
+[MT6373_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = in_sup, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6373_ldo_linear_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6373_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min) / step + 1, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .enable_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR, \
+ .enable_mask = BIT(0), \
+ .vsel_reg = MT6373_PMIC_RG_##vreg##_VOSEL_ADDR, \
+ .vsel_mask = MT6373_PMIC_RG_##vreg##_VOSEL_MASK, \
+ .of_map_mode = mt6373_map_mode, \
+ }, \
+ .lp_mode_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR, \
+ .lp_mode_mask = BIT(1), \
+ .hwirq = ocp_intn, \
+}
+
+#define MT6373_LDO_VT_OPS(match, vreg, in_sup, vops, vrnum, ocp_intn) \
+[MT6373_ID_##vreg] = { \
+ .desc = { \
+ .name = match, \
+ .supply_name = in_sup, \
+ .of_match = of_match_ptr(match), \
+ .ops = &vops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6373_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_ranges##vrnum) * 11, \
+ .linear_ranges = ldo_volt_ranges##vrnum, \
+ .n_linear_ranges = ARRAY_SIZE(ldo_volt_ranges##vrnum), \
+ .linear_range_selectors_bitfield = ldos_cal_selectors, \
+ .enable_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR, \
+ .enable_mask = BIT(0), \
+ .vsel_reg = MT6373_PMIC_RG_##vreg##_VOCAL_ADDR, \
+ .vsel_mask = MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK, \
+ .vsel_range_reg = MT6373_PMIC_RG_##vreg##_VOSEL_ADDR, \
+ .vsel_range_mask = MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK, \
+ .of_map_mode = mt6373_map_mode, \
+ }, \
+ .lp_mode_reg = MT6373_PMIC_RG_LDO_##vreg##_ADDR, \
+ .lp_mode_mask = BIT(1), \
+ .hwirq = ocp_intn, \
+}
+
+#define MT6373_LDO_VT(match, vreg, inp, vrnum, ocp_intn) \
+ MT6373_LDO_VT_OPS(match, vreg, inp, mt6373_ldo_vtable_ops, \
+ vrnum, ocp_intn)
+
+#define MT6373_LDO_EI(match, vreg, inp, vrnum, ocp_intn) \
+ MT6373_LDO_VT_OPS(match, vreg, inp, mt6373_vmch_eint_ops, \
+ vrnum, ocp_intn)
+
+static const unsigned int ldos_cal_selectors[] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+static const struct linear_range ldo_volt_ranges1[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges2[] = {
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges3[] = {
+ REGULATOR_LINEAR_RANGE(600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2100000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges4[] = {
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2500000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2600000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2700000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2800000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(2900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3300000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3400000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(3500000, 0, 10, 10000)
+};
+
+static const struct linear_range ldo_volt_ranges5[] = {
+ REGULATOR_LINEAR_RANGE(900000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1000000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1100000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1200000, 0, 10, 10000),
+ REGULATOR_LINEAR_RANGE(1300000, 0, 10, 10000),
+};
+
+static int mt6373_vreg_enable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_SET_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static int mt6373_vreg_disable_setclr(struct regulator_dev *rdev)
+{
+ return regmap_write(rdev->regmap, rdev->desc->enable_reg + EN_CLR_OFFSET,
+ rdev->desc->enable_mask);
+}
+
+static inline unsigned int mt6373_map_mode(unsigned int mode)
+{
+ switch (mode) {
+ case MT6373_REGULATOR_MODE_NORMAL:
+ return REGULATOR_MODE_NORMAL;
+ case MT6373_REGULATOR_MODE_FCCM:
+ return REGULATOR_MODE_FAST;
+ case MT6373_REGULATOR_MODE_LP:
+ return REGULATOR_MODE_IDLE;
+ case MT6373_REGULATOR_MODE_ULP:
+ return REGULATOR_MODE_STANDBY;
+ default:
+ return REGULATOR_MODE_INVALID;
+ }
+}
+
+static int mt6373_vmch_eint_enable(struct regulator_dev *rdev)
+{
+ const struct regulator_desc *rdesc = rdev->desc;
+ unsigned int val;
+ int ret;
+
+ if (rdesc->id == MT6373_ID_VMCH_EINT_HIGH)
+ val = MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT;
+ else
+ val = 0;
+
+ ret = regmap_update_bits(rdev->regmap,
+ MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR,
+ MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT, val);
+ if (ret)
+ return ret;
+
+ ret = regmap_set_bits(rdev->regmap,
+ MT6373_PMIC_RG_LDO_VMCH_ADDR,
+ rdesc->enable_mask);
+ if (ret)
+ return ret;
+
+ return regmap_set_bits(rdev->regmap, rdesc->enable_reg, rdesc->enable_mask);
+}
+
+static int mt6373_vmch_eint_disable(struct regulator_dev *rdev)
+{
+ const struct regulator_desc *rdesc = rdev->desc;
+ int ret;
+
+ ret = regmap_clear_bits(rdev->regmap,
+ MT6373_PMIC_RG_LDO_VMCH_ADDR,
+ rdesc->enable_mask);
+ if (ret)
+ return ret;
+
+ /* Wait for VMCH discharging */
+ usleep_range(1500, 1600);
+
+ return regmap_clear_bits(rdev->regmap, rdesc->enable_reg, rdesc->enable_mask);
+}
+
+static unsigned int mt6373_regulator_get_mode(struct regulator_dev *rdev)
+{
+ struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+ unsigned int val;
+ int ret;
+
+ if (info->modeset_reg) {
+ ret = regmap_read(rdev->regmap, info->modeset_reg, &val);
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get mt6373 mode: %d\n", ret);
+ return ret;
+ }
+
+ if (val & info->modeset_mask)
+ return REGULATOR_MODE_FAST;
+ } else {
+ val = 0;
+ };
+
+ ret = regmap_read(rdev->regmap, info->lp_mode_reg, &val);
+ val &= info->lp_mode_mask;
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to get lp mode: %d\n", ret);
+ return ret;
+ }
+
+ if (val)
+ return REGULATOR_MODE_IDLE;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int mt6373_buck_unlock(struct regmap *map, bool unlock)
+{
+ u16 buf = unlock ? MT6373_BUCK_TOP_UNLOCK_VALUE : 0;
+
+ return regmap_bulk_write(map, MT6373_BUCK_TOP_KEY_PROT_LO, &buf, sizeof(buf));
+}
+
+static int mt6373_regulator_set_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+ struct regmap *regmap = rdev->regmap;
+ int cur_mode, ret;
+
+ if (!info->modeset_reg && mode == REGULATOR_MODE_FAST)
+ return -EOPNOTSUPP;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ ret = mt6373_buck_unlock(regmap, true);
+ if (ret)
+ break;
+
+ ret = regmap_set_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+ mt6373_buck_unlock(regmap, false);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ cur_mode = mt6373_regulator_get_mode(rdev);
+ if (cur_mode < 0) {
+ ret = cur_mode;
+ break;
+ }
+
+ if (cur_mode == REGULATOR_MODE_FAST) {
+ ret = mt6373_buck_unlock(regmap, true);
+ if (ret)
+ break;
+
+ ret = regmap_clear_bits(regmap, info->modeset_reg, info->modeset_mask);
+
+ mt6373_buck_unlock(regmap, false);
+ break;
+ } else if (cur_mode == REGULATOR_MODE_IDLE) {
+ ret = regmap_clear_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ if (ret == 0)
+ usleep_range(100, 200);
+ } else {
+ ret = 0;
+ }
+ break;
+ case REGULATOR_MODE_IDLE:
+ ret = regmap_set_bits(regmap, info->lp_mode_reg, info->lp_mode_mask);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to set mode %u: %d\n", mode, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void mt6373_oc_irq_enable_work(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+ struct mt6373_regulator_info *info =
+ container_of(dwork, struct mt6373_regulator_info, oc_work);
+
+ enable_irq(info->virq);
+}
+
+static irqreturn_t mt6373_oc_isr(int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+ struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+
+ disable_irq_nosync(info->virq);
+
+ if (regulator_is_enabled_regmap(rdev))
+ regulator_notifier_call_chain(rdev, REGULATOR_EVENT_OVER_CURRENT, NULL);
+
+ schedule_delayed_work(&info->oc_work, msecs_to_jiffies(OC_IRQ_ENABLE_DELAY_MS));
+
+ return IRQ_HANDLED;
+}
+
+static int mt6373_set_ocp(struct regulator_dev *rdev, int lim, int severity, bool enable)
+{
+ struct mt6373_regulator_info *info = rdev_get_drvdata(rdev);
+
+ /* MT6373 supports only enabling protection and does not support limits */
+ if (lim || severity != REGULATOR_SEVERITY_PROT || !enable)
+ return -EINVAL;
+
+ /* If there is no OCP interrupt, there's nothing to set */
+ if (info->virq <= 0)
+ return -EINVAL;
+
+ return devm_request_threaded_irq(&rdev->dev, info->virq, NULL,
+ mt6373_oc_isr, IRQF_ONESHOT,
+ info->desc.name, rdev);
+}
+
+static const struct regulator_ops mt6373_vreg_setclr_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = mt6373_vreg_enable_setclr,
+ .disable = mt6373_vreg_disable_setclr,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6373_regulator_set_mode,
+ .get_mode = mt6373_regulator_get_mode,
+ .set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_ldo_linear_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6373_regulator_set_mode,
+ .get_mode = mt6373_regulator_get_mode,
+ .set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_ldo_vtable_ops = {
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = regulator_map_voltage_pickable_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6373_regulator_set_mode,
+ .get_mode = mt6373_regulator_get_mode,
+ .set_over_current_protection = mt6373_set_ocp,
+};
+
+static const struct regulator_ops mt6373_vmch_eint_ops = {
+ .list_voltage = regulator_list_voltage_pickable_linear_range,
+ .map_voltage = regulator_map_voltage_pickable_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_pickable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = mt6373_vmch_eint_enable,
+ .disable = mt6373_vmch_eint_disable,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_mode = mt6373_regulator_set_mode,
+ .get_mode = mt6373_regulator_get_mode,
+ .set_over_current_protection = mt6373_set_ocp,
+};
+
+/* The array is indexed by id(MT6373_ID_XXX) */
+static struct mt6373_regulator_info mt6373_regulators[] = {
+ MT6373_BUCK("vbuck0", VBUCK0, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 0),
+ MT6373_BUCK("vbuck1", VBUCK1, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 1),
+ MT6373_BUCK("vbuck2", VBUCK2, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 2),
+ MT6373_BUCK("vbuck3", VBUCK3, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_FCCM_ADDR, 3),
+ MT6373_BUCK("vbuck4", VBUCK4, 0, 0, 1, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 4),
+ MT6373_BUCK("vbuck5", VBUCK5, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 5),
+ MT6373_BUCK("vbuck6", VBUCK6, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 6),
+ MT6373_BUCK("vbuck7", VBUCK7, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK0_EN_ADDR,
+ MT6373_PMIC_RG_BUCK0_LP_ADDR, MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR, 7),
+ MT6373_BUCK("vbuck8", VBUCK8, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK1_EN_ADDR,
+ MT6373_PMIC_RG_BUCK1_LP_ADDR, MT6373_PMIC_RG_BUCK1_FCCM_ADDR, 8),
+ MT6373_BUCK("vbuck9", VBUCK9, 0, 1193750, 6250, MT6373_PMIC_RG_BUCK1_EN_ADDR,
+ MT6373_PMIC_RG_BUCK1_LP_ADDR, MT6373_PMIC_RG_BUCK1_FCCM_ADDR, 9),
+ MT6373_LDO_VT("vant18", VANT18, "vs1-ldo1", 3, 28),
+ MT6373_LDO_VT("vaud18", VAUD18, "vs1-ldo1", 3, 16),
+ MT6373_LDO_VT("vaux18", VAUX18, "vsys-ldo2", 2, 18),
+ MT6373_LDO_VT("vcn18io", VCN18IO, "vs1-ldo1", 3, 25),
+ MT6373_LDO_VT("vcn33-1", VCN33_1, "vsys-ldo1", 4, 22),
+ MT6373_LDO_VT("vcn33-2", VCN33_2, "vsys-ldo1", 4, 23),
+ MT6373_LDO_VT("vcn33-3", VCN33_3, "vsys-ldo2", 4, 24),
+ MT6373_LDO_VT("vefuse", VEFUSE, "vsys-ldo2", 1, 31),
+ MT6373_LDO_VT("vfp", VFP, "vsys-ldo2", 1, 36),
+ MT6373_LDO_VT("vibr", VIBR, "vsys-ldo2", 1, 34),
+ MT6373_LDO_VT("vio28", VIO28, "vsys-ldo2", 1, 35),
+ MT6373_LDO_VT("vmc", VMC, "vsys-ldo1", 1, 33),
+ MT6373_LDO_VT("vmch", VMCH, "vsys-ldo3", 4, 32),
+ MT6373_LDO_EI("vmch-eint-high", VMCH_EINT_HIGH, "vsys-ldo3", 4, 0),
+ MT6373_LDO_EI("vmch-eint-low", VMCH_EINT_LOW, "vsys-ldo3", 4, 0),
+ MT6373_LDO_VT("vrf09-aif", VRF09_AIF, "vs3-ldo1", 3, 26),
+ MT6373_LDO_VT("vrf12-aif", VRF12_AIF, "vs2-ldo1", 5, 27),
+ MT6373_LDO_VT("vrf13-aif", VRF13_AIF, "vs2-ldo1", 3, 19),
+ MT6373_LDO_VT("vrf18-aif", VRF18_AIF, "vs1-ldo1", 3, 20),
+ MT6373_LDO_VT("vrfio18-aif", VRFIO18_AIF, "vs1-ldo1", 3, 25),
+ MT6373_LDO_L("vsram-digrf-aif", VSRAM_DIGRF_AIF, "vs3-ldo1", 400000, 1193750, 6250, 29),
+ MT6373_LDO_VT("vtp", VTP, "vsys-ldo2", 1, 37),
+ MT6373_LDO_VT("vusb", VUSB, "vsys-ldo2", 1, 17)
+};
+
+static void mt6373_irq_remove(void *data)
+{
+ int *virq = data;
+
+ irq_dispose_mapping(*virq);
+}
+
+static void mt6373_spmi_remove(void *data)
+{
+ struct spmi_device *sdev = data;
+
+ spmi_device_remove(sdev);
+};
+
+static struct regmap *mt6373_spmi_register_regmap(struct device *dev)
+{
+ struct regmap_config mt6373_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 16,
+ .max_register = 0x1f90,
+ .fast_io = true,
+ };
+ struct spmi_device *sdev, *sparent;
+ u32 base;
+ int ret;
+
+ if (!dev->parent)
+ return ERR_PTR(-ENODEV);
+
+ ret = device_property_read_u32(dev, "reg", &base);
+ if (ret)
+ return ERR_PTR(ret);
+
+ sparent = to_spmi_device(dev->parent);
+ if (!sparent)
+ return ERR_PTR(-ENODEV);
+
+ sdev = spmi_device_alloc(sparent->ctrl);
+ if (!sdev)
+ return ERR_PTR(-ENODEV);
+
+ sdev->usid = sparent->usid;
+ dev_set_name(&sdev->dev, "%d-%02x-regulator", sdev->ctrl->nr, sdev->usid);
+ ret = device_add(&sdev->dev);
+ if (ret) {
+ put_device(&sdev->dev);
+ return ERR_PTR(ret);
+ };
+
+ ret = devm_add_action_or_reset(dev, mt6373_spmi_remove, sdev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mt6373_regmap_config.reg_base = base;
+
+ return devm_regmap_init_spmi_ext(sdev, &mt6373_regmap_config);
+}
+
+static int mt6373_regulator_probe(struct platform_device *pdev)
+{
+ struct device_node *interrupt_parent;
+ struct regulator_config config = {};
+ struct mt6373_regulator_info *info;
+ struct device *dev = &pdev->dev;
+ struct regulator_dev *rdev;
+ struct irq_domain *domain;
+ struct irq_fwspec fwspec;
+ struct spmi_device *sdev;
+ bool is_vbuck4_hw_ctrl;
+ bool is_cw_variant;
+ int i, ret;
+ u32 val;
+
+ config.regmap = mt6373_spmi_register_regmap(dev);
+ if (IS_ERR(config.regmap))
+ return dev_err_probe(dev, PTR_ERR(config.regmap),
+ "Cannot get regmap\n");
+ config.dev = dev;
+ sdev = to_spmi_device(dev->parent);
+ dev_set_drvdata(dev, config.regmap);
+
+ interrupt_parent = of_irq_find_parent(dev->of_node);
+ if (!interrupt_parent)
+ return -EINVAL;
+
+ domain = irq_find_host(interrupt_parent);
+ of_node_put(interrupt_parent);
+ fwspec.fwnode = domain->fwnode;
+
+ fwspec.param_count = 3;
+ fwspec.param[0] = sdev->usid;
+ fwspec.param[2] = IRQ_TYPE_LEVEL_HIGH;
+
+ /*
+ * The first read may fail if the bootloader sets sleep mode: wake up
+ * this PMIC with W/R on the SPMI bus and ignore the first result.
+ */
+ regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val);
+
+ /* Read PMIC variant information */
+ ret = regmap_read(config.regmap, MT6373_PLG_CFG_ELR1, &val);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot read ID register\n");
+
+ val = FIELD_GET(MT6373_ELR_VARIANT_MASK, val);
+ is_cw_variant = (val == MT6373_ELR_VARIANT_MT6373CW);
+
+ /* Read Reserved-SW information */
+ ret = regmap_read(config.regmap, MT6373_RG_RSV_SWREG_H, &val);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot read RSV_SW register\n");
+
+ is_vbuck4_hw_ctrl = val & MT6373_RG_RSV_SWREG_VBUCK4_HW_CTRL;
+
+ for (i = 0; i < ARRAY_SIZE(mt6373_regulators); i++) {
+ info = &mt6373_regulators[i];
+
+ /* MT6373CW VBUCK4 constraints are different */
+ if (info->desc.id == MT6373_ID_VBUCK4) {
+ unsigned int vbuck4_max_uV;
+
+ /* VBUCK4 vreg software control not allowed in hw_ctrl mode */
+ if (is_vbuck4_hw_ctrl)
+ continue;
+
+ if (is_cw_variant) {
+ info->desc.uV_step = 6250;
+ vbuck4_max_uV = 1193750;
+ } else {
+ info->desc.uV_step = 13875;
+ vbuck4_max_uV = 2650125;
+ }
+ info->desc.n_voltages = vbuck4_max_uV / info->desc.uV_step + 1;
+ }
+
+ fwspec.param[0] = to_spmi_device(dev->parent)->usid;
+ fwspec.param[1] = info->hwirq;
+ info->virq = irq_create_fwspec_mapping(&fwspec);
+ if (!info->virq)
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to map IRQ%d\n", info->hwirq);
+
+ ret = devm_add_action_or_reset(dev, mt6373_irq_remove, &info->virq);
+ if (ret) {
+ irq_dispose_mapping(info->virq);
+ return ret;
+ }
+
+ config.driver_data = info;
+ INIT_DELAYED_WORK(&info->oc_work, mt6373_oc_irq_enable_work);
+
+ rdev = devm_regulator_register(dev, &info->desc, &config);
+ if (IS_ERR(rdev))
+ return dev_err_probe(dev, PTR_ERR(rdev),
+ "failed to register %s\n", info->desc.name);
+ }
+
+ return 0;
+}
+
+static void mt6373_regulator_shutdown(struct platform_device *pdev)
+{
+ struct regmap *regmap = dev_get_drvdata(&pdev->dev);
+
+ regmap_write(regmap, MT6373_TOP_CFG_ELR5, MT6373_TOP_CFG_ELR5_SHUTDOWN);
+}
+
+static const struct of_device_id mt6373_regulator_match[] = {
+ { .compatible = "mediatek,mt6373-regulator" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver mt6373_regulator_driver = {
+ .driver = {
+ .name = "mt6373-regulator",
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .of_match_table = mt6373_regulator_match,
+ },
+ .probe = mt6373_regulator_probe,
+ .shutdown = mt6373_regulator_shutdown
+};
+module_platform_driver(mt6373_regulator_driver);
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek MT6373 PMIC Regulator Driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/regulator/mt6373-regulator.h b/include/linux/regulator/mt6373-regulator.h
new file mode 100644
index 000000000000..dd791717d2a1
--- /dev/null
+++ b/include/linux/regulator/mt6373-regulator.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 MediaTek Inc.
+ * Copyright (c) 2025 Collabora Ltd
+ */
+
+#include <linux/bits.h>
+
+#ifndef __LINUX_REGULATOR_MT6373_H
+#define __LINUX_REGULATOR_MT6373_H
+
+/* Register */
+#define MT6373_TOP_CFG_ELR5 0x117
+#define MT6373_TOP_CFG_ELR5_SHUTDOWN BIT(0)
+
+#define MT6373_PMIC_RG_BUCK0_EN_ADDR 0x210
+#define MT6373_PMIC_RG_BUCK_VBUCK0_EN_BIT 0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_EN_BIT 1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_EN_BIT 2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_EN_BIT 3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_EN_BIT 4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_EN_BIT 5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_EN_BIT 6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_EN_BIT 7
+
+#define MT6373_PMIC_RG_BUCK1_EN_ADDR 0x213
+#define MT6373_PMIC_RG_BUCK_VBUCK8_EN_BIT 0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_EN_BIT 1
+
+#define MT6373_PMIC_RG_BUCK0_LP_ADDR 0x216
+#define MT6373_PMIC_RG_BUCK_VBUCK0_LP_BIT 0
+#define MT6373_PMIC_RG_BUCK_VBUCK1_LP_BIT 1
+#define MT6373_PMIC_RG_BUCK_VBUCK2_LP_BIT 2
+#define MT6373_PMIC_RG_BUCK_VBUCK3_LP_BIT 3
+#define MT6373_PMIC_RG_BUCK_VBUCK4_LP_BIT 4
+#define MT6373_PMIC_RG_BUCK_VBUCK5_LP_BIT 5
+#define MT6373_PMIC_RG_BUCK_VBUCK6_LP_BIT 6
+#define MT6373_PMIC_RG_BUCK_VBUCK7_LP_BIT 7
+
+#define MT6373_PMIC_RG_BUCK1_LP_ADDR 0x219
+#define MT6373_PMIC_RG_BUCK_VBUCK8_LP_BIT 0
+#define MT6373_PMIC_RG_BUCK_VBUCK9_LP_BIT 1
+
+#define MT6373_PMIC_RG_BUCK_VBUCK0_VOSEL_ADDR 0x21c
+#define MT6373_PMIC_RG_BUCK_VBUCK1_VOSEL_ADDR 0x21d
+#define MT6373_PMIC_RG_BUCK_VBUCK2_VOSEL_ADDR 0x21e
+#define MT6373_PMIC_RG_BUCK_VBUCK3_VOSEL_ADDR 0x21f
+#define MT6373_PMIC_RG_BUCK_VBUCK4_VOSEL_ADDR 0x220
+#define MT6373_PMIC_RG_BUCK_VBUCK5_VOSEL_ADDR 0x221
+#define MT6373_PMIC_RG_BUCK_VBUCK6_VOSEL_ADDR 0x222
+#define MT6373_PMIC_RG_BUCK_VBUCK7_VOSEL_ADDR 0x223
+#define MT6373_PMIC_RG_BUCK_VBUCK8_VOSEL_ADDR 0x224
+#define MT6373_PMIC_RG_BUCK_VBUCK9_VOSEL_ADDR 0x225
+#define MT6373_PMIC_RG_BUCK_VOSEL_MASK GENMASK(8, 0)
+
+#define MT6373_PLG_CFG_ELR1 0x37b
+#define MT6373_ELR_VARIANT_MASK GENMASK(3, 2)
+#define MT6373_ELR_VARIANT_MT6373CW 1
+#define MT6373_RG_RSV_SWREG_H 0x9d9
+#define MT6373_RG_RSV_SWREG_VBUCK4_HW_CTRL BIT(0)
+
+#define MT6373_BUCK_TOP_KEY_PROT_LO 0x13fa
+
+#define MT6373_PMIC_RG_BUCK1_FCCM_ADDR 0x196d
+#define MT6373_PMIC_RG_VBUCK8_FCCM_BIT 6
+#define MT6373_PMIC_RG_VBUCK9_FCCM_BIT 7
+
+#define MT6373_PMIC_RG_BUCK0_FCCM_ADDR 0x1a02
+#define MT6373_PMIC_RG_VBUCK0_FCCM_BIT 0
+#define MT6373_PMIC_RG_VBUCK1_FCCM_BIT 1
+#define MT6373_PMIC_RG_VBUCK2_FCCM_BIT 2
+#define MT6373_PMIC_RG_VBUCK3_FCCM_BIT 3
+
+#define MT6373_PMIC_RG_BUCK0_1_FCCM_ADDR 0x1a82
+#define MT6373_PMIC_RG_VBUCK4_FCCM_BIT 0
+#define MT6373_PMIC_RG_VBUCK5_FCCM_BIT 1
+#define MT6373_PMIC_RG_VBUCK6_FCCM_BIT 2
+#define MT6373_PMIC_RG_VBUCK7_FCCM_BIT 3
+
+#define MT6373_PMIC_RG_VSRAM_DIGRF_AIF_VOSEL_ADDR 0x1b09
+#define MT6373_PMIC_RG_VSRAM_DIGRF_AIF_VOSEL_MASK GENMASK(6, 0)
+
+#define MT6373_PMIC_RG_LDO_VAUD18_ADDR 0x1b57
+#define MT6373_PMIC_RG_LDO_VUSB_ADDR 0x1b65
+#define MT6373_PMIC_RG_LDO_VAUX18_ADDR 0x1b73
+#define MT6373_PMIC_RG_LDO_VRF13_AIF_ADDR 0x1b81
+#define MT6373_PMIC_RG_LDO_VRF18_AIF_ADDR 0x1b8f
+#define MT6373_PMIC_RG_LDO_VRFIO18_AIF_ADDR 0x1b9d
+#define MT6373_PMIC_RG_LDO_VCN33_1_ADDR 0x1bd7
+#define MT6373_PMIC_RG_LDO_VCN33_2_ADDR 0x1be5
+#define MT6373_PMIC_RG_LDO_VCN33_3_ADDR 0x1bf3
+#define MT6373_PMIC_RG_LDO_VCN18IO_ADDR 0x1c01
+#define MT6373_PMIC_RG_LDO_VRF09_AIF_ADDR 0x1c0f
+#define MT6373_PMIC_RG_LDO_VRF12_AIF_ADDR 0x1c1d
+#define MT6373_PMIC_RG_LDO_VANT18_ADDR 0x1c57
+#define MT6373_PMIC_RG_LDO_VEFUSE_ADDR 0x1c73
+#define MT6373_PMIC_RG_LDO_VMCH_ADDR 0x1c81
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR 0x1c8f
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_HIGH_ADDR MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_LOW_ADDR MT6373_PMIC_RG_LDO_VMCH_EINT_ADDR
+#define MT6373_PMIC_RG_LDO_VMCH_EINT_POL_BIT BIT(2)
+#define MT6373_PMIC_RG_LDO_VMC_ADDR 0x1c90
+#define MT6373_PMIC_RG_LDO_VIBR_ADDR 0x1c9e
+#define MT6373_PMIC_RG_LDO_VIO28_ADDR 0x1cd7
+#define MT6373_PMIC_RG_LDO_VFP_ADDR 0x1ce5
+#define MT6373_PMIC_RG_LDO_VTP_ADDR 0x1cf3
+#define MT6373_PMIC_RG_LDO_VSIM1_ADDR 0x1d01
+#define MT6373_PMIC_RG_LDO_VSIM2_ADDR 0x1d10
+#define MT6373_PMIC_RG_LDO_VSIM2_LP_ADDR 0x1d10
+#define MT6373_PMIC_RG_LDO_VSRAM_DIGRF_AIF_ADDR 0x1d57
+#define MT6373_PMIC_RG_VAUX18_VOCAL_ADDR 0x1dd8
+#define MT6373_PMIC_RG_VAUX18_VOSEL_ADDR 0x1dd9
+#define MT6373_PMIC_RG_VUSB_VOCAL_ADDR 0x1ddc
+#define MT6373_PMIC_RG_VUSB_VOSEL_ADDR 0x1ddd
+#define MT6373_PMIC_RG_VCN33_1_VOCAL_ADDR 0x1de0
+#define MT6373_PMIC_RG_VCN33_1_VOSEL_ADDR 0x1de1
+#define MT6373_PMIC_RG_VCN33_2_VOCAL_ADDR 0x1de4
+#define MT6373_PMIC_RG_VCN33_2_VOSEL_ADDR 0x1de5
+#define MT6373_PMIC_RG_VCN33_3_VOCAL_ADDR 0x1de8
+#define MT6373_PMIC_RG_VCN33_3_VOSEL_ADDR 0x1de9
+#define MT6373_PMIC_RG_VMCH_VOCAL_ADDR 0x1dec
+#define MT6373_PMIC_RG_VMCH_VOSEL_ADDR 0x1ded
+#define MT6373_PMIC_RG_VMCH_EINT_HIGH_VOSEL_ADDR MT6373_PMIC_RG_VMCH_VOSEL_ADDR
+#define MT6373_PMIC_RG_VMCH_EINT_LOW_VOSEL_ADDR MT6373_PMIC_RG_VMCH_VOSEL_ADDR
+#define MT6373_PMIC_RG_VEFUSE_VOCAL_ADDR 0x1df0
+#define MT6373_PMIC_RG_VEFUSE_VOSEL_ADDR 0x1df1
+#define MT6373_PMIC_RG_VMC_VOCAL_ADDR 0x1df4
+#define MT6373_PMIC_RG_VMCH_EINT_HIGH_VOCAL_ADDR MT6373_PMIC_RG_VMC_VOCAL_ADDR
+#define MT6373_PMIC_RG_VMCH_EINT_LOW_VOCAL_ADDR MT6373_PMIC_RG_VMC_VOCAL_ADDR
+#define MT6373_PMIC_RG_VMC_VOSEL_ADDR 0x1df5
+#define MT6373_PMIC_RG_VIBR_VOCAL_ADDR 0x1df8
+#define MT6373_PMIC_RG_VIBR_VOSEL_ADDR 0x1df9
+#define MT6373_PMIC_RG_VIO28_VOCAL_ADDR 0x1dfc
+#define MT6373_PMIC_RG_VIO28_VOSEL_ADDR 0x1dfd
+#define MT6373_PMIC_RG_VFP_VOCAL_ADDR 0x1e00
+#define MT6373_PMIC_RG_VFP_VOSEL_ADDR 0x1e01
+#define MT6373_PMIC_RG_VTP_VOCAL_ADDR 0x1e04
+#define MT6373_PMIC_RG_VTP_VOSEL_ADDR 0x1e05
+#define MT6373_PMIC_RG_VSIM1_VOCAL_ADDR 0x1e08
+#define MT6373_PMIC_RG_VSIM1_VOSEL_ADDR 0x1e09
+#define MT6373_PMIC_RG_VSIM2_VOCAL_ADDR 0x1e0c
+#define MT6373_PMIC_RG_VSIM2_VOSEL_ADDR 0x1e0d
+#define MT6373_PMIC_RG_VAUD18_VOCAL_ADDR 0x1e58
+#define MT6373_PMIC_RG_VAUD18_VOSEL_ADDR 0x1e59
+#define MT6373_PMIC_RG_VRF18_AIF_VOCAL_ADDR 0x1e5c
+#define MT6373_PMIC_RG_VRF18_AIF_VOSEL_ADDR 0x1e5d
+#define MT6373_PMIC_RG_VCN18IO_VOCAL_ADDR 0x1e60
+#define MT6373_PMIC_RG_VCN18IO_VOSEL_ADDR 0x1e61
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOCAL_ADDR 0x1e64
+#define MT6373_PMIC_RG_VRFIO18_AIF_VOSEL_ADDR 0x1e65
+#define MT6373_PMIC_RG_VANT18_VOCAL_ADDR 0x1e68
+#define MT6373_PMIC_RG_VANT18_VOSEL_ADDR 0x1e69
+#define MT6373_PMIC_RG_VRF13_AIF_VOCAL_ADDR 0x1ed8
+#define MT6373_PMIC_RG_VRF13_AIF_VOSEL_ADDR 0x1ed9
+#define MT6373_PMIC_RG_VRF12_AIF_VOCAL_ADDR 0x1edc
+#define MT6373_PMIC_RG_VRF12_AIF_VOSEL_ADDR 0x1edd
+#define MT6373_PMIC_RG_VRF09_AIF_VOCAL_ADDR 0x1f58
+#define MT6373_PMIC_RG_VRF09_AIF_VOSEL_ADDR 0x1f59
+#define MT6373_PMIC_RG_LDO_VT_VOCALSEL_MASK GENMASK(7, 0)
+
+#endif /* __LINUX_REGULATOR_MT6373_H */
--
2.53.0
^ permalink raw reply related
* Re: [PATCH] iommu/arm-smmu-v3-sva: Enable Hardware Access and Hardware Dirty bits
From: Pranjal Shrivastava @ 2026-05-11 13:21 UTC (permalink / raw)
To: Robin Murphy
Cc: Jason Gunthorpe, Nicolin Chen, Will Deacon, Joerg Roedel,
Jean-Philippe Brucker, Catalin Marinas, Mikołaj Lenczewski,
linux-arm-kernel, iommu, linux-kernel
In-Reply-To: <4e129891-2f52-4bac-8e33-1fdde42fd29a@arm.com>
On Fri, May 08, 2026 at 03:24:32PM +0100, Robin Murphy wrote:
> On 2026-05-08 2:57 pm, Pranjal Shrivastava wrote:
> > On Fri, May 08, 2026 at 02:31:11PM +0100, Robin Murphy wrote:
> > > On 2026-05-08 2:12 pm, Pranjal Shrivastava wrote:
> > > > On Fri, May 08, 2026 at 09:35:50AM -0300, Jason Gunthorpe wrote:
> > > > > On Thu, May 07, 2026 at 10:30:14PM +0000, Pranjal Shrivastava wrote:
> > > > > > > @@ -92,6 +92,16 @@ void arm_smmu_make_sva_cd(struct arm_smmu_cd *target,
> > > > > > > target->data[1] = cpu_to_le64(virt_to_phys(mm->pgd) &
> > > > > > > CTXDESC_CD_1_TTB0_MASK);
> > > > > > > +
> > > > > > > + /*
> > > > > > > + * Enable Hardware Access and Dirty updates (DBM) if supported.
> > > > > > > + * This is safe to enable by default, as PTE_WRITE and PTE_DBM
> > > > > > > + * share the same bit.
> > > > > > > + */
> > > > > > > + if (master->smmu->features & ARM_SMMU_FEAT_HA)
> > > > > > > + target->data[0] |= cpu_to_le64(CTXDESC_CD_0_TCR_HA);
> > > > > > > + if (master->smmu->features & ARM_SMMU_FEAT_HD)
> > > > > > > + target->data[0] |= cpu_to_le64(CTXDESC_CD_0_TCR_HD);
> > > > > >
> > > > > > IIUC, we should be setting these if IO_PGTABLE_QUIRK_ARM_HD is present?
> > > > >
> > > > > SVA does not use IO_PGTABLE at all, and it directly constructs its own
> > > > > CD.
> > > > >
> > > > > No relation between those two flows.
> > > >
> > > > I understand that but I mean we need to know if the system supports
> > > > HTTU ? Like for SMMU we use the IO_PGTABLE_QUIRK, shouldn't we be
> > > > checking if the CPU's tables support HTTU?
> > > >
> > > > Are we assuming that if the SMMU IDR presents HTTU capability the MMU
> > > > would also have it? I think an unconditional enablement is risky as we
> > > > may not have system-wide HTTU support.
> > > >
> > > > If we look at arm_smmu_master_sva_supported, the driver already
> > > > maintains a strict agreement between the CPU and SMMU for SVA.
> > > > It checks sanitized CPU ID registers for things like PARANGE & ASIDBITS,
> > > > and it uses system_supports_bbml2_noabort() to decide whether to enable
> > > > FEAT_BBML2.
> > > >
> > > > Shouldn't we follow this exact same pattern for HTTU ?
> > > > We should probably be checking cpu_has_hw_af() (from asm/cpufeature.h)
> > > > in the SVA support check or here if we wanna enable HTTU.
> > >
> > > It might make sense to depend on CONFIG_ARM64_HW_AFDBM - when that is
> > > enabled, then IIRC we already expect to cope with some CPUs not supporting
> > > hardware updates, so it should still be fine for an SMMU to make them even
> > > if no CPU does. However, if it's disabled then I'm not sure if missing
> > > access flag faults (if SMMU HA silently sets them) might be an issue - for
> > > dirty, we'd just never put down the Writeable-Clean permission so enabling
> > > SMMU HD wouldn't do anything anyway.
> >
> > I see, so IIUC, you mean if IS_ENABLED(CONFIG_ARM64_HW_AFDBM) but CPU
> > doesn't enable HTTU, it is perfectly safe to let the SMMU do HTT updates,
> > Since the fault handlers are already expecting HW-triggered updates?
> >
> > Which means our check would be something like:
> >
> > if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) {
> > if (smmu->features & FEAT_HA)
> > ...
> > }
> >
> > instead of cpu_has_hw_af()?
>
> Hmm, looking closer, cpu_has_hw_af() is the thing which actually influences
> mm behaviour (via arch_has_hw_pte_young and arch_wants_old_prefaulted_pte),
> and that can still be false at runtime if ARM64_HW_AFDBM is enabled but any
> CPU doesn't support HAFDBS, so perhaps you were right the first time :)
>
Yea, I believe the cpu_has_hw_af() is the right gate.
> Although AFAICS from __cpu_setup(), ARM64_HW_AFDBM will still
> unconditionally enable TCR_EL1.HA on CPUs which do support it, so maybe it
> is OK anyway?
>
I believe cpu_has_hw_af() is still the safer gate for SVA. While
individual cores might turn on their local HA support, cpu_has_hw_af()
represents the sanitized system view.
In mismatched systems (where some cores support HAFDBS and others don't),
cpu_has_hw_af() will be false & mm shall default to software-managed AF/
Dirty for consistency across all threads. Enabling HTTU in the SMMU while
the kernel mm is in 'SW-Managed' mode could cause the SMMU to silently
flip bits that the kernel is expecting to handle via faults, leading to a
mismatch.
Thanks,
Praan
^ permalink raw reply
* Re: [PATCH RFC] iommu: Enable per-device SSID space for SVA
From: Jason Gunthorpe @ 2026-05-11 13:21 UTC (permalink / raw)
To: Robin Murphy
Cc: Joonwon Kang, Alexander.Grest, amhetre, baolu.lu, iommu, joro,
jpb, kees, linux-arm-kernel, linux-kernel, nicolinc, praan,
smostafa, will, jacob.jun.pan, easwar.hariharan, kevin.tian
In-Reply-To: <30eefd04-1d0f-45d8-b55d-e3e8d41a57ef@arm.com>
On Mon, May 11, 2026 at 01:39:06PM +0100, Robin Murphy wrote:
> On 2026-05-09 6:10 pm, Jason Gunthorpe wrote:
> > On Thu, May 07, 2026 at 09:58:51AM +0000, Joonwon Kang wrote:
> >
> > > By "similar instruction" on ARM, I guess you mean ST64BV0, which fetches
> > > the bottom 32 bits data from ACCDATA_EL1. Please let me know if you meant
> > > others as it will matter. If ST64BV0 is supported on ARM, however, it
> > > would mean that ST64B and ST64BV are also supported already according to
> > > the ID_AA64ISAR1_EL1's LS64 field. The latter 2 instructions are just to
> > > atomically store whatever user wants to a memory location without
> > > referring to ACCDATA_EL1 and all the 3 instructions can be run at EL0. So,
> > > the userspace driver would have enough capability to designate arbitrary
> > > PASID as it wants via the latter 2 instructions when communicating with
> > > multiple devices.
> >
> > IDK exactly what ARM did. IIRC on Intel ENQCMD forms a special
> > non-posted write TLP and the device can tell the TLP came from ENQCMD
> > and so it trusts the encoded PASID. ARM has to have done the same
> > thing - allowing anyone to forge the PASID by using a different
> > instruction misses the point of the Intel design.
>
> Yes, ACCDATA_EL1 is a privileged register neither writeable nor readable by
> userspace[1], so it should be functionally equivalent from an SVA point of
> view.
There is a bit more going on though, I think that is what Joonwon is
mentioning by asking about ST64B and ST64BV. I *think* the answer is:
- ST64B uses a posted write
- ST64BV can be restricted so EL0 cannot execute it, it uses a
non-posted write (AI tells me via EnASR)
- ST64BV0 can be used by EL0, always uses a non-posted write, and always
uses ACCDATA_EL1
Which is similar to Intel. The device only processes the PASID from a
non-posted write, and the CPU prevents userspace from forming
non-posted writes except through ST64BV0
> > Honestly, I'm not sure why they even implemented it. SMMUv3 can't do
> > the translation scheme required to use ENQCMD from a VM anyhow, so it
> > is pretty useless.
>
> Not sure what you mean there - indeed you can't do the SIOV thing of
> assigning individual ADIs to _different_ VMs, but there's still no reason
> you couldn't give the whole accelerator device to one VM, and run the "full"
> kernel driver in that VM to hand out ADIs to processes, same as for
> non-virtualised ST64BV0/ENQCMD usage. It's entirely usable, just not so
> "scalable".
Well yes, technically, but I'm not sure this is attractive in
practice.
The value of ENQCMD on Intel was it can eliminate any HW side
per-context state for simple HW like DMA engines, including for
virtualization.
You pay for that value with some performance loss, but it can be
attractive because of the universal scalability.
However complex devices don't seem to want to use it, once you have to
have per-context state for any other reason the performance downsides
of ENQCMD make it unappealing.
So, IDK, maybe some embedded on-chip device will find a way to make
good use of it, but also I'm not aware of any adoption on x86..
Jason
^ permalink raw reply
* Re: [PATCH 00/15] drm/tidss: Add BeagleY-AI display support (and some more)
From: Swamil Jain @ 2026-05-11 13:19 UTC (permalink / raw)
To: Tomi Valkeinen, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lee Jones, Aradhya Bhatia,
Nishanth Menon, Vignesh Raghavendra, Devarsh Thakkar,
Louis Chauvet
Cc: devicetree, dri-devel, linux-kernel, linux-arm-kernel,
Jayesh Choudhary, Aradhya Bhatia, Andrew Davis
In-Reply-To: <20260420-beagley-ai-display-v1-0-f628543dfd14@ideasonboard.com>
On 20-04-2026 18:24, Tomi Valkeinen wrote:
> This series aims to add display support for all display interfaces on
> BeagleY-AI board. More generally, it adds display support for TI AM62P,
> J722S, and related SoCs, and, as a bit extra, improves AM62L's DPI
> handling.
>
> The main topics to highlight:
>
> - The ti,am625-dss-dpi0-clk-ctrl feels a bit like a hack.
> But it is a single quirk register, among other registers that belong
> to either the firmware or other drivers. So what other options are
> there? This has already been discussed e.g. in
> https://lore.kernel.org/all/20250730-fix-edge-handling-v1-0-1bdfb3fe7922%40bootlin.com/
> without proper conclusion.
>
> - The tidss OLDI support will now use auxiliary device/driver. This seems
> to solve quite neatly the requirement to have a power-domain for each
> OLDI. The main issue that remains is that on AM62P (and similar) we
> will have three OLDI TX DT nodes, even if there are only two in the
> hardware.
>
> With this series one can use the HDMI output on BeagleY-AI. I have also
> tested the DSI output with Raspberry Pi's 7" DSI display, and OLDI
> output with an oscilloscope (I don't have a suitable OLDI panel).
>
> Tomi
>
> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
> ---
The series is tested on TI's AM62P[1] SoC and tested HDMI display and
audio output with BeagleY-AI(AM67A SoC[2]).
Display panels used:
--------------------
DSI Panel: https://www.raspberrypi.com/products/raspberry-pi-touch-display/
OLDI Panel: https://www.ti.com/tool/SK-LCD1
HDMI Panel: https://www.viewsonic.com/in/products/lcd/VA1655-3
Test branch:
https://github.com/jainswamil/linux-next/tree/AM62P_J722S_BEAGLEY_AI_DSS_V1_TEST
Got some DT check warnings with the above test branch[3].
Links
[1]: https://www.ti.com/product/AM62P
[2]: https://www.ti.com/product/AM67A
[3]: https://gist.github.com/jainswamil/945a9859c0f75b41ef21abeede405b2e
Tested-by: Swamil Jain <s-jain1@ti.com>
> Andrew Davis (1):
> arm64: dts: ti: beagley-ai: Enable HDMI display and audio
>
> Jayesh Choudhary (1):
> arm64: dts: ti: k3-am62p-j722s-common-main: Add support for DSS
>
> Swamil Jain (1):
> drm/tidss: Add support for AM62P display subsystem
>
> Tomi Valkeinen (12):
> dt-bindings: display: ti: Move ti,am62l-dss binding to a new binding file
> dt-bindings: display: ti,am65x-dss: Simplify binding
> dt-bindings: mfd: syscon: Add ti,am625-dss-dpi0-clk-ctrl compatible
> dt-bindings: display: ti,am625-oldi: Add optional power-domain for OLDI
> dt-bindings: display: ti,am65x-dss: Add AM62P DSS
> drm/tidss: Remove extra pm_runtime_mark_last_busy
> drm/tidss: oldi: Remove define for unused register OLDI_LB_CTRL
> drm/tidss: Add mechanism to detect DPI output
> drm/tidss: Add external data and sync signal edge configuration
> drm/tidss: Add support for DPIENABLE bit
> drm/tidss: oldi: Fix OLDI signal polarities
> drm/tidss: oldi: Convert OLDI to an aux driver
>
> .../bindings/display/ti/ti,am625-oldi.yaml | 4 +
> .../bindings/display/ti/ti,am62l-dss.yaml | 136 ++++++
> .../bindings/display/ti/ti,am65x-dss.yaml | 176 +++----
> Documentation/devicetree/bindings/mfd/syscon.yaml | 2 +
> MAINTAINERS | 1 +
> .../boot/dts/ti/k3-am62p-j722s-common-main.dtsi | 112 +++++
> arch/arm64/boot/dts/ti/k3-am62p.dtsi | 16 +
> arch/arm64/boot/dts/ti/k3-am67a-beagley-ai.dts | 197 ++++++++
> arch/arm64/boot/dts/ti/k3-j722s.dtsi | 16 +
> drivers/gpu/drm/tidss/tidss_crtc.c | 10 +-
> drivers/gpu/drm/tidss/tidss_crtc.h | 4 +-
> drivers/gpu/drm/tidss/tidss_dispc.c | 46 +-
> drivers/gpu/drm/tidss/tidss_dispc.h | 5 +-
> drivers/gpu/drm/tidss/tidss_dispc_regs.h | 5 +
> drivers/gpu/drm/tidss/tidss_drv.c | 54 ++-
> drivers/gpu/drm/tidss/tidss_drv.h | 5 +-
> drivers/gpu/drm/tidss/tidss_kms.c | 55 ++-
> drivers/gpu/drm/tidss/tidss_oldi.c | 531 +++++++++++++++------
> drivers/gpu/drm/tidss/tidss_oldi.h | 8 +-
> 19 files changed, 1095 insertions(+), 288 deletions(-)
> ---
> base-commit: 3131ff5a117498bb4b9db3a238bb311cbf8383ce
> change-id: 20260420-beagley-ai-display-d7f634cde5f4
> prerequisite-message-id: <20260415110409.2577633-1-s-jain1@ti.com>
> prerequisite-patch-id: 654d90f9cddec8b41e6fb1b3776a632606fef88c
>
> Best regards,
^ permalink raw reply
* Re: [PATCH 5/6] firmware: samsung: acpm: Add TMU protocol support
From: Alexey Klimov @ 2026-05-11 13:17 UTC (permalink / raw)
To: Tudor Ambarus
Cc: Krzysztof Kozlowski, Michael Turquette, Stephen Boyd, Lee Jones,
Alim Akhtar, Sylwester Nawrocki, Chanwoo Choi, André Draszik,
linux-kernel, linux-samsung-soc, linux-arm-kernel, linux-clk,
peter.griffin, jyescas, kernel-team, Krzysztof Kozlowski
In-Reply-To: <806da86b-45b7-43cc-b364-97bade8f4041@linaro.org>
On Thu May 7, 2026 at 9:31 AM BST, Tudor Ambarus wrote:
> On 5/6/26 6:13 PM, Alexey Klimov wrote:
>> On Wed May 6, 2026 at 12:39 PM BST, Tudor Ambarus wrote:
[..]
>>> new file mode 100644
>>> index 000000000000..c68d60b4c0b3
>>> --- /dev/null
>>> +++ b/drivers/firmware/samsung/exynos-acpm-tmu.c
>>
>> [..]
>>
>>> +static int acpm_tmu_to_linux_err(s8 fw_err)
>>> +{
>>> + /*
>>> + * ACPM_TMU_INIT uses BIT(0) and BIT(1) of msg.rx.ret to flag APM
>>> + * capabilities. Treat zero and all positive values as success.
>>
>> ACPM_TMU_INIT returns capabilities inside designated error field?
>
> yes
Heh. Okay.
>> What about other messages/commands? They just return error code there?
>
> all the other commands either return -1 for errors, regardless of the error
> type, or 0 for success.
>>
>>> + */
>>> + if (fw_err >= 0)
>>> + return 0;
>>> +
>>> + if (fw_err == -1)
>>> + return -EACCES;
>>> +
>>> + return -EIO;
>>> +}
>>
>> Could we map these return values with better granularity instead of
>> returning -EIO for everything else that is not minus one?
>
> I think we're good as we are now. The firmware returns either -1 for errors,
> zero for success, or BIT(0) and BIT(1) for TMU_INIT to flag some capabilities.
> I can't tell if there are other commands that return capabilities as well,
> or if there are other capabilities for TMU_INIT, I don't have access to the
> firmware code.
On Exynos850 I see more than just one returned error codes. I definitely
see 0xfe and 0xfd at least. I don't have any data to confirm that ff
maps to -1 and fd-s, fe-s to -2,-3 though and what they mean. From my
experiments I suspect that 0xfe means that call/msg type is not
implemented or not accessible and 0xfd means that passed parameter is
wrong or incorrect or not found.
I am also not sure that I saw 0xff-s but, well, maybe that needs more
experimenting.
Thanks,
Alexey
^ permalink raw reply
* [PATCH 02/10] dt-bindings: clock: Add Amlogic A9 PLL clock controller
From: Jian Hu via B4 Relay @ 2026-05-11 12:47 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl
Cc: linux-kernel, linux-clk, devicetree, linux-amlogic,
linux-arm-kernel, Jian Hu
In-Reply-To: <20260511-b4-a9_clk-v1-0-41cb4071b7c9@amlogic.com>
From: Jian Hu <jian.hu@amlogic.com>
Add the PLL clock controller dt-bindings for the Amlogic A9 SoC family.
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
.../bindings/clock/amlogic,a9-pll-clkc.yaml | 110 +++++++++++++++++++++
include/dt-bindings/clock/amlogic,a9-pll-clkc.h | 55 +++++++++++
2 files changed, 165 insertions(+)
diff --git a/Documentation/devicetree/bindings/clock/amlogic,a9-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a9-pll-clkc.yaml
new file mode 100644
index 000000000000..4ee6013ba1a1
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a9-pll-clkc.yaml
@@ -0,0 +1,110 @@
+# 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-pll-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic A9 Series PLL 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:
+ enum:
+ - amlogic,a9-gp0-pll
+ - amlogic,a9-hifi0-pll
+ - amlogic,a9-hifi1-pll
+ - amlogic,a9-mclk0-pll
+ - amlogic,a9-mclk1-pll
+
+ reg:
+ maxItems: 1
+
+ '#clock-cells':
+ const: 1
+
+ clocks:
+ items:
+ - description: pll input oscillator gate
+ - description: fixed input clock source for mclk_sel_0
+ - description: u3p2pll input clock source for mclk_sel_0 (optional)
+ minItems: 1
+
+ clock-names:
+ items:
+ - const: in0
+ - const: in1
+ - const: in2
+ minItems: 1
+
+required:
+ - compatible
+ - '#clock-cells'
+ - reg
+ - clocks
+ - clock-names
+
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,a9-mclk0-pll
+ - amlogic,a9-mclk1-pll
+
+ then:
+ properties:
+ clocks:
+ maxItems: 3
+
+ clock-names:
+ maxItems: 3
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - amlogic,a9-gp0-pll
+ - amlogic,a9-hifi0-pll
+ - amlogic,a9-hifi1-pll
+
+ then:
+ properties:
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ maxItems: 1
+
+additionalProperties: false
+
+examples:
+ - |
+ apb4 {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@8200 {
+ compatible = "amlogic,a9-gp0-pll";
+ reg = <0x0 0x8200 0x0 0x20>;
+ #clock-cells = <1>;
+ clocks = <&scmi_clk 0>;
+ clock-names = "in0";
+ };
+
+ clock-controller@8330 {
+ compatible = "amlogic,a9-mclk0-pll";
+ reg = <0x0 0x8330 0x0 0x14>;
+ #clock-cells = <1>;
+ clocks = <&scmi_clk 4>,
+ <&scmi_clk 8>;
+ clock-names = "in0", "in1";
+ };
+ };
diff --git a/include/dt-bindings/clock/amlogic,a9-pll-clkc.h b/include/dt-bindings/clock/amlogic,a9-pll-clkc.h
new file mode 100644
index 000000000000..31edb0bc95e7
--- /dev/null
+++ b/include/dt-bindings/clock/amlogic,a9-pll-clkc.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * Copyright (C) 2026 Amlogic, Inc. All rights reserved.
+ */
+
+#ifndef __AMLOGIC_A9_PLL_CLKC_H
+#define __AMLOGIC_A9_PLL_CLKC_H
+
+/* GP0 */
+#define CLKID_GP0_IN_DIV2_DIV 0
+#define CLKID_GP0_IN_DIV2 1
+#define CLKID_GP0_PLL_DCO 2
+#define CLKID_GP0_PLL 3
+
+/* HIFI0 */
+#define CLKID_HIFI0_IN_DIV2_DIV 0
+#define CLKID_HIFI0_IN_DIV2 1
+#define CLKID_HIFI0_PLL_DCO 2
+#define CLKID_HIFI0_PLL 3
+
+/* HIFI1 */
+#define CLKID_HIFI1_IN_DIV2_DIV 0
+#define CLKID_HIFI1_IN_DIV2 1
+#define CLKID_HIFI1_PLL_DCO 2
+#define CLKID_HIFI1_PLL 3
+
+/* MCLK0 */
+#define CLKID_MCLK0_IN_DIV2 0
+#define CLKID_MCLK0_PLL_DCO 1
+#define CLKID_MCLK0_0_PLL 2
+#define CLKID_MCLK0_0_PRE 3
+#define CLKID_MCLK0_0_SEL 4
+#define CLKID_MCLK0_0_DIV 5
+#define CLKID_MCLK0_0 6
+#define CLKID_MCLK0_1_PLL 7
+#define CLKID_MCLK0_1_PRE 8
+#define CLKID_MCLK0_1_SEL 9
+#define CLKID_MCLK0_1_DIV 10
+#define CLKID_MCLK0_1 11
+
+/* MCLK1 */
+#define CLKID_MCLK1_IN_DIV2 0
+#define CLKID_MCLK1_PLL_DCO 1
+#define CLKID_MCLK1_0_PLL 2
+#define CLKID_MCLK1_0_PRE 3
+#define CLKID_MCLK1_0_SEL 4
+#define CLKID_MCLK1_0_DIV 5
+#define CLKID_MCLK1_0 6
+#define CLKID_MCLK1_1_PLL 7
+#define CLKID_MCLK1_1_PRE 8
+#define CLKID_MCLK1_1_SEL 9
+#define CLKID_MCLK1_1_DIV 10
+#define CLKID_MCLK1_1 11
+
+#endif /* __AMLOGIC_A9_PLL_CLKC_H */
--
2.47.1
^ permalink raw reply related
* Re: [PATCH v4 2/2] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
From: Vladimir Oltean @ 2026-05-11 12:50 UTC (permalink / raw)
To: Josua Mayer
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Shawn Guo,
Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Andrew Lunn, Vladimir Oltean, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Yazan Shhady, Mikhail Anikin,
Alexander Dahl, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org, Conor Dooley,
Krzysztof Kozlowski, netdev@vger.kernel.org
In-Reply-To: <f0fdea25-6b2d-4b64-b925-a3f30c8e044c@solid-run.com>
On Mon, May 11, 2026 at 12:30:35PM +0000, Josua Mayer wrote:
> I had the reverse understanding, the switch port specifies rgmii-id,
> and the cpu port specifies "rgmii".
>
> The switch port has mode rgmii-id, indicating that someone should add delays.
Yes, but my understanding is that it is out of scope for the phy-mode = "rgmii-id"
to decide who. It just means that there are no PCB delays.
> It is a fixed link without PHY, so switch must add the delays.
This is an obsolete interpretation of phy-mode. sja1105_parse_rgmii_delays()
explains that in the new interpretation, 'rgmii' or 'rgmii-id' doesn't
indicate anything. The switch inserts the delays because of the
"rx-internal-delay-ps" and "tx-internal-delay-ps" properties.
> From the cpu (eqos) perspcetive it is also a fixed link without phy,
> so I specify rgmii indicating nobody should add delays.
>
> Is this correct?
My understanding may be wrong, but I directly quote:
- If the PCB does not add these delays via extra long traces,
'rgmii-id' should be used. Here, 'id' refers to 'internal delay',
where either the MAC or PHY adds the delay.
- When the PCB does not implement the delays, the MAC or PHY must.
As such, this is software configuration, and so not described in
Device Tree.
> >
> >> + pinctrl-0 = <&eqos_pins>;
> >> + pinctrl-names = "default";
> >> + status = "okay";
> >> +
> >> + fixed-link {
> >> + full-duplex;
> >> + speed = <1000>;
> >> + };
> >> +};
> >> +
> >> +&lpspi0 {
> >> + cs-gpios = <&lsio_gpio1 8 GPIO_ACTIVE_LOW>, <&lsio_gpio1 7 GPIO_ACTIVE_LOW>;
> >> + pinctrl-0 = <&lpspi0_pins>, <&switch_pins>;
> >> + pinctrl-names = "default";
> >> + status = "okay";
> >> +
> >> + ethernet-switch@0 {
> >> + compatible = "nxp,sja1110a";
> >> + reg = <0>;
> >> + reset-gpios = <&lsio_gpio4 3 GPIO_ACTIVE_LOW>;
> >> + spi-max-frequency = <4000000>;
> >> +
> >> + ethernet-ports {
> >> + #address-cells = <1>;
> >> + #size-cells = <0>;
> >> +
> >> + /* 100Base-TX on connector J26 */
> >> + port@1 {
> > Some people might prefer seeing ethernet-port@N instead of port@N, to
> > fully avoid confusion with dtschema/schemas/graph.yaml (although, the
> > container node being ethernet-ports now, the confusion should be
> > avoidable).
> >
> > Also, if you ever perform device tree fixups from the bootloader (like
> > for setting status = "disabled" to status = "okay" for the ports that go
> > to addon boards), please never hardcode fixup paths,
>
> I was expecting device-tree overlays to be used, in which case aliases
> are not needed.
Ok, what do you need for device tree overlays to reference these nodes?
Don't you need a label for them to appear in /__symbols__? Or do you
reference by "&{/absolute/path}" (still bad)?
> > but always use eth
> > aliases to get to them.
> However if it is okay to add eth[0-9]+ aliases also for switch ports, I'll add them.
Absolutely ok.
> > This is in case the port node names ever change,
> > to avoid bootloader regressions.
> Good point!
I don't think there's any downside to adding aliases, so please do, in
case anyone needs them, they should be there.
^ permalink raw reply
* [PATCH 09/10] clk: amlogic: Add A9 peripherals clock controller driver
From: Jian Hu via B4 Relay @ 2026-05-11 12:47 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl
Cc: linux-kernel, linux-clk, devicetree, linux-amlogic,
linux-arm-kernel, Jian Hu
In-Reply-To: <20260511-b4-a9_clk-v1-0-41cb4071b7c9@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 | 2317 ++++++++++++++++++++++++++++++++++++
3 files changed, 2333 insertions(+)
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index 3549e67d6988..48a15a5e1323 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -145,6 +145,21 @@ config COMMON_CLK_A9_PLL
device, AKA A9. PLLs are required by most peripheral to operate.
Say Y if you want A9 PLL clock controller to work.
+config COMMON_CLK_A9_PERIPHERALS
+ tristate "Amlogic A9 SoC peripherals clock controller support"
+ depends on ARM64
+ 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 77636033061f..2b5b67b14efc 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -20,6 +20,7 @@ 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_PLL) += a9-pll.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..338a91c473ea
--- /dev/null
+++ b/drivers/clk/meson/a9-peripherals.c
@@ -0,0 +1,2317 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2026 Amlogic, Inc. All rights reserved
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/amlogic,a9-peripherals-clkc.h>
+#include "clk-regmap.h"
+#include "clk-dualdiv.h"
+#include "vid-pll-div.h"
+#include "meson-clkc-utils.h"
+
+#define SYS_CLK_EN0_REG0 0x30
+#define SYS_CLK_EN0_REG1 0x34
+#define SYS_CLK_EN0_REG2 0x38
+#define SYS_CLK_EN0_REG3 0x3c
+#define SD_EMMC_CLK_CTRL0 0x90
+#define SD_EMMC_CLK_CTRL1 0x94
+#define PWM_CLK_H_CTRL 0xbc
+#define PWM_CLK_I_CTRL 0xc0
+#define PWM_CLK_J_CTRL 0xc4
+#define PWM_CLK_K_CTRL 0xc8
+#define PWM_CLK_L_CTRL 0xcc
+#define PWM_CLK_M_CTRL 0xd0
+#define PWM_CLK_N_CTRL 0xd4
+#define SPISG_CLK_CTRL 0x100
+#define SPISG_CLK_CTRL1 0x104
+#define SAR_CLK_CTRL 0x150
+#define AMFC_CLK_CTRL 0x154
+#define NNA_CLK_CTRL 0x15c
+#define USB_CLK_CTRL 0x160
+#define PCIE_TL_CLK_CTRL 0x164
+#define CMPR_CLK_CTRL 0x168
+#define DEWARP_CLK_CTRL 0x16c
+#define SC_CLK_CTRL 0x170
+#define DPTX_CLK_CTRL 0x178
+#define ISP_CLK_CTRL 0x17c
+#define CVE_CLK_CTRL 0x180
+#define PP_CLK_CTRL 0x184
+#define GLB_CLK_CTRL 0x188
+#define USB_CLK_CTRL0 0x18c
+#define USB_CLK_CTRL1 0x190
+#define CAN_CLK_CTRL 0x194
+#define CAN_CLK_CTRL1 0x198
+#define I3C_CLK_CTRL 0x19c
+#define TS_CLK_CTRL 0x1a0
+#define ETH_CLK_CTRL 0x1a4
+#define GEN_CLK_CTRL 0x1a8
+#define CLK12_24_CTRL 0x1ac
+#define MALI_CLK_CTRL 0x200
+#define MALI_STACK_CLK_CTRL 0x204
+#define DSPA_CLK_CTRL 0x220
+#define HEVCF_CLK_CTRL 0x240
+#define HCODEC_CLK_CTRL 0x244
+#define VPU_CLK_CTRL 0x260
+#define VAPB_CLK_CTRL 0x268
+#define VPU_CLKB_CTRL 0x280
+#define HDMI_CLK_CTRL 0x284
+#define HTX_CLK_CTRL 0x28c
+#define HTX_CLK_CTRL1 0x290
+#define HRX_CLK_CTRL 0x294
+#define HRX_CLK_CTRL1 0x298
+#define HRX_CLK_CTRL2 0x29c
+#define HRX_CLK_CTRL3 0x2a0
+#define VID_LOCK_CLK_CTRL 0x2a4
+#define VDIN_MEAS_CLK_CTRL 0x2a8
+#define VID_PLL_CLK_DIV 0x2b0
+#define VID_CLK_CTRL 0x2c0
+#define VID_CLK_CTRL2 0x2c4
+#define VID_CLK_DIV 0x2c8
+#define VIID_CLK_DIV 0x2cc
+#define VIID_CLK_CTRL 0x2d0
+#define MIPI_CSI_PHY_CLK_CTRL 0x2e0
+#define DSI_MEAS_CLK_CTRL 0x2f4
+
+#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \
+ MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
+
+#define A9_COMP_DIV(_name, _reg, _shift, _width) \
+ MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
+
+#define A9_COMP_GATE(_name, _reg, _bit, _iflags) \
+ MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
+
+static const struct clk_parent_data a9_sys_pclk_parents = { .fw_name = "sys" };
+
+#define A9_SYS_PCLK(_name, _reg, _bit) \
+ MESON_PCLK(a9_##_name, _reg, _bit, &a9_sys_pclk_parents, 0)
+
+static A9_SYS_PCLK(sys_am_axi, SYS_CLK_EN0_REG0, 0);
+static A9_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1);
+static A9_SYS_PCLK(sys_mipi_dsi, SYS_CLK_EN0_REG0, 3);
+static A9_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG0, 4);
+static A9_SYS_PCLK(sys_amfc, SYS_CLK_EN0_REG0, 5);
+static A9_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6);
+static A9_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 7);
+static A9_SYS_PCLK(sys_eth_axi, SYS_CLK_EN0_REG0, 8);
+static A9_SYS_PCLK(sys_dp_apb, SYS_CLK_EN0_REG0, 9);
+static A9_SYS_PCLK(sys_edptx_apb, SYS_CLK_EN0_REG0, 10);
+static A9_SYS_PCLK(sys_u3hsg, SYS_CLK_EN0_REG0, 11);
+static A9_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14);
+static A9_SYS_PCLK(sys_glb, SYS_CLK_EN0_REG0, 15);
+static A9_SYS_PCLK(sys_combo_dphy_apb, SYS_CLK_EN0_REG0, 17);
+static A9_SYS_PCLK(sys_hdmirx_apb, SYS_CLK_EN0_REG0, 18);
+static A9_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG0, 19);
+static A9_SYS_PCLK(sys_mipi_dsi_phy, SYS_CLK_EN0_REG0, 20);
+static A9_SYS_PCLK(sys_can0, SYS_CLK_EN0_REG0, 21);
+static A9_SYS_PCLK(sys_can1, SYS_CLK_EN0_REG0, 22);
+static A9_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24);
+static A9_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25);
+static A9_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26);
+static A9_SYS_PCLK(sys_sc, SYS_CLK_EN0_REG0, 27);
+static A9_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28);
+static A9_SYS_PCLK(sys_mipi_isp, SYS_CLK_EN0_REG0, 29);
+static A9_SYS_PCLK(sys_msr, SYS_CLK_EN0_REG0, 30);
+static A9_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0);
+static A9_SYS_PCLK(sys_mipi_dsi_b, SYS_CLK_EN0_REG1, 1);
+static A9_SYS_PCLK(sys_mipi_dsi1_phy, SYS_CLK_EN0_REG1, 2);
+static A9_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3);
+static A9_SYS_PCLK(sys_eth_1g_mac, SYS_CLK_EN0_REG1, 4);
+static A9_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5);
+static A9_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10);
+static A9_SYS_PCLK(sys_ts_a55, SYS_CLK_EN0_REG1, 11);
+static A9_SYS_PCLK(sys_eth_1g_axi, SYS_CLK_EN0_REG1, 12);
+static A9_SYS_PCLK(sys_ts_dos, SYS_CLK_EN0_REG1, 13);
+static A9_SYS_PCLK(sys_u3drd_b, SYS_CLK_EN0_REG1, 14);
+static A9_SYS_PCLK(sys_ts_core, SYS_CLK_EN0_REG1, 15);
+static A9_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG1, 16);
+static A9_SYS_PCLK(sys_csi_dig_clkin, SYS_CLK_EN0_REG1, 18);
+static A9_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG1, 19);
+static A9_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 20);
+static A9_SYS_PCLK(sys_spisg, SYS_CLK_EN0_REG1, 21);
+static A9_SYS_PCLK(sys_u3drd_1, SYS_CLK_EN0_REG1, 22);
+static A9_SYS_PCLK(sys_u2h, SYS_CLK_EN0_REG1, 23);
+static A9_SYS_PCLK(sys_pcie_mac_a, SYS_CLK_EN0_REG1, 24);
+static A9_SYS_PCLK(sys_u3drd_a, SYS_CLK_EN0_REG1, 25);
+static A9_SYS_PCLK(sys_u2drd, SYS_CLK_EN0_REG1, 26);
+static A9_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27);
+static A9_SYS_PCLK(sys_pcie_mac_b, SYS_CLK_EN0_REG1, 28);
+static A9_SYS_PCLK(sys_periph, SYS_CLK_EN0_REG1, 29);
+static A9_SYS_PCLK(sys_pio, SYS_CLK_EN0_REG2, 0);
+static A9_SYS_PCLK(sys_i3c, SYS_CLK_EN0_REG2, 1);
+static A9_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2);
+static A9_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3);
+static A9_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4);
+static A9_SYS_PCLK(sys_i2c_m_i, SYS_CLK_EN0_REG2, 5);
+static A9_SYS_PCLK(sys_i2c_m_g, SYS_CLK_EN0_REG2, 6);
+static A9_SYS_PCLK(sys_i2c_m_h, SYS_CLK_EN0_REG2, 7);
+static A9_SYS_PCLK(sys_hdmi20_aes, SYS_CLK_EN0_REG2, 9);
+static A9_SYS_PCLK(sys_csi2_host, SYS_CLK_EN0_REG2, 16);
+static A9_SYS_PCLK(sys_csi2_adapt, SYS_CLK_EN0_REG2, 17);
+static A9_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21);
+static A9_SYS_PCLK(sys_pp_dma, SYS_CLK_EN0_REG2, 22);
+static A9_SYS_PCLK(sys_pp_wrapper, SYS_CLK_EN0_REG2, 23);
+static A9_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25);
+static A9_SYS_PCLK(sys_csi2_phy, SYS_CLK_EN0_REG2, 27);
+static A9_SYS_PCLK(sys_saradc, SYS_CLK_EN0_REG2, 28);
+static A9_SYS_PCLK(sys_pwm_j, SYS_CLK_EN0_REG2, 30);
+static A9_SYS_PCLK(sys_pwm_i, SYS_CLK_EN0_REG2, 31);
+static A9_SYS_PCLK(sys_pwm_h, SYS_CLK_EN0_REG3, 0);
+static A9_SYS_PCLK(sys_pwm_n, SYS_CLK_EN0_REG3, 8);
+static A9_SYS_PCLK(sys_pwm_m, SYS_CLK_EN0_REG3, 9);
+static A9_SYS_PCLK(sys_pwm_l, SYS_CLK_EN0_REG3, 10);
+static A9_SYS_PCLK(sys_pwm_k, SYS_CLK_EN0_REG3, 11);
+
+/* Channel 5 is unconnected. */
+static u32 a9_sd_emmc_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 };
+static const struct clk_parent_data a9_sd_emmc_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "hifi0", },
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "gp1", },
+ { .fw_name = "gp0", }
+};
+
+static A9_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL0, 9, 0x7, a9_sd_emmc_parents,
+ a9_sd_emmc_parents_val_table);
+static A9_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL0, 0, 7);
+static A9_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL0, 8, 0);
+
+static A9_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL0, 25, 0x7, a9_sd_emmc_parents,
+ a9_sd_emmc_parents_val_table);
+static A9_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL0, 16, 7);
+static A9_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL0, 24, 0);
+
+static A9_COMP_SEL(sd_emmc_c, SD_EMMC_CLK_CTRL1, 9, 0x7, a9_sd_emmc_parents,
+ a9_sd_emmc_parents_val_table);
+static A9_COMP_DIV(sd_emmc_c, SD_EMMC_CLK_CTRL1, 0, 7);
+static A9_COMP_GATE(sd_emmc_c, SD_EMMC_CLK_CTRL1, 8, 0);
+
+static const struct clk_parent_data a9_pwm_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv3", }
+};
+
+static A9_COMP_SEL(pwm_h, PWM_CLK_H_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_h, PWM_CLK_H_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_h, PWM_CLK_H_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_i, PWM_CLK_I_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_i, PWM_CLK_I_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_i, PWM_CLK_I_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_j, PWM_CLK_J_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_j, PWM_CLK_J_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_j, PWM_CLK_J_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_k, PWM_CLK_K_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_k, PWM_CLK_K_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_k, PWM_CLK_K_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_l, PWM_CLK_L_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_l, PWM_CLK_L_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_l, PWM_CLK_L_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_m, PWM_CLK_M_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_m, PWM_CLK_M_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_m, PWM_CLK_M_CTRL, 8, 0);
+
+static A9_COMP_SEL(pwm_n, PWM_CLK_N_CTRL, 9, 0x7, a9_pwm_parents, NULL);
+static A9_COMP_DIV(pwm_n, PWM_CLK_N_CTRL, 0, 8);
+static A9_COMP_GATE(pwm_n, PWM_CLK_N_CTRL, 8, 0);
+
+static const struct clk_parent_data a9_spisg_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "sys", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv7", },
+ { .fw_name = "gp0", }
+};
+
+static A9_COMP_SEL(spisg, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL);
+static A9_COMP_DIV(spisg, SPISG_CLK_CTRL, 0, 6);
+static A9_COMP_GATE(spisg, SPISG_CLK_CTRL, 8, 0);
+
+static A9_COMP_SEL(spisg1, SPISG_CLK_CTRL, 25, 0x7, a9_spisg_parents, NULL);
+static A9_COMP_DIV(spisg1, SPISG_CLK_CTRL, 16, 6);
+static A9_COMP_GATE(spisg1, SPISG_CLK_CTRL, 24, 0);
+
+static A9_COMP_SEL(spisg2, SPISG_CLK_CTRL1, 9, 0x7, a9_spisg_parents, NULL);
+static A9_COMP_DIV(spisg2, SPISG_CLK_CTRL1, 0, 6);
+static A9_COMP_GATE(spisg2, SPISG_CLK_CTRL1, 8, 0);
+
+static const struct clk_parent_data a9_saradc_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "sys", }
+};
+
+static A9_COMP_SEL(saradc, SAR_CLK_CTRL, 9, 0x7, a9_saradc_parents, NULL);
+static A9_COMP_DIV(saradc, SAR_CLK_CTRL, 0, 8);
+static A9_COMP_GATE(saradc, SAR_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data a9_amfc_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "sys", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv7", }
+};
+
+static A9_COMP_SEL(amfc, AMFC_CLK_CTRL, 9, 0x7, a9_amfc_parents, NULL);
+static A9_COMP_DIV(amfc, AMFC_CLK_CTRL, 0, 6);
+static A9_COMP_GATE(amfc, AMFC_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data a9_nna_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "gp2", },
+ { .fw_name = "hifi", }
+};
+
+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 = "fdiv4", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv7", },
+ { .fw_name = "fdiv2p5", }
+};
+
+static A9_COMP_SEL(usb_48m_pre, USB_CLK_CTRL, 25, 0x7, a9_usb_48m_pre_parents,
+ NULL);
+static A9_COMP_DIV(usb_48m_pre, USB_CLK_CTRL, 16, 7);
+static A9_COMP_GATE(usb_48m_pre, USB_CLK_CTRL, 24, 0);
+
+static const struct clk_parent_data a9_pcie_tl_parents[] = {
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "gp0", },
+ { .fw_name = "sys", },
+ { .fw_name = "xtal", }
+};
+
+static A9_COMP_SEL(pcie_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents,
+ NULL);
+static A9_COMP_DIV(pcie_tl, PCIE_TL_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(pcie_tl, PCIE_TL_CLK_CTRL, 8, 0);
+
+static A9_COMP_SEL(pcie1_tl, PCIE_TL_CLK_CTRL, 25, 0x7, a9_pcie_tl_parents,
+ NULL);
+static A9_COMP_DIV(pcie1_tl, PCIE_TL_CLK_CTRL, 16, 7);
+static A9_COMP_GATE(pcie1_tl, PCIE_TL_CLK_CTRL, 24, 0);
+
+static const struct clk_parent_data a9_cmpr_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv7", },
+ { .fw_name = "hifi0", },
+ { .fw_name = "gp1", }
+};
+
+static A9_COMP_SEL(cmpr, CMPR_CLK_CTRL, 25, 0x7, a9_cmpr_parents, NULL);
+static A9_COMP_DIV(cmpr, CMPR_CLK_CTRL, 16, 7);
+static A9_COMP_GATE(cmpr, CMPR_CLK_CTRL, 24, 0);
+
+static const struct clk_parent_data a9_dewarpa_parents[] = {
+ { .fw_name = "fdiv2p5", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "fdiv7", },
+ { .fw_name = "gp0", },
+ { .fw_name = "hifi0", },
+ { .fw_name = "gp1", }
+};
+
+static A9_COMP_SEL(dewarpa, DEWARP_CLK_CTRL, 9, 0x7, a9_dewarpa_parents, NULL);
+static A9_COMP_DIV(dewarpa, DEWARP_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(dewarpa, DEWARP_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data a9_sc_parents[] = {
+ { .fw_name = "fdiv2", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv5", },
+ { .fw_name = "xtal", }
+};
+
+static A9_COMP_SEL(sc_pre, SC_CLK_CTRL, 9, 0x7, a9_sc_parents, NULL);
+static A9_COMP_DIV(sc_pre, SC_CLK_CTRL, 0, 8);
+static A9_COMP_GATE(sc_pre, SC_CLK_CTRL, 8, 0);
+
+static struct clk_regmap a9_sc = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = SC_CLK_CTRL,
+ .shift = 16,
+ .width = 4,
+ },
+ .hw.init = &(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);
+
+/* Channel 6 is unconnected. */
+static u32 a9_glb_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 7 };
+static struct clk_regmap a9_dspa;
+
+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,
+ },
+};
+
+static const struct clk_parent_data a9_can_pe_parents[] = {
+ { .fw_name = "sys", },
+ { .fw_name = "xtal", },
+ { .fw_name = "usb2drd", },
+ { .fw_name = "fdiv5", }
+};
+
+static A9_COMP_SEL(can_pe, CAN_CLK_CTRL, 9, 0x7, a9_can_pe_parents, NULL);
+static A9_COMP_DIV(can_pe, CAN_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(can_pe, CAN_CLK_CTRL, 8, 0);
+
+static A9_COMP_SEL(can1_pe, CAN_CLK_CTRL, 25, 0x7, a9_can_pe_parents, NULL);
+static A9_COMP_DIV(can1_pe, CAN_CLK_CTRL, 16, 7);
+static A9_COMP_GATE(can1_pe, CAN_CLK_CTRL, 24, 0);
+
+static const struct clk_parent_data a9_can_filter_parents[] = {
+ { .fw_name = "sys", },
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv5", }
+};
+
+static A9_COMP_SEL(can_filter, CAN_CLK_CTRL1, 9, 0x7, a9_can_filter_parents,
+ NULL);
+static A9_COMP_DIV(can_filter, CAN_CLK_CTRL1, 0, 7);
+static A9_COMP_GATE(can_filter, CAN_CLK_CTRL1, 8, 0);
+
+static A9_COMP_SEL(can1_filter, CAN_CLK_CTRL1, 25, 0x7, a9_can_filter_parents,
+ NULL);
+static A9_COMP_DIV(can1_filter, CAN_CLK_CTRL1, 16, 7);
+static A9_COMP_GATE(can1_filter, CAN_CLK_CTRL1, 24, 0);
+
+static const struct clk_parent_data a9_i3c_parents[] = {
+ { .fw_name = "sys", },
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv5", }
+};
+
+static A9_COMP_SEL(i3c, I3C_CLK_CTRL, 9, 0x7, a9_i3c_parents, NULL);
+static A9_COMP_DIV(i3c, I3C_CLK_CTRL, 0, 8);
+static A9_COMP_GATE(i3c, I3C_CLK_CTRL, 8, 0);
+
+static struct clk_regmap a9_ts_div = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = TS_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(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,
+ * ext_rmii connects external PAD.
+ */
+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 3(ddr_dpll_pt_clk) is manged by the DDR module;
+ * channel 12(msr_clk) is manged by clock measures module.
+ * channel 16(audio_dac1_clk) is manged by audio module.
+ * Channel 10, 11, 13, 14 are not connected.
+ */
+static u32 a9_gen_parents_val_table[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9, 15, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, 26};
+static struct clk_regmap a9_vid_pll;
+
+static const struct clk_parent_data a9_gen_parents[] = {
+ { .fw_name = "xtal" },
+ { .fw_name = "rtc" },
+ { .fw_name = "sysplldiv16" },
+ { .hw = &a9_vid_pll.hw },
+ { .fw_name = "gp0" },
+ { .fw_name = "hifi1" },
+ { .fw_name = "hifi0" },
+ { .fw_name = "gp1" },
+ { .fw_name = "gp2" },
+ { .fw_name = "dsudiv16" },
+ { .fw_name = "cpudiv16" },
+ { .fw_name = "a78div16" },
+ { .fw_name = "fdiv2" },
+ { .fw_name = "fdiv2p5" },
+ { .fw_name = "fdiv3" },
+ { .fw_name = "fdiv4" },
+ { .fw_name = "fdiv5" },
+ { .fw_name = "fdiv7" },
+ { .fw_name = "mclk0" },
+ { .fw_name = "mclk1" }
+};
+
+static A9_COMP_SEL(gen, GEN_CLK_CTRL, 12, 0x1f, a9_gen_parents,
+ a9_gen_parents_val_table);
+static A9_COMP_DIV(gen, GEN_CLK_CTRL, 0, 12);
+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_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,
+ },
+};
+
+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_enc, a9_enc1;
+
+static const struct clk_parent_data a9_vid_lock_parents[] = {
+ { .fw_name = "xtal", },
+ { .hw = &a9_enc.hw },
+ { .hw = &a9_enc1.hw }
+};
+
+static A9_COMP_SEL(vid_lock, VID_LOCK_CLK_CTRL, 9, 0x7, a9_vid_lock_parents,
+ NULL);
+static A9_COMP_DIV(vid_lock, VID_LOCK_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(vid_lock, VID_LOCK_CLK_CTRL, 8, 0);
+
+static const struct clk_parent_data a9_vdin_meas_parents[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fdiv4", },
+ { .fw_name = "fdiv3", },
+ { .fw_name = "fdiv5", }
+};
+
+static A9_COMP_SEL(vdin_meas, VDIN_MEAS_CLK_CTRL, 9, 0x7, a9_vdin_meas_parents,
+ NULL);
+static A9_COMP_DIV(vdin_meas, VDIN_MEAS_CLK_CTRL, 0, 7);
+static A9_COMP_GATE(vdin_meas, VDIN_MEAS_CLK_CTRL, 8, 0);
+
+static struct clk_regmap a9_vid_pll_div = {
+ .data = &(struct meson_vid_pll_div_data){
+ .val = {
+ .reg_off = VID_PLL_CLK_DIV,
+ .shift = 0,
+ .width = 15,
+ },
+ .sel = {
+ .reg_off = VID_PLL_CLK_DIV,
+ .shift = 16,
+ .width = 2,
+ },
+ },
+ .hw.init = &(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_vclk_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = VID_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 16,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = a9_vclk_parents,
+ .num_parents = ARRAY_SIZE(a9_vclk_parents),
+ },
+};
+
+static struct clk_regmap a9_vclk_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_DIV,
+ .bit_idx = 16,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk_sel.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = VID_CLK_DIV,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk_in.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 19,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div1_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_div1_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div2_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_div2_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_div2",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk_div2_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div4_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 2,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_div4_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk_div4 = {
+ .mult = 1,
+ .div = 4,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_div4",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk_div4_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div6_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 3,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_div6_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk_div6 = {
+ .mult = 1,
+ .div = 6,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_div6",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk_div6_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk_div12_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL,
+ .bit_idx = 4,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk_div12_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk_div12 = {
+ .mult = 1,
+ .div = 12,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk_div12",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk_div12_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = VIID_CLK_CTRL,
+ .mask = 0x7,
+ .shift = 16,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = a9_vclk_parents,
+ .num_parents = ARRAY_SIZE(a9_vclk_parents),
+ },
+};
+
+static struct clk_regmap a9_vclk2_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_DIV,
+ .bit_idx = 16,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2_sel.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = VIID_CLK_DIV,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk2_in.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 19,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2_div.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div1_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_div1_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div2_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_div2_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk2_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_div2",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk2_div2_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div4_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 2,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_div4_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk2_div4 = {
+ .mult = 1,
+ .div = 4,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_div4",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk2_div4_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div6_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 3,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_div6_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk2_div6 = {
+ .mult = 1,
+ .div = 6,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_div6",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk2_div6_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_vclk2_div12_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VIID_CLK_CTRL,
+ .bit_idx = 4,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "vclk2_div12_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) { &a9_vclk2.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_vclk2_div12 = {
+ .mult = 1,
+ .div = 12,
+ .hw.init = &(struct clk_init_data){
+ .name = "vclk2_div12",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_vclk2_div12_en.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/* Channel 5, 6 and 7 are unconnected */
+static u32 a9_vid_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
+static const struct clk_hw *a9_vid_parents[] = {
+ &a9_vclk_div1_en.hw,
+ &a9_vclk_div2.hw,
+ &a9_vclk_div4.hw,
+ &a9_vclk_div6.hw,
+ &a9_vclk_div12.hw,
+ &a9_vclk2_div1_en.hw,
+ &a9_vclk2_div2.hw,
+ &a9_vclk2_div4.hw,
+ &a9_vclk2_div6.hw,
+ &a9_vclk2_div12.hw
+};
+
+static struct clk_regmap a9_vdac_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = VIID_CLK_DIV,
+ .mask = 0xf,
+ .shift = 28,
+ .table = a9_vid_parents_val_table,
+ },
+ .hw.init = &(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_enc_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 = "enc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = a9_vid_parents,
+ .num_parents = ARRAY_SIZE(a9_vid_parents),
+ },
+};
+
+static struct clk_regmap a9_enc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL2,
+ .bit_idx = 10,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "enc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_enc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap a9_enc1_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = VIID_CLK_DIV,
+ .mask = 0xf,
+ .shift = 8,
+ .table = a9_vid_parents_val_table,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "enc1_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = a9_vid_parents,
+ .num_parents = ARRAY_SIZE(a9_vid_parents),
+ },
+};
+
+static struct clk_regmap a9_enc1 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = VID_CLK_CTRL2,
+ .bit_idx = 11,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "enc1",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_enc1_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_SPISG_SEL] = &a9_spisg_sel.hw,
+ [CLKID_SPISG_DIV] = &a9_spisg_div.hw,
+ [CLKID_SPISG] = &a9_spisg.hw,
+ [CLKID_SPISG1_SEL] = &a9_spisg1_sel.hw,
+ [CLKID_SPISG1_DIV] = &a9_spisg1_div.hw,
+ [CLKID_SPISG1] = &a9_spisg1.hw,
+ [CLKID_SPISG2_SEL] = &a9_spisg2_sel.hw,
+ [CLKID_SPISG2_DIV] = &a9_spisg2_div.hw,
+ [CLKID_SPISG2] = &a9_spisg2.hw,
+ [CLKID_SARADC_SEL] = &a9_saradc_sel.hw,
+ [CLKID_SARADC_DIV] = &a9_saradc_div.hw,
+ [CLKID_SARADC] = &a9_saradc.hw,
+ [CLKID_AMFC_SEL] = &a9_amfc_sel.hw,
+ [CLKID_AMFC_DIV] = &a9_amfc_div.hw,
+ [CLKID_AMFC] = &a9_amfc.hw,
+ [CLKID_NNA_SEL] = &a9_nna_sel.hw,
+ [CLKID_NNA_DIV] = &a9_nna_div.hw,
+ [CLKID_NNA] = &a9_nna.hw,
+ [CLKID_USB_250M_SEL] = &a9_usb_250m_sel.hw,
+ [CLKID_USB_250M_DIV] = &a9_usb_250m_div.hw,
+ [CLKID_USB_250M] = &a9_usb_250m.hw,
+ [CLKID_USB_48M_PRE_SEL] = &a9_usb_48m_pre_sel.hw,
+ [CLKID_USB_48M_PRE_DIV] = &a9_usb_48m_pre_div.hw,
+ [CLKID_USB_48M_PRE] = &a9_usb_48m_pre.hw,
+ [CLKID_PCIE_TL_SEL] = &a9_pcie_tl_sel.hw,
+ [CLKID_PCIE_TL_DIV] = &a9_pcie_tl_div.hw,
+ [CLKID_PCIE_TL] = &a9_pcie_tl.hw,
+ [CLKID_PCIE1_TL_SEL] = &a9_pcie1_tl_sel.hw,
+ [CLKID_PCIE1_TL_DIV] = &a9_pcie1_tl_div.hw,
+ [CLKID_PCIE1_TL] = &a9_pcie1_tl.hw,
+ [CLKID_CMPR_SEL] = &a9_cmpr_sel.hw,
+ [CLKID_CMPR_DIV] = &a9_cmpr_div.hw,
+ [CLKID_CMPR] = &a9_cmpr.hw,
+ [CLKID_DEWARPA_SEL] = &a9_dewarpa_sel.hw,
+ [CLKID_DEWARPA_DIV] = &a9_dewarpa_div.hw,
+ [CLKID_DEWARPA] = &a9_dewarpa.hw,
+ [CLKID_SC_PRE_SEL] = &a9_sc_pre_sel.hw,
+ [CLKID_SC_PRE_DIV] = &a9_sc_pre_div.hw,
+ [CLKID_SC_PRE] = &a9_sc_pre.hw,
+ [CLKID_SC] = &a9_sc.hw,
+ [CLKID_DPTX_APB2_SEL] = &a9_dptx_apb2_sel.hw,
+ [CLKID_DPTX_APB2_DIV] = &a9_dptx_apb2_div.hw,
+ [CLKID_DPTX_APB2] = &a9_dptx_apb2.hw,
+ [CLKID_DPTX_AUD_SEL] = &a9_dptx_aud_sel.hw,
+ [CLKID_DPTX_AUD_DIV] = &a9_dptx_aud_div.hw,
+ [CLKID_DPTX_AUD] = &a9_dptx_aud.hw,
+ [CLKID_ISP_SEL] = &a9_isp_sel.hw,
+ [CLKID_ISP_DIV] = &a9_isp_div.hw,
+ [CLKID_ISP] = &a9_isp.hw,
+ [CLKID_CVE_SEL] = &a9_cve_sel.hw,
+ [CLKID_CVE_DIV] = &a9_cve_div.hw,
+ [CLKID_CVE] = &a9_cve.hw,
+ [CLKID_VGE_SEL] = &a9_vge_sel.hw,
+ [CLKID_VGE_DIV] = &a9_vge_div.hw,
+ [CLKID_VGE] = &a9_vge.hw,
+ [CLKID_PP_SEL] = &a9_pp_sel.hw,
+ [CLKID_PP_DIV] = &a9_pp_div.hw,
+ [CLKID_PP] = &a9_pp.hw,
+ [CLKID_GLB_SEL] = &a9_glb_sel.hw,
+ [CLKID_GLB_DIV] = &a9_glb_div.hw,
+ [CLKID_GLB] = &a9_glb.hw,
+ [CLKID_USB_48M_DUALDIV_IN] = &a9_usb_48m_dualdiv_in.hw,
+ [CLKID_USB_48M_DUALDIV_DIV] = &a9_usb_48m_dualdiv_div.hw,
+ [CLKID_USB_48M_DUALDIV_SEL] = &a9_usb_48m_dualdiv_sel.hw,
+ [CLKID_USB_48M_DUALDIV] = &a9_usb_48m_dualdiv.hw,
+ [CLKID_USB_48M] = &a9_usb_48m.hw,
+ [CLKID_CAN_PE_SEL] = &a9_can_pe_sel.hw,
+ [CLKID_CAN_PE_DIV] = &a9_can_pe_div.hw,
+ [CLKID_CAN_PE] = &a9_can_pe.hw,
+ [CLKID_CAN1_PE_SEL] = &a9_can1_pe_sel.hw,
+ [CLKID_CAN1_PE_DIV] = &a9_can1_pe_div.hw,
+ [CLKID_CAN1_PE] = &a9_can1_pe.hw,
+ [CLKID_CAN_FILTER_SEL] = &a9_can_filter_sel.hw,
+ [CLKID_CAN_FILTER_DIV] = &a9_can_filter_div.hw,
+ [CLKID_CAN_FILTER] = &a9_can_filter.hw,
+ [CLKID_CAN1_FILTER_SEL] = &a9_can1_filter_sel.hw,
+ [CLKID_CAN1_FILTER_DIV] = &a9_can1_filter_div.hw,
+ [CLKID_CAN1_FILTER] = &a9_can1_filter.hw,
+ [CLKID_I3C_SEL] = &a9_i3c_sel.hw,
+ [CLKID_I3C_DIV] = &a9_i3c_div.hw,
+ [CLKID_I3C] = &a9_i3c.hw,
+ [CLKID_TS_DIV] = &a9_ts_div.hw,
+ [CLKID_TS] = &a9_ts.hw,
+ [CLKID_ETH_125M_DIV] = &a9_eth_125m_div.hw,
+ [CLKID_ETH_125M] = &a9_eth_125m.hw,
+ [CLKID_ETH_RMII_SEL] = &a9_eth_rmii_sel.hw,
+ [CLKID_ETH_RMII_DIV] = &a9_eth_rmii_div.hw,
+ [CLKID_ETH_RMII] = &a9_eth_rmii.hw,
+ [CLKID_GEN_SEL] = &a9_gen_sel.hw,
+ [CLKID_GEN_DIV] = &a9_gen_div.hw,
+ [CLKID_GEN] = &a9_gen.hw,
+ [CLKID_CLK24M_IN] = &a9_24m_in.hw,
+ [CLKID_CLK12_24M] = &a9_12_24m.hw,
+ [CLKID_MALI_0_SEL] = &a9_mali_0_sel.hw,
+ [CLKID_MALI_0_DIV] = &a9_mali_0_div.hw,
+ [CLKID_MALI_0] = &a9_mali_0.hw,
+ [CLKID_MALI_1_SEL] = &a9_mali_1_sel.hw,
+ [CLKID_MALI_1_DIV] = &a9_mali_1_div.hw,
+ [CLKID_MALI_1] = &a9_mali_1.hw,
+ [CLKID_MALI] = &a9_mali.hw,
+ [CLKID_MALI_STACK_0_SEL] = &a9_mali_stack_0_sel.hw,
+ [CLKID_MALI_STACK_0_DIV] = &a9_mali_stack_0_div.hw,
+ [CLKID_MALI_STACK_0] = &a9_mali_stack_0.hw,
+ [CLKID_MALI_STACK_1_SEL] = &a9_mali_stack_1_sel.hw,
+ [CLKID_MALI_STACK_1_DIV] = &a9_mali_stack_1_div.hw,
+ [CLKID_MALI_STACK_1] = &a9_mali_stack_1.hw,
+ [CLKID_MALI_STACK] = &a9_mali_stack.hw,
+ [CLKID_DSPA_0_SEL] = &a9_dspa_0_sel.hw,
+ [CLKID_DSPA_0_DIV] = &a9_dspa_0_div.hw,
+ [CLKID_DSPA_0] = &a9_dspa_0.hw,
+ [CLKID_DSPA_1_SEL] = &a9_dspa_1_sel.hw,
+ [CLKID_DSPA_1_DIV] = &a9_dspa_1_div.hw,
+ [CLKID_DSPA_1] = &a9_dspa_1.hw,
+ [CLKID_DSPA] = &a9_dspa.hw,
+ [CLKID_HEVCF_0_SEL] = &a9_hevcf_0_sel.hw,
+ [CLKID_HEVCF_0_DIV] = &a9_hevcf_0_div.hw,
+ [CLKID_HEVCF_0] = &a9_hevcf_0.hw,
+ [CLKID_HEVCF_1_SEL] = &a9_hevcf_1_sel.hw,
+ [CLKID_HEVCF_1_DIV] = &a9_hevcf_1_div.hw,
+ [CLKID_HEVCF_1] = &a9_hevcf_1.hw,
+ [CLKID_HEVCF] = &a9_hevcf.hw,
+ [CLKID_HCODEC_0_SEL] = &a9_hcodec_0_sel.hw,
+ [CLKID_HCODEC_0_DIV] = &a9_hcodec_0_div.hw,
+ [CLKID_HCODEC_0] = &a9_hcodec_0.hw,
+ [CLKID_HCODEC_1_SEL] = &a9_hcodec_1_sel.hw,
+ [CLKID_HCODEC_1_DIV] = &a9_hcodec_1_div.hw,
+ [CLKID_HCODEC_1] = &a9_hcodec_1.hw,
+ [CLKID_HCODEC] = &a9_hcodec.hw,
+ [CLKID_VPU_0_SEL] = &a9_vpu_0_sel.hw,
+ [CLKID_VPU_0_DIV] = &a9_vpu_0_div.hw,
+ [CLKID_VPU_0] = &a9_vpu_0.hw,
+ [CLKID_VPU_1_SEL] = &a9_vpu_1_sel.hw,
+ [CLKID_VPU_1_DIV] = &a9_vpu_1_div.hw,
+ [CLKID_VPU_1] = &a9_vpu_1.hw,
+ [CLKID_VPU] = &a9_vpu.hw,
+ [CLKID_VAPB_0_SEL] = &a9_vapb_0_sel.hw,
+ [CLKID_VAPB_0_DIV] = &a9_vapb_0_div.hw,
+ [CLKID_VAPB_0] = &a9_vapb_0.hw,
+ [CLKID_VAPB_1_SEL] = &a9_vapb_1_sel.hw,
+ [CLKID_VAPB_1_DIV] = &a9_vapb_1_div.hw,
+ [CLKID_VAPB_1] = &a9_vapb_1.hw,
+ [CLKID_VAPB] = &a9_vapb.hw,
+ [CLKID_GE2D] = &a9_ge2d.hw,
+ [CLKID_VPU_CLKB_TMP_SEL] = &a9_vpu_clkb_tmp_sel.hw,
+ [CLKID_VPU_CLKB_TMP_DIV] = &a9_vpu_clkb_tmp_div.hw,
+ [CLKID_VPU_CLKB_TMP] = &a9_vpu_clkb_tmp.hw,
+ [CLKID_VPU_CLKB_DIV] = &a9_vpu_clkb_div.hw,
+ [CLKID_VPU_CLKB] = &a9_vpu_clkb.hw,
+ [CLKID_HDMITX_SYS_SEL] = &a9_hdmitx_sys_sel.hw,
+ [CLKID_HDMITX_SYS_DIV] = &a9_hdmitx_sys_div.hw,
+ [CLKID_HDMITX_SYS] = &a9_hdmitx_sys.hw,
+ [CLKID_HDMITX_PRIF_SEL] = &a9_hdmitx_prif_sel.hw,
+ [CLKID_HDMITX_PRIF_DIV] = &a9_hdmitx_prif_div.hw,
+ [CLKID_HDMITX_PRIF] = &a9_hdmitx_prif.hw,
+ [CLKID_HDMITX_200M_SEL] = &a9_hdmitx_200m_sel.hw,
+ [CLKID_HDMITX_200M_DIV] = &a9_hdmitx_200m_div.hw,
+ [CLKID_HDMITX_200M] = &a9_hdmitx_200m.hw,
+ [CLKID_HDMITX_AUD_SEL] = &a9_hdmitx_aud_sel.hw,
+ [CLKID_HDMITX_AUD_DIV] = &a9_hdmitx_aud_div.hw,
+ [CLKID_HDMITX_AUD] = &a9_hdmitx_aud.hw,
+ [CLKID_HDMIRX_5M_SEL] = &a9_hdmirx_5m_sel.hw,
+ [CLKID_HDMIRX_5M_DIV] = &a9_hdmirx_5m_div.hw,
+ [CLKID_HDMIRX_5M] = &a9_hdmirx_5m.hw,
+ [CLKID_HDMIRX_2M_SEL] = &a9_hdmirx_2m_sel.hw,
+ [CLKID_HDMIRX_2M_DIV] = &a9_hdmirx_2m_div.hw,
+ [CLKID_HDMIRX_2M] = &a9_hdmirx_2m.hw,
+ [CLKID_HDMIRX_CFG_SEL] = &a9_hdmirx_cfg_sel.hw,
+ [CLKID_HDMIRX_CFG_DIV] = &a9_hdmirx_cfg_div.hw,
+ [CLKID_HDMIRX_CFG] = &a9_hdmirx_cfg.hw,
+ [CLKID_HDMIRX_HDCP2X_SEL] = &a9_hdmirx_hdcp2x_sel.hw,
+ [CLKID_HDMIRX_HDCP2X_DIV] = &a9_hdmirx_hdcp2x_div.hw,
+ [CLKID_HDMIRX_HDCP2X] = &a9_hdmirx_hdcp2x.hw,
+ [CLKID_HDMIRX_ACR_REF_SEL] = &a9_hdmirx_acr_ref_sel.hw,
+ [CLKID_HDMIRX_ACR_REF_DIV] = &a9_hdmirx_acr_ref_div.hw,
+ [CLKID_HDMIRX_ACR_REF] = &a9_hdmirx_acr_ref.hw,
+ [CLKID_HDMIRX_METER_SEL] = &a9_hdmirx_meter_sel.hw,
+ [CLKID_HDMIRX_METER_DIV] = &a9_hdmirx_meter_div.hw,
+ [CLKID_HDMIRX_METER] = &a9_hdmirx_meter.hw,
+ [CLKID_VID_LOCK_SEL] = &a9_vid_lock_sel.hw,
+ [CLKID_VID_LOCK_DIV] = &a9_vid_lock_div.hw,
+ [CLKID_VID_LOCK] = &a9_vid_lock.hw,
+ [CLKID_VDIN_MEAS_SEL] = &a9_vdin_meas_sel.hw,
+ [CLKID_VDIN_MEAS_DIV] = &a9_vdin_meas_div.hw,
+ [CLKID_VDIN_MEAS] = &a9_vdin_meas.hw,
+ [CLKID_VID_PLL_DIV] = &a9_vid_pll_div.hw,
+ [CLKID_VID_PLL_SEL] = &a9_vid_pll_sel.hw,
+ [CLKID_VID_PLL] = &a9_vid_pll.hw,
+ [CLKID_VID_PLL_VCLK] = &a9_vid_pll_vclk.hw,
+ [CLKID_VCLK_SEL] = &a9_vclk_sel.hw,
+ [CLKID_VCLK_IN] = &a9_vclk_in.hw,
+ [CLKID_VCLK_DIV] = &a9_vclk_div.hw,
+ [CLKID_VCLK] = &a9_vclk.hw,
+ [CLKID_VCLK_DIV1_EN] = &a9_vclk_div1_en.hw,
+ [CLKID_VCLK_DIV2_EN] = &a9_vclk_div2_en.hw,
+ [CLKID_VCLK_DIV2] = &a9_vclk_div2.hw,
+ [CLKID_VCLK_DIV4_EN] = &a9_vclk_div4_en.hw,
+ [CLKID_VCLK_DIV4] = &a9_vclk_div4.hw,
+ [CLKID_VCLK_DIV6_EN] = &a9_vclk_div6_en.hw,
+ [CLKID_VCLK_DIV6] = &a9_vclk_div6.hw,
+ [CLKID_VCLK_DIV12_EN] = &a9_vclk_div12_en.hw,
+ [CLKID_VCLK_DIV12] = &a9_vclk_div12.hw,
+ [CLKID_VCLK2_SEL] = &a9_vclk2_sel.hw,
+ [CLKID_VCLK2_IN] = &a9_vclk2_in.hw,
+ [CLKID_VCLK2_DIV] = &a9_vclk2_div.hw,
+ [CLKID_VCLK2] = &a9_vclk2.hw,
+ [CLKID_VCLK2_DIV1_EN] = &a9_vclk2_div1_en.hw,
+ [CLKID_VCLK2_DIV2_EN] = &a9_vclk2_div2_en.hw,
+ [CLKID_VCLK2_DIV2] = &a9_vclk2_div2.hw,
+ [CLKID_VCLK2_DIV4_EN] = &a9_vclk2_div4_en.hw,
+ [CLKID_VCLK2_DIV4] = &a9_vclk2_div4.hw,
+ [CLKID_VCLK2_DIV6_EN] = &a9_vclk2_div6_en.hw,
+ [CLKID_VCLK2_DIV6] = &a9_vclk2_div6.hw,
+ [CLKID_VCLK2_DIV12_EN] = &a9_vclk2_div12_en.hw,
+ [CLKID_VCLK2_DIV12] = &a9_vclk2_div12.hw,
+ [CLKID_VDAC_SEL] = &a9_vdac_sel.hw,
+ [CLKID_VDAC] = &a9_vdac.hw,
+ [CLKID_ENC_SEL] = &a9_enc_sel.hw,
+ [CLKID_ENC] = &a9_enc.hw,
+ [CLKID_ENC1_SEL] = &a9_enc1_sel.hw,
+ [CLKID_ENC1] = &a9_enc1.hw,
+ [CLKID_HDMITX_PIXEL_SEL] = &a9_hdmitx_pixel_sel.hw,
+ [CLKID_HDMITX_PIXEL] = &a9_hdmitx_pixel.hw,
+ [CLKID_HDMITX_FE_SEL] = &a9_hdmitx_fe_sel.hw,
+ [CLKID_HDMITX_FE] = &a9_hdmitx_fe.hw,
+ [CLKID_HDMITX1_PIXEL_SEL] = &a9_hdmitx1_pixel_sel.hw,
+ [CLKID_HDMITX1_PIXEL] = &a9_hdmitx1_pixel.hw,
+ [CLKID_HDMITX1_FE_SEL] = &a9_hdmitx1_fe_sel.hw,
+ [CLKID_HDMITX1_FE] = &a9_hdmitx1_fe.hw,
+ [CLKID_CSI_PHY_SEL] = &a9_csi_phy_sel.hw,
+ [CLKID_CSI_PHY_DIV] = &a9_csi_phy_div.hw,
+ [CLKID_CSI_PHY] = &a9_csi_phy.hw,
+ [CLKID_DSI_MEAS_SEL] = &a9_dsi_meas_sel.hw,
+ [CLKID_DSI_MEAS_DIV] = &a9_dsi_meas_div.hw,
+ [CLKID_DSI_MEAS] = &a9_dsi_meas.hw,
+ [CLKID_DSI_B_MEAS_SEL] = &a9_dsi_b_meas_sel.hw,
+ [CLKID_DSI_B_MEAS_DIV] = &a9_dsi_b_meas_div.hw,
+ [CLKID_DSI_B_MEAS] = &a9_dsi_b_meas.hw,
+};
+
+static const struct meson_clkc_data a9_peripherals_clkc_data = {
+ .hw_clks = {
+ .hws = a9_peripherals_hw_clks,
+ .num = ARRAY_SIZE(a9_peripherals_hw_clks),
+ },
+};
+
+static const struct of_device_id a9_peripherals_clkc_match_table[] = {
+ {
+ .compatible = "amlogic,a9-peripherals-clkc",
+ .data = &a9_peripherals_clkc_data,
+ },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, a9_peripherals_clkc_match_table);
+
+static struct platform_driver a9_peripherals_clkc_driver = {
+ .probe = meson_clkc_mmio_probe,
+ .driver = {
+ .name = "a9-peripherals-clkc",
+ .of_match_table = a9_peripherals_clkc_match_table,
+ },
+};
+module_platform_driver(a9_peripherals_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic A9 Peripherals Clock Controller driver");
+MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("CLK_MESON");
--
2.47.1
^ permalink raw reply related
* [PATCH 08/10] clk: amlogic: Add A9 PLL clock controller driver
From: Jian Hu via B4 Relay @ 2026-05-11 12:47 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl
Cc: linux-kernel, linux-clk, devicetree, linux-amlogic,
linux-arm-kernel, Jian Hu
In-Reply-To: <20260511-b4-a9_clk-v1-0-41cb4071b7c9@amlogic.com>
From: Jian Hu <jian.hu@amlogic.com>
Add the PLL 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-pll.c | 831 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 845 insertions(+)
diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index cf8cf3f9e4ee..3549e67d6988 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_PLL
+ tristate "Amlogic A9 SoC PLL controller support"
+ depends on ARM64
+ default ARCH_MESON
+ select COMMON_CLK_MESON_REGMAP
+ select COMMON_CLK_MESON_CLKC_UTILS
+ select COMMON_CLK_MESON_PLL
+ imply COMMON_CLK_SCMI
+ help
+ Support for the PLL clock controller on Amlogic A311Y3 based
+ device, AKA A9. PLLs are required by most peripheral to operate.
+ Say Y if you want A9 PLL 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..77636033061f 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_PLL) += a9-pll.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-pll.c b/drivers/clk/meson/a9-pll.c
new file mode 100644
index 000000000000..84b591c3afff
--- /dev/null
+++ b/drivers/clk/meson/a9-pll.c
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
+/*
+ * Copyright (C) 2026 Amlogic, Inc. All rights reserved
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/clock/amlogic,a9-pll-clkc.h>
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "meson-clkc-utils.h"
+
+#define GP0PLL_CTRL0 0x00
+#define GP0PLL_CTRL1 0x04
+#define GP0PLL_CTRL2 0x08
+#define GP0PLL_CTRL3 0x0c
+#define GP0PLL_CTRL4 0x10
+
+/* HIFI0 and HIFI1 share the same IP and register offset layout. */
+#define HIFIPLL_CTRL0 0x00
+#define HIFIPLL_CTRL1 0x04
+#define HIFIPLL_CTRL2 0x08
+#define HIFIPLL_CTRL3 0x0c
+#define HIFIPLL_CTRL4 0x10
+
+/* MCLK0 and MCLK1 share the same IP and register offset layout. */
+#define MCLKPLL_CTRL0 0x00
+#define MCLKPLL_CTRL1 0x04
+#define MCLKPLL_CTRL2 0x08
+#define MCLKPLL_CTRL3 0x0c
+#define MCLKPLL_CTRL4 0x10
+
+#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
+ MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, NULL, 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) \
+ MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
+
+/*
+ * Compared with previous SoC PLLs, the A9 PLL input path has an inherent
+ * 2-divider. The N pre-divider follows the same calculation rule as OD,
+ * where the pre-divider ratio equals 2^N.
+ *
+ * A9 PLL is composed as follows:
+ *
+ * PLL
+ * +---------------------------------+
+ * | |
+ * | +--+ |
+ * in/2 >>---[ /2^N ]-->| | +-----+ |
+ * | | |------| DCO |----->> out
+ * | +--------->| | +--v--+ |
+ * | | +--+ | |
+ * | | | |
+ * | +--[ *(M + (F/Fmax) ]<--+ |
+ * | |
+ * +---------------------------------+
+ *
+ * out = in / 2 * (m + frac / frac_max) / 2^n
+ */
+
+static struct clk_fixed_factor a9_gp0_in_div2_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "gp0_in_div2_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "in0",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_gp0_in_div2 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = GP0PLL_CTRL0,
+ .bit_idx = 27,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gp0_in_div2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_gp0_in_div2_div.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+/* The output frequency range of the A9 PLL_DCO is 1.4 GHz to 2.8 GHz. */
+static const struct pll_mult_range a9_pll_mult_range = {
+ .min = 117,
+ .max = 233,
+};
+
+static const struct reg_sequence a9_gp0_pll_init_regs[] = {
+ { .reg = GP0PLL_CTRL0, .def = 0x00010000 },
+ { .reg = GP0PLL_CTRL1, .def = 0x11480000 },
+ { .reg = GP0PLL_CTRL2, .def = 0x1219b010 },
+ { .reg = GP0PLL_CTRL3, .def = 0x00008010 }
+};
+
+static struct clk_regmap a9_gp0_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 0,
+ .width = 9,
+ },
+ .n = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 12,
+ .width = 3,
+ },
+ .frac = {
+ .reg_off = GP0PLL_CTRL1,
+ .shift = 0,
+ .width = 17,
+ },
+ .l = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = GP0PLL_CTRL0,
+ .shift = 30,
+ .width = 1,
+ },
+ .range = &a9_pll_mult_range,
+ .init_regs = a9_gp0_pll_init_regs,
+ .init_count = ARRAY_SIZE(a9_gp0_pll_init_regs),
+ .flags = CLK_MESON_PLL_RST_ACTIVE_LOW |
+ CLK_MESON_PLL_N_POWER_OF_TWO |
+ CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gp0_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_gp0_in_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+/* For gp0, hifi and mclk pll, the maximum value of od is 4. */
+static const struct clk_div_table a9_pll_od_table[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 4, 16 },
+ { /* sentinel */ }
+};
+
+static struct clk_regmap a9_gp0_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = GP0PLL_CTRL0,
+ .shift = 20,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gp0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_gp0_pll_dco.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_hifi0_in_div2_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "hifi0_in_div2_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "in0",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_hifi0_in_div2 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = HIFIPLL_CTRL0,
+ .bit_idx = 27,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi0_in_div2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi0_in_div2_div.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct reg_sequence a9_hifi0_pll_init_regs[] = {
+ { .reg = HIFIPLL_CTRL0, .def = 0x00010000 },
+ { .reg = HIFIPLL_CTRL1, .def = 0x11480000 },
+ { .reg = HIFIPLL_CTRL2, .def = 0x1219b010 },
+ { .reg = HIFIPLL_CTRL3, .def = 0x00008010 }
+};
+
+static struct clk_regmap a9_hifi0_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 0,
+ .width = 9,
+ },
+ .n = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 12,
+ .width = 3,
+ },
+ .frac = {
+ .reg_off = HIFIPLL_CTRL1,
+ .shift = 0,
+ .width = 17,
+ },
+ .l = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 30,
+ .width = 1,
+ },
+ .range = &a9_pll_mult_range,
+ .init_regs = a9_hifi0_pll_init_regs,
+ .init_count = ARRAY_SIZE(a9_hifi0_pll_init_regs),
+ .frac_max = 100000,
+ .flags = CLK_MESON_PLL_RST_ACTIVE_LOW |
+ CLK_MESON_PLL_N_POWER_OF_TWO |
+ CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi0_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi0_in_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_hifi0_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = HIFIPLL_CTRL0,
+ .shift = 20,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi0_pll_dco.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_fixed_factor a9_hifi1_in_div2_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "hifi1_in_div2_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "in0",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_hifi1_in_div2 = {
+ .data = &(struct clk_regmap_gate_data) {
+ .offset = HIFIPLL_CTRL0,
+ .bit_idx = 27,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi1_in_div2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi1_in_div2_div.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct reg_sequence a9_hifi1_pll_init_regs[] = {
+ { .reg = HIFIPLL_CTRL0, .def = 0x00010000 },
+ { .reg = HIFIPLL_CTRL1, .def = 0x11480000 },
+ { .reg = HIFIPLL_CTRL2, .def = 0x1219b011 },
+ { .reg = HIFIPLL_CTRL3, .def = 0x00008010 }
+};
+
+static struct clk_regmap a9_hifi1_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 0,
+ .width = 9,
+ },
+ .n = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 12,
+ .width = 3,
+ },
+ .frac = {
+ .reg_off = HIFIPLL_CTRL1,
+ .shift = 0,
+ .width = 17,
+ },
+ .l = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = HIFIPLL_CTRL0,
+ .shift = 30,
+ .width = 1,
+ },
+ .range = &a9_pll_mult_range,
+ .init_regs = a9_hifi1_pll_init_regs,
+ .init_count = ARRAY_SIZE(a9_hifi1_pll_init_regs),
+ .frac_max = 100000,
+ .flags = CLK_MESON_PLL_RST_ACTIVE_LOW |
+ CLK_MESON_PLL_N_POWER_OF_TWO |
+ CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi1_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi1_in_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_hifi1_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = HIFIPLL_CTRL0,
+ .shift = 20,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifi1_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_hifi1_pll_dco.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/*
+ * Unlike GP0 and HIFI PLLs, the input divider 2 of MCLK PLL is
+ * enabled by default and has no enable control bit.
+ */
+static struct clk_fixed_factor a9_mclk0_in_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "mclk0_in_div2_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "in0",
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct reg_sequence a9_mclk0_pll_init_regs[] = {
+ { .reg = MCLKPLL_CTRL1, .def = 0x00422000 },
+ { .reg = MCLKPLL_CTRL2, .def = 0x60000100 },
+ { .reg = MCLKPLL_CTRL3, .def = 0x02000200 },
+ { .reg = MCLKPLL_CTRL4, .def = 0xd616d616 }
+};
+
+static struct clk_regmap a9_mclk0_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 0,
+ .width = 9,
+ },
+ .n = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 12,
+ .width = 3,
+ },
+ .l = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 30,
+ .width = 1,
+ },
+ .range = &a9_pll_mult_range,
+ .init_regs = a9_mclk0_pll_init_regs,
+ .init_count = ARRAY_SIZE(a9_mclk0_pll_init_regs),
+ .flags = CLK_MESON_PLL_RST_ACTIVE_LOW |
+ CLK_MESON_PLL_N_POWER_OF_TWO |
+ CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk0_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk0_in_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk0_0_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 0,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk0_0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk0_pll_dco.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk0_0_pre = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 3,
+ .width = 5,
+ .flags = CLK_DIVIDER_MAX_AT_ZERO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk0_0_pre",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk0_0_pll.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data a9_mclk0_0_parents[] = {
+ { .hw = &a9_mclk0_0_pre.hw },
+ { .fw_name = "in0" },
+ { .fw_name = "in1" },
+ { .fw_name = "in2" }
+};
+
+static A9_COMP_SEL(mclk0_0, MCLKPLL_CTRL3, 12, 0x3, a9_mclk0_0_parents);
+static A9_COMP_DIV(mclk0_0, MCLKPLL_CTRL3, 10, 1);
+static A9_COMP_GATE(mclk0_0, MCLKPLL_CTRL3, 8);
+
+static struct clk_regmap a9_mclk0_1_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 16,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk0_1_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk0_pll_dco.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk0_1_pre = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 19,
+ .width = 5,
+ .flags = CLK_DIVIDER_MAX_AT_ZERO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk0_1_pre",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk0_1_pll.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data a9_mclk0_1_parents[] = {
+ { .hw = &a9_mclk0_1_pre.hw },
+ { .fw_name = "in0" },
+ { .fw_name = "in1" },
+ { .fw_name = "in2" }
+};
+
+static A9_COMP_SEL(mclk0_1, MCLKPLL_CTRL3, 28, 0x3, a9_mclk0_1_parents);
+static A9_COMP_DIV(mclk0_1, MCLKPLL_CTRL3, 26, 1);
+static A9_COMP_GATE(mclk0_1, MCLKPLL_CTRL3, 24);
+
+static struct clk_fixed_factor a9_mclk1_in_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "mclk1_in_div2",
+ .ops = &clk_fixed_factor_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "in0",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk1_pll_dco = {
+ .data = &(struct meson_clk_pll_data) {
+ .en = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 0,
+ .width = 9,
+ },
+ .n = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 12,
+ .width = 3,
+ },
+ .l = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = MCLKPLL_CTRL0,
+ .shift = 30,
+ .width = 1,
+ },
+ .range = &a9_pll_mult_range,
+ .init_regs = a9_mclk0_pll_init_regs,
+ .init_count = ARRAY_SIZE(a9_mclk0_pll_init_regs),
+ .flags = CLK_MESON_PLL_RST_ACTIVE_LOW |
+ CLK_MESON_PLL_N_POWER_OF_TWO |
+ CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk1_pll_dco",
+ .ops = &meson_clk_pll_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk1_in_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk1_0_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 0,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk1_0_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk1_pll_dco.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk1_0_pre = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 3,
+ .width = 5,
+ .flags = CLK_DIVIDER_MAX_AT_ZERO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk1_0_pre",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk1_0_pll.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data a9_mclk1_0_parents[] = {
+ { .hw = &a9_mclk1_0_pre.hw },
+ { .fw_name = "in0" },
+ { .fw_name = "in1" },
+ { .fw_name = "in2" }
+};
+
+static A9_COMP_SEL(mclk1_0, MCLKPLL_CTRL3, 12, 0x3, a9_mclk1_0_parents);
+static A9_COMP_DIV(mclk1_0, MCLKPLL_CTRL3, 10, 1);
+static A9_COMP_GATE(mclk1_0, MCLKPLL_CTRL3, 8);
+
+static struct clk_regmap a9_mclk1_1_pll = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 16,
+ .width = 3,
+ .table = a9_pll_od_table,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk1_1_pll",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk1_pll_dco.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap a9_mclk1_1_pre = {
+ .data = &(struct clk_regmap_div_data) {
+ .offset = MCLKPLL_CTRL3,
+ .shift = 19,
+ .width = 5,
+ .flags = CLK_DIVIDER_MAX_AT_ZERO,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "mclk1_1_pre",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &a9_mclk1_1_pll.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data a9_mclk1_1_parents[] = {
+ { .hw = &a9_mclk1_1_pre.hw },
+ { .fw_name = "in0" },
+ { .fw_name = "in1" },
+ { .fw_name = "in2" }
+};
+
+static A9_COMP_SEL(mclk1_1, MCLKPLL_CTRL3, 28, 0x3, a9_mclk1_1_parents);
+static A9_COMP_DIV(mclk1_1, MCLKPLL_CTRL3, 26, 1);
+static A9_COMP_GATE(mclk1_1, MCLKPLL_CTRL3, 24);
+
+static struct clk_hw *a9_gp0_hw_clks[] = {
+ [CLKID_GP0_IN_DIV2_DIV] = &a9_gp0_in_div2_div.hw,
+ [CLKID_GP0_IN_DIV2] = &a9_gp0_in_div2.hw,
+ [CLKID_GP0_PLL_DCO] = &a9_gp0_pll_dco.hw,
+ [CLKID_GP0_PLL] = &a9_gp0_pll.hw,
+};
+
+static struct clk_hw *a9_hifi0_hw_clks[] = {
+ [CLKID_HIFI0_IN_DIV2_DIV] = &a9_hifi0_in_div2_div.hw,
+ [CLKID_HIFI0_IN_DIV2] = &a9_hifi0_in_div2.hw,
+ [CLKID_HIFI0_PLL_DCO] = &a9_hifi0_pll_dco.hw,
+ [CLKID_HIFI0_PLL] = &a9_hifi0_pll.hw,
+};
+
+static struct clk_hw *a9_hifi1_hw_clks[] = {
+ [CLKID_HIFI1_IN_DIV2_DIV] = &a9_hifi1_in_div2_div.hw,
+ [CLKID_HIFI1_IN_DIV2] = &a9_hifi1_in_div2.hw,
+ [CLKID_HIFI1_PLL_DCO] = &a9_hifi1_pll_dco.hw,
+ [CLKID_HIFI1_PLL] = &a9_hifi1_pll.hw,
+};
+
+static struct clk_hw *a9_mclk0_hw_clks[] = {
+ [CLKID_MCLK0_IN_DIV2] = &a9_mclk0_in_div2.hw,
+ [CLKID_MCLK0_PLL_DCO] = &a9_mclk0_pll_dco.hw,
+ [CLKID_MCLK0_0_PLL] = &a9_mclk0_0_pll.hw,
+ [CLKID_MCLK0_0_PRE] = &a9_mclk0_0_pre.hw,
+ [CLKID_MCLK0_0_SEL] = &a9_mclk0_0_sel.hw,
+ [CLKID_MCLK0_0_DIV] = &a9_mclk0_0_div.hw,
+ [CLKID_MCLK0_0] = &a9_mclk0_0.hw,
+ [CLKID_MCLK0_1_PLL] = &a9_mclk0_1_pll.hw,
+ [CLKID_MCLK0_1_PRE] = &a9_mclk0_1_pre.hw,
+ [CLKID_MCLK0_1_SEL] = &a9_mclk0_1_sel.hw,
+ [CLKID_MCLK0_1_DIV] = &a9_mclk0_1_div.hw,
+ [CLKID_MCLK0_1] = &a9_mclk0_1.hw,
+};
+
+static struct clk_hw *a9_mclk1_hw_clks[] = {
+ [CLKID_MCLK1_IN_DIV2] = &a9_mclk1_in_div2.hw,
+ [CLKID_MCLK1_PLL_DCO] = &a9_mclk1_pll_dco.hw,
+ [CLKID_MCLK1_0_PLL] = &a9_mclk1_0_pll.hw,
+ [CLKID_MCLK1_0_PRE] = &a9_mclk1_0_pre.hw,
+ [CLKID_MCLK1_0_SEL] = &a9_mclk1_0_sel.hw,
+ [CLKID_MCLK1_0_DIV] = &a9_mclk1_0_div.hw,
+ [CLKID_MCLK1_0] = &a9_mclk1_0.hw,
+ [CLKID_MCLK1_1_PLL] = &a9_mclk1_1_pll.hw,
+ [CLKID_MCLK1_1_PRE] = &a9_mclk1_1_pre.hw,
+ [CLKID_MCLK1_1_SEL] = &a9_mclk1_1_sel.hw,
+ [CLKID_MCLK1_1_DIV] = &a9_mclk1_1_div.hw,
+ [CLKID_MCLK1_1] = &a9_mclk1_1.hw,
+};
+
+static const struct meson_clkc_data a9_gp0_data = {
+ .hw_clks = {
+ .hws = a9_gp0_hw_clks,
+ .num = ARRAY_SIZE(a9_gp0_hw_clks),
+ },
+};
+
+static const struct meson_clkc_data a9_hifi0_data = {
+ .hw_clks = {
+ .hws = a9_hifi0_hw_clks,
+ .num = ARRAY_SIZE(a9_hifi0_hw_clks),
+ },
+};
+
+static const struct meson_clkc_data a9_hifi1_data = {
+ .hw_clks = {
+ .hws = a9_hifi1_hw_clks,
+ .num = ARRAY_SIZE(a9_hifi1_hw_clks),
+ },
+};
+
+static const struct meson_clkc_data a9_mclk0_data = {
+ .hw_clks = {
+ .hws = a9_mclk0_hw_clks,
+ .num = ARRAY_SIZE(a9_mclk0_hw_clks),
+ },
+};
+
+static const struct meson_clkc_data a9_mclk1_data = {
+ .hw_clks = {
+ .hws = a9_mclk1_hw_clks,
+ .num = ARRAY_SIZE(a9_mclk1_hw_clks),
+ },
+};
+
+static const struct of_device_id a9_pll_clkc_match_table[] = {
+ { .compatible = "amlogic,a9-gp0-pll", .data = &a9_gp0_data, },
+ { .compatible = "amlogic,a9-hifi0-pll", .data = &a9_hifi0_data, },
+ { .compatible = "amlogic,a9-hifi1-pll", .data = &a9_hifi1_data, },
+ { .compatible = "amlogic,a9-mclk0-pll", .data = &a9_mclk0_data, },
+ { .compatible = "amlogic,a9-mclk1-pll", .data = &a9_mclk1_data, },
+ {}
+};
+MODULE_DEVICE_TABLE(of, a9_pll_clkc_match_table);
+
+static struct platform_driver a9_pll_clkc_driver = {
+ .probe = meson_clkc_mmio_probe,
+ .driver = {
+ .name = "a9-pll-clkc",
+ .of_match_table = a9_pll_clkc_match_table,
+ },
+};
+module_platform_driver(a9_pll_clkc_driver);
+
+MODULE_DESCRIPTION("Amlogic A9 PLL 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 07/10] clk: amlogic: Support POWER_OF_TWO for PLL pre-divider
From: Jian Hu via B4 Relay @ 2026-05-11 12:47 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl
Cc: linux-kernel, linux-clk, devicetree, linux-amlogic,
linux-arm-kernel, Jian Hu
In-Reply-To: <20260511-b4-a9_clk-v1-0-41cb4071b7c9@amlogic.com>
From: Jian Hu <jian.hu@amlogic.com>
The A9 PLL pre-divider uses a division factor of 2^n to ensure a clock
duty cycle of 50% after predivision.
Add flag 'CLK_MESON_PLL_N_POWER_OF_TWO' to indicate that the PLL
pre-divider division factor is 2^n.
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
---
drivers/clk/meson/clk-pll.c | 28 +++++++++++++++++++++++-----
drivers/clk/meson/clk-pll.h | 2 ++
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c
index 8568ad6ba7b6..49483e431d44 100644
--- a/drivers/clk/meson/clk-pll.c
+++ b/drivers/clk/meson/clk-pll.c
@@ -66,6 +66,9 @@ static unsigned long __pll_params_to_rate(unsigned long parent_rate,
rate += DIV_ROUND_UP_ULL(frac_rate, frac_max);
}
+ if (pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO)
+ n = 1 << n;
+
return DIV_ROUND_UP_ULL(rate, n);
}
@@ -83,7 +86,7 @@ static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
* it would result in a division by zero. The rate can't be
* calculated in this case
*/
- if (n == 0)
+ if (n == 0 && !(pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO))
return 0;
m = meson_parm_read(clk->map, &pll->m);
@@ -103,7 +106,12 @@ static unsigned int __pll_params_with_frac(unsigned long rate,
{
unsigned int frac_max = pll->frac_max ? pll->frac_max :
(1 << pll->frac.width);
- u64 val = (u64)rate * n;
+ u64 val;
+
+ if (pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO)
+ n = 1 << n;
+
+ val = (u64)rate * n;
/* Bail out if we are already over the requested rate */
if (rate < parent_rate * m / n)
@@ -142,7 +150,8 @@ static int meson_clk_get_pll_table_index(unsigned int index,
unsigned int *n,
struct meson_clk_pll_data *pll)
{
- if (!pll->table[index].n)
+ if (!pll->table[index].n &&
+ !(pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO))
return -EINVAL;
*m = pll->table[index].m;
@@ -156,7 +165,12 @@ static unsigned int meson_clk_get_pll_range_m(unsigned long rate,
unsigned int n,
struct meson_clk_pll_data *pll)
{
- u64 val = (u64)rate * n;
+ u64 val;
+
+ if (pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO)
+ n = 1 << n;
+
+ val = (u64)rate * n;
if (__pll_round_closest_mult(pll))
return DIV_ROUND_CLOSEST_ULL(val, parent_rate);
@@ -173,11 +187,15 @@ static int meson_clk_get_pll_range_index(unsigned long rate,
{
*n = index + 1;
+ if ((pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO))
+ *n = index;
+
/* Check the predivider range */
if (*n >= (1 << pll->n.width))
return -EINVAL;
- if (*n == 1) {
+ if ((*n == 1 && !(pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO)) ||
+ (*n == 0 && (pll->flags & CLK_MESON_PLL_N_POWER_OF_TWO))) {
/* Get the boundaries out the way */
if (rate <= pll->range->min * parent_rate) {
*m = pll->range->min;
diff --git a/drivers/clk/meson/clk-pll.h b/drivers/clk/meson/clk-pll.h
index 1be7e6e77631..60b2772a54c8 100644
--- a/drivers/clk/meson/clk-pll.h
+++ b/drivers/clk/meson/clk-pll.h
@@ -33,6 +33,8 @@ struct pll_mult_range {
#define CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH BIT(2)
/* rst signal is active-low (Power-on reset) */
#define CLK_MESON_PLL_RST_ACTIVE_LOW BIT(3)
+/* The division factor of the PLL pre-divider is 2^n */
+#define CLK_MESON_PLL_N_POWER_OF_TWO BIT(4)
struct meson_clk_pll_data {
struct parm en;
--
2.47.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox