* Re: (subset) [PATCH v8 1/4] dt-bindings: backlight: Add max25014 support
From: Frank Li @ 2026-05-20 14:38 UTC (permalink / raw)
To: Lee Jones
Cc: Daniel Thompson, Jingoo Han, Pavel Machek, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Helge Deller, Shawn Guo,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Liam Girdwood, Mark Brown, Maud Spierings, dri-devel, linux-leds,
devicetree, linux-kernel, linux-fbdev, imx, linux-arm-kernel
In-Reply-To: <20260520114745.GX305027@google.com>
On Wed, May 20, 2026 at 12:47:45PM +0100, Lee Jones wrote:
> On Tue, 19 May 2026, Frank Li wrote:
>
> > On Thu, Apr 30, 2026 at 02:53:40PM +0100, Lee Jones wrote:
> > > On Tue, 07 Apr 2026 16:41:42 +0200, Maud Spierings wrote:
> > > > The Maxim MAX25014 is a 4-channel automotive grade backlight driver IC
> > > > with integrated boost controller.
> > >
> > > Applied, thanks!
> > >
> > > [1/4] dt-bindings: backlight: Add max25014 support
> > > commit: 5fcbbedec9dfce78044eee922bf2030e1bd03faa
> >
> > Lee Jones:
> >
> > I have not seen it in linux-next. Anything wrong?
>
> I don't know why Backlight hasn't been added to Linux Next.
>
> Rest assured, it's applied to the Backlight tree.
Thank, you'd better check with Mark brown to make sure it is merged into
linux-next because linux-next will do many checking and build works.
Frank
>
> --
> Lee Jones
^ permalink raw reply
* Re: (subset) [PATCH 1/9] dt-bindings: mfd: mediatek: mt6397: Add rtc for MT6359
From: Lee Jones @ 2026-05-20 14:40 UTC (permalink / raw)
To: Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Dmitry Torokhov, Chen Zhong,
Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Louis-Alexis Eyraud
Cc: kernel, linux-pm, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-input, linux-iio
In-Reply-To: <20260429-mediatek-genio-mt6365-cleanup-v1-1-6f43838be92f@collabora.com>
On Wed, 29 Apr 2026 11:44:14 +0200, Louis-Alexis Eyraud wrote:
> The rtc block of MT6359 PMIC is compatible with the one found in MT6358
> but this compatibility was never expressed in the dt-bindings, so add
> the missing compatible string for the rtc subnode.
Applied, thanks!
[1/9] dt-bindings: mfd: mediatek: mt6397: Add rtc for MT6359
commit: 4edf75f835bad0b7e7ac022594b129f9dbf8698c
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: (subset) [PATCH 2/9] dt-bindings: mfd: mediatek: mt6397: Add MT6365 PMIC support
From: Lee Jones @ 2026-05-20 14:41 UTC (permalink / raw)
To: Sen Chu, Sean Wang, Macpaul Lin, Lee Jones, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Dmitry Torokhov, Chen Zhong,
Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Louis-Alexis Eyraud
Cc: kernel, linux-pm, devicetree, linux-kernel, linux-arm-kernel,
linux-mediatek, linux-input, linux-iio
In-Reply-To: <20260429-mediatek-genio-mt6365-cleanup-v1-2-6f43838be92f@collabora.com>
On Wed, 29 Apr 2026 11:44:15 +0200, Louis-Alexis Eyraud wrote:
> MT6365 PMIC is compatible with MT6359, so add the compatible strings
> for the main and sub devices (regulator, rtc, audio codec).
Applied, thanks!
[2/9] dt-bindings: mfd: mediatek: mt6397: Add MT6365 PMIC support
commit: 5a7c6466133eee4370995ad5ccf4c377011a381e
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH v9 2/3] dt-bindings: mfd: aspeed,ast2x00-scu: Describe AST2700 SCU0
From: Lee Jones @ 2026-05-20 14:43 UTC (permalink / raw)
To: Linus Walleij
Cc: Billy Tsai, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley, Andrew Jeffery, Bartosz Golaszewski, Ryan Chen,
Andrew Jeffery, devicetree, linux-arm-kernel, linux-aspeed,
linux-kernel, openbmc, linux-gpio, linux-clk
In-Reply-To: <CAD++jL=3p9BvDgaot3=emM4Zn5jU-ZAUKtB4UwT1HzDiyzKq4Q@mail.gmail.com>
On Mon, 11 May 2026, Linus Walleij wrote:
> On Wed, May 6, 2026 at 10:07 AM Billy Tsai <billy_tsai@aspeedtech.com> wrote:
>
> > AST2700 consists of two interconnected SoC instances, each with its own
> > System Control Unit (SCU). The SCU0 provides pin control, interrupt
> > controllers, clocks, resets, and address-space mappings for the
> > Secondary and Tertiary Service Processors (SSP and TSP).
> >
> > Describe the SSP/TSP address mappings using the standard
> > memory-region and memory-region-names properties.
> >
> > Disallow legacy child nodes that are not present on AST2700, including
> > p2a-control and smp-memram. The latter is unnecessary as software can
> > access the scratch registers via the SCU syscon.
> >
> > Also allow the AST2700 SoC0 pin controller to be described as a child
> > node of the SCU0, and add an example illustrating the SCU0 layout,
> > including reserved-memory, interrupt controllers, and pinctrl.
> >
> > Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
> > Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
>
> This is an MFD patch in the middle of a pinctrl series, I think Lee
> should apply this.
> FWIW:
> Acked-by: Linus Walleij <linusw@kernel.org>
Already applied v8.
--
Lee Jones
^ permalink raw reply
* [PATCH v2 0/8] hdmi: Add common TMDS character rate constants
From: Javier Martinez Canillas @ 2026-05-20 14:43 UTC (permalink / raw)
To: linux-kernel
Cc: Javier Martinez Canillas, Abhinav Kumar, Alain Volmat,
Andrzej Hajda, Andy Yan, Brian Masney, Chen-Yu Tsai, Chris Morgan,
Cristian Ciocaltea, Daniel Stone, David Airlie, Dmitry Baryshkov,
Dmitry Baryshkov, Heiko Stuebner, Jani Nikula, Jernej Skrabec,
Jessica Zhang, Jonas Karlman, Konrad Dybcio, Laurent Pinchart,
Liu Ying, Luca Ceresoli, Maarten Lankhorst, Marijn Suijten,
Maxime Ripard, Neil Armstrong, Raphael Gallais-Pou, Rob Clark,
Robert Foss, Samuel Holland, Sean Paul, Shengjiu Wang,
Simona Vetter, Thomas Zimmermann, dri-devel, freedreno,
linux-arm-kernel, linux-arm-msm, linux-sunxi
Several DRM drivers define their own local macros or use magic numbers for
the standard HDMI TMDS character rate limits. Maxime Ripard suggested that
instead these common rate constants could be included to a shared header.
This series introduces these constants to the <linux/hdmi.h> header and
replaces the local defined constants or magic numbers in drivers.
I split the changes as one patch per driver, so that these can be reviewed
individually and merged at their own pace.
This is a version 2 that addresses issues pointed out by Maxime Ripard and
Dmitry Baryshkov.
Changes in v2:
- Change naming convention to HDMI_$SPEC_TMDS_CHAR_RATE_MAX_HZ (Maxime).
- Define the constants in <linux/hdmi.h> (Dmitry).
Javier Martinez Canillas (8):
video/hdmi: Add common TMDS character rate constants
drm/bridge: dw-hdmi: Use the common TMDS char rate constant
drm/bridge: dw-hdmi-qp: Use the common TMDS char rate constant
drm/bridge: inno-hdmi: Use the common TMDS char rate constant
drm/sti: hdmi: Use the common TMDS char rate constants
drm/sun4i: hdmi: Use the common TMDS char rate constant
drm/msm/hdmi: Use the common TMDS char rate constants in 8996 PHY
drm/msm/hdmi: Use the common TMDS char rate constants in 8998 PHY
drivers/gpu/drm/bridge/inno-hdmi.c | 4 +---
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 6 ++----
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 10 ++++------
drivers/gpu/drm/msm/hdmi/hdmi_phy_8996.c | 6 ++----
drivers/gpu/drm/msm/hdmi/hdmi_phy_8998.c | 6 ++----
drivers/gpu/drm/sti/sti_hdmi_tx3g4c28phy.c | 6 ++++--
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 4 ++--
include/linux/hdmi.h | 6 ++++++
8 files changed, 23 insertions(+), 25 deletions(-)
--
2.54.0
base-commit: 88658ff0e4e7f46dbf8179af1280f2cb295fb0cb
branch: add-common-tmds-rates-v2
^ permalink raw reply
* [PATCH v2 6/8] drm/sun4i: hdmi: Use the common TMDS char rate constant
From: Javier Martinez Canillas @ 2026-05-20 14:43 UTC (permalink / raw)
To: linux-kernel
Cc: Javier Martinez Canillas, Maxime Ripard, Chen-Yu Tsai,
David Airlie, Jernej Skrabec, Maarten Lankhorst, Samuel Holland,
Simona Vetter, Thomas Zimmermann, dri-devel, linux-arm-kernel,
linux-sunxi
In-Reply-To: <20260520144424.1633354-1-javierm@redhat.com>
Replace the 165000000 magic number with the shared constant defined
in the <linux/hdmi.h> header.
The old comment referenced "HDMI <= 1.2" but 165 MHz is actually
the maximum TMDS character rate defined by the HDMI 1.0 spec.
Suggested-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Chen-Yu Tsai <wens@kernel.org>
---
(no changes since v1)
drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
index 07e2afcb4f95..74c7c3720ba8 100644
--- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
+++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c
@@ -189,8 +189,8 @@ sun4i_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (mode->flags & DRM_MODE_FLAG_DBLCLK)
return MODE_BAD;
- /* 165 MHz is the typical max pixelclock frequency for HDMI <= 1.2 */
- if (clock > 165000000)
+ /* HDMI 1.0 max TMDS character rate */
+ if (clock > HDMI_1_0_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
rounded_rate = clk_round_rate(hdmi->tmds_clk, clock);
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2] phy: exynos5-usbdrd: Remove error print for devm_add_action_or_reset()
From: Waqar Hameed @ 2026-05-20 14:58 UTC (permalink / raw)
To: Vinod Koul, Kishon Vijay Abraham I, Krzysztof Kozlowski,
Alim Akhtar
Cc: kernel, linux-phy, linux-arm-kernel, linux-samsung-soc,
linux-kernel
In-Reply-To: <pnd7bx2j2pi.a.out@axis.com>
On Fri, Oct 10, 2025 at 15:39 +0200 Waqar Hameed <waqar.hameed@axis.com> wrote:
> On Tue, Aug 05, 2025 at 11:33 +0200 Waqar Hameed <waqar.hameed@axis.com> wrote:
[...]
> Friendly ping incoming!
Friendly ping 2 incoming!
This will be the last ping for the original patch [1]. I'll interpret
the silence as a NACK (though it would preferable to get an explicit
one...). All other patches in the previous patch series has been merged
[2].
[1] https://lore.kernel.org/all/pnd34a6m7tc.a.out@axis.com/
[2] https://lore.kernel.org/all/pnd7c0s6ji2.fsf@axis.com/
^ permalink raw reply
* Re: [PATCH v5 5/9] mfd: mt6397: Add support for MT6392 PMIC
From: Lee Jones @ 2026-05-20 15:00 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Fabien Parent, Val Packett,
AngeloGioacchino Del Regno, Dmitry Torokhov, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Sen Chu, Sean Wang,
Macpaul Lin, Matthias Brugger, Linus Walleij, Liam Girdwood,
Mark Brown, Gary Bisson, Louis-Alexis Eyraud, Julien Massot,
Akari Tsuyukusa, Chen Zhong, linux-input, devicetree,
linux-kernel, linux-pm, linux-arm-kernel, linux-gpio
In-Reply-To: <20260420213529.1645560-6-l.scorcia@gmail.com>
On Mon, 20 Apr 2026, Luca Leonardo Scorcia wrote:
> From: Fabien Parent <parent.f@gmail.com>
>
> Align the MT6397 PMIC driver to other MFD drivers by passing only an
> identifier through mt6397_of_match[*].data and add support for the MT6392
> PMIC.
>
> Signed-off-by: Fabien Parent <parent.f@gmail.com>
> Signed-off-by: Val Packett <val@packett.cool>
> Signed-off-by: Luca Leonardo Scorcia <l.scorcia@gmail.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/mfd/mt6397-core.c | 118 +++++--
> drivers/mfd/mt6397-irq.c | 8 +
> include/linux/mfd/mt6392/core.h | 42 +++
> include/linux/mfd/mt6392/registers.h | 487 +++++++++++++++++++++++++++
> include/linux/mfd/mt6397/core.h | 1 +
> 5 files changed, 630 insertions(+), 26 deletions(-)
> create mode 100644 include/linux/mfd/mt6392/core.h
> create mode 100644 include/linux/mfd/mt6392/registers.h
>
> diff --git "a/drivers/mfd/mt6397-core.c" "b/drivers/mfd/mt6397-core.c"
> index 1bdacda9a933..5c5c24517c00 100644
> --- "a/drivers/mfd/mt6397-core.c"
> +++ "b/drivers/mfd/mt6397-core.c"
> @@ -18,6 +18,7 @@
> #include <linux/mfd/mt6357/core.h>
> #include <linux/mfd/mt6358/core.h>
> #include <linux/mfd/mt6359/core.h>
> +#include <linux/mfd/mt6392/core.h>
> #include <linux/mfd/mt6397/core.h>
> #include <linux/mfd/mt6323/registers.h>
> #include <linux/mfd/mt6328/registers.h>
> @@ -25,8 +26,20 @@
> #include <linux/mfd/mt6357/registers.h>
> #include <linux/mfd/mt6358/registers.h>
> #include <linux/mfd/mt6359/registers.h>
> +#include <linux/mfd/mt6392/registers.h>
> #include <linux/mfd/mt6397/registers.h>
>
> +enum mfd_match_data {
> + MATCH_DATA_MT6323 = 23,
> + MATCH_DATA_MT6328 = 28,
> + MATCH_DATA_MT6331 = 31,
> + MATCH_DATA_MT6357 = 57,
> + MATCH_DATA_MT6358 = 58,
> + MATCH_DATA_MT6359 = 59,
> + MATCH_DATA_MT6392 = 92,
> + MATCH_DATA_MT6397 = 97,
> +};
> +
> #define MT6323_RTC_BASE 0x8000
> #define MT6323_RTC_SIZE 0x40
>
> @@ -39,6 +52,9 @@
> #define MT6358_RTC_BASE 0x0588
> #define MT6358_RTC_SIZE 0x3c
>
> +#define MT6392_RTC_BASE 0x8000
> +#define MT6392_RTC_SIZE 0x3e
> +
> #define MT6397_RTC_BASE 0xe000
> #define MT6397_RTC_SIZE 0x3e
>
> @@ -65,6 +81,11 @@ static const struct resource mt6358_rtc_resources[] = {
> DEFINE_RES_IRQ(MT6358_IRQ_RTC),
> };
>
> +static const struct resource mt6392_rtc_resources[] = {
> + DEFINE_RES_MEM(MT6392_RTC_BASE, MT6392_RTC_SIZE),
> + DEFINE_RES_IRQ(MT6392_IRQ_RTC),
> +};
> +
> static const struct resource mt6397_rtc_resources[] = {
> DEFINE_RES_MEM(MT6397_RTC_BASE, MT6397_RTC_SIZE),
> DEFINE_RES_IRQ(MT6397_IRQ_RTC),
> @@ -114,6 +135,11 @@ static const struct resource mt6331_keys_resources[] = {
> DEFINE_RES_IRQ_NAMED(MT6331_IRQ_STATUS_HOMEKEY, "homekey"),
> };
>
> +static const struct resource mt6392_keys_resources[] = {
> + DEFINE_RES_IRQ_NAMED(MT6392_IRQ_PWRKEY, "powerkey"),
> + DEFINE_RES_IRQ_NAMED(MT6392_IRQ_FCHRKEY, "homekey"),
What does FCHRKEY mean? Is that a datasheet name?
> +};
> +
> static const struct resource mt6397_keys_resources[] = {
> DEFINE_RES_IRQ_NAMED(MT6397_IRQ_PWRKEY, "powerkey"),
> DEFINE_RES_IRQ_NAMED(MT6397_IRQ_HOMEKEY, "homekey"),
> @@ -253,6 +279,25 @@ static const struct mfd_cell mt6359_devs[] = {
> },
> };
>
> +static const struct mfd_cell mt6392_devs[] = {
> + {
> + .name = "mt6392-rtc",
> + .num_resources = ARRAY_SIZE(mt6392_rtc_resources),
> + .resources = mt6392_rtc_resources,
> + .of_compatible = "mediatek,mt6392-rtc",
> + }, {
> + .name = "mt6392-regulator",
> + }, {
> + .name = "mt6392-pinctrl",
> + .of_compatible = "mediatek,mt6392-pinctrl",
> + }, {
> + .name = "mt6392-keys",
> + .num_resources = ARRAY_SIZE(mt6392_keys_resources),
> + .resources = mt6392_keys_resources,
> + .of_compatible = "mediatek,mt6392-keys"
> + },
MFD_CELL_*() for each.
> +};
> +
> static const struct mfd_cell mt6397_devs[] = {
> {
> .name = "mt6397-rtc",
> @@ -335,6 +380,14 @@ static const struct chip_data mt6359_core = {
> .irq_init = mt6358_irq_init,
> };
>
> +static const struct chip_data mt6392_core = {
> + .cid_addr = MT6392_CID,
> + .cid_shift = 0,
> + .cells = mt6392_devs,
> + .cell_size = ARRAY_SIZE(mt6392_devs),
> + .irq_init = mt6397_irq_init,
> +};
> +
> static const struct chip_data mt6397_core = {
> .cid_addr = MT6397_CID,
> .cid_shift = 0,
> @@ -349,6 +402,7 @@ static int mt6397_probe(struct platform_device *pdev)
> unsigned int id = 0;
> struct mt6397_chip *pmic;
> const struct chip_data *pmic_core;
> + enum mfd_match_data device_data;
>
> pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
> if (!pmic)
> @@ -364,9 +418,36 @@ static int mt6397_probe(struct platform_device *pdev)
> if (!pmic->regmap)
> return -ENODEV;
>
> - pmic_core = of_device_get_match_data(&pdev->dev);
> - if (!pmic_core)
> + device_data = (unsigned int)(uintptr_t)of_device_get_match_data(&pdev->dev);
We should be using generic match data variants now like device_get_match_data().
device_data should be chip_id or something.
> + switch (device_data) {
> + case MATCH_DATA_MT6323:
Pick some better nomenclature.
Ignore the fact that we're using these values in match data.
Do they have real differences, ideally ones which can be read from h/w?
> + pmic_core = &mt6323_core;
> + break;
> + case MATCH_DATA_MT6328:
> + pmic_core = &mt6328_core;
> + break;
> + case MATCH_DATA_MT6331:
> + pmic_core = &mt6331_mt6332_core;
> + break;
> + case MATCH_DATA_MT6357:
> + pmic_core = &mt6357_core;
> + break;
> + case MATCH_DATA_MT6358:
> + pmic_core = &mt6358_core;
> + break;
> + case MATCH_DATA_MT6359:
> + pmic_core = &mt6359_core;
> + break;
> + case MATCH_DATA_MT6392:
> + pmic_core = &mt6392_core;
> + break;
> + case MATCH_DATA_MT6397:
> + pmic_core = &mt6397_core;
> + break;
> + default:
> + dev_err(&pdev->dev, "Unknown device match data %u\n", device_data);
The user doesn't care about your match data.
"Device not supported"
> return -ENODEV;
> + }
>
> ret = regmap_read(pmic->regmap, pmic_core->cid_addr, &id);
> if (ret) {
> @@ -398,30 +479,15 @@ static int mt6397_probe(struct platform_device *pdev)
> }
>
> static const struct of_device_id mt6397_of_match[] = {
> - {
> - .compatible = "mediatek,mt6323",
> - .data = &mt6323_core,
> - }, {
> - .compatible = "mediatek,mt6328",
> - .data = &mt6328_core,
> - }, {
> - .compatible = "mediatek,mt6331",
> - .data = &mt6331_mt6332_core,
> - }, {
> - .compatible = "mediatek,mt6357",
> - .data = &mt6357_core,
> - }, {
> - .compatible = "mediatek,mt6358",
> - .data = &mt6358_core,
> - }, {
> - .compatible = "mediatek,mt6359",
> - .data = &mt6359_core,
> - }, {
> - .compatible = "mediatek,mt6397",
> - .data = &mt6397_core,
> - }, {
> - /* sentinel */
> - }
> + { .compatible = "mediatek,mt6323", .data = (void *)MATCH_DATA_MT6323, },
> + { .compatible = "mediatek,mt6328", .data = (void *)MATCH_DATA_MT6328, },
> + { .compatible = "mediatek,mt6331", .data = (void *)MATCH_DATA_MT6331, },
> + { .compatible = "mediatek,mt6357", .data = (void *)MATCH_DATA_MT6357, },
> + { .compatible = "mediatek,mt6358", .data = (void *)MATCH_DATA_MT6358, },
> + { .compatible = "mediatek,mt6359", .data = (void *)MATCH_DATA_MT6359, },
> + { .compatible = "mediatek,mt6392", .data = (void *)MATCH_DATA_MT6392, },
> + { .compatible = "mediatek,mt6397", .data = (void *)MATCH_DATA_MT6397, },
This is much better.
Maybe we can get rid of the bespoke 'struct chip_data' now?
> + { /* sentinel */ }
> };
> MODULE_DEVICE_TABLE(of, mt6397_of_match);
>
> diff --git "a/drivers/mfd/mt6397-irq.c" "b/drivers/mfd/mt6397-irq.c"
> index 5d2e5459f744..80ea5b92d232 100644
> --- "a/drivers/mfd/mt6397-irq.c"
> +++ "b/drivers/mfd/mt6397-irq.c"
> @@ -15,6 +15,8 @@
> #include <linux/mfd/mt6328/registers.h>
> #include <linux/mfd/mt6331/core.h>
> #include <linux/mfd/mt6331/registers.h>
> +#include <linux/mfd/mt6392/core.h>
> +#include <linux/mfd/mt6392/registers.h>
> #include <linux/mfd/mt6397/core.h>
> #include <linux/mfd/mt6397/registers.h>
>
> @@ -203,6 +205,12 @@ int mt6397_irq_init(struct mt6397_chip *chip)
> chip->int_status[0] = MT6397_INT_STATUS0;
> chip->int_status[1] = MT6397_INT_STATUS1;
> break;
> + case MT6392_CHIP_ID:
> + chip->int_con[0] = MT6392_INT_CON0;
> + chip->int_con[1] = MT6392_INT_CON1;
> + chip->int_status[0] = MT6392_INT_STATUS0;
> + chip->int_status[1] = MT6392_INT_STATUS1;
> + break;
>
> default:
> dev_err(chip->dev, "unsupported chip: 0x%x\n", chip->chip_id);
> diff --git "a/include/linux/mfd/mt6392/core.h" "b/include/linux/mfd/mt6392/core.h"
> new file mode 100644
> index 000000000000..4780dab4da92
> --- /dev/null
> +++ "b/include/linux/mfd/mt6392/core.h"
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
This needs an update.
> + * Author: Chen Zhong <chen.zhong@mediatek.com>
> + */
> +
> +#ifndef __MFD_MT6392_CORE_H__
> +#define __MFD_MT6392_CORE_H__
> +
> +enum mt6392_irq_numbers {
> + MT6392_IRQ_SPKL_AB = 0,
> + MT6392_IRQ_SPKL,
> + MT6392_IRQ_BAT_L,
> + MT6392_IRQ_BAT_H,
> + MT6392_IRQ_WATCHDOG,
> + MT6392_IRQ_PWRKEY,
> + MT6392_IRQ_THR_L,
> + MT6392_IRQ_THR_H,
> + MT6392_IRQ_VBATON_UNDET,
> + MT6392_IRQ_BVALID_DET,
> + MT6392_IRQ_CHRDET,
> + MT6392_IRQ_OV,
> + MT6392_IRQ_LDO = 16,
> + MT6392_IRQ_FCHRKEY,
> + MT6392_IRQ_RELEASE_PWRKEY,
> + MT6392_IRQ_RELEASE_FCHRKEY,
> + MT6392_IRQ_RTC,
> + MT6392_IRQ_VPROC,
> + MT6392_IRQ_VSYS,
> + MT6392_IRQ_VCORE,
> + MT6392_IRQ_TYPE_C_CC,
> + MT6392_IRQ_TYPEC_H_MAX,
> + MT6392_IRQ_TYPEC_H_MIN,
> + MT6392_IRQ_TYPEC_L_MAX,
> + MT6392_IRQ_TYPEC_L_MIN,
> + MT6392_IRQ_THR_MAX,
> + MT6392_IRQ_THR_MIN,
> + MT6392_IRQ_NAG_C_DLTV,
> + MT6392_IRQ_NR,
> +};
> +
> +#endif /* __MFD_MT6392_CORE_H__ */
> diff --git "a/include/linux/mfd/mt6392/registers.h" "b/include/linux/mfd/mt6392/registers.h"
> new file mode 100644
> index 000000000000..4f3a6db830d1
> --- /dev/null
> +++ "b/include/linux/mfd/mt6392/registers.h"
> @@ -0,0 +1,487 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2020 MediaTek Inc.
Same and throughout.
> + * Author: Chen Zhong <chen.zhong@mediatek.com>
> + */
> +
> +#ifndef __MFD_MT6392_REGISTERS_H__
> +#define __MFD_MT6392_REGISTERS_H__
> +
> +/* PMIC Registers */
> +#define MT6392_CHR_CON0 0x0000
> +#define MT6392_CHR_CON1 0x0002
> +#define MT6392_CHR_CON2 0x0004
> +#define MT6392_CHR_CON3 0x0006
> +#define MT6392_CHR_CON4 0x0008
> +#define MT6392_CHR_CON5 0x000A
> +#define MT6392_CHR_CON6 0x000C
> +#define MT6392_CHR_CON7 0x000E
> +#define MT6392_CHR_CON8 0x0010
> +#define MT6392_CHR_CON9 0x0012
> +#define MT6392_CHR_CON10 0x0014
> +#define MT6392_CHR_CON11 0x0016
> +#define MT6392_CHR_CON12 0x0018
> +#define MT6392_CHR_CON13 0x001A
> +#define MT6392_CHR_CON14 0x001C
> +#define MT6392_CHR_CON15 0x001E
> +#define MT6392_CHR_CON16 0x0020
> +#define MT6392_CHR_CON17 0x0022
> +#define MT6392_CHR_CON18 0x0024
> +#define MT6392_CHR_CON19 0x0026
> +#define MT6392_CHR_CON20 0x0028
> +#define MT6392_CHR_CON21 0x002A
> +#define MT6392_CHR_CON22 0x002C
> +#define MT6392_CHR_CON23 0x002E
> +#define MT6392_CHR_CON24 0x0030
> +#define MT6392_CHR_CON25 0x0032
> +#define MT6392_CHR_CON26 0x0034
> +#define MT6392_CHR_CON27 0x0036
> +#define MT6392_CHR_CON28 0x0038
> +#define MT6392_CHR_CON29 0x003A
> +#define MT6392_STRUP_CON0 0x003C
> +#define MT6392_STRUP_CON2 0x003E
> +#define MT6392_STRUP_CON3 0x0040
> +#define MT6392_STRUP_CON4 0x0042
> +#define MT6392_STRUP_CON5 0x0044
> +#define MT6392_STRUP_CON6 0x0046
> +#define MT6392_STRUP_CON7 0x0048
> +#define MT6392_STRUP_CON8 0x004A
> +#define MT6392_STRUP_CON9 0x004C
> +#define MT6392_STRUP_CON10 0x004E
> +#define MT6392_STRUP_CON11 0x0050
> +#define MT6392_SPK_CON0 0x0052
> +#define MT6392_SPK_CON1 0x0054
> +#define MT6392_SPK_CON2 0x0056
> +#define MT6392_SPK_CON6 0x005E
> +#define MT6392_SPK_CON7 0x0060
> +#define MT6392_SPK_CON8 0x0062
> +#define MT6392_SPK_CON9 0x0064
> +#define MT6392_SPK_CON10 0x0066
> +#define MT6392_SPK_CON11 0x0068
> +#define MT6392_SPK_CON12 0x006A
> +#define MT6392_STRUP_CON12 0x006E
> +#define MT6392_STRUP_CON13 0x0070
> +#define MT6392_STRUP_CON14 0x0072
> +#define MT6392_STRUP_CON15 0x0074
> +#define MT6392_STRUP_CON16 0x0076
> +#define MT6392_STRUP_CON17 0x0078
> +#define MT6392_STRUP_CON18 0x007A
> +#define MT6392_STRUP_CON19 0x007C
> +#define MT6392_STRUP_CON20 0x007E
> +#define MT6392_CID 0x0100
> +#define MT6392_TOP_CKPDN0 0x0102
> +#define MT6392_TOP_CKPDN0_SET 0x0104
> +#define MT6392_TOP_CKPDN0_CLR 0x0106
> +#define MT6392_TOP_CKPDN1 0x0108
> +#define MT6392_TOP_CKPDN1_SET 0x010A
> +#define MT6392_TOP_CKPDN1_CLR 0x010C
> +#define MT6392_TOP_CKPDN2 0x010E
> +#define MT6392_TOP_CKPDN2_SET 0x0110
> +#define MT6392_TOP_CKPDN2_CLR 0x0112
> +#define MT6392_TOP_RST_CON 0x0114
> +#define MT6392_TOP_RST_CON_SET 0x0116
> +#define MT6392_TOP_RST_CON_CLR 0x0118
> +#define MT6392_TOP_RST_MISC 0x011A
> +#define MT6392_TOP_RST_MISC_SET 0x011C
> +#define MT6392_TOP_RST_MISC_CLR 0x011E
> +#define MT6392_TOP_CKCON0 0x0120
> +#define MT6392_TOP_CKCON0_SET 0x0122
> +#define MT6392_TOP_CKCON0_CLR 0x0124
> +#define MT6392_TOP_CKCON1 0x0126
> +#define MT6392_TOP_CKCON1_SET 0x0128
> +#define MT6392_TOP_CKCON1_CLR 0x012A
> +#define MT6392_TOP_CKTST0 0x012C
> +#define MT6392_TOP_CKTST1 0x012E
> +#define MT6392_TOP_CKTST2 0x0130
> +#define MT6392_TEST_OUT 0x0132
> +#define MT6392_TEST_CON0 0x0134
> +#define MT6392_TEST_CON1 0x0136
> +#define MT6392_EN_STATUS0 0x0138
> +#define MT6392_EN_STATUS1 0x013A
> +#define MT6392_OCSTATUS0 0x013C
> +#define MT6392_OCSTATUS1 0x013E
> +#define MT6392_PGSTATUS 0x0140
> +#define MT6392_CHRSTATUS 0x0142
> +#define MT6392_TDSEL_CON 0x0144
> +#define MT6392_RDSEL_CON 0x0146
> +#define MT6392_SMT_CON0 0x0148
> +#define MT6392_SMT_CON1 0x014A
> +#define MT6392_DRV_CON0 0x0152
> +#define MT6392_DRV_CON1 0x0154
> +#define MT6392_INT_CON0 0x0160
> +#define MT6392_INT_CON0_SET 0x0162
> +#define MT6392_INT_CON0_CLR 0x0164
> +#define MT6392_INT_CON1 0x0166
> +#define MT6392_INT_CON1_SET 0x0168
> +#define MT6392_INT_CON1_CLR 0x016A
> +#define MT6392_INT_MISC_CON 0x016C
> +#define MT6392_INT_MISC_CON_SET 0x016E
> +#define MT6392_INT_MISC_CON_CLR 0x0170
> +#define MT6392_INT_STATUS0 0x0172
> +#define MT6392_INT_STATUS1 0x0174
> +#define MT6392_OC_GEAR_0 0x0176
> +#define MT6392_OC_GEAR_1 0x0178
> +#define MT6392_OC_GEAR_2 0x017A
> +#define MT6392_OC_CTL_VPROC 0x017C
> +#define MT6392_OC_CTL_VSYS 0x017E
> +#define MT6392_OC_CTL_VCORE 0x0180
> +#define MT6392_FQMTR_CON0 0x0182
> +#define MT6392_FQMTR_CON1 0x0184
> +#define MT6392_FQMTR_CON2 0x0186
> +#define MT6392_RG_SPI_CON 0x0188
> +#define MT6392_DEW_DIO_EN 0x018A
> +#define MT6392_DEW_READ_TEST 0x018C
> +#define MT6392_DEW_WRITE_TEST 0x018E
> +#define MT6392_DEW_CRC_SWRST 0x0190
> +#define MT6392_DEW_CRC_EN 0x0192
> +#define MT6392_DEW_CRC_VAL 0x0194
> +#define MT6392_DEW_DBG_MON_SEL 0x0196
> +#define MT6392_DEW_CIPHER_KEY_SEL 0x0198
> +#define MT6392_DEW_CIPHER_IV_SEL 0x019A
> +#define MT6392_DEW_CIPHER_EN 0x019C
> +#define MT6392_DEW_CIPHER_RDY 0x019E
> +#define MT6392_DEW_CIPHER_MODE 0x01A0
> +#define MT6392_DEW_CIPHER_SWRST 0x01A2
> +#define MT6392_DEW_RDDMY_NO 0x01A4
> +#define MT6392_DEW_RDATA_DLY_SEL 0x01A6
> +#define MT6392_CLK_TRIM_CON0 0x01A8
> +#define MT6392_BUCK_CON0 0x0200
> +#define MT6392_BUCK_CON1 0x0202
> +#define MT6392_BUCK_CON2 0x0204
> +#define MT6392_BUCK_CON3 0x0206
> +#define MT6392_BUCK_CON4 0x0208
> +#define MT6392_BUCK_CON5 0x020A
> +#define MT6392_VPROC_CON0 0x020C
> +#define MT6392_VPROC_CON1 0x020E
> +#define MT6392_VPROC_CON2 0x0210
> +#define MT6392_VPROC_CON3 0x0212
> +#define MT6392_VPROC_CON4 0x0214
> +#define MT6392_VPROC_CON5 0x0216
> +#define MT6392_VPROC_CON7 0x021A
> +#define MT6392_VPROC_CON8 0x021C
> +#define MT6392_VPROC_CON9 0x021E
> +#define MT6392_VPROC_CON10 0x0220
> +#define MT6392_VPROC_CON11 0x0222
> +#define MT6392_VPROC_CON12 0x0224
> +#define MT6392_VPROC_CON13 0x0226
> +#define MT6392_VPROC_CON14 0x0228
> +#define MT6392_VPROC_CON15 0x022A
> +#define MT6392_VPROC_CON18 0x0230
> +#define MT6392_VSYS_CON0 0x0232
> +#define MT6392_VSYS_CON1 0x0234
> +#define MT6392_VSYS_CON2 0x0236
> +#define MT6392_VSYS_CON3 0x0238
> +#define MT6392_VSYS_CON4 0x023A
> +#define MT6392_VSYS_CON5 0x023C
> +#define MT6392_VSYS_CON7 0x0240
> +#define MT6392_VSYS_CON8 0x0242
> +#define MT6392_VSYS_CON9 0x0244
> +#define MT6392_VSYS_CON10 0x0246
> +#define MT6392_VSYS_CON11 0x0248
> +#define MT6392_VSYS_CON12 0x024A
> +#define MT6392_VSYS_CON13 0x024C
> +#define MT6392_VSYS_CON14 0x024E
> +#define MT6392_VSYS_CON15 0x0250
> +#define MT6392_VSYS_CON18 0x0256
> +#define MT6392_BUCK_OC_CON0 0x0258
> +#define MT6392_BUCK_OC_CON1 0x025A
> +#define MT6392_BUCK_OC_CON2 0x025C
> +#define MT6392_BUCK_OC_CON3 0x025E
> +#define MT6392_BUCK_OC_CON4 0x0260
> +#define MT6392_BUCK_OC_VPROC_CON0 0x0262
> +#define MT6392_BUCK_OC_VCORE_CON0 0x0264
> +#define MT6392_BUCK_OC_VSYS_CON0 0x0266
> +#define MT6392_BUCK_ANA_MON_CON0 0x0268
> +#define MT6392_BUCK_EFUSE_OC_CON0 0x026A
> +#define MT6392_VCORE_CON0 0x0300
> +#define MT6392_VCORE_CON1 0x0302
> +#define MT6392_VCORE_CON2 0x0304
> +#define MT6392_VCORE_CON3 0x0306
> +#define MT6392_VCORE_CON4 0x0308
> +#define MT6392_VCORE_CON5 0x030A
> +#define MT6392_VCORE_CON7 0x030E
> +#define MT6392_VCORE_CON8 0x0310
> +#define MT6392_VCORE_CON9 0x0312
> +#define MT6392_VCORE_CON10 0x0314
> +#define MT6392_VCORE_CON11 0x0316
> +#define MT6392_VCORE_CON12 0x0318
> +#define MT6392_VCORE_CON13 0x031A
> +#define MT6392_VCORE_CON14 0x031C
> +#define MT6392_VCORE_CON15 0x031E
> +#define MT6392_VCORE_CON18 0x0324
> +#define MT6392_BUCK_K_CON0 0x032A
> +#define MT6392_BUCK_K_CON1 0x032C
> +#define MT6392_BUCK_K_CON2 0x032E
> +#define MT6392_ANALDO_CON0 0x0400
> +#define MT6392_ANALDO_CON1 0x0402
> +#define MT6392_ANALDO_CON2 0x0404
> +#define MT6392_ANALDO_CON3 0x0406
> +#define MT6392_ANALDO_CON4 0x0408
> +#define MT6392_ANALDO_CON6 0x040C
> +#define MT6392_ANALDO_CON7 0x040E
> +#define MT6392_ANALDO_CON8 0x0410
> +#define MT6392_ANALDO_CON10 0x0412
> +#define MT6392_ANALDO_CON15 0x0414
> +#define MT6392_ANALDO_CON16 0x0416
> +#define MT6392_ANALDO_CON17 0x0418
> +#define MT6392_ANALDO_CON21 0x0420
> +#define MT6392_ANALDO_CON22 0x0422
> +#define MT6392_ANALDO_CON23 0x0424
> +#define MT6392_ANALDO_CON24 0x0426
> +#define MT6392_ANALDO_CON25 0x0428
> +#define MT6392_ANALDO_CON26 0x042A
> +#define MT6392_ANALDO_CON27 0x042C
> +#define MT6392_ANALDO_CON28 0x042E
> +#define MT6392_ANALDO_CON29 0x0430
> +#define MT6392_DIGLDO_CON0 0x0500
> +#define MT6392_DIGLDO_CON2 0x0502
> +#define MT6392_DIGLDO_CON3 0x0504
> +#define MT6392_DIGLDO_CON5 0x0506
> +#define MT6392_DIGLDO_CON6 0x0508
> +#define MT6392_DIGLDO_CON7 0x050A
> +#define MT6392_DIGLDO_CON8 0x050C
> +#define MT6392_DIGLDO_CON10 0x0510
> +#define MT6392_DIGLDO_CON11 0x0512
> +#define MT6392_DIGLDO_CON12 0x0514
> +#define MT6392_DIGLDO_CON15 0x051A
> +#define MT6392_DIGLDO_CON20 0x0524
> +#define MT6392_DIGLDO_CON21 0x0526
> +#define MT6392_DIGLDO_CON23 0x0528
> +#define MT6392_DIGLDO_CON24 0x052A
> +#define MT6392_DIGLDO_CON26 0x052C
> +#define MT6392_DIGLDO_CON27 0x052E
> +#define MT6392_DIGLDO_CON28 0x0530
> +#define MT6392_DIGLDO_CON29 0x0532
> +#define MT6392_DIGLDO_CON30 0x0534
> +#define MT6392_DIGLDO_CON31 0x0536
> +#define MT6392_DIGLDO_CON32 0x0538
> +#define MT6392_DIGLDO_CON33 0x053A
> +#define MT6392_DIGLDO_CON36 0x0540
> +#define MT6392_DIGLDO_CON41 0x0546
> +#define MT6392_DIGLDO_CON44 0x054C
> +#define MT6392_DIGLDO_CON47 0x0552
> +#define MT6392_DIGLDO_CON48 0x0554
> +#define MT6392_DIGLDO_CON49 0x0556
> +#define MT6392_DIGLDO_CON50 0x0558
> +#define MT6392_DIGLDO_CON51 0x055A
> +#define MT6392_DIGLDO_CON52 0x055C
> +#define MT6392_DIGLDO_CON53 0x055E
> +#define MT6392_DIGLDO_CON54 0x0560
> +#define MT6392_DIGLDO_CON55 0x0562
> +#define MT6392_DIGLDO_CON56 0x0564
> +#define MT6392_DIGLDO_CON57 0x0566
> +#define MT6392_DIGLDO_CON58 0x0568
> +#define MT6392_DIGLDO_CON59 0x056A
> +#define MT6392_DIGLDO_CON60 0x056C
> +#define MT6392_DIGLDO_CON61 0x056E
> +#define MT6392_DIGLDO_CON62 0x0570
> +#define MT6392_DIGLDO_CON63 0x0572
> +#define MT6392_EFUSE_CON0 0x0600
> +#define MT6392_EFUSE_CON1 0x0602
> +#define MT6392_EFUSE_CON2 0x0604
> +#define MT6392_EFUSE_CON3 0x0606
> +#define MT6392_EFUSE_CON4 0x0608
> +#define MT6392_EFUSE_CON5 0x060A
> +#define MT6392_EFUSE_CON6 0x060C
> +#define MT6392_EFUSE_VAL_0_15 0x060E
> +#define MT6392_EFUSE_VAL_16_31 0x0610
> +#define MT6392_EFUSE_VAL_32_47 0x0612
> +#define MT6392_EFUSE_VAL_48_63 0x0614
> +#define MT6392_EFUSE_VAL_64_79 0x0616
> +#define MT6392_EFUSE_VAL_80_95 0x0618
> +#define MT6392_EFUSE_VAL_96_111 0x061A
> +#define MT6392_EFUSE_VAL_112_127 0x061C
> +#define MT6392_EFUSE_VAL_128_143 0x061E
> +#define MT6392_EFUSE_VAL_144_159 0x0620
> +#define MT6392_EFUSE_VAL_160_175 0x0622
> +#define MT6392_EFUSE_VAL_176_191 0x0624
> +#define MT6392_EFUSE_VAL_192_207 0x0626
> +#define MT6392_EFUSE_VAL_208_223 0x0628
> +#define MT6392_EFUSE_VAL_224_239 0x062A
> +#define MT6392_EFUSE_VAL_240_255 0x062C
> +#define MT6392_EFUSE_VAL_256_271 0x062E
> +#define MT6392_EFUSE_VAL_272_287 0x0630
> +#define MT6392_EFUSE_VAL_288_303 0x0632
> +#define MT6392_EFUSE_VAL_304_319 0x0634
> +#define MT6392_EFUSE_VAL_320_335 0x0636
> +#define MT6392_EFUSE_VAL_336_351 0x0638
> +#define MT6392_EFUSE_VAL_352_367 0x063A
> +#define MT6392_EFUSE_VAL_368_383 0x063C
> +#define MT6392_EFUSE_VAL_384_399 0x063E
> +#define MT6392_EFUSE_VAL_400_415 0x0640
> +#define MT6392_EFUSE_VAL_416_431 0x0642
> +#define MT6392_RTC_MIX_CON0 0x0644
> +#define MT6392_RTC_MIX_CON1 0x0646
> +#define MT6392_EFUSE_VAL_432_447 0x0648
> +#define MT6392_EFUSE_VAL_448_463 0x064A
> +#define MT6392_EFUSE_VAL_464_479 0x064C
> +#define MT6392_EFUSE_VAL_480_495 0x064E
> +#define MT6392_EFUSE_VAL_496_511 0x0650
> +#define MT6392_EFUSE_DOUT_0_15 0x0652
> +#define MT6392_EFUSE_DOUT_16_31 0x0654
> +#define MT6392_EFUSE_DOUT_32_47 0x0656
> +#define MT6392_EFUSE_DOUT_48_63 0x0658
> +#define MT6392_EFUSE_DOUT_64_79 0x065A
> +#define MT6392_EFUSE_DOUT_80_95 0x065C
> +#define MT6392_EFUSE_DOUT_96_111 0x065E
> +#define MT6392_EFUSE_DOUT_112_127 0x0660
> +#define MT6392_EFUSE_DOUT_128_143 0x0662
> +#define MT6392_EFUSE_DOUT_144_159 0x0664
> +#define MT6392_EFUSE_DOUT_160_175 0x0666
> +#define MT6392_EFUSE_DOUT_176_191 0x0668
> +#define MT6392_EFUSE_DOUT_192_207 0x066A
> +#define MT6392_EFUSE_DOUT_208_223 0x066C
> +#define MT6392_EFUSE_DOUT_224_239 0x066E
> +#define MT6392_EFUSE_DOUT_240_255 0x0670
> +#define MT6392_EFUSE_DOUT_256_271 0x0672
> +#define MT6392_EFUSE_DOUT_272_287 0x0674
> +#define MT6392_EFUSE_DOUT_288_303 0x0676
> +#define MT6392_EFUSE_DOUT_304_319 0x0678
> +#define MT6392_EFUSE_DOUT_320_335 0x067A
> +#define MT6392_EFUSE_DOUT_336_351 0x067C
> +#define MT6392_EFUSE_DOUT_352_367 0x067E
> +#define MT6392_EFUSE_DOUT_368_383 0x0680
> +#define MT6392_EFUSE_DOUT_384_399 0x0682
> +#define MT6392_EFUSE_DOUT_400_415 0x0684
> +#define MT6392_EFUSE_DOUT_416_431 0x0686
> +#define MT6392_EFUSE_DOUT_432_447 0x0688
> +#define MT6392_EFUSE_DOUT_448_463 0x068A
> +#define MT6392_EFUSE_DOUT_464_479 0x068C
> +#define MT6392_EFUSE_DOUT_480_495 0x068E
> +#define MT6392_EFUSE_DOUT_496_511 0x0690
> +#define MT6392_EFUSE_CON7 0x0692
> +#define MT6392_EFUSE_CON8 0x0694
> +#define MT6392_EFUSE_CON9 0x0696
> +#define MT6392_AUXADC_ADC0 0x0700
> +#define MT6392_AUXADC_ADC1 0x0702
> +#define MT6392_AUXADC_ADC2 0x0704
> +#define MT6392_AUXADC_ADC3 0x0706
> +#define MT6392_AUXADC_ADC4 0x0708
> +#define MT6392_AUXADC_ADC5 0x070A
> +#define MT6392_AUXADC_ADC6 0x070C
> +#define MT6392_AUXADC_ADC7 0x070E
> +#define MT6392_AUXADC_ADC8 0x0710
> +#define MT6392_AUXADC_ADC9 0x0712
> +#define MT6392_AUXADC_ADC10 0x0714
> +#define MT6392_AUXADC_ADC11 0x0716
> +#define MT6392_AUXADC_ADC12 0x0718
> +#define MT6392_AUXADC_ADC13 0x071A
> +#define MT6392_AUXADC_ADC14 0x071C
> +#define MT6392_AUXADC_ADC15 0x071E
> +#define MT6392_AUXADC_ADC16 0x0720
> +#define MT6392_AUXADC_ADC17 0x0722
> +#define MT6392_AUXADC_ADC18 0x0724
> +#define MT6392_AUXADC_ADC19 0x0726
> +#define MT6392_AUXADC_ADC20 0x0728
> +#define MT6392_AUXADC_ADC21 0x072A
> +#define MT6392_AUXADC_ADC22 0x072C
> +#define MT6392_AUXADC_STA0 0x072E
> +#define MT6392_AUXADC_STA1 0x0730
> +#define MT6392_AUXADC_RQST0 0x0732
> +#define MT6392_AUXADC_RQST0_SET 0x0734
> +#define MT6392_AUXADC_RQST0_CLR 0x0736
> +#define MT6392_AUXADC_CON0 0x0738
> +#define MT6392_AUXADC_CON0_SET 0x073A
> +#define MT6392_AUXADC_CON0_CLR 0x073C
> +#define MT6392_AUXADC_CON1 0x073E
> +#define MT6392_AUXADC_CON2 0x0740
> +#define MT6392_AUXADC_CON3 0x0742
> +#define MT6392_AUXADC_CON4 0x0744
> +#define MT6392_AUXADC_CON5 0x0746
> +#define MT6392_AUXADC_CON6 0x0748
> +#define MT6392_AUXADC_CON7 0x074A
> +#define MT6392_AUXADC_CON8 0x074C
> +#define MT6392_AUXADC_CON9 0x074E
> +#define MT6392_AUXADC_CON10 0x0750
> +#define MT6392_AUXADC_CON11 0x0752
> +#define MT6392_AUXADC_CON12 0x0754
> +#define MT6392_AUXADC_CON13 0x0756
> +#define MT6392_AUXADC_CON14 0x0758
> +#define MT6392_AUXADC_CON15 0x075A
> +#define MT6392_AUXADC_CON16 0x075C
> +#define MT6392_AUXADC_AUTORPT0 0x075E
> +#define MT6392_AUXADC_LBAT0 0x0760
> +#define MT6392_AUXADC_LBAT1 0x0762
> +#define MT6392_AUXADC_LBAT2 0x0764
> +#define MT6392_AUXADC_LBAT3 0x0766
> +#define MT6392_AUXADC_LBAT4 0x0768
> +#define MT6392_AUXADC_LBAT5 0x076A
> +#define MT6392_AUXADC_LBAT6 0x076C
> +#define MT6392_AUXADC_THR0 0x076E
> +#define MT6392_AUXADC_THR1 0x0770
> +#define MT6392_AUXADC_THR2 0x0772
> +#define MT6392_AUXADC_THR3 0x0774
> +#define MT6392_AUXADC_THR4 0x0776
> +#define MT6392_AUXADC_THR5 0x0778
> +#define MT6392_AUXADC_THR6 0x077A
> +#define MT6392_AUXADC_EFUSE0 0x077C
> +#define MT6392_AUXADC_EFUSE1 0x077E
> +#define MT6392_AUXADC_EFUSE2 0x0780
> +#define MT6392_AUXADC_EFUSE3 0x0782
> +#define MT6392_AUXADC_EFUSE4 0x0784
> +#define MT6392_AUXADC_EFUSE5 0x0786
> +#define MT6392_AUXADC_NAG_0 0x0788
> +#define MT6392_AUXADC_NAG_1 0x078A
> +#define MT6392_AUXADC_NAG_2 0x078C
> +#define MT6392_AUXADC_NAG_3 0x078E
> +#define MT6392_AUXADC_NAG_4 0x0790
> +#define MT6392_AUXADC_NAG_5 0x0792
> +#define MT6392_AUXADC_NAG_6 0x0794
> +#define MT6392_AUXADC_NAG_7 0x0796
> +#define MT6392_AUXADC_NAG_8 0x0798
> +#define MT6392_AUXADC_TYPEC_H_1 0x079A
> +#define MT6392_AUXADC_TYPEC_H_2 0x079C
> +#define MT6392_AUXADC_TYPEC_H_3 0x079E
> +#define MT6392_AUXADC_TYPEC_H_4 0x07A0
> +#define MT6392_AUXADC_TYPEC_H_5 0x07A2
> +#define MT6392_AUXADC_TYPEC_H_6 0x07A4
> +#define MT6392_AUXADC_TYPEC_H_7 0x07A6
> +#define MT6392_AUXADC_TYPEC_L_1 0x07A8
> +#define MT6392_AUXADC_TYPEC_L_2 0x07AA
> +#define MT6392_AUXADC_TYPEC_L_3 0x07AC
> +#define MT6392_AUXADC_TYPEC_L_4 0x07AE
> +#define MT6392_AUXADC_TYPEC_L_5 0x07B0
> +#define MT6392_AUXADC_TYPEC_L_6 0x07B2
> +#define MT6392_AUXADC_TYPEC_L_7 0x07B4
> +#define MT6392_AUXADC_NAG_9 0x07B6
> +#define MT6392_TYPE_C_PHY_RG_0 0x0800
> +#define MT6392_TYPE_C_PHY_RG_CC_RESERVE_CSR 0x0802
> +#define MT6392_TYPE_C_VCMP_CTRL 0x0804
> +#define MT6392_TYPE_C_CTRL 0x0806
> +#define MT6392_TYPE_C_CC_SW_CTRL 0x080a
> +#define MT6392_TYPE_C_CC_VOL_PERIODIC_MEAS_VAL 0x080c
> +#define MT6392_TYPE_C_CC_VOL_DEBOUNCE_CNT_VAL 0x080e
> +#define MT6392_TYPE_C_DRP_SRC_CNT_VAL_0 0x0810
> +#define MT6392_TYPE_C_DRP_SNK_CNT_VAL_0 0x0814
> +#define MT6392_TYPE_C_DRP_TRY_CNT_VAL_0 0x0818
> +#define MT6392_TYPE_C_CC_SRC_DEFAULT_DAC_VAL 0x0820
> +#define MT6392_TYPE_C_CC_SRC_15_DAC_VAL 0x0822
> +#define MT6392_TYPE_C_CC_SRC_30_DAC_VAL 0x0824
> +#define MT6392_TYPE_C_CC_SNK_DAC_VAL_0 0x0828
> +#define MT6392_TYPE_C_CC_SNK_DAC_VAL_1 0x082a
> +#define MT6392_TYPE_C_INTR_EN_0 0x0830
> +#define MT6392_TYPE_C_INTR_EN_2 0x0834
> +#define MT6392_TYPE_C_INTR_0 0x0838
> +#define MT6392_TYPE_C_INTR_2 0x083C
> +#define MT6392_TYPE_C_CC_STATUS 0x0840
> +#define MT6392_TYPE_C_PWR_STATUS 0x0842
> +#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_0 0x0844
> +#define MT6392_TYPE_C_PHY_RG_CC1_RESISTENCE_1 0x0846
> +#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_0 0x0848
> +#define MT6392_TYPE_C_PHY_RG_CC2_RESISTENCE_1 0x084a
> +#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_0 0x0860
> +#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_0 0x0864
> +#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_1 0x0866
> +#define MT6392_TYPE_C_CC_SW_FORCE_MODE_ENABLE_1 0x0868
> +#define MT6392_TYPE_C_CC_SW_FORCE_MODE_VAL_2 0x086c
> +#define MT6392_TYPE_C_CC_DAC_CALI_CTRL 0x0870
> +#define MT6392_TYPE_C_CC_DAC_CALI_RESULT 0x0872
> +#define MT6392_TYPE_C_DEBUG_PORT_SELECT_0 0x0880
> +#define MT6392_TYPE_C_DEBUG_PORT_SELECT_1 0x0882
> +#define MT6392_TYPE_C_DEBUG_MODE_SELECT 0x0884
> +#define MT6392_TYPE_C_DEBUG_OUT_READ_0 0x0888
> +#define MT6392_TYPE_C_DEBUG_OUT_READ_1 0x088a
> +#define MT6392_TYPE_C_SW_DEBUG_PORT_0 0x088c
> +#define MT6392_TYPE_C_SW_DEBUG_PORT_1 0x088e
> +
> +#endif /* __MFD_MT6392_REGISTERS_H__ */
> diff --git "a/include/linux/mfd/mt6397/core.h" "b/include/linux/mfd/mt6397/core.h"
> index 340fc72e22aa..3729a6856c13 100644
> --- "a/include/linux/mfd/mt6397/core.h"
> +++ "b/include/linux/mfd/mt6397/core.h"
> @@ -20,6 +20,7 @@ enum chip_id {
> MT6359_CHIP_ID = 0x59,
> MT6366_CHIP_ID = 0x66,
> MT6391_CHIP_ID = 0x91,
> + MT6392_CHIP_ID = 0x92,
This looks like a duplicated struct.
Can't we use this instead of the made-up 'mfd_match_data'?
> MT6397_CHIP_ID = 0x97,
> };
>
> --
> 2.43.0
--
Lee Jones
^ permalink raw reply
* [PATCH v2] iommu: Allow device driver to use its own PASID space for SVA
From: Joonwon Kang @ 2026-05-20 15:07 UTC (permalink / raw)
To: jgg, will, robin.murphy, joro, jpb
Cc: Alexander.Grest, amhetre, baolu.lu, easwar.hariharan,
jacob.jun.pan, kees, kevin.tian, nicolinc, praan, smostafa, tglx,
mingo, bp, dave.hansen, x86, hpa, peterz, sohil.mehta, kas,
alexander.shishkin, ryasuoka, xin, linux-kernel, iommu,
linux-arm-kernel, joonwonkang
For SVA, the IOMMU core always allocates PASID from the global PASID
space. The use of this global PASID space comes from the limitation of
the ENQCMD instruction in Intel CPUs that it fetches its PASID operand
from IA32_PASID, which is per-process; when a process wants to
communicate with multiple devices with the ENQCMD instruction, it cannot
change its PASID for each device without the kernel's intervention. Also
note that ARM introduced a similar instruction, which is ST64BV0.
Due to this nature, SVA with ARM SMMU v3 has been found not working in
our environment when other modules/devices compete for PASID. The
environment looks as follows:
- The device is not a PCIe device.
- The device is to use SVA.
- The supported SSID/PASID space is very small for the device; only 1 to
3 SSIDs are supported.
With this setup, when other modules have allocated all the PASIDs that
our device is expected to use from the global PASID space via APIs like
iommu_alloc_global_pasid() or iommu_sva_bind_device(), SVA binding to
our device fails due to the lack of available PASIDs.
This commit resolves the issue by allowing device driver to maintain its
own PASID space and assign a PASID from that for the process-device bond
via a new API called `iommu_sva_bind_device_pasid(dev, mm, pasid)`. Doing
that, however, will disallow the process to execute the ENQCMD-like
instructions at EL0. It is because the process cannot change its PASID in
IA32_PASID(or ACCDATA_EL1 on ARM) for each device without the kernel's
intervention. For this reason, calling `iommu_sva_bind_device()` and then
`iommu_sva_bind_device_pasid()` for the same process will not be allowed
and vice versa.
Currently, there is a limitation that a process simultaneously doing SVA
with multiple devices with different PASIDs is not supported. So, calling
`iommu_sva_bind_device_pasid()` multiple times for the same process with
different devices will not be allowed for now while that for
`iommu_sva_bind_device()` will be.
Another limitation is that a process cannot do `iommu_sva_bind_device()`
if it has ever done `iommu_sva_bind_device_pasid()` even though it has
been unbound after use.
Suggested-by: Jason Gunthorpe <jgg@ziepe.ca>
Suggested-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Joonwon Kang <joonwonkang@google.com>
---
v2: Reuse iommu_mm->pasid after SVA bound by iommu_sva_bind_device_pasid()
is unbound.
v1: Initial version.
arch/x86/kernel/traps.c | 9 +--
drivers/iommu/iommu-sva.c | 151 +++++++++++++++++++++++++++++---------
include/linux/iommu.h | 14 +++-
3 files changed, 134 insertions(+), 40 deletions(-)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 0ca3912ecb7f..0131c8e5fb10 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -857,13 +857,12 @@ static bool try_fixup_enqcmd_gp(void)
return false;
/*
- * If the mm has not been allocated a
- * PASID, the #GP can not be fixed up.
+ * If the mm has not been allocated a PASID or ENQCMD has been
+ * disallowed, the #GP can not be fixed up.
*/
- if (!mm_valid_pasid(current->mm))
- return false;
-
pasid = mm_get_enqcmd_pasid(current->mm);
+ if (pasid == IOMMU_PASID_INVALID)
+ return false;
/*
* Did this thread already have its PASID activated?
diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c
index bc7c7232a43e..a83333651ad0 100644
--- a/drivers/iommu/iommu-sva.c
+++ b/drivers/iommu/iommu-sva.c
@@ -10,6 +10,9 @@
#include "iommu-priv.h"
+/* Whether pasid is to be allocated from the global PASID space */
+#define IOMMU_PASID_GLOBAL_ANY IOMMU_NO_PASID
+
static DEFINE_MUTEX(iommu_sva_lock);
static bool iommu_sva_present;
static LIST_HEAD(iommu_sva_mms);
@@ -17,10 +20,11 @@ static struct iommu_domain *iommu_sva_domain_alloc(struct device *dev,
struct mm_struct *mm);
/* Allocate a PASID for the mm within range (inclusive) */
-static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct device *dev)
+static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm,
+ struct device *dev,
+ ioasid_t pasid)
{
struct iommu_mm_data *iommu_mm;
- ioasid_t pasid;
lockdep_assert_held(&iommu_sva_lock);
@@ -30,8 +34,27 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
iommu_mm = mm->iommu_mm;
/* Is a PASID already associated with this mm? */
if (iommu_mm) {
+ if ((pasid == IOMMU_PASID_GLOBAL_ANY && !iommu_mm->pasid_global) ||
+ (pasid != IOMMU_PASID_GLOBAL_ANY && iommu_mm->pasid_global))
+ return ERR_PTR(-EBUSY);
+
+ if (!iommu_mm->pasid_global) {
+ if (list_empty(&iommu_mm->sva_domains))
+ iommu_mm->pasid = pasid;
+
+ if (pasid != iommu_mm->pasid) {
+ /*
+ * Currently, a process simultaneously doing
+ * SVA with multiple devices with different
+ * PASIDs is not supported.
+ */
+ return ERR_PTR(-ENOSPC);
+ }
+ }
+
if (iommu_mm->pasid >= dev->iommu->max_pasids)
return ERR_PTR(-EOVERFLOW);
+
return iommu_mm;
}
@@ -39,37 +62,30 @@ static struct iommu_mm_data *iommu_alloc_mm_data(struct mm_struct *mm, struct de
if (!iommu_mm)
return ERR_PTR(-ENOMEM);
- pasid = iommu_alloc_global_pasid(dev);
- if (pasid == IOMMU_PASID_INVALID) {
- kfree(iommu_mm);
- return ERR_PTR(-ENOSPC);
+ if (pasid == IOMMU_PASID_GLOBAL_ANY) {
+ pasid = iommu_alloc_global_pasid(dev);
+ if (pasid == IOMMU_PASID_INVALID) {
+ kfree(iommu_mm);
+ return ERR_PTR(-ENOSPC);
+ }
+ iommu_mm->pasid_global = true;
+ } else {
+ if (pasid >= dev->iommu->max_pasids) {
+ kfree(iommu_mm);
+ return ERR_PTR(-EOVERFLOW);
+ }
+ iommu_mm->pasid_global = false;
}
iommu_mm->pasid = pasid;
iommu_mm->mm = mm;
INIT_LIST_HEAD(&iommu_mm->sva_domains);
- /*
- * Make sure the write to mm->iommu_mm is not reordered in front of
- * initialization to iommu_mm fields. If it does, readers may see a
- * valid iommu_mm with uninitialized values.
- */
- smp_store_release(&mm->iommu_mm, iommu_mm);
+
return iommu_mm;
}
-/**
- * iommu_sva_bind_device() - Bind a process address space to a device
- * @dev: the device
- * @mm: the mm to bind, caller must hold a reference to mm_users
- *
- * Create a bond between device and address space, allowing the device to
- * access the mm using the PASID returned by iommu_sva_get_pasid(). If a
- * bond already exists between @device and @mm, an additional internal
- * reference is taken. Caller must call iommu_sva_unbind_device()
- * to release each reference.
- *
- * On error, returns an ERR_PTR value.
- */
-struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
+static struct iommu_sva *iommu_sva_bind_device_internal(struct device *dev,
+ struct mm_struct *mm,
+ ioasid_t pasid)
{
struct iommu_group *group = dev->iommu_group;
struct iommu_attach_handle *attach_handle;
@@ -84,7 +100,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
mutex_lock(&iommu_sva_lock);
/* Allocate mm->pasid if necessary. */
- iommu_mm = iommu_alloc_mm_data(mm, dev);
+ iommu_mm = iommu_alloc_mm_data(mm, dev, pasid);
if (IS_ERR(iommu_mm)) {
ret = PTR_ERR(iommu_mm);
goto out_unlock;
@@ -96,7 +112,7 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
handle = container_of(attach_handle, struct iommu_sva, handle);
if (attach_handle->domain->mm != mm) {
ret = -EBUSY;
- goto out_unlock;
+ goto out_free_iommu_mm;
}
refcount_inc(&handle->users);
mutex_unlock(&iommu_sva_lock);
@@ -105,17 +121,17 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
if (PTR_ERR(attach_handle) != -ENOENT) {
ret = PTR_ERR(attach_handle);
- goto out_unlock;
+ goto out_free_iommu_mm;
}
handle = kzalloc_obj(*handle);
if (!handle) {
ret = -ENOMEM;
- goto out_unlock;
+ goto out_free_iommu_mm;
}
/* Search for an existing domain. */
- list_for_each_entry(domain, &mm->iommu_mm->sva_domains, next) {
+ list_for_each_entry(domain, &iommu_mm->sva_domains, next) {
ret = iommu_attach_device_pasid(domain, dev, iommu_mm->pasid,
&handle->handle);
if (!ret) {
@@ -143,6 +159,15 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
list_add(&iommu_mm->mm_list_elm, &iommu_sva_mms);
}
list_add(&domain->next, &iommu_mm->sva_domains);
+ if (!mm->iommu_mm) {
+ /*
+ * Make sure the write to mm->iommu_mm is not reordered in
+ * front of initialization to iommu_mm fields. If it does,
+ * readers may see a valid iommu_mm with uninitialized values.
+ */
+ smp_store_release(&mm->iommu_mm, iommu_mm);
+ }
+
out:
refcount_set(&handle->users, 1);
mutex_unlock(&iommu_sva_lock);
@@ -153,12 +178,66 @@ struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm
iommu_domain_free(domain);
out_free_handle:
kfree(handle);
+out_free_iommu_mm:
+ if (!mm->iommu_mm) {
+ if (iommu_mm->pasid_global)
+ iommu_free_global_pasid(iommu_mm->pasid);
+ kfree(iommu_mm);
+ }
out_unlock:
mutex_unlock(&iommu_sva_lock);
return ERR_PTR(ret);
}
+
+/**
+ * iommu_sva_bind_device() - Bind a process address space to a device
+ * @dev: the device
+ * @mm: the mm to bind, caller must hold a reference to mm_users
+ *
+ * Create a bond between device and address space, allowing the device to
+ * access the mm using the PASID returned by iommu_sva_get_pasid(). If a
+ * bond already exists between @device and @mm, an additional internal
+ * reference is taken. Caller must call iommu_sva_unbind_device()
+ * to release each reference.
+ *
+ * On error, returns an ERR_PTR value.
+ */
+struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
+{
+ return iommu_sva_bind_device_internal(dev, mm, IOMMU_PASID_GLOBAL_ANY);
+}
EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
+/**
+ * iommu_sva_bind_device_pasid() - Bind a process address space to a device
+ * with a designated pasid
+ * @dev: the device
+ * @mm: the mm to bind, caller must hold a reference to mm_users
+ * @pasid: the pasid to assign to the bond
+ *
+ * Create a bond between device and address space, allowing the device to
+ * access the mm using the PASID returned by iommu_sva_get_pasid(). If a
+ * bond already exists between @device and @mm, an additional internal
+ * reference is taken. Caller must call iommu_sva_unbind_device()
+ * to release each reference.
+ *
+ * It is the caller's responsibility to maintain the PASID space for @pasid.
+ * After the bond is created, the process for @mm will not be able to execute
+ * ENQCMD or similar instructions at EL0. To allow those instructions at EL0,
+ * iommu_sva_bind_device() must be used instead.
+ *
+ * On error, returns an ERR_PTR value.
+ */
+struct iommu_sva *iommu_sva_bind_device_pasid(struct device *dev,
+ struct mm_struct *mm,
+ ioasid_t pasid)
+{
+ if (pasid == IOMMU_PASID_GLOBAL_ANY)
+ return ERR_PTR(-EINVAL);
+ return iommu_sva_bind_device_internal(dev, mm, pasid);
+}
+EXPORT_SYMBOL_GPL(iommu_sva_bind_device_pasid);
+
/**
* iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
* @handle: the handle returned by iommu_sva_bind_device()
@@ -198,9 +277,12 @@ EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
u32 iommu_sva_get_pasid(struct iommu_sva *handle)
{
- struct iommu_domain *domain = handle->handle.domain;
+ struct iommu_mm_data *iommu_mm = handle->handle.domain->mm->iommu_mm;
+
+ if (!iommu_mm)
+ return IOMMU_PASID_INVALID;
- return mm_get_enqcmd_pasid(domain->mm);
+ return iommu_mm->pasid;
}
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
@@ -211,7 +293,8 @@ void mm_pasid_drop(struct mm_struct *mm)
if (!iommu_mm)
return;
- iommu_free_global_pasid(iommu_mm->pasid);
+ if (iommu_mm->pasid_global)
+ iommu_free_global_pasid(iommu_mm->pasid);
kfree(iommu_mm);
}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e587d4ac4d33..5b6116e7152d 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -1140,6 +1140,7 @@ struct iommu_sva {
struct iommu_mm_data {
u32 pasid;
+ bool pasid_global;
struct mm_struct *mm;
struct list_head sva_domains;
struct list_head mm_list_elm;
@@ -1626,7 +1627,7 @@ static inline u32 mm_get_enqcmd_pasid(struct mm_struct *mm)
{
struct iommu_mm_data *iommu_mm = READ_ONCE(mm->iommu_mm);
- if (!iommu_mm)
+ if (!iommu_mm || !iommu_mm->pasid_global)
return IOMMU_PASID_INVALID;
return iommu_mm->pasid;
}
@@ -1634,6 +1635,9 @@ static inline u32 mm_get_enqcmd_pasid(struct mm_struct *mm)
void mm_pasid_drop(struct mm_struct *mm);
struct iommu_sva *iommu_sva_bind_device(struct device *dev,
struct mm_struct *mm);
+struct iommu_sva *iommu_sva_bind_device_pasid(struct device *dev,
+ struct mm_struct *mm,
+ ioasid_t pasid);
void iommu_sva_unbind_device(struct iommu_sva *handle);
u32 iommu_sva_get_pasid(struct iommu_sva *handle);
void iommu_sva_invalidate_kva_range(unsigned long start, unsigned long end);
@@ -1644,6 +1648,14 @@ iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
return ERR_PTR(-ENODEV);
}
+static inline struct iommu_sva *
+iommu_sva_bind_device_pasid(struct device *dev,
+ struct mm_struct *mm,
+ ioasid_t pasid)
+{
+ return ERR_PTR(-ENODEV);
+}
+
static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
{
}
--
2.54.0.631.ge1b05301d1-goog
^ permalink raw reply related
* [PATCH v8 0/5] airoha: an7581: USB support
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
This is a major rework of the old v2 series.
The SoC always support USB 2.0 but for USB 3.0 it needs additional
configuration for the Serdes port. Such port can be either configured
for USB usage or for PCIe lines or HSGMII and these are configured
in the SCU space.
The previous implementation of a dedicated SSR driver was too
complex and fragile for the simple task of configuring a register
hence it was dropped and the handling is entirely in the PHY driver.
Everything was reducted to the dt-bindings to describe the Serdes line.
Also the property for the PHY are renamed to a more suitable name and
everything is now mandatory to simplify the implementation.
(the PHY are always present and active on the SoC)
Also other unrelated patch are dropped from this series.
Changes v8:
- Squash header to clk Documentation patch
- Address comments from AI Bot
Changes v7:
- Rework to double PHY implementation
(suggested by Rob)
Now the clk driver expose a PHY for Serdes port
USB PHY driver selects it
- Rebase on top of linux-next
Link: https://lore.kernel.org/all/20260306190156.22297-1-ansuelsmth@gmail.com/
Changes v6:
- Fix kernel test robot (sparse warning)
Link: https://lore.kernel.org/all/20260306190156.22297-1-ansuelsmth@gmail.com/
Changes v5:
- Add Ack and Review tag from Connor
- Implement Ethernet support in the USB driver
(testing support for this Serdes on a special reference board)
- Use an7581 prefix for USB PHY driver
Link: https://lore.kernel.org/all/20251107160251.2307088-1-ansuelsmth@gmail.com/
Changes v4:
- Rename PCIe and USB PHY to AN7581
- Drop airoha,scu (handled directly in driver)
- Drop dt-bindings for monitor clock in favor of raw values
- Better describe the usage of airoha,usb3-serdes
- Simplify values of dt-bindings SSR SERDES
Link: https://lore.kernel.org/all/20251107160251.2307088-1-ansuelsmth@gmail.com/
Changes v3:
- Drop clk changes
- Drop SSR driver
- Rename property in Documentation
- Simplify PHY handling
- Move SSR handling inside the PHY driver
Link: https://lore.kernel.org/all/20251029173713.7670-1-ansuelsmth@gmail.com/
Changes v2:
- Drop changes for simple-mfd
- Rework PHY node structure to single node
- Drop port-id property in favor of serdes-port and
usb2-monitor-clock-sel
- Make the SSR driver probe from the clock driver
Christian Marangi (5):
dt-bindings: clock: airoha: Add PHY binding for Serdes port
dt-bindings: phy: Add documentation for Airoha AN7581 USB PHY
clk: en7523: Add support for selecting the Serdes port in SCU
phy: move and rename Airoha PCIe PHY driver to dedicated directory
phy: airoha: Add support for Airoha AN7581 USB PHY
.../bindings/clock/airoha,en7523-scu.yaml | 9 +
.../bindings/phy/airoha,an7581-usb-phy.yaml | 62 ++
MAINTAINERS | 11 +-
drivers/clk/Kconfig | 1 +
drivers/clk/clk-en7523.c | 216 ++++++-
drivers/phy/Kconfig | 11 +-
drivers/phy/Makefile | 4 +-
drivers/phy/airoha/Kconfig | 24 +
drivers/phy/airoha/Makefile | 4 +
.../phy-an7581-pcie-regs.h} | 2 +-
.../phy-an7581-pcie.c} | 6 +-
drivers/phy/airoha/phy-an7581-usb.c | 554 ++++++++++++++++++
include/dt-bindings/soc/airoha,scu-ssr.h | 11 +
13 files changed, 894 insertions(+), 21 deletions(-)
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
create mode 100644 drivers/phy/airoha/Kconfig
create mode 100644 drivers/phy/airoha/Makefile
rename drivers/phy/{phy-airoha-pcie-regs.h => airoha/phy-an7581-pcie-regs.h} (99%)
rename drivers/phy/{phy-airoha-pcie.c => airoha/phy-an7581-pcie.c} (99%)
create mode 100644 drivers/phy/airoha/phy-an7581-usb.c
create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h
--
2.53.0
^ permalink raw reply
* [PATCH v8 1/5] dt-bindings: clock: airoha: Add PHY binding for Serdes port
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
Add PHY cell property for Serdes port selection. Currently supported only
for Airoha AN7581 SoC, that support up to 4 Serdes port.
The Serdes port can support both PCIe, USB3 or Ethernet mode.
- PCIe1 Serdes can support PCIe or Ethernet mode.
- PCIe2 Serdes can support PCIe or Ethernet mode.
- USB1 Serdes can support USB3 or HSGMII mode.
- USB2 Serdes can support USB3 or PCIe mode.
Add bindings to permit correct reference of the Serdes ports in DT.
Values are just symbolic and enumerates the Serdes port with a specific
number for precise reference.
The available Serdes port can be selected following the dt-binding header
in [2].
[2] <include/dt-bindings/soc/airoha,scu-ssr.h>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../devicetree/bindings/clock/airoha,en7523-scu.yaml | 9 +++++++++
include/dt-bindings/soc/airoha,scu-ssr.h | 11 +++++++++++
2 files changed, 20 insertions(+)
create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h
diff --git a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
index eb24a5687639..913ddc16182b 100644
--- a/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
+++ b/Documentation/devicetree/bindings/clock/airoha,en7523-scu.yaml
@@ -23,6 +23,7 @@ description: |
All these identifiers can be found in:
[1]: <include/dt-bindings/clock/en7523-clk.h>.
+ [2]: <include/dt-bindings/soc/airoha,scu-ssr.h>.
The clocks are provided inside a system controller node.
@@ -50,6 +51,12 @@ properties:
description: ID of the controller reset line
const: 1
+ '#phy-cells':
+ description:
+ The first cell indicates the serdes phy number, see [2] for the
+ available serdes port.
+ const: 1
+
required:
- compatible
- reg
@@ -65,6 +72,8 @@ allOf:
reg:
minItems: 2
+ '#phy-cells': false
+
- if:
properties:
compatible:
diff --git a/include/dt-bindings/soc/airoha,scu-ssr.h b/include/dt-bindings/soc/airoha,scu-ssr.h
new file mode 100644
index 000000000000..33c64844ada3
--- /dev/null
+++ b/include/dt-bindings/soc/airoha,scu-ssr.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+
+#ifndef __DT_BINDINGS_AIROHA_SCU_SSR_H
+#define __DT_BINDINGS_AIROHA_SCU_SSR_H
+
+#define AIROHA_SCU_SERDES_PCIE1 0
+#define AIROHA_SCU_SERDES_PCIE2 1
+#define AIROHA_SCU_SERDES_USB1 2
+#define AIROHA_SCU_SERDES_USB2 3
+
+#endif /* __DT_BINDINGS_AIROHA_SCU_SSR_H */
--
2.53.0
^ permalink raw reply related
* [PATCH v8 2/5] dt-bindings: phy: Add documentation for Airoha AN7581 USB PHY
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
Add documentation for Airoha AN7581 USB PHY that describe the USB PHY
for the USB controller.
Airoha AN7581 SoC support a maximum of 2 USB port. The USB 2.0 mode is
always supported. The USB 3.0 mode is optional and depends on the Serdes
mode currently configured on the system for the relevant USB port.
To correctly calibrate, the USB 2.0 port require correct value in
"airoha,usb2-monitor-clk-sel" property. Both the 2 USB 2.0 port permit
selecting one of the 4 monitor clock for calibration (internal clock not
exposed to the system) but each port have only one of the 4 actually
connected in HW hence the correct value needs to be specified in DT
based on board and the physical port. Normally it's monitor clock 1 for
USB1 and monitor clock 2 for USB2.
To correctly setup the Serdes mode attached to the USB 3.0 mode, a phys
property is required with the phandle pointing to the correct Serdes port
provided by the SCU node.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
.../bindings/phy/airoha,an7581-usb-phy.yaml | 62 +++++++++++++++++++
MAINTAINERS | 6 ++
2 files changed, 68 insertions(+)
create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
diff --git a/Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml b/Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
new file mode 100644
index 000000000000..f561cf2a8103
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
@@ -0,0 +1,62 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/phy/airoha,an7581-usb-phy.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha AN7581 SoC USB PHY
+
+maintainers:
+ - Christian Marangi <ansuelsmth@gmail.com>
+
+description: >
+ The Airoha AN7581 SoC USB PHY describes the USB PHY for the USB controller.
+
+ Airoha AN7581 SoC support a maximum of 2 USB port. The USB 2.0 mode is
+ always supported. The USB 3.0 mode is optional and depends on the Serdes
+ mode currently configured on the system for the relevant USB port.
+
+properties:
+ compatible:
+ const: airoha,an7581-usb-phy
+
+ reg:
+ maxItems: 1
+
+ airoha,usb2-monitor-clk-sel:
+ description: Describe what oscillator across the available 4
+ should be selected for USB 2.0 Slew Rate calibration.
+ $ref: /schemas/types.yaml#/definitions/uint32
+ enum: [0, 1, 2, 3]
+
+ phys:
+ items:
+ - description: phandle to Serdes PHY
+
+ '#phy-cells':
+ description: The cell contains the mode, PHY_TYPE_USB2 or PHY_TYPE_USB3,
+ as defined in dt-bindings/phy/phy.h.
+ const: 1
+
+required:
+ - compatible
+ - reg
+ - airoha,usb2-monitor-clk-sel
+ - '#phy-cells'
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/airoha,scu-ssr.h>
+
+ phy@1fac0000 {
+ compatible = "airoha,an7581-usb-phy";
+ reg = <0x1fac0000 0x10000>;
+
+ airoha,usb2-monitor-clk-sel = <1>;
+ phys = <&scu AIROHA_SCU_SERDES_USB1>;
+
+ #phy-cells = <1>;
+ };
+
diff --git a/MAINTAINERS b/MAINTAINERS
index 21c0ef0b9ce5..932044785a39 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -771,6 +771,12 @@ S: Maintained
F: Documentation/devicetree/bindings/spi/airoha,en7581-snand.yaml
F: drivers/spi/spi-airoha-snfi.c
+AIROHA USB PHY DRIVER
+M: Christian Marangi <ansuelsmth@gmail.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
+
AIRSPY MEDIA DRIVER
L: linux-media@vger.kernel.org
S: Orphan
--
2.53.0
^ permalink raw reply related
* [PATCH v8 4/5] phy: move and rename Airoha PCIe PHY driver to dedicated directory
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
To keep the generic PHY directory tidy, move the PCIe PHY driver for
Airoha AN7581 SoC to a dedicated directory.
Also rename the driver and add the relevant SoC name to the .c and .h
file in preparation for support of PCIe and USB PHY driver for Airoha
AN7583 SoC that use a completely different implementation and
calibration for PHYs and will have their own dedicated drivers.
The rename permits to better identify the specific usage of the driver
in the future once the airoha PHY directory will have multiple driver
for multiple SoC.
The config is changed from PHY_AIROHA_PCIE to PHY_AIROHA_AN7581_PCIE.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
MAINTAINERS | 4 ++--
drivers/phy/Kconfig | 11 +----------
drivers/phy/Makefile | 4 ++--
drivers/phy/airoha/Kconfig | 13 +++++++++++++
drivers/phy/airoha/Makefile | 3 +++
.../phy-an7581-pcie-regs.h} | 2 +-
.../{phy-airoha-pcie.c => airoha/phy-an7581-pcie.c} | 6 +++---
7 files changed, 25 insertions(+), 18 deletions(-)
create mode 100644 drivers/phy/airoha/Kconfig
create mode 100644 drivers/phy/airoha/Makefile
rename drivers/phy/{phy-airoha-pcie-regs.h => airoha/phy-an7581-pcie-regs.h} (99%)
rename drivers/phy/{phy-airoha-pcie.c => airoha/phy-an7581-pcie.c} (99%)
diff --git a/MAINTAINERS b/MAINTAINERS
index 932044785a39..7bea8c620da8 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -759,8 +759,8 @@ M: Lorenzo Bianconi <lorenzo@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/phy/airoha,en7581-pcie-phy.yaml
-F: drivers/phy/phy-airoha-pcie-regs.h
-F: drivers/phy/phy-airoha-pcie.c
+F: drivers/phy/airoha/phy-an7581-pcie-regs.h
+F: drivers/phy/airoha/phy-an7581-pcie.c
AIROHA SPI SNFI DRIVER
M: Lorenzo Bianconi <lorenzo@kernel.org>
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 227b9a4c612e..f9cd765a3ccc 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -46,16 +46,6 @@ config GENERIC_PHY_MIPI_DPHY
Provides a number of helpers a core functions for MIPI D-PHY
drivers to us.
-config PHY_AIROHA_PCIE
- tristate "Airoha PCIe-PHY Driver"
- depends on ARCH_AIROHA || COMPILE_TEST
- depends on OF
- select GENERIC_PHY
- help
- Say Y here to add support for Airoha PCIe PHY driver.
- This driver create the basic PHY instance and provides initialize
- callback for PCIe GEN3 port.
-
config PHY_CAN_TRANSCEIVER
tristate "CAN transceiver PHY"
select GENERIC_PHY
@@ -133,6 +123,7 @@ config PHY_XGENE
help
This option enables support for APM X-Gene SoC multi-purpose PHY.
+source "drivers/phy/airoha/Kconfig"
source "drivers/phy/allwinner/Kconfig"
source "drivers/phy/amlogic/Kconfig"
source "drivers/phy/apple/Kconfig"
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index f49d83f00a3d..84062279fa63 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_PHY_COMMON_PROPS) += phy-common-props.o
obj-$(CONFIG_PHY_COMMON_PROPS_TEST) += phy-common-props-test.o
obj-$(CONFIG_GENERIC_PHY) += phy-core.o
obj-$(CONFIG_GENERIC_PHY_MIPI_DPHY) += phy-core-mipi-dphy.o
-obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o
obj-$(CONFIG_PHY_CAN_TRANSCEIVER) += phy-can-transceiver.o
obj-$(CONFIG_PHY_GOOGLE_USB) += phy-google-usb.o
obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o
@@ -17,7 +16,8 @@ obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o
obj-$(CONFIG_PHY_SNPS_EUSB2) += phy-snps-eusb2.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
-obj-$(CONFIG_GENERIC_PHY) += allwinner/ \
+obj-$(CONFIG_GENERIC_PHY) += airoha/ \
+ allwinner/ \
amlogic/ \
apple/ \
broadcom/ \
diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig
new file mode 100644
index 000000000000..9a1b625a7701
--- /dev/null
+++ b/drivers/phy/airoha/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Phy drivers for Airoha devices
+#
+config PHY_AIROHA_AN7581_PCIE
+ tristate "Airoha AN7581 PCIe-PHY Driver"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ help
+ Say Y here to add support for Airoha AN7581 PCIe PHY driver.
+ This driver create the basic PHY instance and provides initialize
+ callback for PCIe GEN3 port.
diff --git a/drivers/phy/airoha/Makefile b/drivers/phy/airoha/Makefile
new file mode 100644
index 000000000000..912f3e11a061
--- /dev/null
+++ b/drivers/phy/airoha/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-$(CONFIG_PHY_AIROHA_AN7581_PCIE) += phy-an7581-pcie.o
diff --git a/drivers/phy/phy-airoha-pcie-regs.h b/drivers/phy/airoha/phy-an7581-pcie-regs.h
similarity index 99%
rename from drivers/phy/phy-airoha-pcie-regs.h
rename to drivers/phy/airoha/phy-an7581-pcie-regs.h
index 58572c793722..b938a7b468fe 100644
--- a/drivers/phy/phy-airoha-pcie-regs.h
+++ b/drivers/phy/airoha/phy-an7581-pcie-regs.h
@@ -1,4 +1,4 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2024 AIROHA Inc
* Author: Lorenzo Bianconi <lorenzo@kernel.org>
diff --git a/drivers/phy/phy-airoha-pcie.c b/drivers/phy/airoha/phy-an7581-pcie.c
similarity index 99%
rename from drivers/phy/phy-airoha-pcie.c
rename to drivers/phy/airoha/phy-an7581-pcie.c
index 56e9ade8a9fd..81ddf0e7638b 100644
--- a/drivers/phy/phy-airoha-pcie.c
+++ b/drivers/phy/airoha/phy-an7581-pcie.c
@@ -13,7 +13,7 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include "phy-airoha-pcie-regs.h"
+#include "phy-an7581-pcie-regs.h"
#define LEQ_LEN_CTRL_MAX_VAL 7
#define FREQ_LOCK_MAX_ATTEMPT 10
@@ -1279,12 +1279,12 @@ MODULE_DEVICE_TABLE(of, airoha_pcie_phy_of_match);
static struct platform_driver airoha_pcie_phy_driver = {
.probe = airoha_pcie_phy_probe,
.driver = {
- .name = "airoha-pcie-phy",
+ .name = "airoha-an7581-pcie-phy",
.of_match_table = airoha_pcie_phy_of_match,
},
};
module_platform_driver(airoha_pcie_phy_driver);
-MODULE_DESCRIPTION("Airoha PCIe PHY driver");
+MODULE_DESCRIPTION("Airoha AN7581 PCIe PHY driver");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* [PATCH v8 3/5] clk: en7523: Add support for selecting the Serdes port in SCU
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
In the SCU register for clock and reset, there are also some register to
select the Serdes port mode. The Airoha AN7581 SoC have 4 different Serdes
that can switch between PCIe, USB or Ethernet mode.
Add a simple PHY provider that expose the .set_mode OP to toggle the
requested mode for the Serdes port.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
drivers/clk/Kconfig | 1 +
drivers/clk/clk-en7523.c | 216 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 214 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index b2efbe9f6acb..e60a824b5117 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -221,6 +221,7 @@ config COMMON_CLK_EN7523
bool "Clock driver for Airoha/EcoNet SoC system clocks"
depends on OF
depends on ARCH_AIROHA || ECONET || COMPILE_TEST
+ select GENERIC_PHY
default ARCH_AIROHA
help
This driver provides the fixed clocks and gates present on Airoha
diff --git a/drivers/clk/clk-en7523.c b/drivers/clk/clk-en7523.c
index 1ab0e2eca5d3..d4b73c5f15b9 100644
--- a/drivers/clk/clk-en7523.c
+++ b/drivers/clk/clk-en7523.c
@@ -6,14 +6,18 @@
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
+#include <linux/phy/phy.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
#include <dt-bindings/clock/en7523-clk.h>
#include <dt-bindings/reset/airoha,en7523-reset.h>
#include <dt-bindings/reset/airoha,en7581-reset.h>
#include <dt-bindings/clock/econet,en751221-scu.h>
#include <dt-bindings/reset/econet,en751221-scu.h>
+#include <dt-bindings/soc/airoha,scu-ssr.h>
#define RST_NR_PER_BANK 32
@@ -40,9 +44,22 @@
#define REG_HIR_MASK GENMASK(31, 16)
/* EN7581 */
#define REG_NP_SCU_PCIC 0x88
+#define REG_NP_SCU_SSR3 0x94
+#define REG_SSUSB_HSGMII_SEL_MASK BIT(29)
+#define REG_SSUSB_HSGMII_SEL_HSGMII FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x0)
+#define REG_SSUSB_HSGMII_SEL_USB FIELD_PREP_CONST(REG_SSUSB_HSGMII_SEL_MASK, 0x1)
#define REG_NP_SCU_SSTR 0x9c
#define REG_PCIE_XSI0_SEL_MASK GENMASK(14, 13)
+#define REG_PCIE_XSI0_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x0)
+#define REG_PCIE_XSI0_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x1)
+#define REG_PCIE_XSI0_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI0_SEL_MASK, 0x2)
#define REG_PCIE_XSI1_SEL_MASK GENMASK(12, 11)
+#define REG_PCIE_XSI1_SEL_PCIE FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x0)
+#define REG_PCIE_XSI1_SEL_XFI FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x1)
+#define REG_PCIE_XSI1_SEL_HSGMII FIELD_PREP_CONST(REG_PCIE_XSI1_SEL_MASK, 0x2)
+#define REG_USB_PCIE_SEL_MASK BIT(3)
+#define REG_USB_PCIE_SEL_PCIE FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x0)
+#define REG_USB_PCIE_SEL_USB FIELD_PREP_CONST(REG_USB_PCIE_SEL_MASK, 0x1)
#define REG_CRYPTO_CLKSRC2 0x20c
/* EN751221 */
#define EN751221_REG_SPI_DIV 0x0cc
@@ -81,6 +98,8 @@ enum en_hir {
HIR_MAX = 14,
};
+#define EN_SERDES_PHY_NUM 4
+
struct en_clk_desc {
int id;
const char *name;
@@ -113,6 +132,18 @@ struct en_rst_data {
struct reset_controller_dev rcdev;
};
+struct en_serdes_phy_instance {
+ struct phy *phy;
+ unsigned int serdes_port;
+};
+
+struct en_clk_priv {
+ void __iomem *base;
+ /* protect SCU register */
+ spinlock_t lock;
+ struct en_serdes_phy_instance *serdes_phys[EN_SERDES_PHY_NUM];
+};
+
struct en_clk_soc_data {
u32 num_clocks;
const struct clk_ops pcie_ops;
@@ -830,12 +861,179 @@ static int en7581_reset_register(struct device *dev, void __iomem *base,
return devm_reset_controller_register(dev, &rst_data->rcdev);
}
+static int en7581_serdes_phy_set_mode(struct phy *phy, enum phy_mode mode,
+ int submode)
+{
+ struct en_serdes_phy_instance *instance = phy_get_drvdata(phy);
+ struct en_clk_priv *priv = dev_get_drvdata(phy->dev.parent);
+ u32 reg, mask, sel, val;
+ unsigned long flags;
+
+ switch (instance->serdes_port) {
+ case AIROHA_SCU_SERDES_PCIE1:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_PCIE_XSI0_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET) {
+ switch (submode) {
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ sel = REG_PCIE_XSI0_SEL_XFI;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ sel = REG_PCIE_XSI0_SEL_HSGMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ sel = REG_PCIE_XSI0_SEL_PCIE;
+ }
+
+ break;
+ case AIROHA_SCU_SERDES_PCIE2:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_PCIE_XSI1_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_PCIE)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET) {
+ switch (submode) {
+ case PHY_INTERFACE_MODE_USXGMII:
+ case PHY_INTERFACE_MODE_10GBASER:
+ sel = REG_PCIE_XSI1_SEL_XFI;
+ break;
+ case PHY_INTERFACE_MODE_SGMII:
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_2500BASEX:
+ sel = REG_PCIE_XSI1_SEL_HSGMII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ sel = REG_PCIE_XSI1_SEL_PCIE;
+ }
+
+ break;
+ case AIROHA_SCU_SERDES_USB1:
+ reg = REG_NP_SCU_SSR3;
+ mask = REG_SSUSB_HSGMII_SEL_MASK;
+
+ if (mode != PHY_MODE_ETHERNET && mode != PHY_MODE_USB_DEVICE &&
+ mode != PHY_MODE_USB_DEVICE_SS)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_ETHERNET)
+ sel = REG_SSUSB_HSGMII_SEL_HSGMII;
+ else
+ sel = REG_SSUSB_HSGMII_SEL_USB;
+
+ break;
+ case AIROHA_SCU_SERDES_USB2:
+ reg = REG_NP_SCU_SSTR;
+ mask = REG_USB_PCIE_SEL_MASK;
+
+ if (mode != PHY_MODE_PCIE && mode != PHY_MODE_USB_DEVICE &&
+ mode != PHY_MODE_USB_DEVICE_SS)
+ return -EINVAL;
+
+ if (mode == PHY_MODE_PCIE)
+ sel = REG_USB_PCIE_SEL_PCIE;
+ else
+ sel = REG_USB_PCIE_SEL_USB;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->lock, flags);
+ val = readl(priv->base + reg);
+ val &= ~mask;
+ val |= sel;
+ writel(val, priv->base + reg);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static const struct phy_ops en7581_serdes_phy_ops = {
+ .set_mode = en7581_serdes_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static struct phy *en7581_serdes_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct en_clk_priv *priv = dev_get_drvdata(dev);
+ struct en_serdes_phy_instance *instance;
+ unsigned int serdes_port;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ serdes_port = args->args[0];
+ if (serdes_port >= EN_SERDES_PHY_NUM) {
+ dev_err(dev, "invalid serdes port: %d\n", serdes_port);
+ return ERR_PTR(-EINVAL);
+ }
+
+ instance = priv->serdes_phys[serdes_port];
+ if (!instance) {
+ dev_err(dev, "failed to find appropriate serdes phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return instance->phy;
+}
+
+static int en7581_serdes_phy_register(struct device *dev)
+{
+ struct en_clk_priv *priv = dev_get_drvdata(dev);
+ struct phy_provider *phy_provider;
+ int i;
+
+ for (i = 0; i < EN_SERDES_PHY_NUM; i++) {
+ struct en_serdes_phy_instance *instance;
+
+ instance = devm_kzalloc(dev, sizeof(*instance),
+ GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ instance->phy = devm_phy_create(dev, NULL,
+ &en7581_serdes_phy_ops);
+ if (IS_ERR(instance->phy))
+ return dev_err_probe(dev, PTR_ERR(instance->phy), "failed to create phy\n");
+
+ instance->serdes_port = i;
+ priv->serdes_phys[i] = instance;
+
+ phy_set_drvdata(instance->phy, instance);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, en7581_serdes_phy_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
static int en7581_clk_hw_init(struct platform_device *pdev,
struct clk_hw_onecell_data *clk_data)
{
+ struct en_clk_priv *priv = platform_get_drvdata(pdev);
struct regmap *map;
void __iomem *base;
u32 val;
+ int ret;
map = syscon_regmap_lookup_by_compatible("airoha,en7581-chip-scu");
if (IS_ERR(map))
@@ -845,6 +1043,8 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
if (IS_ERR(base))
return PTR_ERR(base);
+ priv->base = base;
+
en7581_register_clocks(&pdev->dev, clk_data, map, base);
val = readl(base + REG_NP_SCU_SSTR);
@@ -853,9 +1053,12 @@ static int en7581_clk_hw_init(struct platform_device *pdev,
val = readl(base + REG_NP_SCU_PCIC);
writel(val | 3, base + REG_NP_SCU_PCIC);
- return en7581_reset_register(&pdev->dev, base, en7581_rst_map,
- ARRAY_SIZE(en7581_rst_map),
- en7581_rst_ofs);
+ ret = en7581_reset_register(&pdev->dev, base, en7581_rst_map,
+ ARRAY_SIZE(en7581_rst_map), en7581_rst_ofs);
+ if (ret)
+ return ret;
+
+ return en7581_serdes_phy_register(&pdev->dev);
}
static enum en_hir get_hw_id(void __iomem *np_base)
@@ -962,16 +1165,23 @@ static int en7523_clk_probe(struct platform_device *pdev)
struct device_node *node = pdev->dev.of_node;
const struct en_clk_soc_data *soc_data;
struct clk_hw_onecell_data *clk_data;
+ struct en_clk_priv *priv;
int r;
soc_data = device_get_match_data(&pdev->dev);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
clk_data = devm_kzalloc(&pdev->dev,
struct_size(clk_data, hws, soc_data->num_clocks),
GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
+ platform_set_drvdata(pdev, priv);
+
clk_data->num = soc_data->num_clocks;
r = soc_data->hw_init(pdev, clk_data);
if (r)
--
2.53.0
^ permalink raw reply related
* [PATCH v8 5/5] phy: airoha: Add support for Airoha AN7581 USB PHY
From: Christian Marangi @ 2026-05-20 15:09 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Christian Marangi, Vinod Koul,
Neil Armstrong, Lorenzo Bianconi, Felix Fietkau, linux-clk,
devicetree, linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
Add support for Airoha AN7581 USB PHY driver. AN7581 supports up to 2
USB port with USB 2.0 mode always supported and USB 3.0 mode available
only if the Serdes port is correctly configured for USB 3.0.
If the USB 3.0 mode is not configured, the modes needs to be also
disabled in the xHCI node or the driver will report unsable clock and
fail probe.
For USB 2.0 Slew Rate calibration, airoha,usb2-monitor-clk-sel is
mandatory and is used to select the monitor clock for calibration.
Normally it's 1 for USB port 1 and 2 for USB port 2.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
MAINTAINERS | 1 +
drivers/phy/airoha/Kconfig | 11 +
drivers/phy/airoha/Makefile | 1 +
drivers/phy/airoha/phy-an7581-usb.c | 554 ++++++++++++++++++++++++++++
4 files changed, 567 insertions(+)
create mode 100644 drivers/phy/airoha/phy-an7581-usb.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 7bea8c620da8..2f05faa44503 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -776,6 +776,7 @@ M: Christian Marangi <ansuelsmth@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
+F: drivers/phy/airoha/phy-an7581-usb.c
AIRSPY MEDIA DRIVER
L: linux-media@vger.kernel.org
diff --git a/drivers/phy/airoha/Kconfig b/drivers/phy/airoha/Kconfig
index 9a1b625a7701..634448ee39b5 100644
--- a/drivers/phy/airoha/Kconfig
+++ b/drivers/phy/airoha/Kconfig
@@ -11,3 +11,14 @@ config PHY_AIROHA_AN7581_PCIE
Say Y here to add support for Airoha AN7581 PCIe PHY driver.
This driver create the basic PHY instance and provides initialize
callback for PCIe GEN3 port.
+
+config PHY_AIROHA_AN7581_USB
+ tristate "Airoha AN7581 USB PHY Driver"
+ depends on ARCH_AIROHA || COMPILE_TEST
+ depends on OF
+ select GENERIC_PHY
+ select REGMAP_MMIO
+ help
+ Say 'Y' here to add support for Airoha AN7581 USB PHY driver.
+ This driver create the basic PHY instance and provides initialize
+ callback for USB port.
diff --git a/drivers/phy/airoha/Makefile b/drivers/phy/airoha/Makefile
index 912f3e11a061..944bf842deba 100644
--- a/drivers/phy/airoha/Makefile
+++ b/drivers/phy/airoha/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_PHY_AIROHA_AN7581_PCIE) += phy-an7581-pcie.o
+obj-$(CONFIG_PHY_AIROHA_AN7581_USB) += phy-an7581-usb.o
diff --git a/drivers/phy/airoha/phy-an7581-usb.c b/drivers/phy/airoha/phy-an7581-usb.c
new file mode 100644
index 000000000000..af20f5cb4ed1
--- /dev/null
+++ b/drivers/phy/airoha/phy-an7581-usb.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Author: Christian Marangi <ansuelsmth@gmail.com>
+ */
+
+#include <dt-bindings/phy/phy.h>
+#include <dt-bindings/soc/airoha,scu-ssr.h>
+#include <linux/bitfield.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* U2PHY */
+#define AIROHA_USB_PHY_FMCR0 0x100
+#define AIROHA_USB_PHY_MONCLK_SEL GENMASK(27, 26)
+#define AIROHA_USB_PHY_MONCLK_SEL0 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x0)
+#define AIROHA_USB_PHY_MONCLK_SEL1 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x1)
+#define AIROHA_USB_PHY_MONCLK_SEL2 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x2)
+#define AIROHA_USB_PHY_MONCLK_SEL3 FIELD_PREP_CONST(AIROHA_USB_PHY_MONCLK_SEL, 0x3)
+#define AIROHA_USB_PHY_FREQDET_EN BIT(24)
+#define AIROHA_USB_PHY_CYCLECNT GENMASK(23, 0)
+#define AIROHA_USB_PHY_FMMONR0 0x10c
+#define AIROHA_USB_PHY_USB_FM_OUT GENMASK(31, 0)
+#define AIROHA_USB_PHY_FMMONR1 0x110
+#define AIROHA_USB_PHY_FRCK_EN BIT(8)
+
+#define AIROHA_USB_PHY_USBPHYACR4 0x310
+#define AIROHA_USB_PHY_USB20_FS_CR GENMASK(10, 8)
+#define AIROHA_USB_PHY_USB20_FS_CR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x0)
+#define AIROHA_USB_PHY_USB20_FS_CR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x2)
+#define AIROHA_USB_PHY_USB20_FS_CR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x4)
+#define AIROHA_USB_PHY_USB20_FS_CR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_CR, 0x6)
+#define AIROHA_USB_PHY_USB20_FS_SR GENMASK(2, 0)
+#define AIROHA_USB_PHY_USB20_FS_SR_MAX FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x0)
+#define AIROHA_USB_PHY_USB20_FS_SR_NORMAL FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x2)
+#define AIROHA_USB_PHY_USB20_FS_SR_SMALLER FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x4)
+#define AIROHA_USB_PHY_USB20_FS_SR_MIN FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_FS_SR, 0x6)
+#define AIROHA_USB_PHY_USBPHYACR5 0x314
+#define AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN BIT(15)
+#define AIROHA_USB_PHY_USB20_HSTX_SRCTRL GENMASK(14, 12)
+#define AIROHA_USB_PHY_USBPHYACR6 0x318
+#define AIROHA_USB_PHY_USB20_BC11_SW_EN BIT(23)
+#define AIROHA_USB_PHY_USB20_DISCTH GENMASK(7, 4)
+#define AIROHA_USB_PHY_USB20_DISCTH_400 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x0)
+#define AIROHA_USB_PHY_USB20_DISCTH_420 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x1)
+#define AIROHA_USB_PHY_USB20_DISCTH_440 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x2)
+#define AIROHA_USB_PHY_USB20_DISCTH_460 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x3)
+#define AIROHA_USB_PHY_USB20_DISCTH_480 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x4)
+#define AIROHA_USB_PHY_USB20_DISCTH_500 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x5)
+#define AIROHA_USB_PHY_USB20_DISCTH_520 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x6)
+#define AIROHA_USB_PHY_USB20_DISCTH_540 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x7)
+#define AIROHA_USB_PHY_USB20_DISCTH_560 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x8)
+#define AIROHA_USB_PHY_USB20_DISCTH_580 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0x9)
+#define AIROHA_USB_PHY_USB20_DISCTH_600 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xa)
+#define AIROHA_USB_PHY_USB20_DISCTH_620 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xb)
+#define AIROHA_USB_PHY_USB20_DISCTH_640 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xc)
+#define AIROHA_USB_PHY_USB20_DISCTH_660 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xd)
+#define AIROHA_USB_PHY_USB20_DISCTH_680 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xe)
+#define AIROHA_USB_PHY_USB20_DISCTH_700 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_DISCTH, 0xf)
+#define AIROHA_USB_PHY_USB20_SQTH GENMASK(3, 0)
+#define AIROHA_USB_PHY_USB20_SQTH_85 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x0)
+#define AIROHA_USB_PHY_USB20_SQTH_90 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x1)
+#define AIROHA_USB_PHY_USB20_SQTH_95 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x2)
+#define AIROHA_USB_PHY_USB20_SQTH_100 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x3)
+#define AIROHA_USB_PHY_USB20_SQTH_105 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x4)
+#define AIROHA_USB_PHY_USB20_SQTH_110 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x5)
+#define AIROHA_USB_PHY_USB20_SQTH_115 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x6)
+#define AIROHA_USB_PHY_USB20_SQTH_120 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x7)
+#define AIROHA_USB_PHY_USB20_SQTH_125 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x8)
+#define AIROHA_USB_PHY_USB20_SQTH_130 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0x9)
+#define AIROHA_USB_PHY_USB20_SQTH_135 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xa)
+#define AIROHA_USB_PHY_USB20_SQTH_140 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xb)
+#define AIROHA_USB_PHY_USB20_SQTH_145 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xc)
+#define AIROHA_USB_PHY_USB20_SQTH_150 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xd)
+#define AIROHA_USB_PHY_USB20_SQTH_155 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xe)
+#define AIROHA_USB_PHY_USB20_SQTH_160 FIELD_PREP_CONST(AIROHA_USB_PHY_USB20_SQTH, 0xf)
+
+#define AIROHA_USB_PHY_U2PHYDTM1 0x36c
+#define AIROHA_USB_PHY_FORCE_IDDIG BIT(9)
+#define AIROHA_USB_PHY_IDDIG BIT(1)
+
+#define AIROHA_USB_PHY_GPIO_CTLD 0x80c
+#define AIROHA_USB_PHY_C60802_GPIO_CTLD GENMASK(31, 0)
+#define AIROHA_USB_PHY_SSUSB_IP_SW_RST BIT(31)
+#define AIROHA_USB_PHY_MCU_BUS_CK_GATE_EN BIT(30)
+#define AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST BIT(29)
+#define AIROHA_USB_PHY_SSUSB_SW_RST BIT(28)
+
+#define AIROHA_USB_PHY_U3_PHYA_REG0 0xb00
+#define AIROHA_USB_PHY_SSUSB_BG_DIV GENMASK(29, 28)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_2 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x0)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_4 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x1)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_8 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x2)
+#define AIROHA_USB_PHY_SSUSB_BG_DIV_16 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_BG_DIV, 0x3)
+#define AIROHA_USB_PHY_U3_PHYA_REG1 0xb04
+#define AIROHA_USB_PHY_SSUSB_XTAL_TOP_RESERVE GENMASK(25, 10)
+#define AIROHA_USB_PHY_U3_PHYA_REG6 0xb18
+#define AIROHA_USB_PHY_SSUSB_CDR_RESERVE GENMASK(31, 24)
+#define AIROHA_USB_PHY_U3_PHYA_REG8 0xb20
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY GENMASK(7, 6)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_32 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x0)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_64 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x1)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_128 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x2)
+#define AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_216 FIELD_PREP_CONST(AIROHA_USB_PHY_SSUSB_CDR_RST_DLY, 0x3)
+
+#define AIROHA_USB_PHY_U3_PHYA_DA_REG19 0xc38
+#define AIROHA_USB_PHY_SSUSB_PLL_SSC_DELTA1_U3 GENMASK(15, 0)
+
+#define AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT 1024
+#define AIROHA_USB_PHY_REF_CK 20
+#define AIROHA_USB_PHY_U2_SR_COEF 28
+#define AIROHA_USB_PHY_U2_SR_COEF_DIVISOR 1000
+
+#define AIROHA_USB_PHY_DEFAULT_SR_CALIBRATION 0x5
+#define AIROHA_USB_PHY_FREQDET_SLEEP 1000 /* 1ms */
+#define AIROHA_USB_PHY_FREQDET_TIMEOUT (AIROHA_USB_PHY_FREQDET_SLEEP * 10)
+
+struct an7581_usb_phy_instance {
+ struct phy *phy;
+ u32 type;
+};
+
+enum an7581_usb_phy_instance_type {
+ AIROHA_PHY_USB2,
+ AIROHA_PHY_USB3,
+
+ AIROHA_PHY_USB_MAX,
+};
+
+struct an7581_usb_phy_priv {
+ struct device *dev;
+ struct regmap *regmap;
+
+ unsigned int monclk_sel;
+
+ struct phy *serdes_phy;
+ struct an7581_usb_phy_instance *phys[AIROHA_PHY_USB_MAX];
+};
+
+static void an7581_usb_phy_u2_slew_rate_calibration(struct an7581_usb_phy_priv *priv)
+{
+ u32 fm_out = 0;
+ u32 srctrl;
+
+ /* Enable HS TX SR calibration */
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR5,
+ AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ /* Enable Free run clock */
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_FMMONR1,
+ AIROHA_USB_PHY_FRCK_EN);
+
+ /* Select Monitor Clock */
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_FMCR0,
+ AIROHA_USB_PHY_MONCLK_SEL,
+ FIELD_PREP(AIROHA_USB_PHY_MONCLK_SEL,
+ priv->monclk_sel));
+
+ /* Set cyclecnt */
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_FMCR0,
+ AIROHA_USB_PHY_CYCLECNT,
+ FIELD_PREP(AIROHA_USB_PHY_CYCLECNT,
+ AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT));
+
+ /* Enable Frequency meter */
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_FMCR0,
+ AIROHA_USB_PHY_FREQDET_EN);
+
+ /* Timeout can happen and we will apply workaround at the end */
+ regmap_read_poll_timeout(priv->regmap, AIROHA_USB_PHY_FMMONR0, fm_out,
+ fm_out, AIROHA_USB_PHY_FREQDET_SLEEP,
+ AIROHA_USB_PHY_FREQDET_TIMEOUT);
+
+ /* Disable Frequency meter */
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_FMCR0,
+ AIROHA_USB_PHY_FREQDET_EN);
+
+ /* Disable Free run clock */
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_FMMONR1,
+ AIROHA_USB_PHY_FRCK_EN);
+
+ /* Disable HS TX SR calibration */
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR5,
+ AIROHA_USB_PHY_USB20_HSTX_SRCAL_EN);
+
+ usleep_range(1000, 1500);
+
+ /* Frequency was not detected, use default SR calibration value */
+ if (!fm_out) {
+ srctrl = AIROHA_USB_PHY_DEFAULT_SR_CALIBRATION;
+ dev_err(priv->dev, "Frequency not detected, using default SR calibration.\n");
+ } else {
+ /* (1024 / FM_OUT) * REF_CK * U2_SR_COEF (round to the nearest digits) */
+ srctrl = AIROHA_USB_PHY_REF_CK * AIROHA_USB_PHY_U2_SR_COEF;
+ srctrl = (srctrl * AIROHA_USB_PHY_U2_FM_DET_CYCLE_CNT) / fm_out;
+ srctrl = DIV_ROUND_CLOSEST(srctrl, AIROHA_USB_PHY_U2_SR_COEF_DIVISOR);
+ dev_dbg(priv->dev, "SR calibration applied: %x\n", srctrl);
+ }
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR5,
+ AIROHA_USB_PHY_USB20_HSTX_SRCTRL,
+ FIELD_PREP(AIROHA_USB_PHY_USB20_HSTX_SRCTRL, srctrl));
+}
+
+static void an7581_usb_phy_u2_init(struct an7581_usb_phy_priv *priv)
+{
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR4,
+ AIROHA_USB_PHY_USB20_FS_CR,
+ AIROHA_USB_PHY_USB20_FS_CR_MIN);
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR4,
+ AIROHA_USB_PHY_USB20_FS_SR,
+ AIROHA_USB_PHY_USB20_FS_SR_NORMAL);
+
+ /* FIXME: evaluate if needed */
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_SQTH,
+ AIROHA_USB_PHY_USB20_SQTH_130);
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_DISCTH,
+ AIROHA_USB_PHY_USB20_DISCTH_600);
+
+ /* Enable the USB port and then disable after calibration */
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ an7581_usb_phy_u2_slew_rate_calibration(priv);
+
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ usleep_range(1000, 1500);
+}
+
+/*
+ * USB 3.0 mode can only work if USB serdes is correctly set.
+ * This is validated in xLate function.
+ */
+static void an7581_usb_phy_u3_init(struct an7581_usb_phy_priv *priv)
+{
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_U3_PHYA_REG8,
+ AIROHA_USB_PHY_SSUSB_CDR_RST_DLY,
+ AIROHA_USB_PHY_SSUSB_CDR_RST_DLY_32);
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_U3_PHYA_REG6,
+ AIROHA_USB_PHY_SSUSB_CDR_RESERVE,
+ FIELD_PREP(AIROHA_USB_PHY_SSUSB_CDR_RESERVE, 0xe));
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_U3_PHYA_REG0,
+ AIROHA_USB_PHY_SSUSB_BG_DIV,
+ AIROHA_USB_PHY_SSUSB_BG_DIV_4);
+
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_U3_PHYA_REG1,
+ FIELD_PREP(AIROHA_USB_PHY_SSUSB_XTAL_TOP_RESERVE, 0x600));
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_U3_PHYA_DA_REG19,
+ AIROHA_USB_PHY_SSUSB_PLL_SSC_DELTA1_U3,
+ FIELD_PREP(AIROHA_USB_PHY_SSUSB_PLL_SSC_DELTA1_U3, 0x43));
+}
+
+static int an7581_usb_phy_init(struct phy *phy)
+{
+ struct an7581_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7581_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+ int ret;
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ an7581_usb_phy_u2_init(priv);
+ break;
+ case PHY_TYPE_USB3:
+ ret = phy_set_mode(priv->serdes_phy, PHY_MODE_USB_DEVICE_SS);
+ if (ret)
+ return ret;
+
+ an7581_usb_phy_u3_init(priv);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int an7581_usb_phy_u2_power_on(struct an7581_usb_phy_priv *priv)
+{
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int an7581_usb_phy_u3_power_on(struct an7581_usb_phy_priv *priv)
+{
+ regmap_clear_bits(priv->regmap, AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_SSUSB_IP_SW_RST |
+ AIROHA_USB_PHY_MCU_BUS_CK_GATE_EN |
+ AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST |
+ AIROHA_USB_PHY_SSUSB_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int an7581_usb_phy_power_on(struct phy *phy)
+{
+ struct an7581_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7581_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ an7581_usb_phy_u2_power_on(priv);
+ break;
+ case PHY_TYPE_USB3:
+ an7581_usb_phy_u3_power_on(priv);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int an7581_usb_phy_u2_power_off(struct an7581_usb_phy_priv *priv)
+{
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_USBPHYACR6,
+ AIROHA_USB_PHY_USB20_BC11_SW_EN);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int an7581_usb_phy_u3_power_off(struct an7581_usb_phy_priv *priv)
+{
+ regmap_set_bits(priv->regmap, AIROHA_USB_PHY_GPIO_CTLD,
+ AIROHA_USB_PHY_SSUSB_IP_SW_RST |
+ AIROHA_USB_PHY_FORCE_SSUSB_IP_SW_RST);
+
+ usleep_range(1000, 1500);
+
+ return 0;
+}
+
+static int an7581_usb_phy_power_off(struct phy *phy)
+{
+ struct an7581_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7581_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ an7581_usb_phy_u2_power_off(priv);
+ break;
+ case PHY_TYPE_USB3:
+ an7581_usb_phy_u3_power_off(priv);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int an7581_usb_phy_u2_set_mode(struct an7581_usb_phy_priv *priv,
+ enum phy_mode mode)
+{
+ u32 val;
+
+ /*
+ * For Device and Host mode, enable force IDDIG.
+ * For Device set IDDIG, for Host clear IDDIG.
+ * For OTG disable force and clear IDDIG bit while at it.
+ */
+ switch (mode) {
+ case PHY_MODE_USB_DEVICE:
+ val = AIROHA_USB_PHY_FORCE_IDDIG |
+ AIROHA_USB_PHY_IDDIG;
+ break;
+ case PHY_MODE_USB_HOST:
+ val = AIROHA_USB_PHY_FORCE_IDDIG;
+ break;
+ case PHY_MODE_USB_OTG:
+ val = 0;
+ break;
+ default:
+ return 0;
+ }
+
+ regmap_update_bits(priv->regmap, AIROHA_USB_PHY_U2PHYDTM1,
+ AIROHA_USB_PHY_FORCE_IDDIG |
+ AIROHA_USB_PHY_IDDIG, val);
+
+ return 0;
+}
+
+static int an7581_usb_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode)
+{
+ struct an7581_usb_phy_instance *instance = phy_get_drvdata(phy);
+ struct an7581_usb_phy_priv *priv = dev_get_drvdata(phy->dev.parent);
+
+ switch (instance->type) {
+ case PHY_TYPE_USB2:
+ return an7581_usb_phy_u2_set_mode(priv, mode);
+ default:
+ return 0;
+ }
+}
+
+static struct phy *an7581_usb_phy_xlate(struct device *dev,
+ const struct of_phandle_args *args)
+{
+ struct an7581_usb_phy_priv *priv = dev_get_drvdata(dev);
+ struct an7581_usb_phy_instance *instance = NULL;
+ unsigned int index, phy_type;
+
+ if (args->args_count != 1) {
+ dev_err(dev, "invalid number of cells in 'phy' property\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ phy_type = args->args[0];
+ if (!(phy_type == PHY_TYPE_USB2 || phy_type == PHY_TYPE_USB3)) {
+ dev_err(dev, "unsupported device type: %d\n", phy_type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (index = 0; index < AIROHA_PHY_USB_MAX; index++)
+ if (priv->phys[index] &&
+ phy_type == priv->phys[index]->type) {
+ instance = priv->phys[index];
+ break;
+ }
+
+ if (!instance) {
+ dev_err(dev, "failed to find appropriate phy\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return instance->phy;
+}
+
+static const struct phy_ops airoha_phy = {
+ .init = an7581_usb_phy_init,
+ .power_on = an7581_usb_phy_power_on,
+ .power_off = an7581_usb_phy_power_off,
+ .set_mode = an7581_usb_phy_set_mode,
+ .owner = THIS_MODULE,
+};
+
+static const struct regmap_config an7581_usb_phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int an7581_usb_phy_probe(struct platform_device *pdev)
+{
+ struct phy_provider *phy_provider;
+ struct an7581_usb_phy_priv *priv;
+ struct device *dev = &pdev->dev;
+ unsigned int index;
+ void __iomem *base;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+
+ ret = of_property_read_u32(dev->of_node, "airoha,usb2-monitor-clk-sel",
+ &priv->monclk_sel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Monitor clock selection is mandatory for USB PHY calibration\n");
+
+ if (priv->monclk_sel > 3)
+ return dev_err_probe(dev, -EINVAL, "only 4 Monitor clock are selectable on the SoC\n");
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ priv->regmap = devm_regmap_init_mmio(dev, base, &an7581_usb_phy_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ platform_set_drvdata(pdev, priv);
+
+ for (index = 0; index < AIROHA_PHY_USB_MAX; index++) {
+ struct an7581_usb_phy_instance *instance;
+ u32 phy_type;
+
+ switch (index) {
+ case AIROHA_PHY_USB2:
+ phy_type = PHY_TYPE_USB2;
+ break;
+ case AIROHA_PHY_USB3:
+ phy_type = PHY_TYPE_USB3;
+ break;
+ }
+
+ if (phy_type == PHY_TYPE_USB3) {
+ priv->serdes_phy = devm_phy_get(dev, NULL);
+ if (IS_ERR(priv->serdes_phy))
+ return dev_err_probe(dev, PTR_ERR(priv->serdes_phy), "missing serdes phy for USB 3.0\n");
+ }
+
+ instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
+ if (!instance)
+ return -ENOMEM;
+
+ instance->type = phy_type;
+ priv->phys[index] = instance;
+
+ instance->phy = devm_phy_create(dev, NULL, &airoha_phy);
+ if (IS_ERR(instance->phy))
+ return dev_err_probe(dev, PTR_ERR(instance->phy), "failed to create phy\n");
+
+ phy_set_drvdata(instance->phy, instance);
+ }
+
+ phy_provider = devm_of_phy_provider_register(&pdev->dev, an7581_usb_phy_xlate);
+
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id airoha_phy_id_table[] = {
+ { .compatible = "airoha,an7581-usb-phy" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, airoha_phy_id_table);
+
+static struct platform_driver an7581_usb_driver = {
+ .probe = an7581_usb_phy_probe,
+ .driver = {
+ .name = "airoha-an7581-usb-phy",
+ .of_match_table = airoha_phy_id_table,
+ },
+};
+
+module_platform_driver(an7581_usb_driver);
+
+MODULE_DESCRIPTION("Airoha AN7581 USB PHY driver");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* [PATCH v2 0/1] add USB PHY node and USB OTG pinctrl support to S32G2/S32G3 SoCs
From: Khristine Andreea Barbulescu @ 2026-05-20 15:10 UTC (permalink / raw)
To: Chester Lin, Matthias Brugger, Ghennadi Procopciuc, Frank Li,
Sascha Hauer, Fabio Estevam, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Pengutronix Kernel Team, linux-arm-kernel, imx, devicetree,
linux-kernel, NXP S32 Linux, Christophe Lizzi, Alberto Ruiz,
Enric Balletbo
This patchset aims to add two changes to the S32G2/S32G3 dtsi support:
- Add the usbphynop node for S32G SoC based boards
- Add the usbotg pinctrl support for S32G SoC based boards
v2 -> v1:
- use hyphenated naming for USB OTG pin groups
- replace deprecated 'fsl,usbphy' with 'phys'
- move 'usbphynop' node to the SoC-level dtsi
Khristine Andreea Barbulescu (1):
arm64: dts: Add usbphynop and usbotg pinctrl for S32G platforms
arch/arm64/boot/dts/freescale/s32g2.dtsi | 7 ++-
arch/arm64/boot/dts/freescale/s32g3.dtsi | 7 ++-
.../boot/dts/freescale/s32gxxxa-evb.dtsi | 46 ++++++++++++++++++-
.../boot/dts/freescale/s32gxxxa-rdb.dtsi | 46 ++++++++++++++++++-
4 files changed, 102 insertions(+), 4 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v2 1/1] arm64: dts: Add usbphynop and usbotg pinctrl for S32G platforms
From: Khristine Andreea Barbulescu @ 2026-05-20 15:10 UTC (permalink / raw)
To: Chester Lin, Matthias Brugger, Ghennadi Procopciuc, Frank Li,
Sascha Hauer, Fabio Estevam, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: Pengutronix Kernel Team, linux-arm-kernel, imx, devicetree,
linux-kernel, NXP S32 Linux, Christophe Lizzi, Alberto Ruiz,
Enric Balletbo
In-Reply-To: <20260520151007.4193688-1-khristineandreea.barbulescu@oss.nxp.com>
Add the usbphynop node and the usbotg pinctrl
support for the S32G2 and S32G3 SoCs.
This enables the USB controller to reference the
generic PHY and use the required pinmux for USB OTG ops.
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32g2.dtsi | 7 ++-
arch/arm64/boot/dts/freescale/s32g3.dtsi | 7 ++-
.../boot/dts/freescale/s32gxxxa-evb.dtsi | 46 ++++++++++++++++++-
.../boot/dts/freescale/s32gxxxa-rdb.dtsi | 46 ++++++++++++++++++-
4 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 51d00dac12de..a35bb284270e 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -3,7 +3,7 @@
* NXP S32G2 SoC family
*
* Copyright (c) 2021 SUSE LLC
- * Copyright 2017-2021, 2024-2025 NXP
+ * Copyright 2017-2021, 2024-2026 NXP
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -108,6 +108,11 @@ psci {
};
};
+ usbphynop: usbphynop {
+ compatible = "usb-nop-xceiv";
+ #phy-cells = <0>;
+ };
+
soc@0 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index e314f3c7d61d..b980e5f2b059 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright 2021-2025 NXP
+ * Copyright 2021-2026 NXP
*
* Authors: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
* Ciprian Costea <ciprianmarian.costea@nxp.com>
@@ -165,6 +165,11 @@ scmi_shmem: shm@d0000000 {
};
};
+ usbphynop: usbphynop {
+ compatible = "usb-nop-xceiv";
+ #phy-cells = <0>;
+ };
+
soc@0 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi b/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
index 803ff4531077..26009c1e90dc 100644
--- a/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32gxxxa-evb.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright 2024 NXP
+ * Copyright 2024, 2026 NXP
*
* Authors: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
* Ghennadi Procopciuc <ghennadi.procopciuc@oss.nxp.com>
@@ -245,6 +245,39 @@ dspi5-grp4 {
bias-pull-up;
};
};
+
+ usbotg_pins: usbotg-pins {
+ usbotg-grp0 {
+ pinmux = <0x3802>, <0x3812>,
+ <0x3822>, <0x3832>,
+ <0x3842>, <0x3852>,
+ <0x3862>, <0x3872>,
+ <0x37f2>, <0x3882>,
+ <0x3892>;
+ };
+
+ usbotg-grp1 {
+ pinmux = <0x3e1>, <0x3f1>,
+ <0x401>, <0x411>,
+ <0xbc1>, <0xbd1>,
+ <0xbe1>, <0x701>;
+ output-enable;
+ input-enable;
+ slew-rate = <208>;
+ };
+
+ usbotg-grp2 {
+ pinmux = <0xb80>, <0xb90>, <0xbb0>;
+ input-enable;
+ slew-rate = <208>;
+ };
+
+ usbotg-grp3 {
+ pinmux = <0xba1>;
+ output-enable;
+ slew-rate = <208>;
+ };
+ };
};
&can0 {
@@ -304,3 +337,14 @@ &spi5 {
pinctrl-names = "default";
status = "okay";
};
+
+&usbmisc {
+ status = "okay";
+};
+
+&usbotg {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usbotg_pins>;
+ phys = <&usbphynop>;
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi b/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
index 979868f6d2c5..a8abb10b0e7a 100644
--- a/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32gxxxa-rdb.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright 2024 NXP
+ * Copyright 2024, 2026 NXP
*
* Authors: Ciprian Marian Costea <ciprianmarian.costea@oss.nxp.com>
* Ghennadi Procopciuc <ghennadi.procopciuc@oss.nxp.com>
@@ -199,6 +199,39 @@ dspi5-grp4 {
bias-pull-up;
};
};
+
+ usbotg_pins: usbotg-pins {
+ usbotg-grp0 {
+ pinmux = <0x3802>, <0x3812>,
+ <0x3822>, <0x3832>,
+ <0x3842>, <0x3852>,
+ <0x3862>, <0x3872>,
+ <0x37f2>, <0x3882>,
+ <0x3892>;
+ };
+
+ usbotg-grp1 {
+ pinmux = <0x3e1>, <0x3f1>,
+ <0x401>, <0x411>,
+ <0xbc1>, <0xbd1>,
+ <0xbe1>, <0x701>;
+ output-enable;
+ input-enable;
+ slew-rate = <208>;
+ };
+
+ usbotg-grp2 {
+ pinmux = <0xb80>, <0xb90>, <0xbb0>;
+ input-enable;
+ slew-rate = <208>;
+ };
+
+ usbotg-grp3 {
+ pinmux = <0xba1>;
+ output-enable;
+ slew-rate = <208>;
+ };
+ };
};
&can0 {
@@ -257,3 +290,14 @@ &i2c4 {
pinctrl-1 = <&i2c4_gpio_pins>;
status = "okay";
};
+
+&usbmisc {
+ status = "okay";
+};
+
+&usbotg {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usbotg_pins>;
+ phys = <&usbphynop>;
+ status = "okay";
+};
--
2.34.1
^ permalink raw reply related
* Re: [PATCH v8 0/5] airoha: an7581: USB support
From: Christian Marangi @ 2026-05-20 15:14 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Brian Masney, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Vinod Koul, Neil Armstrong,
Lorenzo Bianconi, Felix Fietkau, linux-clk, devicetree,
linux-kernel, linux-arm-kernel, linux-phy
In-Reply-To: <20260520150912.11614-1-ansuelsmth@gmail.com>
On Wed, May 20, 2026 at 05:09:05PM +0200, Christian Marangi wrote:
> This is a major rework of the old v2 series.
>
> The SoC always support USB 2.0 but for USB 3.0 it needs additional
> configuration for the Serdes port. Such port can be either configured
> for USB usage or for PCIe lines or HSGMII and these are configured
> in the SCU space.
>
> The previous implementation of a dedicated SSR driver was too
> complex and fragile for the simple task of configuring a register
> hence it was dropped and the handling is entirely in the PHY driver.
>
> Everything was reducted to the dt-bindings to describe the Serdes line.
>
> Also the property for the PHY are renamed to a more suitable name and
> everything is now mandatory to simplify the implementation.
> (the PHY are always present and active on the SoC)
>
> Also other unrelated patch are dropped from this series.
>
> Changes v8:
> - Squash header to clk Documentation patch
> - Address comments from AI Bot
>
> Changes v7:
> - Rework to double PHY implementation
> (suggested by Rob)
> Now the clk driver expose a PHY for Serdes port
> USB PHY driver selects it
> - Rebase on top of linux-next
> Link: https://lore.kernel.org/all/20260306190156.22297-1-ansuelsmth@gmail.com/
Typo for the link. It's:
Link: https://lore.kernel.org/all/20260519220813.28468-1-ansuelsmth@gmail.com/
>
> Changes v6:
> - Fix kernel test robot (sparse warning)
> Link: https://lore.kernel.org/all/20260306190156.22297-1-ansuelsmth@gmail.com/
>
> Changes v5:
> - Add Ack and Review tag from Connor
> - Implement Ethernet support in the USB driver
> (testing support for this Serdes on a special reference board)
> - Use an7581 prefix for USB PHY driver
> Link: https://lore.kernel.org/all/20251107160251.2307088-1-ansuelsmth@gmail.com/
>
> Changes v4:
> - Rename PCIe and USB PHY to AN7581
> - Drop airoha,scu (handled directly in driver)
> - Drop dt-bindings for monitor clock in favor of raw values
> - Better describe the usage of airoha,usb3-serdes
> - Simplify values of dt-bindings SSR SERDES
> Link: https://lore.kernel.org/all/20251107160251.2307088-1-ansuelsmth@gmail.com/
>
> Changes v3:
> - Drop clk changes
> - Drop SSR driver
> - Rename property in Documentation
> - Simplify PHY handling
> - Move SSR handling inside the PHY driver
> Link: https://lore.kernel.org/all/20251029173713.7670-1-ansuelsmth@gmail.com/
>
> Changes v2:
> - Drop changes for simple-mfd
> - Rework PHY node structure to single node
> - Drop port-id property in favor of serdes-port and
> usb2-monitor-clock-sel
> - Make the SSR driver probe from the clock driver
>
> Christian Marangi (5):
> dt-bindings: clock: airoha: Add PHY binding for Serdes port
> dt-bindings: phy: Add documentation for Airoha AN7581 USB PHY
> clk: en7523: Add support for selecting the Serdes port in SCU
> phy: move and rename Airoha PCIe PHY driver to dedicated directory
> phy: airoha: Add support for Airoha AN7581 USB PHY
>
> .../bindings/clock/airoha,en7523-scu.yaml | 9 +
> .../bindings/phy/airoha,an7581-usb-phy.yaml | 62 ++
> MAINTAINERS | 11 +-
> drivers/clk/Kconfig | 1 +
> drivers/clk/clk-en7523.c | 216 ++++++-
> drivers/phy/Kconfig | 11 +-
> drivers/phy/Makefile | 4 +-
> drivers/phy/airoha/Kconfig | 24 +
> drivers/phy/airoha/Makefile | 4 +
> .../phy-an7581-pcie-regs.h} | 2 +-
> .../phy-an7581-pcie.c} | 6 +-
> drivers/phy/airoha/phy-an7581-usb.c | 554 ++++++++++++++++++
> include/dt-bindings/soc/airoha,scu-ssr.h | 11 +
> 13 files changed, 894 insertions(+), 21 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/phy/airoha,an7581-usb-phy.yaml
> create mode 100644 drivers/phy/airoha/Kconfig
> create mode 100644 drivers/phy/airoha/Makefile
> rename drivers/phy/{phy-airoha-pcie-regs.h => airoha/phy-an7581-pcie-regs.h} (99%)
> rename drivers/phy/{phy-airoha-pcie.c => airoha/phy-an7581-pcie.c} (99%)
> create mode 100644 drivers/phy/airoha/phy-an7581-usb.c
> create mode 100644 include/dt-bindings/soc/airoha,scu-ssr.h
>
> --
> 2.53.0
>
--
Ansuel
^ permalink raw reply
* Re: [PATCH v8 phy-next 15/31] drm/rockchip: dw_hdmi: avoid direct dereference of phy->dev.of_node
From: Vladimir Oltean @ 2026-05-20 15:20 UTC (permalink / raw)
To: Heiko Stuebner
Cc: linux-phy, Vinod Koul, Neil Armstrong, dri-devel, freedreno,
linux-arm-kernel, linux-arm-msm, linux-can, linux-gpio, linux-ide,
linux-kernel, linux-media, linux-pci, linux-renesas-soc,
linux-riscv, linux-rockchip, linux-samsung-soc, linux-scsi,
linux-sunxi, linux-tegra, linux-usb, netdev, spacemit,
UNGLinuxDriver, Sandy Huang, Andy Yan, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter
In-Reply-To: <3758596.1xdlsreqCQ@phil>
Hi Heiko,
On Wed, May 20, 2026 at 04:21:24PM +0200, Heiko Stuebner wrote:
> Hi Vladimir,
>
> Am Dienstag, 5. Mai 2026, 12:05:07 Mitteleuropäische Sommerzeit schrieb Vladimir Oltean:
> > The dw_hdmi-rockchip driver validates pixel clock rates against the
> > HDMI PHY's internal clock provider on certain SoCs like RK3328.
> > This is currently achieved by dereferencing hdmi->phy->dev.of_node
> > to obtain the provider node, which violates the Generic PHY API's
> > encapsulation (the goal is for struct phy to be an opaque pointer
> > with a hidden definition, to be interacted with only using API
> > functions or NULL pointer checks, for the case where optional variants
> > of phy_get() did not find a PHY).
> >
> > Refactor dw_hdmi_rockchip_bind() to perform a manual phandle lookup
> > on the "hdmi" PHY index within the controller's DT node. This provides
> > a parallel path to the clock provider's OF node without relying on the
> > internal structure of the struct phy handle.
> >
> > Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
> > Reviewed-by: Heiko Stueber <heiko@sntech.de>
>
> there is now already more stuff depending on this change [0], and
> the change itself also is sort of independent of the whole
> phy-series. And somehow this series itself sadly hasn't gotten
> much review yet.
>
> So would you be ok with me just picking this one patch for the
> drm-misc-tree?
>
>
> Thanks
> Heiko
>
> [0] https://lore.kernel.org/dri-devel/20260518193748.2482823-1-jonas@kwiboo.se/
I am currently out of office, so I can't look very closely, but yes,
I did agree with Vinod to try to reduce the size of this series by
submitting some of the changes this cycle to individual subsystems, and
the cross-tree remainder the following cycle. So yes, feel free to pick
from this series and I'll submit to dri-devel whatever remains when I
return to this activity.
^ permalink raw reply
* Re: [PATCH] net: stmmac: mmc: Remove duplicate mmc_rx crc
From: Andrew Lunn @ 2026-05-20 15:23 UTC (permalink / raw)
To: dev.taqnialabs
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Maxime Coquelin, Alexandre Torgue, netdev,
linux-stm32, linux-arm-kernel, linux-kernel
In-Reply-To: <20260520-xgmac-mmc_rx_crc-cleanup-v1-1-7133f529859f@gmail.com>
On Wed, May 20, 2026 at 02:25:12PM +0000, Abid Ali via B4 Relay wrote:
> From: Abid Ali <dev.taqnialabs@gmail.com>
>
> Double read of mmc_rx_crc_error in XGMAC is removed.
The commit message should explain "Why?". I can read the code add see
what the patch does.
Why remove the double read? Why is this safe to do? This is hardware,
maybe it has latches values? Or clear on read? Maybe two reads are
required? So the Why? Is very important, more important than the code
change itself.
Andrew
---
pw-bot: cr
^ permalink raw reply
* Re: [PATCH v2 1/3] crypto: atmel-sha204a - Drop of_device_id data
From: Uwe Kleine-König (The Capable Hub) @ 2026-05-20 15:25 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: Thorsten Blum, Herbert Xu, David S. Miller, Nicolas Ferre,
Alexandre Belloni, Claudiu Beznea, linux-crypto, linux-arm-kernel,
linux-kernel
In-Reply-To: <46130020-eaa5-44ad-9c6d-62ccb30c19d9@app.fastmail.com>
[-- Attachment #1: Type: text/plain, Size: 2397 bytes --]
Hello Ard,
On Wed, May 20, 2026 at 09:49:49AM +0200, Ard Biesheuvel wrote:
> On Wed, 20 May 2026, at 09:01, Uwe Kleine-König (The Capable Hub) wrote:
> > The driver binds to i2c devices only and thus in the absence of an
> > assignment for .data in the of_device_id array i2c_get_match_data()
> > falls back to .driver_data from the i2c_device_id array. So only provide
> > &atsha204_quality once to reduce duplication.
> >
> > Signed-off-by: Uwe Kleine-König (The Capable Hub) <u.kleine-koenig@baylibre.com>
> > ---
> > drivers/crypto/atmel-sha204a.c | 4 ++--
> > 1 file changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
> > index 6e6ac4770416..f17e1f6af1a3 100644
> > --- a/drivers/crypto/atmel-sha204a.c
> > +++ b/drivers/crypto/atmel-sha204a.c
> > @@ -208,8 +208,8 @@ static void atmel_sha204a_remove(struct i2c_client *client)
> > }
> >
> > static const struct of_device_id atmel_sha204a_dt_ids[] = {
> > - { .compatible = "atmel,atsha204", .data = &atsha204_quality },
> > - { .compatible = "atmel,atsha204a", },
> > + { .compatible = "atmel,atsha204" },
> > + { .compatible = "atmel,atsha204a" },
> > { }
> > };
> > MODULE_DEVICE_TABLE(of, atmel_sha204a_dt_ids);
>
> Just trying to figure out how this is supposed to work:
>
> i2c_get_match_data()
> data = device_get_match_data(&client->dev);
> ... returns NULL ...
> if (!data) {
> match = i2c_match_id(driver->id_table, client);
> ... compares client->name with { "atsha204", "atsha204a" }
>
> So we will be relying on client->name having been set to either
> "atsha204" or "atsha204a" on the DT probe path before
> i2c_match_data() is called, but I am struggling to see where
> that might happen.
That happens when the client is created. Relevant are:
int of_i2c_get_board_info(struct device *dev, struct device_node *node,
...
{
...
if (of_alias_from_compatible(node, info->type, sizeof(info->type)) < 0) {
...
}
which sets info->type from .compatible with the vendor part skipped.
Then
static struct i2c_client *of_i2c_register_device(...)
{
...
ret = of_i2c_get_board_info(&adap->dev, node, &info);
...
client = i2c_new_client_device(adap, &info);
...
}
where i2c_new_client_device() uses info->type to populate client->name.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* [PATCH 00/17] KVM: arm64: Introduce pKVM hypervisor heap allocator
From: Vincent Donnefort @ 2026-05-20 15:26 UTC (permalink / raw)
To: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will
Cc: linux-arm-kernel, kvmarm, kernel-team, qperret, tabba,
Vincent Donnefort
pKVM historically lacked a dynamic memory allocator: all hypervisor-side
VM and VCPU structures had to be sized on the host, allocated as
contiguous pages and donated to the hypervisor.
This design tightly coupled the hypervisor's memory footprint to
host-side constraints, complicated memory reclaim, and severely
restricted VM scalability.
This patch series introduces a dynamically-mapped custom heap allocator
(hyp_allocator) to the pKVM hypervisor. The initial users are the
pkvm_hyp_vm and pkvm_hyp_vcpu structs, and the hypervisor tracing
metadata.
In the near future, this heap allocator is expected to be leveraged to
support SVE in protected VMs and in the distant future, it will also
support dynamic device assignment.
By moving to a hypervisor-managed dynamic allocator, we also allow
deduplicating the donation/reclaim path of EL2-private structures.
The main building blocks for this series are:
1. pkvm_hyp_req:
----------------
When the hypervisor heap allocator goes out of memory (-ENOMEM), it
suspends the hypercall, embeds a PKVM_HYP_REQ_HYP_ALLOC top-up request
into the SMCCC HVC return registers, and exits back to the host.
This building block will also be useful for the future huge-mapping
support in protected guests, allowing EL2 to raise requests such as
block splitting back to the host.
2. hyp_allocator:
----------------
This heap allocator manages a reserved VA space range, dynamically
mapping and unmapping physical pages on-demand to minimise the pKVM
hypervisor footprint. As memory is reclaimed and relinquished to the
host, unmapped holes are introduced within the VA space. To prevent
orphan mapped regions, neighboring unused chunks cannot be merged if
they are separated by an unmapped region.
The allocator chunk metadata is stored directly into the VA space range.
To minimize metadata overhead, chunks only link to each other via a
relative 32-bit offset.
A simple hardening of the metadata is added via a simple 32-bit hash.
3. shrinker:
------------
As the heap allocator isn't reclaimed actively on VM or tracing
teardown, a shrinker is added to allow the host to reclaim unused memory
from the hypervisor when the host is under heavy memory pressure.
Vincent Donnefort (17):
KVM: arm64: Add __pkvm_private_range_pa
KVM: arm64: Add pkvm_remove_mappings
KVM: arm64: Add __hyp_allocator_map for the pKVM hyp
KVM: arm64: Add a heap allocator for the pKVM hyp
KVM: arm64: Allow kvm_hyp_memcache usage outside of stage-2
KVM: arm64: Add topup interface for the pKVM heap allocator
KVM: arm64: Add pkvm_hyp_req infrastructure
KVM: arm64: Handle PKVM_HYP_REQ_HYP_ALLOC request
KVM: arm64: Add reclaim interface for the pKVM heap alloc
KVM: arm64: Add selftests for the pKVM heap allocator
KVM: arm64: Add a shrinker for pKVM
KVM: arm64: Filter out non-kernel addresses in kern_hyp_va
KVM: arm64: Move hyp_vm refcount into the structure
KVM: arm64: Use noclear for PGD in __pkvm_init_vm error path
KVM: arm64: Alloc pkvm_hyp_vm using pKVM heap allocator
KVM: arm64: Alloc pkvm_hyp_vcpu using pKVM heap allocator
KVM: arm64: Alloc simple_buffer_page using pKVM hyp allocator
arch/arm64/include/asm/kvm_asm.h | 4 +
arch/arm64/include/asm/kvm_host.h | 14 +-
arch/arm64/include/asm/kvm_mmu.h | 3 +
arch/arm64/include/asm/kvm_pkvm.h | 104 ++
arch/arm64/kvm/arm.c | 24 +
arch/arm64/kvm/hyp/hyp-constants.c | 2 -
arch/arm64/kvm/hyp/include/nvhe/alloc.h | 24 +
arch/arm64/kvm/hyp/include/nvhe/mm.h | 3 +
arch/arm64/kvm/hyp/include/nvhe/pkvm.h | 19 +-
arch/arm64/kvm/hyp/nvhe/Makefile | 2 +-
arch/arm64/kvm/hyp/nvhe/alloc.c | 1233 +++++++++++++++++++++++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 123 ++-
arch/arm64/kvm/hyp/nvhe/mm.c | 33 +
arch/arm64/kvm/hyp/nvhe/pkvm.c | 111 +-
arch/arm64/kvm/hyp/nvhe/setup.c | 5 +
arch/arm64/kvm/hyp/nvhe/trace.c | 69 +-
arch/arm64/kvm/hyp_trace.c | 16 +-
arch/arm64/kvm/mmu.c | 4 +-
arch/arm64/kvm/pkvm.c | 130 ++-
arch/arm64/kvm/trace_pkvm.h | 37 +
20 files changed, 1808 insertions(+), 152 deletions(-)
create mode 100644 arch/arm64/kvm/hyp/include/nvhe/alloc.h
create mode 100644 arch/arm64/kvm/hyp/nvhe/alloc.c
create mode 100644 arch/arm64/kvm/trace_pkvm.h
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
2.54.0.631.ge1b05301d1-goog
^ permalink raw reply
* [PATCH 02/17] KVM: arm64: Add pkvm_remove_mappings
From: Vincent Donnefort @ 2026-05-20 15:26 UTC (permalink / raw)
To: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will
Cc: linux-arm-kernel, kvmarm, kernel-team, qperret, tabba,
Vincent Donnefort
In-Reply-To: <20260520152650.4107895-1-vdonnefort@google.com>
Add the counterpart to pkvm_create_mappings(), allowing previously
mapped ranges to be removed. This will be useful for the upcoming pKVM
heap allocator to manage its private mappings.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/kvm/hyp/include/nvhe/mm.h b/arch/arm64/kvm/hyp/include/nvhe/mm.h
index d3137c16b632..725bb0fb941d 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/mm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/mm.h
@@ -25,6 +25,7 @@ int hyp_back_vmemmap(phys_addr_t back);
int pkvm_cpu_set_vector(enum arm64_hyp_spectre_vector slot);
int pkvm_create_mappings(void *from, void *to, enum kvm_pgtable_prot prot);
int pkvm_create_mappings_locked(void *from, void *to, enum kvm_pgtable_prot prot);
+void pkvm_remove_mappings(void *from, void *to);
int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
enum kvm_pgtable_prot prot,
unsigned long *haddr);
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index 773426a68d2d..ec59da1322a7 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -146,6 +146,20 @@ int pkvm_create_mappings(void *from, void *to, enum kvm_pgtable_prot prot)
return ret;
}
+void pkvm_remove_mappings(void *from, void *to)
+{
+ u64 size;
+
+ to = PTR_ALIGN(to, PAGE_SIZE);
+ from = PTR_ALIGN_DOWN(from, PAGE_SIZE);
+ size = (u64)to - (u64)from;
+ WARN_ON(from > to);
+
+ hyp_spin_lock(&pkvm_pgd_lock);
+ WARN_ON(kvm_pgtable_hyp_unmap(&pkvm_pgtable, (u64)from, size) != size);
+ hyp_spin_unlock(&pkvm_pgd_lock);
+}
+
int hyp_back_vmemmap(phys_addr_t back)
{
unsigned long i, start, size, end = 0;
--
2.54.0.631.ge1b05301d1-goog
^ permalink raw reply related
* [PATCH 03/17] KVM: arm64: Add __hyp_allocator_map for the pKVM hyp
From: Vincent Donnefort @ 2026-05-20 15:26 UTC (permalink / raw)
To: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will
Cc: linux-arm-kernel, kvmarm, kernel-team, qperret, tabba,
Vincent Donnefort
In-Reply-To: <20260520152650.4107895-1-vdonnefort@google.com>
In preparation for the pKVM heap allocator, introduce __hyp_allocator_map()
to map a single physical page to a given virtual address in the hypervisor
stage-1 page-table.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/kvm/hyp/include/nvhe/mm.h b/arch/arm64/kvm/hyp/include/nvhe/mm.h
index 725bb0fb941d..98a7774b541c 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/mm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/mm.h
@@ -32,5 +32,6 @@ int __pkvm_create_private_mapping(phys_addr_t phys, size_t size,
int pkvm_create_stack(phys_addr_t phys, unsigned long *haddr);
int pkvm_alloc_private_va_range(size_t size, unsigned long *haddr);
phys_addr_t __pkvm_private_range_pa(void *va);
+int __hyp_allocator_map(void *va, phys_addr_t phys);
#endif /* __KVM_HYP_MM_H */
diff --git a/arch/arm64/kvm/hyp/nvhe/mm.c b/arch/arm64/kvm/hyp/nvhe/mm.c
index ec59da1322a7..c1c01f81ac5f 100644
--- a/arch/arm64/kvm/hyp/nvhe/mm.c
+++ b/arch/arm64/kvm/hyp/nvhe/mm.c
@@ -160,6 +160,11 @@ void pkvm_remove_mappings(void *from, void *to)
hyp_spin_unlock(&pkvm_pgd_lock);
}
+int __hyp_allocator_map(void *va, phys_addr_t phys)
+{
+ return __pkvm_create_mappings((unsigned long)va, PAGE_SIZE, phys, PAGE_HYP);
+}
+
int hyp_back_vmemmap(phys_addr_t back)
{
unsigned long i, start, size, end = 0;
--
2.54.0.631.ge1b05301d1-goog
^ permalink raw reply related
* [PATCH 05/17] KVM: arm64: Allow kvm_hyp_memcache usage outside of stage-2
From: Vincent Donnefort @ 2026-05-20 15:26 UTC (permalink / raw)
To: maz, oliver.upton, joey.gouly, suzuki.poulose, yuzenghui,
catalin.marinas, will
Cc: linux-arm-kernel, kvmarm, kernel-team, qperret, tabba,
Vincent Donnefort
In-Reply-To: <20260520152650.4107895-1-vdonnefort@google.com>
Although currently limited to guest stage-2 page-table allocations,
struct kvm_hyp_memcache is a useful primitive for passing a list of
discontiguous pages between host and hypervisor.
Introduce init_hyp_memcache() to initialise a generic hyp memcache, and
init_hyp_stage2_memcache() for stage-2 specific memcaches. The generic
initialiser will be used to top up the upcoming pKVM heap allocator.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 65eead8362e0..15c5378b70a0 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -91,9 +91,22 @@ struct kvm_hyp_memcache {
struct pkvm_mapping *mapping; /* only used from EL1 */
#define HYP_MEMCACHE_ACCOUNT_STAGE2 BIT(1)
+#define HYP_MEMCACHE_ACCOUNT_KMEMCG BIT(2)
unsigned long flags;
};
+static inline void init_hyp_memcache(struct kvm_hyp_memcache *mc)
+{
+ memset(mc, 0, sizeof(*mc));
+ mc->mapping = ZERO_SIZE_PTR; /* Prevent allocation, solely useful for stage2 memcache */
+}
+
+static inline void init_hyp_stage2_memcache(struct kvm_hyp_memcache *mc)
+{
+ memset(mc, 0, sizeof(*mc));
+ mc->flags = HYP_MEMCACHE_ACCOUNT_STAGE2 | HYP_MEMCACHE_ACCOUNT_KMEMCG;
+}
+
static inline void push_hyp_memcache(struct kvm_hyp_memcache *mc,
phys_addr_t *p,
phys_addr_t (*to_pa)(void *virt))
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index d089c107d9b7..04dd442c127e 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -1132,9 +1132,11 @@ static void hyp_mc_free_fn(void *addr, void *mc)
static void *hyp_mc_alloc_fn(void *mc)
{
struct kvm_hyp_memcache *memcache = mc;
+ gfp_t gfp = (memcache->flags & HYP_MEMCACHE_ACCOUNT_KMEMCG) ?
+ GFP_KERNEL_ACCOUNT : GFP_KERNEL;
void *addr;
- addr = (void *)__get_free_page(GFP_KERNEL_ACCOUNT);
+ addr = (void *)__get_free_page(gfp);
if (addr && memcache->flags & HYP_MEMCACHE_ACCOUNT_STAGE2)
kvm_account_pgtable_pages(addr, 1);
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index 053e4f733e4b..8324a6a1bc48 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -111,7 +111,7 @@ static int __pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu)
void *hyp_vcpu;
int ret;
- vcpu->arch.pkvm_memcache.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
+ init_hyp_stage2_memcache(&vcpu->arch.pkvm_memcache);
hyp_vcpu = alloc_pages_exact(hyp_vcpu_sz, GFP_KERNEL_ACCOUNT);
if (!hyp_vcpu)
@@ -172,7 +172,7 @@ static int __pkvm_create_hyp_vm(struct kvm *kvm)
goto free_vm;
kvm->arch.pkvm.is_created = true;
- kvm->arch.pkvm.stage2_teardown_mc.flags |= HYP_MEMCACHE_ACCOUNT_STAGE2;
+ init_hyp_stage2_memcache(&kvm->arch.pkvm.stage2_teardown_mc);
kvm_account_pgtable_pages(pgd, pgd_sz / PAGE_SIZE);
return 0;
--
2.54.0.631.ge1b05301d1-goog
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox