* Re: [PATCH net] net: airoha: Fix memory leak in airoha_qdma_rx_process()
From: Simon Horman @ 2026-04-03 15:59 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-arm-kernel, linux-mediatek, netdev
In-Reply-To: <20260402-airoha_qdma_rx_process-mem-leak-fix-v1-1-b5706f402d3c@kernel.org>
On Thu, Apr 02, 2026 at 02:57:10PM +0200, Lorenzo Bianconi wrote:
> If an error occurs on the subsequents buffers belonging to the
> non-linear part of the skb (e.g. due to an error in the payload length
> reported by the NIC or if we consumed all the available fragments for
> the skb), the page_pool fragment will not be linked to the skb so it will
> not return to the pool in the airoha_qdma_rx_process() error path. Fix the
> memory leak partially reverting commit 'd6d2b0e1538d ("net: airoha: Fix
> page recycling in airoha_qdma_rx_process()")' and always running
> page_pool_put_full_page routine in the airoha_qdma_rx_process() error
> path.
>
> Fixes: d6d2b0e1538d ("net: airoha: Fix page recycling in airoha_qdma_rx_process()")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
Reviewed-by: Simon Horman <horms@kernel.org>
^ permalink raw reply
* Re: [PATCH v20 06/10] power: reset: Add psci-reboot-mode driver
From: Lorenzo Pieralisi @ 2026-04-03 15:50 UTC (permalink / raw)
To: Shivendra Pratap
Cc: Arnd Bergmann, Bjorn Andersson, Sebastian Reichel, Rob Herring,
Souvik Chakravarty, Krzysztof Kozlowski, Andy Yan,
Matthias Brugger, Mark Rutland, Conor Dooley, Konrad Dybcio,
John Stultz, Moritz Fischer, Bartosz Golaszewski, Sudeep Holla,
Florian Fainelli, Krzysztof Kozlowski, Dmitry Baryshkov,
Mukesh Ojha, Andre Draszik, Kathiravan Thirumoorthy, linux-pm,
linux-kernel, linux-arm-kernel, linux-arm-msm, devicetree,
Srinivas Kandagatla
In-Reply-To: <da6f4566-a719-409b-80a9-40ca89e3e721@oss.qualcomm.com>
On Fri, Apr 03, 2026 at 12:05:27AM +0530, Shivendra Pratap wrote:
>
>
> On 01-04-2026 20:07, Lorenzo Pieralisi wrote:
> > On Tue, Mar 31, 2026 at 11:30:09PM +0530, Shivendra Pratap wrote:
> > >
> > >
> > > On 27-03-2026 19:25, Lorenzo Pieralisi wrote:
> > > > On Wed, Mar 04, 2026 at 11:33:06PM +0530, Shivendra Pratap wrote:
> > > > > PSCI supports different types of resets like COLD reset, ARCH WARM
>
> [snip..]
>
> > > > > + * Predefined reboot-modes are defined as per the values
> > > > > + * of enum reboot_mode defined in the kernel: reboot.c.
> > > > > + */
> > > > > +static struct mode_info psci_resets[] = {
> > > > > + { .mode = "warm", .magic = REBOOT_WARM},
> > > > > + { .mode = "soft", .magic = REBOOT_SOFT},
> > > > > + { .mode = "cold", .magic = REBOOT_COLD},
> >
> > These strings match the command userspace issue right ? I think that we
> > should make them match the corresponding PSCI reset types, the list above
> > maps command to reboot_mode values and those can belong to any reboot
> > mode driver to be honest they don't make much sense in a PSCI reboot
> > mode driver only.
> >
> > It is a question for everyone here: would it make sense to make these
> > predefined resets a set of strings, eg:
> >
> > psci-system-reset
> > psci-system-reset2-arch-warm-reset
> >
> > and then vendor resets:
> >
> > psci-system-reset2-vendor-reset
>
> Can you share bit more details on this? We are already defining the string
> from userspace in the struct - eg: ".mode = "warm".
"warm","soft","cold" are not strictly speaking PSCI concepts and mean nothing
well defined to user space and even if they did, they would not belong in
the PSCI reboot mode driver but in generic code.
Spelling out what a reset is might help instead, again, this is just my
opinion, I don't know how the semantics of resets have been handled thus
far.
If userspace issues a LINUX_REBOOT_CMD_RESTART2 with arg, say,
"psci-system-reset2-arch-warm-reset" it is pretty clear what it wants
to do in PSCI.
Again, it is a suggestion, comments welcome.
> yes we can move away from enum reboot_mode and use custom psci defines one -
> Ack.
>
> >
>
> [snip ..]
>
> > > > > +
> > > > > +/*
> > > > > + * arg1 is reset_type(Low 32 bit of magic).
> > > > > + * arg2 is cookie(High 32 bit of magic).
> > > > > + * If reset_type is 0, cookie will be used to decide the reset command.
> > > > > + */
> > > > > +static int psci_reboot_mode_write(struct reboot_mode_driver *reboot, u64 magic)
> > > > > +{
> > > > > + u32 reset_type = REBOOT_MODE_ARG1(magic);
> > > > > + u32 cookie = REBOOT_MODE_ARG2(magic);
> > > > > +
> > > > > + if (reset_type == 0) {
> > > > > + if (cookie == REBOOT_WARM || cookie == REBOOT_SOFT)
> > > > > + psci_set_reset_cmd(true, 0, 0);
> > > > > + else
> > > > > + psci_set_reset_cmd(false, 0, 0);
> > > > > + } else {
> > > > > + psci_set_reset_cmd(true, reset_type, cookie);
> > > > > + }
> > > >
> > > > I don't think that psci_set_reset_cmd() has the right interface (and this
> > > > nested if is too complicated for my taste). All we need to pass is reset-type
> > > > and cookie (and if the reset is one of the predefined ones, reset-type is 0
> > > > and cookie is the REBOOT_* cookie).
> > > >
> > > > Then the PSCI firmware driver will take the action according to what
> > > > resets are available.
> > > >
> > > > How does it sound ?
> > >
> > > So we mean these checks will move to the psci driver? Sorry for re-iterating
> > > the question.
> >
> > Given what I say above, I believe that something we can do is mapping the magic
> > to an enum like:
> >
> > PSCI_SYSTEM_RESET
> > PSCI_SYSTEM_RESET2_ARCH_SYSTEM_WARM_RESET
> > PSCI_SYSTEM_RESET2_VENDOR_RESET
> >
> > and can add a probe function into PSCI driver similar to psci_has_osi_support() but
> > to probe for SYSTEM_RESET2 and initialize the predefined strings accordingly,
> > depending on its presence.
>
> Not able to get it cleanly.
>
> 1. Will move away from reboot_mode enum for pre-defined modes and define new
> enum defining these modes- fine.
> 2. get SYSTEM_RESET2 is supported from psci exported function -- fine, but
> how we use it here now, as we do not want to send the reset_cmd from
> psci_set_reset_cmd now?
You do keep psci_set_reset_cmd() but all it is used for is setting a struct
shared with the PSCI driver where you initialize the enum above, possibly
with a cookie if it is a vendor reset.
> 3. For pre-defined modes, warm/soft or cold - reset_type and cookie, both
> are zero, sys_reset2 or sys_reset2 decides the ARCH reset vs cold reset.
> 4. For vendor-rest , we use sys_reset2 with reset_type and cookie.
Yes.
> All above is done in reboot_notifier call at psci-reboot-mode.
> --
>
> Now in the final restart_notifier->psci_sys_reset --
>
> If panic is in progress, we do not use any of the cmd based reset params and
> go with the legacy reset. So we need to preserve the values that were set
> from psci-reboot-mode.
>
> Did not understand the proposed suggestion in above usecase. Need more input
> on this.
I explained above. The reboot mode driver sets the command to carry out
depending on the string coming from user space and whether PSCI supports
SYSTEM_RESET2 or not.
> --
>
> One other option is to have a restart_notifier in psci-reboot-mode, with
> lesser priority than psci_sys_rest and then handle all the case including
> panic and sys_reset2.
No.
Thanks,
Lorenzo
^ permalink raw reply
* Re: [PATCH v6 09/10] clk: realtek: Add RTD1625-ISO clock controller driver
From: Brian Masney @ 2026-04-03 15:29 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-10-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:56PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the ISO (Isolation) domain clock controller on the Realtek
> RTD1625 SoC. This controller manages clocks in the always-on power domain,
> ensuring essential services remain functional even when the main system
> power is gated.
>
> Since the reset controller shares the same register space with the ISO
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the ISO domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc arrays from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-iso.c | 144 ++++++++++++++++++++++
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-iso.c | 96 +++++++++++++++
> 4 files changed, 242 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-iso.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-iso.c
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index c992f97dfbc7..1680435e1e0f 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -10,3 +10,4 @@ clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-iso.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-iso.c b/drivers/clk/realtek/clk-rtd1625-iso.c
> new file mode 100644
> index 000000000000..027a131363f9
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-iso.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap-gate.h"
> +
> +#define RTD1625_ISO_CLK_MAX 19
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_CLK_MAX 5
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p4, 0, 0x4, 0, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_p3, 0, 0x4, 1, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_cec0, "clk_en_misc", 0, 0x4, 2, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbusrx_sys, 0, 0x4, 3, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbustx_sys, 0, 0x4, 4, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_sys, 0, 0x4, 5, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_cbus_osc, 0, 0x4, 6, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c0, 0, 0x4, 9, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_i2c1, 0, 0x4, 10, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_250m, 0, 0x4, 11, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_etn_sys, 0, 0x4, 12, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_drd, 0, 0x4, 13, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_host, 0, 0x4, 14, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb_u3_host, 0, 0x4, 15, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_usb, 0, 0x4, 16, 0);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vtc, 0, 0x4, 17, 0);
> +static CLK_REGMAP_GATE(clk_en_misc_vfd, "clk_en_misc", 0, 0x4, 18, 0);
> +
> +static struct clk_regmap *rtd1625_clk_regmap_list[] = {
static const? Same for some others below as well.
> + &clk_en_usb_p4.clkr,
> + &clk_en_usb_p3.clkr,
> + &clk_en_misc_cec0.clkr,
> + &clk_en_cbusrx_sys.clkr,
> + &clk_en_cbustx_sys.clkr,
> + &clk_en_cbus_sys.clkr,
> + &clk_en_cbus_osc.clkr,
> + &clk_en_i2c0.clkr,
> + &clk_en_i2c1.clkr,
> + &clk_en_etn_250m.clkr,
> + &clk_en_etn_sys.clkr,
> + &clk_en_usb_drd.clkr,
> + &clk_en_usb_host.clkr,
> + &clk_en_usb_u3_host.clkr,
> + &clk_en_usb.clkr,
> + &clk_en_vtc.clkr,
> + &clk_en_misc_vfd.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_clk_data = {
> + .num = RTD1625_ISO_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_CLK_EN_USB_P4] = &__clk_regmap_gate_hw(&clk_en_usb_p4),
> + [RTD1625_ISO_CLK_EN_USB_P3] = &__clk_regmap_gate_hw(&clk_en_usb_p3),
> + [RTD1625_ISO_CLK_EN_MISC_CEC0] = &__clk_regmap_gate_hw(&clk_en_misc_cec0),
> + [RTD1625_ISO_CLK_EN_CBUSRX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbusrx_sys),
> + [RTD1625_ISO_CLK_EN_CBUSTX_SYS] = &__clk_regmap_gate_hw(&clk_en_cbustx_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_SYS] = &__clk_regmap_gate_hw(&clk_en_cbus_sys),
> + [RTD1625_ISO_CLK_EN_CBUS_OSC] = &__clk_regmap_gate_hw(&clk_en_cbus_osc),
> + [RTD1625_ISO_CLK_EN_I2C0] = &__clk_regmap_gate_hw(&clk_en_i2c0),
> + [RTD1625_ISO_CLK_EN_I2C1] = &__clk_regmap_gate_hw(&clk_en_i2c1),
> + [RTD1625_ISO_CLK_EN_ETN_250M] = &__clk_regmap_gate_hw(&clk_en_etn_250m),
> + [RTD1625_ISO_CLK_EN_ETN_SYS] = &__clk_regmap_gate_hw(&clk_en_etn_sys),
> + [RTD1625_ISO_CLK_EN_USB_DRD] = &__clk_regmap_gate_hw(&clk_en_usb_drd),
> + [RTD1625_ISO_CLK_EN_USB_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_host),
> + [RTD1625_ISO_CLK_EN_USB_U3_HOST] = &__clk_regmap_gate_hw(&clk_en_usb_u3_host),
> + [RTD1625_ISO_CLK_EN_USB] = &__clk_regmap_gate_hw(&clk_en_usb),
> + [RTD1625_ISO_CLK_EN_VTC] = &__clk_regmap_gate_hw(&clk_en_vtc),
> + [RTD1625_ISO_CLK_EN_MISC_VFD] = &__clk_regmap_gate_hw(&clk_en_misc_vfd),
> + [RTD1625_ISO_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_desc = {
> + .clk_data = &rtd1625_iso_clk_data,
> + .clks = rtd1625_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_clk_regmap_list),
> +};
> +
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_irda, 0, 0x4, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur10, 0, 0x4, 8, 1);
> +
> +static struct clk_regmap *rtd1625_iso_s_clk_regmap_list[] = {
> + &clk_en_irda.clkr,
> + &clk_en_ur10.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_iso_s_clk_data = {
> + .num = RTD1625_ISO_S_CLK_MAX,
> + .hws = {
> + [RTD1625_ISO_S_CLK_EN_IRDA] = &__clk_regmap_gate_hw(&clk_en_irda),
> + [RTD1625_ISO_S_CLK_EN_UR10] = &__clk_regmap_gate_hw(&clk_en_ur10),
> + [RTD1625_ISO_S_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_iso_s_desc = {
> + .clk_data = &rtd1625_iso_s_clk_data,
> + .clks = rtd1625_iso_s_clk_regmap_list,
> + .num_clks = ARRAY_SIZE(rtd1625_iso_s_clk_regmap_list),
> +};
> +
> +static int rtd1625_iso_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> + return rtk_clk_probe(pdev, desc, "iso_rst");
Add newline before return.
> +}
> +
> +static const struct of_device_id rtd1625_iso_match[] = {
> + {.compatible = "realtek,rtd1625-iso-clk", .data = &rtd1625_iso_desc},
> + {.compatible = "realtek,rtd1625-iso-s-clk", .data = &rtd1625_iso_s_desc},
> + { /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_probe,
> + .driver = {
> + .name = "rtk-rtd1625-iso-clk",
> + .of_match_table = rtd1625_iso_match,
> + },
> +};
> +
> +static int __init rtd1625_iso_init(void)
> +{
> + return platform_driver_register(&rtd1625_iso_driver);
> +}
> +subsys_initcall(rtd1625_iso_init);
> +
> +MODULE_DESCRIPTION("Realtek RTD1625 ISO Controller Driver");
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index 8ca1fa939f10..26b3ddc75ada 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o reset-rtd1625-iso.o
Some comment as the previous patch. CONFIG_RESET_RTK_COMMON is expected
to be common, right? If so, a SoC-specific driver shouldn't be listed
here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-iso.c b/drivers/reset/realtek/reset-rtd1625-iso.c
> new file mode 100644
> index 000000000000..f2a0478382ae
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-iso.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/of.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_ISO_RSTN_MAX 29
> +#define RTD1625_ISO_S_RSTN_MAX 5
> +
> +static struct rtk_reset_desc rtd1625_iso_reset_descs[] = {
static const?
> + [RTD1625_ISO_RSTN_VFD] = { .ofs = 0x88, .bit = 0 },
> + [RTD1625_ISO_RSTN_CEC0] = { .ofs = 0x88, .bit = 2 },
> + [RTD1625_ISO_RSTN_CEC1] = { .ofs = 0x88, .bit = 3 },
> + [RTD1625_ISO_RSTN_CBUSTX] = { .ofs = 0x88, .bit = 5 },
> + [RTD1625_ISO_RSTN_CBUSRX] = { .ofs = 0x88, .bit = 6 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_XTAL_POW] = { .ofs = 0x88, .bit = 7 },
> + [RTD1625_ISO_RSTN_UR0] = { .ofs = 0x88, .bit = 8 },
> + [RTD1625_ISO_RSTN_GMAC] = { .ofs = 0x88, .bit = 9 },
> + [RTD1625_ISO_RSTN_GPHY] = { .ofs = 0x88, .bit = 10 },
> + [RTD1625_ISO_RSTN_I2C_0] = { .ofs = 0x88, .bit = 11 },
> + [RTD1625_ISO_RSTN_I2C_1] = { .ofs = 0x88, .bit = 12 },
> + [RTD1625_ISO_RSTN_CBUS] = { .ofs = 0x88, .bit = 13 },
> + [RTD1625_ISO_RSTN_USB_DRD] = { .ofs = 0x88, .bit = 14 },
> + [RTD1625_ISO_RSTN_USB_HOST] = { .ofs = 0x88, .bit = 15 },
> + [RTD1625_ISO_RSTN_USB_PHY_0] = { .ofs = 0x88, .bit = 16 },
> + [RTD1625_ISO_RSTN_USB_PHY_1] = { .ofs = 0x88, .bit = 17 },
> + [RTD1625_ISO_RSTN_USB_PHY_2] = { .ofs = 0x88, .bit = 18 },
> + [RTD1625_ISO_RSTN_USB] = { .ofs = 0x88, .bit = 19 },
> + [RTD1625_ISO_RSTN_TYPE_C] = { .ofs = 0x88, .bit = 20 },
> + [RTD1625_ISO_RSTN_USB_U3_HOST] = { .ofs = 0x88, .bit = 21 },
> + [RTD1625_ISO_RSTN_USB3_PHY0_POW] = { .ofs = 0x88, .bit = 22 },
> + [RTD1625_ISO_RSTN_USB3_P0_MDIO] = { .ofs = 0x88, .bit = 23 },
> + [RTD1625_ISO_RSTN_USB3_PHY1_POW] = { .ofs = 0x88, .bit = 24 },
> + [RTD1625_ISO_RSTN_USB3_P1_MDIO] = { .ofs = 0x88, .bit = 25 },
> + [RTD1625_ISO_RSTN_VTC] = { .ofs = 0x88, .bit = 26 },
> + [RTD1625_ISO_RSTN_USB3_PHY2_POW] = { .ofs = 0x88, .bit = 27 },
> + [RTD1625_ISO_RSTN_USB3_P2_MDIO] = { .ofs = 0x88, .bit = 28 },
> + [RTD1625_ISO_RSTN_USB_PHY_3] = { .ofs = 0x88, .bit = 29 },
> + [RTD1625_ISO_RSTN_USB_PHY_4] = { .ofs = 0x88, .bit = 30 },
> +};
> +
> +static struct rtk_reset_desc rtd1625_iso_s_reset_descs[] = {
> + [RTD1625_ISO_S_RSTN_ISOM_MIS] = { .ofs = 0x310, .bit = 0, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_GPIOM] = { .ofs = 0x310, .bit = 2, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_TIMER7] = { .ofs = 0x310, .bit = 4, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_IRDA] = { .ofs = 0x310, .bit = 6, .write_en = 1 },
> + [RTD1625_ISO_S_RSTN_UR10] = { .ofs = 0x310, .bit = 8, .write_en = 1 },
> +};
> +
> +static int rtd1625_iso_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct device *parent = dev->parent;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + if (of_device_is_compatible(parent->of_node, "realtek,rtd1625-iso-s-clk")) {
> + data->descs = rtd1625_iso_s_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_S_RSTN_MAX;
> + } else {
> + data->descs = rtd1625_iso_reset_descs;
> + data->rcdev.nr_resets = RTD1625_ISO_RSTN_MAX;
> + }
> + return rtk_reset_controller_add(dev, data);
Newline before return.
> +}
> +
> +static const struct auxiliary_device_id rtd1625_iso_reset_ids[] = {
> + {
> + .name = "clk_rtk.iso_rst",
> + },
I would combine the { .name } all on one line.
Brian
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_iso_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_iso_driver = {
> + .probe = rtd1625_iso_reset_probe,
> + .id_table = rtd1625_iso_reset_ids,
> + .driver = {
> + .name = "rtd1625-iso-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_iso_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v6 08/10] clk: realtek: Add RTD1625-CRT clock controller driver
From: Brian Masney @ 2026-04-03 15:24 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-9-eleanor.lin@realtek.com>
Hi Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:55PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add support for the CRT (Clock, Reset, and Test) domain clock controller
> on the Realtek RTD1625 SoC. This driver provides essential clock sources
> (including PLLs), gating, and multiplexing functionalities for the
> platform's peripherals.
>
> Since the reset controller shares the same register space with the CRT
> clock controller, it is instantiated as an auxiliary device by the core
> clock driver. This patch also includes the corresponding auxiliary reset
> driver to handle the CRT domain resets.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move struct rtk_reset_desc array from the clock driver to the dedicated reset driver.
> - Implement and register a dedicated reset auxiliary driver.
> ---
> drivers/clk/realtek/Kconfig | 13 +
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-rtd1625-crt.c | 779 ++++++++++++++++++++++
> drivers/reset/realtek/Kconfig | 2 +
> drivers/reset/realtek/Makefile | 2 +-
> drivers/reset/realtek/reset-rtd1625-crt.c | 186 ++++++
> 6 files changed, 982 insertions(+), 1 deletion(-)
> create mode 100644 drivers/clk/realtek/clk-rtd1625-crt.c
> create mode 100644 drivers/reset/realtek/reset-rtd1625-crt.c
>
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index b31a31e57b3a..6a213cfd66bc 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -28,4 +28,17 @@ config RTK_CLK_COMMON
> config RTK_CLK_PLL_MMC
> bool
>
> +config COMMON_CLK_RTD1625
> + tristate "RTD1625 Clock Controller"
> + select RTK_CLK_COMMON
> + select RTK_CLK_PLL_MMC
> + help
> + Support for the clock controller on Realtek RTD1625 SoCs.
> +
> + This driver provides clock sources, gating, multiplexing, and
> + reset control for peripherals on the RTD1625 platform.
> +
> + Say Y here if your system is based on the RTD1625 and you need
> + its peripheral devices to function.
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index fd7d777902c8..c992f97dfbc7 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -9,3 +9,4 @@ clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
>
> clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> +obj-$(CONFIG_COMMON_CLK_RTD1625) += clk-rtd1625-crt.o
> diff --git a/drivers/clk/realtek/clk-rtd1625-crt.c b/drivers/clk/realtek/clk-rtd1625-crt.c
> new file mode 100644
> index 000000000000..fcb8b08722c8
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-rtd1625-crt.c
> @@ -0,0 +1,779 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2022 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <dt-bindings/clock/realtek,rtd1625-clk.h>
> +#include <linux/array_size.h>
> +#include <linux/bits.h>
> +#include <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +#include "clk-regmap-gate.h"
> +#include "clk-regmap-mux.h"
> +
> +#define RTD1625_CRT_CLK_MAX 172
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +#define RTD1625_REG_PLL_ACPU1 0x10c
> +#define RTD1625_REG_PLL_ACPU2 0x110
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU0 0x5c0
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU1 0x5c4
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU2 0x5c8
> +#define RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2 0x5dc
> +
> +#define RTD1625_REG_PLL_VE1_1 0x114
> +#define RTD1625_REG_PLL_VE1_2 0x118
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_0 0x580
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_1 0x584
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_2 0x588
> +#define RTD1625_REG_PLL_SSC_DIG_VE1_DBG2 0x59c
> +
> +#define RTD1625_REG_PLL_GPU1 0x1c0
> +#define RTD1625_REG_PLL_GPU2 0x1c4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU0 0x5a0
> +#define RTD1625_REG_PLL_SSC_DIG_GPU1 0x5a4
> +#define RTD1625_REG_PLL_SSC_DIG_GPU2 0x5a8
> +#define RTD1625_REG_PLL_SSC_DIG_GPU_DBG2 0x5bc
> +
> +#define RTD1625_REG_PLL_NPU1 0x1c8
> +#define RTD1625_REG_PLL_NPU2 0x1cc
> +#define RTD1625_REG_PLL_SSC_DIG_NPU0 0x800
> +#define RTD1625_REG_PLL_SSC_DIG_NPU1 0x804
> +#define RTD1625_REG_PLL_SSC_DIG_NPU2 0x808
> +#define RTD1625_REG_PLL_SSC_DIG_NPU_DBG2 0x81c
> +
> +#define RTD1625_REG_PLL_VE2_1 0x1d0
> +#define RTD1625_REG_PLL_VE2_2 0x1d4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_0 0x5e0
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_1 0x5e4
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_2 0x5e8
> +#define RTD1625_REG_PLL_SSC_DIG_VE2_DBG2 0x5fc
> +
> +#define RTD1625_REG_PLL_HIFI1 0x1d8
> +#define RTD1625_REG_PLL_HIFI2 0x1dc
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI0 0x6e0
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI1 0x6e4
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI2 0x6e8
> +#define RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2 0x6fc
> +
> +#define RTD1625_REG_PLL_BUS1 0x524
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DDSA1 0x564
> +
> +#define RTD1625_REG_PLL_SSC_DIG_DCSB1 0x544
> +
> +static const char * const clk_gpu_parents[] = {"pll_gpu", "clk_sys"};
> +static CLK_REGMAP_MUX(clk_gpu, clk_gpu_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x28, 12, 0x1);
> +static const char * const clk_ve_parents[] = {"pll_vo", "clk_sysh", "pll_ve1", "pll_ve2"};
> +static CLK_REGMAP_MUX(clk_ve1, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 0, 0x3);
> +static CLK_REGMAP_MUX(clk_ve2, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 3, 0x3);
> +static CLK_REGMAP_MUX(clk_ve4, clk_ve_parents, CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
> + 0x4c, 6, 0x3);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_misc, CLK_IS_CRITICAL, 0x50, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie0, 0, 0x50, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gspi, 0, 0x50, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_iso_misc, 0, 0x50, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sds, 0, 0x50, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmi, 0, 0x50, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_gpu, "clk_gpu", CLK_SET_RATE_PARENT, 0x50, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_ve1, "clk_ve1", CLK_SET_RATE_PARENT, 0x50, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_ve2, "clk_ve2", CLK_SET_RATE_PARENT, 0x50, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_se, 0, 0x50, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_md, 0, 0x54, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tp, CLK_IS_CRITICAL, 0x54, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_rcic, 0, 0x54, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nf, 0, 0x54, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_emmc, 0, 0x54, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd, 0, 0x54, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio_ip, 0, 0x54, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_csi, 0, 0x54, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_emmc_ip, "pll_emmc", CLK_SET_RATE_PARENT, 0x54, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sdio, 0, 0x54, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sd_ip, 0, 0x54, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpb, 0, 0x54, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc1, "clk_en_misc", 0, 0x54, 30, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_3, "clk_en_misc", 0, 0x58, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_jpeg, 0, 0x58, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_acpu, "pll_acpu", CLK_SET_RATE_PARENT,
> + 0x58, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_sc0, "clk_en_misc", 0, 0x58, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmirx, 0, 0x58, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hse, CLK_IS_CRITICAL, 0x58, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_fan, 0, 0x5c, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sys, 0, 0x5c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_wrap_sysh, 0, 0x5c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_sata_mac_sysh, 0, 0x5c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_r2rdsc, 0, 0x5c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie1, 0, 0x5c, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_4, "clk_en_misc", 0, 0x5c, 20, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_5, "clk_en_misc", 0, 0x5c, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio, 0, 0x5c, 24, 1);
> +static CLK_REGMAP_GATE(clk_en_ve4, "clk_ve4", CLK_SET_RATE_PARENT,
> + 0x5c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edp, 0, 0x5c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tsio_trx, 0, 0x5c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_pcie2, 0, 0x8c, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_earc, 0, 0x8c, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lite, 0, 0x8c, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mipi_dsi, 0, 0x8c, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npupp, 0, 0x8c, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu, 0, 0x8c, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu0, 0, 0x8c, 14, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu1, 0, 0x8c, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_nsram, 0, 0x8c, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_hdmitop, 0, 0x8c, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu_iso_npu, 0, 0x8c, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_keyladder, 0, 0x8c, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp_klm, 0, 0x8c, 28, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ifcp, 0, 0x8c, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_genpw, 0, 0xb0, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_chip, 0, 0xb0, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_ip, 0, 0xb0, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdlm2m, 0, 0xb0, 6, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_mdl_xtal, 0, 0xb0, 8, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_test_mux, 0, 0xb0, 10, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dla, 0, 0xb0, 12, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_tpcw, 0, 0xb0, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_gpu_ts_src, 0, 0xb0, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_vi, 0, 0xb0, 22, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds1, 0, 0xb0, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lvds2, 0, 0xb0, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_aucpu, 0, 0xb0, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_ur1, "clk_en_ur_top", 0, 0x884, 0, 1);
> +static CLK_REGMAP_GATE(clk_en_ur2, "clk_en_ur_top", 0, 0x884, 2, 1);
> +static CLK_REGMAP_GATE(clk_en_ur3, "clk_en_ur_top", 0, 0x884, 4, 1);
> +static CLK_REGMAP_GATE(clk_en_ur4, "clk_en_ur_top", 0, 0x884, 6, 1);
> +static CLK_REGMAP_GATE(clk_en_ur5, "clk_en_ur_top", 0, 0x884, 8, 1);
> +static CLK_REGMAP_GATE(clk_en_ur6, "clk_en_ur_top", 0, 0x884, 10, 1);
> +static CLK_REGMAP_GATE(clk_en_ur7, "clk_en_ur_top", 0, 0x884, 12, 1);
> +static CLK_REGMAP_GATE(clk_en_ur8, "clk_en_ur_top", 0, 0x884, 14, 1);
> +static CLK_REGMAP_GATE(clk_en_ur9, "clk_en_ur_top", 0, 0x884, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_ur_top, CLK_IS_CRITICAL, 0x884, 18, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_7, "clk_en_misc", 0, 0x884, 28, 1);
> +static CLK_REGMAP_GATE(clk_en_misc_i2c_6, "clk_en_misc", 0, 0x884, 30, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi0, 0, 0x894, 0, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi1, 0, 0x894, 2, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_spi2, 0, 0x894, 4, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc0, 0, 0x894, 16, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_lsadc1, 0, 0x894, 18, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_isomis_dma, 0, 0x894, 20, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_dptx, 0, 0x894, 24, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_npu_mipi_csi, 0, 0x894, 26, 1);
> +static CLK_REGMAP_GATE_NO_PARENT(clk_en_edptx, 0, 0x894, 28, 1);
> +
> +#define FREQ_NF_MASK 0x7ffff
> +#define FREQ_NF(_r, _nf) {.rate = _r, .val = (_nf),}
> +
> +static const struct freq_table acpu_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ve_tbl[] = {
> + FREQ_NF(553500000, 0x12800),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(688500000, 0x17800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table bus_tbl[] = {
> + FREQ_NF(513000000, 0x11000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(553500000, 0x12800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table ddsa_tbl[] = {
> + FREQ_NF(432000000, 0xe000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table gpu_tbl[] = {
> + FREQ_NF(405000000, 0xd000),
> + FREQ_NF(540000000, 0x12000),
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_NF(850500000, 0x1d800),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table hifi_tbl[] = {
> + FREQ_NF(756000000, 0x1a000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct freq_table npu_tbl[] = {
> + FREQ_NF(661500000, 0x16800),
> + FREQ_NF(729000000, 0x19000),
> + FREQ_NF(810000000, 0x1c000),
> + FREQ_TABLE_END
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x5},
> + {RTD1625_REG_PLL_ACPU2, 0x7},
> + {RTD1625_REG_PLL_ACPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU2, 0x1e1f8e},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5, 200},
> + {RTD1625_REG_PLL_ACPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_ACPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_acpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_ACPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_acpu = {
static const?
> + .clkr.hw.init = CLK_HW_INIT("pll_acpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_acpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_acpu_seq_power_on),
> + .seq_power_off = pll_acpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_acpu_seq_power_off),
> + .seq_pre_set_freq = pll_acpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_acpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_acpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_acpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_ACPU1,
> + .freq_tbl = acpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_ACPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_ACPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x5},
> + {RTD1625_REG_PLL_VE1_2, 0x7},
> + {RTD1625_REG_PLL_VE1_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE1_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE1_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve1_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE1_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve1 = {
Same here about static const, plus some others below?
> + .clkr.hw.init = CLK_HW_INIT("pll_ve1", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve1_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve1_seq_power_on),
> + .seq_power_off = pll_ve1_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve1_seq_power_off),
> + .seq_pre_set_freq = pll_ve1_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve1_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve1_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve1_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE1_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE1_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE1_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static struct clk_pll pll_ddsa = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ddsa", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DDSA1,
> + .freq_tbl = ddsa_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static struct clk_pll pll_bus = {
> + .clkr.hw.init = CLK_HW_INIT("pll_bus", "osc27m", &rtk_clk_pll_ro_ops, CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_BUS1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sys, "clk_sys", "pll_bus", 2, 1, 0);
> +
> +static struct clk_pll pll_dcsb = {
> + .clkr.hw.init = CLK_HW_INIT("pll_dcsb", "osc27m", &rtk_clk_pll_ro_ops,
> + CLK_GET_RATE_NOCACHE),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_DCSB1,
> + .freq_tbl = bus_tbl,
> + .freq_mask = FREQ_NF_MASK,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_sysh, "clk_sysh", "pll_dcsb", 1, 1, 0);
> +
> +static const struct reg_sequence pll_gpu_seq_power_on[] = {
> + {RTD1625_REG_PLL_GPU2, 0x5},
> + {RTD1625_REG_PLL_GPU2, 0x7},
> + {RTD1625_REG_PLL_GPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5, 200},
> + {RTD1625_REG_PLL_GPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_power_off[] = {
> + {RTD1625_REG_PLL_GPU2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_gpu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_GPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_gpu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_gpu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_gpu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_gpu_seq_power_on),
> + .seq_power_off = pll_gpu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_gpu_seq_power_off),
> + .seq_pre_set_freq = pll_gpu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_gpu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_gpu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_gpu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_GPU1,
> + .freq_tbl = gpu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_GPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_GPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_on[] = {
> + {RTD1625_REG_PLL_NPU2, 0x5},
> + {RTD1625_REG_PLL_NPU2, 0x7},
> + {RTD1625_REG_PLL_NPU1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5, 200},
> + {RTD1625_REG_PLL_NPU2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_power_off[] = {
> + {RTD1625_REG_PLL_NPU2, 0x4},
> + {RTD1625_REG_PLL_NPU1, 0x54010},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_npu_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_NPU0, 0x5},
> +};
> +
> +static struct clk_pll pll_npu = {
> + .clkr.hw.init = CLK_HW_INIT("pll_npu", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_npu_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_npu_seq_power_on),
> + .seq_power_off = pll_npu_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_npu_seq_power_off),
> + .seq_pre_set_freq = pll_npu_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_npu_seq_pre_set_freq),
> + .seq_post_set_freq = pll_npu_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_npu_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_NPU1,
> + .freq_tbl = npu_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_NPU_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_NPU2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(clk_npu, "clk_npu", "pll_npu", 1, 1, CLK_SET_RATE_PARENT);
> +static CLK_FIXED_FACTOR(clk_npu_mipi_csi, "clk_npu_mipi_csi", "pll_npu", 1, 1,
> + CLK_SET_RATE_PARENT);
> +
> +static const struct reg_sequence pll_ve2_seq_power_on[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x5},
> + {RTD1625_REG_PLL_VE2_2, 0x7},
> + {RTD1625_REG_PLL_VE2_1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5, 200},
> + {RTD1625_REG_PLL_VE2_2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_power_off[] = {
> + {RTD1625_REG_PLL_VE2_2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_ve2_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_VE2_0, 0x5},
> +};
> +
> +static struct clk_pll pll_ve2 = {
> + .clkr.hw.init = CLK_HW_INIT("pll_ve2", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_ve2_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_ve2_seq_power_on),
> + .seq_power_off = pll_ve2_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_ve2_seq_power_off),
> + .seq_pre_set_freq = pll_ve2_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_ve2_seq_pre_set_freq),
> + .seq_post_set_freq = pll_ve2_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_ve2_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_VE2_1,
> + .freq_tbl = ve_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_VE2_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_VE2_2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_on[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x5},
> + {RTD1625_REG_PLL_HIFI2, 0x7},
> + {RTD1625_REG_PLL_HIFI1, 0x54000},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5, 200},
> + {RTD1625_REG_PLL_HIFI2, 0x3},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_power_off[] = {
> + {RTD1625_REG_PLL_HIFI2, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_pre_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x4},
> +};
> +
> +static const struct reg_sequence pll_hifi_seq_post_set_freq[] = {
> + {RTD1625_REG_PLL_SSC_DIG_HIFI0, 0x5},
> +};
> +
> +static struct clk_pll pll_hifi = {
> + .clkr.hw.init = CLK_HW_INIT("pll_hifi", "osc27m", &rtk_clk_pll_ops, CLK_GET_RATE_NOCACHE),
> + .seq_power_on = pll_hifi_seq_power_on,
> + .num_seq_power_on = ARRAY_SIZE(pll_hifi_seq_power_on),
> + .seq_power_off = pll_hifi_seq_power_off,
> + .num_seq_power_off = ARRAY_SIZE(pll_hifi_seq_power_off),
> + .seq_pre_set_freq = pll_hifi_seq_pre_set_freq,
> + .num_seq_pre_set_freq = ARRAY_SIZE(pll_hifi_seq_pre_set_freq),
> + .seq_post_set_freq = pll_hifi_seq_post_set_freq,
> + .num_seq_post_set_freq = ARRAY_SIZE(pll_hifi_seq_post_set_freq),
> + .freq_reg = RTD1625_REG_PLL_SSC_DIG_HIFI1,
> + .freq_tbl = hifi_tbl,
> + .freq_mask = FREQ_NF_MASK,
> + .freq_ready_reg = RTD1625_REG_PLL_SSC_DIG_HIFI_DBG2,
> + .freq_ready_mask = BIT(20),
> + .freq_ready_val = BIT(20),
> + .power_reg = RTD1625_REG_PLL_HIFI2,
> + .power_mask = 0x7,
> + .power_val_on = 0x3,
> +};
> +
> +static CLK_FIXED_FACTOR(pll_emmc_ref, "pll_emmc_ref", "osc27m", 1, 1, 0);
> +
> +static struct clk_pll_mmc pll_emmc = {
> + .pll_ofs = 0x1f0,
> + .ssc_dig_ofs = 0x6b0,
> + .clkr.hw.init = CLK_HW_INIT("pll_emmc", "pll_emmc_ref", &rtk_clk_pll_mmc_ops, 0),
> + .phase0_hw.init = CLK_HW_INIT("pll_emmc_vp0", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> + .phase1_hw.init = CLK_HW_INIT("pll_emmc_vp1", "pll_emmc", &rtk_clk_pll_mmc_phase_ops, 0),
> +};
> +
> +static struct clk_regmap *rtd1625_crt_regmap_clks[] = {
> + &clk_en_misc.clkr,
> + &clk_en_pcie0.clkr,
> + &clk_en_gspi.clkr,
> + &clk_en_iso_misc.clkr,
> + &clk_en_sds.clkr,
> + &clk_en_hdmi.clkr,
> + &clk_en_gpu.clkr,
> + &clk_en_ve1.clkr,
> + &clk_en_ve2.clkr,
> + &clk_en_se.clkr,
> + &clk_en_md.clkr,
> + &clk_en_tp.clkr,
> + &clk_en_rcic.clkr,
> + &clk_en_nf.clkr,
> + &clk_en_emmc.clkr,
> + &clk_en_sd.clkr,
> + &clk_en_sdio_ip.clkr,
> + &clk_en_mipi_csi.clkr,
> + &clk_en_emmc_ip.clkr,
> + &clk_en_sdio.clkr,
> + &clk_en_sd_ip.clkr,
> + &clk_en_tpb.clkr,
> + &clk_en_misc_sc1.clkr,
> + &clk_en_misc_i2c_3.clkr,
> + &clk_en_jpeg.clkr,
> + &clk_en_acpu.clkr,
> + &clk_en_misc_sc0.clkr,
> + &clk_en_hdmirx.clkr,
> + &clk_en_hse.clkr,
> + &clk_en_fan.clkr,
> + &clk_en_sata_wrap_sys.clkr,
> + &clk_en_sata_wrap_sysh.clkr,
> + &clk_en_sata_mac_sysh.clkr,
> + &clk_en_r2rdsc.clkr,
> + &clk_en_pcie1.clkr,
> + &clk_en_misc_i2c_4.clkr,
> + &clk_en_misc_i2c_5.clkr,
> + &clk_en_tsio.clkr,
> + &clk_en_ve4.clkr,
> + &clk_en_edp.clkr,
> + &clk_en_tsio_trx.clkr,
> + &clk_en_pcie2.clkr,
> + &clk_en_earc.clkr,
> + &clk_en_lite.clkr,
> + &clk_en_mipi_dsi.clkr,
> + &clk_en_npupp.clkr,
> + &clk_en_npu.clkr,
> + &clk_en_aucpu0.clkr,
> + &clk_en_aucpu1.clkr,
> + &clk_en_nsram.clkr,
> + &clk_en_hdmitop.clkr,
> + &clk_en_aucpu_iso_npu.clkr,
> + &clk_en_keyladder.clkr,
> + &clk_en_ifcp_klm.clkr,
> + &clk_en_ifcp.clkr,
> + &clk_en_mdl_genpw.clkr,
> + &clk_en_mdl_chip.clkr,
> + &clk_en_mdl_ip.clkr,
> + &clk_en_mdlm2m.clkr,
> + &clk_en_mdl_xtal.clkr,
> + &clk_en_test_mux.clkr,
> + &clk_en_dla.clkr,
> + &clk_en_tpcw.clkr,
> + &clk_en_gpu_ts_src.clkr,
> + &clk_en_vi.clkr,
> + &clk_en_lvds1.clkr,
> + &clk_en_lvds2.clkr,
> + &clk_en_aucpu.clkr,
> + &clk_en_ur1.clkr,
> + &clk_en_ur2.clkr,
> + &clk_en_ur3.clkr,
> + &clk_en_ur4.clkr,
> + &clk_en_ur5.clkr,
> + &clk_en_ur6.clkr,
> + &clk_en_ur7.clkr,
> + &clk_en_ur8.clkr,
> + &clk_en_ur9.clkr,
> + &clk_en_ur_top.clkr,
> + &clk_en_misc_i2c_7.clkr,
> + &clk_en_misc_i2c_6.clkr,
> + &clk_en_spi0.clkr,
> + &clk_en_spi1.clkr,
> + &clk_en_spi2.clkr,
> + &clk_en_lsadc0.clkr,
> + &clk_en_lsadc1.clkr,
> + &clk_en_isomis_dma.clkr,
> + &clk_en_dptx.clkr,
> + &clk_en_npu_mipi_csi.clkr,
> + &clk_en_edptx.clkr,
> + &clk_gpu.clkr,
> + &clk_ve1.clkr,
> + &clk_ve2.clkr,
> + &clk_ve4.clkr,
> + &pll_ve1.clkr,
> + &pll_ddsa.clkr,
> + &pll_bus.clkr,
> + &pll_dcsb.clkr,
> + &pll_gpu.clkr,
> + &pll_npu.clkr,
> + &pll_ve2.clkr,
> + &pll_hifi.clkr,
> + &pll_emmc.clkr,
> + &pll_acpu.clkr,
> +};
> +
> +static struct clk_hw_onecell_data rtd1625_crt_hw_data = {
> + .num = RTD1625_CRT_CLK_MAX,
> + .hws = {
> + [RTD1625_CRT_CLK_EN_MISC] = &__clk_regmap_gate_hw(&clk_en_misc),
> + [RTD1625_CRT_CLK_EN_PCIE0] = &__clk_regmap_gate_hw(&clk_en_pcie0),
> + [RTD1625_CRT_CLK_EN_GSPI] = &__clk_regmap_gate_hw(&clk_en_gspi),
> + [RTD1625_CRT_CLK_EN_ISO_MISC] = &__clk_regmap_gate_hw(&clk_en_iso_misc),
> + [RTD1625_CRT_CLK_EN_SDS] = &__clk_regmap_gate_hw(&clk_en_sds),
> + [RTD1625_CRT_CLK_EN_HDMI] = &__clk_regmap_gate_hw(&clk_en_hdmi),
> + [RTD1625_CRT_CLK_EN_GPU] = &__clk_regmap_gate_hw(&clk_en_gpu),
> + [RTD1625_CRT_CLK_EN_VE1] = &__clk_regmap_gate_hw(&clk_en_ve1),
> + [RTD1625_CRT_CLK_EN_VE2] = &__clk_regmap_gate_hw(&clk_en_ve2),
> + [RTD1625_CRT_CLK_EN_MD] = &__clk_regmap_gate_hw(&clk_en_md),
> + [RTD1625_CRT_CLK_EN_TP] = &__clk_regmap_gate_hw(&clk_en_tp),
> + [RTD1625_CRT_CLK_EN_RCIC] = &__clk_regmap_gate_hw(&clk_en_rcic),
> + [RTD1625_CRT_CLK_EN_NF] = &__clk_regmap_gate_hw(&clk_en_nf),
> + [RTD1625_CRT_CLK_EN_EMMC] = &__clk_regmap_gate_hw(&clk_en_emmc),
> + [RTD1625_CRT_CLK_EN_SD] = &__clk_regmap_gate_hw(&clk_en_sd),
> + [RTD1625_CRT_CLK_EN_SDIO_IP] = &__clk_regmap_gate_hw(&clk_en_sdio_ip),
> + [RTD1625_CRT_CLK_EN_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EMMC_IP] = &__clk_regmap_gate_hw(&clk_en_emmc_ip),
> + [RTD1625_CRT_CLK_EN_SDIO] = &__clk_regmap_gate_hw(&clk_en_sdio),
> + [RTD1625_CRT_CLK_EN_SD_IP] = &__clk_regmap_gate_hw(&clk_en_sd_ip),
> + [RTD1625_CRT_CLK_EN_TPB] = &__clk_regmap_gate_hw(&clk_en_tpb),
> + [RTD1625_CRT_CLK_EN_MISC_SC1] = &__clk_regmap_gate_hw(&clk_en_misc_sc1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_3] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_3),
> + [RTD1625_CRT_CLK_EN_ACPU] = &__clk_regmap_gate_hw(&clk_en_acpu),
> + [RTD1625_CRT_CLK_EN_JPEG] = &__clk_regmap_gate_hw(&clk_en_jpeg),
> + [RTD1625_CRT_CLK_EN_MISC_SC0] = &__clk_regmap_gate_hw(&clk_en_misc_sc0),
> + [RTD1625_CRT_CLK_EN_HDMIRX] = &__clk_regmap_gate_hw(&clk_en_hdmirx),
> + [RTD1625_CRT_CLK_EN_HSE] = &__clk_regmap_gate_hw(&clk_en_hse),
> + [RTD1625_CRT_CLK_EN_FAN] = &__clk_regmap_gate_hw(&clk_en_fan),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYS] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sys),
> + [RTD1625_CRT_CLK_EN_SATA_WRAP_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_wrap_sysh),
> + [RTD1625_CRT_CLK_EN_SATA_MAC_SYSH] = &__clk_regmap_gate_hw(&clk_en_sata_mac_sysh),
> + [RTD1625_CRT_CLK_EN_R2RDSC] = &__clk_regmap_gate_hw(&clk_en_r2rdsc),
> + [RTD1625_CRT_CLK_EN_PCIE1] = &__clk_regmap_gate_hw(&clk_en_pcie1),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_4] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_4),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_5] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_5),
> + [RTD1625_CRT_CLK_EN_TSIO] = &__clk_regmap_gate_hw(&clk_en_tsio),
> + [RTD1625_CRT_CLK_EN_VE4] = &__clk_regmap_gate_hw(&clk_en_ve4),
> + [RTD1625_CRT_CLK_EN_EDP] = &__clk_regmap_gate_hw(&clk_en_edp),
> + [RTD1625_CRT_CLK_EN_TSIO_TRX] = &__clk_regmap_gate_hw(&clk_en_tsio_trx),
> + [RTD1625_CRT_CLK_EN_PCIE2] = &__clk_regmap_gate_hw(&clk_en_pcie2),
> + [RTD1625_CRT_CLK_EN_EARC] = &__clk_regmap_gate_hw(&clk_en_earc),
> + [RTD1625_CRT_CLK_EN_LITE] = &__clk_regmap_gate_hw(&clk_en_lite),
> + [RTD1625_CRT_CLK_EN_MIPI_DSI] = &__clk_regmap_gate_hw(&clk_en_mipi_dsi),
> + [RTD1625_CRT_CLK_EN_NPUPP] = &__clk_regmap_gate_hw(&clk_en_npupp),
> + [RTD1625_CRT_CLK_EN_NPU] = &__clk_regmap_gate_hw(&clk_en_npu),
> + [RTD1625_CRT_CLK_EN_AUCPU0] = &__clk_regmap_gate_hw(&clk_en_aucpu0),
> + [RTD1625_CRT_CLK_EN_AUCPU1] = &__clk_regmap_gate_hw(&clk_en_aucpu1),
> + [RTD1625_CRT_CLK_EN_NSRAM] = &__clk_regmap_gate_hw(&clk_en_nsram),
> + [RTD1625_CRT_CLK_EN_HDMITOP] = &__clk_regmap_gate_hw(&clk_en_hdmitop),
> + [RTD1625_CRT_CLK_EN_AUCPU_ISO_NPU] = &__clk_regmap_gate_hw(&clk_en_aucpu_iso_npu),
> + [RTD1625_CRT_CLK_EN_KEYLADDER] = &__clk_regmap_gate_hw(&clk_en_keyladder),
> + [RTD1625_CRT_CLK_EN_IFCP_KLM] = &__clk_regmap_gate_hw(&clk_en_ifcp_klm),
> + [RTD1625_CRT_CLK_EN_IFCP] = &__clk_regmap_gate_hw(&clk_en_ifcp),
> + [RTD1625_CRT_CLK_EN_MDL_GENPW] = &__clk_regmap_gate_hw(&clk_en_mdl_genpw),
> + [RTD1625_CRT_CLK_EN_MDL_CHIP] = &__clk_regmap_gate_hw(&clk_en_mdl_chip),
> + [RTD1625_CRT_CLK_EN_MDL_IP] = &__clk_regmap_gate_hw(&clk_en_mdl_ip),
> + [RTD1625_CRT_CLK_EN_MDLM2M] = &__clk_regmap_gate_hw(&clk_en_mdlm2m),
> + [RTD1625_CRT_CLK_EN_MDL_XTAL] = &__clk_regmap_gate_hw(&clk_en_mdl_xtal),
> + [RTD1625_CRT_CLK_EN_TEST_MUX] = &__clk_regmap_gate_hw(&clk_en_test_mux),
> + [RTD1625_CRT_CLK_EN_DLA] = &__clk_regmap_gate_hw(&clk_en_dla),
> + [RTD1625_CRT_CLK_EN_TPCW] = &__clk_regmap_gate_hw(&clk_en_tpcw),
> + [RTD1625_CRT_CLK_EN_GPU_TS_SRC] = &__clk_regmap_gate_hw(&clk_en_gpu_ts_src),
> + [RTD1625_CRT_CLK_EN_VI] = &__clk_regmap_gate_hw(&clk_en_vi),
> + [RTD1625_CRT_CLK_EN_LVDS1] = &__clk_regmap_gate_hw(&clk_en_lvds1),
> + [RTD1625_CRT_CLK_EN_LVDS2] = &__clk_regmap_gate_hw(&clk_en_lvds2),
> + [RTD1625_CRT_CLK_EN_AUCPU] = &__clk_regmap_gate_hw(&clk_en_aucpu),
> + [RTD1625_CRT_CLK_EN_UR1] = &__clk_regmap_gate_hw(&clk_en_ur1),
> + [RTD1625_CRT_CLK_EN_UR2] = &__clk_regmap_gate_hw(&clk_en_ur2),
> + [RTD1625_CRT_CLK_EN_UR3] = &__clk_regmap_gate_hw(&clk_en_ur3),
> + [RTD1625_CRT_CLK_EN_UR4] = &__clk_regmap_gate_hw(&clk_en_ur4),
> + [RTD1625_CRT_CLK_EN_UR5] = &__clk_regmap_gate_hw(&clk_en_ur5),
> + [RTD1625_CRT_CLK_EN_UR6] = &__clk_regmap_gate_hw(&clk_en_ur6),
> + [RTD1625_CRT_CLK_EN_UR7] = &__clk_regmap_gate_hw(&clk_en_ur7),
> + [RTD1625_CRT_CLK_EN_UR8] = &__clk_regmap_gate_hw(&clk_en_ur8),
> + [RTD1625_CRT_CLK_EN_UR9] = &__clk_regmap_gate_hw(&clk_en_ur9),
> + [RTD1625_CRT_CLK_EN_UR_TOP] = &__clk_regmap_gate_hw(&clk_en_ur_top),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_7] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_7),
> + [RTD1625_CRT_CLK_EN_MISC_I2C_6] = &__clk_regmap_gate_hw(&clk_en_misc_i2c_6),
> + [RTD1625_CRT_CLK_EN_SPI0] = &__clk_regmap_gate_hw(&clk_en_spi0),
> + [RTD1625_CRT_CLK_EN_SPI1] = &__clk_regmap_gate_hw(&clk_en_spi1),
> + [RTD1625_CRT_CLK_EN_SPI2] = &__clk_regmap_gate_hw(&clk_en_spi2),
> + [RTD1625_CRT_CLK_EN_LSADC0] = &__clk_regmap_gate_hw(&clk_en_lsadc0),
> + [RTD1625_CRT_CLK_EN_LSADC1] = &__clk_regmap_gate_hw(&clk_en_lsadc1),
> + [RTD1625_CRT_CLK_EN_ISOMIS_DMA] = &__clk_regmap_gate_hw(&clk_en_isomis_dma),
> + [RTD1625_CRT_CLK_EN_DPTX] = &__clk_regmap_gate_hw(&clk_en_dptx),
> + [RTD1625_CRT_CLK_EN_NPU_MIPI_CSI] = &__clk_regmap_gate_hw(&clk_en_npu_mipi_csi),
> + [RTD1625_CRT_CLK_EN_EDPTX] = &__clk_regmap_gate_hw(&clk_en_edptx),
> + [RTD1625_CRT_CLK_GPU] = &__clk_regmap_mux_hw(&clk_gpu),
> + [RTD1625_CRT_CLK_VE1] = &__clk_regmap_mux_hw(&clk_ve1),
> + [RTD1625_CRT_CLK_VE2] = &__clk_regmap_mux_hw(&clk_ve2),
> + [RTD1625_CRT_CLK_VE4] = &__clk_regmap_mux_hw(&clk_ve4),
> + [RTD1625_CRT_PLL_VE1] = &__clk_pll_hw(&pll_ve1),
> + [RTD1625_CRT_PLL_DDSA] = &__clk_pll_hw(&pll_ddsa),
> + [RTD1625_CRT_PLL_BUS] = &__clk_pll_hw(&pll_bus),
> + [RTD1625_CRT_CLK_SYS] = &clk_sys.hw,
> + [RTD1625_CRT_PLL_DCSB] = &__clk_pll_hw(&pll_dcsb),
> + [RTD1625_CRT_CLK_SYSH] = &clk_sysh.hw,
> + [RTD1625_CRT_PLL_GPU] = &__clk_pll_hw(&pll_gpu),
> + [RTD1625_CRT_PLL_NPU] = &__clk_pll_hw(&pll_npu),
> + [RTD1625_CRT_PLL_VE2] = &__clk_pll_hw(&pll_ve2),
> + [RTD1625_CRT_PLL_HIFI] = &__clk_pll_hw(&pll_hifi),
> + [RTD1625_CRT_PLL_EMMC_REF] = &pll_emmc_ref.hw,
> + [RTD1625_CRT_PLL_EMMC] = &__clk_pll_mmc_hw(&pll_emmc),
> + [RTD1625_CRT_PLL_EMMC_VP0] = &pll_emmc.phase0_hw,
> + [RTD1625_CRT_PLL_EMMC_VP1] = &pll_emmc.phase1_hw,
> + [RTD1625_CRT_PLL_ACPU] = &__clk_pll_hw(&pll_acpu),
> + [RTD1625_CRT_CLK_NPU] = &clk_npu.hw,
> + [RTD1625_CRT_CLK_NPU_MIPI_CSI] = &clk_npu_mipi_csi.hw,
> +
> + [RTD1625_CRT_CLK_MAX] = NULL,
> + },
> +};
> +
> +static const struct rtk_clk_desc rtd1625_crt_desc = {
> + .clk_data = &rtd1625_crt_hw_data,
> + .clks = rtd1625_crt_regmap_clks,
> + .num_clks = ARRAY_SIZE(rtd1625_crt_regmap_clks),
> +};
> +
> +static int rtd1625_crt_probe(struct platform_device *pdev)
> +{
> + const struct rtk_clk_desc *desc;
> +
> + desc = of_device_get_match_data(&pdev->dev);
> + if (!desc)
> + return -EINVAL;
> +
> + return rtk_clk_probe(pdev, desc, "crt_rst");
> +}
> +
> +static const struct of_device_id rtd1625_crt_match[] = {
> + {.compatible = "realtek,rtd1625-crt-clk", .data = &rtd1625_crt_desc,},
> + {/* sentinel */}
Add a space around the comment like so:
{ /* sentinel */ }
> +};
> +
> +static struct platform_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_probe,
> + .driver = {
> + .name = "rtk-rtd1625-crt-clk",
> + .of_match_table = rtd1625_crt_match,
> + },
> +};
> +
> +static int __init rtd1625_crt_init(void)
> +{
> + return platform_driver_register(&rtd1625_crt_driver);
> +}
> +subsys_initcall(rtd1625_crt_init);
> +
> +MODULE_DESCRIPTION("Reatek RTD1625 CRT Controller Driver");
s/Reatek/Realtex/
> +MODULE_AUTHOR("Cheng-Yu Lee <cylee12@realtek.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_CLK");
> diff --git a/drivers/reset/realtek/Kconfig b/drivers/reset/realtek/Kconfig
> index 99a14d355803..a44c7834191c 100644
> --- a/drivers/reset/realtek/Kconfig
> +++ b/drivers/reset/realtek/Kconfig
> @@ -1,3 +1,5 @@
> # SPDX-License-Identifier: GPL-2.0-only
> config RESET_RTK_COMMON
> bool
> + select AUXILIARY_BUS
> + default COMMON_CLK_RTD1625
> diff --git a/drivers/reset/realtek/Makefile b/drivers/reset/realtek/Makefile
> index b59a3f7f2453..8ca1fa939f10 100644
> --- a/drivers/reset/realtek/Makefile
> +++ b/drivers/reset/realtek/Makefile
> @@ -1,2 +1,2 @@
> # SPDX-License-Identifier: GPL-2.0-only
> -obj-$(CONFIG_RESET_RTK_COMMON) += common.o
> +obj-$(CONFIG_RESET_RTK_COMMON) += common.o reset-rtd1625-crt.o
CONFIG_RESET_RTK_COMMON is supposed to be common, right? If so, the
SoC-specific driver shouldn't be included here.
> diff --git a/drivers/reset/realtek/reset-rtd1625-crt.c b/drivers/reset/realtek/reset-rtd1625-crt.c
> new file mode 100644
> index 000000000000..ebb15bb68885
> --- /dev/null
> +++ b/drivers/reset/realtek/reset-rtd1625-crt.c
> @@ -0,0 +1,186 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 Realtek Semiconductor Corporation
> + */
> +
> +#include <dt-bindings/reset/realtek,rtd1625.h>
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/errno.h>
> +#include <linux/slab.h>
> +#include "common.h"
> +
> +#define RTD1625_CRT_RSTN_MAX 123
> +
> +static struct rtk_reset_desc rtd1625_crt_reset_descs[] = {
> + /* Bank 0: offset 0x0 */
> + [RTD1625_CRT_RSTN_MISC] = { .ofs = 0x0, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DIP] = { .ofs = 0x0, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GSPI] = { .ofs = 0x0, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS] = { .ofs = 0x0, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_REG] = { .ofs = 0x0, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDS_PHY] = { .ofs = 0x0, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU2D] = { .ofs = 0x0, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DC_PHY] = { .ofs = 0x0, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_CRT] = { .ofs = 0x0, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC] = { .ofs = 0x0, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SE] = { .ofs = 0x0, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DLA] = { .ofs = 0x0, .bit = 30, .write_en = 1 },
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Can this cause undefined behavior during reset mask computation?
Several reset array entries set .bit = 30 and .write_en = 1. In
rtk_reset_assert() and rtk_reset_deassert(), if the bitmask is computed as
0x3 << desc->bit, 0x3 is a signed 32-bit integer literal. Left-shifting it by
30 results in 0xC0000000, which exceeds the maximum positive value for a
signed 32-bit integer.
Modifying the sign bit via left-shift on a signed type invokes undefined
behavior in C. Would an unsigned literal (e.g., 0x3U << desc->bit) be needed
to safely construct the mask?
> + /* Bank 1: offset 0x4 */
> + [RTD1625_CRT_RSTN_JPEG] = { .ofs = 0x4, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SD] = { .ofs = 0x4, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SDIO] = { .ofs = 0x4, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCR_CNT] = { .ofs = 0x4, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_STITCH] = { .ofs = 0x4, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY] = { .ofs = 0x4, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0] = { .ofs = 0x4, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_CORE] = { .ofs = 0x4, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_POWER] = { .ofs = 0x4, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_NONSTICH] = { .ofs = 0x4, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_PHY_MDIO] = { .ofs = 0x4, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE0_SGMII_MDIO] = { .ofs = 0x4, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO2] = { .ofs = 0x4, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC0] = { .ofs = 0x4, .bit = 30, .write_en = 1 },
> + /* Bank 2: offset 0x8 */
> + [RTD1625_CRT_RSTN_MD] = { .ofs = 0x8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS1] = { .ofs = 0x8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LVDS2] = { .ofs = 0x8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MISC_SC1] = { .ofs = 0x8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_3] = { .ofs = 0x8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_FAN] = { .ofs = 0x8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TVE] = { .ofs = 0x8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AIO] = { .ofs = 0x8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VO] = { .ofs = 0x8, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_CSI] = { .ofs = 0x8, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX] = { .ofs = 0x8, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMIRX_WRAP] = { .ofs = 0x8, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMI] = { .ofs = 0x8, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP] = { .ofs = 0x8, .bit = 30, .write_en = 1 },
> + /* Bank 3: offset 0xc */
> + [RTD1625_CRT_RSTN_SATA_PHY_POW1] = { .ofs = 0xc, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_PHY_POW0] = { .ofs = 0xc, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO1] = { .ofs = 0xc, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MDIO0] = { .ofs = 0xc, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_WRAP] = { .ofs = 0xc, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P1] = { .ofs = 0xc, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_P0] = { .ofs = 0xc, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SATA_MAC_COM] = { .ofs = 0xc, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_STITCH] = { .ofs = 0xc, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY] = { .ofs = 0xc, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1] = { .ofs = 0xc, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_CORE] = { .ofs = 0xc, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_POWER] = { .ofs = 0xc, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_NONSTICH] = { .ofs = 0xc, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE1_PHY_MDIO] = { .ofs = 0xc, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HDMITOP] = { .ofs = 0xc, .bit = 30, .write_en = 1 },
> + /* Bank 4: offset 0x68 */
> + [RTD1625_CRT_RSTN_I2C_4] = { .ofs = 0x68, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_5] = { .ofs = 0x68, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TSIO] = { .ofs = 0x68, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VI] = { .ofs = 0x68, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDP] = { .ofs = 0x68, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU] = { .ofs = 0x68, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_MMU_FUNC] = { .ofs = 0x68, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU] = { .ofs = 0x68, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HSE_MMU_FUNC] = { .ofs = 0x68, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDLM2M] = { .ofs = 0x68, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISO_GSPI] = { .ofs = 0x68, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SOFT_NPU] = { .ofs = 0x68, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2EMMC] = { .ofs = 0x68, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EARC] = { .ofs = 0x68, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1] = { .ofs = 0x68, .bit = 30, .write_en = 1 },
> + /* Bank 5: offset 0x90 */
> + [RTD1625_CRT_RSTN_PCIE2_STITCH] = { .ofs = 0x90, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY] = { .ofs = 0x90, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2] = { .ofs = 0x90, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_CORE] = { .ofs = 0x90, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_POWER] = { .ofs = 0x90, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_NONSTICH] = { .ofs = 0x90, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_PCIE2_PHY_MDIO] = { .ofs = 0x90, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_UMCTL2] = { .ofs = 0x90, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MIPI_DSI] = { .ofs = 0x90, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_HIFM] = { .ofs = 0x90, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NSRAM] = { .ofs = 0x90, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU0_REG] = { .ofs = 0x90, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_GENPW] = { .ofs = 0x90, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_CHIP] = { .ofs = 0x90, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MDL_IP] = { .ofs = 0x90, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_TEST_MUX] = { .ofs = 0x90, .bit = 30, .write_en = 1 },
> + /* Bank 6: offset 0xb8 */
> + [RTD1625_CRT_RSTN_ISO_BIST] = { .ofs = 0xb8, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN_BIST] = { .ofs = 0xb8, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_MAIN2_BIST] = { .ofs = 0xb8, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE1_BIST] = { .ofs = 0xb8, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE2_BIST] = { .ofs = 0xb8, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DCPHY_BIST] = { .ofs = 0xb8, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_GPU_BIST] = { .ofs = 0xb8, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DISP_BIST] = { .ofs = 0xb8, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_NPU_BIST] = { .ofs = 0xb8, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_CAS_BIST] = { .ofs = 0xb8, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_VE4_BIST] = { .ofs = 0xb8, .bit = 20, .write_en = 1 },
> + /* Bank 7: offset 0x454 (DUMMY0, no write_en) */
> + [RTD1625_CRT_RSTN_EMMC] = { .ofs = 0x454, .bit = 0 },
> + /* Bank 8: offset 0x458 (DUMMY1, no write_en) */
> + [RTD1625_CRT_RSTN_GPU] = { .ofs = 0x458, .bit = 0 },
> + /* Bank 9: offset 0x464 (DUMMY4, no write_en) */
> + [RTD1625_CRT_RSTN_VE2] = { .ofs = 0x464, .bit = 0 },
> + /* Bank 10: offset 0x880 */
> + [RTD1625_CRT_RSTN_UR1] = { .ofs = 0x880, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR2] = { .ofs = 0x880, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR3] = { .ofs = 0x880, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR4] = { .ofs = 0x880, .bit = 6, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR5] = { .ofs = 0x880, .bit = 8, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR6] = { .ofs = 0x880, .bit = 10, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR7] = { .ofs = 0x880, .bit = 12, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR8] = { .ofs = 0x880, .bit = 14, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR9] = { .ofs = 0x880, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_UR_TOP] = { .ofs = 0x880, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_7] = { .ofs = 0x880, .bit = 28, .write_en = 1 },
> + [RTD1625_CRT_RSTN_I2C_6] = { .ofs = 0x880, .bit = 30, .write_en = 1 },
> + /* Bank 11: offset 0x890 */
> + [RTD1625_CRT_RSTN_SPI0] = { .ofs = 0x890, .bit = 0, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI1] = { .ofs = 0x890, .bit = 2, .write_en = 1 },
> + [RTD1625_CRT_RSTN_SPI2] = { .ofs = 0x890, .bit = 4, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC0] = { .ofs = 0x890, .bit = 16, .write_en = 1 },
> + [RTD1625_CRT_RSTN_LSADC1] = { .ofs = 0x890, .bit = 18, .write_en = 1 },
> + [RTD1625_CRT_RSTN_ISOMIS_DMA] = { .ofs = 0x890, .bit = 20, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUDIO_ADC] = { .ofs = 0x890, .bit = 22, .write_en = 1 },
> + [RTD1625_CRT_RSTN_DPTX] = { .ofs = 0x890, .bit = 24, .write_en = 1 },
> + [RTD1625_CRT_RSTN_AUCPU1_REG] = { .ofs = 0x890, .bit = 26, .write_en = 1 },
> + [RTD1625_CRT_RSTN_EDPTX] = { .ofs = 0x890, .bit = 28, .write_en = 1 },
> +};
> +
> +static int rtd1625_crt_reset_probe(struct auxiliary_device *adev,
> + const struct auxiliary_device_id *id)
> +{
> + struct device *dev = &adev->dev;
> + struct rtk_reset_data *data;
> +
> + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + data->descs = rtd1625_crt_reset_descs;
> + data->rcdev.nr_resets = RTD1625_CRT_RSTN_MAX;
> + return rtk_reset_controller_add(dev, data);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Will the reset controller driver unconditionally fail to probe with -ENODEV
due to an incompatible regmap acquisition method?
The rtk_reset_controller_add() helper attempts to retrieve the shared regmap
from the parent clock device using dev_get_regmap(parent, NULL). However, the
parent clock driver (rtk_clk_probe()) acquires its regmap via
device_node_to_regmap().
This syscon helper creates the regmap but does not associate it with the
parent struct device via devres. Because the regmap is absent from the
parent's devres list, dev_get_regmap() will always return NULL, causing the
reset driver probe to fail unconditionally and leaving dependent peripherals
without reset control.
Brian
> +}
> +
> +static const struct auxiliary_device_id rtd1625_crt_reset_ids[] = {
> + {
> + .name = "clk_rtk.crt_rst",
> + },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(auxiliary, rtd1625_crt_reset_ids);
> +
> +static struct auxiliary_driver rtd1625_crt_driver = {
> + .probe = rtd1625_crt_reset_probe,
> + .id_table = rtd1625_crt_reset_ids,
> + .driver = {
> + .name = "rtd1625-crt-reset",
> + },
> +};
> +module_auxiliary_driver(rtd1625_crt_driver);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("REALTEK_RESET");
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH v3 2/2] mailbox: Make mbox_send_message() return error code when tx fails
From: Joonwon Kang @ 2026-04-03 15:19 UTC (permalink / raw)
To: jassisinghbrar
Cc: angelogioacchino.delregno, jonathanh, joonwonkang,
linux-arm-kernel, linux-kernel, linux-mediatek, linux-tegra,
matthias.bgg, stable, thierry.reding, akpm
In-Reply-To: <CABb+yY3hYcJ82QGor3w5KKHUGz9Pc1k64Jdf-94E4Yvv0DTeyQ@mail.gmail.com>
> On Thu, Apr 2, 2026 at 12:07 PM Joonwon Kang <joonwonkang@google.com> wrote:
> >
> > When the mailbox controller failed transmitting message, the error code
> > was only passed to the client's tx done handler and not to
> > mbox_send_message(). For this reason, the function could return a false
> > success. This commit resolves the issue by introducing the tx status and
> > checking it before mbox_send_message() returns.
> >
> Can you please share the scenario when this becomes necessary? This
> can potentially change the ground underneath some clients, so we have
> to be sure this is really useful.
I would say the problem here is generic enough to apply to all the cases where
the send result needs to be checked. Since the return value of the send API is
not the real send result, any users who believe that this blocking send API
will return the real send result could fall for that. For example, users may
think the send was successful even though it was not actually. I believe it is
uncommon that users have to register a callback solely to get the send result
even though they are using the blocking send API already. Also, I guess there
is no special reason why only the mailbox send API should work this way among
other typical blocking send APIs. For these reasons, this patch makes the send
API return the real send result. This way, users will not need to register the
redundant callback and I think the return value will align with their common
expectation.
Regarding the change in the ground for some clients, could you help to clarify
a bit more on what change, you expect, would surprise the clients?
Thanks,
Joonwon Kang
>
> Thanks
> Jassi
>
>
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Joonwon Kang <joonwonkang@google.com>
> > ---
> > drivers/mailbox/mailbox.c | 20 +++++++++++++++-----
> > include/linux/mailbox_controller.h | 2 ++
> > 2 files changed, 17 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> > index d63386468982..ea9aec9dc947 100644
> > --- a/drivers/mailbox/mailbox.c
> > +++ b/drivers/mailbox/mailbox.c
> > @@ -21,7 +21,10 @@
> > static LIST_HEAD(mbox_cons);
> > static DEFINE_MUTEX(con_mutex);
> >
> > -static int add_to_rbuf(struct mbox_chan *chan, void *mssg, struct completion *tx_complete)
> > +static int add_to_rbuf(struct mbox_chan *chan,
> > + void *mssg,
> > + struct completion *tx_complete,
> > + int *tx_status)
> > {
> > int idx;
> >
> > @@ -34,6 +37,7 @@ static int add_to_rbuf(struct mbox_chan *chan, void *mssg, struct completion *tx
> > idx = chan->msg_free;
> > chan->msg_data[idx].data = mssg;
> > chan->msg_data[idx].tx_complete = tx_complete;
> > + chan->msg_data[idx].tx_status = tx_status;
> > chan->msg_count++;
> >
> > if (idx == MBOX_TX_QUEUE_LEN - 1)
> > @@ -91,12 +95,13 @@ static void msg_submit(struct mbox_chan *chan)
> >
> > static void tx_tick(struct mbox_chan *chan, int r, int idx)
> > {
> > - struct mbox_message mssg = {MBOX_NO_MSG, NULL};
> > + struct mbox_message mssg = {MBOX_NO_MSG, NULL, NULL};
> >
> > scoped_guard(spinlock_irqsave, &chan->lock) {
> > if (idx >= 0 && idx != chan->active_req) {
> > chan->msg_data[idx].data = MBOX_NO_MSG;
> > chan->msg_data[idx].tx_complete = NULL;
> > + chan->msg_data[idx].tx_status = NULL;
> > return;
> > }
> >
> > @@ -116,8 +121,10 @@ static void tx_tick(struct mbox_chan *chan, int r, int idx)
> > if (chan->cl->tx_done)
> > chan->cl->tx_done(chan->cl, mssg.data, r);
> >
> > - if (r != -ETIME && chan->cl->tx_block)
> > + if (r != -ETIME && chan->cl->tx_block) {
> > + *mssg.tx_status = r;
> > complete(mssg.tx_complete);
> > + }
> > }
> >
> > static enum hrtimer_restart txdone_hrtimer(struct hrtimer *hrtimer)
> > @@ -286,15 +293,16 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > int t;
> > int idx;
> > struct completion tx_complete;
> > + int tx_status = 0;
> >
> > if (!chan || !chan->cl || mssg == MBOX_NO_MSG)
> > return -EINVAL;
> >
> > if (chan->cl->tx_block) {
> > init_completion(&tx_complete);
> > - t = add_to_rbuf(chan, mssg, &tx_complete);
> > + t = add_to_rbuf(chan, mssg, &tx_complete, &tx_status);
> > } else {
> > - t = add_to_rbuf(chan, mssg, NULL);
> > + t = add_to_rbuf(chan, mssg, NULL, NULL);
> > }
> >
> > if (t < 0) {
> > @@ -318,6 +326,8 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > idx = t;
> > t = -ETIME;
> > tx_tick(chan, t, idx);
> > + } else if (tx_status < 0) {
> > + t = tx_status;
> > }
> > }
> >
> > diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
> > index 912499ad08ed..890da97bcb50 100644
> > --- a/include/linux/mailbox_controller.h
> > +++ b/include/linux/mailbox_controller.h
> > @@ -117,10 +117,12 @@ struct mbox_controller {
> > * struct mbox_message - Internal representation of a mailbox message
> > * @data: Data packet
> > * @tx_complete: Pointer to the transmission completion
> > + * @tx_status: Pointer to the transmission status
> > */
> > struct mbox_message {
> > void *data;
> > struct completion *tx_complete;
> > + int *tx_status;
> > };
> >
> > /**
> > --
> > 2.53.0.1185.g05d4b7b318-goog
> >
^ permalink raw reply
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:10 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun,
I should have finished going through Sashiko while manually reviewing
your patches.
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Is it intended to use bitwise OR to accumulate these return values? Because
these hardware operations return standard negative error codes on failure,
performing a bitwise OR on multiple negative integers will merge their bit
patterns and create a corrupted error code.
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
Sashiko reports:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Are the mask and shift values mismatched here? PLL_FLAG_INITAL_EMMC_MASK is
defined as BIT(1) (0x02), but PLL_FLAG_INITAL_EMMC_SHIFT is 8.
When regmap_update_bits() applies the 0x02 mask to a value shifted by 8,
won't it evaluate to 0 and fail to set the intended initialization flag?
Brian
^ permalink raw reply
* Re: [PATCH v6 07/10] clk: realtek: Add support for MMC-tuned PLL clocks
From: Brian Masney @ 2026-04-03 15:07 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-8-eleanor.lin@realtek.com>
Hi Yu-Chun and Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:54PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add clk_pll_mmc_ops for enable/disable, prepare, rate control, and status
> operations on MMC PLL clocks.
>
> Also add clk_pll_mmc_phase_ops to support phase get/set operations.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Jyan Chou <jyanchou@realtek.com>
> Signed-off-by: Jyan Chou <jyanchou@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move to_clk_pll_mmc() from clk-pll.h to clk-pll-mmc.c to limit its scope.
> - Change offset type from int to unsigned int.
> ---
> MAINTAINERS | 8 +
> drivers/clk/realtek/Kconfig | 3 +
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-pll-mmc.c | 410 ++++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-pll.h | 13 +
> 5 files changed, 436 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-pll-mmc.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8318156a02b5..4b28af4b26b5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22245,6 +22245,14 @@ F: drivers/reset/realtek/*
> F: include/dt-bindings/clock/realtek*
> F: include/dt-bindings/reset/realtek*
>
> +REALTEK SOC PLL CLOCK FOR MMC SUPPORT
> +M: Cheng-Yu Lee <cylee12@realtek.com>
> +M: Jyan Chou <jyanchou@realtek.com>
> +M: Yu-Chun Lin <eleanor.lin@realtek.com>
> +L: linux-clk@vger.kernel.org
> +S: Supported
> +F: drivers/clk/realtek/clk-pll-mmc.c
> +
> REALTEK SPI-NAND
> M: Chris Packham <chris.packham@alliedtelesis.co.nz>
> S: Maintained
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> index bc47d3f1c452..b31a31e57b3a 100644
> --- a/drivers/clk/realtek/Kconfig
> +++ b/drivers/clk/realtek/Kconfig
> @@ -25,4 +25,7 @@ config RTK_CLK_COMMON
> multiple Realtek clock implementations, and include integration
> with reset controllers where required.
>
> +config RTK_CLK_PLL_MMC
> + bool
> +
> endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index f90dc57fcfdb..fd7d777902c8 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -7,3 +7,5 @@ clk-rtk-y += clk-pll.o
> clk-rtk-y += clk-regmap-gate.o
> clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
> +
> +clk-rtk-$(CONFIG_RTK_CLK_PLL_MMC) += clk-pll-mmc.o
> diff --git a/drivers/clk/realtek/clk-pll-mmc.c b/drivers/clk/realtek/clk-pll-mmc.c
> new file mode 100644
> index 000000000000..d28c7027d3f0
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll-mmc.c
> @@ -0,0 +1,410 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2021 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/bits.h>
> +#include <linux/module.h>
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +
> +#define PLL_EMMC1_OFFSET 0x0
> +#define PLL_EMMC2_OFFSET 0x4
> +#define PLL_EMMC3_OFFSET 0x8
> +#define PLL_EMMC4_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC1_OFFSET 0x0
> +#define PLL_SSC_DIG_EMMC3_OFFSET 0xc
> +#define PLL_SSC_DIG_EMMC4_OFFSET 0x10
> +
> +#define PLL_MMC_SSC_DIV_N_VAL 0x1b
> +
> +#define PLL_PHRT0_MASK BIT(1)
> +#define PLL_PHSEL_MASK GENMASK(4, 0)
> +#define PLL_SSCPLL_RS_MASK GENMASK(12, 10)
> +#define PLL_SSCPLL_ICP_MASK GENMASK(9, 5)
> +#define PLL_SSC_DIV_EXT_F_MASK GENMASK(25, 13)
> +#define PLL_PI_IBSELH_MASK GENMASK(28, 27)
> +#define PLL_SSC_DIV_N_MASK GENMASK(23, 16)
> +#define PLL_NCODE_SSC_EMMC_MASK GENMASK(20, 13)
> +#define PLL_FCODE_SSC_EMMC_MASK GENMASK(12, 0)
> +#define PLL_GRAN_EST_EM_MC_MASK GENMASK(20, 0)
> +#define PLL_EN_SSC_EMMC_MASK BIT(0)
> +#define PLL_FLAG_INITAL_EMMC_MASK BIT(1)
> +
> +#define PLL_PHRT0_SHIFT 1
> +#define PLL_SSCPLL_RS_SHIFT 10
> +#define PLL_SSCPLL_ICP_SHIFT 5
> +#define PLL_SSC_DIV_EXT_F_SHIFT 13
> +#define PLL_PI_IBSELH_SHIFT 27
> +#define PLL_SSC_DIV_N_SHIFT 16
> +#define PLL_NCODE_SSC_EMMC_SHIFT 13
> +#define PLL_FLAG_INITAL_EMMC_SHIFT 8
> +
> +#define CYCLE_DEGREES 360
> +#define PHASE_STEPS 32
> +#define PHASE_SCALE_FACTOR 1125
> +
> +static inline struct clk_pll_mmc *to_clk_pll_mmc(struct clk_hw *hw)
> +{
> + struct clk_regmap *clkr = to_clk_regmap(hw);
> +
> + return container_of(clkr, struct clk_pll_mmc, clkr);
> +}
> +
> +static inline int get_phrt0(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 reg;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, ®);
> + if (ret)
> + return ret;
> +
> + *val = (reg >> PLL_PHRT0_SHIFT) & PLL_PHRT0_MASK;
Sashiko reports the following:
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
With PLL_PHRT0_SHIFT defined as 1 and PLL_PHRT0_MASK as BIT(1) (0x02), shifting
right by 1 moves the target bit 1 to position 0, but masking with 0x02 checks
position 1 of the shifted value.
Will this cause clk_pll_mmc_is_enabled() to always evaluate to false since it
expects val == 0x1?
> + return 0;
> +}
> +
> +static inline int set_phrt0(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHRT0_MASK, val << PLL_PHRT0_SHIFT);
> +}
> +
> +static inline int get_phsel(struct clk_pll_mmc *clkm, int id, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> + u32 sft = id ? 8 : 3;
Put variables in reverse Christmas tree order.
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val >> sft) & PLL_PHSEL_MASK;
> + return 0;
> +}
> +
> +static inline int set_phsel(struct clk_pll_mmc *clkm, int id, u32 val)
> +{
> + u32 sft = id ? 8 : 3;
> +
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC1_OFFSET,
> + PLL_PHSEL_MASK << sft, val << sft);
> +}
> +
> +static inline int set_sscpll_rs(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_RS_MASK, val << PLL_SSCPLL_RS_SHIFT);
> +}
> +
> +static inline int set_sscpll_icp(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSCPLL_ICP_MASK, val << PLL_SSCPLL_ICP_SHIFT);
> +}
> +
> +static inline int get_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + u32 raw_val;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_EXT_F_MASK) >> PLL_SSC_DIV_EXT_F_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_ssc_div_ext_f(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_SSC_DIV_EXT_F_MASK,
> + val << PLL_SSC_DIV_EXT_F_SHIFT);
> +}
> +
> +static inline int set_pi_ibselh(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC2_OFFSET,
> + PLL_PI_IBSELH_MASK, val << PLL_PI_IBSELH_SHIFT);
> +}
> +
> +static inline int set_ssc_div_n(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_update_bits(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET,
> + PLL_SSC_DIV_N_MASK, val << PLL_SSC_DIV_N_SHIFT);
> +}
> +
> +static inline int get_ssc_div_n(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC3_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = (raw_val & PLL_SSC_DIV_N_MASK) >> PLL_SSC_DIV_N_SHIFT;
> + return 0;
> +}
> +
> +static inline int set_pow_ctl(struct clk_pll_mmc *clkm, u32 val)
> +{
> + return regmap_write(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, val);
> +}
> +
> +static inline int get_pow_ctl(struct clk_pll_mmc *clkm, u32 *val)
> +{
> + int ret;
> + u32 raw_val;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->pll_ofs + PLL_EMMC4_OFFSET, &raw_val);
> + if (ret)
> + return ret;
> +
> + *val = raw_val;
> +
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_set_phase(struct clk_hw *hw, int degrees)
> +{
> + struct clk_hw *hwp = clk_hw_get_parent(hw);
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
Are you checking to see if these two pointers are the same? If so, what
do you think about this instead?
hw == &clkm->phase0_hw
> + val = DIV_ROUND_CLOSEST(degrees * 100, PHASE_SCALE_FACTOR);
> + ret = set_phsel(clkm, phase_id, val);
> + if (ret)
> + return ret;
> +
> + usleep_range(10, 20);
> + return 0;
> +}
> +
> +static int clk_pll_mmc_phase_get_phase(struct clk_hw *hw)
> +{
> + struct clk_hw *hwp;
> + struct clk_pll_mmc *clkm;
> + int phase_id;
> + int ret;
> + u32 val;
> +
> + hwp = clk_hw_get_parent(hw);
> + if (!hwp)
> + return -ENOENT;
> +
> + clkm = to_clk_pll_mmc(hwp);
> + phase_id = (hw - &clkm->phase0_hw) ? 1 : 0;
> + ret = get_phsel(clkm, phase_id, &val);
> + if (ret)
> + return ret;
> +
> + val = DIV_ROUND_CLOSEST(val * CYCLE_DEGREES, PHASE_STEPS);
> +
> + return val;
> +}
> +
> +const struct clk_ops rtk_clk_pll_mmc_phase_ops = {
> + .set_phase = clk_pll_mmc_phase_set_phase,
> + .get_phase = clk_pll_mmc_phase_get_phase,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_mmc_phase_ops, "REALTEK_CLK");
> +
> +static int clk_pll_mmc_prepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + return set_pow_ctl(clkm, 7);
> +}
> +
> +static void clk_pll_mmc_unprepare(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_pow_ctl(clkm, 0);
> +}
> +
> +static int clk_pll_mmc_is_prepared(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_pow_ctl(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val != 0x0;
> +}
> +
> +static int clk_pll_mmc_enable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + int ret;
> +
> + ret = set_phrt0(clkm, 1);
> + if (ret)
> + return ret;
> +
> + udelay(10);
> + return 0;
> +}
> +
> +static void clk_pll_mmc_disable(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> +
> + set_phrt0(clkm, 0);
> + udelay(10);
> +}
> +
> +static int clk_pll_mmc_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val;
> + int ret;
> +
> + ret = get_phrt0(clkm, &val);
> + if (ret)
> + return 1;
> +
> + return val == 0x1;
> +}
> +
> +static unsigned long clk_pll_mmc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val, ext_f;
> + int ret;
> +
> + ret = get_ssc_div_n(clkm, &val);
> + if (ret)
> + return ret;
> +
> + ret = get_ssc_div_ext_f(clkm, &ext_f);
> + if (ret)
> + return ret;
> +
> + return parent_rate / 4 * (val + 2) + (parent_rate / 4 * ext_f) / 8192;
> +}
> +
> +static int clk_pll_mmc_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
> +{
Should there be a check for a parent rate of zero before the division is
done?
> + u32 val = DIV_ROUND_CLOSEST(req->rate * 4, req->best_parent_rate);
> +
> + req->rate = req->best_parent_rate * val / 4;
> + return 0;
> +}
> +
> +static int clk_pll_mmc_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate)
> +{
> + struct clk_pll_mmc *clkm = to_clk_pll_mmc(hw);
> + u32 val = PLL_MMC_SSC_DIV_N_VAL;
> + int ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK, 0x0 << PLL_FLAG_INITAL_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_n(clkm, val);
> + if (ret)
> + return ret;
> +
> + ret = set_ssc_div_ext_f(clkm, 1517);
> + if (ret)
> + return ret;
> +
> + switch (val) {
> + case 31 ... 46:
> + ret |= set_pi_ibselh(clkm, 3);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 2);
> + break;
> +
> + case 20 ... 30:
> + ret |= set_pi_ibselh(clkm, 2);
> + ret |= set_sscpll_rs(clkm, 3);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 10 ... 19:
> + ret |= set_pi_ibselh(clkm, 1);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 1);
> + break;
> +
> + case 5 ... 9:
> + ret |= set_pi_ibselh(clkm, 0);
> + ret |= set_sscpll_rs(clkm, 2);
> + ret |= set_sscpll_icp(clkm, 0);
> + break;
> + }
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_NCODE_SSC_EMMC_MASK,
> + 27 << PLL_NCODE_SSC_EMMC_SHIFT);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC3_OFFSET,
> + PLL_FCODE_SSC_EMMC_MASK, 321);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC4_OFFSET,
> + PLL_GRAN_EST_EM_MC_MASK, 5985);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x1);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_EN_SSC_EMMC_MASK, 0x0);
> + if (ret)
> + return ret;
> +
> + ret = regmap_update_bits(clkm->clkr.regmap,
> + clkm->ssc_dig_ofs + PLL_SSC_DIG_EMMC1_OFFSET,
> + PLL_FLAG_INITAL_EMMC_MASK,
> + 0x1 << PLL_FLAG_INITAL_EMMC_SHIFT);
It looks like the rate and parent rate are not used in this function.
Will this always end up with the same rate when everything is
successful?
Brian
^ permalink raw reply
* Re: [PATCH v6 06/10] clk: realtek: Add support for mux clock
From: Brian Masney @ 2026-04-03 14:54 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-7-eleanor.lin@realtek.com>
Hi Yu-Chun and Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:53PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Add a simple regmap-based clk_ops implementation for Realtek mux clocks.
>
> The implementation supports parent selection and rate determination through
> regmap-backed register access.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> ---
> drivers/clk/realtek/Makefile | 1 +
> drivers/clk/realtek/clk-regmap-mux.c | 48 ++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-regmap-mux.h | 43 +++++++++++++++++++++++++
> 3 files changed, 92 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-regmap-mux.c
> create mode 100644 drivers/clk/realtek/clk-regmap-mux.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index 74375f8127ac..f90dc57fcfdb 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -5,4 +5,5 @@ clk-rtk-y += common.o
>
> clk-rtk-y += clk-pll.o
> clk-rtk-y += clk-regmap-gate.o
> +clk-rtk-y += clk-regmap-mux.o
> clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-regmap-mux.c b/drivers/clk/realtek/clk-regmap-mux.c
> new file mode 100644
> index 000000000000..068b056d61f0
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-regmap-mux.c
> @@ -0,0 +1,48 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/clk-provider.h>
Sort the includes.
> +#include "clk-regmap-mux.h"
> +
> +static u8 clk_regmap_mux_get_parent(struct clk_hw *hw)
> +{
> + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> + int num_parents = clk_hw_get_num_parents(hw);
> + u32 val;
> + int ret;
> +
> + ret = regmap_read(clkm->clkr.regmap, clkm->mux_ofs, &val);
> + if (ret)
> + return 0;
This is another case where it'd be nice to get the get_parent
declaration fixed. Stephen recently linked to some work of his from 2022
here.
https://lore.kernel.org/linux-clk/177431305509.5403.15386021337517970667@lazor/
There's nothing for you to do right now.
> +
> + val = val >> clkm->shift & clkm->mask;
I know there's the order of operations, however for clarity I would just
include some () here to make it clear the expected order.
> +
> + if (val >= num_parents)
Remove newline before if.
> + return 0;
> +
> + return val;
Or you could just use a ternary operator:
return val >= num_parents ? 0 : val;
> +}
> +
> +static int clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index)
> +{
> + struct clk_regmap_mux *clkm = to_clk_regmap_mux(hw);
> +
> + return regmap_update_bits(clkm->clkr.regmap, clkm->mux_ofs,
> + clkm->mask << clkm->shift, index << clkm->shift);
> +}
> +
> +const struct clk_ops rtk_clk_regmap_mux_ops = {
> + .set_parent = clk_regmap_mux_set_parent,
> + .get_parent = clk_regmap_mux_get_parent,
> + .determine_rate = __clk_mux_determine_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ops, "REALTEK_CLK");
> +
> +const struct clk_ops rtk_clk_regmap_mux_ro_ops = {
> + .get_parent = clk_regmap_mux_get_parent,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_regmap_mux_ro_ops, "REALTEK_CLK");
rtk_clk_regmap_mux_ro_ops is exported, however the declaration is not actually
declared in any header files.
Brian
^ permalink raw reply
* Re: [PATCH v3 1/2] mailbox: Use per-thread completion to fix wrong completion order
From: Joonwon Kang @ 2026-04-03 14:51 UTC (permalink / raw)
To: jassisinghbrar
Cc: angelogioacchino.delregno, jonathanh, joonwonkang,
linux-arm-kernel, linux-kernel, linux-mediatek, linux-tegra,
matthias.bgg, stable, thierry.reding
In-Reply-To: <CABb+yY0ub51k-eFpPfgARXtwYjWzRSjbPDLtoMD77YQR8JH+=Q@mail.gmail.com>
> On Thu, Apr 2, 2026 at 12:07 PM Joonwon Kang <joonwonkang@google.com> wrote:
> >
> > Previously, a sender thread in mbox_send_message() could be woken up at
> > a wrong time in blocking mode. It is because there was only a single
> > completion for a channel whereas messages from multiple threads could be
> > sent in any order; since the shared completion could be signalled in any
> > order, it could wake up a wrong sender thread.
> >
> > This commit resolves the false wake-up issue with the following changes:
> > - Completions are created just as many as the number of concurrent sender
> > threads
> > - A completion is created on a sender thread's stack
> > - Each slot of the message queue, i.e. `msg_data`, contains a pointer to
> > its target completion
> > - tx_tick() signals the completion of the currently active slot of the
> > message queue
> >
> I think I reviewed it already or is this happening on
> one-channel-one-client usage? Because mailbox api does not support
> channels shared among multiple clients.
Yes, this patch is handling the one-channel-one-client usage but when that
single channel is shared between multiple threads. From my understanding, the
discussion back then ended with how to circumvent the issue rather than whether
we will eventually solve this in the mailbox framework or not, and if yes, how
we will, and if not, why. I think it should still be resolved in the framework
for the reasons in the cover letter. Could you help to give a second review
with regards to those aspects?
Thanks,
Joonwon Kang
^ permalink raw reply
* Re: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Brian Masney @ 2026-04-03 14:44 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-5-eleanor.lin@realtek.com>
Hi Cheng-Yu and Yu-Chun,
On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Provide a full set of PLL operations for programmable PLLs and a read-only
> variant for fixed or hardware-managed PLLs.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + int ret;
> +
> + fv = ftbl_find_by_rate(clkp->freq_tbl, rate);
> + if (!fv || fv->rate != rate)
> + return -EINVAL;
> +
> + if (clkp->seq_pre_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_pre_set_freq,
> + clkp->num_seq_pre_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + ret = regmap_update_bits(clkp->clkr.regmap, clkp->freq_reg,
> + clkp->freq_mask, fv->val);
> + if (ret)
> + return ret;
> +
> + if (clkp->seq_post_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_post_set_freq,
> + clkp->num_seq_post_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + if (is_power_on(clkp)) {
> + ret = wait_freq_ready(clkp);
I should have checked Sashiko before I hit send on my last review.
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
It suggested the following:
In the Common Clock Framework, .set_rate executes under the prepare_lock
mutex, while .enable and .disable execute under the enable_lock spinlock.
Could an interleaved clk_pll_enable() corrupt the hardware state by running
its seq_power_on sequence concurrently with these multi-step register
updates?
There also appears to be a potential race condition later in this function:
if (is_power_on(clkp)) {
ret = wait_freq_ready(clkp);
...
}
If .disable() powers off the PLL right before wait_freq_ready() is called,
will wait_freq_ready() poll a disabled PLL and erroneously return
-ETIMEDOUT? Is a private spinlock needed to serialize these operations?
Brian
^ permalink raw reply
* Re: [PATCH] arm64: dts: ti: k3-j721e-main: Update delay select values for MMC1/2 subsystems
From: Romain Naour @ 2026-04-03 14:42 UTC (permalink / raw)
To: Moteen Shah, devicetree, linux-arm-kernel, linux-omap
Cc: conor+dt, krzk+dt, robh, kristo, vigneshr, nm, stable
In-Reply-To: <8d4a2839-5b1e-479e-a462-dbbc3d016020@ti.com>
Hello Moteen, All,
Le 31/03/2026 à 14:19, Moteen Shah a écrit :
> Hey Romain,
>
> Thanks for the patch
>
> On 19/02/26 02:08, Romain Naour wrote:
>> The previous SPRSP36J datasheet recommends to set ti,otap-del-sel-sd-hs
>> value to 0 for MMC1 and MMC2 interfaces. These values were updated in
>> kernel 6.5. As a result we have some occasional regression with ultra
>> high speed DDR50 SDXC cards while mounting the rootfs:
>
> This error shouldn't be limited to just DDR50, were you seeing similar behavior
> with other speed modes?
I have a followup patch to enable back the SDR104 support with j721e SoC (SR 1.1
and 2.0) and I noticed the same behavior with some "specific" SDcards.
The J721e SR 1.0 doesn't support SDR104 due to an errata.
Nowadays, even the TI J721e EVM board revA (reference board) uses a SR1.1 SoC.
See the post on TI forum with further analysis:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1626659/dra829j-q1-mmcsd-ultra-high-speed-uhs-modes-issues
It turnout that the kernel is not able to detect UHS speed with some SDcards
vendors after uboot initialized them with UHS speed (SDR104). I'm not sure why.
Still, the datasheet was updated with a new set of timing values for HS and
legacy speed.
Maybe I should remove the part about SD card initialization issues, it may be
related to another issue.
>>
>> mmc1: error -110 whilst initialising SD card
>>
>> A similar issue may occur with u-boot after a reboot while
>> initialising the SD card:
>>
>> mmc_init: -110, time 67
>>
>> Update the delay values for legacy and high speed modes, based on
>> the latest revised datasheet SPRSP36K released in April 2024 [1].
>>
>> (MMC1/2 - SD/SDIO Interface): Updated/Changed the
>> "OTAPDLYENA, DELAY ENABLE" and "OTAPDLYSEL, DELAY VALUE" for the
>> Default Speed and High Speed modes from "0x0" to "0x1"
>>
>> [1] Table 6-86. MMC1/2 DLL Delay Mapping for All Timing Modes, in
>> https://www.ti.com/lit/ds/symlink/tda4vm.pdf,
>> (SPRSP36K – SEPTEMBER 2021 – REVISED APRIL 2024)
>>
>> Cc: stable@vger.kernel.org # 6.5+
>> Fixes: af398252d68e ("arm64: dts: ti: k3-j721e-main: Update delay select
>> values for MMC subsystems")
>> Signed-off-by: Romain Naour <romain.naour@smile.fr>
>> ---
>> arch/arm64/boot/dts/ti/k3-j721e-main.dtsi | 8 ++++----
>> 1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi b/arch/arm64/boot/dts/
>> ti/k3-j721e-main.dtsi
>> index d5fd30a01032..418e6010ef1f 100644
>> --- a/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
>> +++ b/arch/arm64/boot/dts/ti/k3-j721e-main.dtsi
>> @@ -1643,8 +1643,8 @@ main_sdhci1: mmc@4fb0000 {
>> clocks = <&k3_clks 92 5>, <&k3_clks 92 0>;
>> assigned-clocks = <&k3_clks 92 0>;
>> assigned-clock-parents = <&k3_clks 92 1>;
>> - ti,otap-del-sel-legacy = <0x0>;
>> - ti,otap-del-sel-sd-hs = <0x0>;
>> + ti,otap-del-sel-legacy = <0x1>;
>> + ti,otap-del-sel-sd-hs = <0x1>;
>> ti,otap-del-sel-sdr12 = <0xf>;
>> ti,otap-del-sel-sdr25 = <0xf>;
>> ti,otap-del-sel-sdr50 = <0xc>;
>> @@ -1671,8 +1671,8 @@ main_sdhci2: mmc@4f98000 {
>> clocks = <&k3_clks 93 5>, <&k3_clks 93 0>;
>> assigned-clocks = <&k3_clks 93 0>;
>> assigned-clock-parents = <&k3_clks 93 1>;
>> - ti,otap-del-sel-legacy = <0x0>;
>> - ti,otap-del-sel-sd-hs = <0x0>;
>> + ti,otap-del-sel-legacy = <0x1>;
>> + ti,otap-del-sel-sd-hs = <0x1>;
>> ti,otap-del-sel-sdr12 = <0xf>;
>> ti,otap-del-sel-sdr25 = <0xf>;
>> ti,otap-del-sel-sdr50 = <0xc>;
>
>
> Reviewed-by: Moteen Shah <m-shah@ti.com>
Thanks!
Best regards,
Romain
>
> Regards,
> Moteen
>
^ permalink raw reply
* Re: [PATCH] Subject: ASoC stm32_sai: fix incorrect BCLK polarity for DSP_A/B, LEFT_J
From: Mark Brown @ 2026-04-03 14:41 UTC (permalink / raw)
To: Tomasz Merta
Cc: alsa-devel@alsa-project.org, olivier.moysan@foss.st.com,
arnaud.pouliquen@foss.st.com, lgirdwood@gmail.com, perex@perex.cz,
tiwai@suse.com, mcoquelin.stm32@gmail.com,
alexandre.torgue@foss.st.com,
linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <SA1PR04MB8467CE79DCA58DF65FD9A798935EA@SA1PR04MB8467.namprd04.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 989 bytes --]
On Fri, Apr 03, 2026 at 02:07:52PM +0000, Tomasz Merta wrote:
> From 553c09cfa84fa801fbd8dcd5c9ae96e94a54ee31 Mon Sep 17 00:00:00 2001
>
> Tomasz Merta
> Software Engineer
> E: Tomasz.Merta@arrow.com
> Arrow Electronics | arrow.com
> From: Tomasz Merta <tomasz.merta@arrow.com>
> Date: Fri, 3 Apr 2026 10:33:11 +0200
> Subject: [PATCH] Subject: ASoC stm32_sai: fix incorrect BCLK polarity for
> DSP_A/B, LEFT_J
>
> The STM32 SAI driver do not set the clock strobing bit (CKSTR) for DSP_A,
> DSP_B and LEFT_J formats, causing data to be sampled on the wrong BCLK
> edge when SND_SOC_DAIFMT_NB_NF is used.
Your mail is pretty mangled here, there's a HTML part and the patch
appears to be appended after a signature, it looks like all the tabs got
converted into spaces too. If you're having trouble sending b4's web
submission API:
https://b4.docs.kernel.org/en/latest/contributor/send.html
bypasses your mail infrastructure which tends to make life easier.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 1/1] dt-bindings: timer: fsl,imxgpt: add compatible string fsl,imx25-epit
From: Daniel Lezcano @ 2026-04-03 14:40 UTC (permalink / raw)
To: Mark Brown
Cc: Frank Li, Daniel Lezcano, Thomas Gleixner, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam,
open list:CLOCKSOURCE, CLOCKEVENT DRIVERS,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
open list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE,
Stephen Rothwell
In-Reply-To: <3ba9e33e-8d58-469c-9c21-5861c0f6c5eb@sirena.org.uk>
On 4/3/26 13:43, Mark Brown wrote:
> On Fri, Apr 03, 2026 at 10:15:49AM +0200, Daniel Lezcano wrote:
>> On 4/3/26 10:00, Frank Li wrote:
>
>>> Can't find it at linux-next master branch, anything wrong!
>
>> The patch is in timer/next but may be linux-next disabled my branch
>
> I have a timers/drivers/next branch in your git tree in -next but
> no record of anything else. That branch was last updated on January
> 20th. If you want something else adding let me know.
No it is ok, I had a confusion in my branches. I updated the wrong one.
Now it is fixed.
Thanks
^ permalink raw reply
* Re: [PATCH v6 05/10] clk: realtek: Add support for gate clock
From: Brian Masney @ 2026-04-03 14:40 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-6-eleanor.lin@realtek.com>
Hi Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:52PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Introduce clk_regmap_gate_ops supporting enable, disable, is_enabled, and
> disable_unused for standard regmap gate clocks.
disable_unused is not implemented below.
>
> Add clk_regmap_gate_ro_ops as a read-only variant exposing only is_enabled.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> ---
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-regmap-gate.c | 69 +++++++++++++++++++++++++++
> drivers/clk/realtek/clk-regmap-gate.h | 65 +++++++++++++++++++++++++
> 3 files changed, 136 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-regmap-gate.c
> create mode 100644 drivers/clk/realtek/clk-regmap-gate.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index a89ad77993e9..74375f8127ac 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -2,5 +2,7 @@
> obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
>
> clk-rtk-y += common.o
> +
> clk-rtk-y += clk-pll.o
> +clk-rtk-y += clk-regmap-gate.o
> clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-regmap-gate.c b/drivers/clk/realtek/clk-regmap-gate.c
> new file mode 100644
> index 000000000000..8738d6c6f8dd
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-regmap-gate.c
> @@ -0,0 +1,69 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include <linux/bits.h>
> +#include "clk-regmap-gate.h"
> +#include <linux/clk-provider.h>
linux/clk-provider.h needs to be included before clk-regmap-gate.h.
Also Sashiko reports that linux/export.h should also be included.
https://sashiko.dev/#/patchset/20260402073957.2742459-1-eleanor.lin%40realtek.com
Brian
^ permalink raw reply
* Re: [PATCH v6 04/10] clk: realtek: Add support for phase locked loops (PLLs)
From: Brian Masney @ 2026-04-03 14:34 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-5-eleanor.lin@realtek.com>
Hi Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:51PM +0800, Yu-Chun Lin wrote:
> From: Cheng-Yu Lee <cylee12@realtek.com>
>
> Provide a full set of PLL operations for programmable PLLs and a read-only
> variant for fixed or hardware-managed PLLs.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Add the headers used in c file to follow the "Include What You Use" principle.
> - Move to_clk_pll() from clk-pll.h to clk-pll.c to limit its scope.
> ---
> drivers/clk/realtek/Makefile | 2 +
> drivers/clk/realtek/clk-pll.c | 164 +++++++++++++++++++++++++++++++
> drivers/clk/realtek/clk-pll.h | 42 ++++++++
> drivers/clk/realtek/freq_table.c | 36 +++++++
> drivers/clk/realtek/freq_table.h | 21 ++++
> 5 files changed, 265 insertions(+)
> create mode 100644 drivers/clk/realtek/clk-pll.c
> create mode 100644 drivers/clk/realtek/clk-pll.h
> create mode 100644 drivers/clk/realtek/freq_table.c
> create mode 100644 drivers/clk/realtek/freq_table.h
>
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> index 377ec776ee47..a89ad77993e9 100644
> --- a/drivers/clk/realtek/Makefile
> +++ b/drivers/clk/realtek/Makefile
> @@ -2,3 +2,5 @@
> obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
>
> clk-rtk-y += common.o
> +clk-rtk-y += clk-pll.o
> +clk-rtk-y += freq_table.o
> diff --git a/drivers/clk/realtek/clk-pll.c b/drivers/clk/realtek/clk-pll.c
> new file mode 100644
> index 000000000000..44730b22a94c
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll.c
> @@ -0,0 +1,164 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2024 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/regmap.h>
> +#include "clk-pll.h"
> +
> +#define TIMEOUT 2000
> +
> +static inline struct clk_pll *to_clk_pll(struct clk_hw *hw)
> +{
> + struct clk_regmap *clkr = to_clk_regmap(hw);
> +
> + return container_of(clkr, struct clk_pll, clkr);
> +}
> +
> +static int wait_freq_ready(struct clk_pll *clkp)
> +{
> + u32 pollval;
> +
> + if (!clkp->freq_ready_valid)
> + return 0;
> +
> + return regmap_read_poll_timeout_atomic(clkp->clkr.regmap, clkp->freq_ready_reg, pollval,
> + (pollval & clkp->freq_ready_mask)
> + == clkp->freq_ready_val, 0, TIMEOUT);
I would put the "(pollval & clkp->freq_ready_mask) == clkp->freq_ready_val" on
the same line to improve readability. You can go out to 100 characters.
Also should the delay be greater than 0 to avoid tons of constant
retries?
> +}
> +
> +static bool is_power_on(struct clk_pll *clkp)
> +{
> + u32 val;
> +
> + if (!clkp->power_reg)
> + return true;
> +
> + if (regmap_read(clkp->clkr.regmap, clkp->power_reg, &val))
> + return true;
Is the intention if there is an error, then it marks it as success?
> +
> + return (val & clkp->power_mask) == clkp->power_val_on;
> +}
> +
> +static void clk_pll_disable(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> +
> + if (!clkp->seq_power_off)
> + return;
> +
> + regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_power_off,
> + clkp->num_seq_power_off);
> +}
> +
> +static int clk_pll_is_enabled(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> +
> + return is_power_on(clkp);
> +}
> +
> +static int clk_pll_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *ftblv = NULL;
> +
> + ftblv = ftbl_find_by_rate(clkp->freq_tbl, req->rate);
> + if (!ftblv)
> + return -EINVAL;
> +
> + req->rate = ftblv->rate;
> + return 0;
Add newline before return.
> +}
> +
> +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + u32 freq_val;
> +
> + if (regmap_read(clkp->clkr.regmap, clkp->freq_reg, &freq_val))
> + return 0;
> +
> + freq_val &= clkp->freq_mask;
> +
> + fv = ftbl_find_by_val_with_mask(clkp->freq_tbl, clkp->freq_mask,
> + freq_val);
> + return fv ? fv->rate : 0;
Add newline before return.
> +}
> +
> +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + const struct freq_table *fv;
> + int ret;
> +
> + fv = ftbl_find_by_rate(clkp->freq_tbl, rate);
> + if (!fv || fv->rate != rate)
> + return -EINVAL;
> +
> + if (clkp->seq_pre_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_pre_set_freq,
> + clkp->num_seq_pre_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + ret = regmap_update_bits(clkp->clkr.regmap, clkp->freq_reg,
> + clkp->freq_mask, fv->val);
> + if (ret)
> + return ret;
> +
> + if (clkp->seq_post_set_freq) {
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_post_set_freq,
> + clkp->num_seq_post_set_freq);
> + if (ret)
> + return ret;
> + }
> +
> + if (is_power_on(clkp)) {
> + ret = wait_freq_ready(clkp);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int clk_pll_enable(struct clk_hw *hw)
> +{
> + struct clk_pll *clkp = to_clk_pll(hw);
> + int ret;
> +
> + if (!clkp->seq_power_on)
> + return 0;
> +
> + if (is_power_on(clkp))
> + return 0;
> +
> + ret = regmap_multi_reg_write(clkp->clkr.regmap, clkp->seq_power_on,
> + clkp->num_seq_power_on);
> + if (ret)
> + return ret;
> +
> + return wait_freq_ready(clkp);
> +}
> +
> +const struct clk_ops rtk_clk_pll_ops = {
> + .enable = clk_pll_enable,
> + .disable = clk_pll_disable,
> + .is_enabled = clk_pll_is_enabled,
> + .recalc_rate = clk_pll_recalc_rate,
> + .determine_rate = clk_pll_determine_rate,
> + .set_rate = clk_pll_set_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_ops, "REALTEK_CLK");
> +
> +const struct clk_ops rtk_clk_pll_ro_ops = {
> + .recalc_rate = clk_pll_recalc_rate,
> +};
> +EXPORT_SYMBOL_NS_GPL(rtk_clk_pll_ro_ops, "REALTEK_CLK");
> diff --git a/drivers/clk/realtek/clk-pll.h b/drivers/clk/realtek/clk-pll.h
> new file mode 100644
> index 000000000000..00884585a242
> --- /dev/null
> +++ b/drivers/clk/realtek/clk-pll.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2019 Realtek Semiconductor Corporation
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#ifndef __CLK_REALTEK_CLK_PLL_H
> +#define __CLK_REALTEK_CLK_PLL_H
> +
> +#include "common.h"
> +#include "freq_table.h"
> +
> +struct reg_sequence;
> +
> +struct clk_pll {
> + struct clk_regmap clkr;
> + const struct reg_sequence *seq_power_on;
> + u32 num_seq_power_on;
> + const struct reg_sequence *seq_power_off;
> + u32 num_seq_power_off;
> + const struct reg_sequence *seq_pre_set_freq;
> + u32 num_seq_pre_set_freq;
> + const struct reg_sequence *seq_post_set_freq;
> + u32 num_seq_post_set_freq;
> + const struct freq_table *freq_tbl;
> + u32 freq_reg;
> + u32 freq_mask;
> + u32 freq_ready_valid;
> + u32 freq_ready_mask;
> + u32 freq_ready_reg;
> + u32 freq_ready_val;
> + u32 power_reg;
> + u32 power_mask;
> + u32 power_val_on;
> +};
> +
> +#define __clk_pll_hw(_ptr) __clk_regmap_hw(&(_ptr)->clkr)
> +
> +extern const struct clk_ops rtk_clk_pll_ops;
> +extern const struct clk_ops rtk_clk_pll_ro_ops;
> +
> +#endif /* __CLK_REALTEK_CLK_PLL_H */
> diff --git a/drivers/clk/realtek/freq_table.c b/drivers/clk/realtek/freq_table.c
> new file mode 100644
> index 000000000000..272a10e75a54
> --- /dev/null
> +++ b/drivers/clk/realtek/freq_table.c
> @@ -0,0 +1,36 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +
> +#include <linux/bitops.h>
> +#include "freq_table.h"
> +
> +const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl,
> + unsigned long rate)
> +{
> + unsigned long best_rate = 0;
> + const struct freq_table *best = NULL;
Put variables in reverse Christmas tree order.
> +
> + for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> + if (ftbl->rate == rate)
> + return ftbl;
> +
> + if (ftbl->rate > rate)
> + continue;
> +
> + if (ftbl->rate > best_rate) {
> + best_rate = ftbl->rate;
> + best = ftbl;
> + }
> + }
> +
> + return best;
> +}
> +
> +const struct freq_table *
> +ftbl_find_by_val_with_mask(const struct freq_table *ftbl, u32 mask, u32 value)
> +{
> + for (; !IS_FREQ_TABLE_END(ftbl); ftbl++) {
> + if ((ftbl->val & mask) == (value & mask))
> + return ftbl;
> + }
> + return NULL;
> +};
> diff --git a/drivers/clk/realtek/freq_table.h b/drivers/clk/realtek/freq_table.h
> new file mode 100644
> index 000000000000..6d9116651105
> --- /dev/null
> +++ b/drivers/clk/realtek/freq_table.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +struct freq_table {
> + u32 val;
> + unsigned long rate;
> +};
> +
> +/* ofs check */
> +#define CLK_OFS_INVALID -1
> +#define CLK_OFS_IS_VALID(_ofs) ((_ofs) != CLK_OFS_INVALID)
Is this used anywhere?
Brian
> +
> +#define FREQ_TABLE_END \
> + { \
> + .rate = 0 \
> + }
> +#define IS_FREQ_TABLE_END(_f) ((_f)->rate == 0)
> +
> +const struct freq_table *ftbl_find_by_rate(const struct freq_table *ftbl,
> + unsigned long rate);
> +const struct freq_table *
> +ftbl_find_by_val_with_mask(const struct freq_table *ftbl, u32 mask, u32 value);
> --
> 2.34.1
>
^ permalink raw reply
* Re: [PATCH] ARM: mvebu: validate memory node device_type strings
From: Andrew Lunn @ 2026-04-03 14:31 UTC (permalink / raw)
To: Pengpeng Hou
Cc: Gregory Clement, Sebastian Hesselbarth, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260403151504.4-dt-arm-mvebu-resend-pengpeng@iscas.ac.cn>
On Fri, Apr 03, 2026 at 10:42:46AM +0800, Pengpeng Hou wrote:
> mvebu_scan_mem() fetches the raw device_type property and immediately
> compares it with strcmp(). Flat DT properties are external boot input,
> and this path does not prove that the property is NUL-terminated within
> its declared bounds.
>
> Use fdt_stringlist_get() so malformed unterminated device_type
> properties are rejected before they are used as C strings.
>
> Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
> ---
> arch/arm/mach-mvebu/board-v7.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
> index a0740ab0dca9..f867f6233108 100644
> --- a/arch/arm/mach-mvebu/board-v7.c
> +++ b/arch/arm/mach-mvebu/board-v7.c
> @@ -11,6 +11,7 @@
>
> #include <linux/kernel.h>
> #include <linux/init.h>
> +#include <linux/libfdt.h>
> #include <linux/of_address.h>
> #include <linux/of_fdt.h>
> #include <linux/io.h>
> @@ -66,7 +67,8 @@ void __iomem *mvebu_get_scu_base(void)
> static int __init mvebu_scan_mem(unsigned long node, const char *uname,
> int depth, void *data)
> {
> - const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
> + const char *type = fdt_stringlist_get(initial_boot_params, node,
> + "device_type", 0, NULL);
> const __be32 *reg, *endp;
> int l;
Did you read the comment?
/*
* When returning from suspend, the platform goes through the
* bootloader, which executes its DDR3 training code. This code has
* the unfortunate idea of using the first 10 KB of each DRAM bank to
* exercise the RAM and calculate the optimal timings. Therefore, this
* area of RAM is overwritten, and shouldn't be used by the kernel if
* suspend/resume is supported.
*/
You probably want to make use of:
* -FDT_ERR_BADVALUE if the property value is not NUL-terminated
* -FDT_ERR_NOTFOUND if the property does not exist
Andrew
^ permalink raw reply
* Re: [PATCH bpf-next v12 2/5] bpf: Pass bpf_verifier_env to JIT
From: bot+bpf-ci @ 2026-04-03 14:30 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, yonghong.song, puranjay,
a.s.protopopov, alexis.lothore, list+bpf, linux, yangtiezhu,
hengqi.chen, johan.almbladh, paulburton, hbathini, chleroy,
naveen, luke.r.nels, xi.wang, bjorn, pulehui, iii, hca, gor,
davem, udknight, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260403132811.753894-3-xukuohai@huaweicloud.com>
[-- Attachment #1: Type: text/plain, Size: 2348 bytes --]
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index cc61fe57b98d..093ab0f68c81 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> @@ -2551,47 +2528,63 @@ static bool bpf_prog_select_interpreter(struct bpf_prog *fp)
> return select_interpreter;
> }
>
> -static struct bpf_prog *bpf_prog_jit_compile(struct bpf_prog *prog)
> +static struct bpf_prog *bpf_prog_jit_compile(struct bpf_verifier_env *env, struct bpf_prog *prog)
> {
> #ifdef CONFIG_BPF_JIT
> bool blinded = false;
> struct bpf_prog *orig_prog = prog;
> + struct bpf_insn_aux_data *orig_insn_aux;
>
> if (bpf_prog_need_blind(orig_prog)) {
> + if (env) {
> + /* If env is not NULL, we are called from the end of bpf_check(), at this
> + * point, only insn_aux_data is used after failure, so we only restore it
> + * here.
> + */
> + orig_insn_aux = bpf_dup_insn_aux_data(env);
> + if (!orig_insn_aux)
> + return orig_prog;
> + }
> + prog = bpf_jit_blind_constants(env, orig_prog);
[ ... ]
> + return prog;
> +
> +out_restore:
> + bpf_restore_insn_aux_data(env, orig_insn_aux);
> +out_free:
> + kvfree(orig_insn_aux);
> #endif
> return prog;
> }
When the out_restore label is reached (blinding or JIT failure with
env != NULL), bpf_restore_insn_aux_data() sets env->insn_aux_data to
point to orig_insn_aux:
kernel/bpf/verifier.c:bpf_restore_insn_aux_data() {
vfree(env->insn_aux_data);
env->insn_aux_data = orig_insn_aux;
}
The code then falls through to the out_free label, which calls
kvfree(orig_insn_aux). This frees the memory that env->insn_aux_data
now points to, leaving it as a dangling pointer.
Since this function is called from inside bpf_check() via
__bpf_prog_select_runtime(), the subsequent cleanup in bpf_check()
accesses the freed memory:
kernel/bpf/verifier.c:bpf_check() {
...
clear_insn_aux_data(env, 0, env->prog->len);
vfree(env->insn_aux_data);
}
Could the out_restore path return directly instead of falling through
to out_free, since after the restore env now owns orig_insn_aux and
bpf_check() will free it during normal cleanup?
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/23948799625
^ permalink raw reply
* Re: [PATCH bpf-next v12 1/5] bpf: Move constants blinding out of arch-specific JITs
From: bot+bpf-ci @ 2026-04-03 14:30 UTC (permalink / raw)
To: xukuohai, bpf, linux-kernel, linux-arm-kernel
Cc: ast, daniel, andrii, martin.lau, eddyz87, yonghong.song, puranjay,
a.s.protopopov, alexis.lothore, list+bpf, linux, yangtiezhu,
hengqi.chen, johan.almbladh, paulburton, hbathini, chleroy,
naveen, luke.r.nels, xi.wang, bjorn, pulehui, iii, hca, gor,
davem, udknight, ast, andrii, daniel, martin.lau, eddyz87,
yonghong.song, clm, ihor.solodrai
In-Reply-To: <20260403132811.753894-2-xukuohai@huaweicloud.com>
[-- Attachment #1: Type: text/plain, Size: 1947 bytes --]
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index a431b7d50e1b..66cef3744fde 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
[ ... ]
> +static void restore_insn_aux_data(struct bpf_verifier_env *env,
> + struct bpf_insn_aux_data *orig_insn_aux)
> +{
> + /* the expanded elements are zero-filled, so no special handling is required */
> + vfree(env->insn_aux_data);
> + env->insn_aux_data = orig_insn_aux;
> +}
[ ... ]
> +out_restore:
> + restore_subprog_starts(env, orig_subprog_starts);
> + restore_insn_aux_data(env, orig_insn_aux);
> + kvfree(orig_subprog_starts);
> +out_free_aux:
> + kvfree(orig_insn_aux);
> +out_cleanup:
> + /* cleanup main prog to be interpreted */
> + prog->jit_requested = 0;
> + prog->blinding_requested = 0;
> + return err;
Is there a double-free of env->insn_aux_data on the out_restore path?
restore_insn_aux_data() sets env->insn_aux_data = orig_insn_aux, then
out_restore falls through to out_free_aux which does
kvfree(orig_insn_aux), freeing the just-restored pointer.
Later, bpf_check() cleanup runs:
clear_insn_aux_data(env, 0, env->prog->len);
vfree(env->insn_aux_data);
which would be a use-after-free followed by a double-free.
The out_restore path is reached when bpf_jit_blind_constants() or
__jit_subprogs() fails while blinding was active, which can happen
under memory pressure with multi-subprog BPF programs.
It looks like out_restore needs a goto out_cleanup (or similar) after
kvfree(orig_subprog_starts) to skip the out_free_aux label, since after
restoring, orig_insn_aux is owned by env->insn_aux_data and must not be
freed here.
This regression is not fixed by later commits in the series.
---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
CI run summary: https://github.com/kernel-patches/bpf/actions/runs/23948799625
^ permalink raw reply
* [PATCH 3/3] arm64: dts: broadcom: rp1: Add PWM node
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <cover.1775223441.git.andrea.porta@suse.com>
From: Stanimir Varbanov <svarbanov@suse.de>
The RP1 chipset used on the Raspberry Pi 5 features an integrated
PWM controller to drive the cooling fan.
Add the corresponding DT node for this PWM controller.
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Co-developed-by: Andrea della Porta <andrea.porta@suse.com>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 ++++++++++++
arch/arm64/boot/dts/broadcom/rp1-common.dtsi | 10 ++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
index 2856082814462..a4e5ba23bf536 100644
--- a/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
+++ b/arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
@@ -64,12 +64,24 @@ phy1: ethernet-phy@1 {
};
&rp1_gpio {
+ fan_pwm_default_state: fan-pwm-default-state {
+ function = "pwm1";
+ pins = "gpio45";
+ bias-pull-down;
+ };
+
usb_vbus_default_state: usb-vbus-default-state {
function = "vbus1";
groups = "vbus1";
};
};
+&rp1_pwm {
+ pinctrl-0 = <&fan_pwm_default_state>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
&rp1_usb0 {
pinctrl-0 = <&usb_vbus_default_state>;
pinctrl-names = "default";
diff --git a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
index 5a815c3797945..7e78501e62b0c 100644
--- a/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
+++ b/arch/arm64/boot/dts/broadcom/rp1-common.dtsi
@@ -56,6 +56,16 @@ rp1_eth: ethernet@40100000 {
#size-cells = <0>;
};
+ rp1_pwm: pwm@4009c000 {
+ compatible = "raspberrypi,rp1-pwm";
+ reg = <0x00 0x4009c000 0x0 0x100>;
+ clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clocks = <&rp1_clocks RP1_CLK_PWM1>;
+ assigned-clock-rates = <50000000>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
rp1_usb0: usb@40200000 {
compatible = "snps,dwc3";
reg = <0x00 0x40200000 0x0 0x100000>;
--
2.35.3
^ permalink raw reply related
* [PATCH 2/3] pwm: rp1: Add RP1 PWM controller driver
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <cover.1775223441.git.andrea.porta@suse.com>
From: Naushir Patuck <naush@raspberrypi.com>
The Raspberry Pi RP1 southbridge features an embedded PWM
controller with 4 output channels, alongside an RPM interface
to read the fan speed on the Raspberry Pi 5.
Add the supporting driver.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
drivers/pwm/Kconfig | 10 ++
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rp1.c | 244 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 255 insertions(+)
create mode 100644 drivers/pwm/pwm-rp1.c
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6f3147518376a..22e4fc6385da2 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -625,6 +625,16 @@ config PWM_ROCKCHIP
Generic PWM framework driver for the PWM controller found on
Rockchip SoCs.
+config PWM_RP1
+ tristate "RP1 PWM support"
+ depends on MISC_RP1 || COMPILE_TEST
+ depends on HWMON
+ help
+ PWM framework driver for Raspberry Pi RP1 controller
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-rp1.
+
config PWM_SAMSUNG
tristate "Samsung PWM support"
depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025d..895a7c42fe9c0 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -56,6 +56,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT) += pwm-rzg2l-gpt.o
obj-$(CONFIG_PWM_RENESAS_RZ_MTU3) += pwm-rz-mtu3.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
+obj-$(CONFIG_PWM_RP1) += pwm-rp1.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c
new file mode 100644
index 0000000000000..0a1c1c1dd27e9
--- /dev/null
+++ b/drivers/pwm/pwm-rp1.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * pwm-rp1.c
+ *
+ * Raspberry Pi RP1 PWM.
+ *
+ * Copyright © 2026 Raspberry Pi Ltd.
+ *
+ * Author: Naushir Patuck (naush@raspberrypi.com)
+ *
+ * Based on the pwm-bcm2835 driver by:
+ * Bart Tanghe <bart.tanghe@thomasmore.be>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define PWM_GLOBAL_CTRL 0x000
+#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 0x10))
+#define PWM_RANGE(x) (0x018 + ((x) * 0x10))
+#define PWM_PHASE(x) (0x01C + ((x) * 0x10))
+#define PWM_DUTY(x) (0x020 + ((x) * 0x10))
+
+/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */
+#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0))
+#define PWM_CHANNEL_ENABLE(x) BIT(x)
+#define PWM_POLARITY BIT(3)
+#define SET_UPDATE BIT(31)
+#define PWM_MODE_MASK GENMASK(1, 0)
+
+#define NUM_PWMS 4
+
+struct rp1_pwm {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static const struct hwmon_channel_info * const rp1_fan_hwmon_info[] = {
+ HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
+ NULL
+};
+
+static umode_t rp1_fan_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
+ u32 attr, int channel)
+{
+ umode_t mode = 0;
+
+ if (type == hwmon_fan && attr == hwmon_fan_input)
+ mode = 0444;
+
+ return mode;
+}
+
+static int rp1_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *val)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ if (type != hwmon_fan || attr != hwmon_fan_input)
+ return -EOPNOTSUPP;
+
+ *val = readl(rp1->base + PWM_PHASE(2));
+
+ return 0;
+}
+
+static const struct hwmon_ops rp1_fan_hwmon_ops = {
+ .is_visible = rp1_fan_hwmon_is_visible,
+ .read = rp1_fan_hwmon_read,
+};
+
+static const struct hwmon_chip_info rp1_fan_hwmon_chip_info = {
+ .ops = &rp1_fan_hwmon_ops,
+ .info = rp1_fan_hwmon_info,
+};
+
+static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u32 value;
+
+ value = readl(rp1->base + PWM_GLOBAL_CTRL);
+ value |= SET_UPDATE;
+ writel(value, rp1->base + PWM_GLOBAL_CTRL);
+}
+
+static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+
+ writel(PWM_CHANNEL_DEFAULT, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ return 0;
+}
+
+static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ u32 value;
+
+ value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ value &= ~PWM_MODE_MASK;
+ writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+
+ rp1_pwm_apply_config(chip, pwm);
+}
+
+static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
+ const struct pwm_state *state)
+{
+ struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
+ unsigned long clk_rate = clk_get_rate(rp1->clk);
+ unsigned long clk_period;
+ u32 value;
+
+ if (!clk_rate) {
+ dev_err(&chip->dev, "failed to get clock rate\n");
+ return -EINVAL;
+ }
+
+ /* set period and duty cycle */
+ clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);
+
+ writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),
+ rp1->base + PWM_DUTY(pwm->hwpwm));
+
+ writel(DIV_ROUND_CLOSEST(state->period, clk_period),
+ rp1->base + PWM_RANGE(pwm->hwpwm));
+
+ /* set polarity */
+ value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+ if (state->polarity == PWM_POLARITY_NORMAL)
+ value &= ~PWM_POLARITY;
+ else
+ value |= PWM_POLARITY;
+ writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
+
+ /* enable/disable */
+ value = readl(rp1->base + PWM_GLOBAL_CTRL);
+ if (state->enabled)
+ value |= PWM_CHANNEL_ENABLE(pwm->hwpwm);
+ else
+ value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);
+ writel(value, rp1->base + PWM_GLOBAL_CTRL);
+
+ rp1_pwm_apply_config(chip, pwm);
+
+ return 0;
+}
+
+static const struct pwm_ops rp1_pwm_ops = {
+ .request = rp1_pwm_request,
+ .free = rp1_pwm_free,
+ .apply = rp1_pwm_apply,
+};
+
+static int rp1_pwm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device *hwmon_dev;
+ struct pwm_chip *chip;
+ struct rp1_pwm *rp1;
+ int ret;
+
+ chip = devm_pwmchip_alloc(dev, NUM_PWMS, sizeof(*rp1));
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ rp1 = pwmchip_get_drvdata(chip);
+
+ rp1->base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(rp1->base))
+ return PTR_ERR(rp1->base);
+
+ rp1->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(rp1->clk))
+ return dev_err_probe(dev, PTR_ERR(rp1->clk), "clock not found\n");
+
+ ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
+ if (ret)
+ return dev_err_probe(dev, ret, "fail to get exclusive rate\n");
+
+ chip->ops = &rp1_pwm_ops;
+
+ platform_set_drvdata(pdev, chip);
+
+ ret = devm_pwmchip_add(dev, chip);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register PWM chip\n");
+
+ hwmon_dev = devm_hwmon_device_register_with_info(dev, "rp1_fan_tach", rp1,
+ &rp1_fan_hwmon_chip_info,
+ NULL);
+
+ if (IS_ERR(hwmon_dev))
+ return dev_err_probe(dev, PTR_ERR(hwmon_dev),
+ "failed to register hwmon fan device\n");
+
+ return 0;
+}
+
+static int rp1_pwm_suspend(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(rp1->clk);
+
+ return 0;
+}
+
+static int rp1_pwm_resume(struct device *dev)
+{
+ struct rp1_pwm *rp1 = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(rp1->clk);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(rp1_pwm_pm_ops, rp1_pwm_suspend, rp1_pwm_resume);
+
+static const struct of_device_id rp1_pwm_of_match[] = {
+ { .compatible = "raspberrypi,rp1-pwm" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
+
+static struct platform_driver rp1_pwm_driver = {
+ .probe = rp1_pwm_probe,
+ .driver = {
+ .name = "rp1-pwm",
+ .of_match_table = rp1_pwm_of_match,
+ .pm = pm_ptr(&rp1_pwm_pm_ops),
+ },
+};
+module_platform_driver(rp1_pwm_driver);
+
+MODULE_DESCRIPTION("RP1 PWM driver");
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
+MODULE_LICENSE("GPL");
--
2.35.3
^ permalink raw reply related
* [PATCH 1/3] dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <cover.1775223441.git.andrea.porta@suse.com>
From: Naushir Patuck <naush@raspberrypi.com>
Add the devicetree binding documentation for the PWM
controller found in the Raspberry Pi RP1 chipset.
Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
---
.../bindings/pwm/raspberrypi,rp1-pwm.yaml | 52 +++++++++++++++++++
1 file changed, 52 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
diff --git a/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml b/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
new file mode 100644
index 0000000000000..d6b3f52561636
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pwm/raspberrypi,rp1-pwm.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi RP1 PWM controller
+
+maintainers:
+ - Naushir Patuck <naush@raspberrypi.com>
+
+allOf:
+ - $ref: pwm.yaml#
+
+description: |
+ The PWM peripheral is a flexible waveform generator with a
+ variety of operational modes. It has the following features:
+ - four independent output channels
+ - 32-bit counter widths
+ - Seven output generation modes
+ - Optional per-channel output inversion
+ - Optional duty-cycle data FIFO with DMA support
+ - Optional sigma-delta noise shaping engine
+
+properties:
+ compatible:
+ const: raspberrypi,rp1-pwm
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ "#pwm-cells":
+ const: 3
+
+required:
+ - compatible
+ - reg
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ pwm@98000 {
+ compatible = "raspberrypi,rp1-pwm";
+ reg = <0x98000 0x100>;
+ clocks = <&rp1_clocks 17>;
+ #pwm-cells = <3>;
+ };
--
2.35.3
^ permalink raw reply related
* [PATCH 0/3] Add RP1 PWM controller support
From: Andrea della Porta @ 2026-04-03 14:31 UTC (permalink / raw)
To: Uwe Kleine-König, linux-pwm, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Florian Fainelli,
Broadcom internal kernel review list, Andrea della Porta,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
This patchset adds support for the PWM controller found on the
Raspberry Pi RP1 southbridge. This is necessary to operate the
cooling fan connected to one of the PWM channels.
The tachometer pin for the fan speed is managed by the firmware
running on the RP1's M-core. It uses the PHASE2 register
to report the RPM, which is then exported by this driver as a
hwmon device.
Subsequent patches will add the CPU thermal zone, which acts as
a consumer of the PWM device.
Best regards,
Andrea
Naushir Patuck (2):
dt-bindings: pwm: Add Raspberry Pi RP1 PWM controller
pwm: rp1: Add RP1 PWM controller driver
Stanimir Varbanov (1):
arm64: dts: broadcom: rp1: Add PWM node
.../bindings/pwm/raspberrypi,rp1-pwm.yaml | 52 ++++
.../boot/dts/broadcom/bcm2712-rpi-5-b.dts | 12 +
arch/arm64/boot/dts/broadcom/rp1-common.dtsi | 10 +
drivers/pwm/Kconfig | 10 +
drivers/pwm/Makefile | 1 +
drivers/pwm/pwm-rp1.c | 244 ++++++++++++++++++
6 files changed, 329 insertions(+)
create mode 100644 Documentation/devicetree/bindings/pwm/raspberrypi,rp1-pwm.yaml
create mode 100644 drivers/pwm/pwm-rp1.c
--
2.35.3
^ permalink raw reply
* Re: [PATCH v6 03/10] clk: realtek: Introduce a common probe()
From: Brian Masney @ 2026-04-03 14:21 UTC (permalink / raw)
To: Yu-Chun Lin
Cc: mturquette, sboyd, robh, krzk+dt, conor+dt, p.zabel, cylee12,
afaerber, jyanchou, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-realtek-soc, james.tai, cy.huang,
stanley_chang
In-Reply-To: <20260402073957.2742459-4-eleanor.lin@realtek.com>
Hi Cheng-Yu,
On Thu, Apr 02, 2026 at 03:39:50PM +0800, Cheng-Yu Lee wrote:
> Add rtk_clk_probe() to set up the shared regmap, register clock hardware,
> and add the clock provider.
>
> Additionally, if the "#reset-cells" property is present in the device tree,
> it creates and registers an auxiliary device using the provided aux_name.
> This allows the dedicated reset driver to bind to this device, enabling
> both clock and reset drivers to share the same regmap.
>
> Signed-off-by: Cheng-Yu Lee <cylee12@realtek.com>
> Co-developed-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> Signed-off-by: Yu-Chun Lin <eleanor.lin@realtek.com>
> ---
> Changes in v6:
> - Replace direct reset controller initialization with auxiliary device creation.
> - Add aux_name parameter to rtk_clk_probe() to register the reset auxiliary device.
> - Simplify rtk_clk_desc because reset data is handled entirely by the auxiliary reset driver.
> - In Kconfig, change "depends on RESET_CONTROLLER" to "select RESET_CONTROLLER"
> - Remove unused includes headers and added <linux/auxiliary_bus.h>.
> ---
> MAINTAINERS | 1 +
> drivers/clk/Kconfig | 1 +
> drivers/clk/Makefile | 1 +
> drivers/clk/realtek/Kconfig | 28 +++++++++++++++
> drivers/clk/realtek/Makefile | 4 +++
> drivers/clk/realtek/common.c | 67 ++++++++++++++++++++++++++++++++++++
> drivers/clk/realtek/common.h | 37 ++++++++++++++++++++
> 7 files changed, 139 insertions(+)
> create mode 100644 drivers/clk/realtek/Kconfig
> create mode 100644 drivers/clk/realtek/Makefile
> create mode 100644 drivers/clk/realtek/common.c
> create mode 100644 drivers/clk/realtek/common.h
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8f355896583b..8318156a02b5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22240,6 +22240,7 @@ L: devicetree@vger.kernel.org
> L: linux-clk@vger.kernel.org
> S: Supported
> F: Documentation/devicetree/bindings/clock/realtek*
> +F: drivers/clk/realtek/*
> F: drivers/reset/realtek/*
> F: include/dt-bindings/clock/realtek*
> F: include/dt-bindings/reset/realtek*
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 3d803b4cf5c1..d60f6415b0a3 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -519,6 +519,7 @@ source "drivers/clk/nuvoton/Kconfig"
> source "drivers/clk/pistachio/Kconfig"
> source "drivers/clk/qcom/Kconfig"
> source "drivers/clk/ralink/Kconfig"
> +source "drivers/clk/realtek/Kconfig"
> source "drivers/clk/renesas/Kconfig"
> source "drivers/clk/rockchip/Kconfig"
> source "drivers/clk/samsung/Kconfig"
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index f7bce3951a30..69b84d1e7bcc 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -140,6 +140,7 @@ obj-$(CONFIG_COMMON_CLK_PISTACHIO) += pistachio/
> obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
> obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
> obj-y += ralink/
> +obj-$(CONFIG_COMMON_CLK_REALTEK) += realtek/
> obj-y += renesas/
> obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
> obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/
> diff --git a/drivers/clk/realtek/Kconfig b/drivers/clk/realtek/Kconfig
> new file mode 100644
> index 000000000000..bc47d3f1c452
> --- /dev/null
> +++ b/drivers/clk/realtek/Kconfig
> @@ -0,0 +1,28 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +config COMMON_CLK_REALTEK
> + bool "Clock driver for Realtek SoCs"
> + depends on ARCH_REALTEK || COMPILE_TEST
> + default ARCH_REALTEK
> + help
> + Enable the common clock framework infrastructure for Realtek
> + system-on-chip platforms.
> +
> + This provides the base support required by individual Realtek
> + clock controller drivers to expose clocks to peripheral devices.
> +
> + If you have a Realtek-based platform, say Y.
> +
> +if COMMON_CLK_REALTEK
> +
> +config RTK_CLK_COMMON
> + tristate "Realtek Clock Common"
> + select RESET_CONTROLLER
> + select RESET_RTK_COMMON
select AUXILIARY_BUS ?
> + help
> + Common helper code shared by Realtek clock controller drivers.
> +
> + This provides utility functions and data structures used by
> + multiple Realtek clock implementations, and include integration
> + with reset controllers where required.
> +
> +endif
> diff --git a/drivers/clk/realtek/Makefile b/drivers/clk/realtek/Makefile
> new file mode 100644
> index 000000000000..377ec776ee47
> --- /dev/null
> +++ b/drivers/clk/realtek/Makefile
> @@ -0,0 +1,4 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +obj-$(CONFIG_RTK_CLK_COMMON) += clk-rtk.o
> +
> +clk-rtk-y += common.o
> diff --git a/drivers/clk/realtek/common.c b/drivers/clk/realtek/common.c
> new file mode 100644
> index 000000000000..c5aea15a3714
> --- /dev/null
> +++ b/drivers/clk/realtek/common.c
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2019 Realtek Semiconductor Corporation
If you are making changes here, should the copyrights be updated to
include 2026?
> + * Author: Cheng-Yu Lee <cylee12@realtek.com>
> + */
> +
> +#include <linux/auxiliary_bus.h>
> +#include <linux/device.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include "common.h"
> +
> +static int rtk_reset_controller_register(struct device *dev, const char *aux_name)
> +{
> + struct auxiliary_device *adev;
> +
> + if (!of_property_present(dev->of_node, "#reset-cells"))
> + return 0;
> +
> + adev = devm_auxiliary_device_create(dev, aux_name, NULL);
> +
> + if (IS_ERR(adev))
> + return PTR_ERR(adev);
> + return 0;
Add newline before return.
> +}
> +
> +int rtk_clk_probe(struct platform_device *pdev, const struct rtk_clk_desc *desc,
> + const char *aux_name)
> +{
> + int i, ret;
> + struct regmap *regmap;
> + struct device *dev = &pdev->dev;
Put variables in reverse Christmas tree order.
> +
> + regmap = device_node_to_regmap(pdev->dev.of_node);
> + if (IS_ERR(regmap))
> + return dev_err_probe(dev, PTR_ERR(regmap), "failed to get regmap\n");
> +
> + for (i = 0; i < desc->num_clks; i++)
> + desc->clks[i]->regmap = regmap;
> +
> + for (i = 0; i < desc->clk_data->num; i++) {
> + struct clk_hw *hw = desc->clk_data->hws[i];
> +
> + if (!hw)
> + continue;
> +
> + ret = devm_clk_hw_register(dev, hw);
> +
> + if (ret) {
Remove newline before if.
> + dev_warn(dev, "failed to register hw of clk%d: %d\n", i,
> + ret);
> + desc->clk_data->hws[i] = NULL;
This chunk doesn't take into account probe deferrals.
Brian
^ permalink raw reply
* Re: [PATCH v8 08/10] ASoC: mediatek: mt8196: add platform driver
From: Mark Brown @ 2026-04-03 14:07 UTC (permalink / raw)
To: Cyril Chao
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Matthias Brugger, AngeloGioacchino Del Regno, Jaroslav Kysela,
Takashi Iwai, linux-sound, devicetree, linux-kernel,
linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, Darren Ye
In-Reply-To: <20260324015719.17543-9-Cyril.Chao@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 636 bytes --]
On Tue, Mar 24, 2026 at 09:56:49AM +0800, Cyril Chao wrote:
> +static int mt8196_set_cm(struct mtk_base_afe *afe, int id,
> + bool update, bool swap, unsigned int ch)
> +{
> + struct mt8196_afe_private *afe_priv = afe->platform_priv;
> + unsigned int rate = afe_priv->cm_rate[id];
> + unsigned int rate_val = mt8196_rate_transform(afe->dev, rate);
> + unsigned int update_val = update ? ((((26000000 / rate) - 10) / (ch / 2)) - 1) : 0x64;
> + int reg = AFE_CM0_CON0 + 0x10 * id;
The driver looks like it supports mono so won't this trigger divide by
zero?
Also please write normal conditional statements, it's much more
leigible.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH] iommu/rockchip: fix page table allocation flags for v2 IOMMU
From: Midgy Balon @ 2026-04-03 14:02 UTC (permalink / raw)
To: Simon Xue
Cc: Jonas Karlman, iommu, joro, will, robin.murphy, Heiko Stuebner,
linux-arm-kernel, linux-rockchip, linux-kernel, stable
In-Reply-To: <5663593b-2c53-4632-ad2c-db9efa8e9ab2@rock-chips.com>
From: Midgy BALON <midgy971@gmail.com>
To: Simon Xue <xxm@rock-chips.com>
Cc: Jonas Karlman <jonas@kwiboo.se>, iommu@lists.linux.dev,
joro@8bytes.org, will@kernel.org, robin.murphy@arm.com,
heiko@sntech.de, linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org,
stable@vger.kernel.org
In-Reply-To: <5663593b-2c53-4632-ad2c-db9efa8e9ab2@rock-chips.com>
References: <20260331075010.1463-1-midgy971@gmail.com>
<0f285782-b12a-4abd-bca7-b6c549bed59f@rock-chips.com>
<e622cc9e-8fb0-454a-b88e-dc13cf2ff507@kwiboo.se>
<89ed223d-1a2c-447d-9f21-76969e668855@rock-chips.com>
<5663593b-2c53-4632-ad2c-db9efa8e9ab2@rock-chips.com>
Subject: Re: [PATCH] iommu/rockchip: fix page table allocation flags
for v2 IOMMU
On 4/3/2026, Simon Xue wrote:
> We internally checked that the RK356x SoCs integrate two different
> IOMMU versions (v1.0 and v2.0), like NPU and ISP use the v1.0 IOMMU.
>
> Both versions can map 40-bit physical pages, but v1.0 does not support
> placing the first-level page table above 4 GB.
>
> To fix this, I think we need to land this patch first:
> https://lore.kernel.org/all/20260310105303.128859-1-xxm@rock-chips.com/
>
> Then on top of that, we can add a new compatible string to distinguish
> the IOMMU versions.
Thank you Simon and Jonas for the internal investigation. This explains
exactly what I observed.
To answer Simon's earlier question: the IP block hitting both failure
modes is the NPU IOMMU (rknpu_mmu, at 0xfde4b000), currently bound
to "rockchip,rk3568-iommu" in rk356x-base.dtsi. Both the downstream
rknpu driver and the upstream Rocket accel driver (drivers/accel/rocket/)
use this IOMMU.
The v1.0 first-level page table constraint explains both failure modes.
On boards with more than 4 GB of RAM the DTE table can be allocated
above 0x100000000, and the v1.0 hardware silently truncates or errors
on that address. The SWIOTLB bounce-buffer path is a consequence of
the same root cause: with DMA_BIT_MASK(32) on the NPU device, bounce
buffers land below 4 GB, phys_to_virt() of the bounce address is then
used as the PTE write target, and the subsequent
dma_sync_single_for_device(DMA_TO_DEVICE) overwrites those PTEs with
zeros from the original buffer.
Please consider my original patch withdrawn. Modifying iommu_data_ops_v2
was too broad and would have incorrectly constrained VOP2 MMU and all
other v2 IOMMU users.
I agree fully with the two-step approach. On top of your per-device-ops
patch [1], I plan to send:
[1/2] iommu/rockchip: Add "rockchip,rk3568-iommu-v1" compatible
for IOMMU v1.0 blocks (NPU, ISP/VICAP) on RK3568
— ops with .gfp_flags = GFP_DMA32,
.dma_bit_mask = DMA_BIT_MASK(40)
(v1.0 can still map 40-bit physical pages; only the DTE
table base must be below 4 GB)
[2/2] arm64: dts: rockchip: rk356x: Use "rockchip,rk3568-iommu-v1"
for rknpu_mmu (0xfde4b000) and vicap_mmu (0xfdfe0800)
One note on the SWIOTLB issue: with GFP_DMA32 in the new ops, page
table allocations never reach SWIOTLB, so the "track L2 base addresses"
approach you suggested should not be necessary — GFP_DMA32 prevents the
bounce-buffer poisoning at the source. Happy to be corrected if there
is another path where it is still needed.
I am happy to add Tested-by to your per-device-ops patch [1].
[1] https://lore.kernel.org/all/20260310105303.128859-1-xxm@rock-chips.com/
Regards,
Midgy BALON
Le ven. 3 avr. 2026 à 06:40, Simon Xue <xxm@rock-chips.com> a écrit :
>
>
> 在 2026/4/1 18:22, Simon Xue 写道:
> > Hi Jonas,
> >
> > 在 2026/4/1 16:41, Jonas Karlman 写道:
> >> Hi Simon,
> >>
> >> On 4/1/2026 9:48 AM, Simon wrote:
> >>> Hi Midgy,
> >>>
> >>> 在 2026/3/31 15:50, Midgy BALON 写道:
> >>>> commit 2a7e6400f72b ("iommu: rockchip: Allocate tables from all
> >>>> available memory for IOMMU v2") removed GFP_DMA32 from
> >>>> iommu_data_ops_v2, reasoning that RK356x and RK3588 IOMMU v2 hardware
> >>>> supports up to 40-bit physical addresses for page tables. However, the
> >>>> RK3568 IOMMU page-table walker uses a 32-bit AXI bus: it cannot access
> >>>> physical addresses above 4 GB regardless of the address encoding
> >>>> range.
> >>>>
> >>>> On boards with more than 4 GB of RAM (e.g. 8 GB LPDDR4X), removing
> >>>> GFP_DMA32 causes two distinct failure modes:
> >>>>
> >>>> 1. Direct allocation above 4 GB: iommu_alloc_pages_sz() may return
> >>>> memory above 0x100000000. The hardware page-table walker
> >>>> issues a
> >>>> bus error trying to dereference those addresses, causing an IOMMU
> >>>> fault on the first DMA transaction.
> >>> Which IP block is hitting this? We'd like to take a look on our end.
> >> I have seen reports that the NPU MMU on RK3568/RK3566 is having some
> >> issue using DTE/PTE with >32-bit addresses, maybe it uses a different
> >> MMU hw revision or has some hw errata?
> >>
> >> From my own testing at least the VOP2 MMU on RK3568 (and RK3588) was
> >> able to handle 40-bit addressable DTE/PTE, hence the original commit
> >> 2a7e6400f72b ("iommu: rockchip: Allocate tables from all available
> >> memory for IOMMU v2").
> >>
> >> As also mentioned in my reply at [1], maybe the NPU MMU has some hw
> >> limitation or errata and may need to use a different compatible.
> >
> > Yes, We are checking internally whether different IOMMU versions
> > integrated.
> >
> > I will share what we find once we have results.
> >
> We internally checked that the RK356x SoCs integrate two different IOMMU
> versions (v1.0 and v2.0), like NPU and ISP use the v1.0 IOMMU.
>
> Both versions can map 40-bit physical pages, but v1.0 does not support
> placing the first-level page table above 4 GB.
>
> To fix this, I think we need to land this patch first:
> https://lore.kernel.org/all/20260310105303.128859-1-xxm@rock-chips.com/
>
> Then on top of that, we can add a new compatible string to distinguish
> the IOMMU versions.
>
> >> [1]
> >> https://lore.kernel.org/r/3cd63b3d-1c5e-4a11-856e-c4aeb5d97d55@kwiboo.se/
> >>
> >> Regards,
> >> Jonas
> >>
> >>>> 2. SWIOTLB bounce-buffer poisoning: without GFP_DMA32, page tables
> >>>> land
> >>>> above the SWIOTLB window. dma_map_single() with DMA_BIT_MASK(32)
> >>>> then bounces them into a buffer below 4 GB.
> >>>> rk_dte_get_page_table()
> >>>> returns phys_to_virt() of the bounce buffer address; PTEs are
> >>>> written
> >>>> there; the next dma_sync_single_for_device(DMA_TO_DEVICE)
> >>>> copies the
> >>>> original (zero) data back over the bounce buffer, silently
> >>>> erasing the
> >>>> freshly written PTEs. The IOMMU faults because every PTE
> >>>> reads as zero.
> >>> This probably need a separate patch. One way to fix it would be to
> >>> track the
> >>> original L2 page table base addresses in struct rk_iommu_domain,
> >>> then have rk_dte_get_page_table() return the tracked address instead of
> >>> deriving it from the DTE.
> >>>
> >>>> Restore GFP_DMA32 (and DMA_BIT_MASK(32)) for iommu_data_ops_v2, which
> >>>> currently only serves "rockchip,rk3568-iommu" in mainline.
> >>>>
> >>>> Tested on Radxa ROCK 3B (RK3568, 8 GB LPDDR4X):
> >>>> - MobileNetV1 via RKNN: 5.8 ms/inference (IOMMU mode)
> >>>> - YOLOv5s 640x640 via RKNN: ~57 ms/inference (IOMMU mode)
> >>>> - No IOMMU faults, correct inference results
> >>>>
> >>>> Fixes: 2a7e6400f72b ("iommu: rockchip: Allocate tables from all
> >>>> available memory for IOMMU v2")
> >>>> Cc: stable@vger.kernel.org
> >>>> Cc: Jonas Karlman <jonas@kwiboo.se>
> >>>> Signed-off-by: Midgy BALON <midgy971@gmail.com>
> >>>> ---
> >>>> drivers/iommu/rockchip-iommu.c | 4 ++--
> >>>> 1 file changed, 2 insertions(+), 2 deletions(-)
> >>>>
> >>>> diff --git a/drivers/iommu/rockchip-iommu.c
> >>>> b/drivers/iommu/rockchip-iommu.c
> >>>> index 85f3667e797..8b45db29471 100644
> >>>> --- a/drivers/iommu/rockchip-iommu.c
> >>>> +++ b/drivers/iommu/rockchip-iommu.c
> >>>> @@ -1358,8 +1358,8 @@ static struct rk_iommu_ops iommu_data_ops_v2 = {
> >>>> .pt_address = &rk_dte_pt_address_v2,
> >>>> .mk_dtentries = &rk_mk_dte_v2,
> >>>> .mk_ptentries = &rk_mk_pte_v2,
> >>>> - .dma_bit_mask = DMA_BIT_MASK(40),
> >>>> - .gfp_flags = 0,
> >>>> + .dma_bit_mask = DMA_BIT_MASK(32),
> >>>> + .gfp_flags = GFP_DMA32,
> >>>> };
> >>>> static const struct of_device_id rk_iommu_dt_ids[] = {
> >>
^ permalink raw reply
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