* [PATCH v4 0/3] riscv: support effective hardware PTE A/D updates
From: Yunhui Cui @ 2026-06-18 6:44 UTC (permalink / raw)
To: akpm, alex, andrew+kernel, aou, apatel, apopple, atishp,
baolin.wang, cleger, conor+dt, cuiyunhui, debug, devicetree,
guodong, hui.wang, krzk+dt, linux-kernel, linux-riscv,
liu.xuemei1, namcao, nick.hu, palmer, pincheng.plct, pjw,
qingwei.hu, ritesh.list, rmclure, robh, wangruikang, zhangchunyan,
zong.li
This series makes RISC-V track hardware PTE A/D updating by the
effective runtime state instead of treating Svadu discovery alone as
enough.
When both Svade and Svadu are present, Svadu is disabled at boot and
must be enabled through SBI FWFT. The series enables FWFT PTE A/D
hardware updating on all currently online CPUs before enabling the
global static key, and enables it for later hotplug CPUs early in
smp_callin(), before they are marked online. If FWFT setup fails, the
kernel falls back to software-managed A/D updates.
It also makes live PTE access/permission updates use cmpxchg-based
merges so that software updates do not lose concurrently
hardware-updated accessed, dirty, or soft-dirty state.
Changes since v3:
- Keep the only-Svadu binding contract as always enabled, and only
describe the Svade+Svadu boot state as disabled instead of turned-off.
- Detect the need for FWFT from per-CPU Svade state instead of the global
ISA intersection, so asymmetric Svade/Svadu systems do not skip FWFT.
- Document the secondary-hart FWFT bringup state flow in the commit log.
Yunhui Cui (3):
dt-bindings: riscv: describe Svadu as disabled at boot
riscv: track effective hardware PTE A/D updating
riscv: preserve A/D and soft-dirty state across PTE updates
.../devicetree/bindings/riscv/extensions.yaml | 2 +-
arch/riscv/include/asm/cpufeature.h | 8 ++
arch/riscv/include/asm/pgtable.h | 27 +++--
arch/riscv/kernel/cpufeature.c | 101 ++++++++++++++++--
arch/riscv/kernel/smpboot.c | 4 +
arch/riscv/mm/pgtable.c | 68 ++++++++++--
6 files changed, 185 insertions(+), 25 deletions(-)
--
2.39.5
^ permalink raw reply
* Re: [PATCH v2 1/4] soc: qcom: rpmh: Allow non-child devices to issue write commands
From: Fenglin Wu @ 2026-06-18 6:39 UTC (permalink / raw)
To: Dmitry Baryshkov, Konrad Dybcio
Cc: linux-arm-msm, Bjorn Andersson, Konrad Dybcio, Linus Walleij,
Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bartosz Golaszewski, David Collins, Subbaraman Narayanamurthy,
Kamal Wadhwa, Maulik Shah, kernel, linux-kernel, linux-gpio,
devicetree
In-Reply-To: <ao2bl4vzgb3mvqnk2kgvgqnifujbvy6oyzuj4rnvjrv6teyrel@56txzbrtwm64>
On 6/12/2026 8:27 AM, Dmitry Baryshkov wrote:
> On Thu, Jun 11, 2026 at 12:36:43PM +0200, Konrad Dybcio wrote:
>> On 6/9/26 3:28 AM, Fenglin Wu wrote:
>>> On 6/8/2026 5:21 AM, Dmitry Baryshkov wrote:
>>>> On Thu, Jun 04, 2026 at 10:02:43AM +0800, Fenglin Wu wrote:
>>>>> On 6/2/2026 3:29 PM, Fenglin Wu wrote:
>>>>>> On 6/1/2026 9:37 PM, Dmitry Baryshkov wrote:
>>>>>>> On Thu, May 28, 2026 at 06:05:35PM -0700, Fenglin Wu wrote:
>>>>>>>> Currently, the RPMH driver only allows child devices of the RPMH
>>>>>>>> controller to issue commands, as it assumes dev->parent points to the
>>>>>>>> RSC device.
>>>>>>>>
>>>>>>>> There is a possibility that certain devices which are not children of
>>>>>>>> the RPMH controller want to send commands for special control at the
>>>>>>>> RPMH side. For example, in PMH0101 PMICs, there are bidirectional
>>>>>>>> level shifter (LS) peripherals, and each LS works with a pair of PMIC
>>>>>>>> GPIOs. The control of the LS, which is combined with the GPIO
>>>>>>>> configuration, is handled by RPMH firmware for sharing the resource
>>>>>>>> between different subsystems. From a hardware point of view, the LS
>>>>>>>> functionality is tied to a pair of PMIC GPIOs, so its control is more
>>>>>>>> suitable to be added in the pinctrl-spmi-gpio driver by adding the
>>>>>>>> level-shifter function. However, the pinctrl-spmi-gpio device is a
>>>>>>>> child device of the SPMI controller, not the RPMH controller.
>>>>>>> This replicates the story of the PMIC regulators. There are two drivers,
>>>>>>> one SPMI and one RPMh. Why don't we add a separate, RPMh-based GPIO
>>>>>>> driver targeting only those paired GPIOs (and we don't even need to
>>>>>>> represent them as a pair, it might be just one pin).
>>>>>> Thanks for the suggestion.
>>>>>>
>>>>>> I agree that adding a separate, RPMh-based GPIO driver would be more
>>>>>> straightforward from RPMh control perspective. It makes the new device
>>>>>> as a child of the RSC device then it can naturally use the APIs for RPMh
>>>>>> commands. The main challenge here is, we need to make the level-shifter
>>>>>> mutually exclusive with other GPIO functions when the GPIO pairs are
>>>>>> used in level-shifter function, which means we need to write SPMI
>>>>>> commands to disable the associated GPIO modules. I am not sure if AOP
>>>>>> already handles this; as far as I know, AOP only manages the
>>>>>> BIDIR_LVL_SHIFTER module registers. Let me double check on this
>>>>>> internally, if the GPIO modules could be controlled along
>>>>>> with BIDIR_LVL_SHIFTER module registers at AOP side, and get back.
>>>>>>
>>>>> I checked on this internally, AOP only handles BIDIR_LVL_SHIFTER module
>>>>> registers, it doesn't disable the associated GPIO modules. Also, I still
>>>>> have no idea how could we make the "level-shifter" function to be mutually
>>>>> exclusive with other GPIO functions after moved it into a separate driver.
>>>>> Do you have further suggestions?
>>>> So, for my understanding, we still need to write SPMI registers to
>>>> configure the pins and only then AOP can handle the level shifter?
>>>>
>>>> I was thinking of using gpio-reserved-ranges to prevent those GPIOs from
>>>> being used by the normal SPMI driver.
>>> More background: "level-shifter" module is actually an independent hardware which is not part of the GPIO module. However, they are sharing the physical pins. Which means, from PMIC chip perspective, these pins can be configured to either a GPIO function or the "level-shifter" function. So in PMIC base dtsi file, for example, pmh0101.dtsi, these pins should not be restricted in the GPIO nodes in "gpio-reserved-ranges".
>>>
>>> Also, we need to make the GPIO modules are disabled when the "level-shifter" is enabled, to ensure that the "level-shifter" circuitry is not impacted by the GPIO modules internal circuitry. So it is supposed to write GPIO EN_CTL register (offset 0x46) to 0 through SPMI bus when the "level-shifter" is enabled.
>>>
>>> That's why we have the requirement to access both RPMh and SPMI bus in the same driver.
>> I was thinking about other ways to solve it.. maybe someting like:
>>
>> &pmh0101_gpios {
>> pmh0101_ls_pins1_2: foo-bar {
>> pins = "gpio1", "gpio2";
>> // appropriate pinctrl config
>> };
>> };
>>
>> &rpmh_rsc {
>> // should this be a gpio controller? a mux provider?
>> // is there another class that would better suit this?
>> rpmh_level_shifter: rpmh-foo-bar {
>> pinctrl-0 = <&>;
>> pinctrl-names = "default";
>> };
>> };
>>
>> // but where would it make sense to describe?
>> // fixed-regulator or something akin to that?
>> &some_consumer {
>> someclass = <&rpmh_level_shifter 1>;
>> };
>>
>> i.e. the "rpmh level shifter" driver would consume a reference to the
>> pins, configure them as necessary (just like any other pinctrl consumer)
>> upon request
> SGTM.
Thanks for the suggestion, Konrad and Dmitry!
Using the pinctrl state in the new driver to disable GPIO pairs is a
good idea. I’ve been considering which class would best support the PMIC
level-shifter, especially since we’re moving it to a new driver and it’s
no longer restricted by the pinctrl framework. Functionally, the driver
should provide following capabilities:
1. Enable and disable the level-shifter at runtime. Consumers, likely
I2C client devices, will enable it when active and disable it when not,
mainly to save power.
2. Allow sharing the level-shifter between multiple consumers, even
across different subsystems (currently managed by AOP).
I see flaws in each of the following approaches and haven’t decided
which to use:
A. Using the mux subsystem: The level-shifter acts as a switch, so it
fits the mux subsystem physically. It can be enabled/disabled via
‘mux_control_select()’ and ‘mux_control_deselect()’. However, with
multiple consumers, a second call to ‘mux_control_select()’ is blocked
until ‘mux_control_deselect()’ is called, so votes from multiple
consumers are not allowed and can’t be aggregated.
B. Using the GPIO/pinctrl subsystem: After moving to a new driver, the
level-shifter doesn’t fit the GPIO controller or pinctrl device concept.
It has only one pinmux, and each level-shifter works with two pins.
Also, both GPIO and pinctrl frameworks require exclusive control, and
couldn't shared between consumers.
C. Using the regulator framework: The level-shifter is controlled via
the RPMh XOB resource at the AOP side, which was adopted from the idea
of power rails sharing between subsystems. The regulator framework’s
APIs and reference counting fit the requirements for sharing between
multiple consumers. The problem is, the level-shifter isn’t a power rail
so it is conceptually not a regulator.
Please let me know your thoughts. If there isn’t a suitable approach for
supporting the PMIC level-shifter right now, I’ll stop chasing on this
until there is a better idea.
Thanks
>> Konrad
^ permalink raw reply
* Re: [PATCH v4 3/3] arm64: dts: qcom: Add Vicharak Axon Mini
From: Ajit Singh @ 2026-06-18 6:29 UTC (permalink / raw)
To: Konrad Dybcio
Cc: Bjorn Andersson, Bartosz Golaszewski, Dmitry Baryshkov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, linux-arm-msm,
devicetree, linux-kernel
In-Reply-To: <5c80c430-8bc7-4d03-be7e-c6dd518705e7@oss.qualcomm.com>
On Tue, Jun 16, 2026 at 02:10:44PM +0530, Konrad Dybcio wrote:
> On 6/12/26 6:16 AM, Ajit Singh wrote:
> > On Wed, Jun 10, 2026 at 02:58:19PM +0530, Konrad Dybcio wrote:
> >> On 6/7/26 1:36 PM, Ajit Singh wrote:
> >>> Add DTS for the Vicharak Axon Mini board based on the Qualcomm
> >>> QCS6490 SoC.
> >>>
> >>> This adds debug UART, eMMC, UFS, SDIO WLAN, USB 2.0 host, PCIe
> >>> support along with regulators.
> >>>
> >>> The UFS ICE block is kept disabled because enabling it currently causes
> >>> an SError during qcom_ice_create() on this board. UFS works without ICE.
> >>>
> >>> Signed-off-by: Ajit Singh <blfizzyy@gmail.com>
> >>> ---
> >>
> >> [...]
> >>
> >>> + vreg_l12c_1p8: ldo12 {
> >>> + regulator-name = "vreg_l12c_1p8";
> >>> + regulator-min-microvolt = <1800000>;
> >>> + regulator-max-microvolt = <2000000>;
> >>> + regulator-initial-mode = <RPMH_REGULATOR_MODE_HPM>;
> >>> +
> >>> + /*
> >>> + * VREG_L12C_1P8 supplies the Ampak WLAN/BT module
> >>> + * VDDIO and the external 32.768 kHz oscillator.
> >>> + */
> >>
> >> Sorry for the long review timelines on the previous patch, many of us
> >> were out for conferences..
> >>
> >> Is the oscillator used for that WLAN module? Would you ideally like to
> >> be able to turn it on/off?
> >
> > yes, oscillator is used for WLAN modules. Oscillator is powered from the same
> > VREG_L12C rail as WLAN VDDIO, so there is no separate regulator control to put
> > in pwrseq. So I think this will work fine?
>
> Probably? My point is that you marked it as always-on, so it will *never*
> turn off right now. For e.g. Qualcomm wifi, there's some timing spec that
> needs to be met wrt delays between toggling various regulators and GPIOs
> going to the module, hence I suggested you may need some pwrseq inbetween
> to achieve reliable powering on/off
>
Right, I checked the module timing requirements.
The module requires VBAT to be present before or at the same time as VDDIO, and
WL_REG_ON to be asserted only after VBAT/VDDIO are valid, around 2 sleep-clock
cycles later.
On this board, VBAT is the shared VCC_3V3 rail and is enabled by hardware, so
it is already present before VDDIO. VREG_L12C supplies WLAN/BT VDDIO and is
kept on. The WL_REG_ON timing is handled by the existing mmc-pwrseq-simple
reset GPIO/delay before SDIO enumeration.
So I think the current sequencing matches the module timing requirement.
> Konrad
Ajit
^ permalink raw reply
* Re: [PATCH v3 2/3] media: i2c: add os02g10 image sensor driver
From: Elgin Perumbilly @ 2026-06-18 6:22 UTC (permalink / raw)
To: Vladimir Zapolskiy, sakari.ailus@linux.intel.com,
laurent.pinchart@ideasonboard.com
Cc: Tarang Raval, Mauro Carvalho Chehab, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Hans Verkuil, Hans de Goede,
Mehdi Djait, Sylvain Petinot, Benjamin Mugnier,
Bryan O'Donoghue, Himanshu Bhavani, Heimir Thor Sverrisson,
Jingjing Xiong, Svyatoslav Ryhel, linux-media@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <421ae63a-88c6-4e81-8478-7f581357676b@linaro.org>
Hi Vladimir,
Thank you for the review.
I have addressed all of the comments except for two, where I am not entirely
sure about the requested changes. Could you please take a look at the points
below and let me know your opinion?
> On 4/24/26 12:25, Elgin Perumbilly wrote:
> > Add a v4l2 subdevice driver for the Omnivision os02g10 sensor.
> >
> > The Omnivision os02g10 is a CMOS image sensor with an active array size of
> > 1920 x 1080.
> >
> > The following features are supported:
> > - Manual exposure an gain control support
> > - vblank/hblank control support
> > - vflip/hflip control support
> > - Test pattern control support
> > - Supported resolution: 1920 x 1080 @ 30fps (SBGGR10)
> >
> > Signed-off-by: Elgin Perumbilly <elgin.perumbilly@siliconsignals.io>
> > Reviewed-by: Tarang Raval <tarang.raval@siliconsignals.io>
...
> > +#include <linux/array_size.h>
> > +#include <linux/bitops.h>
> > +#include <linux/cleanup.h>
> > +#include <linux/clk.h>
> > +#include <linux/container_of.h>
> > +#include <linux/delay.h>
> > +#include <linux/err.h>
> > +#include <linux/gpio/consumer.h>
> > +#include <linux/i2c.h>
> > +#include <linux/module.h>
> > +#include <linux/mutex.h>
> > +#include <linux/pm_runtime.h>
> > +#include <linux/property.h>
> > +#include <linux/regulator/consumer.h>
> > +#include <linux/units.h>
> > +#include <linux/types.h>
> > +#include <linux/time.h>
> > +#include <linux/regmap.h>
>
> Please sort the list of includes in alphabetical order, also you
> may consider to shrink the list by removing quite many inherited
> includes.
Some maintainers prefer the "include what you use" approach, like Andy,
so I added all the headers that are directly used. Should I now remove
any inherited includes?
> > +#include <media/v4l2-cci.h>
> > +#include <media/v4l2-ctrls.h>
> > +#include <media/v4l2-device.h>
> > +#include <media/v4l2-fwnode.h>
> > +#include <media/v4l2-mediabus.h>
...
> > +static int os02g10_set_framefmt(struct os02g10 *os02g10,
> > + struct v4l2_subdev_state *state)
> > +{
> > + const struct v4l2_mbus_framefmt *format;
> > + const struct os02g10_mode *mode;
> > + int ret = 0;
> > +
> > + format = v4l2_subdev_state_get_format(state, 0);
> > + mode = v4l2_find_nearest_size(supported_modes,
> > + ARRAY_SIZE(supported_modes), width,
> > + height, format->width, format->height);
> > +
> > + cci_write(os02g10->cci, OS02G10_REG_V_START, mode->y_start, &ret);
> > + cci_write(os02g10->cci, OS02G10_REG_V_SIZE, mode->height, &ret);
> > + cci_write(os02g10->cci, OS02G10_REG_V_SIZE_MIPI, mode->height, &ret);
> > + cci_write(os02g10->cci, OS02G10_REG_H_START, mode->x_start, &ret);
> > + cci_write(os02g10->cci, OS02G10_REG_H_SIZE, mode->width, &ret);
> > + cci_write(os02g10->cci, OS02G10_REG_H_SIZE_MIPI, mode->width, &ret);
> > +
> > + return ret;
>
> Just "return 0" here, and remove the local variable.
Could you clarify why this should return 0? The local ret is passed to all
cci_write() calls so that any write error is propagated. Returning 0 here
would appear to suppress those errors and always report success.
Best Regards,
Elgin
^ permalink raw reply
* Re: [External] Re: [PATCH v3 2/3] riscv: track effective hardware PTE A/D updating
From: yunhui cui @ 2026-06-18 6:16 UTC (permalink / raw)
To: sashiko-reviews; +Cc: robh, conor+dt, devicetree
In-Reply-To: <20260609131621.3541C1F00898@smtp.kernel.org>
Hi sashiko,
On Tue, Jun 9, 2026 at 9:16 PM <sashiko-bot@kernel.org> wrote:
>
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] Incorrect global ISA extension check prevents FWFT enablement on asymmetric SVADE/SVADU systems.
> --
>
> commit f3d7c0060d5bf449bef26605d30b6a4b56780451
> Author: Yunhui Cui <cuiyunhui@bytedance.com>
> Subject: riscv: track effective hardware PTE A/D updating
>
> This commit separates the tracking of hardware PTE A/D updating from SVADU
> discovery. It enables Firmware Features (FWFT) on all online harts before
> globally advertising the feature, and requires secondary harts to enable it
> before they are marked online.
>
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > --- a/arch/riscv/kernel/cpufeature.c
> > +++ b/arch/riscv/kernel/cpufeature.c
> [ ... ]
> > @@ -287,15 +291,88 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
> > static int __init riscv_hw_pte_ad_updating_init(void)
> > {
> > bool has_svade, has_svadu;
> > int ret;
> >
> > has_svade = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADE);
> > has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> >
> > if (!has_svadu)
> > return 0;
> >
> > if (has_svade) {
> > riscv_hw_pte_ad_updating_requires_fwft = true;
> > ret = riscv_set_online_hw_pte_ad_updating(true);
>
> [Severity: High]
> Since riscv_has_extension_unlikely checks the global intersection of
> extensions, will has_svade evaluate to false on an asymmetric system where
> some CPUs support both SVADE and SVADU, but others only support SVADU?
Thanks, I'll address this in v4.
>
> If has_svade evaluates to false, FWFT enablement is skipped here, but
> riscv_set_hw_pte_ad_updating is unconditionally called at the end of this
> function. Could this cause the kernel to assume hardware A/D tracking is
> active globally, even though CPUs with both extensions would remain in their
> default software-managed SVADE mode?
>
> If the kernel incorrectly assumes hardware A/D tracking is active, would this
> cause arch_has_hw_pte_young to return true and erroneously expose the SVADU
> extension to KVM guests? It seems like this could lead to unexpected VS-stage
> page faults and guest crashes if the underlying host CPU traps on missing A/D
> bits while the guest OS expects hardware updates.
>
> [ ... ]
>
> --
> Sashiko AI review · https://sashiko.dev/#/patchset/20260609130021.99899-1-cuiyunhui@bytedance.com?part=2
Thanks,
Yunhui
^ permalink raw reply
* Re: [PATCH 3/9] firmware: imx: ele: Add API functions for OCOTP fuse access
From: Frieder Schrempf @ 2026-06-18 5:52 UTC (permalink / raw)
To: Frank Li
Cc: Pankaj Gupta, Peng Fan (OSS), Frieder Schrempf,
Srinivas Kandagatla, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Shawn Guo, devicetree, imx, linux-arm-kernel,
linux-kernel
In-Reply-To: <ajL7-OqjYuQHyZOI@SMW015318>
On 17.06.26 21:56, Frank Li wrote:
> On Wed, Jun 17, 2026 at 08:54:35AM +0200, Frieder Schrempf wrote:
>> On 16.06.26 22:05, Frank Li wrote:
>>> On Tue, Jun 16, 2026 at 07:59:54PM +0200, Frieder Schrempf wrote:
>>>> On 16.06.26 17:36, Frank Li wrote:
>>>>> On Tue, Jun 16, 2026 at 01:52:18PM +0200, Frieder Schrempf wrote:
>>>>>> From: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>>
>>>>>> The ELE S400 API provides read and write access to the OCOTP fuse
>>>>>> registers. This adds the necessary API functions imx_se_read_fuse()
>>>>>> and imx_se_write_fuse() to be used by other drivers such as the
>>>>>> OCOTP S400 NVMEM driver.
>>>>>>
>>>>>> This is ported from the downstream vendor kernel.
>>>>>>
>>>>>> Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
>>>>>> ---
>>>>>> drivers/firmware/imx/ele_base_msg.c | 122 ++++++++++++++++++++++++++++++++++++
>>>>>> drivers/firmware/imx/ele_base_msg.h | 6 ++
>>>>>> include/linux/firmware/imx/se_api.h | 3 +
>>>>>> 3 files changed, 131 insertions(+)
>>>>>>
>>>>> ...
>>>>>> +++ b/include/linux/firmware/imx/se_api.h
>>>>>> @@ -11,4 +11,7 @@
>>>>>> #define SOC_ID_OF_IMX8ULP 0x084d
>>>>>> #define SOC_ID_OF_IMX93 0x9300
>>>>>>
>>>>>> +int imx_se_read_fuse(void *se_if_data, uint16_t fuse_id, u32 *value);
>>>>>> +int imx_se_write_fuse(void *se_if_data, uint16_t fuse_id, u32 value);
>>>>>> +
>>>>>
>>>>> This API should implement in fuse drivers. Other consume should use standard
>>>>> fuse API to get value. If put here, it may bypass fuse driver.
>>>>
>>>> The reason this is here, is the downstream implementation in linux-imx
>>>> and the current code organization.
>>>
>>> Downstream may not good enough, sometime, it is quick solution.
>>
>> Ok, but the code structure and API design has been upstreamed like this
>> and the refactoring could have been done before, if downstream is known
>> to not be well organized.
>>
>>>
>>>> I thought there is some good reason
>>>> to have shared functions and it looks like Pankaj structured it like
>>>> this so all API functions live in ele_base_msg.c and the internal
>>>> structs and defines in ele_base_msg.h and se_ctrl.h are not exposed to
>>>> other drivers.
>>>>
>>>> If I would move this into imx-ocotp-ele.c, then I would also need to
>>>> change how the code is organized and make the internal se_api functions
>>>> exposed to other drivers. I don't know if that is really a good idea.
>>>>
>>>> I get your point but it looks like this contradicts the intention of
>>>> having a clean API in the firmware driver.
>>>
>>> You can refer imx-ocotp-scu.c, structure should be similar, only difference
>>> is that lower transfer APIs.
>> Ok, this would mean that I expose the generic SE functions and structs
>> required for fuse handling. In practice, I would remove
>> imx_se_read_fuse() and imx_se_write_fuse() from se_api.h and instead add
>> the following:
>>
>> struct se_msg_hdr { ... };
>> struct se_api_msg { ... };
>> struct se_if_priv;
>> se_fill_cmd_msg_hdr( ... );
>> se_msg_send_rcv( ... );
>> se_val_rsp_hdr_n_status( ... );
>>
>> Then I would export the functions in ele_common.c and put the fuse
>> read/write functions in the NVMEM driver.
>>
>> Is that what you want me to do?
>
> Yes, Idealy, it should be children device under ele, ELE like a bus, which
> previous lower level data transfer, ocotp should be base on top then it.
> like spi/i2c, which provide low level data transfer.
Ok, please also see the discussion with Krzysztof on the bindings patch.
The problem is that this driver uses both, MMIO and firmware interface.
Therefore putting a child node in the ELE device node is probably not
correct, either!?
In general I think it's a good idea as the fuses actually live inside
the ELE block so this would properly describe the hardware, but again
this would create a hard dependency on the closed source ELE firmware
which I don't like that much.
^ permalink raw reply
* Re: [PATCH v2 1/2] dt-bindings: PCI: qcom: Document the Hawi PCIe Controller
From: Manivannan Sadhasivam @ 2026-06-18 5:51 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Matthew Leung, Bjorn Helgaas, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, linux-arm-msm, linux-pci,
devicetree, linux-kernel
In-Reply-To: <m2kwzigrz4fbdedzr2bj2auqtvafj6qstbplghssato4d6tdnd@ftug3clgxmd6>
On Fri, Jun 12, 2026 at 09:22:10AM +0300, Dmitry Baryshkov wrote:
> On Thu, Jun 11, 2026 at 06:17:57PM -0700, Matthew Leung wrote:
> > On Sun, Jun 07, 2026 at 11:01:10PM +0300, Dmitry Baryshkov wrote:
> > > On Fri, May 29, 2026 at 01:10:08AM +0000, Matthew Leung wrote:
> > > > Add a dedicated schema for the PCIe controllers found on the Hawi
> > > > platform.
> > > >
> > > > Signed-off-by: Matthew Leung <matthew.leung@oss.qualcomm.com>
> > > > ---
> > > > .../devicetree/bindings/pci/qcom,hawi-pcie.yaml | 204 +++++++++++++++++++++
> > > > 1 file changed, 204 insertions(+)
> > > >
> > > > +
> > > > +examples:
> > > > + - |
> > > > + #include <dt-bindings/clock/qcom,hawi-gcc.h>
> > > > + #include <dt-bindings/gpio/gpio.h>
> > > > + #include <dt-bindings/interconnect/qcom,icc.h>
> > > > + #include <dt-bindings/interconnect/qcom,hawi-rpmh.h>
> > >
> > > Stop referencing clocks and interconnect header files. Replace used nocs
> > > with ephemeral values.
> > >
> > > > + #include <dt-bindings/interrupt-controller/arm-gic.h>
> > > > +
> > > > + soc {
> > > > + #address-cells = <2>;
> > > > + #size-cells = <2>;
> > >
> > > Not looking around should be a sin. Take a look at other Qualcomm PCIe
> > > bindings. Compare them to yours. Then fix yours to follow.
> > >
> > > Hint: the extra soc node is useless. This is just an example, so use the
> > > default, 1 cells for address and size.
> >
> > Thank you for the feedback. This new binding follows the examples set in
> > the qcom,pcie-sm8x50 bindings and retains the same formatting (extra soc
> > node and header references).
>
> Hmm, interesting. Then I'm a sinner :-)
>
> I looked at msm8996, but I didn't notice that the rest of the files use
> the soc node (and match what you've sent). Please excuse me.
>
Stop looking at MSM8996 and have some compassion for newer SoCs ;)
> >
> > I understand the example can be simplified with your suggestions but
> > want additional confirmation that these will be the convention for new
> > bindings going forward.
>
> At least, let's keep it for now. The other comment stands. To remove
> dependencies please use ephemeral nodes instead of depending on DT
> bindings from other subsystems.
>
Agree. Since this series missed 7.2 merge window, the dependency won't matter
now. But for the sake of correctness, we should use ephemeral nodes going
forward.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH 10/11] regulator: db8500: Add power domain regulators
From: sashiko-bot @ 2026-06-18 5:23 UTC (permalink / raw)
To: Linus Walleij
Cc: devicetree, vkoul, robh, conor+dt, dmaengine, Frank.Li, dri-devel
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-10-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] The `db8500_regulator_disable` callback incorrectly treats a return value of 1 from `pm_runtime_put_sync_suspend` as an error, causing early abort and state desynchronization.
- [High] Mismatched Genpd APIs (`of_genpd_add_device` paired with `dev_pm_domain_detach`) lead to a silent detach failure and Use-After-Free list corruption.
- [High] Embedding a `struct device` in a devres-managed structure (`devm_kzalloc`) with an empty release function causes a lifecycle violation and Use-After-Free.
- [High] The virtual device is never fully registered with `device_add()`, leading to a memory leak of PM QoS constraints.
- [High] The driver saves an OF node pointer to the persistent device structure without incrementing its reference count, risking a dangling pointer.
--
commit abd72295748300bd01e4a7216b2321ff24b1a38f
Author: Linus Walleij <linusw@kernel.org>
regulator: db8500: Add power domain regulators
Add a DB8500 regulator driver for the VAPE and VSMPS2 compatibility nodes,
backing the regulator enable state with corresponding power domains.
> diff --git a/drivers/regulator/db8500-regulator.c b/drivers/regulator/db8500-regulator.c
> new file mode 100644
> index 0000000000000..c5a9a1baaf8ea
> --- /dev/null
> +++ b/drivers/regulator/db8500-regulator.c
[ ... ]
> +static int db8500_regulator_disable(struct regulator_dev *rdev)
> +{
> + struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
> + int ret;
> +
> + ret = pm_runtime_put_sync_suspend(&info->pd_dev);
> + if (ret)
> + return ret;
[Severity: High]
Does this propagate a success status as an error?
According to the PM subsystem rules, pm_runtime_put_sync_suspend() returns 1
when the device is already in the RPM_SUSPENDED state. Since this checks
if (ret) and returns it, won't the regulator core treat this as a failure,
aborting the disable operation and leaving the regulator's use_count and
enable_count out of sync?
[ ... ]
> +static void db8500_regulator_release(struct device *dev)
> +{
> +}
[Severity: High]
Does this empty release function circumvent kobject lifecycle tracking?
The struct device is embedded in devres memory allocated via devm_kzalloc().
Since put_device() does not guarantee synchronous memory reclamation, will
devres forcibly free the memory when the driver unbinds, creating a
use-after-free for any subsystem still holding a reference to pd_dev?
> +
> +static void db8500_regulator_cleanup(void *data)
> +{
> + struct db8500_regulator_info *info = data;
> +
> + pm_runtime_disable(&info->pd_dev);
> + dev_pm_domain_detach(&info->pd_dev, true);
[Severity: High]
Will this detach silently fail?
The device is attached using of_genpd_add_device(), which adds it to
genpd->dev_list but does not populate the dev->pm_domain->detach callback.
Since dev_pm_domain_detach() checks for that callback, won't it be a no-op,
leaving the device in the genpd active lists when freed and causing a
use-after-free?
Should this use pm_genpd_remove_device() instead?
> + put_device(&info->pd_dev);
> +}
[ ... ]
> +static int db8500_regulator_register(struct platform_device *pdev,
> + struct device_node *np)
> +{
[ ... ]
> + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
> + if (!info)
> + return -ENOMEM;
> +
> + device_initialize(&info->pd_dev);
> + info->pd_dev.parent = &pdev->dev;
> + info->pd_dev.of_node = np;
[Severity: High]
Could this leave a dangling pointer in info->pd_dev.of_node?
The np pointer is provided by for_each_available_child_of_node() in
db8500_regulator_probe(), which automatically drops the reference on the
node when advancing the loop.
Since of_node_get() isn't used here to increment the reference count, will
the reference be dropped when the loop concludes?
> + info->pd_dev.release = db8500_regulator_release;
> + ret = dev_set_name(&info->pd_dev, "%s-pd", match->name);
> + if (ret)
> + goto put_device;
> +
> + ret = of_parse_phandle_with_args(np, "power-domains", cells, 0, &pd_args);
> + if (ret)
> + goto put_device;
> +
> + ret = of_genpd_add_device(&pd_args, &info->pd_dev);
[Severity: High]
Does this leak PM QoS constraints?
The device is initialized with device_initialize() but never fully registered
with device_add().
Since of_genpd_add_device() automatically registers a resume latency QoS
notifier that dynamically allocates PM QoS constraint structures, and those
are normally freed by device_del(), will these structures leak upon cleanup
because device_del() is never called?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=10
^ permalink raw reply
* Re: [PATCH v7 2/4] PCI: Use standard wait times for PCIe link monitoring
From: Aksh Garg @ 2026-06-18 5:19 UTC (permalink / raw)
To: Thierry Reding, Bjorn Helgaas, Lorenzo Pieralisi,
Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Karthikeyan Mitran, Hou Zhiqiang,
Thomas Petazzoni, Pali Rohár, Michal Simek, Kevin Xie
Cc: linux-pci, devicetree, linux-tegra, linux-kernel,
linux-arm-kernel, Thierry Reding
In-Reply-To: <20260617-tegra264-pcie-v7-2-eae7ae964629@nvidia.com>
On 17/06/26 21:31, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Instead of defining the wait values for each driver, use common values
> defined in the core pci.h header file. Note that while most drivers use
> the usleep_range(), it looks like these were mostly cargo culted and
> msleep() is a better choice given the fixed delay that the specification
> calls for. Convert all drivers to msleep() and use the existing
> definition.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
Reviewed-by: Aksh Garg <a-garg7@ti.com>
> Changes in v7:
> - rebase on top of next-20260615 (resolve pci-aardvark.c conflict)
>
> Changes in v6:
> - convert all drivers to use msleep() (Lukas Wunner)
>
> Changes in v2:
> - fix build for Cadence
> ---
^ permalink raw reply
* Re: [PATCH 08/11] dmaengine: ste_dma40: Use power domain for LCLA SRAM
From: sashiko-bot @ 2026-06-18 5:15 UTC (permalink / raw)
To: Linus Walleij
Cc: Frank.Li, robh, vkoul, dmaengine, devicetree, dri-devel, conor+dt
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-8-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
New issues:
- [High] Calling synchronous runtime PM functions on a non-IRQ-safe device from atomic context.
- [High] Forcing immediate synchronous suspend of the SRAM PM domain defeats the DMA controller's autosuspend design and causes severe performance degradation.
- [High] The consumer driver forcefully enables runtime PM on a supplier device, risking unbalanced PM states.
- [High] Missing device link between the DMA controller and the external LCLA SRAM device, leading to system suspend ordering races.
Pre-existing issues:
- [Critical] Validation logic incorrectly bounds `dev_type`, leading to a critical out-of-bounds pointer write in `lookup_log_chans`.
- [High] An early probe failure unconditionally calls `pm_runtime_disable(base->dev)`, permanently disabling runtime PM on subsequent probe retries.
- [High] Missing `free_irq()` in the error paths of `d40_probe()`.
- [High] Unchecked return value of `d40_queue_start()` leaks runtime PM reference and permanently hangs the channel.
--
commit ee86cbf896c47f035fc9bd6d0f30e49d8a83841a
Author: Linus Walleij <linusw@kernel.org>
dmaengine: ste_dma40: Use power domain for LCLA SRAM
This patch replaces the LCLA ESRAM regulator with runtime PM support.
It fetches the SRAM device for the ESRAM34 power domain from the device tree.
The driver then holds a runtime PM reference on this domain while DMA
transfers are active.
> diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
> index 9b803c0aec254..6ca67ec446dc5 100644
> --- a/drivers/dma/ste_dma40.c
> +++ b/drivers/dma/ste_dma40.c
[ ... ]
> @@ -628,6 +630,22 @@ static struct device *chan2dev(struct d40_chan *d40c)
> return &d40c->chan.dev->device;
> }
>
> +static void d40_transfer_runtime_get(struct d40_base *base)
> +{
> + if (base->lcla_dev)
> + pm_runtime_get_sync(base->lcla_dev);
[Severity: High]
Does this code call a blocking runtime PM function on an external SRAM device
from an atomic context?
d40_transfer_runtime_get() and d40_transfer_runtime_put() are called from
d40_queue_start() and dma_tc_handle(). Both of these execute under the
d40c->lock spinlock, and dma_tc_handle() runs from the hardirq handler.
Because base->lcla_dev is an external SRAM device whose PM domain requires
sleeping locks to power on or off, it is not IRQ-safe. Calling synchronous
PM operations on it in an atomic context might trigger a might_sleep() warning
and a scheduling-while-atomic kernel panic.
> +
> + pm_runtime_get_sync(base->dev);
> +}
> +
> +static void d40_transfer_runtime_put(struct d40_base *base)
> +{
> + pm_runtime_put_autosuspend(base->dev);
> +
> + if (base->lcla_dev)
> + pm_runtime_put_sync_suspend(base->lcla_dev);
[Severity: High]
Could forcing an immediate synchronous suspend of the SRAM PM domain defeat
the DMA controller's autosuspend design and cause performance degradation?
By using pm_runtime_put_sync_suspend() here, the external SRAM device is
forced to power down immediately as soon as a single DMA transfer completes.
The DMA controller itself uses pm_runtime_put_autosuspend() to handle bursty
transfers efficiently.
Suspending the shared SRAM immediately and synchronously might cause every
subsequent DMA transfer to block while the PM domain wakes up, which could
introduce significant latency.
> +}
[ ... ]
> @@ -1516,7 +1534,7 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
> if (d40d != NULL) {
> if (!d40c->busy) {
> d40c->busy = true;
> - pm_runtime_get_sync(d40c->base->dev);
> + d40_transfer_runtime_get(d40c->base);
> }
>
> /* Remove from queue */
[Severity: High]
This is a pre-existing issue, but does d40_queue_start() leak a runtime PM
reference and hang the channel if the hardware start fails?
If d40_start(d40c) fails later in this function, it returns NULL without
reverting d40c->busy or dropping the PM reference:
err = d40_start(d40c);
if (err)
return NULL;
Callers like d40_issue_pending() ignore this return value. The channel then
remains permanently marked as busy, preventing future transfers, and the
leaked PM reference prevents the device from suspending.
[ ... ]
> @@ -3590,23 +3593,32 @@ static int __init d40_probe(struct platform_device *pdev)
> }
>
> if (base->plat_data->use_esram_lcla) {
> + np_lcla = of_parse_phandle(np, "sram", 1);
> + if (!np_lcla) {
> + dev_err(dev, "no LCLA SRAM node\n");
> + ret = -EINVAL;
> + goto destroy_cache;
> + }
>
> - base->lcpa_regulator = regulator_get(base->dev, "lcla_esram");
> - if (IS_ERR(base->lcpa_regulator)) {
> - d40_err(dev, "Failed to get lcpa_regulator\n");
> - ret = PTR_ERR(base->lcpa_regulator);
> - base->lcpa_regulator = NULL;
> + np_lcla_parent = of_get_parent(np_lcla);
> + of_node_put(np_lcla);
> + if (!np_lcla_parent) {
> + dev_err(dev, "no LCLA SRAM parent node\n");
> + ret = -EINVAL;
> goto destroy_cache;
> }
>
> - ret = regulator_enable(base->lcpa_regulator);
> - if (ret) {
> - d40_err(dev,
> - "Failed to enable lcpa_regulator\n");
> - regulator_put(base->lcpa_regulator);
> - base->lcpa_regulator = NULL;
> + lcla_pdev = of_find_device_by_node(np_lcla_parent);
> + of_node_put(np_lcla_parent);
> + if (!lcla_pdev) {
> + ret = -EPROBE_DEFER;
> goto destroy_cache;
> }
> + base->lcla_dev = &lcla_pdev->dev;
[Severity: High]
Is a device link missing between the DMA controller and the external LCLA
SRAM device?
The driver relies on the runtime PM of lcla_dev, but it doesn't appear to
call device_link_add() to inform the PM core that base->dev depends on
base->lcla_dev.
During a system sleep transition, the PM core might suspend devices in
parallel or based on standard device tree hierarchy, potentially suspending
lcla_dev before the DMA controller. This could physically power off the SRAM
while active DMA transfers are still running.
> + if (!pm_runtime_enabled(base->lcla_dev)) {
> + pm_runtime_enable(base->lcla_dev);
[Severity: High]
Is it safe for a consumer driver to forcefully alter the core runtime PM
state of an external supplier device?
A consumer driver generally shouldn't manually manipulate the enable/disable
state of a supplier device it does not own.
If the supplier SRAM driver probes concurrently or manages its own state,
its call to pm_runtime_enable() will find disable_depth already at 0,
which could trigger an "Unbalanced pm_runtime_enable!" warning and
corrupt the device's internal power state machine.
> + base->lcla_pm_enabled = true;
> + }
> }
>
> writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
[ ... ]
> @@ -3642,16 +3654,17 @@ static int __init d40_probe(struct platform_device *pdev)
> SZ_1K * base->num_phy_chans,
> DMA_TO_DEVICE);
>
> - if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
> + if (!base->lcla_pool.base_unaligned && base->lcla_pool.base &&
> + base->lcla_pool.pages)
> free_pages((unsigned long)base->lcla_pool.base,
> base->lcla_pool.pages);
>
> kfree(base->lcla_pool.base_unaligned);
>
> - if (base->lcpa_regulator) {
> - regulator_disable(base->lcpa_regulator);
> - regulator_put(base->lcpa_regulator);
> - }
> + if (base->lcla_pm_enabled)
> + pm_runtime_disable(base->lcla_dev);
> + if (base->lcla_dev)
> + put_device(base->lcla_dev);
> pm_runtime_disable(base->dev);
[Severity: High]
This is a pre-existing issue, but might this error path permanently disable
runtime PM on subsequent probe retries?
If d40_probe() encounters an error before pm_runtime_enable(base->dev) is
executed (for example, when lcla_pdev is not found and returns -EPROBE_DEFER),
it jumps to destroy_cache.
This unconditionally calls pm_runtime_disable(base->dev), incrementing
disable_depth from 1 to 2. When the probe is retried and succeeds,
pm_runtime_enable() will only decrement the depth to 1, leaving the device
permanently disabled for runtime PM.
[Severity: High]
This is a pre-existing issue, but could the destroy_cache error path leak
the registered IRQ?
Earlier in d40_probe(), request_irq() is called to register the hardware
interrupt handler:
ret = request_irq(base->irq, d40_handle_interrupt, 0, D40_NAME, base);
If a subsequent step fails, the function jumps to destroy_cache, which cleans
up memory and DMA mappings but does not call free_irq().
The interrupt handler remains registered for a device whose driver data and
resources have been freed. If the hardware asserts an interrupt, the kernel
might execute the handler using freed memory.
>
> report_failure:
[Severity: Critical]
This is a pre-existing issue, but does the validation logic for dev_type
allow an out-of-bounds write during channel allocation?
In d40_validate_conf(), conf->dev_type is validated against num_log_chans:
if ((is_log && conf->dev_type > d40c->base->num_log_chans)
However, in d40_allocate_channel(), log_num is calculated as either
2 * dev_type or 2 * dev_type + 1. This allows log_num to reach up to
2 * 256 + 1 = 513.
The driver then writes to the lookup array:
d40c->base->lookup_log_chans[d40c->log_num] = d40c;
Since lookup_log_chans is only sized to hold num_log_chans elements,
this results in a write past the end of the array.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=8
^ permalink raw reply
* Re: [PATCH 09/11] regulator: db8500-prcmu: Remove EPOD regulators
From: sashiko-bot @ 2026-06-18 5:15 UTC (permalink / raw)
To: Linus Walleij
Cc: dri-devel, dmaengine, devicetree, Frank.Li, robh, vkoul, conor+dt
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-9-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
Pre-existing issues:
- [High] Calling pm_runtime_get_sync() and pm_runtime_put_sync_suspend() on `lcla_dev` from the DMA hardirq handler causes a 'sleeping in atomic context' bug.
--
commit faf19ae1be6f68a94634761ce6a55206f7f124da
Author: Linus Walleij <linusw@kernel.org>
regulator: db8500-prcmu: Remove EPOD regulators
Remove the obsolete DB8500 PRCMU regulator drivers.
> Drop the regulator build hooks now that EPODs are power domains.
[Severity: High]
This isn't a bug introduced by this patch, but since the EPODs are now power
domains, is it safe to use them from atomic contexts?
An earlier patch in this series transitioned the LCLA SRAM to use power
domains, but the DMA interrupt handler d40_handle_interrupt() acquires
spinlocks (base->interrupt_lock and d40c->lock) before taking this path:
d40_handle_interrupt()
dma_tc_handle()
d40_queue_start()
d40_transfer_runtime_get()
pm_runtime_get_sync(base->lcla_dev)
d40_transfer_runtime_put()
pm_runtime_put_sync_suspend(base->lcla_dev)
Because base->lcla_dev is tied to the ESRAM34 generic PM domain and is not
marked IRQ-safe (GENPD_FLAG_IRQ_SAFE), its callbacks are invoked, leading
to sleeping operations while holding spinlocks:
pd_power_off()
guard(mutex)(&ux500_pd_lock)
db8500_prcmu_set_epod()
mutex_lock(&mb2_transfer.lock)
Could this lead to scheduling while atomic bugs and deadlocks?
> Keep the MFD cell around because a later patch reuses it for a
> small compatibility regulator driver.
>
> Assisted-by: Codex:gpt-5-5
> Signed-off-by: Linus Walleij <linusw@kernel.org>
[ ... ]
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=9
^ permalink raw reply
* Re: [PATCH 05/11] ARM: dts: ux500: Add power domains
From: sashiko-bot @ 2026-06-18 5:14 UTC (permalink / raw)
To: Linus Walleij
Cc: robh, dri-devel, conor+dt, devicetree, Frank.Li, vkoul, dmaengine
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-5-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The `clocks` node is incorrectly assigned to `DOMAIN_VPLL` instead of `DOMAIN_VAPE` and includes an unresolved `CHECKME` comment.
- [Medium] Adding `power-domains` to nodes whose binding schemas do not allow it will cause `dtbs_check` validation errors.
--
commit 57cdb12b349af07637860b10a8f8232b9e2930bc
Author: Linus Walleij <linusw@kernel.org>
ARM: dts: ux500: Add power domains
Add the actual power domains to all the SoC peripherals.
> diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
> index d76a65da70111..a6fef302c994e 100644
> --- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
> +++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
[ ... ]
> @@ -334,6 +340,7 @@ L2: cache-controller {
> compatible = "arm,pl310-cache";
> reg = <0xa0412000 0x1000>;
> interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
> + power-domains = <&pm_domains DOMAIN_VARM>;
[Severity: Medium]
Will adding power-domains here cause dtbs_check validation errors?
The l2c2x0.yaml binding schema (along with others modified in this patch like
arm/pmu.yaml, stericsson,u8500-clks.yaml, arm,twd-timer.yaml,
arm,twd-wdt.yaml, and ste,mcde.yaml) does not include power-domains in its
list of allowed properties.
Do these bindings need to be updated to document the power-domains capability
before it can be used?
> cache-unified;
> cache-level = <2>;
> };
[ ... ]
> @@ -357,6 +365,7 @@ clocks {
> reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>,
> <0x8000f000 0x1000>, <0xa03ff000 0x1000>,
> <0xa03cf000 0x1000>;
> + power-domains = <&pm_domains DOMAIN_VPLL>; /* CHECKME: correct domain? */
[Severity: High]
Should this be DOMAIN_VAPE instead of DOMAIN_VPLL?
The PRCC registers mapped here for peripheral groups 1, 2, 3, 5, and 6 reside
in the VAPE power domain alongside the peripherals they clock.
If the clock controller is assigned to DOMAIN_VPLL, the power domain framework
won't guarantee DOMAIN_VAPE is powered on when accessing these registers,
which could cause a synchronous external abort.
Also, is the CHECKME comment intended to be resolved before merging?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=5
^ permalink raw reply
* Re: [PATCH 06/11] pmdomain: st: ux500: Control DB8500 EPODs
From: sashiko-bot @ 2026-06-18 5:14 UTC (permalink / raw)
To: Linus Walleij
Cc: devicetree, vkoul, Frank.Li, dmaengine, dri-devel, conor+dt, robh
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-6-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] Probe error path leaks dynamically allocated memory, fails to unregister PM domains, and lacks rollback for partially added subdomains.
- [High] Hardware RAM retention capabilities are entirely lost, rendering related state handling logic dead code.
- [Medium] Bisection breakage: Disabling REGULATOR_DB8500_PRCMU causes consumer devices expecting `v-ape-supply` to permanently fail to probe.
--
commit 26ccd884add2c876cdf4c876688df7b868a2fa06
Author: Linus Walleij <linusw@kernel.org>
pmdomain: st: ux500: Control DB8500 EPODs
Move the DB8500 EPOD state handling into the Ux500 power-domain driver.
Keep the old regulator driver mutually exclusive with the pmdomain driver.
> diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
> --- a/arch/arm/mach-ux500/Kconfig
> +++ b/arch/arm/mach-ux500/Kconfig
[ ... ]
> @@ -26,7 +26,7 @@ menuconfig ARCH_U8500
> select PL310_ERRATA_753970 if CACHE_L2X0
> select PM_GENERIC_DOMAINS if PM
> select REGULATOR
> - select REGULATOR_DB8500_PRCMU
> + select UX500_PM_DOMAIN
> select REGULATOR_FIXED_VOLTAGE
> select SOC_BUS
> select RESET_CONTROLLER
[Severity: Medium]
Does this break git bisect by disabling the regulator provider before consumer
devices are updated?
Consumer devices depending on v-ape-supply may receive -EPROBE_DEFER
indefinitely if the regulator driver is disabled here. I see this is fixed in
a later commit ("regulator: db8500: Add power domain regulators"), but is it
possible to reorder the changes to avoid breaking bisection?
> diff --git a/drivers/pmdomain/st/ste-ux500-pm-domain.c b/drivers/pmdomain/st/ste-ux500-pm-domain.c
> --- a/drivers/pmdomain/st/ste-ux500-pm-domain.c
> +++ b/drivers/pmdomain/st/ste-ux500-pm-domain.c
[ ... ]
> +static int disable_epod(u16 epod_id, bool ramret)
> +{
> + int ret;
> +
> + if (ramret) {
> + if (!epod_on[epod_id]) {
> + ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
> + if (ret < 0)
> + return ret;
> + }
> + epod_ramret[epod_id] = false;
> + } else {
> + if (epod_ramret[epod_id]) {
> + ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
[Severity: High]
Is the hardware RAM retention capability effectively lost here?
The struct dbx500_powerdomain_info defines is_ramret, but none of the
newly defined domains initialize it to true (e.g., for SVAMMDSP or SIAMMDSP).
Because ramret is always false, epod_ramret[] is never set, making
the EPOD_STATE_RAMRET state unreachable. Does this dead code need to
be activated by setting is_ramret on the appropriate domains?
[ ... ]
> +static int ux500_pm_domains_probe(struct platform_device *pdev)
> {
> struct device_node *np = pdev->dev.of_node;
> struct genpd_onecell_data *genpd_data;
> int i;
> + int ret;
>
> if (!np)
> return -ENODEV;
[ ... ]
> for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i)
> - pm_genpd_init(ux500_pm_domains[i], NULL, false);
> + pm_genpd_init(ux500_pm_domains[i], NULL, true);
> +
> + ret = ux500_pm_domains_add_subdomains();
> + if (ret)
> + return ret;
[Severity: High]
Does this error path leak memory and leave the power domains registered?
If ux500_pm_domains_add_subdomains() fails, it returns an error directly.
This leaves genpd_data allocated and the domains initialized and linked into
the global gpd_list via pm_genpd_init().
If a driver unbind/rebind occurs, could INIT_LIST_HEAD be invoked on elements
already in the list, potentially corrupting the doubly linked list and causing
a kernel panic?
Should pm_genpd_remove() be called for initialized domains, and the added
subdomains be rolled back with pm_genpd_remove_subdomain() before returning?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=6
^ permalink raw reply
* Re: [PATCH 07/11] drm/mcde: Use power domain for display power
From: sashiko-bot @ 2026-06-18 5:11 UTC (permalink / raw)
To: Linus Walleij
Cc: conor+dt, devicetree, Frank.Li, dri-devel, dmaengine, vkoul, robh
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-7-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Incorrect return value check for pm_runtime_put_sync_suspend(), treating success as an error.
- [High] Resource leak of the main clock (mcde_clk) on the probe error path.
--
commit 1e2436e1c266a49af52c126fb77756c71e5e0e91
Author: Linus Walleij <linusw@kernel.org>
drm/mcde: Use power domain for display power
Replace explicit EPOD regulator handling with runtime PM.
Use the MCDE power domain and drop the regulator dependency.
> diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
> index 257a6e84dd583..52f071bb347c4 100644
> --- a/drivers/gpu/drm/mcde/mcde_display.c
> +++ b/drivers/gpu/drm/mcde/mcde_display.c
[ ... ]
> @@ -1327,9 +1326,9 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
> spin_unlock_irq(&crtc->dev->event_lock);
> }
>
> - ret = regulator_disable(mcde->epod);
> + ret = pm_runtime_put_sync_suspend(mcde->dev);
> if (ret)
> - dev_err(drm->dev, "can't disable EPOD regulator\n");
> + dev_err(drm->dev, "can't disable MCDE power domain\n");
[Severity: High]
According to the Runtime PM API contract, pm_runtime_put_sync_suspend()
returns 1 when the device is already in the RPM_SUSPENDED state. Is it
intentional to treat a positive return value as an error here? If the device
is already suspended, this will log a false-positive error.
> /* Make sure we are powered down (before we may power up again) */
> usleep_range(50000, 70000);
>
> diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
> index 5f2c462bad7e1..3f966cccda5a3 100644
> --- a/drivers/gpu/drm/mcde/mcde_drv.c
> +++ b/drivers/gpu/drm/mcde/mcde_drv.c
[ ... ]
> @@ -412,14 +392,15 @@ static int mcde_probe(struct platform_device *pdev)
>
> /*
> * Perform an invasive reset of the MCDE and all blocks by
> - * cutting the power to the subsystem, then bring it back up
> + * powering down the subsystem, then bring it back up
> * later when we enable the display as a result of
> * component_master_add_with_match().
> */
> - ret = regulator_disable(mcde->epod);
> + ret = pm_runtime_put_sync_suspend(dev);
> if (ret) {
> - dev_err(dev, "can't disable EPOD regulator\n");
> - return ret;
> + dev_err(dev, "can't disable MCDE power domain\n");
> + pm_runtime_get_noresume(dev);
> + goto clk_disable;
> }
[Severity: High]
Does this incorrectly abort the probe sequence if the device is already
suspended?
pm_runtime_put_sync_suspend() returns 1 if the device was already in the
RPM_SUSPENDED state, which is a success condition, but the if (ret) check
here treats it as a failure.
> /* Wait 50 ms so we are sure we cut the power */
> usleep_range(50000, 70000);
[ ... ]
> @@ -428,25 +409,18 @@ static int mcde_probe(struct platform_device *pdev)
> match);
> if (ret) {
> dev_err(dev, "failed to add component master\n");
> - /*
> - * The EPOD regulator is already disabled at this point so some
> - * special errorpath code is needed
> - */
> - clk_disable_unprepare(mcde->mcde_clk);
> - regulator_disable(mcde->vana);
> - return ret;
> + goto clk_disable_pm_disabled;
> }
>
> return 0;
>
> clk_disable:
> clk_disable_unprepare(mcde->mcde_clk);
> -regulator_off:
> - regulator_disable(mcde->vana);
> -regulator_epod_off:
> - regulator_disable(mcde->epod);
> +pm_runtime_put:
> + pm_runtime_put_sync_suspend(dev);
> +clk_disable_pm_disabled:
> + pm_runtime_disable(dev);
> return ret;
> -
> }
[Severity: High]
Does this code leak the main clock when component_master_add_with_match()
fails?
The goto clk_disable_pm_disabled jump skips over the clk_disable label, so
clk_disable_unprepare(mcde->mcde_clk) is never called.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=7
^ permalink raw reply
* Re: [PATCH 03/11] pmdomain: st: ux500: Implement more power domains
From: sashiko-bot @ 2026-06-18 5:10 UTC (permalink / raw)
To: Linus Walleij
Cc: robh, devicetree, vkoul, conor+dt, dmaengine, dri-devel, Frank.Li
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-3-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The comment regarding Vape_esram0_pwr contradicts the implementation of ux500_pm_domain_esram_12.
--
commit e7c9ddf5e852fa7ba6bbf083dd8b845efaaf86e5
Author: Linus Walleij <linusw@kernel.org>
pmdomain: st: ux500: Implement more power domains
This starts to implement the power domains that are just skeleton
implementations right now.
> diff --git a/drivers/pmdomain/st/ste-ux500-pm-domain.c b/drivers/pmdomain/st/ste-ux500-pm-domain.c
> index 6896cb4a7b716..7230010046908 100644
> --- a/drivers/pmdomain/st/ste-ux500-pm-domain.c
> +++ b/drivers/pmdomain/st/ste-ux500-pm-domain.c
> @@ -41,14 +41,137 @@ static int pd_power_on(struct generic_pm_domain *domain)
> return 0;
> }
>
> +/*
> + * Apart from these voltage domains there is also VSAFE which is always
> + * on. Vape_esram0_pwr for eSRAM0 is connected to VSAFE.
> + */
> static struct generic_pm_domain ux500_pm_domain_vape = {
[ ... ]
> +static struct generic_pm_domain ux500_pm_domain_b2r2_mcde = {
> + /* Vape_DSS_pwr DSS (display subsystem) */
> + .name = "B2R2_MCDE",
> + .power_off = pd_power_off,
> + .power_on = pd_power_on,
> +};
> +
> +static struct generic_pm_domain ux500_pm_domain_esram_12 = {
> + /* Vape_esram0_pwr, Vape_esram1_pwr */
> + .name = "ESRAM_12",
[Severity: Low]
Is this comment accurate? An earlier comment states that Vape_esram0_pwr for
eSRAM0 is connected to the always-on VSAFE domain, but it is listed here as
part of the switchable ESRAM_12 power domain. Should this comment refer to
Vape_esram1_pwr and Vape_esram2_pwr instead?
> + .power_off = pd_power_off,
> + .power_on = pd_power_on,
> +};
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=3
^ permalink raw reply
* Re: [PATCH v3 4/4] spi: qcom-geni: Enable SPI on SA8255p Qualcomm platforms
From: Praveen Talari @ 2026-06-18 5:07 UTC (permalink / raw)
To: Konrad Dybcio, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, bjorn.andersson
Cc: linux-arm-msm, linux-spi, devicetree, linux-kernel,
mukesh.savaliya, aniket.randive, chandana.chiluveru,
jyothi.seerapu, chiluka.harish
In-Reply-To: <d4d01a6d-4c9e-4822-b0f6-b98e8ecf34f5@oss.qualcomm.com>
Hi Konrad
On 17-06-2026 16:35, Konrad Dybcio wrote:
> On 6/4/26 8:50 AM, Praveen Talari wrote:
>> The Qualcomm automotive SA8255p SoC relies on firmware to configure
>> platform resources, including clocks, interconnects and TLMM.
>> The driver requests resources operations over SCMI using power
>> and performance protocols.
>>
>> The SCMI power protocol enables or disables resources like clocks,
>> interconnect paths, and TLMM (GPIOs) using runtime PM framework APIs,
>> such as resume/suspend, to control power states(on/off).
>>
>> The SCMI performance protocol manages SPI frequency, with each
>> frequency rate represented by a performance level. The driver uses
>> geni_se_set_perf_opp() API to request the desired frequency rate.
>>
>> As part of geni_se_set_perf_opp(), the OPP for the requested frequency
>> is obtained using dev_pm_opp_find_freq_floor() and the performance
>> level is set using dev_pm_opp_set_opp().
>>
>> Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
>> ---
> [...]
>
>> - ret = geni_se_resources_init(&mas->se);
>> + mas->dev_data = device_get_match_data(&pdev->dev);
> This really needs to be null-checked
Sure, will add in next patch set.
Thanks,
Praveen talari
>
> Perhaps also the functions within that are called unconditionally
>
> Konrad
^ permalink raw reply
* Re: [PATCH 01/11] dt-bindings: power: Convert Ux500 PM domains to schema
From: sashiko-bot @ 2026-06-18 5:07 UTC (permalink / raw)
To: Linus Walleij
Cc: devicetree, dmaengine, Frank.Li, vkoul, dri-devel, conor+dt, robh
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-1-eb5e50b1a588@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] The example consumer node `sdi0_per1@80126000` will fail `dt_binding_check` validation due to missing required properties and will trigger a `dtc` warning.
--
commit b98e3bf1a2da87a6966744348740e230bb97bdfd
Author: Linus Walleij <linusw@kernel.org>
dt-bindings: power: Convert Ux500 PM domains to schema
This commit converts the legacy Ux500 power domain text binding to YAML.
It moves the binding under bindings/power and updates the MAINTAINERS file
accordingly.
> diff --git a/Documentation/devicetree/bindings/power/stericsson,ux500-pm-domains.yaml b/Documentation/devicetree/bindings/power/stericsson,ux500-pm-domains.yaml
> new file mode 100644
> index 0000000000000..72c39c083efbf
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/power/stericsson,ux500-pm-domains.yaml
[ ... ]
> +examples:
> + - |
> + #include <dt-bindings/arm/ux500_pm_domains.h>
> +
> + pm_domains: power-controller {
> + compatible = "stericsson,ux500-pm-domains";
> + #power-domain-cells = <1>;
> + };
> +
> + sdi0_per1@80126000 {
> + compatible = "arm,pl18x", "arm,primecell";
> + power-domains = <&pm_domains DOMAIN_VAPE>;
> + };
[Severity: Low]
Will this example consumer node trigger warnings during dt_binding_check?
The node is matched against the arm,pl18x.yaml schema, which requires both
the reg and interrupts properties. Since they are missing here, dt-schema
will likely report validation errors.
Additionally, because the node includes a unit address (@80126000) but lacks
a reg property, does this cause dtc to emit a unit_address_vs_reg warning?
Should dummy reg and interrupts properties be added to the example to
satisfy the schema validation?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org?part=1
^ permalink raw reply
* [PATCH 11/11] ARM: dts: ux500: Remove DB8500 EPOD regulators
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Delete the obsolete DB8500 EPOD regulator nodes.
Keep the VAPE and VSMPS2 compatibility regulators.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 92 ------------------------------------
1 file changed, 92 deletions(-)
diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
index fd6a075e4c93..18727953a863 100644
--- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
@@ -663,97 +663,17 @@ thermal: thermal@801573c0 {
#thermal-sensor-cells = <0>;
};
- /*
- * TODO: Delete these bogus regulators and replace with power
- * domains.
- */
db8500-prcmu-regulators {
compatible = "stericsson,db8500-prcmu-regulator";
- // DB8500_REGULATOR_VAPE
db8500_vape_reg: db8500_vape {
regulator-always-on;
power-domains = <&pm_domains DOMAIN_VAPE>;
};
- // DB8500_REGULATOR_VARM
- db8500_varm_reg: db8500_varm {
- };
-
- // DB8500_REGULATOR_VMODEM
- db8500_vmodem_reg: db8500_vmodem {
- };
-
- // DB8500_REGULATOR_VPLL
- db8500_vpll_reg: db8500_vpll {
- };
-
- // DB8500_REGULATOR_VSMPS1
- db8500_vsmps1_reg: db8500_vsmps1 {
- };
-
- // DB8500_REGULATOR_VSMPS2
db8500_vsmps2_reg: db8500_vsmps2 {
power-domains = <&pm_domains DOMAIN_VSMPS2>;
};
-
- // DB8500_REGULATOR_VSMPS3
- db8500_vsmps3_reg: db8500_vsmps3 {
- };
-
- // DB8500_REGULATOR_VRF1
- db8500_vrf1_reg: db8500_vrf1 {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAMMDSP
- db8500_sva_mmdsp_reg: db8500_sva_mmdsp {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAMMDSPRET
- db8500_sva_mmdsp_ret_reg: db8500_sva_mmdsp_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_SVAPIPE
- db8500_sva_pipe_reg: db8500_sva_pipe {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAMMDSP
- db8500_sia_mmdsp_reg: db8500_sia_mmdsp {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAMMDSPRET
- db8500_sia_mmdsp_ret_reg: db8500_sia_mmdsp_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_SIAPIPE
- db8500_sia_pipe_reg: db8500_sia_pipe {
- };
-
- // DB8500_REGULATOR_SWITCH_SGA
- db8500_sga_reg: db8500_sga {
- vin-supply = <&db8500_vape_reg>;
- };
-
- // DB8500_REGULATOR_SWITCH_B2R2_MCDE
- db8500_b2r2_mcde_reg: db8500_b2r2_mcde {
- vin-supply = <&db8500_vape_reg>;
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM12
- db8500_esram12_reg: db8500_esram12 {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM12RET
- db8500_esram12_ret_reg: db8500_esram12_ret {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM34
- db8500_esram34_reg: db8500_esram34 {
- };
-
- // DB8500_REGULATOR_SWITCH_ESRAM34RET
- db8500_esram34_ret_reg: db8500_esram34_ret {
- };
};
};
@@ -1111,8 +1031,6 @@ msp0: msp@80123000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80123000 0x1000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 31 0 0x12>, /* Logical - DevToMem - HighPrio */
@@ -1130,8 +1048,6 @@ msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v1 */
@@ -1150,8 +1066,6 @@ msp2: msp@80117000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80117000 0x1000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 14 0 0x12>, /* Logical - DevToMem - HighPrio */
@@ -1170,8 +1084,6 @@ msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
- /* TODO: delete and replace with power-domain handling */
- v-ape-supply = <&db8500_vape_reg>;
power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v2 */
@@ -1215,8 +1127,6 @@ gpu@a0300000 {
clocks = <&prcmu_clk PRCMU_ACLK>, <&prcmu_clk PRCMU_SGACLK>;
clock-names = "bus", "core";
power-domains = <&pm_domains DOMAIN_SGA>;
- /* TODO: delete and replace with power-domain handling */
- mali-supply = <&db8500_sga_reg>;
};
mcde@a0350000 {
@@ -1224,8 +1134,6 @@ mcde@a0350000 {
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
power-domains = <&pm_domains DOMAIN_B2R2_MCDE>;
- /* TODO: delete and replace with power-domain handling */
- epod-supply = <&db8500_b2r2_mcde_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */
<&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */
<&prcmu_clk PRCMU_PLLDSI>; /* HDMI clock */
--
2.54.0
^ permalink raw reply related
* [PATCH 10/11] regulator: db8500: Add power domain regulators
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Add a DB8500 regulator driver for the VAPE and VSMPS2 compatibility nodes.
Back the regulator enable state with the corresponding power domains.
This is done for off-chip consumers: the corresponding voltage rails are
routed out so they are used for powering different peripherals using
these voltages as supplies.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 2 +
drivers/regulator/Kconfig | 11 ++
drivers/regulator/Makefile | 1 +
drivers/regulator/db8500-regulator.c | 221 +++++++++++++++++++++++++++++++++++
4 files changed, 235 insertions(+)
diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
index a6fef302c994..fd6a075e4c93 100644
--- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
@@ -673,6 +673,7 @@ db8500-prcmu-regulators {
// DB8500_REGULATOR_VAPE
db8500_vape_reg: db8500_vape {
regulator-always-on;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
// DB8500_REGULATOR_VARM
@@ -693,6 +694,7 @@ db8500_vsmps1_reg: db8500_vsmps1 {
// DB8500_REGULATOR_VSMPS2
db8500_vsmps2_reg: db8500_vsmps2 {
+ power-domains = <&pm_domains DOMAIN_VSMPS2>;
};
// DB8500_REGULATOR_VSMPS3
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index acc698c17bd2..8db63d8d3fa4 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -397,6 +397,17 @@ config REGULATOR_DA9210
converter 12A DC-DC Buck controlled through an I2C
interface.
+config REGULATOR_DB8500
+ bool "ST-Ericsson DB8500 power domain regulators"
+ depends on MFD_DB8500_PRCMU && UX500_PM_DOMAIN && OF
+ default ARCH_U8500
+ help
+ This driver supports the DB8500 VAPE and VSMPS2 regulators.
+ These supplies are represented by generic power domains in hardware,
+ but the same voltage rails are routed out of the chip and used to
+ supply external peripherals.
+ Enable this driver to bridge those regulator consumers to genpd.
+
config REGULATOR_DA9211
tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9223/DA9214/DA9224/DA9215/DA9225 regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 96a02063b843..f4109549525a 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o
obj-$(CONFIG_REGULATOR_DA9121) += da9121-regulator.o
obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o
obj-$(CONFIG_REGULATOR_DA9211) += da9211-regulator.o
+obj-$(CONFIG_REGULATOR_DB8500) += db8500-regulator.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
diff --git a/drivers/regulator/db8500-regulator.c b/drivers/regulator/db8500-regulator.c
new file mode 100644
index 000000000000..c5a9a1baaf8e
--- /dev/null
+++ b/drivers/regulator/db8500-regulator.c
@@ -0,0 +1,221 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Linus Walleij <linusw@kernel.org>
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/slab.h>
+
+struct db8500_regulator_info {
+ struct regulator_desc desc;
+ struct regulator_init_data init_data;
+ struct device pd_dev;
+ bool enabled;
+};
+
+struct db8500_regulator_match {
+ const char *name;
+ const char *supply_name;
+ const char *constraint_name;
+ int fixed_uV;
+ bool always_on;
+};
+
+static const struct db8500_regulator_match db8500_regulator_matches[] = {
+ {
+ .name = "db8500_vape",
+ .supply_name = "db8500-vape",
+ .constraint_name = "db8500-vape",
+ .always_on = true,
+ }, {
+ .name = "db8500_vsmps2",
+ .supply_name = "db8500-vsmps2",
+ .constraint_name = "db8500-vsmps2",
+ .fixed_uV = 1800000,
+ },
+};
+
+static int db8500_regulator_enable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&info->pd_dev);
+ if (ret)
+ return ret;
+
+ info->enabled = true;
+ return 0;
+}
+
+static int db8500_regulator_disable(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+ int ret;
+
+ ret = pm_runtime_put_sync_suspend(&info->pd_dev);
+ if (ret)
+ return ret;
+
+ info->enabled = false;
+ return 0;
+}
+
+static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ return info->enabled;
+}
+
+static int db8500_regulator_get_voltage(struct regulator_dev *rdev)
+{
+ struct db8500_regulator_info *info = rdev_get_drvdata(rdev);
+
+ if (!info->desc.fixed_uV)
+ return -EINVAL;
+
+ return info->desc.fixed_uV;
+}
+
+static const struct regulator_ops db8500_regulator_ops = {
+ .enable = db8500_regulator_enable,
+ .disable = db8500_regulator_disable,
+ .is_enabled = db8500_regulator_is_enabled,
+ .get_voltage = db8500_regulator_get_voltage,
+};
+
+static void db8500_regulator_release(struct device *dev)
+{
+}
+
+static void db8500_regulator_cleanup(void *data)
+{
+ struct db8500_regulator_info *info = data;
+
+ pm_runtime_disable(&info->pd_dev);
+ dev_pm_domain_detach(&info->pd_dev, true);
+ put_device(&info->pd_dev);
+}
+
+static const struct db8500_regulator_match *
+db8500_regulator_match(struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(db8500_regulator_matches); i++) {
+ if (of_node_name_eq(np, db8500_regulator_matches[i].name))
+ return &db8500_regulator_matches[i];
+ }
+
+ return NULL;
+}
+
+static int db8500_regulator_register(struct platform_device *pdev,
+ struct device_node *np)
+{
+ const struct db8500_regulator_match *match;
+ struct regulator_config config = { };
+ struct db8500_regulator_info *info;
+ struct of_phandle_args pd_args;
+ struct regulator_dev *rdev;
+ const char *cells = "#power-domain-cells";
+ int ret;
+
+ match = db8500_regulator_match(np);
+ if (!match)
+ return 0;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ device_initialize(&info->pd_dev);
+ info->pd_dev.parent = &pdev->dev;
+ info->pd_dev.of_node = np;
+ info->pd_dev.release = db8500_regulator_release;
+ ret = dev_set_name(&info->pd_dev, "%s-pd", match->name);
+ if (ret)
+ goto put_device;
+
+ ret = of_parse_phandle_with_args(np, "power-domains", cells, 0, &pd_args);
+ if (ret)
+ goto put_device;
+
+ ret = of_genpd_add_device(&pd_args, &info->pd_dev);
+ of_node_put(pd_args.np);
+ if (ret)
+ goto put_device;
+
+ pm_runtime_enable(&info->pd_dev);
+ ret = devm_add_action_or_reset(&pdev->dev, db8500_regulator_cleanup, info);
+ if (ret)
+ return ret;
+
+ info->init_data.constraints.name = match->constraint_name;
+ info->init_data.constraints.valid_ops_mask = REGULATOR_CHANGE_STATUS;
+ info->init_data.constraints.always_on = match->always_on;
+
+ info->desc.name = match->supply_name;
+ info->desc.of_match = match->name;
+ info->desc.ops = &db8500_regulator_ops;
+ info->desc.type = REGULATOR_VOLTAGE;
+ info->desc.owner = THIS_MODULE;
+ info->desc.fixed_uV = match->fixed_uV;
+ config.dev = &pdev->dev;
+ config.init_data = &info->init_data;
+ config.driver_data = info;
+ config.of_node = np;
+ rdev = devm_regulator_register(&pdev->dev, &info->desc, &config);
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ return 0;
+
+put_device:
+ put_device(&info->pd_dev);
+ return ret;
+}
+
+static int db8500_regulator_probe(struct platform_device *pdev)
+{
+ struct device_node *np;
+ int ret;
+
+ for_each_available_child_of_node(pdev->dev.of_node, np) {
+ ret = db8500_regulator_register(pdev, np);
+ if (ret) {
+ of_node_put(np);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id db8500_regulator_match_table[] = {
+ { .compatible = "stericsson,db8500-prcmu-regulator" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, db8500_regulator_match_table);
+
+static struct platform_driver db8500_regulator_driver = {
+ .driver = {
+ .name = "db8500-prcmu-regulators",
+ .of_match_table = db8500_regulator_match_table,
+ },
+ .probe = db8500_regulator_probe,
+};
+module_platform_driver(db8500_regulator_driver);
+
+MODULE_AUTHOR("Linus Walleij <linusw@kernel.org>");
+MODULE_DESCRIPTION("DB8500 power-domain regulator driver");
+MODULE_LICENSE("GPL");
--
2.54.0
^ permalink raw reply related
* [PATCH 09/11] regulator: db8500-prcmu: Remove EPOD regulators
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Remove the obsolete DB8500 PRCMU regulator drivers.
Drop the regulator build hooks now that EPODs are power domains.
Keep the MFD cell around because a later patch reuses it for a
small compatibility regulator driver.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
drivers/mfd/db8500-prcmu.c | 239 +---------------
drivers/regulator/Kconfig | 12 -
drivers/regulator/Makefile | 2 -
drivers/regulator/db8500-prcmu.c | 501 ---------------------------------
drivers/regulator/dbx500-prcmu.c | 155 ----------
drivers/regulator/dbx500-prcmu.h | 55 ----
include/linux/regulator/db8500-prcmu.h | 38 ---
7 files changed, 1 insertion(+), 1001 deletions(-)
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 21e68a382b11..f1eeab3e6270 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -34,8 +34,6 @@
#include <linux/mfd/core.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/mfd/abx500/ab8500.h>
-#include <linux/regulator/db8500-prcmu.h>
-#include <linux/regulator/machine.h>
#include "db8500-prcmu-regs.h"
/* Index of different voltages to be used when accessing AVSData */
@@ -2704,248 +2702,13 @@ static void init_prcm_registers(void)
writel(val, (PRCM_A9PL_FORCE_CLKEN));
}
-/*
- * Power domain switches (ePODs) modeled as regulators for the DB8500 SoC
- */
-static struct regulator_consumer_supply db8500_vape_consumers[] = {
- REGULATOR_SUPPLY("v-ape", NULL),
- REGULATOR_SUPPLY("v-i2c", "nmk-i2c.0"),
- REGULATOR_SUPPLY("v-i2c", "nmk-i2c.1"),
- REGULATOR_SUPPLY("v-i2c", "nmk-i2c.2"),
- REGULATOR_SUPPLY("v-i2c", "nmk-i2c.3"),
- REGULATOR_SUPPLY("v-i2c", "nmk-i2c.4"),
- /* "v-mmc" changed to "vcore" in the mainline kernel */
- REGULATOR_SUPPLY("vcore", "sdi0"),
- REGULATOR_SUPPLY("vcore", "sdi1"),
- REGULATOR_SUPPLY("vcore", "sdi2"),
- REGULATOR_SUPPLY("vcore", "sdi3"),
- REGULATOR_SUPPLY("vcore", "sdi4"),
- REGULATOR_SUPPLY("v-dma", "dma40.0"),
- REGULATOR_SUPPLY("v-ape", "ab8500-usb.0"),
- /* "v-uart" changed to "vcore" in the mainline kernel */
- REGULATOR_SUPPLY("vcore", "uart0"),
- REGULATOR_SUPPLY("vcore", "uart1"),
- REGULATOR_SUPPLY("vcore", "uart2"),
- REGULATOR_SUPPLY("v-ape", "nmk-ske-keypad.0"),
- REGULATOR_SUPPLY("v-hsi", "ste_hsi.0"),
- REGULATOR_SUPPLY("vddvario", "smsc911x.0"),
-};
-
-static struct regulator_consumer_supply db8500_vsmps2_consumers[] = {
- REGULATOR_SUPPLY("musb_1v8", "ab8500-usb.0"),
- /* AV8100 regulator */
- REGULATOR_SUPPLY("hdmi_1v8", "0-0070"),
-};
-
-static struct regulator_consumer_supply db8500_b2r2_mcde_consumers[] = {
- REGULATOR_SUPPLY("vsupply", "b2r2_bus"),
- REGULATOR_SUPPLY("vsupply", "mcde"),
-};
-
-/* SVA MMDSP regulator switch */
-static struct regulator_consumer_supply db8500_svammdsp_consumers[] = {
- REGULATOR_SUPPLY("sva-mmdsp", "cm_control"),
-};
-
-/* SVA pipe regulator switch */
-static struct regulator_consumer_supply db8500_svapipe_consumers[] = {
- REGULATOR_SUPPLY("sva-pipe", "cm_control"),
-};
-
-/* SIA MMDSP regulator switch */
-static struct regulator_consumer_supply db8500_siammdsp_consumers[] = {
- REGULATOR_SUPPLY("sia-mmdsp", "cm_control"),
-};
-
-/* SIA pipe regulator switch */
-static struct regulator_consumer_supply db8500_siapipe_consumers[] = {
- REGULATOR_SUPPLY("sia-pipe", "cm_control"),
-};
-
-static struct regulator_consumer_supply db8500_sga_consumers[] = {
- REGULATOR_SUPPLY("v-mali", NULL),
-};
-
-/* ESRAM1 and 2 regulator switch */
-static struct regulator_consumer_supply db8500_esram12_consumers[] = {
- REGULATOR_SUPPLY("esram12", "cm_control"),
-};
-
-/* ESRAM3 and 4 regulator switch */
-static struct regulator_consumer_supply db8500_esram34_consumers[] = {
- REGULATOR_SUPPLY("v-esram34", "mcde"),
- REGULATOR_SUPPLY("esram34", "cm_control"),
- REGULATOR_SUPPLY("lcla_esram", "dma40.0"),
-};
-
-static struct regulator_init_data db8500_regulators[DB8500_NUM_REGULATORS] = {
- [DB8500_REGULATOR_VAPE] = {
- .constraints = {
- .name = "db8500-vape",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- .always_on = true,
- },
- .consumer_supplies = db8500_vape_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_vape_consumers),
- },
- [DB8500_REGULATOR_VARM] = {
- .constraints = {
- .name = "db8500-varm",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_VMODEM] = {
- .constraints = {
- .name = "db8500-vmodem",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_VPLL] = {
- .constraints = {
- .name = "db8500-vpll",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_VSMPS1] = {
- .constraints = {
- .name = "db8500-vsmps1",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_VSMPS2] = {
- .constraints = {
- .name = "db8500-vsmps2",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_vsmps2_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_vsmps2_consumers),
- },
- [DB8500_REGULATOR_VSMPS3] = {
- .constraints = {
- .name = "db8500-vsmps3",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_VRF1] = {
- .constraints = {
- .name = "db8500-vrf1",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
- /* dependency to u8500-vape is handled outside regulator framework */
- .constraints = {
- .name = "db8500-sva-mmdsp",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_svammdsp_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_svammdsp_consumers),
- },
- [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
- .constraints = {
- /* "ret" means "retention" */
- .name = "db8500-sva-mmdsp-ret",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
- /* dependency to u8500-vape is handled outside regulator framework */
- .constraints = {
- .name = "db8500-sva-pipe",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_svapipe_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_svapipe_consumers),
- },
- [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
- /* dependency to u8500-vape is handled outside regulator framework */
- .constraints = {
- .name = "db8500-sia-mmdsp",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_siammdsp_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_siammdsp_consumers),
- },
- [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
- .constraints = {
- .name = "db8500-sia-mmdsp-ret",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
- /* dependency to u8500-vape is handled outside regulator framework */
- .constraints = {
- .name = "db8500-sia-pipe",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_siapipe_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_siapipe_consumers),
- },
- [DB8500_REGULATOR_SWITCH_SGA] = {
- .supply_regulator = "db8500-vape",
- .constraints = {
- .name = "db8500-sga",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_sga_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_sga_consumers),
-
- },
- [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
- .supply_regulator = "db8500-vape",
- .constraints = {
- .name = "db8500-b2r2-mcde",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_b2r2_mcde_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_b2r2_mcde_consumers),
- },
- [DB8500_REGULATOR_SWITCH_ESRAM12] = {
- /*
- * esram12 is set in retention and supplied by Vsafe when Vape is off,
- * no need to hold Vape
- */
- .constraints = {
- .name = "db8500-esram12",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_esram12_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_esram12_consumers),
- },
- [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
- .constraints = {
- .name = "db8500-esram12-ret",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
- [DB8500_REGULATOR_SWITCH_ESRAM34] = {
- /*
- * esram34 is set in retention and supplied by Vsafe when Vape is off,
- * no need to hold Vape
- */
- .constraints = {
- .name = "db8500-esram34",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = db8500_esram34_consumers,
- .num_consumer_supplies = ARRAY_SIZE(db8500_esram34_consumers),
- },
- [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
- .constraints = {
- .name = "db8500-esram34-ret",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- },
-};
-
static const struct mfd_cell common_prcmu_devs[] = {
MFD_CELL_NAME("db8500_wdt"),
MFD_CELL_NAME("db8500-cpuidle"),
};
static const struct mfd_cell db8500_prcmu_devs[] = {
- MFD_CELL_OF("db8500-prcmu-regulators", NULL,
- &db8500_regulators, sizeof(db8500_regulators), 0,
+ MFD_CELL_OF("db8500-prcmu-regulators", NULL, NULL, 0, 0,
"stericsson,db8500-prcmu-regulator"),
MFD_CELL_OF("db8500-thermal",
NULL, NULL, 0, 0, "stericsson,db8500-thermal"),
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 35d1b191462c..acc698c17bd2 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -408,18 +408,6 @@ config REGULATOR_DA9211
step down converter 12A or 16A DC-DC Buck controlled through an I2C
interface.
-config REGULATOR_DBX500_PRCMU
- bool
-
-config REGULATOR_DB8500_PRCMU
- bool "ST-Ericsson DB8500 Voltage Domain Regulators"
- depends on MFD_DB8500_PRCMU
- depends on !UX500_PM_DOMAIN
- select REGULATOR_DBX500_PRCMU
- help
- This driver supports the voltage domain regulators controlled by the
- DB8500 PRCMU
-
config REGULATOR_FAN53555
tristate "Fairchild FAN53555 Regulator"
depends on I2C
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 35639f3115fd..96a02063b843 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -48,8 +48,6 @@ obj-$(CONFIG_REGULATOR_DA9063) += da9063-regulator.o
obj-$(CONFIG_REGULATOR_DA9121) += da9121-regulator.o
obj-$(CONFIG_REGULATOR_DA9210) += da9210-regulator.o
obj-$(CONFIG_REGULATOR_DA9211) += da9211-regulator.o
-obj-$(CONFIG_REGULATOR_DBX500_PRCMU) += dbx500-prcmu.o
-obj-$(CONFIG_REGULATOR_DB8500_PRCMU) += db8500-prcmu.o
obj-$(CONFIG_REGULATOR_FAN53555) += fan53555.o
obj-$(CONFIG_REGULATOR_FAN53880) += fan53880.o
obj-$(CONFIG_REGULATOR_GPIO) += gpio-regulator.o
diff --git a/drivers/regulator/db8500-prcmu.c b/drivers/regulator/db8500-prcmu.c
deleted file mode 100644
index 1ec2e1348891..000000000000
--- a/drivers/regulator/db8500-prcmu.c
+++ /dev/null
@@ -1,501 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
- * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
- *
- * Power domain regulators on DB8500
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/mfd/dbx500-prcmu.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/db8500-prcmu.h>
-#include <linux/regulator/of_regulator.h>
-#include <linux/of.h>
-#include <linux/module.h>
-#include "dbx500-prcmu.h"
-
-static int db8500_regulator_enable(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev), "regulator-%s-enable\n",
- info->desc.name);
-
- if (!info->is_enabled) {
- info->is_enabled = true;
- if (!info->exclude_from_power_state)
- power_state_active_enable();
- }
-
- return 0;
-}
-
-static int db8500_regulator_disable(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
- int ret = 0;
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev), "regulator-%s-disable\n",
- info->desc.name);
-
- if (info->is_enabled) {
- info->is_enabled = false;
- if (!info->exclude_from_power_state)
- ret = power_state_active_disable();
- }
-
- return ret;
-}
-
-static int db8500_regulator_is_enabled(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev), "regulator-%s-is_enabled (is_enabled):"
- " %i\n", info->desc.name, info->is_enabled);
-
- return info->is_enabled;
-}
-
-/* db8500 regulator operations */
-static const struct regulator_ops db8500_regulator_ops = {
- .enable = db8500_regulator_enable,
- .disable = db8500_regulator_disable,
- .is_enabled = db8500_regulator_is_enabled,
-};
-
-/*
- * EPOD control
- */
-static bool epod_on[NUM_EPOD_ID];
-static bool epod_ramret[NUM_EPOD_ID];
-
-static int enable_epod(u16 epod_id, bool ramret)
-{
- int ret;
-
- if (ramret) {
- if (!epod_on[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
- if (ret < 0)
- return ret;
- }
- epod_ramret[epod_id] = true;
- } else {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
- if (ret < 0)
- return ret;
- epod_on[epod_id] = true;
- }
-
- return 0;
-}
-
-static int disable_epod(u16 epod_id, bool ramret)
-{
- int ret;
-
- if (ramret) {
- if (!epod_on[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
- if (ret < 0)
- return ret;
- }
- epod_ramret[epod_id] = false;
- } else {
- if (epod_ramret[epod_id]) {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
- if (ret < 0)
- return ret;
- } else {
- ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
- if (ret < 0)
- return ret;
- }
- epod_on[epod_id] = false;
- }
-
- return 0;
-}
-
-/*
- * Regulator switch
- */
-static int db8500_regulator_switch_enable(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-enable\n",
- info->desc.name);
-
- ret = enable_epod(info->epod_id, info->is_ramret);
- if (ret < 0) {
- dev_err(rdev_get_dev(rdev),
- "regulator-switch-%s-enable: prcmu call failed\n",
- info->desc.name);
- goto out;
- }
-
- info->is_enabled = true;
-out:
- return ret;
-}
-
-static int db8500_regulator_switch_disable(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
- int ret;
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev), "regulator-switch-%s-disable\n",
- info->desc.name);
-
- ret = disable_epod(info->epod_id, info->is_ramret);
- if (ret < 0) {
- dev_err(rdev_get_dev(rdev),
- "regulator_switch-%s-disable: prcmu call failed\n",
- info->desc.name);
- goto out;
- }
-
- info->is_enabled = false;
-out:
- return ret;
-}
-
-static int db8500_regulator_switch_is_enabled(struct regulator_dev *rdev)
-{
- struct dbx500_regulator_info *info = rdev_get_drvdata(rdev);
-
- if (info == NULL)
- return -EINVAL;
-
- dev_vdbg(rdev_get_dev(rdev),
- "regulator-switch-%s-is_enabled (is_enabled): %i\n",
- info->desc.name, info->is_enabled);
-
- return info->is_enabled;
-}
-
-static const struct regulator_ops db8500_regulator_switch_ops = {
- .enable = db8500_regulator_switch_enable,
- .disable = db8500_regulator_switch_disable,
- .is_enabled = db8500_regulator_switch_is_enabled,
-};
-
-/*
- * Regulator information
- */
-static struct dbx500_regulator_info
-dbx500_regulator_info[DB8500_NUM_REGULATORS] = {
- [DB8500_REGULATOR_VAPE] = {
- .desc = {
- .name = "db8500-vape",
- .of_match = of_match_ptr("db8500_vape"),
- .id = DB8500_REGULATOR_VAPE,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VARM] = {
- .desc = {
- .name = "db8500-varm",
- .of_match = of_match_ptr("db8500_varm"),
- .id = DB8500_REGULATOR_VARM,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VMODEM] = {
- .desc = {
- .name = "db8500-vmodem",
- .of_match = of_match_ptr("db8500_vmodem"),
- .id = DB8500_REGULATOR_VMODEM,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VPLL] = {
- .desc = {
- .name = "db8500-vpll",
- .of_match = of_match_ptr("db8500_vpll"),
- .id = DB8500_REGULATOR_VPLL,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VSMPS1] = {
- .desc = {
- .name = "db8500-vsmps1",
- .of_match = of_match_ptr("db8500_vsmps1"),
- .id = DB8500_REGULATOR_VSMPS1,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VSMPS2] = {
- .desc = {
- .name = "db8500-vsmps2",
- .of_match = of_match_ptr("db8500_vsmps2"),
- .id = DB8500_REGULATOR_VSMPS2,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- .fixed_uV = 1800000,
- .n_voltages = 1,
- },
- .exclude_from_power_state = true,
- },
- [DB8500_REGULATOR_VSMPS3] = {
- .desc = {
- .name = "db8500-vsmps3",
- .of_match = of_match_ptr("db8500_vsmps3"),
- .id = DB8500_REGULATOR_VSMPS3,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_VRF1] = {
- .desc = {
- .name = "db8500-vrf1",
- .of_match = of_match_ptr("db8500_vrf1"),
- .id = DB8500_REGULATOR_VRF1,
- .ops = &db8500_regulator_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- },
- [DB8500_REGULATOR_SWITCH_SVAMMDSP] = {
- .desc = {
- .name = "db8500-sva-mmdsp",
- .of_match = of_match_ptr("db8500_sva_mmdsp"),
- .id = DB8500_REGULATOR_SWITCH_SVAMMDSP,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SVAMMDSP,
- },
- [DB8500_REGULATOR_SWITCH_SVAMMDSPRET] = {
- .desc = {
- .name = "db8500-sva-mmdsp-ret",
- .of_match = of_match_ptr("db8500_sva_mmdsp_ret"),
- .id = DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SVAMMDSP,
- .is_ramret = true,
- },
- [DB8500_REGULATOR_SWITCH_SVAPIPE] = {
- .desc = {
- .name = "db8500-sva-pipe",
- .of_match = of_match_ptr("db8500_sva_pipe"),
- .id = DB8500_REGULATOR_SWITCH_SVAPIPE,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SVAPIPE,
- },
- [DB8500_REGULATOR_SWITCH_SIAMMDSP] = {
- .desc = {
- .name = "db8500-sia-mmdsp",
- .of_match = of_match_ptr("db8500_sia_mmdsp"),
- .id = DB8500_REGULATOR_SWITCH_SIAMMDSP,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SIAMMDSP,
- },
- [DB8500_REGULATOR_SWITCH_SIAMMDSPRET] = {
- .desc = {
- .name = "db8500-sia-mmdsp-ret",
- .of_match = of_match_ptr("db8500_sia_mmdsp_ret"),
- .id = DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SIAMMDSP,
- .is_ramret = true,
- },
- [DB8500_REGULATOR_SWITCH_SIAPIPE] = {
- .desc = {
- .name = "db8500-sia-pipe",
- .of_match = of_match_ptr("db8500_sia_pipe"),
- .id = DB8500_REGULATOR_SWITCH_SIAPIPE,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SIAPIPE,
- },
- [DB8500_REGULATOR_SWITCH_SGA] = {
- .desc = {
- .name = "db8500-sga",
- .of_match = of_match_ptr("db8500_sga"),
- .id = DB8500_REGULATOR_SWITCH_SGA,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_SGA,
- },
- [DB8500_REGULATOR_SWITCH_B2R2_MCDE] = {
- .desc = {
- .name = "db8500-b2r2-mcde",
- .of_match = of_match_ptr("db8500_b2r2_mcde"),
- .id = DB8500_REGULATOR_SWITCH_B2R2_MCDE,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_B2R2_MCDE,
- },
- [DB8500_REGULATOR_SWITCH_ESRAM12] = {
- .desc = {
- .name = "db8500-esram12",
- .of_match = of_match_ptr("db8500_esram12"),
- .id = DB8500_REGULATOR_SWITCH_ESRAM12,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_ESRAM12,
- .is_enabled = true,
- },
- [DB8500_REGULATOR_SWITCH_ESRAM12RET] = {
- .desc = {
- .name = "db8500-esram12-ret",
- .of_match = of_match_ptr("db8500_esram12_ret"),
- .id = DB8500_REGULATOR_SWITCH_ESRAM12RET,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_ESRAM12,
- .is_ramret = true,
- },
- [DB8500_REGULATOR_SWITCH_ESRAM34] = {
- .desc = {
- .name = "db8500-esram34",
- .of_match = of_match_ptr("db8500_esram34"),
- .id = DB8500_REGULATOR_SWITCH_ESRAM34,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_ESRAM34,
- .is_enabled = true,
- },
- [DB8500_REGULATOR_SWITCH_ESRAM34RET] = {
- .desc = {
- .name = "db8500-esram34-ret",
- .of_match = of_match_ptr("db8500_esram34_ret"),
- .id = DB8500_REGULATOR_SWITCH_ESRAM34RET,
- .ops = &db8500_regulator_switch_ops,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- },
- .epod_id = EPOD_ID_ESRAM34,
- .is_ramret = true,
- },
-};
-
-static int db8500_regulator_probe(struct platform_device *pdev)
-{
- struct regulator_init_data *db8500_init_data;
- struct dbx500_regulator_info *info;
- struct regulator_config config = { };
- struct regulator_dev *rdev;
- int err, i;
-
- db8500_init_data = dev_get_platdata(&pdev->dev);
-
- for (i = 0; i < ARRAY_SIZE(dbx500_regulator_info); i++) {
- /* assign per-regulator data */
- info = &dbx500_regulator_info[i];
-
- config.driver_data = info;
- config.dev = &pdev->dev;
- if (db8500_init_data)
- config.init_data = &db8500_init_data[i];
-
- rdev = devm_regulator_register(&pdev->dev, &info->desc,
- &config);
- if (IS_ERR(rdev)) {
- err = PTR_ERR(rdev);
- dev_err(&pdev->dev, "failed to register %s: err %i\n",
- info->desc.name, err);
- return err;
- }
- dev_dbg(&pdev->dev, "regulator-%s-probed\n", info->desc.name);
- }
-
- ux500_regulator_debug_init(pdev, dbx500_regulator_info,
- ARRAY_SIZE(dbx500_regulator_info));
- return 0;
-}
-
-static void db8500_regulator_remove(struct platform_device *pdev)
-{
- ux500_regulator_debug_exit();
-}
-
-static struct platform_driver db8500_regulator_driver = {
- .driver = {
- .name = "db8500-prcmu-regulators",
- .probe_type = PROBE_PREFER_ASYNCHRONOUS,
- },
- .probe = db8500_regulator_probe,
- .remove = db8500_regulator_remove,
-};
-
-static int __init db8500_regulator_init(void)
-{
- return platform_driver_register(&db8500_regulator_driver);
-}
-
-static void __exit db8500_regulator_exit(void)
-{
- platform_driver_unregister(&db8500_regulator_driver);
-}
-
-arch_initcall(db8500_regulator_init);
-module_exit(db8500_regulator_exit);
-
-MODULE_AUTHOR("STMicroelectronics/ST-Ericsson");
-MODULE_DESCRIPTION("DB8500 regulator driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c
deleted file mode 100644
index a45c1e1ac7ef..000000000000
--- a/drivers/regulator/dbx500-prcmu.c
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Authors: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
- * Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
- *
- * UX500 common part of Power domain regulators
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/regulator/driver.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include "dbx500-prcmu.h"
-
-/*
- * power state reference count
- */
-static int power_state_active_cnt; /* will initialize to zero */
-static DEFINE_SPINLOCK(power_state_active_lock);
-
-void power_state_active_enable(void)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- power_state_active_cnt++;
- spin_unlock_irqrestore(&power_state_active_lock, flags);
-}
-
-int power_state_active_disable(void)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- if (power_state_active_cnt <= 0) {
- pr_err("power state: unbalanced enable/disable calls\n");
- ret = -EINVAL;
- goto out;
- }
-
- power_state_active_cnt--;
-out:
- spin_unlock_irqrestore(&power_state_active_lock, flags);
- return ret;
-}
-
-#ifdef CONFIG_REGULATOR_DEBUG
-
-static int power_state_active_get(void)
-{
- unsigned long flags;
- int cnt;
-
- spin_lock_irqsave(&power_state_active_lock, flags);
- cnt = power_state_active_cnt;
- spin_unlock_irqrestore(&power_state_active_lock, flags);
-
- return cnt;
-}
-
-static struct ux500_regulator_debug {
- struct dentry *dir;
- struct dbx500_regulator_info *regulator_array;
- int num_regulators;
- u8 *state_before_suspend;
- u8 *state_after_suspend;
-} rdebug;
-
-static int ux500_regulator_power_state_cnt_show(struct seq_file *s, void *p)
-{
- /* print power state count */
- seq_printf(s, "ux500-regulator power state count: %i\n",
- power_state_active_get());
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(ux500_regulator_power_state_cnt);
-
-static int ux500_regulator_status_show(struct seq_file *s, void *p)
-{
- int i;
-
- /* print dump header */
- seq_puts(s, "ux500-regulator status:\n");
- seq_printf(s, "%31s : %8s : %8s\n", "current", "before", "after");
-
- for (i = 0; i < rdebug.num_regulators; i++) {
- struct dbx500_regulator_info *info;
- /* Access per-regulator data */
- info = &rdebug.regulator_array[i];
-
- /* print status */
- seq_printf(s, "%20s : %8s : %8s : %8s\n",
- info->desc.name,
- info->is_enabled ? "enabled" : "disabled",
- rdebug.state_before_suspend[i] ? "enabled" : "disabled",
- rdebug.state_after_suspend[i] ? "enabled" : "disabled");
- }
-
- return 0;
-}
-DEFINE_SHOW_ATTRIBUTE(ux500_regulator_status);
-
-int
-ux500_regulator_debug_init(struct platform_device *pdev,
- struct dbx500_regulator_info *regulator_info,
- int num_regulators)
-{
- /* create directory */
- rdebug.dir = debugfs_create_dir("ux500-regulator", NULL);
-
- /* create "status" file */
- debugfs_create_file("status", 0444, rdebug.dir, &pdev->dev,
- &ux500_regulator_status_fops);
-
- /* create "power-state-count" file */
- debugfs_create_file("power-state-count", 0444, rdebug.dir,
- &pdev->dev, &ux500_regulator_power_state_cnt_fops);
-
- rdebug.regulator_array = regulator_info;
- rdebug.num_regulators = num_regulators;
-
- rdebug.state_before_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_before_suspend)
- goto exit_destroy_power_state;
-
- rdebug.state_after_suspend = kzalloc(num_regulators, GFP_KERNEL);
- if (!rdebug.state_after_suspend)
- goto exit_free;
-
- return 0;
-
-exit_free:
- kfree(rdebug.state_before_suspend);
-exit_destroy_power_state:
- debugfs_remove_recursive(rdebug.dir);
- return -ENOMEM;
-}
-
-int ux500_regulator_debug_exit(void)
-{
- debugfs_remove_recursive(rdebug.dir);
- kfree(rdebug.state_after_suspend);
- kfree(rdebug.state_before_suspend);
-
- return 0;
-}
-#endif
diff --git a/drivers/regulator/dbx500-prcmu.h b/drivers/regulator/dbx500-prcmu.h
deleted file mode 100644
index 2fb3aaef9dbb..000000000000
--- a/drivers/regulator/dbx500-prcmu.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Bengt Jonsson <bengt.jonsson@stericsson.com> for ST-Ericsson,
- * Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
- */
-
-#ifndef DBX500_REGULATOR_H
-#define DBX500_REGULATOR_H
-
-#include <linux/platform_device.h>
-
-/**
- * struct dbx500_regulator_info - dbx500 regulator information
- * @desc: regulator description
- * @is_enabled: status of the regulator
- * @epod_id: id for EPOD (power domain)
- * @is_ramret: RAM retention switch for EPOD (power domain)
- *
- */
-struct dbx500_regulator_info {
- struct regulator_desc desc;
- bool is_enabled;
- u16 epod_id;
- bool is_ramret;
- bool exclude_from_power_state;
-};
-
-void power_state_active_enable(void);
-int power_state_active_disable(void);
-
-
-#ifdef CONFIG_REGULATOR_DEBUG
-int ux500_regulator_debug_init(struct platform_device *pdev,
- struct dbx500_regulator_info *regulator_info,
- int num_regulators);
-
-int ux500_regulator_debug_exit(void);
-#else
-
-static inline int ux500_regulator_debug_init(struct platform_device *pdev,
- struct dbx500_regulator_info *regulator_info,
- int num_regulators)
-{
- return 0;
-}
-
-static inline int ux500_regulator_debug_exit(void)
-{
- return 0;
-}
-
-#endif
-#endif
diff --git a/include/linux/regulator/db8500-prcmu.h b/include/linux/regulator/db8500-prcmu.h
deleted file mode 100644
index d58ff273157e..000000000000
--- a/include/linux/regulator/db8500-prcmu.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> for ST-Ericsson
- *
- * Interface to power domain regulators on DB8500
- */
-
-#ifndef __REGULATOR_H__
-#define __REGULATOR_H__
-
-/* Number of DB8500 regulators and regulator enumeration */
-enum db8500_regulator_id {
- DB8500_REGULATOR_VAPE,
- DB8500_REGULATOR_VARM,
- DB8500_REGULATOR_VMODEM,
- DB8500_REGULATOR_VPLL,
- DB8500_REGULATOR_VSMPS1,
- DB8500_REGULATOR_VSMPS2,
- DB8500_REGULATOR_VSMPS3,
- DB8500_REGULATOR_VRF1,
- DB8500_REGULATOR_SWITCH_SVAMMDSP,
- DB8500_REGULATOR_SWITCH_SVAMMDSPRET,
- DB8500_REGULATOR_SWITCH_SVAPIPE,
- DB8500_REGULATOR_SWITCH_SIAMMDSP,
- DB8500_REGULATOR_SWITCH_SIAMMDSPRET,
- DB8500_REGULATOR_SWITCH_SIAPIPE,
- DB8500_REGULATOR_SWITCH_SGA,
- DB8500_REGULATOR_SWITCH_B2R2_MCDE,
- DB8500_REGULATOR_SWITCH_ESRAM12,
- DB8500_REGULATOR_SWITCH_ESRAM12RET,
- DB8500_REGULATOR_SWITCH_ESRAM34,
- DB8500_REGULATOR_SWITCH_ESRAM34RET,
- DB8500_NUM_REGULATORS
-};
-
-#endif
--
2.54.0
^ permalink raw reply related
* [PATCH 08/11] dmaengine: ste_dma40: Use power domain for LCLA SRAM
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Replace the LCLA ESRAM regulator with runtime PM.
Use the SRAM device that owns the ESRAM34 power domain.
Hold that domain while DMA transfers are active.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
drivers/dma/ste_dma40.c | 97 ++++++++++++++++++++++++++++---------------------
1 file changed, 55 insertions(+), 42 deletions(-)
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 9b803c0aec25..6ca67ec446dc 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -21,8 +21,8 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_dma.h>
+#include <linux/of_platform.h>
#include <linux/amba/bus.h>
-#include <linux/regulator/consumer.h>
#include "dmaengine.h"
#include "ste_dma40.h"
@@ -571,7 +571,8 @@ struct d40_gen_dmac {
* to phy_chans entries.
* @plat_data: Pointer to provided platform_data which is the driver
* configuration.
- * @lcpa_regulator: Pointer to hold the regulator for the esram bank for lcla.
+ * @lcla_dev: SRAM device for the ESRAM bank used by LCLA.
+ * @lcla_pm_enabled: Whether runtime PM was enabled for LCLA by this driver.
* @phy_res: Vector containing all physical channels.
* @lcla_pool: lcla pool settings and data.
* @lcpa_base: The virtual mapped address of LCPA.
@@ -607,7 +608,8 @@ struct d40_base {
struct d40_chan **lookup_log_chans;
struct d40_chan **lookup_phy_chans;
struct stedma40_platform_data *plat_data;
- struct regulator *lcpa_regulator;
+ struct device *lcla_dev;
+ bool lcla_pm_enabled;
/* Physical half channels */
struct d40_phy_res *phy_res;
struct d40_lcla_pool lcla_pool;
@@ -628,6 +630,22 @@ static struct device *chan2dev(struct d40_chan *d40c)
return &d40c->chan.dev->device;
}
+static void d40_transfer_runtime_get(struct d40_base *base)
+{
+ if (base->lcla_dev)
+ pm_runtime_get_sync(base->lcla_dev);
+
+ pm_runtime_get_sync(base->dev);
+}
+
+static void d40_transfer_runtime_put(struct d40_base *base)
+{
+ pm_runtime_put_autosuspend(base->dev);
+
+ if (base->lcla_dev)
+ pm_runtime_put_sync_suspend(base->lcla_dev);
+}
+
static bool chan_is_physical(struct d40_chan *chan)
{
return chan->log_num == D40_PHY_CHAN;
@@ -1516,7 +1534,7 @@ static struct d40_desc *d40_queue_start(struct d40_chan *d40c)
if (d40d != NULL) {
if (!d40c->busy) {
d40c->busy = true;
- pm_runtime_get_sync(d40c->base->dev);
+ d40_transfer_runtime_get(d40c->base);
}
/* Remove from queue */
@@ -1579,7 +1597,7 @@ static void dma_tc_handle(struct d40_chan *d40c)
if (d40_queue_start(d40c) == NULL) {
d40c->busy = false;
- pm_runtime_put_autosuspend(d40c->base->dev);
+ d40_transfer_runtime_put(d40c->base);
}
d40_desc_remove(d40d);
@@ -2052,7 +2070,7 @@ static int d40_free_dma(struct d40_chan *d40c)
d40c->base->lookup_phy_chans[phy->num] = NULL;
if (d40c->busy)
- pm_runtime_put_autosuspend(d40c->base->dev);
+ d40_transfer_runtime_put(d40c->base);
d40c->busy = false;
d40c->phy_chan = NULL;
@@ -2613,7 +2631,7 @@ static int d40_terminate_all(struct dma_chan *chan)
d40_term_all(d40c);
pm_runtime_put_autosuspend(d40c->base->dev);
if (d40c->busy)
- pm_runtime_put_autosuspend(d40c->base->dev);
+ d40_transfer_runtime_put(d40c->base);
d40c->busy = false;
spin_unlock_irqrestore(&d40c->lock, flags);
@@ -2916,29 +2934,11 @@ static int __init d40_dmaengine_init(struct d40_base *base,
#ifdef CONFIG_PM_SLEEP
static int dma40_suspend(struct device *dev)
{
- struct d40_base *base = dev_get_drvdata(dev);
- int ret;
-
- ret = pm_runtime_force_suspend(dev);
- if (ret)
- return ret;
-
- if (base->lcpa_regulator)
- ret = regulator_disable(base->lcpa_regulator);
- return ret;
+ return pm_runtime_force_suspend(dev);
}
static int dma40_resume(struct device *dev)
{
- struct d40_base *base = dev_get_drvdata(dev);
- int ret = 0;
-
- if (base->lcpa_regulator) {
- ret = regulator_enable(base->lcpa_regulator);
- if (ret)
- return ret;
- }
-
return pm_runtime_force_resume(dev);
}
#endif
@@ -3492,7 +3492,10 @@ static int __init d40_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct device_node *np_lcpa;
+ struct device_node *np_lcla;
+ struct device_node *np_lcla_parent;
struct d40_base *base;
+ struct platform_device *lcla_pdev;
struct resource *res;
struct resource res_lcpa;
int num_reserved_chans;
@@ -3590,23 +3593,32 @@ static int __init d40_probe(struct platform_device *pdev)
}
if (base->plat_data->use_esram_lcla) {
+ np_lcla = of_parse_phandle(np, "sram", 1);
+ if (!np_lcla) {
+ dev_err(dev, "no LCLA SRAM node\n");
+ ret = -EINVAL;
+ goto destroy_cache;
+ }
- base->lcpa_regulator = regulator_get(base->dev, "lcla_esram");
- if (IS_ERR(base->lcpa_regulator)) {
- d40_err(dev, "Failed to get lcpa_regulator\n");
- ret = PTR_ERR(base->lcpa_regulator);
- base->lcpa_regulator = NULL;
+ np_lcla_parent = of_get_parent(np_lcla);
+ of_node_put(np_lcla);
+ if (!np_lcla_parent) {
+ dev_err(dev, "no LCLA SRAM parent node\n");
+ ret = -EINVAL;
goto destroy_cache;
}
- ret = regulator_enable(base->lcpa_regulator);
- if (ret) {
- d40_err(dev,
- "Failed to enable lcpa_regulator\n");
- regulator_put(base->lcpa_regulator);
- base->lcpa_regulator = NULL;
+ lcla_pdev = of_find_device_by_node(np_lcla_parent);
+ of_node_put(np_lcla_parent);
+ if (!lcla_pdev) {
+ ret = -EPROBE_DEFER;
goto destroy_cache;
}
+ base->lcla_dev = &lcla_pdev->dev;
+ if (!pm_runtime_enabled(base->lcla_dev)) {
+ pm_runtime_enable(base->lcla_dev);
+ base->lcla_pm_enabled = true;
+ }
}
writel_relaxed(D40_DREG_GCC_ENABLE_ALL, base->virtbase + D40_DREG_GCC);
@@ -3642,16 +3654,17 @@ static int __init d40_probe(struct platform_device *pdev)
SZ_1K * base->num_phy_chans,
DMA_TO_DEVICE);
- if (!base->lcla_pool.base_unaligned && base->lcla_pool.base)
+ if (!base->lcla_pool.base_unaligned && base->lcla_pool.base &&
+ base->lcla_pool.pages)
free_pages((unsigned long)base->lcla_pool.base,
base->lcla_pool.pages);
kfree(base->lcla_pool.base_unaligned);
- if (base->lcpa_regulator) {
- regulator_disable(base->lcpa_regulator);
- regulator_put(base->lcpa_regulator);
- }
+ if (base->lcla_pm_enabled)
+ pm_runtime_disable(base->lcla_dev);
+ if (base->lcla_dev)
+ put_device(base->lcla_dev);
pm_runtime_disable(base->dev);
report_failure:
--
2.54.0
^ permalink raw reply related
* [PATCH 07/11] drm/mcde: Use power domain for display power
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Replace explicit EPOD regulator handling with runtime PM.
Use the MCDE power domain and drop the regulator dependency.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
drivers/gpu/drm/mcde/mcde_clk_div.c | 4 +--
drivers/gpu/drm/mcde/mcde_display.c | 11 +++----
drivers/gpu/drm/mcde/mcde_drm.h | 2 --
drivers/gpu/drm/mcde/mcde_drv.c | 63 +++++++++++--------------------------
drivers/gpu/drm/mcde/mcde_dsi.c | 1 -
5 files changed, 25 insertions(+), 56 deletions(-)
diff --git a/drivers/gpu/drm/mcde/mcde_clk_div.c b/drivers/gpu/drm/mcde/mcde_clk_div.c
index 8c5af2677357..1a22e6233946 100644
--- a/drivers/gpu/drm/mcde/mcde_clk_div.c
+++ b/drivers/gpu/drm/mcde/mcde_clk_div.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/clk-provider.h>
#include <linux/io.h>
-#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include "mcde_drm.h"
#include "mcde_display_regs.h"
@@ -95,7 +95,7 @@ static unsigned long mcde_clk_div_recalc_rate(struct clk_hw *hw,
* It will come up with 0 in the divider register bits, which
* means "divide by 2".
*/
- if (!regulator_is_enabled(mcde->epod))
+ if (!pm_runtime_active(mcde->dev))
return DIV_ROUND_UP_ULL(prate, 2);
cr = readl(mcde->regs + cdiv->cr);
diff --git a/drivers/gpu/drm/mcde/mcde_display.c b/drivers/gpu/drm/mcde/mcde_display.c
index 257a6e84dd58..52f071bb347c 100644
--- a/drivers/gpu/drm/mcde/mcde_display.c
+++ b/drivers/gpu/drm/mcde/mcde_display.c
@@ -7,7 +7,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/dma-buf.h>
-#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/media-bus-format.h>
#include <drm/drm_device.h>
@@ -1168,16 +1168,15 @@ static void mcde_display_enable(struct drm_simple_display_pipe *pipe,
int ret;
/* This powers up the entire MCDE block and the DSI hardware */
- ret = regulator_enable(mcde->epod);
+ ret = pm_runtime_resume_and_get(mcde->dev);
if (ret) {
- dev_err(drm->dev, "can't re-enable EPOD regulator\n");
+ dev_err(drm->dev, "can't enable MCDE power domain\n");
return;
}
dev_info(drm->dev, "enable MCDE, %d x %d format %p4cc\n",
mode->hdisplay, mode->vdisplay, &format);
-
/* Clear any pending interrupts */
mcde_display_disable_irqs(mcde);
writel(0, mcde->regs + MCDE_IMSCERR);
@@ -1327,9 +1326,9 @@ static void mcde_display_disable(struct drm_simple_display_pipe *pipe)
spin_unlock_irq(&crtc->dev->event_lock);
}
- ret = regulator_disable(mcde->epod);
+ ret = pm_runtime_put_sync_suspend(mcde->dev);
if (ret)
- dev_err(drm->dev, "can't disable EPOD regulator\n");
+ dev_err(drm->dev, "can't disable MCDE power domain\n");
/* Make sure we are powered down (before we may power up again) */
usleep_range(50000, 70000);
diff --git a/drivers/gpu/drm/mcde/mcde_drm.h b/drivers/gpu/drm/mcde/mcde_drm.h
index ecb70b4b737c..d4ff7606d917 100644
--- a/drivers/gpu/drm/mcde/mcde_drm.h
+++ b/drivers/gpu/drm/mcde/mcde_drm.h
@@ -91,8 +91,6 @@ struct mcde {
/* Locks the MCDE FIFO control register A and B */
spinlock_t fifo_crx1_lock;
- struct regulator *epod;
- struct regulator *vana;
};
#define to_mcde(dev) container_of(dev, struct mcde, drm)
diff --git a/drivers/gpu/drm/mcde/mcde_drv.c b/drivers/gpu/drm/mcde/mcde_drv.c
index 5f2c462bad7e..3f966cccda5a 100644
--- a/drivers/gpu/drm/mcde/mcde_drv.c
+++ b/drivers/gpu/drm/mcde/mcde_drv.c
@@ -61,7 +61,7 @@
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -283,45 +283,25 @@ static int mcde_probe(struct platform_device *pdev)
mcde->dev = dev;
platform_set_drvdata(pdev, drm);
- /* First obtain and turn on the main power */
- mcde->epod = devm_regulator_get(dev, "epod");
- if (IS_ERR(mcde->epod)) {
- ret = PTR_ERR(mcde->epod);
- dev_err(dev, "can't get EPOD regulator\n");
- return ret;
- }
- ret = regulator_enable(mcde->epod);
+ pm_runtime_enable(dev);
+ ret = pm_runtime_resume_and_get(dev);
if (ret) {
- dev_err(dev, "can't enable EPOD regulator\n");
+ dev_err(dev, "can't enable MCDE power domain\n");
+ pm_runtime_disable(dev);
return ret;
}
- mcde->vana = devm_regulator_get(dev, "vana");
- if (IS_ERR(mcde->vana)) {
- ret = PTR_ERR(mcde->vana);
- dev_err(dev, "can't get VANA regulator\n");
- goto regulator_epod_off;
- }
- ret = regulator_enable(mcde->vana);
- if (ret) {
- dev_err(dev, "can't enable VANA regulator\n");
- goto regulator_epod_off;
- }
- /*
- * The vendor code uses ESRAM (onchip RAM) and need to activate
- * the v-esram34 regulator, but we don't use that yet
- */
/* Clock the silicon so we can access the registers */
mcde->mcde_clk = devm_clk_get(dev, "mcde");
if (IS_ERR(mcde->mcde_clk)) {
dev_err(dev, "unable to get MCDE main clock\n");
ret = PTR_ERR(mcde->mcde_clk);
- goto regulator_off;
+ goto pm_runtime_put;
}
ret = clk_prepare_enable(mcde->mcde_clk);
if (ret) {
dev_err(dev, "failed to enable MCDE main clock\n");
- goto regulator_off;
+ goto pm_runtime_put;
}
dev_info(dev, "MCDE clk rate %lu Hz\n", clk_get_rate(mcde->mcde_clk));
@@ -412,14 +392,15 @@ static int mcde_probe(struct platform_device *pdev)
/*
* Perform an invasive reset of the MCDE and all blocks by
- * cutting the power to the subsystem, then bring it back up
+ * powering down the subsystem, then bring it back up
* later when we enable the display as a result of
* component_master_add_with_match().
*/
- ret = regulator_disable(mcde->epod);
+ ret = pm_runtime_put_sync_suspend(dev);
if (ret) {
- dev_err(dev, "can't disable EPOD regulator\n");
- return ret;
+ dev_err(dev, "can't disable MCDE power domain\n");
+ pm_runtime_get_noresume(dev);
+ goto clk_disable;
}
/* Wait 50 ms so we are sure we cut the power */
usleep_range(50000, 70000);
@@ -428,25 +409,18 @@ static int mcde_probe(struct platform_device *pdev)
match);
if (ret) {
dev_err(dev, "failed to add component master\n");
- /*
- * The EPOD regulator is already disabled at this point so some
- * special errorpath code is needed
- */
- clk_disable_unprepare(mcde->mcde_clk);
- regulator_disable(mcde->vana);
- return ret;
+ goto clk_disable_pm_disabled;
}
return 0;
clk_disable:
clk_disable_unprepare(mcde->mcde_clk);
-regulator_off:
- regulator_disable(mcde->vana);
-regulator_epod_off:
- regulator_disable(mcde->epod);
+pm_runtime_put:
+ pm_runtime_put_sync_suspend(dev);
+clk_disable_pm_disabled:
+ pm_runtime_disable(dev);
return ret;
-
}
static void mcde_remove(struct platform_device *pdev)
@@ -456,8 +430,7 @@ static void mcde_remove(struct platform_device *pdev)
component_master_del(&pdev->dev, &mcde_drm_comp_ops);
clk_disable_unprepare(mcde->mcde_clk);
- regulator_disable(mcde->vana);
- regulator_disable(mcde->epod);
+ pm_runtime_disable(&pdev->dev);
}
static void mcde_shutdown(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 47d45897ed06..e09b2d4aca0c 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -8,7 +8,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
-#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_atomic_helper.h>
--
2.54.0
^ permalink raw reply related
* [PATCH 06/11] pmdomain: st: ux500: Control DB8500 EPODs
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Move the DB8500 EPOD state handling into the Ux500 power-domain driver.
Keep the old regulator driver mutually exclusive with the pmdomain driver.
Assisted-by: Codex:gpt-5-5
Signed-off-by: Linus Walleij <linusw@kernel.org>
---
arch/arm/mach-ux500/Kconfig | 2 +-
drivers/pmdomain/st/ste-ux500-pm-domain.c | 380 ++++++++++++++++++++++--------
drivers/regulator/Kconfig | 1 +
3 files changed, 282 insertions(+), 101 deletions(-)
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index c18def269137..56636c993f49 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -26,7 +26,7 @@ menuconfig ARCH_U8500
select PL310_ERRATA_753970 if CACHE_L2X0
select PM_GENERIC_DOMAINS if PM
select REGULATOR
- select REGULATOR_DB8500_PRCMU
+ select UX500_PM_DOMAIN
select REGULATOR_FIXED_VOLTAGE
select SOC_BUS
select RESET_CONTROLLER
diff --git a/drivers/pmdomain/st/ste-ux500-pm-domain.c b/drivers/pmdomain/st/ste-ux500-pm-domain.c
index 723001004690..1cd5b4985db0 100644
--- a/drivers/pmdomain/st/ste-ux500-pm-domain.c
+++ b/drivers/pmdomain/st/ste-ux500-pm-domain.c
@@ -6,172 +6,315 @@
*
* Implements PM domains using the generic PM domain for ux500.
*/
+#include <linux/cleanup.h>
#include <linux/device.h>
+#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/mfd/dbx500-prcmu.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
#include <linux/printk.h>
#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/of.h>
-#include <linux/pm_domain.h>
#include <dt-bindings/arm/ux500_pm_domains.h>
-static int pd_power_off(struct generic_pm_domain *domain)
+#define UX500_EPOD_NONE NUM_EPOD_ID
+
+/**
+ * struct dbx500_powerdomain_info - dbx500 power domain information
+ * @genpd: generic power domain
+ * @epod_id: id for EPOD (power domain)
+ * @is_ramret: RAM retention switch for EPOD (power domain)
+ * @exclude_from_power_state: exclude domain from power state count
+ */
+struct dbx500_powerdomain_info {
+ struct generic_pm_domain genpd;
+ u16 epod_id;
+ bool is_ramret;
+ bool exclude_from_power_state;
+};
+
+static DEFINE_MUTEX(ux500_pd_lock);
+static int power_state_active_cnt;
+static bool epod_on[NUM_EPOD_ID];
+static bool epod_ramret[NUM_EPOD_ID];
+
+static void power_state_active_enable(void)
+{
+ power_state_active_cnt++;
+}
+
+static int power_state_active_disable(void)
{
- /*
- * Handle the gating of the PM domain regulator here.
- *
- * Drivers/subsystems handling devices in the PM domain needs to perform
- * register context save/restore from their respective runtime PM
- * callbacks, to be able to enable PM domain gating/ungating.
- */
+ if (power_state_active_cnt <= 0) {
+ pr_err("power state: unbalanced enable/disable calls\n");
+ return -EINVAL;
+ }
+
+ power_state_active_cnt--;
return 0;
}
-static int pd_power_on(struct generic_pm_domain *domain)
+static int enable_epod(u16 epod_id, bool ramret)
{
- /*
- * Handle the ungating of the PM domain regulator here.
- *
- * Drivers/subsystems handling devices in the PM domain needs to perform
- * register context save/restore from their respective runtime PM
- * callbacks, to be able to enable PM domain gating/ungating.
- */
+ int ret;
+
+ if (ramret) {
+ if (!epod_on[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ if (ret < 0)
+ return ret;
+ }
+ epod_ramret[epod_id] = true;
+ } else {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_ON);
+ if (ret < 0)
+ return ret;
+ epod_on[epod_id] = true;
+ }
+
+ return 0;
+}
+
+static int disable_epod(u16 epod_id, bool ramret)
+{
+ int ret;
+
+ if (ramret) {
+ if (!epod_on[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ if (ret < 0)
+ return ret;
+ }
+ epod_ramret[epod_id] = false;
+ } else {
+ if (epod_ramret[epod_id]) {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_RAMRET);
+ if (ret < 0)
+ return ret;
+ } else {
+ ret = prcmu_set_epod(epod_id, EPOD_STATE_OFF);
+ if (ret < 0)
+ return ret;
+ }
+ epod_on[epod_id] = false;
+ }
+
return 0;
}
+static int pd_power_off(struct generic_pm_domain *domain)
+{
+ struct dbx500_powerdomain_info *info =
+ container_of(domain, struct dbx500_powerdomain_info, genpd);
+ int ret = 0;
+
+ guard(mutex)(&ux500_pd_lock);
+ if (info->epod_id < NUM_EPOD_ID)
+ ret = disable_epod(info->epod_id, info->is_ramret);
+ else if (!info->exclude_from_power_state)
+ ret = power_state_active_disable();
+
+ return ret;
+}
+
+static int pd_power_on(struct generic_pm_domain *domain)
+{
+ struct dbx500_powerdomain_info *info =
+ container_of(domain, struct dbx500_powerdomain_info, genpd);
+ int ret = 0;
+
+ guard(mutex)(&ux500_pd_lock);
+ if (info->epod_id < NUM_EPOD_ID)
+ ret = enable_epod(info->epod_id, info->is_ramret);
+ else if (!info->exclude_from_power_state)
+ power_state_active_enable();
+
+ return ret;
+}
+
/*
* Apart from these voltage domains there is also VSAFE which is always
* on. Vape_esram0_pwr for eSRAM0 is connected to VSAFE.
*/
-static struct generic_pm_domain ux500_pm_domain_vape = {
+static struct dbx500_powerdomain_info ux500_pm_domain_vape = {
/* Vape_pwr */
- .name = "VAPE", /* 0.95 .. 1.20 V */
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "VAPE", /* 0.95 .. 1.20 V */
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
-static struct generic_pm_domain ux500_pm_domain_varm = {
- .name = "VARM",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_varm = {
+ .genpd = {
+ .name = "VARM",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
-static struct generic_pm_domain ux500_pm_domain_vmodem = {
- .name = "VMODEM",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vmodem = {
+ .genpd = {
+ .name = "VMODEM",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
-static struct generic_pm_domain ux500_pm_domain_vpll = {
- .name = "VPLL", /* 1.8 V */
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vpll = {
+ .genpd = {
+ .name = "VPLL", /* 1.8 V */
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
/*
* CHECKME: as these are used directly by peripherals as regulators,
* perhaps they should stay in the regulator subsystem?
*/
-static struct generic_pm_domain ux500_pm_domain_vsmps1 = {
- .name = "VSMPS1", /* Also called VIO (1.2V) */
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vsmps1 = {
+ .genpd = {
+ .name = "VSMPS1", /* Also called VIO (1.2V) */
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
-static struct generic_pm_domain ux500_pm_domain_vsmps2 = {
- .name = "VSMPS2", /* Also called VIO (1.8V) */
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vsmps2 = {
+ .genpd = {
+ .name = "VSMPS2", /* Also called VIO (1.8V) */
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
+ .exclude_from_power_state = true,
};
-static struct generic_pm_domain ux500_pm_domain_vsmps3 = {
- .name = "VSMPS3",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vsmps3 = {
+ .genpd = {
+ .name = "VSMPS3",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
-static struct generic_pm_domain ux500_pm_domain_vrf1 = {
- .name = "VRF1",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+static struct dbx500_powerdomain_info ux500_pm_domain_vrf1 = {
+ .genpd = {
+ .name = "VRF1",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = UX500_EPOD_NONE,
};
/* The following are technically children of VAPE */
-static struct generic_pm_domain ux500_pm_domain_sva_mmdsp = {
+static struct dbx500_powerdomain_info ux500_pm_domain_sva_mmdsp = {
/* Vape_SVA_MMDSP_pwr */
- .name = "SVA_MMDSP",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "SVA_MMDSP",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_SVAMMDSP,
};
-static struct generic_pm_domain ux500_pm_domain_sva_pipe = {
+static struct dbx500_powerdomain_info ux500_pm_domain_sva_pipe = {
/* Vape_SVA_pwr */
- .name = "SVA_PIPE",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "SVA_PIPE",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_SVAPIPE,
};
-static struct generic_pm_domain ux500_pm_domain_sia_mmdsp = {
+static struct dbx500_powerdomain_info ux500_pm_domain_sia_mmdsp = {
/* Vape_SIA_MMDSP_pwr */
- .name = "SIA_MMDSP",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "SIA_MMDSP",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_SIAMMDSP,
};
-static struct generic_pm_domain ux500_pm_domain_sia_pipe = {
+static struct dbx500_powerdomain_info ux500_pm_domain_sia_pipe = {
/* Vape_SIA_pwr */
- .name = "SIA_PIPE",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "SIA_PIPE",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_SIAPIPE,
};
-static struct generic_pm_domain ux500_pm_domain_sga = {
+static struct dbx500_powerdomain_info ux500_pm_domain_sga = {
/* Vape_SGA_pwr */
- .name = "SGA",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "SGA",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_SGA,
};
-static struct generic_pm_domain ux500_pm_domain_b2r2_mcde = {
+static struct dbx500_powerdomain_info ux500_pm_domain_b2r2_mcde = {
/* Vape_DSS_pwr DSS (display subsystem) */
- .name = "B2R2_MCDE",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "B2R2_MCDE",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_B2R2_MCDE,
};
-static struct generic_pm_domain ux500_pm_domain_esram_12 = {
+static struct dbx500_powerdomain_info ux500_pm_domain_esram_12 = {
/* Vape_esram0_pwr, Vape_esram1_pwr */
- .name = "ESRAM_12",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "ESRAM_12",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_ESRAM12,
};
-static struct generic_pm_domain ux500_pm_domain_esram_34 = {
+static struct dbx500_powerdomain_info ux500_pm_domain_esram_34 = {
/* Vape_esram3_pwr, Vape_esram4_pwr */
- .name = "ESRAM_34",
- .power_off = pd_power_off,
- .power_on = pd_power_on,
+ .genpd = {
+ .name = "ESRAM_34",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+ },
+ .epod_id = EPOD_ID_ESRAM34,
};
static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = {
- [DOMAIN_VAPE] = &ux500_pm_domain_vape,
- [DOMAIN_VARM] = &ux500_pm_domain_varm,
- [DOMAIN_VMODEM] = &ux500_pm_domain_vmodem,
- [DOMAIN_VPLL] = &ux500_pm_domain_vpll,
- [DOMAIN_VSMPS1] = &ux500_pm_domain_vsmps1,
- [DOMAIN_VSMPS2] = &ux500_pm_domain_vsmps2,
- [DOMAIN_VSMPS3] = &ux500_pm_domain_vsmps3,
- [DOMAIN_VRF1] = &ux500_pm_domain_vrf1,
- [DOMAIN_SVA_MMDSP] = &ux500_pm_domain_sva_mmdsp,
- [DOMAIN_SVA_PIPE] = &ux500_pm_domain_sva_pipe,
- [DOMAIN_SIA_MMDSP] = &ux500_pm_domain_sia_mmdsp,
- [DOMAIN_SIA_PIPE] = &ux500_pm_domain_sia_pipe,
- [DOMAIN_SGA] = &ux500_pm_domain_sga,
- [DOMAIN_B2R2_MCDE] = &ux500_pm_domain_b2r2_mcde,
- [DOMAIN_ESRAM_12] = &ux500_pm_domain_esram_12,
- [DOMAIN_ESRAM_34] = &ux500_pm_domain_esram_34,
+ [DOMAIN_VAPE] = &ux500_pm_domain_vape.genpd,
+ [DOMAIN_VARM] = &ux500_pm_domain_varm.genpd,
+ [DOMAIN_VMODEM] = &ux500_pm_domain_vmodem.genpd,
+ [DOMAIN_VPLL] = &ux500_pm_domain_vpll.genpd,
+ [DOMAIN_VSMPS1] = &ux500_pm_domain_vsmps1.genpd,
+ [DOMAIN_VSMPS2] = &ux500_pm_domain_vsmps2.genpd,
+ [DOMAIN_VSMPS3] = &ux500_pm_domain_vsmps3.genpd,
+ [DOMAIN_VRF1] = &ux500_pm_domain_vrf1.genpd,
+ [DOMAIN_SVA_MMDSP] = &ux500_pm_domain_sva_mmdsp.genpd,
+ [DOMAIN_SVA_PIPE] = &ux500_pm_domain_sva_pipe.genpd,
+ [DOMAIN_SIA_MMDSP] = &ux500_pm_domain_sia_mmdsp.genpd,
+ [DOMAIN_SIA_PIPE] = &ux500_pm_domain_sia_pipe.genpd,
+ [DOMAIN_SGA] = &ux500_pm_domain_sga.genpd,
+ [DOMAIN_B2R2_MCDE] = &ux500_pm_domain_b2r2_mcde.genpd,
+ [DOMAIN_ESRAM_12] = &ux500_pm_domain_esram_12.genpd,
+ [DOMAIN_ESRAM_34] = &ux500_pm_domain_esram_34.genpd,
};
static const struct of_device_id ux500_pm_domain_matches[] = {
@@ -179,11 +322,44 @@ static const struct of_device_id ux500_pm_domain_matches[] = {
{ },
};
+static int ux500_pm_domain_add_subdomain(struct generic_pm_domain *domain)
+{
+ return pm_genpd_add_subdomain(&ux500_pm_domain_vape.genpd, domain);
+}
+
+static int ux500_pm_domains_add_subdomains(void)
+{
+ int ret;
+
+ ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sva_mmdsp.genpd);
+ if (ret)
+ return ret;
+
+ ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sva_pipe.genpd);
+ if (ret)
+ return ret;
+
+ ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sia_mmdsp.genpd);
+ if (ret)
+ return ret;
+
+ ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sia_pipe.genpd);
+ if (ret)
+ return ret;
+
+ ret = ux500_pm_domain_add_subdomain(&ux500_pm_domain_sga.genpd);
+ if (ret)
+ return ret;
+
+ return ux500_pm_domain_add_subdomain(&ux500_pm_domain_b2r2_mcde.genpd);
+}
+
static int ux500_pm_domains_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct genpd_onecell_data *genpd_data;
int i;
+ int ret;
if (!np)
return -ENODEV;
@@ -196,7 +372,11 @@ static int ux500_pm_domains_probe(struct platform_device *pdev)
genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains);
for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i)
- pm_genpd_init(ux500_pm_domains[i], NULL, false);
+ pm_genpd_init(ux500_pm_domains[i], NULL, true);
+
+ ret = ux500_pm_domains_add_subdomains();
+ if (ret)
+ return ret;
of_genpd_add_provider_onecell(np, genpd_data);
return 0;
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 87554ab92801..35d1b191462c 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -414,6 +414,7 @@ config REGULATOR_DBX500_PRCMU
config REGULATOR_DB8500_PRCMU
bool "ST-Ericsson DB8500 Voltage Domain Regulators"
depends on MFD_DB8500_PRCMU
+ depends on !UX500_PM_DOMAIN
select REGULATOR_DBX500_PRCMU
help
This driver supports the voltage domain regulators controlled by the
--
2.54.0
^ permalink raw reply related
* [PATCH 05/11] ARM: dts: ux500: Add power domains
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij, Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
Add the actual power domains to all the SoC peripherals.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 58 ++++++++++++++++++++++++++++++------
1 file changed, 49 insertions(+), 9 deletions(-)
diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
index d76a65da7011..a6fef302c994 100644
--- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
@@ -154,6 +154,7 @@ sram@40020000 {
reg = <0x40020000 0x40000>;
#address-cells = <1>;
#size-cells = <1>;
+ power-domains = <&pm_domains DOMAIN_ESRAM_12>;
ranges = <0 0x40020000 0x40000>;
};
sram@40060000 {
@@ -162,6 +163,7 @@ sram@40060000 {
reg = <0x40060000 0x40000>;
#address-cells = <1>;
#size-cells = <1>;
+ power-domains = <&pm_domains DOMAIN_ESRAM_34>;
ranges = <0 0x40060000 0x40000>;
lcla: sram@20000 {
@@ -181,7 +183,7 @@ lcla: sram@20000 {
ptm@801ae000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0x801ae000 0x1000>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "apb_pclk", "atclk";
cpu = <&CPU0>;
@@ -197,7 +199,7 @@ ptm0_out_port: endpoint {
ptm@801af000 {
compatible = "arm,coresight-etm3x", "arm,primecell";
reg = <0x801af000 0x1000>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "apb_pclk", "atclk";
cpu = <&CPU1>;
@@ -213,7 +215,7 @@ ptm1_out_port: endpoint {
funnel@801a6000 {
compatible = "arm,coresight-dynamic-funnel", "arm,primecell";
reg = <0x801a6000 0x1000>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "apb_pclk", "atclk";
out-ports {
@@ -249,6 +251,7 @@ replicator {
compatible = "arm,coresight-static-replicator";
clocks = <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "atclk";
+ power-domains = <&pm_domains DOMAIN_VARM>;
out-ports {
#address-cells = <1>;
@@ -280,7 +283,7 @@ replicator_in_port0: endpoint {
tpiu@80190000 {
compatible = "arm,coresight-tpiu", "arm,primecell";
reg = <0x80190000 0x1000>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "apb_pclk", "atclk";
in-ports {
@@ -295,7 +298,7 @@ tpiu_in_port: endpoint {
etb@801a4000 {
compatible = "arm,coresight-etb10", "arm,primecell";
reg = <0x801a4000 0x1000>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&prcmu_clk PRCMU_APETRACECLK>, <&prcmu_clk PRCMU_APEATCLK>;
clock-names = "apb_pclk", "atclk";
in-ports {
@@ -314,11 +317,13 @@ intc: interrupt-controller@a0411000 {
interrupt-controller;
reg = <0xa0411000 0x1000>,
<0xa0410100 0x100>;
+ power-domains = <&pm_domains DOMAIN_VARM>;
};
scu@a0410000 {
compatible = "arm,cortex-a9-scu";
reg = <0xa0410000 0x100>;
+ power-domains = <&pm_domains DOMAIN_VARM>;
};
/*
@@ -326,6 +331,7 @@ scu@a0410000 {
* and various things like spin tables
*/
backupram@80150000 {
+ /* This memory is in the VSAFE (always on) power domain */
compatible = "ste,dbx500-backupram";
reg = <0x80150000 0x2000>;
};
@@ -334,6 +340,7 @@ L2: cache-controller {
compatible = "arm,pl310-cache";
reg = <0xa0412000 0x1000>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pm_domains DOMAIN_VARM>;
cache-unified;
cache-level = <2>;
};
@@ -341,6 +348,7 @@ L2: cache-controller {
pmu {
compatible = "arm,cortex-a9-pmu";
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pm_domains DOMAIN_VARM>;
};
pm_domains: power-controller {
@@ -357,6 +365,7 @@ clocks {
reg = <0x8012f000 0x1000>, <0x8011f000 0x1000>,
<0x8000f000 0x1000>, <0xa03ff000 0x1000>,
<0xa03cf000 0x1000>;
+ power-domains = <&pm_domains DOMAIN_VPLL>; /* CHECKME: correct domain? */
prcmu_clk: prcmu-clock {
#clock-cells = <1>;
@@ -393,7 +402,7 @@ mtu@a03c6000 {
compatible = "st,nomadik-mtu";
reg = <0xa03c6000 0x1000>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
-
+ power-domains = <&pm_domains DOMAIN_VAPE>;
clocks = <&prcmu_clk PRCMU_TIMCLK>, <&prcc_pclk 6 6>;
clock-names = "timclk", "apb_pclk";
};
@@ -402,7 +411,7 @@ timer@a0410600 {
compatible = "arm,cortex-a9-twd-timer";
reg = <0xa0410600 0x20>;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_HIGH)>;
-
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&smp_twd_clk>;
};
@@ -410,14 +419,15 @@ watchdog@a0410620 {
compatible = "arm,cortex-a9-twd-wdt";
reg = <0xa0410620 0x20>;
interrupts = <GIC_PPI 14 (GIC_CPU_MASK_RAW(3) | IRQ_TYPE_LEVEL_HIGH)>;
+ power-domains = <&pm_domains DOMAIN_VARM>;
clocks = <&smp_twd_clk>;
};
rtc@80154000 {
+ /* This peripheral is in the VSAFE (always on) power domain */
compatible = "arm,pl031", "arm,primecell";
reg = <0x80154000 0x1000>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&rtc_clk>;
clock-names = "apb_pclk";
};
@@ -435,6 +445,7 @@ gpio0: gpio@8012e000 {
gpio-bank = <0>;
gpio-ranges = <&pinctrl 0 0 32>;
clocks = <&prcc_pclk 1 9>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio1: gpio@8012e080 {
@@ -450,6 +461,7 @@ gpio1: gpio@8012e080 {
gpio-bank = <1>;
gpio-ranges = <&pinctrl 0 32 5>;
clocks = <&prcc_pclk 1 9>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio2: gpio@8000e000 {
@@ -465,6 +477,7 @@ gpio2: gpio@8000e000 {
gpio-bank = <2>;
gpio-ranges = <&pinctrl 0 64 32>;
clocks = <&prcc_pclk 3 8>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio3: gpio@8000e080 {
@@ -480,6 +493,7 @@ gpio3: gpio@8000e080 {
gpio-bank = <3>;
gpio-ranges = <&pinctrl 0 96 2>;
clocks = <&prcc_pclk 3 8>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio4: gpio@8000e100 {
@@ -495,6 +509,7 @@ gpio4: gpio@8000e100 {
gpio-bank = <4>;
gpio-ranges = <&pinctrl 0 128 32>;
clocks = <&prcc_pclk 3 8>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio5: gpio@8000e180 {
@@ -510,6 +525,7 @@ gpio5: gpio@8000e180 {
gpio-bank = <5>;
gpio-ranges = <&pinctrl 0 160 12>;
clocks = <&prcc_pclk 3 8>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio6: gpio@8011e000 {
@@ -525,6 +541,7 @@ gpio6: gpio@8011e000 {
gpio-bank = <6>;
gpio-ranges = <&pinctrl 0 192 32>;
clocks = <&prcc_pclk 2 11>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio7: gpio@8011e080 {
@@ -540,6 +557,7 @@ gpio7: gpio@8011e080 {
gpio-bank = <7>;
gpio-ranges = <&pinctrl 0 224 7>;
clocks = <&prcc_pclk 2 11>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
gpio8: gpio@a03fe000 {
@@ -555,6 +573,7 @@ gpio8: gpio@a03fe000 {
gpio-bank = <8>;
gpio-ranges = <&pinctrl 0 256 12>;
clocks = <&prcc_pclk 5 1>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
pinctrl: pinctrl {
@@ -570,6 +589,7 @@ usb_per5@a03e0000 {
reg = <0xa03e0000 0x10000>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "mc";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
dr_mode = "otg";
@@ -613,9 +633,11 @@ dma: dma-controller@801C0000 {
memcpy-channels = <56 57 58 59 60>;
clocks = <&prcmu_clk PRCMU_DMACLK>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
prcmu: prcmu@80157000 {
+ /* This peripheral is in the VSAFE (always on) power domain */
compatible = "stericsson,db8500-prcmu", "syscon";
reg = <0x80157000 0x2000>, <0x801b0000 0x8000>, <0x801b8000 0x1000>;
reg-names = "prcmu", "prcmu-tcpm", "prcmu-tcdm";
@@ -641,6 +663,10 @@ thermal: thermal@801573c0 {
#thermal-sensor-cells = <0>;
};
+ /*
+ * TODO: Delete these bogus regulators and replace with power
+ * domains.
+ */
db8500-prcmu-regulators {
compatible = "stericsson,db8500-prcmu-regulator";
@@ -932,6 +958,7 @@ serial0: serial@80120000 {
clocks = <&prcc_kclk 1 0>, <&prcc_pclk 1 0>;
clock-names = "uart", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
resets = <&prcc_reset DB8500_PRCC_1 DB8500_PRCC_1_RESET_UART0>;
status = "disabled";
@@ -948,6 +975,7 @@ serial1: serial@80121000 {
clocks = <&prcc_kclk 1 1>, <&prcc_pclk 1 1>;
clock-names = "uart", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
resets = <&prcc_reset DB8500_PRCC_1 DB8500_PRCC_1_RESET_UART1>;
status = "disabled";
@@ -964,6 +992,7 @@ serial2: serial@80007000 {
clocks = <&prcc_kclk 3 6>, <&prcc_pclk 3 6>;
clock-names = "uart", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
resets = <&prcc_reset DB8500_PRCC_3 DB8500_PRCC_3_RESET_UART2>;
status = "disabled";
@@ -1080,7 +1109,9 @@ msp0: msp@80123000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80123000 0x1000>;
interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ /* TODO: delete and replace with power-domain handling */
v-ape-supply = <&db8500_vape_reg>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 31 0 0x12>, /* Logical - DevToMem - HighPrio */
<&dma 31 0 0x10>; /* Logical - MemToDev - HighPrio */
@@ -1097,7 +1128,9 @@ msp1: msp@80124000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80124000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ /* TODO: delete and replace with power-domain handling */
v-ape-supply = <&db8500_vape_reg>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v1 */
dmas = <&dma 30 0 0x10>; /* Logical - MemToDev - HighPrio */
@@ -1115,7 +1148,9 @@ msp2: msp@80117000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80117000 0x1000>;
interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ /* TODO: delete and replace with power-domain handling */
v-ape-supply = <&db8500_vape_reg>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
dmas = <&dma 14 0 0x12>, /* Logical - DevToMem - HighPrio */
<&dma 14 1 0x19>; /* Physical Chan 1 - MemToDev
@@ -1133,7 +1168,9 @@ msp3: msp@80125000 {
compatible = "stericsson,ux500-msp-i2s";
reg = <0x80125000 0x1000>;
interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+ /* TODO: delete and replace with power-domain handling */
v-ape-supply = <&db8500_vape_reg>;
+ power-domains = <&pm_domains DOMAIN_VAPE>;
/* This DMA channel only exist on DB8500 v2 */
dmas = <&dma 30 0 0x12>; /* Logical - DevToMem - HighPrio */
@@ -1175,14 +1212,17 @@ gpu@a0300000 {
"combined";
clocks = <&prcmu_clk PRCMU_ACLK>, <&prcmu_clk PRCMU_SGACLK>;
clock-names = "bus", "core";
+ power-domains = <&pm_domains DOMAIN_SGA>;
+ /* TODO: delete and replace with power-domain handling */
mali-supply = <&db8500_sga_reg>;
- power-domains = <&pm_domains DOMAIN_VAPE>;
};
mcde@a0350000 {
compatible = "ste,mcde";
reg = <0xa0350000 0x1000>;
interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>;
+ power-domains = <&pm_domains DOMAIN_B2R2_MCDE>;
+ /* TODO: delete and replace with power-domain handling */
epod-supply = <&db8500_b2r2_mcde_reg>;
clocks = <&prcmu_clk PRCMU_MCDECLK>, /* Main MCDE clock */
<&prcmu_clk PRCMU_LCDCLK>, /* LCD clock */
--
2.54.0
^ permalink raw reply related
* [PATCH 04/11] ARM: dts: ux500: Rename power domains node
From: Linus Walleij @ 2026-06-18 5:00 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Ulf Hansson,
Mark Brown, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Vinod Koul, Frank Li, Lee Jones
Cc: linux-arm-kernel, devicetree, linux-pm, dri-devel, dmaengine,
Linus Walleij, Linus Walleij
In-Reply-To: <20260618-ux500-power-domains-v7-1-v1-0-eb5e50b1a588@kernel.org>
This matches the naming used in the binding document
Documentation/devicetree/bindings/power/power-domain.yaml
It's most logical to call it a power controller.
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
arch/arm/boot/dts/st/ste-dbx5x0.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
index 0f87abeddc33..d76a65da7011 100644
--- a/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/st/ste-dbx5x0.dtsi
@@ -343,7 +343,7 @@ pmu {
interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
};
- pm_domains: pm_domains0 {
+ pm_domains: power-controller {
compatible = "stericsson,ux500-pm-domains";
#power-domain-cells = <1>;
};
--
2.54.0
^ 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