* Re: [PATCH v7 13/20] KVM: arm64: Apply dynamic guest counter reservations
From: James Clark @ 2026-05-14 9:10 UTC (permalink / raw)
To: Colton Lewis
Cc: alexandru.elisei, pbonzini, corbet, linux, catalin.marinas, will,
maz, oliver.upton, mizhang, joey.gouly, suzuki.poulose, yuzenghui,
mark.rutland, shuah, gankulkarni, linux-doc, linux-kernel,
linux-arm-kernel, kvmarm, linux-perf-users, linux-kselftest, kvm
In-Reply-To: <gsntzf23b6m2.fsf@coltonlewis-kvm.c.googlers.com>
On 13/05/2026 5:45 pm, Colton Lewis wrote:
> James Clark <james.clark@linaro.org> writes:
>
>> On 04/05/2026 10:18 pm, Colton Lewis wrote:
>>> Apply dynamic guest counter reservations by checking if the requested
>>> guest mask collides with any events the host has scheduled and calling
>>> pmu_perf_resched_update() with a hook that updates the mask of
>>> available counters in between schedule out and schedule in.
>
>>> Signed-off-by: Colton Lewis <coltonlewis@google.com>
>>> ---
>>> arch/arm64/kvm/pmu-direct.c | 69 ++++++++++++++++++++++++++++++++
>>> ++++
>>> include/linux/perf/arm_pmu.h | 1 +
>>> 2 files changed, 70 insertions(+)
>
>>> diff --git a/arch/arm64/kvm/pmu-direct.c b/arch/arm64/kvm/pmu-direct.c
>>> index 2252d3b905db9..14cc419dbafad 100644
>>> --- a/arch/arm64/kvm/pmu-direct.c
>>> +++ b/arch/arm64/kvm/pmu-direct.c
>>> @@ -100,6 +100,73 @@ u8 kvm_pmu_hpmn(struct kvm_vcpu *vcpu)
>>> return *host_data_ptr(nr_event_counters);
>>> }
>
>>> +/* Callback to update counter mask between perf scheduling */
>>> +static void kvm_pmu_update_mask(struct pmu *pmu, void *data)
>>> +{
>>> + struct arm_pmu *arm_pmu = to_arm_pmu(pmu);
>>> + unsigned long *new_mask = data;
>>> +
>>> + bitmap_copy(arm_pmu->cntr_mask, new_mask, ARMPMU_MAX_HWEVENTS);
>>> +}
>>> +
>>> +/**
>>> + * kvm_pmu_set_guest_counters() - Handle dynamic counter reservations
>>> + * @cpu_pmu: struct arm_pmu to potentially modify
>>> + * @guest_mask: new guest mask for the pmu
>>> + *
>>> + * Check if guest counters will interfere with current host events and
>>> + * call into perf_pmu_resched_update if a reschedule is required.
>>> + */
>>> +static void kvm_pmu_set_guest_counters(struct arm_pmu *cpu_pmu, u64
>>> guest_mask)
>>> +{
>>> + struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
>>> + DECLARE_BITMAP(guest_bitmap, ARMPMU_MAX_HWEVENTS);
>>> + DECLARE_BITMAP(new_mask, ARMPMU_MAX_HWEVENTS);
>>> + bool need_resched = false;
>>> +
>>> + bitmap_from_arr64(guest_bitmap, &guest_mask, ARMPMU_MAX_HWEVENTS);
>>> + bitmap_copy(new_mask, cpu_pmu->hw_cntr_mask, ARMPMU_MAX_HWEVENTS);
>>> +
>>> + if (guest_mask) {
>>> + /* Subtract guest counters from available host mask */
>>> + bitmap_andnot(new_mask, new_mask, guest_bitmap,
>>> ARMPMU_MAX_HWEVENTS);
>>> +
>>> + /* Did we collide with an active host event? */
>>> + if (bitmap_intersects(cpuc->used_mask, guest_bitmap,
>>> ARMPMU_MAX_HWEVENTS)) {
>>> + int idx;
>>> +
>>> + need_resched = true;
>>> + cpuc->host_squeezed = true;
>>> +
>>> + /* Look for pinned events that are about to be preempted */
>>> + for_each_set_bit(idx, guest_bitmap, ARMPMU_MAX_HWEVENTS) {
>>> + if (test_bit(idx, cpuc->used_mask) && cpuc-
>>> >events[idx] &&
>>> + cpuc->events[idx]->attr.pinned) {
>>> + pr_warn_ratelimited("perf: Pinned host event
>>> squeezed out by KVM guest PMU partition\n");
>
>> Hi Colton,
>
>> I get "perf: Pinned host event squeezed out by KVM guest PMU partition"
>> even with arm_pmuv3.reserved_host_counters=3 for example. I would have
>> expected any non zero value to stop the warning.
>
>> I think armv8pmu_get_single_idx() needs to be changed to allocate from
>> the high end host counters first. A more complicated option would be
>> checking to see if there are any non-pinned counters in the host
>> reserved half when a new pinned counter is opened, then swapping the
>> places of the new pinned and existing non-pinned counters so pinned
>> always prefer being put into the host half. But it's probably not worth
>> doing that.
>
>> James
>
>
> I agree it makes the most sense to allocate from the top, but I'm happy
> the basic idea works.
>
Another thing I forgot to mention is that even with the ratelimited
warning, this spams the logs any time the host and guest are both using
the PMU and I'm not sure how useful that is.
>>> + break;
>>> + }
>>> + }
>>> + }
>>> + } else {
>>> + /*
>>> + * Restoring to hw_cntr_mask.
>>> + * Only resched if we previously squeezed an event.
>>> + */
>>> + if (cpuc->host_squeezed) {
>>> + need_resched = true;
>>> + cpuc->host_squeezed = false;
>>> + }
>>> + }
>>> +
>>> + if (need_resched) {
>>> + /* Collision: run full perf reschedule */
>>> + perf_pmu_resched_update(&cpu_pmu->pmu, kvm_pmu_update_mask,
>>> new_mask);
>>> + } else {
>>> + /* Host was never using guest counters anyway */
>>> + bitmap_copy(cpu_pmu->cntr_mask, new_mask, ARMPMU_MAX_HWEVENTS);
>>> + }
>>> +}
>>> +
>>> /**
>>> * kvm_pmu_host_counter_mask() - Compute bitmask of host-reserved
>>> counters
>>> * @pmu: Pointer to arm_pmu struct
>>> @@ -218,6 +285,7 @@ void kvm_pmu_load(struct kvm_vcpu *vcpu)
>
>>> pmu = vcpu->kvm->arch.arm_pmu;
>>> guest_counters = kvm_pmu_guest_counter_mask(pmu);
>>> + kvm_pmu_set_guest_counters(pmu, guest_counters);
>>> kvm_pmu_apply_event_filter(vcpu);
>
>>> for_each_set_bit(i, &guest_counters, ARMPMU_MAX_HWEVENTS) {
>>> @@ -319,5 +387,6 @@ void kvm_pmu_put(struct kvm_vcpu *vcpu)
>>> val = read_sysreg(pmintenset_el1);
>>> __vcpu_assign_sys_reg(vcpu, PMINTENSET_EL1, val & mask);
>
>>> + kvm_pmu_set_guest_counters(pmu, 0);
>>> preempt_enable();
>>> }
>>> diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
>>> index f7b000bb3eca8..63f88fec5e80f 100644
>>> --- a/include/linux/perf/arm_pmu.h
>>> +++ b/include/linux/perf/arm_pmu.h
>>> @@ -75,6 +75,7 @@ struct pmu_hw_events {
>
>>> /* Active events requesting branch records */
>>> unsigned int branch_users;
>>> + bool host_squeezed;
>>> };
>
>>> enum armpmu_attr_groups {
^ permalink raw reply
* Re: [PATCH 5/5] arm_mpam: detect and enable MPAM-Fb PCC support
From: Ben Horgan @ 2026-05-14 9:10 UTC (permalink / raw)
To: Andre Przywara, Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla,
Catalin Marinas, Will Deacon, Rafael J . Wysocki, Len Brown,
James Morse, Reinette Chatre, Fenghua Yu
Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <81f8bea6-bcf3-4523-ae0e-3d45c32800cb@arm.com>
Hi Andre,
On 5/13/26 15:51, Andre Przywara wrote:
> Hi Ben,
>
> On 5/8/26 12:48, Ben Horgan wrote:
>> Hi Andre,
>>
>> On 4/29/26 15:13, Andre Przywara wrote:
>>> The Arm MPAM-Fb specification [1] describes a protocol to access MSC
>>> registers through a firmware interface. This requires a shared memory
>>> region to hold the message, and a mailbox to trigger the access.
>>> For ACPI this is wrapped as a PCC channel, described using existing
>>> ACPI abstractions.
>>>
>>> Add code to parse those PCC table descriptions associated with an MSC,
>>> and store the parsed information in the MSC struct.
>>> This will be used by the MPAM-Fb access wrapper code.
>>>
>>> [1] https://developer.arm.com/documentation/den0144/latest
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>> drivers/acpi/arm64/mpam.c | 2 ++
>>> drivers/resctrl/mpam_devices.c | 46 +++++++++++++++++++++++++++++++---
>>> 2 files changed, 45 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/acpi/arm64/mpam.c b/drivers/acpi/arm64/mpam.c
>>> index 99c2bdbb3314..edb4d10e8dc3 100644
>>> --- a/drivers/acpi/arm64/mpam.c
>>> +++ b/drivers/acpi/arm64/mpam.c
>>> @@ -341,6 +341,8 @@ static struct platform_device * __init acpi_mpam_parse_msc(struct acpi_mpam_msc_
>>> } else if (iface == MPAM_IFACE_PCC) {
>>> props[next_prop++] = PROPERTY_ENTRY_U32("pcc-channel",
>>> tbl_msc->base_address);
>>> + props[next_prop++] = PROPERTY_ENTRY_U32("msc-id",
>>> + tbl_msc->identifier);
>>> }
>>> acpi_mpam_parse_irqs(pdev, tbl_msc, res, &next_res);
>>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>>> index 62aa04cb6905..6f0d0959d3a4 100644
>>> --- a/drivers/resctrl/mpam_devices.c
>>> +++ b/drivers/resctrl/mpam_devices.c
>>> @@ -19,6 +19,7 @@
>>> #include <linux/irqdesc.h>
>>> #include <linux/list.h>
>>> #include <linux/lockdep.h>
>>> +#include <linux/mailbox_client.h>
>>> #include <linux/mutex.h>
>>> #include <linux/platform_device.h>
>>> #include <linux/printk.h>
>>> @@ -27,6 +28,9 @@
>>> #include <linux/types.h>
>>> #include <linux/workqueue.h>
>>> +#include <acpi/pcc.h>
>>> +#include <acpi/acpi_io.h>
>>> +
>>> #include "mpam_internal.h"
>>> #include "mpam_fb.h"
>>> @@ -1042,7 +1046,8 @@ static u64 mpam_msc_read_mbwu_l(struct mpam_msc *msc)
>>> mpam_mon_sel_lock_held(msc);
>>> - WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
>>> + if (msc->iface == MPAM_IFACE_MMIO)
>>> + WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
>>
>> This should be in a different patch.
>
> Which one, preferably? A separate one? Or patch 3/5, which adds the PCC access code?
> This one here is the patch that enables non-MMIO accesses, so I figured that's the place we should relax this check.
I thought this matched the WARN_ON_ONCE() changes in patch 3/5 but that patch just concentrates on the lower level so
I'm ok to keep it in this patch. I think you've missed a similar WARN_ON_ONCE() in mpam_msc_zero_mbwu_l() though.
>
>>
>>> WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
>>> mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4);
>>> @@ -2042,10 +2047,15 @@ static void mpam_msc_drv_remove(struct platform_device *pdev)
>>> mpam_free_garbage();
>>> }
>>> +static void mpam_pcc_rx_callback(struct mbox_client *cl, void *msg)
>>> +{
>>> + /* TODO: wake up tasks blocked on this MSC's PCC channel */
>>> +}
>>> +
>>> static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
>>> {
>>> int err;
>>> - u32 tmp;
>>> + u32 pcc_subspace_id;
>>> struct mpam_msc *msc;
>>> struct resource *msc_res;
>>> struct device *dev = &pdev->dev;
>>> @@ -2090,7 +2100,8 @@ static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
>>> if (err)
>>> return ERR_PTR(err);
>>> - if (device_property_read_u32(&pdev->dev, "pcc-channel", &tmp))
>>> + if (device_property_read_u32(&pdev->dev, "pcc-channel",
>>> + &pcc_subspace_id))
>>> msc->iface = MPAM_IFACE_MMIO;
>>> else
>>> msc->iface = MPAM_IFACE_PCC;
>>> @@ -2106,6 +2117,35 @@ static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
>>> }
>>> msc->mapped_hwpage_sz = msc_res->end - msc_res->start;
>>> msc->mapped_hwpage = io;
>>> + } else if (msc->iface == MPAM_IFACE_PCC) {
>>> + u32 msc_id;
>>> +
>>> + msc->pcc_cl.dev = &pdev->dev;
>>> + msc->pcc_cl.rx_callback = mpam_pcc_rx_callback;
>>> + msc->pcc_cl.tx_block = false;
>>
>> How do we make sure that, for instance, a MON_SEL write has completed before we start reading
>> the associated counters? Is there an ordering guarantee?
>
> What is your concern here, exactly? To group all the accesses selected by one MON_SEL write, we have the mon_sel lock
> (now mutex) already. And on the mbox side I think we are safe because the PCC channel is exclusive, we have the per-
> channel mutex (pcc_chan_lock, in patch 3/5), and we wait for confirmation from the other end, even for writes. So as
That sounds like there is no problem then. I wasn't sure that we were waiting for confirmation of writes. We can assume
that the f/w end of the link processing the requests in the order it acknowledges them, right?
Is the waiting for confirmation of writes done by this bit of patch 3?
+ status = readl(chan->shmem + SCMI_MSG_HEADER_OFS);
+ if (FIELD_GET(MPAM_MSC_TOKEN_MASK, status) != token)
+ return -ETIMEDOUT;
> long as the MON_SEL write appears in program order before the counter read, all should be good, no? Am I missing something?
I expect that I'm the one who was missing something.
Thanks,
Ben
>
> Cheers,
> Andre
>
>>
>> Thanks,
>>
>> Ben
>>
>>> + msc->pcc_cl.tx_tout = 1000; /* 1s */
>>> + msc->pcc_cl.knows_txdone = false;
>>> +
>>> + if (device_property_read_u32(&pdev->dev, "msc-id", &msc_id)) {
>>> + pr_err("missing MPAM-Fb MSC identifier\n");
>>> + return ERR_PTR(-EINVAL);
>>> + }
>>> + msc->mpam_fb_msc_id = msc_id;
>>> +
>>> + msc->pcc_chan = pcc_mbox_request_channel(&msc->pcc_cl,
>>> + pcc_subspace_id);
>>> + if (IS_ERR(msc->pcc_chan)) {
>>> + pr_err("Failed to request MSC PCC channel\n");
>>> + return (void *)msc->pcc_chan;
>>> + }
>>> +
>>> + if (msc->pcc_chan->shmem_size < MPAM_FB_MAX_MSG_SIZE) {
>>> + pr_err("MPAM-Fb PCC channel size too small.\n");
>>> + pcc_mbox_free_channel(msc->pcc_chan);
>>> + return ERR_PTR(-ENOMEM);
>>> + }
>>> +
>>> + mutex_init(&msc->pcc_chan_lock);
>>> } else {
>>> return ERR_PTR(-EINVAL);
>>> }
>>
>
^ permalink raw reply
* [PATCH v4 1/6] mfd: dt-bindings: mt6397: Add regulator supplies
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree,
Krzysztof Kozlowski
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
On the MT6397 family each buck regulator has a separate supply. LDOs are
split into various groups with independent supplies. There is also a
supply for the regulator control logic.
Add descriptions for all of the supplies for the MT6359.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Lee, request from Mark:
Lee, this seems like mostly a regulator series - OK for me to apply this
patch and send you a tag for it?
Changes since v3:
- Dropped duplicate 'va09' from 'vsys-ldo2-supply' (Sashiko)
Changes since v2:
- Fix vsys-vsmps-supply property name
Changes since v1:
- Use regular expression to describe vcn33_* names
- Moved regulator supplies to top level PMIC node
- Moved changes to mfd binding
---
.../bindings/mfd/mediatek,mt6397.yaml | 50 +++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
index 05c121b0cb3d..ecdc77fafaf4 100644
--- a/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
+++ b/Documentation/devicetree/bindings/mfd/mediatek,mt6397.yaml
@@ -225,12 +225,62 @@ properties:
description:
Pin controller
+ vsys-smps-supply:
+ description: Supply for regulator control logic
+
+patternProperties:
+ "^vsys-v[a-z]+[0-9]*-supply$":
+ description: Supplies for PMIC buck regulators
+ "^vs(ys|[12])-ldo[1-9]-supply$":
+ description: Supplies for PMIC LDO regulators
+
required:
- compatible
- regulators
additionalProperties: false
+allOf:
+ - if:
+ properties:
+ "compatible":
+ contains:
+ const: mediatek,mt6359
+ then:
+ properties:
+ vsys-ldo1-supply:
+ description: Supply for LDOs vcn33_[12], vio28, vfe28, vibr
+ vsys-ldo2-supply:
+ description: Supply for LDOs vaux18, vbif28, vxo22, vrfck, vrfck_1,
+ vemc, vsim1, vsim2, vusb
+ vsys-vcore-supply:
+ description: Supply for buck regulator vcore
+ vsys-vgpu11-supply:
+ description: Supply for buck regulator vgpu11
+ vsys-vmodem-supply:
+ description: Supply for buck regulator vmodem
+ vsys-vpa-supply:
+ description: Supply for buck regulator vpa
+ vsys-vproc1-supply:
+ description: Supply for buck regulator vproc1
+ vsys-vproc2-supply:
+ description: Supply for buck regulator vproc2
+ vsys-vpu-supply:
+ description: Supply for buck regulator vpu
+ vsys-vs1-supply:
+ description: Supply for buck regulator vs1
+ vsys-vs2-supply:
+ description: Supply for buck regulator vs2
+ vs1-ldo1-supply:
+ description: Supply for LDOs vaud18, vcamio, vm18, vufs
+ vs1-ldo2-supply:
+ description: Supply for LDOs vcn18, vefuse, vio18, vrf18
+ vs2-ldo1-supply:
+ description:
+ Supply for LDOs vsram_proc1, vsram_proc2, vsram_others, vsram_md
+ vs2-ldo2-supply:
+ description: Supply for LDOs va09, va12, vcn13, vrf12
+
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 2/6] regulator: dt-bindings: mt6359: Drop regulator-name pattern restrictions
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree,
Krzysztof Kozlowski
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
The name of the regulator should match what the board design specifies
for the power rail. There should be no limitations on what the name can
be, and they definitely don't always follow the PMIC's own names.
Drop the restrictions on regulator-name.
Fixes: 8771456635d5 ("dt-bindings: regulator: Add document for MT6359 regulator")
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
.../bindings/regulator/mt6359-regulator.yaml | 43 -------------------
1 file changed, 43 deletions(-)
diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
index fe4ac9350ba0..ac925334ae83 100644
--- a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
@@ -18,84 +18,41 @@ patternProperties:
"^buck_v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^v(s1|gpu11|modem|pu|core|s2|pa|proc2|proc1|core_sshub)$"
-
unevaluatedProperties: false
"^ldo_v(ibr|rf12|usb|camio|efuse|xo22)$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^v(ibr|rf12|usb|camio|efuse|xo22)$"
-
unevaluatedProperties: false
"^ldo_v(rfck|emc|a12|a09|ufs|bbck)$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^v(rfck|emc|a12|a09|ufs|bbck)$"
-
unevaluatedProperties: false
"^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$"
-
unevaluatedProperties: false
"^ldo_vsram_(proc2|others|md|proc1|others_sshub)$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^vsram_(proc2|others|md|proc1|others_sshub)$"
-
unevaluatedProperties: false
"^ldo_v(fe|bif|io)28$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^v(fe|bif|io)28$"
-
unevaluatedProperties: false
"^ldo_v(aud|io|aux|rf|m)18$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^v(aud|io|aux|rf|m)18$"
-
unevaluatedProperties: false
"^ldo_vsim[12]$":
type: object
$ref: regulator.yaml#
-
- properties:
- regulator-name:
- pattern: "^vsim[12]$"
-
- required:
- - regulator-name
-
unevaluatedProperties: false
additionalProperties: false
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 4/6] regulator: mt6359: const-ify regulator descriptions
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
The regulator descriptions and extended descriptions don't change at
runtime. The only reason they are not const is that the regulator
driver data is non-const.
Const-ify the descriptions and all references to them. For the driver
data, explicitly cast it to non-const void *.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
drivers/regulator/mt6359-regulator.c | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
index c8a788858824..bcf9a476a34e 100644
--- a/drivers/regulator/mt6359-regulator.c
+++ b/drivers/regulator/mt6359-regulator.c
@@ -251,7 +251,7 @@ static int mt6359_get_status(struct regulator_dev *rdev)
{
int ret;
u32 regval;
- struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
ret = regmap_read(rdev->regmap, info->status_reg, ®val);
if (ret != 0) {
@@ -267,7 +267,7 @@ static int mt6359_get_status(struct regulator_dev *rdev)
static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev)
{
- struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
int ret, regval;
ret = regmap_read(rdev->regmap, info->modeset_reg, ®val);
@@ -299,7 +299,7 @@ static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev)
static int mt6359_regulator_set_mode(struct regulator_dev *rdev,
unsigned int mode)
{
- struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
int ret = 0, val;
int curr_mode;
@@ -354,7 +354,7 @@ static int mt6359_regulator_set_mode(struct regulator_dev *rdev,
static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev,
u32 sel)
{
- struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
u32 val = 0;
@@ -393,7 +393,7 @@ static int mt6359p_vemc_set_voltage_sel(struct regulator_dev *rdev,
static int mt6359p_vemc_get_voltage_sel(struct regulator_dev *rdev)
{
- struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
+ const struct mt6359_regulator_info *info = rdev_get_drvdata(rdev);
int ret;
u32 val = 0;
@@ -469,7 +469,7 @@ static const struct regulator_ops mt6359p_vemc_ops = {
};
/* The array is indexed by id(MT6359_ID_XXX) */
-static struct mt6359_regulator_info mt6359_regulators[] = {
+static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
MT6359_RG_BUCK_VS1_EN_ADDR,
MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
@@ -705,7 +705,7 @@ static struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
};
-static struct mt6359_regulator_info mt6359p_regulators[] = {
+static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
MT6359_RG_BUCK_VS1_EN_ADDR,
MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
@@ -950,7 +950,7 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = {};
struct regulator_dev *rdev;
- struct mt6359_regulator_info *mt6359_info;
+ const struct mt6359_regulator_info *mt6359_info;
int i, hw_ver, ret;
ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver);
@@ -965,7 +965,8 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
config.dev = mt6397->dev;
config.regmap = mt6397->regmap;
for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) {
- config.driver_data = mt6359_info;
+ /* drop const here, but all uses in the driver are const */
+ config.driver_data = (void *)mt6359_info;
rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name);
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 3/6] regulator: dt-bindings: mt6359: Deprecate bogus vcn33_[12]_* split regulators
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree,
Krzysztof Kozlowski
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
vcn33_[12]_bt and vcn33_[12]_wifi refer to the same output. There are
two enable bits in the registers so that BT and WiFi drivers can toggle
them separately without any coordination. If either bit is set, then the
regulator output is enabled.
Deprecate the existing regulators, and add proper regulators matching
the outputs: vcn33_1 and vcn33_2.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes since v3:
- Added ending match to regex for deprecated vcn33_[12]_(bt|wifi) (Sashiko)
- Updated example to use proper vcn33_[12] nodes (Sashiko)
---
.../bindings/regulator/mt6359-regulator.yaml | 29 +++++++++----------
1 file changed, 14 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
index ac925334ae83..e3c20412c8a7 100644
--- a/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/mt6359-regulator.yaml
@@ -30,7 +30,7 @@ patternProperties:
$ref: regulator.yaml#
unevaluatedProperties: false
- "^ldo_vcn(18|13|33_1_bt|13_1_wifi|33_2_bt|33_2_wifi)$":
+ "^ldo_vcn(18|13|33_[12])$":
type: object
$ref: regulator.yaml#
unevaluatedProperties: false
@@ -55,6 +55,15 @@ patternProperties:
$ref: regulator.yaml#
unevaluatedProperties: false
+ "^ldo_vcn33_[12]_(bt|wifi)$":
+ type: object
+ $ref: regulator.yaml#
+ description:
+ vcn33_[12]_(bt|wifi) are incorrect representations.
+ Use vcn33_[12] instead.
+ deprecated: true
+ unevaluatedProperties: false
+
additionalProperties: false
examples:
@@ -203,13 +212,8 @@ examples:
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <1300000>;
};
- mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1_bt {
- regulator-name = "vcn33_1_bt";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <3500000>;
- };
- mt6359_vcn33_1_wifi_ldo_reg: ldo_vcn33_1_wifi {
- regulator-name = "vcn33_1_wifi";
+ mt6359_vcn33_1_bt_ldo_reg: ldo_vcn33_1 {
+ regulator-name = "vcn33_1";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <3500000>;
};
@@ -270,13 +274,8 @@ examples:
regulator-min-microvolt = <2500000>;
regulator-max-microvolt = <3300000>;
};
- mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2_bt {
- regulator-name = "vcn33_2_bt";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <3500000>;
- };
- mt6359_vcn33_2_wifi_ldo_reg: ldo_vcn33_2_wifi {
- regulator-name = "vcn33_2_wifi";
+ mt6359_vcn33_2_bt_ldo_reg: ldo_vcn33_2 {
+ regulator-name = "vcn33_2";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <3500000>;
};
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 6/6] regulator: mt6359: Add proper ldo_vcn33_[12] regulators
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
The ldo_vcn33_[12]_wifi and ldo_vcn33_[12]_bt are just two regulator
outputs instead of four. The wifi and bt parts refer to separate enable
bits that are OR-ed together to affect the actual regulator output. The
separate bits allow the wifi and bt stacks to enable their power without
coordination between them. These have been deprecated in favor of proper
nodes matching the output.
Add proper ldo_vcn33_[12] regulators to replace the existing ones. The
enable status is synced to just one of the two enable bits, and the
other is forced off. This makes the handling in other bits simpler.
The existing *_(bt|wifi) regulators are converted to no-op regulators
that are fed from their new respective ldo_vcn33_[12] regulator. This
allows existing device trees to continue to work.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v3:
- Fixed index off-by-one in error message in mt6359_sync_vcn33_setting()
(Sashiko)
- Added check of return value from mt6359_sync_vcn33_setting() (Sashiko)
Changes since v1:
- Instead of dropping one regulator from each output, add a new one for
each output; the existing *_(bt|wifi) ones are then supplied from the
new one
---
drivers/regulator/mt6359-regulator.c | 184 +++++++++++++++++----
include/linux/regulator/mt6359-regulator.h | 10 +-
2 files changed, 159 insertions(+), 35 deletions(-)
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
index 46cafe93b24e..af0e0339fbdd 100644
--- a/drivers/regulator/mt6359-regulator.c
+++ b/drivers/regulator/mt6359-regulator.c
@@ -166,6 +166,20 @@ struct mt6359_regulator_info {
.qi = BIT(0), \
}
+#define MT6359_LDO_NOOP(match, _name, supply) \
+[MT6359_ID_##_name] = { \
+ .desc = { \
+ .name = #_name, \
+ .supply_name = supply, \
+ .of_match = of_match_ptr(match), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &mt6359_noop_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6359_ID_##_name, \
+ .owner = THIS_MODULE, \
+ }, \
+}
+
static const unsigned int vsim1_voltages[] = {
0, 0, 0, 1700000, 1800000, 0, 0, 0, 2700000, 0, 0, 3000000, 3100000,
};
@@ -475,6 +489,9 @@ static const struct regulator_ops mt6359p_vemc_ops = {
.get_status = mt6359_get_status,
};
+/* Used for backward-compatible placeholder regulators */
+static const struct regulator_ops mt6359_noop_ops = {};
+
/* The array is indexed by id(MT6359_ID_XXX) */
static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500,
@@ -596,18 +613,12 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR,
MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1", VCN33_1, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_1_EN_0_ADDR,
MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages,
- MT6359_RG_LDO_VCN33_1_EN_1_ADDR,
- MT6359_RG_LDO_VCN33_1_EN_1_SHIFT,
- MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
- MT6359_RG_VCN33_1_VOSEL_MASK <<
- MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359_RG_LDO_VAUX18_EN_ADDR,
MT6359_DA_VAUX18_B_EN_ADDR, 1800000),
MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750,
@@ -644,18 +655,12 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR,
MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2", VCN33_2, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_2_EN_0_ADDR,
MT6359_RG_LDO_VCN33_2_EN_0_SHIFT,
MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages,
- MT6359_RG_LDO_VCN33_2_EN_1_ADDR,
- MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
- MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
- MT6359_RG_VCN33_2_VOSEL_MASK <<
- MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages,
MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT,
MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR,
@@ -711,6 +716,11 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+ /* Placeholders for DT backward compatibility */
+ MT6359_LDO_NOOP("ldo_vcn33_1_bt", VCN33_1_BT, "LDO_VCN33_1"),
+ MT6359_LDO_NOOP("ldo_vcn33_1_wifi", VCN33_1_WIFI, "LDO_VCN33_1"),
+ MT6359_LDO_NOOP("ldo_vcn33_2_bt", VCN33_2_BT, "LDO_VCN33_2"),
+ MT6359_LDO_NOOP("ldo_vcn33_2_wifi", VCN33_2_WIFI, "LDO_VCN33_2"),
};
static const struct mt6359_regulator_info mt6359p_regulators[] = {
@@ -835,18 +845,12 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR,
MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1", VCN33_1, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_1_EN_0_ADDR,
MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages,
- MT6359P_RG_LDO_VCN33_1_EN_1_ADDR,
- MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT,
- MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
- MT6359_RG_VCN33_1_VOSEL_MASK <<
- MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359P_RG_LDO_VAUX18_EN_ADDR,
MT6359P_DA_VAUX18_B_EN_ADDR, 1800000),
MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750,
@@ -885,18 +889,12 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR,
MT6359P_RG_LDO_VEMC_VOSEL_0_MASK <<
MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT),
- MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2", VCN33_2, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_2_EN_0_ADDR,
MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT,
MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages,
- MT6359P_RG_LDO_VCN33_2_EN_1_ADDR,
- MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
- MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
- MT6359_RG_VCN33_2_VOSEL_MASK <<
- MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages,
MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT,
MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR,
@@ -951,27 +949,119 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_VOSEL_SHIFT),
+ /* Placeholders for DT backward compatibility */
+ MT6359_LDO_NOOP("ldo_vcn33_1_bt", VCN33_1_BT, "LDO_VCN33_1"),
+ MT6359_LDO_NOOP("ldo_vcn33_1_wifi", VCN33_1_WIFI, "LDO_VCN33_1"),
+ MT6359_LDO_NOOP("ldo_vcn33_2_bt", VCN33_2_BT, "LDO_VCN33_2"),
+ MT6359_LDO_NOOP("ldo_vcn33_2_wifi", VCN33_2_WIFI, "LDO_VCN33_2"),
+};
+
+struct mt6359_vcn33_regs {
+ u32 wifi_en_reg;
+ u32 wifi_en_mask;
+ u32 bt_en_reg;
+ u32 bt_en_mask;
+};
+
+static const struct mt6359_vcn33_regs vcn33_regs[][2] = {
+ { /* MT6359 */
+ {
+ .wifi_en_reg = MT6359_RG_LDO_VCN33_1_EN_1_ADDR,
+ .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_1_SHIFT),
+ .bt_en_reg = MT6359_RG_LDO_VCN33_1_EN_0_ADDR,
+ .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_0_SHIFT),
+ }, {
+ .wifi_en_reg = MT6359_RG_LDO_VCN33_2_EN_1_ADDR,
+ .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_1_SHIFT),
+ .bt_en_reg = MT6359_RG_LDO_VCN33_2_EN_0_ADDR,
+ .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_0_SHIFT),
+ }
+ }, { /* MT6359P */
+ {
+ .wifi_en_reg = MT6359P_RG_LDO_VCN33_1_EN_1_ADDR,
+ .wifi_en_mask = BIT(MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT),
+ .bt_en_reg = MT6359P_RG_LDO_VCN33_1_EN_0_ADDR,
+ .bt_en_mask = BIT(MT6359_RG_LDO_VCN33_1_EN_0_SHIFT),
+ }, {
+ .wifi_en_reg = MT6359P_RG_LDO_VCN33_2_EN_1_ADDR,
+ .wifi_en_mask = BIT(MT6359_RG_LDO_VCN33_2_EN_1_SHIFT),
+ .bt_en_reg = MT6359P_RG_LDO_VCN33_2_EN_0_ADDR,
+ .bt_en_mask = BIT(MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT),
+ }
+ }
};
+static int mt6359_sync_vcn33_setting(struct device *dev, unsigned int idx)
+{
+ struct mt6397_chip *mt6397 = dev_get_drvdata(dev->parent);
+ unsigned int val;
+ int ret;
+
+ /*
+ * VCN33_[12]_WIFI and VCN33_[12]_BT are two separate enable bits for
+ * the same regulator. They share the same voltage setting and output
+ * pin. Instead of having two potentially conflicting regulators, just
+ * have one regulator. Sync the two enable bits and only use one in
+ * the regulator device.
+ */
+ for (unsigned int i = 0; i < ARRAY_SIZE(vcn33_regs[0]); i++) {
+ u32 bt_en_mask = vcn33_regs[idx][i].bt_en_mask;
+ u32 wifi_en_mask = vcn33_regs[idx][i].wifi_en_mask;
+
+ ret = regmap_read(mt6397->regmap, vcn33_regs[idx][i].wifi_en_reg, &val);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read VCN33_%u_WIFI setting\n",
+ i + 1);
+
+ if (!(val & wifi_en_mask))
+ continue;
+
+ /* Sync VCN33_[12]_WIFI enable status to VCN33_[12]_BT */
+ ret = regmap_update_bits(mt6397->regmap, vcn33_regs[idx][i].bt_en_reg,
+ bt_en_mask, bt_en_mask);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to sync VCN33_%u_WIFI setting to VCN33_%u_BT\n",
+ i + 1, i + 1);
+
+ /* Disable VCN33_[12]_WIFI */
+ ret = regmap_update_bits(mt6397->regmap, vcn33_regs[idx][i].wifi_en_reg,
+ wifi_en_mask, 0);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to disable VCN33_%u_WIFI\n", i + 1);
+ }
+
+ return 0;
+}
+
static int mt6359_regulator_probe(struct platform_device *pdev)
{
struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = {};
struct regulator_dev *rdev;
const struct mt6359_regulator_info *mt6359_info;
- const char *vio18_name;
+ const char *vio18_name, *vcn33_1_name, *vcn33_2_name;
int i, hw_ver, ret;
ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver);
if (ret)
return ret;
- if (hw_ver >= MT6359P_CHIP_VER)
+ if (hw_ver >= MT6359P_CHIP_VER) {
mt6359_info = mt6359p_regulators;
- else
+ ret = mt6359_sync_vcn33_setting(&pdev->dev, 1);
+ if (ret)
+ return ret;
+ } else {
mt6359_info = mt6359_regulators;
+ ret = mt6359_sync_vcn33_setting(&pdev->dev, 0);
+ if (ret)
+ return ret;
+ }
vio18_name = mt6359_info[MT6359_ID_VIO18].desc.name;
+ vcn33_1_name = mt6359_info[MT6359_ID_VCN33_1].desc.name;
+ vcn33_2_name = mt6359_info[MT6359_ID_VCN33_2].desc.name;
config.dev = mt6397->dev;
config.regmap = mt6397->regmap;
@@ -993,6 +1083,30 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
desc = _desc;
}
+ /* Use vcn33_1's actual name as supply_name for vcn33_1_(bt|wifi) */
+ if ((i == MT6359_ID_VCN33_1_BT || i == MT6359_ID_VCN33_1_WIFI) &&
+ strcmp(desc->supply_name, vcn33_1_name) != 0) {
+ _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL);
+ if (!_desc)
+ return -ENOMEM;
+
+ memcpy(_desc, desc, sizeof(*_desc));
+ _desc->supply_name = vcn33_1_name;
+ desc = _desc;
+ }
+
+ /* Use vcn33_2's actual name as supply_name for vcn33_2_(bt|wifi) */
+ if ((i == MT6359_ID_VCN33_2_BT || i == MT6359_ID_VCN33_2_WIFI) &&
+ strcmp(desc->supply_name, vcn33_2_name) != 0) {
+ _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL);
+ if (!_desc)
+ return -ENOMEM;
+
+ memcpy(_desc, desc, sizeof(*_desc));
+ _desc->supply_name = vcn33_2_name;
+ desc = _desc;
+ }
+
rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name);
@@ -1002,6 +1116,14 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
/* Save vio18 name for vbbck */
if (i == MT6359_ID_VIO18)
vio18_name = rdev_get_name(rdev);
+
+ /* Save vcn33_1 name for vbbck */
+ if (i == MT6359_ID_VCN33_1)
+ vcn33_1_name = rdev_get_name(rdev);
+
+ /* Save vcn33_2 name for vbbck */
+ if (i == MT6359_ID_VCN33_2)
+ vcn33_2_name = rdev_get_name(rdev);
}
return 0;
diff --git a/include/linux/regulator/mt6359-regulator.h b/include/linux/regulator/mt6359-regulator.h
index 6d6e5a58f482..ce2cd0fc9d95 100644
--- a/include/linux/regulator/mt6359-regulator.h
+++ b/include/linux/regulator/mt6359-regulator.h
@@ -29,8 +29,7 @@ enum {
MT6359_ID_VCN18,
MT6359_ID_VFE28,
MT6359_ID_VCN13,
- MT6359_ID_VCN33_1_BT,
- MT6359_ID_VCN33_1_WIFI,
+ MT6359_ID_VCN33_1,
MT6359_ID_VAUX18,
MT6359_ID_VSRAM_OTHERS,
MT6359_ID_VEFUSE,
@@ -39,8 +38,7 @@ enum {
MT6359_ID_VBIF28,
MT6359_ID_VIO28,
MT6359_ID_VEMC,
- MT6359_ID_VCN33_2_BT,
- MT6359_ID_VCN33_2_WIFI,
+ MT6359_ID_VCN33_2,
MT6359_ID_VA12,
MT6359_ID_VA09,
MT6359_ID_VRF18,
@@ -51,6 +49,10 @@ enum {
MT6359_ID_VSRAM_PROC1,
MT6359_ID_VSIM2,
MT6359_ID_VSRAM_OTHERS_SSHUB,
+ MT6359_ID_VCN33_1_BT,
+ MT6359_ID_VCN33_1_WIFI,
+ MT6359_ID_VCN33_2_BT,
+ MT6359_ID_VCN33_2_WIFI,
MT6359_ID_RG_MAX,
};
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v4 5/6] regulator: mt6359: Add regulator supply names
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree
In-Reply-To: <20260514091520.2718987-1-wenst@chromium.org>
The MT6359 regulator DT binding defines the supply names for the PMIC.
Add support for them by adding .supply_name field settings for each
regulator. The buck regulators each have their own supply. The name
of the supply is related to the name of the buck regulator. The LDOs
have shared supplies.
Add the supply name to the declaration of each regulator. At the moment
they are declared explicitly, but the buck regulator macro can be made
to derive both the match string and supply name from the base name once
the *_sshub regulators are figured out and removed. For context, the
*_sshub regulators are not separate regulators, but separate settings
for the same name regulators without the "_sshub" suffix.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Changes since v3:
- Changed vbbck's supply name to 'VIO18' to match vio18's default name
(Sashiko)
Changes since v1:
- Handle vbbck's supply internally
---
drivers/regulator/mt6359-regulator.c | 220 +++++++++++++++------------
1 file changed, 125 insertions(+), 95 deletions(-)
diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c
index bcf9a476a34e..46cafe93b24e 100644
--- a/drivers/regulator/mt6359-regulator.c
+++ b/drivers/regulator/mt6359-regulator.c
@@ -38,7 +38,7 @@ struct mt6359_regulator_info {
u32 lp_mode_mask;
};
-#define MT6359_BUCK(match, _name, min, max, step, \
+#define MT6359_BUCK(match, _name, supply, min, max, step, \
_enable_reg, _status_reg, \
_vsel_reg, _vsel_mask, \
_lp_mode_reg, _lp_mode_shift, \
@@ -46,6 +46,7 @@ struct mt6359_regulator_info {
[MT6359_ID_##_name] = { \
.desc = { \
.name = #_name, \
+ .supply_name = supply, \
.of_match = of_match_ptr(match), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &mt6359_volt_linear_ops, \
@@ -69,11 +70,12 @@ struct mt6359_regulator_info {
.modeset_mask = BIT(_modeset_shift), \
}
-#define MT6359_LDO_LINEAR(match, _name, min, max, step, \
+#define MT6359_LDO_LINEAR(match, _name, supply, min, max, step, \
_enable_reg, _status_reg, _vsel_reg, _vsel_mask) \
[MT6359_ID_##_name] = { \
.desc = { \
.name = #_name, \
+ .supply_name = supply, \
.of_match = of_match_ptr(match), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &mt6359_volt_linear_ops, \
@@ -92,12 +94,13 @@ struct mt6359_regulator_info {
.qi = BIT(0), \
}
-#define MT6359_LDO(match, _name, _volt_table, \
+#define MT6359_LDO(match, _name, supply, _volt_table, \
_enable_reg, _enable_mask, _status_reg, \
_vsel_reg, _vsel_mask, _en_delay) \
[MT6359_ID_##_name] = { \
.desc = { \
.name = #_name, \
+ .supply_name = supply, \
.of_match = of_match_ptr(match), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &mt6359_volt_table_ops, \
@@ -116,11 +119,13 @@ struct mt6359_regulator_info {
.qi = BIT(0), \
}
-#define MT6359_REG_FIXED(match, _name, _enable_reg, \
- _status_reg, _fixed_volt) \
+#define MT6359_REG_FIXED(match, _name, supply, \
+ _enable_reg, _status_reg, \
+ _fixed_volt) \
[MT6359_ID_##_name] = { \
.desc = { \
.name = #_name, \
+ .supply_name = supply, \
.of_match = of_match_ptr(match), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &mt6359_volt_fixed_ops, \
@@ -136,12 +141,14 @@ struct mt6359_regulator_info {
.qi = BIT(0), \
}
-#define MT6359P_LDO1(match, _name, _ops, _volt_table, \
- _enable_reg, _enable_mask, _status_reg, \
- _vsel_reg, _vsel_mask) \
+#define MT6359P_LDO1(match, _name, supply, _ops, \
+ _volt_table, _enable_reg, \
+ _enable_mask, _status_reg, \
+ _vsel_reg, _vsel_mask) \
[MT6359_ID_##_name] = { \
.desc = { \
.name = #_name, \
+ .supply_name = supply, \
.of_match = of_match_ptr(match), \
.regulators_node = of_match_ptr("regulators"), \
.ops = &_ops, \
@@ -470,14 +477,14 @@ static const struct regulator_ops mt6359p_vemc_ops = {
/* The array is indexed by id(MT6359_ID_XXX) */
static const struct mt6359_regulator_info mt6359_regulators[] = {
- MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+ MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500,
MT6359_RG_BUCK_VS1_EN_ADDR,
MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
MT6359_RG_BUCK_VS1_VOSEL_MASK <<
MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
- MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vgpu11", VGPU11, "vsys-vgpu11", 400000, 1193750, 6250,
MT6359_RG_BUCK_VGPU11_EN_ADDR,
MT6359_DA_VGPU11_EN_ADDR, MT6359_RG_BUCK_VGPU11_VOSEL_ADDR,
MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
@@ -485,7 +492,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_BUCK_VGPU11_LP_ADDR,
MT6359_RG_BUCK_VGPU11_LP_SHIFT,
MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
- MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+ MT6359_BUCK("buck_vmodem", VMODEM, "vsys-vmodem", 400000, 1100000, 6250,
MT6359_RG_BUCK_VMODEM_EN_ADDR,
MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
@@ -493,35 +500,35 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_BUCK_VMODEM_LP_ADDR,
MT6359_RG_BUCK_VMODEM_LP_SHIFT,
MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
- MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vpu", VPU, "vsys-vpu", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPU_EN_ADDR,
MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
MT6359_RG_BUCK_VPU_VOSEL_MASK <<
MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
- MT6359_BUCK("buck_vcore", VCORE, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vcore", VCORE, "vsys-vcore", 400000, 1193750, 6250,
MT6359_RG_BUCK_VCORE_EN_ADDR,
MT6359_DA_VCORE_EN_ADDR, MT6359_RG_BUCK_VCORE_VOSEL_ADDR,
MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
- MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+ MT6359_BUCK("buck_vs2", VS2, "vsys-vs2", 800000, 1600000, 12500,
MT6359_RG_BUCK_VS2_EN_ADDR,
MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
MT6359_RG_BUCK_VS2_VOSEL_MASK <<
MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
- MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+ MT6359_BUCK("buck_vpa", VPA, "vsys-vpa", 500000, 3650000, 50000,
MT6359_RG_BUCK_VPA_EN_ADDR,
MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
MT6359_RG_BUCK_VPA_VOSEL_MASK <<
MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
- MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vproc2", VPROC2, "vsys-vproc2", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPROC2_EN_ADDR,
MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
@@ -529,7 +536,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_BUCK_VPROC2_LP_ADDR,
MT6359_RG_BUCK_VPROC2_LP_SHIFT,
MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
- MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vproc1", VPROC1, "vsys-vproc1", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPROC1_EN_ADDR,
MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
@@ -537,7 +544,7 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_BUCK_VPROC1_LP_ADDR,
MT6359_RG_BUCK_VPROC1_LP_SHIFT,
MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
- MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vcore_sshub", VCORE_SSHUB, "vsys-vcore", 400000, 1193750, 6250,
MT6359_RG_BUCK_VCORE_SSHUB_EN_ADDR,
MT6359_DA_VCORE_EN_ADDR,
MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_ADDR,
@@ -545,158 +552,159 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
MT6359_RG_BUCK_VCORE_SSHUB_VOSEL_SHIFT,
MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
- MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359_RG_LDO_VAUD18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vaud18", VAUD18, "vs1-ldo1", MT6359_RG_LDO_VAUD18_EN_ADDR,
MT6359_DA_VAUD18_B_EN_ADDR, 1800000),
- MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+ MT6359_LDO("ldo_vsim1", VSIM1, "vsys-ldo2", vsim1_voltages,
MT6359_RG_LDO_VSIM1_EN_ADDR, MT6359_RG_LDO_VSIM1_EN_SHIFT,
MT6359_DA_VSIM1_B_EN_ADDR, MT6359_RG_VSIM1_VOSEL_ADDR,
MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
480),
- MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+ MT6359_LDO("ldo_vibr", VIBR, "vsys-ldo1", vibr_voltages,
MT6359_RG_LDO_VIBR_EN_ADDR, MT6359_RG_LDO_VIBR_EN_SHIFT,
MT6359_DA_VIBR_B_EN_ADDR, MT6359_RG_VIBR_VOSEL_ADDR,
MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+ MT6359_LDO("ldo_vrf12", VRF12, "vs2-ldo2", vrf12_voltages,
MT6359_RG_LDO_VRF12_EN_ADDR, MT6359_RG_LDO_VRF12_EN_SHIFT,
MT6359_DA_VRF12_B_EN_ADDR, MT6359_RG_VRF12_VOSEL_ADDR,
MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
120),
- MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359_RG_LDO_VUSB_EN_0_ADDR,
+ MT6359_REG_FIXED("ldo_vusb", VUSB, "vsys-ldo2", MT6359_RG_LDO_VUSB_EN_0_ADDR,
MT6359_DA_VUSB_B_EN_ADDR, 3000000),
- MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, "vs2-ldo1", 500000, 1293750, 6250,
MT6359_RG_LDO_VSRAM_PROC2_EN_ADDR,
MT6359_DA_VSRAM_PROC2_B_EN_ADDR,
MT6359_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
- MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+ MT6359_LDO("ldo_vio18", VIO18, "vs1-ldo2", volt18_voltages,
MT6359_RG_LDO_VIO18_EN_ADDR, MT6359_RG_LDO_VIO18_EN_SHIFT,
MT6359_DA_VIO18_B_EN_ADDR, MT6359_RG_VIO18_VOSEL_ADDR,
MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
960),
- MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+ MT6359_LDO("ldo_vcamio", VCAMIO, "vs1-ldo1", volt18_voltages,
MT6359_RG_LDO_VCAMIO_EN_ADDR, MT6359_RG_LDO_VCAMIO_EN_SHIFT,
MT6359_DA_VCAMIO_B_EN_ADDR, MT6359_RG_VCAMIO_VOSEL_ADDR,
MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
1290),
- MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359_RG_LDO_VCN18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vcn18", VCN18, "vs1-ldo2", MT6359_RG_LDO_VCN18_EN_ADDR,
MT6359_DA_VCN18_B_EN_ADDR, 1800000),
- MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359_RG_LDO_VFE28_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vfe28", VFE28, "vsys-ldo1", MT6359_RG_LDO_VFE28_EN_ADDR,
MT6359_DA_VFE28_B_EN_ADDR, 2800000),
- MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+ MT6359_LDO("ldo_vcn13", VCN13, "vs2-ldo2", vcn13_voltages,
MT6359_RG_LDO_VCN13_EN_ADDR, MT6359_RG_LDO_VCN13_EN_SHIFT,
MT6359_DA_VCN13_B_EN_ADDR, MT6359_RG_VCN13_VOSEL_ADDR,
MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_1_EN_0_ADDR,
MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_1_EN_1_ADDR,
MT6359_RG_LDO_VCN33_1_EN_1_SHIFT,
MT6359_DA_VCN33_1_B_EN_ADDR, MT6359_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359_RG_LDO_VAUX18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359_RG_LDO_VAUX18_EN_ADDR,
MT6359_DA_VAUX18_B_EN_ADDR, 1800000),
- MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+ MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750,
6250,
MT6359_RG_LDO_VSRAM_OTHERS_EN_ADDR,
MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
- MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+ MT6359_LDO("ldo_vefuse", VEFUSE, "vs1-ldo2", vefuse_voltages,
MT6359_RG_LDO_VEFUSE_EN_ADDR, MT6359_RG_LDO_VEFUSE_EN_SHIFT,
MT6359_DA_VEFUSE_B_EN_ADDR, MT6359_RG_VEFUSE_VOSEL_ADDR,
MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+ MT6359_LDO("ldo_vxo22", VXO22, "vsys-ldo2", vxo22_voltages,
MT6359_RG_LDO_VXO22_EN_ADDR, MT6359_RG_LDO_VXO22_EN_SHIFT,
MT6359_DA_VXO22_B_EN_ADDR, MT6359_RG_VXO22_VOSEL_ADDR,
MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
120),
- MT6359_LDO("ldo_vrfck", VRFCK, vrfck_voltages,
+ MT6359_LDO("ldo_vrfck", VRFCK, "vsys-ldo2", vrfck_voltages,
MT6359_RG_LDO_VRFCK_EN_ADDR, MT6359_RG_LDO_VRFCK_EN_SHIFT,
MT6359_DA_VRFCK_B_EN_ADDR, MT6359_RG_VRFCK_VOSEL_ADDR,
MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
480),
- MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359_RG_LDO_VBIF28_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vbif28", VBIF28, "vsys-ldo2", MT6359_RG_LDO_VBIF28_EN_ADDR,
MT6359_DA_VBIF28_B_EN_ADDR, 2800000),
- MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+ MT6359_LDO("ldo_vio28", VIO28, "vsys-ldo2", vio28_voltages,
MT6359_RG_LDO_VIO28_EN_ADDR, MT6359_RG_LDO_VIO28_EN_SHIFT,
MT6359_DA_VIO28_B_EN_ADDR, MT6359_RG_VIO28_VOSEL_ADDR,
MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vemc", VEMC, vemc_voltages,
+ MT6359_LDO("ldo_vemc", VEMC, "vsys-ldo2", vemc_voltages,
MT6359_RG_LDO_VEMC_EN_ADDR, MT6359_RG_LDO_VEMC_EN_SHIFT,
MT6359_DA_VEMC_B_EN_ADDR, MT6359_RG_VEMC_VOSEL_ADDR,
MT6359_RG_VEMC_VOSEL_MASK << MT6359_RG_VEMC_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_2_EN_0_ADDR,
MT6359_RG_LDO_VCN33_2_EN_0_SHIFT,
MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages,
MT6359_RG_LDO_VCN33_2_EN_1_ADDR,
MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
MT6359_DA_VCN33_2_B_EN_ADDR, MT6359_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_va12", VA12, va12_voltages,
+ MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages,
MT6359_RG_LDO_VA12_EN_ADDR, MT6359_RG_LDO_VA12_EN_SHIFT,
MT6359_DA_VA12_B_EN_ADDR, MT6359_RG_VA12_VOSEL_ADDR,
MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_va09", VA09, va09_voltages,
+ MT6359_LDO("ldo_va09", VA09, "vs2-ldo2", va09_voltages,
MT6359_RG_LDO_VA09_EN_ADDR, MT6359_RG_LDO_VA09_EN_SHIFT,
MT6359_DA_VA09_B_EN_ADDR, MT6359_RG_VA09_VOSEL_ADDR,
MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+ MT6359_LDO("ldo_vrf18", VRF18, "vs1-ldo2", vrf18_voltages,
MT6359_RG_LDO_VRF18_EN_ADDR, MT6359_RG_LDO_VRF18_EN_SHIFT,
MT6359_DA_VRF18_B_EN_ADDR, MT6359_RG_VRF18_VOSEL_ADDR,
MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
120),
- MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1100000, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, "vs2-ldo1", 500000, 1100000, 6250,
MT6359_RG_LDO_VSRAM_MD_EN_ADDR,
MT6359_DA_VSRAM_MD_B_EN_ADDR,
MT6359_RG_LDO_VSRAM_MD_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
- MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+ MT6359_LDO("ldo_vufs", VUFS, "vs1-ldo1", volt18_voltages,
MT6359_RG_LDO_VUFS_EN_ADDR, MT6359_RG_LDO_VUFS_EN_SHIFT,
MT6359_DA_VUFS_B_EN_ADDR, MT6359_RG_VUFS_VOSEL_ADDR,
MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
1920),
- MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+ MT6359_LDO("ldo_vm18", VM18, "vs1-ldo1", volt18_voltages,
MT6359_RG_LDO_VM18_EN_ADDR, MT6359_RG_LDO_VM18_EN_SHIFT,
MT6359_DA_VM18_B_EN_ADDR, MT6359_RG_VM18_VOSEL_ADDR,
MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
1920),
- MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+ /* vbbck is fed from vio18 internally. */
+ MT6359_LDO("ldo_vbbck", VBBCK, "VIO18", vbbck_voltages,
MT6359_RG_LDO_VBBCK_EN_ADDR, MT6359_RG_LDO_VBBCK_EN_SHIFT,
MT6359_DA_VBBCK_B_EN_ADDR, MT6359_RG_VBBCK_VOSEL_ADDR,
MT6359_RG_VBBCK_VOSEL_MASK << MT6359_RG_VBBCK_VOSEL_SHIFT,
240),
- MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, "vs2-ldo1", 500000, 1293750, 6250,
MT6359_RG_LDO_VSRAM_PROC1_EN_ADDR,
MT6359_DA_VSRAM_PROC1_B_EN_ADDR,
MT6359_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
- MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+ MT6359_LDO("ldo_vsim2", VSIM2, "vsys-ldo2", vsim2_voltages,
MT6359_RG_LDO_VSIM2_EN_ADDR, MT6359_RG_LDO_VSIM2_EN_SHIFT,
MT6359_DA_VSIM2_B_EN_ADDR, MT6359_RG_VSIM2_VOSEL_ADDR,
MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
480),
- MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+ MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, "vs2-ldo1",
500000, 1293750, 6250,
MT6359_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
MT6359_DA_VSRAM_OTHERS_B_EN_ADDR,
@@ -706,14 +714,14 @@ static const struct mt6359_regulator_info mt6359_regulators[] = {
};
static const struct mt6359_regulator_info mt6359p_regulators[] = {
- MT6359_BUCK("buck_vs1", VS1, 800000, 2200000, 12500,
+ MT6359_BUCK("buck_vs1", VS1, "vsys-vs1", 800000, 2200000, 12500,
MT6359_RG_BUCK_VS1_EN_ADDR,
MT6359_DA_VS1_EN_ADDR, MT6359_RG_BUCK_VS1_VOSEL_ADDR,
MT6359_RG_BUCK_VS1_VOSEL_MASK <<
MT6359_RG_BUCK_VS1_VOSEL_SHIFT,
MT6359_RG_BUCK_VS1_LP_ADDR, MT6359_RG_BUCK_VS1_LP_SHIFT,
MT6359_RG_VS1_FPWM_ADDR, MT6359_RG_VS1_FPWM_SHIFT),
- MT6359_BUCK("buck_vgpu11", VGPU11, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vgpu11", VGPU11, "vsys-vgpu11", 400000, 1193750, 6250,
MT6359_RG_BUCK_VGPU11_EN_ADDR,
MT6359_DA_VGPU11_EN_ADDR, MT6359P_RG_BUCK_VGPU11_VOSEL_ADDR,
MT6359_RG_BUCK_VGPU11_VOSEL_MASK <<
@@ -721,7 +729,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_RG_BUCK_VGPU11_LP_ADDR,
MT6359_RG_BUCK_VGPU11_LP_SHIFT,
MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
- MT6359_BUCK("buck_vmodem", VMODEM, 400000, 1100000, 6250,
+ MT6359_BUCK("buck_vmodem", VMODEM, "vsys-vmodem", 400000, 1100000, 6250,
MT6359_RG_BUCK_VMODEM_EN_ADDR,
MT6359_DA_VMODEM_EN_ADDR, MT6359_RG_BUCK_VMODEM_VOSEL_ADDR,
MT6359_RG_BUCK_VMODEM_VOSEL_MASK <<
@@ -729,35 +737,35 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_RG_BUCK_VMODEM_LP_ADDR,
MT6359_RG_BUCK_VMODEM_LP_SHIFT,
MT6359_RG_VMODEM_FCCM_ADDR, MT6359_RG_VMODEM_FCCM_SHIFT),
- MT6359_BUCK("buck_vpu", VPU, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vpu", VPU, "vsys-vpu", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPU_EN_ADDR,
MT6359_DA_VPU_EN_ADDR, MT6359_RG_BUCK_VPU_VOSEL_ADDR,
MT6359_RG_BUCK_VPU_VOSEL_MASK <<
MT6359_RG_BUCK_VPU_VOSEL_SHIFT,
MT6359_RG_BUCK_VPU_LP_ADDR, MT6359_RG_BUCK_VPU_LP_SHIFT,
MT6359_RG_VPU_FCCM_ADDR, MT6359_RG_VPU_FCCM_SHIFT),
- MT6359_BUCK("buck_vcore", VCORE, 506250, 1300000, 6250,
+ MT6359_BUCK("buck_vcore", VCORE, "vsys-vcore", 506250, 1300000, 6250,
MT6359_RG_BUCK_VCORE_EN_ADDR,
MT6359_DA_VCORE_EN_ADDR, MT6359P_RG_BUCK_VCORE_VOSEL_ADDR,
MT6359_RG_BUCK_VCORE_VOSEL_MASK <<
MT6359_RG_BUCK_VCORE_VOSEL_SHIFT,
MT6359_RG_BUCK_VCORE_LP_ADDR, MT6359_RG_BUCK_VCORE_LP_SHIFT,
MT6359_RG_VCORE_FCCM_ADDR, MT6359_RG_VCORE_FCCM_SHIFT),
- MT6359_BUCK("buck_vs2", VS2, 800000, 1600000, 12500,
+ MT6359_BUCK("buck_vs2", VS2, "vsys-vs2", 800000, 1600000, 12500,
MT6359_RG_BUCK_VS2_EN_ADDR,
MT6359_DA_VS2_EN_ADDR, MT6359_RG_BUCK_VS2_VOSEL_ADDR,
MT6359_RG_BUCK_VS2_VOSEL_MASK <<
MT6359_RG_BUCK_VS2_VOSEL_SHIFT,
MT6359_RG_BUCK_VS2_LP_ADDR, MT6359_RG_BUCK_VS2_LP_SHIFT,
MT6359_RG_VS2_FPWM_ADDR, MT6359_RG_VS2_FPWM_SHIFT),
- MT6359_BUCK("buck_vpa", VPA, 500000, 3650000, 50000,
+ MT6359_BUCK("buck_vpa", VPA, "vsys-vpa", 500000, 3650000, 50000,
MT6359_RG_BUCK_VPA_EN_ADDR,
MT6359_DA_VPA_EN_ADDR, MT6359_RG_BUCK_VPA_VOSEL_ADDR,
MT6359_RG_BUCK_VPA_VOSEL_MASK <<
MT6359_RG_BUCK_VPA_VOSEL_SHIFT,
MT6359_RG_BUCK_VPA_LP_ADDR, MT6359_RG_BUCK_VPA_LP_SHIFT,
MT6359_RG_VPA_MODESET_ADDR, MT6359_RG_VPA_MODESET_SHIFT),
- MT6359_BUCK("buck_vproc2", VPROC2, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vproc2", VPROC2, "vsys-vproc2", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPROC2_EN_ADDR,
MT6359_DA_VPROC2_EN_ADDR, MT6359_RG_BUCK_VPROC2_VOSEL_ADDR,
MT6359_RG_BUCK_VPROC2_VOSEL_MASK <<
@@ -765,7 +773,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_RG_BUCK_VPROC2_LP_ADDR,
MT6359_RG_BUCK_VPROC2_LP_SHIFT,
MT6359_RG_VPROC2_FCCM_ADDR, MT6359_RG_VPROC2_FCCM_SHIFT),
- MT6359_BUCK("buck_vproc1", VPROC1, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vproc1", VPROC1, "vsys-vproc1", 400000, 1193750, 6250,
MT6359_RG_BUCK_VPROC1_EN_ADDR,
MT6359_DA_VPROC1_EN_ADDR, MT6359_RG_BUCK_VPROC1_VOSEL_ADDR,
MT6359_RG_BUCK_VPROC1_VOSEL_MASK <<
@@ -773,7 +781,7 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_RG_BUCK_VPROC1_LP_ADDR,
MT6359_RG_BUCK_VPROC1_LP_SHIFT,
MT6359_RG_VPROC1_FCCM_ADDR, MT6359_RG_VPROC1_FCCM_SHIFT),
- MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, 400000, 1193750, 6250,
+ MT6359_BUCK("buck_vgpu11_sshub", VGPU11_SSHUB, "vsys-vgpu11", 400000, 1193750, 6250,
MT6359P_RG_BUCK_VGPU11_SSHUB_EN_ADDR,
MT6359_DA_VGPU11_EN_ADDR,
MT6359P_RG_BUCK_VGPU11_SSHUB_VOSEL_ADDR,
@@ -782,161 +790,161 @@ static const struct mt6359_regulator_info mt6359p_regulators[] = {
MT6359_RG_BUCK_VGPU11_LP_ADDR,
MT6359_RG_BUCK_VGPU11_LP_SHIFT,
MT6359_RG_VGPU11_FCCM_ADDR, MT6359_RG_VGPU11_FCCM_SHIFT),
- MT6359_REG_FIXED("ldo_vaud18", VAUD18, MT6359P_RG_LDO_VAUD18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vaud18", VAUD18, "vs1-ldo1", MT6359P_RG_LDO_VAUD18_EN_ADDR,
MT6359P_DA_VAUD18_B_EN_ADDR, 1800000),
- MT6359_LDO("ldo_vsim1", VSIM1, vsim1_voltages,
+ MT6359_LDO("ldo_vsim1", VSIM1, "vsys-ldo2", vsim1_voltages,
MT6359P_RG_LDO_VSIM1_EN_ADDR, MT6359P_RG_LDO_VSIM1_EN_SHIFT,
MT6359P_DA_VSIM1_B_EN_ADDR, MT6359P_RG_VSIM1_VOSEL_ADDR,
MT6359_RG_VSIM1_VOSEL_MASK << MT6359_RG_VSIM1_VOSEL_SHIFT,
480),
- MT6359_LDO("ldo_vibr", VIBR, vibr_voltages,
+ MT6359_LDO("ldo_vibr", VIBR, "vsys-ldo1", vibr_voltages,
MT6359P_RG_LDO_VIBR_EN_ADDR, MT6359P_RG_LDO_VIBR_EN_SHIFT,
MT6359P_DA_VIBR_B_EN_ADDR, MT6359P_RG_VIBR_VOSEL_ADDR,
MT6359_RG_VIBR_VOSEL_MASK << MT6359_RG_VIBR_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vrf12", VRF12, vrf12_voltages,
+ MT6359_LDO("ldo_vrf12", VRF12, "vs2-ldo2", vrf12_voltages,
MT6359P_RG_LDO_VRF12_EN_ADDR, MT6359P_RG_LDO_VRF12_EN_SHIFT,
MT6359P_DA_VRF12_B_EN_ADDR, MT6359P_RG_VRF12_VOSEL_ADDR,
MT6359_RG_VRF12_VOSEL_MASK << MT6359_RG_VRF12_VOSEL_SHIFT,
480),
- MT6359_REG_FIXED("ldo_vusb", VUSB, MT6359P_RG_LDO_VUSB_EN_0_ADDR,
+ MT6359_REG_FIXED("ldo_vusb", VUSB, "vsys-ldo2", MT6359P_RG_LDO_VUSB_EN_0_ADDR,
MT6359P_DA_VUSB_B_EN_ADDR, 3000000),
- MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, 500000, 1293750, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_proc2", VSRAM_PROC2, "vs2-ldo1", 500000, 1293750, 6250,
MT6359P_RG_LDO_VSRAM_PROC2_EN_ADDR,
MT6359P_DA_VSRAM_PROC2_B_EN_ADDR,
MT6359P_RG_LDO_VSRAM_PROC2_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_PROC2_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_PROC2_VOSEL_SHIFT),
- MT6359_LDO("ldo_vio18", VIO18, volt18_voltages,
+ MT6359_LDO("ldo_vio18", VIO18, "vs1-ldo2", volt18_voltages,
MT6359P_RG_LDO_VIO18_EN_ADDR, MT6359P_RG_LDO_VIO18_EN_SHIFT,
MT6359P_DA_VIO18_B_EN_ADDR, MT6359P_RG_VIO18_VOSEL_ADDR,
MT6359_RG_VIO18_VOSEL_MASK << MT6359_RG_VIO18_VOSEL_SHIFT,
960),
- MT6359_LDO("ldo_vcamio", VCAMIO, volt18_voltages,
+ MT6359_LDO("ldo_vcamio", VCAMIO, "vs1-ldo1", volt18_voltages,
MT6359P_RG_LDO_VCAMIO_EN_ADDR,
MT6359P_RG_LDO_VCAMIO_EN_SHIFT,
MT6359P_DA_VCAMIO_B_EN_ADDR, MT6359P_RG_VCAMIO_VOSEL_ADDR,
MT6359_RG_VCAMIO_VOSEL_MASK << MT6359_RG_VCAMIO_VOSEL_SHIFT,
1290),
- MT6359_REG_FIXED("ldo_vcn18", VCN18, MT6359P_RG_LDO_VCN18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vcn18", VCN18, "vs1-ldo2", MT6359P_RG_LDO_VCN18_EN_ADDR,
MT6359P_DA_VCN18_B_EN_ADDR, 1800000),
- MT6359_REG_FIXED("ldo_vfe28", VFE28, MT6359P_RG_LDO_VFE28_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vfe28", VFE28, "vsys-ldo1", MT6359P_RG_LDO_VFE28_EN_ADDR,
MT6359P_DA_VFE28_B_EN_ADDR, 2800000),
- MT6359_LDO("ldo_vcn13", VCN13, vcn13_voltages,
+ MT6359_LDO("ldo_vcn13", VCN13, "vs2-ldo2", vcn13_voltages,
MT6359P_RG_LDO_VCN13_EN_ADDR, MT6359P_RG_LDO_VCN13_EN_SHIFT,
MT6359P_DA_VCN13_B_EN_ADDR, MT6359P_RG_VCN13_VOSEL_ADDR,
MT6359_RG_VCN13_VOSEL_MASK << MT6359_RG_VCN13_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1_bt", VCN33_1_BT, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_1_EN_0_ADDR,
MT6359_RG_LDO_VCN33_1_EN_0_SHIFT,
MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_1_wifi", VCN33_1_WIFI, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_1_EN_1_ADDR,
MT6359P_RG_LDO_VCN33_1_EN_1_SHIFT,
MT6359P_DA_VCN33_1_B_EN_ADDR, MT6359P_RG_VCN33_1_VOSEL_ADDR,
MT6359_RG_VCN33_1_VOSEL_MASK <<
MT6359_RG_VCN33_1_VOSEL_SHIFT, 240),
- MT6359_REG_FIXED("ldo_vaux18", VAUX18, MT6359P_RG_LDO_VAUX18_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vaux18", VAUX18, "vsys-ldo2", MT6359P_RG_LDO_VAUX18_EN_ADDR,
MT6359P_DA_VAUX18_B_EN_ADDR, 1800000),
- MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750,
+ MT6359_LDO_LINEAR("ldo_vsram_others", VSRAM_OTHERS, "vs2-ldo1", 500000, 1293750,
6250,
MT6359P_RG_LDO_VSRAM_OTHERS_EN_ADDR,
MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
MT6359P_RG_LDO_VSRAM_OTHERS_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_OTHERS_VOSEL_SHIFT),
- MT6359_LDO("ldo_vefuse", VEFUSE, vefuse_voltages,
+ MT6359_LDO("ldo_vefuse", VEFUSE, "vs1-ldo2", vefuse_voltages,
MT6359P_RG_LDO_VEFUSE_EN_ADDR,
MT6359P_RG_LDO_VEFUSE_EN_SHIFT,
MT6359P_DA_VEFUSE_B_EN_ADDR, MT6359P_RG_VEFUSE_VOSEL_ADDR,
MT6359_RG_VEFUSE_VOSEL_MASK << MT6359_RG_VEFUSE_VOSEL_SHIFT,
240),
- MT6359_LDO("ldo_vxo22", VXO22, vxo22_voltages,
+ MT6359_LDO("ldo_vxo22", VXO22, "vsys-ldo2", vxo22_voltages,
MT6359P_RG_LDO_VXO22_EN_ADDR, MT6359P_RG_LDO_VXO22_EN_SHIFT,
MT6359P_DA_VXO22_B_EN_ADDR, MT6359P_RG_VXO22_VOSEL_ADDR,
MT6359_RG_VXO22_VOSEL_MASK << MT6359_RG_VXO22_VOSEL_SHIFT,
480),
- MT6359_LDO("ldo_vrfck_1", VRFCK, vrfck_voltages_1,
+ MT6359_LDO("ldo_vrfck_1", VRFCK, "vsys-ldo2", vrfck_voltages_1,
MT6359P_RG_LDO_VRFCK_EN_ADDR, MT6359P_RG_LDO_VRFCK_EN_SHIFT,
MT6359P_DA_VRFCK_B_EN_ADDR, MT6359P_RG_VRFCK_VOSEL_ADDR,
MT6359_RG_VRFCK_VOSEL_MASK << MT6359_RG_VRFCK_VOSEL_SHIFT,
480),
- MT6359_REG_FIXED("ldo_vbif28", VBIF28, MT6359P_RG_LDO_VBIF28_EN_ADDR,
+ MT6359_REG_FIXED("ldo_vbif28", VBIF28, "vsys-ldo2", MT6359P_RG_LDO_VBIF28_EN_ADDR,
MT6359P_DA_VBIF28_B_EN_ADDR, 2800000),
- MT6359_LDO("ldo_vio28", VIO28, vio28_voltages,
+ MT6359_LDO("ldo_vio28", VIO28, "vsys-ldo2", vio28_voltages,
MT6359P_RG_LDO_VIO28_EN_ADDR, MT6359P_RG_LDO_VIO28_EN_SHIFT,
MT6359P_DA_VIO28_B_EN_ADDR, MT6359P_RG_VIO28_VOSEL_ADDR,
MT6359_RG_VIO28_VOSEL_MASK << MT6359_RG_VIO28_VOSEL_SHIFT,
1920),
- MT6359P_LDO1("ldo_vemc_1", VEMC, mt6359p_vemc_ops, vemc_voltages_1,
+ MT6359P_LDO1("ldo_vemc_1", VEMC, "vsys-ldo2", mt6359p_vemc_ops, vemc_voltages_1,
MT6359P_RG_LDO_VEMC_EN_ADDR, MT6359P_RG_LDO_VEMC_EN_SHIFT,
MT6359P_DA_VEMC_B_EN_ADDR,
MT6359P_RG_LDO_VEMC_VOSEL_0_ADDR,
MT6359P_RG_LDO_VEMC_VOSEL_0_MASK <<
MT6359P_RG_LDO_VEMC_VOSEL_0_SHIFT),
- MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2_bt", VCN33_2_BT, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_2_EN_0_ADDR,
MT6359P_RG_LDO_VCN33_2_EN_0_SHIFT,
MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, vcn33_voltages,
+ MT6359_LDO("ldo_vcn33_2_wifi", VCN33_2_WIFI, "vsys-ldo1", vcn33_voltages,
MT6359P_RG_LDO_VCN33_2_EN_1_ADDR,
MT6359_RG_LDO_VCN33_2_EN_1_SHIFT,
MT6359P_DA_VCN33_2_B_EN_ADDR, MT6359P_RG_VCN33_2_VOSEL_ADDR,
MT6359_RG_VCN33_2_VOSEL_MASK <<
MT6359_RG_VCN33_2_VOSEL_SHIFT, 240),
- MT6359_LDO("ldo_va12", VA12, va12_voltages,
+ MT6359_LDO("ldo_va12", VA12, "vs2-ldo2", va12_voltages,
MT6359P_RG_LDO_VA12_EN_ADDR, MT6359P_RG_LDO_VA12_EN_SHIFT,
MT6359P_DA_VA12_B_EN_ADDR, MT6359P_RG_VA12_VOSEL_ADDR,
MT6359_RG_VA12_VOSEL_MASK << MT6359_RG_VA12_VOSEL_SHIFT,
960),
- MT6359_LDO("ldo_va09", VA09, va09_voltages,
+ MT6359_LDO("ldo_va09", VA09, "vs2-ldo2", va09_voltages,
MT6359P_RG_LDO_VA09_EN_ADDR, MT6359P_RG_LDO_VA09_EN_SHIFT,
MT6359P_DA_VA09_B_EN_ADDR, MT6359P_RG_VA09_VOSEL_ADDR,
MT6359_RG_VA09_VOSEL_MASK << MT6359_RG_VA09_VOSEL_SHIFT,
960),
- MT6359_LDO("ldo_vrf18", VRF18, vrf18_voltages,
+ MT6359_LDO("ldo_vrf18", VRF18, "vs1-ldo2", vrf18_voltages,
MT6359P_RG_LDO_VRF18_EN_ADDR, MT6359P_RG_LDO_VRF18_EN_SHIFT,
MT6359P_DA_VRF18_B_EN_ADDR, MT6359P_RG_VRF18_VOSEL_ADDR,
MT6359_RG_VRF18_VOSEL_MASK << MT6359_RG_VRF18_VOSEL_SHIFT,
240),
- MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, 500000, 1293750, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_md", VSRAM_MD, "vs2-ldo1", 500000, 1293750, 6250,
MT6359P_RG_LDO_VSRAM_MD_EN_ADDR,
MT6359P_DA_VSRAM_MD_B_EN_ADDR,
MT6359P_RG_LDO_VSRAM_MD_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_MD_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_MD_VOSEL_SHIFT),
- MT6359_LDO("ldo_vufs", VUFS, volt18_voltages,
+ MT6359_LDO("ldo_vufs", VUFS, "vs1-ldo1", volt18_voltages,
MT6359P_RG_LDO_VUFS_EN_ADDR, MT6359P_RG_LDO_VUFS_EN_SHIFT,
MT6359P_DA_VUFS_B_EN_ADDR, MT6359P_RG_VUFS_VOSEL_ADDR,
MT6359_RG_VUFS_VOSEL_MASK << MT6359_RG_VUFS_VOSEL_SHIFT,
1920),
- MT6359_LDO("ldo_vm18", VM18, volt18_voltages,
+ MT6359_LDO("ldo_vm18", VM18, "vs1-ldo1", volt18_voltages,
MT6359P_RG_LDO_VM18_EN_ADDR, MT6359P_RG_LDO_VM18_EN_SHIFT,
MT6359P_DA_VM18_B_EN_ADDR, MT6359P_RG_VM18_VOSEL_ADDR,
MT6359_RG_VM18_VOSEL_MASK << MT6359_RG_VM18_VOSEL_SHIFT,
1920),
- MT6359_LDO("ldo_vbbck", VBBCK, vbbck_voltages,
+ MT6359_LDO("ldo_vbbck", VBBCK, "LDO_VIO18", vbbck_voltages,
MT6359P_RG_LDO_VBBCK_EN_ADDR, MT6359P_RG_LDO_VBBCK_EN_SHIFT,
MT6359P_DA_VBBCK_B_EN_ADDR, MT6359P_RG_VBBCK_VOSEL_ADDR,
MT6359P_RG_VBBCK_VOSEL_MASK << MT6359P_RG_VBBCK_VOSEL_SHIFT,
480),
- MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, 500000, 1293750, 6250,
+ MT6359_LDO_LINEAR("ldo_vsram_proc1", VSRAM_PROC1, "vs2-ldo1", 500000, 1293750, 6250,
MT6359P_RG_LDO_VSRAM_PROC1_EN_ADDR,
MT6359P_DA_VSRAM_PROC1_B_EN_ADDR,
MT6359P_RG_LDO_VSRAM_PROC1_VOSEL_ADDR,
MT6359_RG_LDO_VSRAM_PROC1_VOSEL_MASK <<
MT6359_RG_LDO_VSRAM_PROC1_VOSEL_SHIFT),
- MT6359_LDO("ldo_vsim2", VSIM2, vsim2_voltages,
+ MT6359_LDO("ldo_vsim2", VSIM2, "vsys-ldo2", vsim2_voltages,
MT6359P_RG_LDO_VSIM2_EN_ADDR, MT6359P_RG_LDO_VSIM2_EN_SHIFT,
MT6359P_DA_VSIM2_B_EN_ADDR, MT6359P_RG_VSIM2_VOSEL_ADDR,
MT6359_RG_VSIM2_VOSEL_MASK << MT6359_RG_VSIM2_VOSEL_SHIFT,
480),
- MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB,
+ MT6359_LDO_LINEAR("ldo_vsram_others_sshub", VSRAM_OTHERS_SSHUB, "vs2-ldo1",
500000, 1293750, 6250,
MT6359P_RG_LDO_VSRAM_OTHERS_SSHUB_EN_ADDR,
MT6359P_DA_VSRAM_OTHERS_B_EN_ADDR,
@@ -951,6 +959,7 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
struct regulator_config config = {};
struct regulator_dev *rdev;
const struct mt6359_regulator_info *mt6359_info;
+ const char *vio18_name;
int i, hw_ver, ret;
ret = regmap_read(mt6397->regmap, MT6359P_HWCID, &hw_ver);
@@ -962,16 +971,37 @@ static int mt6359_regulator_probe(struct platform_device *pdev)
else
mt6359_info = mt6359_regulators;
+ vio18_name = mt6359_info[MT6359_ID_VIO18].desc.name;
+
config.dev = mt6397->dev;
config.regmap = mt6397->regmap;
for (i = 0; i < MT6359_MAX_REGULATOR; i++, mt6359_info++) {
+ const struct regulator_desc *desc = &mt6359_info->desc;
+ struct regulator_desc *_desc;
+
/* drop const here, but all uses in the driver are const */
config.driver_data = (void *)mt6359_info;
- rdev = devm_regulator_register(&pdev->dev, &mt6359_info->desc, &config);
+
+ /* Use vio18's actual name as supply_name for vbbck */
+ if (i == MT6359_ID_VBBCK && strcmp(desc->supply_name, vio18_name) != 0) {
+ _desc = devm_kzalloc(&pdev->dev, sizeof(*_desc), GFP_KERNEL);
+ if (!_desc)
+ return -ENOMEM;
+
+ memcpy(_desc, desc, sizeof(*_desc));
+ _desc->supply_name = vio18_name;
+ desc = _desc;
+ }
+
+ rdev = devm_regulator_register(&pdev->dev, desc, &config);
if (IS_ERR(rdev)) {
dev_err(&pdev->dev, "failed to register %s\n", mt6359_info->desc.name);
return PTR_ERR(rdev);
}
+
+ /* Save vio18 name for vbbck */
+ if (i == MT6359_ID_VIO18)
+ vio18_name = rdev_get_name(rdev);
}
return 0;
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* Re: [PATCH] firmware: arm_ffa: honor descriptor size in PARTITION_INFO_GET_REGS
From: Sudeep Holla @ 2026-05-14 9:16 UTC (permalink / raw)
To: Jamie Nguyen
Cc: linux-arm-kernel@lists.infradead.org, Sudeep Holla,
linux-kernel@vger.kernel.org
In-Reply-To: <5325A2E7-4987-400A-A1B2-A5C3122D88D1@nvidia.com>
On Wed, May 13, 2026 at 07:48:05PM +0000, Jamie Nguyen wrote:
>
>
> > On May 13, 2026, at 10:15 AM, Sudeep Holla <sudeep.holla@kernel.org> wrote:
> >
> > On Tue, May 12, 2026 at 08:28:00PM -0700, Jamie Nguyen wrote:
> >> __ffa_partition_info_get_regs() walks the response with a hardcoded
> >> 24-byte stride (regs += 3) even though the SPMC tells us the actual
> >> per-descriptor size via PARTITION_INFO_SZ in x2[63:48]. The size is
> >> read into buf_sz and then thrown away.
> >>
> >> That works while every SPMC returns the FF-A v1.1 layout, but it falls
> >> apart against a v1.3 SPMC returning the 48-byte descriptor. The loop
> >> strides over half a descriptor at a time and ends up parsing every
> >> other entry from a slice of two adjacent ones.
> >>
> >> The FF-A spec (v1.2, section 18.5) says that the producer should
> >> report the descriptor size, and the consumer is supposed to stride by
> >> that size and ignore any trailing fields it doesn't understand. The
> >> non-REGS path (__ffa_partition_info_get) does this already, and the
> >> REGS path should match.
> >>
> >> Use buf_sz for the stride, and bail out with -EPROTO if the SPMC
> >> reports something we can't safely walk.
> >>
> >
> > Can you check if the issue is addressed in -next by:
> > Commit 3974ea193840 ("firmware: arm_ffa: Bound PARTITION_INFO_GET_REGS copies")
>
> Thanks for the pointer. I tested 3974ea193840 on the same hardware
> that reproduces the bug, but the descriptor-stride issue is still
> present.
>
> The relevant loop at the end of __ffa_partition_info_get_regs()
> still has:
>
> buf_sz = PARTITION_INFO_SZ(partition_info.a2);
> if (buf_sz > sizeof(*buffer))
> buf_sz = sizeof(*buffer);
> ...
> for (idx = 0; idx < nr_desc; idx++, buf++) {
> ...
> regs += 3; /* bug is here */
> }
>
> With 48-byte descriptors the SPMC returns nr_desc = 2 per call,
Well why is the firmware sending 48byte entry when 24byte is expected.
--
Regards,
Sudeep
^ permalink raw reply
* Re: [PATCH 3/5] arm_mpam: add MPAM-Fb MSC firmware access support
From: Ben Horgan @ 2026-05-14 9:30 UTC (permalink / raw)
To: Andre Przywara, Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla,
Catalin Marinas, Will Deacon, Rafael J . Wysocki, Len Brown,
James Morse, Reinette Chatre, Fenghua Yu
Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-4-andre.przywara@arm.com>
Hi Andre,
I'm just having another look to try and understand this a bit better.
On 4/29/26 15:13, Andre Przywara wrote:
> The Arm MPAM Firmware-backed (Fb) Profile document[1] describes an
> alternative way of accessing the "Memory System Components" (MSC) in an
> MPAM enabled system.
> Normally the MSCs are MMIO mapped, but in some implementations this
> might not be possible (MSC located outside of the local socket, MSC
> mapped secure-only) or desirable (direct MMIO access too slow or needs
> to be mediated through a control processor). MPAM-fb standardises a
> protocol to abstract MSC accesses, building on the SCMI protocol.
>
> Add functions that do an MSC read or write access by redirecting the
> request through a firmware interface. For now this done via an ACPI
> PCC shared memory and mailbox combination.
>
> Since the protocol used is only a small subset of the full SCMI spec,
> and the SCMI protocol has no full ACPI support anyway, open-code the
> SCMI message generation and handshake, for just the fields we need.
>
> [1] https://developer.arm.com/documentation/den0144/latest
>
> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> ---
> drivers/resctrl/Makefile | 2 +-
> drivers/resctrl/mpam_devices.c | 16 +++-
> drivers/resctrl/mpam_fb.c | 158 ++++++++++++++++++++++++++++++++
> drivers/resctrl/mpam_fb.h | 17 ++++
> drivers/resctrl/mpam_internal.h | 5 +
> include/linux/arm_mpam.h | 2 +-
> 6 files changed, 196 insertions(+), 4 deletions(-)
> create mode 100644 drivers/resctrl/mpam_fb.c
> create mode 100644 drivers/resctrl/mpam_fb.h
[...]
> static inline void _mpam_write_partsel_reg(struct mpam_msc *msc, u16 reg, u32 val)
> diff --git a/drivers/resctrl/mpam_fb.c b/drivers/resctrl/mpam_fb.c
> new file mode 100644
> index 000000000000..bfb5798c74b0
> --- /dev/null
> +++ b/drivers/resctrl/mpam_fb.c
[...]
> +
> +#define SCMI_CHANNEL_FREE true
> +#define SCMI_CHANNEL_BUSY false
> +static int mpam_fb_wait_for_channel(struct pcc_mbox_chan *chan,
> + bool free)
> +{
> + u32 status = free ? SCMI_CHAN_STATUS_FREE_BIT : 0;
> + u32 val;
> +
> + /*
> + * The channel should really be free always at this point, as we take
> + * a lock for every read or write request. Check the free bit anyway,
> + * for good measure and to catch corner cases.
> + */
> + return readl_poll_timeout(chan->shmem + SCMI_CHAN_STATUS_OFS, val,
> + (val & SCMI_CHAN_STATUS_FREE_BIT) == status,
> + 1, 10000);
> +}
What would be the reason to call mpam_fb_wait_for_channel() with
free=SCMI_CHANNEL_BUSY? I see that in this patch you always call it with
free=SCMI_CHANNEL_FREE.
Thanks,
Ben
> +
> +static int mpam_fb_send_request(struct mpam_msc *msc, u16 reg, u32 *result,
> + bool is_write)
> +{
> + unsigned int token = atomic_inc_return(&mpam_fb_token);
> + struct pcc_mbox_chan *chan = msc->pcc_chan;
> + u32 status;
> + int ret;
> +
> + guard(mutex)(&msc->pcc_chan_lock);
> + ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
> + if (ret < 0)
> + return ret;
> +
> + /* Clear error bit and mark the channel as belonging to the callee */
> + writel(0, chan->shmem + SCMI_CHAN_STATUS_OFS);
> +
> + if (is_write)
> + ret = mpam_fb_build_write_message(msc->mpam_fb_msc_id, reg,
> + *result, token, chan->shmem);
> + else
> + ret = mpam_fb_build_read_message(msc->mpam_fb_msc_id, reg,
> + token, chan->shmem);
> + if (ret < 0)
> + return ret;
> +
> + ret = mbox_send_message(chan->mchan, NULL);
> + if (ret < 0)
> + return ret;
> +
> + ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
> + if (ret)
> + return ret;
> +
> + status = readl(chan->shmem + SCMI_MSG_HEADER_OFS);
> + if (FIELD_GET(MPAM_MSC_TOKEN_MASK, status) != token)
> + return -ETIMEDOUT;
> +
> + ret = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x0);
> + if (ret < 0)
> + return ret;
> +
> + if (!is_write)
> + *result = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x4);
> +
> + return 0;
> +}
> +
> +int mpam_fb_send_read_request(struct mpam_msc *msc, u16 reg, u32 *result)
> +{
> + return mpam_fb_send_request(msc, reg, result, false);
> +}
> +
> +int mpam_fb_send_write_request(struct mpam_msc *msc, u16 reg, u32 value)
> +{
> + return mpam_fb_send_request(msc, reg, &value, true);
> +}
^ permalink raw reply
* [PATCH v4 0/6] regulator: mt6359: cleanup and add supplies
From: Chen-Yu Tsai @ 2026-05-14 9:15 UTC (permalink / raw)
To: Mark Brown, Liam Girdwood, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno
Cc: Chen-Yu Tsai, linux-arm-kernel, linux-mediatek, devicetree
Hi,
This is v4 of my "MT6359 PMIC cleanup and add supplies" series. This
version addresses review comments from Sashiko.
Changes since v3:
- Dropped duplicate 'va09' regulator from 'vsys-ldo2-supply'
- Added ending match to regex for deprecated vcn33_[12]_(bt|wifi) nodes
- Updated regulator DT example to use proper vcn33_[12] nodes
- Changed vbbck's supply name to 'VIO18' to match vio18 regulator's
default name
- Fixed index off-by-one in error message in mt6359_sync_vcn33_setting()
- Added check of return value from mt6359_sync_vcn33_setting()
- Link to v3:
https://lore.kernel.org/all/20260512085358.1693208-1-wenst@chromium.org/
Changes since v2:
- Fixed vsys-smps-supply property name (from "vspms-supply")
- Collected reviewed-by on patch 3
- Included Lee in recipients (sorry about that)
- Link to v2:
https://lore.kernel.org/all/20260429074113.3720271-1-wenst@chromium.org/
Changes since v1:
- Moved regulator supply properties up to the PMIC mfd node
- This requires moving the properties to the mfd bindings
- deprecated vcn33_[12]_(bt|wifi) regulators and added vcn33_[12]
- model the deprecated ones as downstream to the new ones
(vcn33_[12] -> vcn33_[12]_(bt|wifi)
- Handle internal supply of vbbck directly in the driver, instead of
specifying it in the binding
- Added patch to constify data structures in the regulator driver
- Link to v1:
https://lore.kernel.org/all/20260320072440.2403318-1-wenst@chromium.org/
This series is part of a broader collection of regulator related
cleanups for MediaTek Chromebooks. This one covers the MT6359 PMIC.
The MT6359 PMIC is similar to the MT6358 and MT6366 PMICs. I've done
cleanups for those in the past.
Patch 1 adds the names of the power supply inputs to the binding.
Patch 2 drops the restrictions on the regulator-name property from the
binding. The name of the supply rail ideally should match the design
schematics, not the PMIC's output name. The DT should be free to set
whatever name it needs.
Patch 3 deprecates the vcn33_[12]_(bt|wifi) regulators, and adds new
proper vcn33_[12] regulators. The two *real* VCN33 regulator outputs
each have two enable bits that are OR-ed together to control the
output. This allowed WiFi and BT stacks to separately control power
output without coordination.
Patch 4 constifies the data structures used throughout the regulator
driver. While not directly related, it touches the same context and
it is easier to include it in the series.
Patch 5 adds the supply names from the DT binding change in patch 2
to the regulator descriptions in the driver. This patch has a whole
bunch of checkpatch.pl warnings, but I wonder if it's because the
context size for checking complex macros is not large enough.
Patch 6 implements the changes of the DT binding change in patch 3.
One part not yet covered in this series is the removal of the *_sshub
regulators. These are not actual regulators, but a set of separate
configurations to be used by the low power sensor hub or embedded
controller. How these combine with the standard set of configurations
set by the main processor is TBD.
Device tree changes will be sent separately. The goal is to get the
regulator tree as complete as possible. This includes adding supply
names to other regulator DT bindings, and adding all the supply links
to the existing DTs.
Please have a look.
Thanks
ChenYu
Chen-Yu Tsai (6):
mfd: dt-bindings: mt6397: Add regulator supplies
regulator: dt-bindings: mt6359: Drop regulator-name pattern
restrictions
regulator: dt-bindings: mt6359: Deprecate bogus vcn33_[12]_* split
regulators
regulator: mt6359: const-ify regulator descriptions
regulator: mt6359: Add regulator supply names
regulator: mt6359: Add proper ldo_vcn33_[12] regulators
.../bindings/mfd/mediatek,mt6397.yaml | 50 +++
.../bindings/regulator/mt6359-regulator.yaml | 70 +--
drivers/regulator/mt6359-regulator.c | 405 ++++++++++++------
include/linux/regulator/mt6359-regulator.h | 10 +-
4 files changed, 348 insertions(+), 187 deletions(-)
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply
* Re: [PATCH] firmware: arm_ffa: honor descriptor size in PARTITION_INFO_GET_REGS
From: Sudeep Holla @ 2026-05-14 9:31 UTC (permalink / raw)
To: Jamie Nguyen; +Cc: linux-arm-kernel, linux-kernel, Sudeep Holla
In-Reply-To: <20260513032800.68807-1-jamien@nvidia.com>
On Tue, May 12, 2026 at 08:28:00PM -0700, Jamie Nguyen wrote:
> __ffa_partition_info_get_regs() walks the response with a hardcoded
> 24-byte stride (regs += 3) even though the SPMC tells us the actual
> per-descriptor size via PARTITION_INFO_SZ in x2[63:48]. The size is
> read into buf_sz and then thrown away.
>
> That works while every SPMC returns the FF-A v1.1 layout, but it falls
> apart against a v1.3 SPMC returning the 48-byte descriptor. The loop
> strides over half a descriptor at a time and ends up parsing every
> other entry from a slice of two adjacent ones.
>
> The FF-A spec (v1.2, section 18.5) says that the producer should
> report the descriptor size, and the consumer is supposed to stride by
> that size and ignore any trailing fields it doesn't understand. The
> non-REGS path (__ffa_partition_info_get) does this already, and the
> REGS path should match.
>
> Use buf_sz for the stride, and bail out with -EPROTO if the SPMC
> reports something we can't safely walk.
>
> Fixes: 7bc0f589c81d ("firmware: arm_ffa: Fix big-endian support in __ffa_partition_info_regs_get()")
> Signed-off-by: Jamie Nguyen <jamien@nvidia.com>
> ---
> drivers/firmware/arm_ffa/driver.c | 35 ++++++++++++++++++++++++++++---
> 1 file changed, 32 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c
> index c72ee4756585..b712e8a03dab 100644
> --- a/drivers/firmware/arm_ffa/driver.c
> +++ b/drivers/firmware/arm_ffa/driver.c
> @@ -321,6 +321,22 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
> #define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
> #define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
> #define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
> +
> +/*
> + * FF-A v1.2 section 13.9 Table 13.40: registers x3..x17 carry the partition
> + * descriptors, i.e. 15 u64 of payload per FFA_PARTITION_INFO_GET_REGS call.
> + */
> +#define FFA_PART_INFO_REGS_PAYLOAD_U64 15
> +
> +/*
> + * FF-A v1.1 partition information descriptor (FF-A v1.2 section 6.2.1
> + * Table 6.1): id (2) + exec_ctxt (2) + properties (4) + UUID (16) = 24
> + * bytes. This is the minimum size the SPMC must report; the kernel reads
> + * exactly these fields and ignores any trailing ones per the forward-
> + * compatibility rules in FF-A v1.2 section 18.5.
> + */
I can't see any such details is the above mention version and section.
Can you confirm you are looking at [1] ?
--
Regards,
Sudeep
[1] https://developer.arm.com/documentation/den0077/j
^ permalink raw reply
* Re: [PATCH v14 10/44] arm64: RMI: Add support for SRO
From: Steven Price @ 2026-05-14 9:33 UTC (permalink / raw)
To: Aneesh Kumar K.V, kvm, kvmarm
Cc: Catalin Marinas, Marc Zyngier, Will Deacon, James Morse,
Oliver Upton, Suzuki K Poulose, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Gavin Shan,
Shanker Donthineni, Alper Gun, Emi Kisanuki, Vishal Annapurve,
WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <yq5a8q9ma08r.fsf@kernel.org>
On 14/05/2026 09:01, Aneesh Kumar K.V wrote:
> Steven Price <steven.price@arm.com> writes:
>
>> +unsigned long rmi_sro_execute(struct rmi_sro_state *sro, gfp_t gfp)
>> +{
>> + unsigned long sro_handle;
>> + struct arm_smccc_1_2_regs regs;
>> + struct arm_smccc_1_2_regs *regs_in = &sro->regs;
>> +
>> + rmi_smccc_invoke(regs_in, ®s);
>> +
>> + sro_handle = regs.a1;
>> +
>> + while (RMI_RETURN_STATUS(regs.a0) == RMI_INCOMPLETE) {
>> + bool can_cancel = RMI_RETURN_CAN_CANCEL(regs.a0);
>> + int ret;
>> +
>> + switch (RMI_RETURN_MEMREQ(regs.a0)) {
>> + case RMI_OP_MEM_REQ_NONE:
>> + regs = (struct arm_smccc_1_2_regs){
>> + SMC_RMI_OP_CONTINUE, sro_handle, 0
>> + };
>> + rmi_smccc_invoke(®s, ®s);
>> + break;
>> + case RMI_OP_MEM_REQ_DONATE:
>> + ret = rmi_sro_donate(sro, sro_handle, regs.a2, ®s,
>> + gfp);
>> + break;
>> + case RMI_OP_MEM_REQ_RECLAIM:
>> + ret = rmi_sro_reclaim(sro, sro_handle, ®s);
>> + break;
>> + default:
>> + ret = WARN_ON(1);
>> + break;
>> + }
>> +
>> + if (ret) {
>> + if (can_cancel) {
>> + /*
>> + * FIXME: Handle cancelling properly!
>> + *
>> + * If the operation has failed due to memory
>> + * allocation failure then the information on
>> + * the memory allocation should be saved, so
>> + * that the allocation can be repeated outside
>> + * of any context which prevented the
>> + * allocation.
>> + */
>> + }
>> + if (WARN_ON(ret))
>> + return ret;
>> + }
>> + }
>> +
>> + return regs.a0;
>> +}
>
> Can you also add support to return x1,x2 etc
Indeed that's going to be needed. Looking at this function again I don't
think we actually need the on-stack 'regs' any more. So the below (very
lightly tested) diff would use the regs from sro which also means they
will be there for the caller if it needs them.
Thanks,
Steve
---8<---
diff --git a/arch/arm64/kernel/rmi.c b/arch/arm64/kernel/rmi.c
index a8107ca9bb6d..58a0216be409 100644
--- a/arch/arm64/kernel/rmi.c
+++ b/arch/arm64/kernel/rmi.c
@@ -356,30 +356,29 @@ void rmi_sro_free(struct rmi_sro_state *sro)
unsigned long rmi_sro_execute(struct rmi_sro_state *sro, gfp_t gfp)
{
unsigned long sro_handle;
- struct arm_smccc_1_2_regs regs;
- struct arm_smccc_1_2_regs *regs_in = &sro->regs;
+ struct arm_smccc_1_2_regs *regs = &sro->regs;
- rmi_smccc_invoke(regs_in, ®s);
+ rmi_smccc_invoke(regs, regs);
- sro_handle = regs.a1;
+ sro_handle = regs->a1;
- while (RMI_RETURN_STATUS(regs.a0) == RMI_INCOMPLETE) {
- bool can_cancel = RMI_RETURN_CAN_CANCEL(regs.a0);
+ while (RMI_RETURN_STATUS(regs->a0) == RMI_INCOMPLETE) {
+ bool can_cancel = RMI_RETURN_CAN_CANCEL(regs->a0);
int ret;
- switch (RMI_RETURN_MEMREQ(regs.a0)) {
+ switch (RMI_RETURN_MEMREQ(regs->a0)) {
case RMI_OP_MEM_REQ_NONE:
- regs = (struct arm_smccc_1_2_regs){
+ *regs = (struct arm_smccc_1_2_regs){
SMC_RMI_OP_CONTINUE, sro_handle, 0
};
- rmi_smccc_invoke(®s, ®s);
+ rmi_smccc_invoke(regs, regs);
break;
case RMI_OP_MEM_REQ_DONATE:
- ret = rmi_sro_donate(sro, sro_handle, regs.a2, ®s,
+ ret = rmi_sro_donate(sro, sro_handle, regs->a2, regs,
gfp);
break;
case RMI_OP_MEM_REQ_RECLAIM:
- ret = rmi_sro_reclaim(sro, sro_handle, ®s);
+ ret = rmi_sro_reclaim(sro, sro_handle, regs);
break;
default:
ret = WARN_ON(1);
@@ -404,7 +403,7 @@ unsigned long rmi_sro_execute(struct rmi_sro_state *sro, gfp_t gfp)
}
}
- return regs.a0;
+ return regs->a0;
}
static int rmi_check_version(void)
^ permalink raw reply related
* [PATCH v5 0/3] Switch Arm CCA to use an auxiliary device instead of a platform device
From: Aneesh Kumar K.V (Arm) @ 2026-05-14 9:40 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose
As discussed here:
https://lore.kernel.org/all/20250728135216.48084-12-aneesh.kumar@kernel.org
The general feedback was that a platform device should not be used when
there is no underlying platform resource to represent. The existing CCA
support uses a platform device solely to anchor the TSM interface in the
device hierarchy, which is not an appropriate use of a platform device.
Use an auxiliary device instead to track CCA support.
The TSM framework uses the device abstraction to provide cross-architecture
TSM and TEE I/O functionality, including enumerating available platform TEE
I/O capabilities and provisioning connections between the platform TSM and
device DSMs.
For the CCA platform, the resulting device hierarchy appears as follows.
Note that the auxiliary device is still parented by the arm-smccc platform
device, so the sysfs path remains under /devices/platform/arm-smccc/:
$ cd /sys/class/tsm/
$ ls -al
total 0
drwxr-xr-x 2 root root 0 Jan 1 00:02 .
drwxr-xr-x 23 root root 0 Jan 1 00:00 ..
lrwxrwxrwx 1 root root 0 Jan 1 00:03 tsm0 -> ../../devices/platform/arm-smccc/arm_cca_guest.arm-rsi-dev.0/tsm/tsm0
$
Changes from v4:
https://lore.kernel.org/all/20260427061615.905018-1-aneesh.kumar@kernel.org
* Add /sys/firmware/cca/realm_guest for detecting realm guest
* Convert smccc-trng to auxiliary device from platform device
Changes from v3:
https://lore.kernel.org/all/20260309100507.2303361-1-aneesh.kumar@kernel.org
* Rebased onto the latest kernel
* Drop pr_fmt() from drivers/firmware/smccc/rmm.c
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
Aneesh Kumar K.V (Arm) (3):
firmware: smccc: coco: Manage arm-smccc platform device and CCA
auxiliary drivers
hwrng: arm_smccc_trng: Register as an auxiliary device
coco: guest: arm64: Replace dummy CCA device with sysfs ABI
Documentation/ABI/testing/sysfs-firmware-cca | 10 ++++
arch/arm64/include/asm/rsi.h | 2 +-
arch/arm64/kernel/rsi.c | 39 ++++++++----
drivers/char/hw_random/arm_smccc_trng.c | 25 ++++----
drivers/firmware/smccc/Kconfig | 1 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/rmm.c | 24 ++++++++
drivers/firmware/smccc/rmm.h | 17 ++++++
drivers/firmware/smccc/smccc.c | 29 +++++++--
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/Makefile | 2 +
.../{arm-cca-guest.c => arm-cca.c} | 59 +++++++++----------
12 files changed, 153 insertions(+), 57 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-cca
create mode 100644 drivers/firmware/smccc/rmm.c
create mode 100644 drivers/firmware/smccc/rmm.h
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (84%)
--
2.43.0
^ permalink raw reply
* [PATCH v5 1/3] firmware: smccc: coco: Manage arm-smccc platform device and CCA auxiliary drivers
From: Aneesh Kumar K.V (Arm) @ 2026-05-14 9:40 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose
In-Reply-To: <20260514094030.42495-1-aneesh.kumar@kernel.org>
Make the SMCCC driver responsible for registering the arm-smccc platform
device and after confirming the relevant SMCCC function IDs, create
the arm_cca_guest auxiliary device.
Also update the arm-cca-guest driver to use the auxiliary device
interface instead of the platform device (arm-cca-dev). The removal of
the platform device registration will follow in a subsequent patch,
allowing this change to be applied without immediately breaking existing
userspace dependencies [1].
[1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/include/asm/rsi.h | 2 +-
arch/arm64/kernel/rsi.c | 2 +-
drivers/firmware/smccc/Kconfig | 1 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/rmm.c | 24 ++++++++
drivers/firmware/smccc/rmm.h | 17 ++++++
drivers/firmware/smccc/smccc.c | 17 ++++++
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/Makefile | 2 +
.../{arm-cca-guest.c => arm-cca.c} | 59 +++++++++----------
10 files changed, 94 insertions(+), 32 deletions(-)
create mode 100644 drivers/firmware/smccc/rmm.c
create mode 100644 drivers/firmware/smccc/rmm.h
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (84%)
diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
index 88b50d660e85..2d2d363aaaee 100644
--- a/arch/arm64/include/asm/rsi.h
+++ b/arch/arm64/include/asm/rsi.h
@@ -10,7 +10,7 @@
#include <linux/jump_label.h>
#include <asm/rsi_cmds.h>
-#define RSI_PDEV_NAME "arm-cca-dev"
+#define RSI_DEV_NAME "arm-rsi-dev"
DECLARE_STATIC_KEY_FALSE(rsi_present);
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 9e846ce4ef9c..8380e5ba88d2 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -161,7 +161,7 @@ void __init arm64_rsi_init(void)
}
static struct platform_device rsi_dev = {
- .name = RSI_PDEV_NAME,
+ .name = "arm-cca-dev",
.id = PLATFORM_DEVID_NONE
};
diff --git a/drivers/firmware/smccc/Kconfig b/drivers/firmware/smccc/Kconfig
index 15e7466179a6..2b6984757241 100644
--- a/drivers/firmware/smccc/Kconfig
+++ b/drivers/firmware/smccc/Kconfig
@@ -8,6 +8,7 @@ config HAVE_ARM_SMCCC
config HAVE_ARM_SMCCC_DISCOVERY
bool
depends on ARM_PSCI_FW
+ select AUXILIARY_BUS
default y
help
SMCCC v1.0 lacked discoverability and hence PSCI v1.0 was updated
diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
index 40d19144a860..146dc3c03c20 100644
--- a/drivers/firmware/smccc/Makefile
+++ b/drivers/firmware/smccc/Makefile
@@ -2,3 +2,4 @@
#
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
+obj-$(CONFIG_ARM64) += rmm.o
diff --git a/drivers/firmware/smccc/rmm.c b/drivers/firmware/smccc/rmm.c
new file mode 100644
index 000000000000..728338cb5a22
--- /dev/null
+++ b/drivers/firmware/smccc/rmm.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+
+#include <linux/auxiliary_bus.h>
+
+#include "rmm.h"
+
+void __init register_rsi_device(struct platform_device *pdev)
+{
+ unsigned long ret;
+ unsigned long ver_lower, ver_higher;
+
+ if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
+ return;
+
+ ret = rsi_request_version(RSI_ABI_VERSION, &ver_lower, &ver_higher);
+ if (ret != RSI_SUCCESS)
+ return;
+
+ __devm_auxiliary_device_create(&pdev->dev,
+ "arm_cca_guest", RSI_DEV_NAME, NULL, 0);
+}
diff --git a/drivers/firmware/smccc/rmm.h b/drivers/firmware/smccc/rmm.h
new file mode 100644
index 000000000000..a47a650d4f51
--- /dev/null
+++ b/drivers/firmware/smccc/rmm.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SMCCC_RMM_H
+#define _SMCCC_RMM_H
+
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_ARM64
+#include <asm/rsi_cmds.h>
+void __init register_rsi_device(struct platform_device *pdev);
+#else
+
+static void __init register_rsi_device(struct platform_device *pdev)
+{
+
+}
+#endif
+#endif
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index bdee057db2fd..eb077b9aa6da 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -12,6 +12,8 @@
#include <linux/platform_device.h>
#include <asm/archrandom.h>
+#include "rmm.h"
+
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
@@ -85,6 +87,21 @@ static int __init smccc_devices_init(void)
{
struct platform_device *pdev;
+ if (smccc_conduit == SMCCC_CONDUIT_NONE)
+ return 0;
+
+ pdev = platform_device_register_simple("arm-smccc",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(pdev)) {
+ pr_err("arm-smccc: could not register device: %ld\n", PTR_ERR(pdev));
+ } else {
+ /*
+ * Register the RMI and RSI devices only when firmware exposes
+ * the required SMCCC function IDs at a supported revision.
+ */
+ register_rsi_device(pdev);
+ }
+
if (smccc_trng_available) {
pdev = platform_device_register_simple("smccc_trng", -1,
NULL, 0);
diff --git a/drivers/virt/coco/arm-cca-guest/Kconfig b/drivers/virt/coco/arm-cca-guest/Kconfig
index 3f0f013f03f1..a42359a90558 100644
--- a/drivers/virt/coco/arm-cca-guest/Kconfig
+++ b/drivers/virt/coco/arm-cca-guest/Kconfig
@@ -2,6 +2,7 @@ config ARM_CCA_GUEST
tristate "Arm CCA Guest driver"
depends on ARM64
select TSM_REPORTS
+ select AUXILIARY_BUS
help
The driver provides userspace interface to request and
attestation report from the Realm Management Monitor(RMM).
diff --git a/drivers/virt/coco/arm-cca-guest/Makefile b/drivers/virt/coco/arm-cca-guest/Makefile
index 69eeba08e98a..75a120e24fda 100644
--- a/drivers/virt/coco/arm-cca-guest/Makefile
+++ b/drivers/virt/coco/arm-cca-guest/Makefile
@@ -1,2 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest.o
+
+arm-cca-guest-y += arm-cca.o
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
similarity index 84%
rename from drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
rename to drivers/virt/coco/arm-cca-guest/arm-cca.c
index 0c9ea24a200c..7daada072cc0 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -3,6 +3,7 @@
* Copyright (C) 2023 ARM Ltd.
*/
+#include <linux/auxiliary_bus.h>
#include <linux/arm-smccc.h>
#include <linux/cc_platform.h>
#include <linux/kernel.h>
@@ -181,52 +182,50 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
return ret;
}
-static const struct tsm_report_ops arm_cca_tsm_ops = {
+static const struct tsm_report_ops arm_cca_tsm_report_ops = {
.name = KBUILD_MODNAME,
.report_new = arm_cca_report_new,
};
-/**
- * arm_cca_guest_init - Register with the Trusted Security Module (TSM)
- * interface.
- *
- * Return:
- * * %0 - Registered successfully with the TSM interface.
- * * %-ENODEV - The execution context is not an Arm Realm.
- * * %-EBUSY - Already registered.
- */
-static int __init arm_cca_guest_init(void)
+static void unregister_cca_tsm_report(void *data)
+{
+ tsm_report_unregister(&arm_cca_tsm_report_ops);
+}
+
+static int cca_devsec_tsm_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
int ret;
if (!is_realm_world())
return -ENODEV;
- ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
- if (ret < 0)
- pr_err("Error %d registering with TSM\n", ret);
+ ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
+ if (ret < 0) {
+ dev_err_probe(&adev->dev, ret, "Error registering with TSM\n");
+ return ret;
+ }
- return ret;
-}
-module_init(arm_cca_guest_init);
+ ret = devm_add_action_or_reset(&adev->dev, unregister_cca_tsm_report, NULL);
+ if (ret < 0) {
+ dev_err_probe(&adev->dev, ret, "Error registering devm action\n");
+ return ret;
+ }
-/**
- * arm_cca_guest_exit - unregister with the Trusted Security Module (TSM)
- * interface.
- */
-static void __exit arm_cca_guest_exit(void)
-{
- tsm_report_unregister(&arm_cca_tsm_ops);
+ return 0;
}
-module_exit(arm_cca_guest_exit);
-/* modalias, so userspace can autoload this module when RSI is available */
-static const struct platform_device_id arm_cca_match[] __maybe_unused = {
- { RSI_PDEV_NAME, 0},
- { }
+static const struct auxiliary_device_id cca_devsec_tsm_id_table[] = {
+ { .name = KBUILD_MODNAME "." RSI_DEV_NAME },
+ {}
};
+MODULE_DEVICE_TABLE(auxiliary, cca_devsec_tsm_id_table);
-MODULE_DEVICE_TABLE(platform, arm_cca_match);
+static struct auxiliary_driver cca_devsec_tsm_driver = {
+ .probe = cca_devsec_tsm_probe,
+ .id_table = cca_devsec_tsm_id_table,
+};
+module_auxiliary_driver(cca_devsec_tsm_driver);
MODULE_AUTHOR("Sami Mujawar <sami.mujawar@arm.com>");
MODULE_DESCRIPTION("Arm CCA Guest TSM Driver");
MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v5 2/3] hwrng: arm_smccc_trng: Register as an auxiliary device
From: Aneesh Kumar K.V (Arm) @ 2026-05-14 9:40 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose
In-Reply-To: <20260514094030.42495-1-aneesh.kumar@kernel.org>
The SMCCC TRNG interface is a firmware-provided function rather than a
standalone platform device. Register it as an auxiliary device under the
arm-smccc platform device and convert the hwrng driver to an auxiliary
driver.
This keeps the TRNG device tied to the SMCCC core device while preserving
module autoloading through the auxiliary device ID table.
The conversion changes the device path from the old platform device path,
but no userspace dependency on that path was found. This was confirmed with
a Debian Code Search lookup for the existing platform device name/path.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
drivers/char/hw_random/arm_smccc_trng.c | 25 ++++++++++++++-----------
drivers/firmware/smccc/smccc.c | 24 +++++++++++++-----------
2 files changed, 27 insertions(+), 22 deletions(-)
diff --git a/drivers/char/hw_random/arm_smccc_trng.c b/drivers/char/hw_random/arm_smccc_trng.c
index dcb8e7f37f25..5d56fcbcefa0 100644
--- a/drivers/char/hw_random/arm_smccc_trng.c
+++ b/drivers/char/hw_random/arm_smccc_trng.c
@@ -16,7 +16,7 @@
#include <linux/device.h>
#include <linux/hw_random.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
+#include <linux/auxiliary_bus.h>
#include <linux/arm-smccc.h>
#ifdef CONFIG_ARM64
@@ -94,29 +94,32 @@ static int smccc_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
return copied;
}
-static int smccc_trng_probe(struct platform_device *pdev)
+static int smccc_trng_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
struct hwrng *trng;
- trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+ trng = devm_kzalloc(&adev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
trng->name = "smccc_trng";
trng->read = smccc_trng_read;
- return devm_hwrng_register(&pdev->dev, trng);
+ return devm_hwrng_register(&adev->dev, trng);
}
-static struct platform_driver smccc_trng_driver = {
- .driver = {
- .name = "smccc_trng",
- },
- .probe = smccc_trng_probe,
+static const struct auxiliary_device_id smccc_trng_id_table[] = {
+ { .name = KBUILD_MODNAME ".smccc_trng" },
+ {}
};
-module_platform_driver(smccc_trng_driver);
+MODULE_DEVICE_TABLE(auxiliary, smccc_trng_id_table);
-MODULE_ALIAS("platform:smccc_trng");
+static struct auxiliary_driver smccc_trng_driver = {
+ .probe = smccc_trng_probe,
+ .id_table = smccc_trng_id_table,
+};
+module_auxiliary_driver(smccc_trng_driver);
MODULE_AUTHOR("Andre Przywara");
MODULE_DESCRIPTION("Arm SMCCC TRNG firmware interface support");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index eb077b9aa6da..49ac8172def4 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -10,6 +10,7 @@
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/auxiliary_bus.h>
#include <asm/archrandom.h>
#include "rmm.h"
@@ -94,20 +95,21 @@ static int __init smccc_devices_init(void)
PLATFORM_DEVID_NONE, NULL, 0);
if (IS_ERR(pdev)) {
pr_err("arm-smccc: could not register device: %ld\n", PTR_ERR(pdev));
- } else {
- /*
- * Register the RMI and RSI devices only when firmware exposes
- * the required SMCCC function IDs at a supported revision.
- */
- register_rsi_device(pdev);
+ return 0;
}
+ /*
+ * Register the RMI and RSI devices only when firmware exposes
+ * the required SMCCC function IDs at a supported revision.
+ */
+ register_rsi_device(pdev);
if (smccc_trng_available) {
- pdev = platform_device_register_simple("smccc_trng", -1,
- NULL, 0);
- if (IS_ERR(pdev))
- pr_err("smccc_trng: could not register device: %ld\n",
- PTR_ERR(pdev));
+ struct auxiliary_device *adev;
+
+ adev = __devm_auxiliary_device_create(&pdev->dev,
+ "arm_smccc_trng", "smccc_trng", NULL, 0);
+ if (!adev)
+ pr_err("smccc_trng: could not register device\n");
}
return 0;
--
2.43.0
^ permalink raw reply related
* [PATCH v5 3/3] coco: guest: arm64: Replace dummy CCA device with sysfs ABI
From: Aneesh Kumar K.V (Arm) @ 2026-05-14 9:40 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose
In-Reply-To: <20260514094030.42495-1-aneesh.kumar@kernel.org>
The SMCCC firmware driver now creates the arm-smccc platform device and
instantiates the CCA auxiliary devices once the RSI ABI is discovered. The
arm64-specific arm-cca-dev platform device stub is therefore no longer
needed.
However, userspace has used the arm-cca-dev platform device to detect Arm
CCA Realm guests [1]. Removing it without a replacement would break that
detection and would also leave userspace depending on kernel device-model
details.
Add /sys/firmware/cca/realm_guest as a stable, architecture-provided ABI
for detecting whether the kernel is running as an Arm CCA Realm guest. The
file returns 1 in Realm world and 0 otherwise, similar to the existing s390
/sys/firmware/uv/prot_virt_guest interface for protected virtualization
guests.
Remove the dummy arm-cca-dev registration now that userspace has a
dedicated CCA Realm guest indicator, and document the new ABI in
Documentation/ABI/testing/sysfs-firmware-cca.
[1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
Documentation/ABI/testing/sysfs-firmware-cca | 10 +++++
arch/arm64/kernel/rsi.c | 39 +++++++++++++++-----
2 files changed, 39 insertions(+), 10 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-cca
diff --git a/Documentation/ABI/testing/sysfs-firmware-cca b/Documentation/ABI/testing/sysfs-firmware-cca
new file mode 100644
index 000000000000..bf177d636b92
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-cca
@@ -0,0 +1,10 @@
+What: /sys/firmware/cca/realm_guest
+Date: May 2026
+Contact: Linux ARM Kernel Mailing list <linux-arm-kernel@lists.infradead.org>
+Description: Read-only. Indicates whether the kernel is running as an
+ Arm Confidential Compute Architecture (CCA) Realm guest.
+
+ The value is one of:
+
+ 0: the kernel is not running as a Realm guest
+ 1: the kernel is running as a Realm guest
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 8380e5ba88d2..a3e9b3bb5679 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -9,6 +9,8 @@
#include <linux/swiotlb.h>
#include <linux/cc_platform.h>
#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
#include <asm/mem_encrypt.h>
@@ -16,6 +18,7 @@
#include <asm/rsi.h>
static struct realm_config config;
+static struct kobject *cca_kobj;
unsigned long prot_ns_shared;
EXPORT_SYMBOL(prot_ns_shared);
@@ -160,17 +163,33 @@ void __init arm64_rsi_init(void)
static_branch_enable(&rsi_present);
}
-static struct platform_device rsi_dev = {
- .name = "arm-cca-dev",
- .id = PLATFORM_DEVID_NONE
+static ssize_t cca_is_realm_guest(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", is_realm_world());
+}
+
+static struct kobj_attribute cca_realm_guest =
+ __ATTR(realm_guest, 0444, cca_is_realm_guest, NULL);
+
+static const struct attribute *cca_realm_attrs[] = {
+ &cca_realm_guest.attr,
+ NULL,
};
-static int __init arm64_create_dummy_rsi_dev(void)
+static int __init realm_sysfs_init(void)
{
- if (is_realm_world() &&
- platform_device_register(&rsi_dev))
- pr_err("failed to register rsi platform device\n");
- return 0;
-}
+ int ret;
+
+ cca_kobj = kobject_create_and_add("cca", firmware_kobj);
+ if (!cca_kobj)
+ return -ENOMEM;
-arch_initcall(arm64_create_dummy_rsi_dev)
+ ret = sysfs_create_files(cca_kobj, cca_realm_attrs);
+ if (!ret)
+ return 0;
+
+ kobject_put(cca_kobj);
+ return ret;
+}
+device_initcall(realm_sysfs_init);
--
2.43.0
^ permalink raw reply related
* [PATCH v2 0/7] mm/vmalloc: Speed up ioremap, vmalloc and vmap with contiguous memory
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang
This patchset accelerates ioremap, vmalloc, and vmap when the memory
is physically fully or partially contiguous. Two techniques are used:
1. Avoid page table rewalk when setting PTEs/PMDs for multiple memory
segments
2. Use batched mappings wherever possible in both vmalloc and ARM64
layers
Besides accelerating the mapping path, this also enables large
mappings (PMD and cont-PTE) for vmap, which are currently not
supported.
Patches 1-2 extend ARM64 vmalloc CONT-PTE mapping to support multiple
CONT-PTE regions instead of just one.
Patch 3 extracts a common helper vmap_set_ptes() that consolidates PTE
mapping logic between the ioremap and vmalloc/vmap paths, handling both
CONT_PTE and regular PTE mappings. This prepares for the next patch.
Patch 4 extends the page table walk path to support page shifts other
than PAGE_SHIFT and eliminates the page table rewalk for huge vmalloc
mappings. The function is renamed from vmap_small_pages_range_noflush()
to vmap_pages_range_noflush_walk().
Patches 5-7 add huge vmap support for contiguous pages, including
support for non-compound pages with pfn alignment verification.
On the RK3588 8-core ARM64 SoC, with tasks pinned to a little core and
the performance CPUfreq policy enabled, benchmark results:
* ioremap(1 MB): 1.35× faster (3407 ns -> 2526 ns)
* vmalloc(1 MB) mapping time (excluding allocation) with
VM_ALLOW_HUGE_VMAP: 1.42× faster (5.00 us -> 3.53us)
* vmap(100MB) with order-8 pages: 8.3× faster (1235 us -> 149 us)
Many thanks to Xueyuan Chen for his testing efforts on RK3588 boards.
Changes since v1:
- Fix condition order and use PMD_SIZE instead of CONT_PMD_SIZE in
patch 1 (Dev Jain)
- Squash patch 3+4 and patch 5+7 (Dev Jain)
- Replace "zigzag" with "page table rewalk" in commit messages
(Dev Jain)
- Rename vmap_small_pages_range_noflush() to
vmap_pages_range_noflush_walk() (Dev Jain)
- Extract vmap_set_ptes() as a new patch to consolidate PTE mapping
logic between vmap_pte_range() and vmap_pages_pte_range(), handling
both CONT_PTE and regular mappings (Mike Rapoport)
- Support non-compound pages in get_vmap_batch_order() by falling
back to physical contiguity scanning with pfn alignment check
(Dev Jain, Uladzislau Rezki)
- In get_vmap_batch_order(), filter out orders that the architecture
cannot batch by checking arch_vmap_pte_supported_shift() directly.
This avoids overhead for orders 1-3 on ARM64 CONT_PTE with 4K
pages. (patch 5)
Barry Song (Xiaomi) (6):
arm64/hugetlb: Extend batching of multiple CONT_PTE in a single PTE
setup
arm64/vmalloc: Allow arch_vmap_pte_range_map_size to batch multiple
CONT_PTE
mm/vmalloc: Extend page table walk to support larger page_shift sizes
and eliminate page table rewalk
mm/vmalloc: map contiguous pages in batches for vmap() if possible
mm/vmalloc: align vm_area so vmap() can batch mappings
mm/vmalloc: Stop scanning for compound pages after encountering small
pages in vmap
Wen Jiang (1):
mm/vmalloc: Extract vmap_set_ptes() to consolidate PTE mapping logic
arch/arm64/include/asm/vmalloc.h | 6 +-
arch/arm64/mm/hugetlbpage.c | 10 ++
mm/vmalloc.c | 221 ++++++++++++++++++++++++-------
3 files changed, 189 insertions(+), 48 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2 1/7] arm64/hugetlb: Extend batching of multiple CONT_PTE in a single PTE setup
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
For sizes aligned to CONT_PTE_SIZE and smaller than PMD_SIZE,
we can batch CONT_PTE settings instead of handling them individually.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
arch/arm64/mm/hugetlbpage.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 30772a909..d477a9dd1 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -110,6 +110,12 @@ static inline int num_contig_ptes(unsigned long size, size_t *pgsize)
contig_ptes = CONT_PTES;
break;
default:
+ if (size > 0 && size < PMD_SIZE &&
+ IS_ALIGNED(size, CONT_PTE_SIZE)) {
+ contig_ptes = size >> PAGE_SHIFT;
+ *pgsize = PAGE_SIZE;
+ break;
+ }
WARN_ON(!__hugetlb_valid_size(size));
}
@@ -359,6 +365,10 @@ pte_t arch_make_huge_pte(pte_t entry, unsigned int shift, vm_flags_t flags)
case CONT_PTE_SIZE:
return pte_mkcont(entry);
default:
+ if (pagesize > 0 && pagesize < PMD_SIZE &&
+ IS_ALIGNED(pagesize, CONT_PTE_SIZE))
+ return pte_mkcont(entry);
+
break;
}
pr_warn("%s: unrecognized huge page size 0x%lx\n",
--
2.34.1
^ permalink raw reply related
* [PATCH v2 2/7] arm64/vmalloc: Allow arch_vmap_pte_range_map_size to batch multiple CONT_PTE
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
Allow arch_vmap_pte_range_map_size to batch multiple CONT_PTE hugepages,
reducing both PTE setup and TLB flush iterations.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
arch/arm64/include/asm/vmalloc.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/include/asm/vmalloc.h b/arch/arm64/include/asm/vmalloc.h
index 4ec1acd3c..9eea06d0f 100644
--- a/arch/arm64/include/asm/vmalloc.h
+++ b/arch/arm64/include/asm/vmalloc.h
@@ -23,6 +23,8 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,
unsigned long end, u64 pfn,
unsigned int max_page_shift)
{
+ unsigned long size;
+
/*
* If the block is at least CONT_PTE_SIZE in size, and is naturally
* aligned in both virtual and physical space, then we can pte-map the
@@ -40,7 +42,9 @@ static inline unsigned long arch_vmap_pte_range_map_size(unsigned long addr,
if (!IS_ALIGNED(PFN_PHYS(pfn), CONT_PTE_SIZE))
return PAGE_SIZE;
- return CONT_PTE_SIZE;
+ size = min3(end - addr, 1UL << max_page_shift, PMD_SIZE >> 1);
+ size = 1UL << (fls(size) - 1);
+ return size;
}
#define arch_vmap_pte_range_unmap_size arch_vmap_pte_range_unmap_size
--
2.34.1
^ permalink raw reply related
* [PATCH v2 3/7] mm/vmalloc: Extract vmap_set_ptes() to consolidate PTE mapping logic
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
Extract the common PTE mapping logic from vmap_pte_range() into a
shared helper vmap_set_ptes(). This handles both CONT_PTE and regular
PTE mappings in a single function, preparing for the next patch which
will extend vmap_pages_pte_range() to also use this helper.
The #ifdef CONFIG_HUGETLB_PAGE guard is moved inside vmap_set_ptes(),
so callers no longer need to handle the conditional compilation.
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
mm/vmalloc.c | 49 ++++++++++++++++++++++++++++++++++---------------
1 file changed, 34 insertions(+), 15 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 3e9e5156f..9bfd0aa34 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -91,6 +91,35 @@ struct vfree_deferred {
static DEFINE_PER_CPU(struct vfree_deferred, vfree_deferred);
/*** Page table manipulation functions ***/
+
+/*
+ * Set PTE mappings for the given PFN. Try CONT_PTE mappings first when
+ * supported, otherwise fall back to PAGE_SIZE mappings.
+ *
+ * Return: mapping size.
+ */
+static __always_inline unsigned long vmap_set_ptes(pte_t *pte,
+ unsigned long addr, unsigned long end, u64 pfn,
+ pgprot_t prot, unsigned int max_page_shift)
+{
+#ifdef CONFIG_HUGETLB_PAGE
+ if (max_page_shift > PAGE_SHIFT) {
+ unsigned long size;
+
+ size = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);
+ if (size != PAGE_SIZE) {
+ pte_t entry = pfn_pte(pfn, prot);
+
+ entry = arch_make_huge_pte(entry, ilog2(size), 0);
+ set_huge_pte_at(&init_mm, addr, pte, entry, size);
+ return size;
+ }
+ }
+#endif
+ set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
+ return PAGE_SIZE;
+}
+
static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
phys_addr_t phys_addr, pgprot_t prot,
unsigned int max_page_shift, pgtbl_mod_mask *mask)
@@ -98,7 +127,8 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
pte_t *pte;
u64 pfn;
struct page *page;
- unsigned long size = PAGE_SIZE;
+ unsigned long size;
+ unsigned int steps;
if (WARN_ON_ONCE(!PAGE_ALIGNED(end - addr)))
return -EINVAL;
@@ -119,20 +149,9 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
BUG();
}
-#ifdef CONFIG_HUGETLB_PAGE
- size = arch_vmap_pte_range_map_size(addr, end, pfn, max_page_shift);
- if (size != PAGE_SIZE) {
- pte_t entry = pfn_pte(pfn, prot);
-
- entry = arch_make_huge_pte(entry, ilog2(size), 0);
- set_huge_pte_at(&init_mm, addr, pte, entry, size);
- pfn += PFN_DOWN(size);
- continue;
- }
-#endif
- set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
- pfn++;
- } while (pte += PFN_DOWN(size), addr += size, addr != end);
+ size = vmap_set_ptes(pte, addr, end, pfn, prot, max_page_shift);
+ steps = PFN_DOWN(size);
+ } while (pte += steps, pfn += steps, addr += size, addr != end);
lazy_mmu_mode_disable();
*mask |= PGTBL_PTE_MODIFIED;
--
2.34.1
^ permalink raw reply related
* [PATCH v2 4/7] mm/vmalloc: Extend page table walk to support larger page_shift sizes and eliminate page table rewalk
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
vmap_pages_range_noflush_walk() (formerly vmap_small_pages_range_noflush())
provides a clean interface by taking struct page **pages and mapping them
via direct PTE iteration. This avoids the page table rewalk seen when
using vmap_range_noflush() for page_shift values other than PAGE_SHIFT.
Extend it to support larger page_shift values, and add PMD- and
contiguous-PTE mappings as well. Rename it to vmap_pages_range_noflush_walk()
since it now handles more than just small pages.
For vmalloc() allocations with VM_ALLOW_HUGE_VMAP, we no longer need to
iterate over pages one by one via vmap_range_noflush(), which would
otherwise lead to page table rewalk. The code is now unified with the
PAGE_SHIFT case by simply calling vmap_pages_range_noflush_walk().
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
mm/vmalloc.c | 64 +++++++++++++++++++++++++++-------------------------
1 file changed, 33 insertions(+), 31 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9bfd0aa34..516d40650 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -543,8 +543,10 @@ void vunmap_range(unsigned long addr, unsigned long end)
static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
+ unsigned long pfn, size;
+ unsigned int steps;
int err = 0;
pte_t *pte;
@@ -575,9 +577,10 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
break;
}
- set_pte_at(&init_mm, addr, pte, mk_pte(page, prot));
- (*nr)++;
- } while (pte++, addr += PAGE_SIZE, addr != end);
+ pfn = page_to_pfn(page);
+ size = vmap_set_ptes(pte, addr, end, pfn, prot, shift);
+ steps = PFN_DOWN(size);
+ } while (pte += steps, *nr += steps, addr += size, addr != end);
lazy_mmu_mode_disable();
*mask |= PGTBL_PTE_MODIFIED;
@@ -587,7 +590,7 @@ static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
pmd_t *pmd;
unsigned long next;
@@ -597,7 +600,20 @@ static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,
return -ENOMEM;
do {
next = pmd_addr_end(addr, end);
- if (vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask))
+
+ if (shift == PMD_SHIFT) {
+ struct page *page = pages[*nr];
+ phys_addr_t phys_addr = page_to_phys(page);
+
+ if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot,
+ shift)) {
+ *mask |= PGTBL_PMD_MODIFIED;
+ *nr += 1 << (shift - PAGE_SHIFT);
+ continue;
+ }
+ }
+
+ if (vmap_pages_pte_range(pmd, addr, next, prot, pages, nr, mask, shift))
return -ENOMEM;
} while (pmd++, addr = next, addr != end);
return 0;
@@ -605,7 +621,7 @@ static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,
static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
pud_t *pud;
unsigned long next;
@@ -615,7 +631,7 @@ static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,
return -ENOMEM;
do {
next = pud_addr_end(addr, end);
- if (vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask))
+ if (vmap_pages_pmd_range(pud, addr, next, prot, pages, nr, mask, shift))
return -ENOMEM;
} while (pud++, addr = next, addr != end);
return 0;
@@ -623,7 +639,7 @@ static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,
static int vmap_pages_p4d_range(pgd_t *pgd, unsigned long addr,
unsigned long end, pgprot_t prot, struct page **pages, int *nr,
- pgtbl_mod_mask *mask)
+ pgtbl_mod_mask *mask, unsigned int shift)
{
p4d_t *p4d;
unsigned long next;
@@ -633,14 +649,14 @@ static int vmap_pages_p4d_range(pgd_t *pgd, unsigned long addr,
return -ENOMEM;
do {
next = p4d_addr_end(addr, end);
- if (vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask))
+ if (vmap_pages_pud_range(p4d, addr, next, prot, pages, nr, mask, shift))
return -ENOMEM;
} while (p4d++, addr = next, addr != end);
return 0;
}
-static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
- pgprot_t prot, struct page **pages)
+static int vmap_pages_range_noflush_walk(unsigned long addr, unsigned long end,
+ pgprot_t prot, struct page **pages, unsigned int shift)
{
unsigned long start = addr;
pgd_t *pgd;
@@ -655,7 +671,7 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
next = pgd_addr_end(addr, end);
if (pgd_bad(*pgd))
mask |= PGTBL_PGD_MODIFIED;
- err = vmap_pages_p4d_range(pgd, addr, next, prot, pages, &nr, &mask);
+ err = vmap_pages_p4d_range(pgd, addr, next, prot, pages, &nr, &mask, shift);
if (err)
break;
} while (pgd++, addr = next, addr != end);
@@ -678,27 +694,13 @@ static int vmap_small_pages_range_noflush(unsigned long addr, unsigned long end,
int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
pgprot_t prot, struct page **pages, unsigned int page_shift)
{
- unsigned int i, nr = (end - addr) >> PAGE_SHIFT;
-
WARN_ON(page_shift < PAGE_SHIFT);
- if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC) ||
- page_shift == PAGE_SHIFT)
- return vmap_small_pages_range_noflush(addr, end, prot, pages);
-
- for (i = 0; i < nr; i += 1U << (page_shift - PAGE_SHIFT)) {
- int err;
-
- err = vmap_range_noflush(addr, addr + (1UL << page_shift),
- page_to_phys(pages[i]), prot,
- page_shift);
- if (err)
- return err;
+ if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC))
+ page_shift = PAGE_SHIFT;
- addr += 1UL << page_shift;
- }
-
- return 0;
+ return vmap_pages_range_noflush_walk(addr, end, prot, pages,
+ min(page_shift, PMD_SHIFT));
}
int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
--
2.34.1
^ permalink raw reply related
* [PATCH v2 5/7] mm/vmalloc: map contiguous pages in batches for vmap() if possible
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
In many cases, the pages passed to vmap() may include high-order
pages. For example, the systemheap often allocates pages in descending
order: order 8, then 4, then 0. Currently, vmap() iterates over every
page individually—even pages inside a high-order block are handled
one by one.
This patch detects physically contiguous pages (regardless of whether
they are compound or non-compound) by scanning with
num_pages_contiguous(), and maps them as a single contiguous block
whenever possible. The first page's pfn must be aligned to the
mapping order for the batched mapping to be used.
Pages with the same page_shift are coalesced and mapped via
vmap_pages_range_noflush_walk() to avoid page table rewalk.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Co-developed-by: Dev Jain <dev.jain@arm.com>
Signed-off-by: Dev Jain <dev.jain@arm.com>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
mm/vmalloc.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 73 insertions(+), 2 deletions(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 516d40650..c30a7673e 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3520,6 +3520,77 @@ void vunmap(const void *addr)
}
EXPORT_SYMBOL(vunmap);
+static inline int get_vmap_batch_order(struct page **pages,
+ unsigned int max_steps, unsigned int idx)
+{
+ unsigned int nr_contig;
+ int order;
+
+ if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP) ||
+ ioremap_max_page_shift == PAGE_SHIFT)
+ return 0;
+
+ nr_contig = num_pages_contiguous(&pages[idx], max_steps);
+ if (nr_contig < 2)
+ return 0;
+
+ order = fls(nr_contig) - 1;
+
+ if (arch_vmap_pte_supported_shift(PAGE_SIZE << order) == PAGE_SHIFT)
+ return 0;
+
+ /* Ensure the first page's pfn is aligned to the order */
+ if (!IS_ALIGNED(page_to_pfn(pages[idx]), 1 << order))
+ return 0;
+
+ return order;
+}
+
+static int __vmap_huge(unsigned long addr, unsigned long end,
+ pgprot_t prot, struct page **pages)
+{
+ unsigned int count = (end - addr) >> PAGE_SHIFT;
+ unsigned int prev_shift = 0, idx = 0;
+ unsigned long map_addr = addr;
+ int err;
+
+ err = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,
+ PAGE_SHIFT, GFP_KERNEL);
+ if (err)
+ goto out;
+
+ for (unsigned int i = 0; i < count; ) {
+ unsigned int shift = PAGE_SHIFT +
+ get_vmap_batch_order(pages, count - i, i);
+
+ if (!i)
+ prev_shift = shift;
+
+ if (shift != prev_shift) {
+ err = vmap_pages_range_noflush_walk(map_addr, addr,
+ prot, pages + idx,
+ min(prev_shift, PMD_SHIFT));
+ if (err)
+ goto out;
+ prev_shift = shift;
+ map_addr = addr;
+ idx = i;
+ }
+
+ addr += 1UL << shift;
+ i += 1U << (shift - PAGE_SHIFT);
+ }
+
+ /* Remaining */
+ if (map_addr < end)
+ err = vmap_pages_range_noflush_walk(map_addr, end,
+ prot, pages + idx, min(prev_shift, PMD_SHIFT));
+
+out:
+ flush_cache_vmap(addr, end);
+ return err;
+}
+
/**
* vmap - map an array of pages into virtually contiguous space
* @pages: array of page pointers
@@ -3563,8 +3634,8 @@ void *vmap(struct page **pages, unsigned int count,
return NULL;
addr = (unsigned long)area->addr;
- if (vmap_pages_range(addr, addr + size, pgprot_nx(prot),
- pages, PAGE_SHIFT) < 0) {
+ if (__vmap_huge(addr, addr + size, pgprot_nx(prot),
+ pages) < 0) {
vunmap(area->addr);
return NULL;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v2 7/7] mm/vmalloc: Stop scanning for compound pages after encountering small pages in vmap
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
Users typically allocate memory in descending orders, e.g.
8 → 4 → 0. Once an order-0 page is encountered, subsequent
pages are likely to also be order-0, so we stop scanning
for compound pages at that point.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
mm/vmalloc.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index b3389c8f1..60579bfbf 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3576,6 +3576,12 @@ static int __vmap_huge(unsigned long addr, unsigned long end,
map_addr = addr;
idx = i;
}
+ /*
+ * Once small pages are encountered, the remaining pages
+ * are likely small as well
+ */
+ if (shift == PAGE_SHIFT)
+ break;
addr += 1UL << shift;
i += 1U << (shift - PAGE_SHIFT);
--
2.34.1
^ permalink raw reply related
* [PATCH v2 6/7] mm/vmalloc: align vm_area so vmap() can batch mappings
From: Wen Jiang @ 2026-05-14 9:41 UTC (permalink / raw)
To: linux-mm, linux-arm-kernel, catalin.marinas, will, akpm, urezki
Cc: baohua, Xueyuan.chen21, dev.jain, rppt, david, ryan.roberts,
anshuman.khandual, ajd, linux-kernel, Wen Jiang, Xueyuan Chen
In-Reply-To: <20260514094108.2016201-1-jiangwen6@xiaomi.com>
From: "Barry Song (Xiaomi)" <baohua@kernel.org>
Try to align the vmap virtual address to PMD_SHIFT or a
larger PTE mapping size hinted by the architecture, so
contiguous pages can be batch-mapped when setting PMD or
PTE entries.
Signed-off-by: Barry Song (Xiaomi) <baohua@kernel.org>
Signed-off-by: Wen Jiang <jiangwen6@xiaomi.com>
Tested-by: Xueyuan Chen <xueyuan.chen21@gmail.com>
---
mm/vmalloc.c | 31 ++++++++++++++++++++++++++++++-
1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index c30a7673e..b3389c8f1 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3591,6 +3591,35 @@ static int __vmap_huge(unsigned long addr, unsigned long end,
return err;
}
+static struct vm_struct *get_aligned_vm_area(unsigned long size, unsigned long flags)
+{
+ unsigned int shift = (size >= PMD_SIZE) ? PMD_SHIFT :
+ arch_vmap_pte_supported_shift(size);
+ struct vm_struct *vm_area = NULL;
+
+ /*
+ * Try to allocate an aligned vm_area so contiguous pages can be
+ * mapped in batches.
+ */
+ while (1) {
+ unsigned long align = 1UL << shift;
+
+ vm_area = __get_vm_area_node(size, align, PAGE_SHIFT, flags,
+ VMALLOC_START, VMALLOC_END,
+ NUMA_NO_NODE, GFP_KERNEL,
+ __builtin_return_address(0));
+ if (vm_area || shift <= PAGE_SHIFT)
+ goto out;
+ if (shift == PMD_SHIFT)
+ shift = arch_vmap_pte_supported_shift(size);
+ else if (shift > PAGE_SHIFT)
+ shift = PAGE_SHIFT;
+ }
+
+out:
+ return vm_area;
+}
+
/**
* vmap - map an array of pages into virtually contiguous space
* @pages: array of page pointers
@@ -3629,7 +3658,7 @@ void *vmap(struct page **pages, unsigned int count,
return NULL;
size = (unsigned long)count << PAGE_SHIFT;
- area = get_vm_area_caller(size, flags, __builtin_return_address(0));
+ area = get_aligned_vm_area(size, flags);
if (!area)
return NULL;
--
2.34.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