* Re: [PATCH] srcu: Optimize SRCU-fast per-CPU counter increments on arm64
From: Will Deacon @ 2026-03-26 10:58 UTC (permalink / raw)
To: Puranjay Mohan
Cc: Lai Jiangshan, Mark Rutland, Catalin Marinas, Paul E. McKenney,
Josh Triplett, Steven Rostedt, Mathieu Desnoyers, rcu,
linux-arm-kernel, linux-kernel
In-Reply-To: <20260326102608.1855088-1-puranjay@kernel.org>
On Thu, Mar 26, 2026 at 03:26:07AM -0700, Puranjay Mohan wrote:
> On architectures like arm64, this_cpu_inc() wraps the underlying atomic
> instruction (ldadd) with preempt_disable/enable to prevent migration
> between the per-CPU address calculation and the atomic operation.
> However, SRCU does not need this protection because it sums counters
> across all CPUs for grace-period detection, so operating on a "stale"
> CPU's counter after migration is harmless.
>
> This commit therefore introduces srcu_percpu_counter_inc(), which
> consolidates the SRCU-fast reader counter updates into a single helper,
> replacing the if/else dispatch between this_cpu_inc() and
> atomic_long_inc(raw_cpu_ptr(...)) that was previously open-coded at
> each call site.
>
> On arm64, this helper uses atomic_long_fetch_add_relaxed(), which
> compiles to the value-returning ldadd instruction. This is preferred
> over atomic_long_inc()'s non-value-returning stadd because ldadd is
> resolved in L1 cache whereas stadd may be resolved further out in the
> memory hierarchy [1].
>
> On x86, where this_cpu_inc() compiles to a single "incl %gs:offset"
> instruction with no preempt wrappers, the helper falls through to
> this_cpu_inc(), so there is no change. Architectures with
> NEED_SRCU_NMI_SAFE continue to use atomic_long_inc(raw_cpu_ptr(...)),
> again with no change. All remaining architectures also use the
> this_cpu_inc() path, again with no change.
>
> refscale measurements on a 72-CPU arm64 Neoverse-V2 system show ~11%
> improvement in SRCU-fast reader duration:
>
> Unpatched: median 9.273 ns, avg 9.319 ns (min 9.219, max 9.853)
> Patched: median 8.275 ns, avg 8.411 ns (min 8.186, max 9.183)
>
> Command: kvm.sh --torture refscale --duration 1 --cpus 72 \
> --configs NOPREEMPT --trust-make --bootargs \
> "refscale.scale_type=srcu-fast refscale.nreaders=72 \
> refscale.nruns=100"
>
> [1] https://lore.kernel.org/r/e7d539ed-ced0-4b96-8ecd-048a5b803b85@paulmck-laptop
>
> Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> ---
> include/linux/srcutree.h | 51 +++++++++++++++++++++++++++-------------
> 1 file changed, 35 insertions(+), 16 deletions(-)
>
> diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h
> index fd1a9270cb9a..4ff18de3edfd 100644
> --- a/include/linux/srcutree.h
> +++ b/include/linux/srcutree.h
> @@ -286,15 +286,43 @@ static inline struct srcu_ctr __percpu *__srcu_ctr_to_ptr(struct srcu_struct *ss
> * on architectures that support NMIs but do not supply NMI-safe
> * implementations of this_cpu_inc().
> */
> +
> +/*
> + * Atomically increment a per-CPU SRCU counter.
> + *
> + * On most architectures, this_cpu_inc() is optimal (e.g., on x86 it is
> + * a single "incl %gs:offset" instruction). However, on architectures
> + * like arm64, s390, and loongarch, this_cpu_inc() wraps the underlying
> + * atomic instruction with preempt_disable/enable to prevent migration
> + * between the per-CPU address calculation and the atomic operation.
> + * SRCU does not need this protection because it sums counters across
> + * all CPUs for grace-period detection, so operating on a "stale" CPU's
> + * counter after migration is harmless.
> + *
> + * On arm64, use atomic_long_fetch_add_relaxed() which compiles to the
> + * value-returning ldadd instruction instead of atomic_long_inc()'s
> + * non-value-returning stadd, because ldadd is resolved in L1 cache
> + * whereas stadd may be resolved further out in the memory hierarchy.
> + * https://lore.kernel.org/r/e7d539ed-ced0-4b96-8ecd-048a5b803b85@paulmck-laptop
> + */
> +static __always_inline void
> +srcu_percpu_counter_inc(atomic_long_t __percpu *v)
> +{
> +#ifdef CONFIG_ARM64
> + (void)atomic_long_fetch_add_relaxed(1, raw_cpu_ptr(v));
> +#elif IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)
> + atomic_long_inc(raw_cpu_ptr(v));
> +#else
> + this_cpu_inc(v->counter);
> +#endif
> +}
No, this is a hack. arm64 shouldn't be treated specially here.
The ldadd issue was already fixed properly in
git.kernel.org/linus/535fdfc5a2285. If you want to improve our preempt
disable/enable code or add helpers that don't require that, then patches
are welcome, but bodging random callers with arch-specific code for a
micro-benchmark is completely the wrong approach.
Will
^ permalink raw reply
* Re: [PATCH v2 0/4] arm64: Add BRBE support for bpf_get_branch_snapshot()
From: Will Deacon @ 2026-03-26 11:01 UTC (permalink / raw)
To: Puranjay Mohan
Cc: bpf, Mark Rutland, Catalin Marinas, Alexei Starovoitov,
Andrii Nakryiko, Daniel Borkmann, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Leo Yan, Rob Herring,
Breno Leitao, linux-arm-kernel, linux-perf-users, kernel-team,
anshuman.khandual
In-Reply-To: <CANk7y0jnY-V7Hv912gwc45jSx2UqLw5PBcdOdoFfS175bNuDmg@mail.gmail.com>
On Thu, Mar 26, 2026 at 08:57:14AM +0000, Puranjay Mohan wrote:
> Hi Catalin, Mark, and Will,
>
> Would you mind taking a look at this patchset when you have a chance?
Adding Rob and Anshuman, as they wrote the perf driver for BRBE and are
the best people to review this stuff.
Will
^ permalink raw reply
* Re: [PATCH RESEND 1/2] regulator: dt-bindings: mt6315: Add regulator supplies
From: Mark Brown @ 2026-03-26 11:08 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Krzysztof Kozlowski, Liam Girdwood, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, linux-arm-kernel, linux-mediatek,
devicetree
In-Reply-To: <CAGXv+5Fo2GmvWQGogA-KTsFChE0-SOwWek6BQ+ZA3xaXup_z+A@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 717 bytes --]
On Thu, Mar 26, 2026 at 12:14:32PM +0800, Chen-Yu Tsai wrote:
> On Thu, Mar 26, 2026 at 12:55 AM Mark Brown <broonie@kernel.org> wrote:
> > The top level, so people can figure out where to describe supplies
> > without having to read the bindings so much - the supplies go into the
> > chip, even if they're distributed within it.
> OK. What about the more complicated mfd PMICs? We already added
> *-supplies for the regulator side of these PMICs in
> - regulator/mediatek,mt6358-regulator.yaml
> - regulator/mediatek,mt6363-regulator.yaml
> And my other series for the MT6359 also adds them in this manner.
Existing bindings are existing bindings, we can't really do anything
with them.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: Lorenzo Stoakes (Oracle) @ 2026-03-26 11:10 UTC (permalink / raw)
To: Baolin Wang
Cc: David Hildenbrand (Arm), Barry Song, akpm, catalin.marinas, will,
lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt, surenb,
mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <bfd282b1-523d-4945-97a0-ec30fe1df577@linux.alibaba.com>
On Thu, Mar 26, 2026 at 09:47:51AM +0800, Baolin Wang wrote:
>
>
> On 3/25/26 11:06 PM, Lorenzo Stoakes (Oracle) wrote:
> > On Wed, Mar 25, 2026 at 03:58:36PM +0100, David Hildenbrand (Arm) wrote:
> > > On 3/25/26 15:36, Lorenzo Stoakes (Oracle) wrote:
> > > > On Mon, Mar 16, 2026 at 03:15:18PM +0100, David Hildenbrand (Arm) wrote:
> > > > > On 3/16/26 07:25, Baolin Wang wrote:
> > > > > >
> > > > > >
> > > > > >
> > > > > > Sure. However, after investigating RISC‑V and x86, I found that
> > > > > > ptep_clear_flush_young() does not flush the TLB on these architectures:
> > > > > >
> > > > > > int ptep_clear_flush_young(struct vm_area_struct *vma,
> > > > > > unsigned long address, pte_t *ptep)
> > > > > > {
> > > > > > /*
> > > > > > * On x86 CPUs, clearing the accessed bit without a TLB flush
> > > > > > * doesn't cause data corruption. [ It could cause incorrect
> > > > > > * page aging and the (mistaken) reclaim of hot pages, but the
> > > > > > * chance of that should be relatively low. ]
> > > > > > *
> > > > > > * So as a performance optimization don't flush the TLB when
> > > > > > * clearing the accessed bit, it will eventually be flushed by
> > > > > > * a context switch or a VM operation anyway. [ In the rare
> > > > > > * event of it not getting flushed for a long time the delay
> > > > > > * shouldn't really matter because there's no real memory
> > > > > > * pressure for swapout to react to. ]
> > > > > > */
> > > > > > return ptep_test_and_clear_young(vma, address, ptep);
> > > > > > }
> > > > >
> > > > > You'd probably want an arch helper then, that tells you whether
> > > > > a flush_tlb_range() after ptep_test_and_clear_young() is required.
> > > > >
> > > > > Or some special flush_tlb_range() helper.
> > > > >
> > > > > I agree that it requires more work.
>
> (Sorry, David. I forgot to reply to your email because I've had a lot to
> sort out recently.)
>
> Rather than adding more arch helpers (we already have plenty for the young
> flag check), I think we should try removing the TLB flush, as I mentioned to
> Barry[1]. MGLRU reclaim already skips the TLB flush, and it seems to work
> fine. What do you think?
>
> Here are our previous attempts to remove the TLB flush:
>
> My patch: https://lkml.org/lkml/2023/10/24/533
> Barry's patch:
> https://lore.kernel.org/lkml/20220617070555.344368-1-21cnbao@gmail.com/
>
> [1] https://lore.kernel.org/all/6bdc4b03-9631-4717-a3fa-2785a7930aba@linux.alibaba.com/
>
> > > > Sorry unclear here - does the series need more work or does a follow up patch
> > > > need more work?
> > >
> > > Follow up!
> >
> > Ok good as in mm-stable now. Sadly means I don't get to review it but there we
> > go.
>
> Actually this patchset has already been merged upstream:)
Err but this revision was sent _during_ the merge window...?
Was sent on 9th Feb on Monday in merge window week 1, with a functional change
listed:
- Skip batched unmapping for uffd case, reported by Dev. Thanks.
And then sent in 2nd batch on 18th Feb (see [0]).
So we were ok with 1 week of 'testing' (does anybody actually test -next during
the merge window? Was it even sent to -next?) for what appears to be a
functional change?
And there was ongoing feedback on this and the v5 series (at [1])?
This doesn't really feel sane?
And now I'm confused as to whether mm-stable patches can collect tags, since
presumably this was in mm-stable at the point this respin was done?
Maybe I'm missing something here but this doesn't feel like a sane process?
Thanks, Lorenzo
[0]:https://lore.kernel.org/all/20260218200016.8906fb904af9439e7b496327@linux-foundation.org/
[1]:https://lore.kernel.org/linux-mm/cover.1766631066.git.baolin.wang@linux.alibaba.com/
^ permalink raw reply
* Re: [PATCH v2] net: stmmac: skip VLAN restore when VLAN hash ops are missing
From: Michal Piekos @ 2026-03-26 11:14 UTC (permalink / raw)
To: Ovidiu Panait
Cc: Maxime Chevallier, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Maxime Coquelin, Alexandre Torgue,
netdev@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <TY7P301MB198407F8C0280B991334304ED356A@TY7P301MB1984.JPNP301.PROD.OUTLOOK.COM>
On Thu, Mar 26, 2026 at 08:07:33AM +0000, Ovidiu Panait wrote:
> Hi,
>
> >
> > Hi,
> >
> > On 21/03/2026 06:38, Michal Piekos wrote:
> > > stmmac_vlan_restore() unconditionally calls stmmac_vlan_update() when
> > > NETIF_F_VLAN_FEATURES is set. On platforms where priv->hw->vlan (or
> > > ->update_vlan_hash) is not provided, stmmac_update_vlan_hash() returns
> > > -EINVAL via stmmac_do_void_callback(), resulting in a spurious
> > > "Failed to restore VLANs" error even when no VLAN filtering is in use.
> > >
> > > Check presence of VLAN HW FILTER flags before stmmac_vlan_update().
> > >
> > > Tested on Orange Pi Zero 3.
> > >
> > > Fixes: bd7ad51253a7 ("net: stmmac: Fix VLAN HW state restore")
> > > Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
> > > ---
> > > This patch fixes a noisy "Failed to restore VLANs" message on platforms
> > > where stmmac VLAN hash ops are not implemented.
> > > stmmac_vlan_restore() calls stmmac_vlan_update() without checking for
> > > VLAN hash ops presence which results in -EINVAL.
> >
> > I've been seeing the same message on socfpga. My two cents on that is
> > that this error messages doesn't bring anything to the table anyways.
> >
> > As Russell explains, it's either triggered when the vlan op isn't
> > implemented (the stmmac callback macro stuff turns that into a -EINVAL),
> > or when some capabilities arent present. All in all, it's always stuff
> > that users can't really do anything about, as it's HW limitations, I
> > think we can simply discard this message.
> >
> > Also, nothing actually checks what stmmac_vlan_restore() returns, so we
> > might as well return void ?
> >
>
> I think this is the best solution until the VLAN capabilities handling is
> cleaned up.
>
> Michal, please let me know if you will be handling this in v3 or I should
> send a fix for it.
>
I will provide the fix for it latest during the weekend.
Michal
> Thanks,
> Ovidiu
>
> > Maxime
> >
> > > ---
> > > Changes in v2:
> > > - Replace check for hash ops with check for HW FILTER flags
> > > - Link to v1: https://lore.kernel.org/r/20260314-vlan-restore-error-v1-
> > 1-4fc6c3e2115f@mmpsystems.pl
> > > ---
> > > drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 ++-
> > > 1 file changed, 2 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > > index 6827c99bde8c..cfc0ce9cec9c 100644
> > > --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > > +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
> > > @@ -6863,7 +6863,8 @@ static int stmmac_vlan_restore(struct stmmac_priv
> > *priv)
> > > {
> > > int ret;
> > >
> > > - if (!(priv->dev->features & NETIF_F_VLAN_FEATURES))
> > > + if (!(priv->dev->features &
> > > + (NETIF_F_HW_VLAN_CTAG_FILTER | NETIF_F_HW_VLAN_STAG_FILTER)))
> > > return 0;
> > >
> > > if (priv->hw->num_vlan)
> > >
> > > ---
> > > base-commit: 42bddab0563fe67882b2722620a66dd98c8dbf33
> > > change-id: 20260314-vlan-restore-error-f8b3a1c7f50a
> > >
> > > Best regards,
>
^ permalink raw reply
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
From: Dave Stevenson @ 2026-03-26 11:16 UTC (permalink / raw)
To: Ville Syrjälä
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <acPmcMbUvzWMzC-Q@intel.com>
On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
<ville.syrjala@linux.intel.com> wrote:
>
> On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > <nicolas.frattaroli@collabora.com> wrote:
> > >
> > > Add a new general DRM property named "color format" which can be used by
> > > userspace to request the display driver to output a particular color
> > > format.
> > >
> > > Possible options are:
> > > - auto (setup by default, driver internally picks the color format)
> > > - rgb
> > > - ycbcr444
> > > - ycbcr422
> > > - ycbcr420
> > >
> > > Drivers should advertise from this list which formats they support.
> > > Together with this list and EDID data from the sink we should be able
> > > to relay a list of usable color formats to users to pick from.
> > >
> > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > ---
> > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > 4 files changed, 228 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > index 26953ed6b53e..b7753454b777 100644
> > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > if (old_connector_state->max_requested_bpc !=
> > > new_connector_state->max_requested_bpc)
> > > new_crtc_state->connectors_changed = true;
> > > +
> > > + if (old_connector_state->color_format !=
> > > + new_connector_state->color_format)
> > > + new_crtc_state->connectors_changed = true;
> > > +
> > > }
> > >
> > > if (funcs->atomic_check)
> > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > index 5bd5bf6661df..dee510c85e59 100644
> > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > state->privacy_screen_sw_state = val;
> > > } else if (property == connector->broadcast_rgb_property) {
> > > state->hdmi.broadcast_rgb = val;
> > > + } else if (property == connector->color_format_property) {
> > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > + drm_dbg_atomic(connector->dev,
> > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > + connector->base.id, connector->name, val);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + state->color_format = val;
> > > } else if (connector->funcs->atomic_set_property) {
> > > return connector->funcs->atomic_set_property(connector,
> > > state, property, val);
> > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > *val = state->privacy_screen_sw_state;
> > > } else if (property == connector->broadcast_rgb_property) {
> > > *val = state->hdmi.broadcast_rgb;
> > > + } else if (property == connector->color_format_property) {
> > > + *val = state->color_format;
> > > } else if (connector->funcs->atomic_get_property) {
> > > return connector->funcs->atomic_get_property(connector,
> > > state, property, val);
> > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > index 47dc53c4a738..e848374dee0b 100644
> > > --- a/drivers/gpu/drm/drm_connector.c
> > > +++ b/drivers/gpu/drm/drm_connector.c
> > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > >
> > > +static const u32 hdmi_colorformats =
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > +
> > > +static const u32 dp_colorformats =
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > +
> > > /*
> > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > * Format Table 2-120
> > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > }
> > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > >
> > > +/**
> > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > + * @connector: connector to create the color format property on
> > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > + * values the connector supports
> > > + *
> > > + * Called by a driver to create a color format property. The property is
> > > + * attached to the connector automatically on success.
> > > + *
> > > + * @supported_color_formats should only include color formats the connector
> > > + * type can actually support.
> > > + *
> > > + * Returns:
> > > + * 0 on success, negative errno on error
> > > + */
> > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > + unsigned long supported_color_formats)
> > > +{
> > > + struct drm_device *dev = connector->dev;
> > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > + unsigned int i = 0;
> > > + unsigned long fmt;
> > > +
> > > + if (connector->color_format_property)
> > > + return 0;
> > > +
> > > + if (!supported_color_formats) {
> > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > +
> > > + switch (connector->connector_type) {
> > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > + break;
> > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > + case DRM_MODE_CONNECTOR_eDP:
> > > + if (supported_color_formats & ~dp_colorformats) {
> > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > + connector->base.id, connector->name);
> > > + return -EINVAL;
> > > + }
> > > + break;
> > > + }
> > > +
> > > + enum_list[0].name = "AUTO";
> > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > +
> > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > + switch (fmt) {
> > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > + break;
> > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > + break;
> > > + default:
> > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > + fmt, connector->base.id, connector->name);
> > > + continue;
> > > + }
> > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > + }
> > > +
> > > + connector->color_format_property =
> > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > + enum_list, i + 1);
> > > +
> > > + if (!connector->color_format_property)
> > > + return -ENOMEM;
> > > +
> > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > +
> > > + return 0;
> > > +}
> > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > +
> > > /**
> > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > * @old_state: old connector state to compare
> > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > index af8b92d2d5b7..bd549f912b76 100644
> > > --- a/include/drm/drm_connector.h
> > > +++ b/include/drm/drm_connector.h
> > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > + * Number of valid output color format values in this enum
> > > */
> > > enum drm_output_color_format {
> > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > };
> > >
> > > +/**
> > > + * enum drm_connector_color_format - Connector Color Format Request
> > > + *
> > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > + * for a specific color format on a connector through the DRM "color format"
> > > + * property. The difference is that it has an "AUTO" value to specify that
> > > + * no specific choice has been made.
> > > + */
> > > +enum drm_connector_color_format {
> > > + /**
> > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > + * helpers should pick a suitable color format. All implementations of a
> > > + * specific display protocol must behave the same way with "AUTO", but
> > > + * different display protocols do not necessarily have the same "AUTO"
> > > + * semantics.
> > > + *
> > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > + * YCbCr 4:2:0.
> >
> > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
>
> On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> compared to 8bpc 4:4:4.
It does save bandwidth against 10 or 12bpc RGB 4:4:4.
Or is the implication that max_bpc = 12 and
DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
RGB in preference to selecting 4:2:2?
Dave
> --
> Ville Syrjälä
> Intel
^ permalink raw reply
* Re: [PATCH] srcu: Optimize SRCU-fast per-CPU counter increments on arm64
From: Puranjay Mohan @ 2026-03-26 11:17 UTC (permalink / raw)
To: Will Deacon
Cc: Lai Jiangshan, Mark Rutland, Catalin Marinas, Paul E. McKenney,
Josh Triplett, Steven Rostedt, Mathieu Desnoyers, rcu,
linux-arm-kernel, linux-kernel
In-Reply-To: <acURahmSDqFYgcIz@willie-the-truck>
On Thu, Mar 26, 2026 at 10:58 AM Will Deacon <will@kernel.org> wrote:
>
> On Thu, Mar 26, 2026 at 03:26:07AM -0700, Puranjay Mohan wrote:
> > On architectures like arm64, this_cpu_inc() wraps the underlying atomic
> > instruction (ldadd) with preempt_disable/enable to prevent migration
> > between the per-CPU address calculation and the atomic operation.
> > However, SRCU does not need this protection because it sums counters
> > across all CPUs for grace-period detection, so operating on a "stale"
> > CPU's counter after migration is harmless.
> >
> > This commit therefore introduces srcu_percpu_counter_inc(), which
> > consolidates the SRCU-fast reader counter updates into a single helper,
> > replacing the if/else dispatch between this_cpu_inc() and
> > atomic_long_inc(raw_cpu_ptr(...)) that was previously open-coded at
> > each call site.
> >
> > On arm64, this helper uses atomic_long_fetch_add_relaxed(), which
> > compiles to the value-returning ldadd instruction. This is preferred
> > over atomic_long_inc()'s non-value-returning stadd because ldadd is
> > resolved in L1 cache whereas stadd may be resolved further out in the
> > memory hierarchy [1].
> >
> > On x86, where this_cpu_inc() compiles to a single "incl %gs:offset"
> > instruction with no preempt wrappers, the helper falls through to
> > this_cpu_inc(), so there is no change. Architectures with
> > NEED_SRCU_NMI_SAFE continue to use atomic_long_inc(raw_cpu_ptr(...)),
> > again with no change. All remaining architectures also use the
> > this_cpu_inc() path, again with no change.
> >
> > refscale measurements on a 72-CPU arm64 Neoverse-V2 system show ~11%
> > improvement in SRCU-fast reader duration:
> >
> > Unpatched: median 9.273 ns, avg 9.319 ns (min 9.219, max 9.853)
> > Patched: median 8.275 ns, avg 8.411 ns (min 8.186, max 9.183)
> >
> > Command: kvm.sh --torture refscale --duration 1 --cpus 72 \
> > --configs NOPREEMPT --trust-make --bootargs \
> > "refscale.scale_type=srcu-fast refscale.nreaders=72 \
> > refscale.nruns=100"
> >
> > [1] https://lore.kernel.org/r/e7d539ed-ced0-4b96-8ecd-048a5b803b85@paulmck-laptop
> >
> > Signed-off-by: Puranjay Mohan <puranjay@kernel.org>
> > ---
> > include/linux/srcutree.h | 51 +++++++++++++++++++++++++++-------------
> > 1 file changed, 35 insertions(+), 16 deletions(-)
> >
> > diff --git a/include/linux/srcutree.h b/include/linux/srcutree.h
> > index fd1a9270cb9a..4ff18de3edfd 100644
> > --- a/include/linux/srcutree.h
> > +++ b/include/linux/srcutree.h
> > @@ -286,15 +286,43 @@ static inline struct srcu_ctr __percpu *__srcu_ctr_to_ptr(struct srcu_struct *ss
> > * on architectures that support NMIs but do not supply NMI-safe
> > * implementations of this_cpu_inc().
> > */
> > +
> > +/*
> > + * Atomically increment a per-CPU SRCU counter.
> > + *
> > + * On most architectures, this_cpu_inc() is optimal (e.g., on x86 it is
> > + * a single "incl %gs:offset" instruction). However, on architectures
> > + * like arm64, s390, and loongarch, this_cpu_inc() wraps the underlying
> > + * atomic instruction with preempt_disable/enable to prevent migration
> > + * between the per-CPU address calculation and the atomic operation.
> > + * SRCU does not need this protection because it sums counters across
> > + * all CPUs for grace-period detection, so operating on a "stale" CPU's
> > + * counter after migration is harmless.
> > + *
> > + * On arm64, use atomic_long_fetch_add_relaxed() which compiles to the
> > + * value-returning ldadd instruction instead of atomic_long_inc()'s
> > + * non-value-returning stadd, because ldadd is resolved in L1 cache
> > + * whereas stadd may be resolved further out in the memory hierarchy.
> > + * https://lore.kernel.org/r/e7d539ed-ced0-4b96-8ecd-048a5b803b85@paulmck-laptop
> > + */
> > +static __always_inline void
> > +srcu_percpu_counter_inc(atomic_long_t __percpu *v)
> > +{
> > +#ifdef CONFIG_ARM64
> > + (void)atomic_long_fetch_add_relaxed(1, raw_cpu_ptr(v));
> > +#elif IS_ENABLED(CONFIG_NEED_SRCU_NMI_SAFE)
> > + atomic_long_inc(raw_cpu_ptr(v));
> > +#else
> > + this_cpu_inc(v->counter);
> > +#endif
> > +}
>
> No, this is a hack. arm64 shouldn't be treated specially here.
>
> The ldadd issue was already fixed properly in
> git.kernel.org/linus/535fdfc5a2285. If you want to improve our preempt
> disable/enable code or add helpers that don't require that, then patches
> are welcome, but bodging random callers with arch-specific code for a
> micro-benchmark is completely the wrong approach.
Thanks for the feedback.
I basically want to remove the overhead of preempt disable/enable that
comes with this_cpu_*(), because in SRCU (and maybe at other places
too) we don't need that safety. One way would be to define
raw_cpu_add_* helpers in arch/arm64/include/asm/percpu.h but that
wouldn't be good for existing callers of raw_cpu_add() as currently
raw_cpu_add() resolves to raw_cpu_generic_to_op(pcp, val, +=), which
is not atomic. Another way would be to add new helpers that do per-CPU
atomics without preempt enable/disable.
And do you think this optimization is worth doing? or should I just not do it?
Thanks,
Puranjay
^ permalink raw reply
* [PATCH v2 1/2] dt: bindings: arm: add bindings for TQMa95xxLA
From: Alexander Stein @ 2026-03-26 11:03 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Geert Uytterhoeven, Magnus Damm, Shawn Guo
Cc: Markus Niebel, devicetree, linux-kernel, imx, linux-arm-kernel,
linux, linux-renesas-soc, Alexander Stein, Krzysztof Kozlowski
From: Markus Niebel <Markus.Niebel@ew.tq-group.com>
TQMa95xxLA is a SOM using NXP i.MX95 CPU. MBa95xxCA is a carrier
reference design / starter kit board.
[1] https://www.tq-group.com/en/products/tq-embedded/arm-architecture/tqma95xxla/
Signed-off-by: Markus Niebel <Markus.Niebel@ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
---
Changes in v2:
* Added Krzysztof's A-b
Documentation/devicetree/bindings/arm/fsl.yaml | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index a476a6b11ba06..db8f8a0c87619 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -1614,6 +1614,17 @@ properties:
- const: kontron,imx93-osm-s # Kontron OSM-S i.MX93 SoM
- const: fsl,imx93
+ - description:
+ TQMa95xxLA is a series of SOM featuring NXP i.MX95 SoC variants,
+ designed to be soldered on different carrier boards.
+ MBa95xxCA is a carrier reference design / starter kit that allows
+ to use TQMa95xxLA via an adaper board.
+ items:
+ - enum:
+ - tq,imx95-tqma9596la-mba95xxca # TQ-Systems GmbH i.MX95 TQMa95xxLA SOM on MBa95xxCA
+ - const: tq,imx95-tqma9596la # TQ-Systems GmbH i.MX95 TQMa95xxLA SOM
+ - const: fsl,imx95
+
- description:
TQMa95xxSA is a series of SOM featuring NXP i.MX95 SoC variants.
It has the SMARC form factor and is designed to be placed on
--
2.43.0
^ permalink raw reply related
* [PATCH v2 2/2] arm64: dts: add tqma9596la-mba95xxca
From: Alexander Stein @ 2026-03-26 11:03 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Geert Uytterhoeven, Magnus Damm, Shawn Guo
Cc: Markus Niebel, devicetree, linux-kernel, imx, linux-arm-kernel,
linux, linux-renesas-soc, Alexander Stein
In-Reply-To: <20260326111803.1248934-1-alexander.stein@ew.tq-group.com>
From: Markus Niebel <Markus.Niebel@ew.tq-group.com>
This adds support for TQMa95xxLA modules, designed to be soldered
on a carrier board. MBa95xxCA is a carrier reference board / starter kit
design.
There is a common device tree for all variants with e.g. reduced
CPU core / feature count.
Enable the external accessible PCIe controllers as host,
add clocking and reset GPIO. While at it, add hogs for GPIO
lines from the M.2 slots until M.2 connector driver is available.
Signed-off-by: Markus Niebel <Markus.Niebel@ew.tq-group.com>
Signed-off-by: Alexander Stein <alexander.stein@ew.tq-group.com>
---
Changes in v2:
* removed useless regulator
* added USB PD source configuration
* Removed unused uart-has-rtscts properties (unused by LPUART)
* Fixed RTS/CTS pullups in pinctrl
* Added thermalzone on module
arch/arm64/boot/dts/freescale/Makefile | 1 +
.../freescale/imx95-tqma9596la-mba95xxca.dts | 947 ++++++++++++++++++
.../boot/dts/freescale/imx95-tqma9596la.dtsi | 297 ++++++
3 files changed, 1245 insertions(+)
create mode 100644 arch/arm64/boot/dts/freescale/imx95-tqma9596la-mba95xxca.dts
create mode 100644 arch/arm64/boot/dts/freescale/imx95-tqma9596la.dtsi
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 2879d567dede0..df79e56771319 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -554,6 +554,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx95-15x15-frdm.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-19x19-evk-sof.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-toradex-smarc-dev.dtb
+dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596la-mba95xxca.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-tqma9596sa-mb-smarc-2.dtb
dtb-$(CONFIG_ARCH_MXC) += imx95-var-dart-sonata.dtb
diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596la-mba95xxca.dts b/arch/arm64/boot/dts/freescale/imx95-tqma9596la-mba95xxca.dts
new file mode 100644
index 0000000000000..f75580bb91e3e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596la-mba95xxca.dts
@@ -0,0 +1,947 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2024-2026 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ * Author: Markus Niebel
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/leds/common.h>
+#include <dt-bindings/net/ti-dp83867.h>
+#include <dt-bindings/pwm/pwm.h>
+#include <dt-bindings/usb/pd.h>
+#include "imx95-tqma9596la.dtsi"
+
+/ {
+ model = "TQ-Systems i.MX95 TQMa95xxLA on MBa95xxCA";
+ compatible = "tq,imx95-tqma9596la-mba95xxca", "tq,imx95-tqma9596la", "fsl,imx95";
+ chassis-type = "embedded";
+
+ aliases {
+ ethernet0 = &enetc_port0;
+ ethernet1 = &enetc_port1;
+ ethernet2 = &enetc_port2;
+ gpio0 = &gpio1;
+ gpio1 = &gpio2;
+ gpio2 = &gpio3;
+ gpio3 = &gpio4;
+ i2c0 = &lpi2c1;
+ i2c1 = &lpi2c2;
+ i2c2 = &lpi2c3;
+ i2c3 = &lpi2c4;
+ i2c4 = &lpi2c5;
+ i2c5 = &lpi2c6;
+ i2c6 = &lpi2c7;
+ i2c7 = &lpi2c8;
+ mmc0 = &usdhc1;
+ mmc1 = &usdhc2;
+ rtc0 = &pcf85063;
+ rtc1 = &scmi_bbm;
+ serial0 = &lpuart1;
+ serial1 = &lpuart2;
+ serial2 = &lpuart3;
+ serial3 = &lpuart4;
+ serial4 = &lpuart5;
+ serial5 = &lpuart6;
+ serial6 = &lpuart7;
+ serial7 = &lpuart8;
+ spi0 = &flexspi1;
+ };
+
+ chosen {
+ stdout-path = &lpuart1;
+ };
+
+ backlight_lvds: backlight-lvds {
+ compatible = "pwm-backlight";
+ pwms = <&tpm5 2 100000 0>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ enable-gpios = <&expander2 6 GPIO_ACTIVE_HIGH>;
+ power-supply = <®_12v0>;
+ status = "disabled";
+ };
+
+ clk_eth: clk-eth {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <156250000>;
+ };
+
+ /*
+ * TODO: gate is disabled for now and GPIO are hogged
+ * ENETC driver switches the clock far too late for ENETC2 + SFP
+ */
+ clk_eth_gate: clk-eth-gate {
+ compatible = "gpio-gate-clock";
+ enable-gpios = <&expander2 0 GPIO_ACTIVE_HIGH>;
+ clocks = <&clk_eth>;
+ #clock-cells = <0>;
+ status = "disabled";
+ };
+
+ clk_xtal25: clk-xtal25 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ autorepeat;
+
+ button-b {
+ label = "BUTTON_B#";
+ linux,code = <BTN_1>;
+ gpios = <&expander1 0 GPIO_ACTIVE_LOW>;
+ wakeup-source;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ led-1 {
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_STATUS;
+ gpios = <&expander2 13 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ led-2 {
+ color = <LED_COLOR_ID_AMBER>;
+ function = LED_FUNCTION_HEARTBEAT;
+ gpios = <&expander2 14 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ iio-hwmon {
+ compatible = "iio-hwmon";
+ io-channels = <&adc1 0>, <&adc1 1>, <&adc1 2>, <&adc1 3>,
+ <&adc1 4>, <&adc1 5>, <&adc1 6>, <&adc1 7>;
+ };
+
+ reg_v1v8_mb: regulator-v1v8-mb {
+ compatible = "regulator-fixed";
+ regulator-name = "V_1V8_MB";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ reg_v3v3_mb: regulator-v3v3-mb {
+ compatible = "regulator-fixed";
+ regulator-name = "V_3V3_MB";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_3v3a_10g: regulator-3v3a-10g {
+ compatible = "regulator-fixed";
+ regulator-name = "3V3A_10G";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&expander2 15 GPIO_ACTIVE_HIGH>;
+ startup-delay-us = <2000>;
+ enable-active-high;
+ };
+
+ reg_12v0: regulator-12v0 {
+ compatible = "regulator-fixed";
+ regulator-name = "12V0";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ gpio = <&expander1 15 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_pwm_fan: regulator-pwm-fan {
+ compatible = "regulator-fixed";
+ regulator-name = "FAN_PWR";
+ regulator-min-microvolt = <12000000>;
+ regulator-max-microvolt = <12000000>;
+ gpio = <&expander3 15 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ vin-supply = <®_12v0>;
+ };
+
+ reg_lvds: regulator-lvds {
+ compatible = "regulator-fixed";
+ regulator-name = "LCD_PWR_EN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&expander2 7 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ /* USB NC limitations, RM 162.1.2 VBUS limitations */
+ reg_vbus_usb3: regulator-vbus-usb3 {
+ compatible = "regulator-fixed";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-name = "USB3_VBUS";
+ gpio = <&gpio4 1 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ sfp_xfi: sfp-xfi {
+ compatible = "sff,sfp";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sfp>;
+ i2c-bus = <&lpi2c7>;
+ maximum-power-milliwatt = <2000>;
+ mod-def0-gpios = <&expander1 3 GPIO_ACTIVE_LOW>;
+ tx-fault-gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
+ los-gpios = <&gpio2 31 GPIO_ACTIVE_HIGH>;
+ tx-disable-gpios = <&expander2 2 GPIO_ACTIVE_HIGH>;
+ };
+
+ sound {
+ compatible = "fsl,imx-audio-tlv320aic32x4";
+ model = "tqm-tlv320aic32";
+ audio-codec = <&tlv320aic3x04>;
+ audio-cpu = <&sai3>;
+ audio-routing =
+ "IN3_L", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HPL",
+ "Headphone Jack", "HPR",
+ "IN1_L", "Line In Jack",
+ "IN1_R", "Line In Jack",
+ "Line Out Jack", "LOL",
+ "Line Out Jack", "LOR";
+ };
+};
+
+&adc1 {
+ status = "okay";
+};
+
+&enetc_port0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enetc0>;
+ phy-handle = <ðphy0>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+};
+
+&enetc_port1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enetc1>;
+ phy-handle = <ðphy1>;
+ phy-mode = "rgmii-id";
+ status = "okay";
+};
+
+/* No support for XFI yet */
+&enetc_port2 {
+ sfp = <&sfp_xfi>;
+ phy-mode = "10gbase-r";
+ clocks = <&clk_eth>;
+ clock-names = "enet_ref_clk";
+ managed = "in-band-status";
+ status = "disabled";
+};
+
+&flexcan1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "okay";
+};
+
+&flexcan2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan2>;
+ status = "okay";
+};
+
+&lpi2c2 {
+ tlv320aic3x04: audio-codec@18 {
+ compatible = "ti,tlv320aic32x4";
+ reg = <0x18>;
+ clocks = <&scmi_clk IMX95_CLK_SAI3>;
+ clock-names = "mclk";
+ reset-gpios = <&expander1 14 GPIO_ACTIVE_LOW>;
+ iov-supply = <®_v3v3_mb>;
+ ldoin-supply = <®_v3v3_mb>;
+ };
+
+ fan_controller: fan-controller@2f {
+ compatible = "microchip,emc2301", "microchip,emc2305";
+ reg = <0x2f>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #pwm-cells = <3>;
+ status = "okay";
+
+ fan: fan@0 {
+ reg = <0x0>;
+ pwms = <&fan_controller 40000 PWM_POLARITY_INVERTED 1>;
+ #cooling-cells = <2>;
+ fan-supply = <®_pwm_fan>;
+ };
+ };
+
+ ptn5110: usb-typec@50 {
+ compatible = "nxp,ptn5110", "tcpci";
+ reg = <0x50>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_typec>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <28 IRQ_TYPE_LEVEL_LOW>;
+
+ typec_con: connector {
+ compatible = "usb-c-connector";
+ label = "X9";
+ power-role = "source";
+ data-role = "dual";
+ source-pdos = <PDO_FIXED(5000, 500, PDO_FIXED_USB_COMM)>;
+ self-powered;
+
+ port {
+ typec_con_hs: endpoint {
+ remote-endpoint = <&typec_hs>;
+ };
+ };
+ };
+ };
+
+ sensor_mb: temperature-sensor@1e {
+ compatible = "nxp,se97b", "jedec,jc-42.4-temp";
+ reg = <0x1e>;
+ };
+
+ eeprom_mb: eeprom@56 {
+ compatible = "nxp,se97b", "atmel,24c02";
+ reg = <0x56>;
+ pagesize = <16>;
+ vcc-supply = <®_v3v3_mb>;
+ };
+
+ pcieclk: clock-generator@68 {
+ compatible = "renesas,9fgv0441";
+ reg = <0x68>;
+ clocks = <&clk_xtal25>;
+ #clock-cells = <1>;
+ };
+
+ /* D39 IN/OUT 3V3 */
+ expander1: gpio@74 {
+ compatible = "ti,tca9539";
+ reg = <0x74>;
+ vcc-supply = <®_v3v3_mb>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_expander1>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupt-parent = <&gpio2>;
+ interrupts = <14 IRQ_TYPE_EDGE_FALLING>;
+
+ gpio-line-names =
+ /* 00 */ "BUTTON_B#", "CAM0_SYNC_3V3",
+ /* 02 */ "CAM1_SYNC_3V3", "SFP_MOD_ABS",
+ /* 04 */ "DIG_IN1", "DIG_IN2",
+ /* 06 */ "DIG_IN3", "DIG_IN4",
+ /* 08 */ "DIG_OUT_1_2_STATE", "DIG_OUT_3_4_STATE",
+ /* 10 */ "DIG_OUT_1_EN", "DIG_OUT_2_EN",
+ /* 12 */ "DIG_OUT_3_EN", "DIG_OUT_4_EN",
+ /* 14 */ "AUDIO_RST#", "12V_EN";
+ };
+
+ /* D40 OUT 3V3 */
+ expander2: gpio@75 {
+ compatible = "ti,tca9539";
+ reg = <0x75>;
+ vcc-supply = <®_3v3>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ /* 00 */ "ETH10G_REFCLK_EN", "ETH10G_REFCLK_RST#",
+ /* 02 */ "SFP_TX_DIS", "USB3_RESET#",
+ /* 04 */ "USB2_RESET#", "LCD_RESET#",
+ /* 06 */ "LCD_BLT_EN", "LCD_PWR_EN",
+ /* 08 */ "M2_KEYE_PERST#", "M2_KEYE_WDISABLE1#",
+ /* 10 */ "M2_KEYE_WDISABLE2#", "M2_KEYB_PERST#",
+ /* 12 */ "M2_KEYB_WDISABLE1#", "USER_LED1",
+ /* 14 */ "USER_LED2", "3V3A_10G_EN";
+
+ eth10g-refclk-en-hog {
+ gpio-hog;
+ gpios = <0 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "ETH10G_REFCLK_EN";
+ };
+
+ eth10g-refclk-rst-hog {
+ gpio-hog;
+ gpios = <1 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "ETH10G_REFCLK_RST#";
+ };
+
+ m2_keye_wdisable1_hog: m2-keye-wdisable1-hog {
+ gpio-hog;
+ gpios = <9 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYE_WDISABLE1#";
+ };
+
+ m2_keye_wdisable2_hog: m2-keye-wdisable2-hog {
+ gpio-hog;
+ gpios = <10 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYE_WDISABLE2#";
+ };
+
+ m2-keyb-wdisable1-hog {
+ gpio-hog;
+ gpios = <12 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYB_WDISABLE1#";
+ };
+ };
+
+ /* D41 OUT 1V8 */
+ expander3: gpio@76 {
+ compatible = "ti,tca9539";
+ reg = <0x76>;
+ vcc-supply = <®_v1v8_mb>;
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ gpio-line-names =
+ /* 00 */ "ENET1_RESET#", "ENET2_RESET#",
+ /* 02 */ "M2_KEYE_SDIO_RST#", "M2_KEYE_DEV_WLAN_WAKE#",
+ /* 04 */ "M2_KEYE_DEV_BT_WAKE", "M2_KEYB_W_DISABLE2#",
+ /* 06 */ "M2_KEYB_RST#", "M2_KEYB_FULL_CARD_PWR_OFF#",
+ /* 08 */ "M2_KEYB_DPR", "CAM0_PWR#",
+ /* 10 */ "CAM1_PWR#", "CAM0_RST#",
+ /* 12 */ "CAM1_RST#", "CAM0_TRIGGER",
+ /* 14 */ "CAM1_TRIGGER", "FAN_PWR_EN";
+
+ m2-keye-sdio-rst-hog {
+ gpio-hog;
+ gpios = <2 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYE_SDIO_RST#";
+ };
+
+ m2-keye-dev_wlan-wake-hog {
+ gpio-hog;
+ gpios = <3 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "M2_KEYE_DEV_WLAN_WAKE#";
+ };
+
+ m2-keye-dev_bt-wake-hog {
+ gpio-hog;
+ gpios = <4 GPIO_ACTIVE_LOW>;
+ input;
+ line-name = "M2_KEYE_DEV_BT_WAKE#";
+ };
+
+ m2-keyb-wdisable2-hog {
+ gpio-hog;
+ gpios = <5 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYB_WDISABLE1#";
+ };
+
+ m2-keyb-rst-hog {
+ gpio-hog;
+ gpios = <6 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYB_RST#";
+ };
+
+ m2-keyb-full-card-pwr-off-hog {
+ gpio-hog;
+ gpios = <7 GPIO_ACTIVE_LOW>;
+ output-low;
+ line-name = "M2_KEYB_FULL_CARD_PWR_OFF#";
+ };
+ };
+};
+
+/* X4 + XFP */
+&lpi2c7 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_lpi2c7>;
+ pinctrl-1 = <&pinctrl_lpi2c7_recovery>;
+ scl-gpios = <&gpio2 7 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ sda-gpios = <&gpio2 6 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
+ status = "okay";
+
+ /* TODO: 0x19: retimer */
+
+ /* 0x50 / 0x51: SFP EEPROM */
+};
+
+/* X4 */
+&lpspi4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpspi4>;
+ cs-gpios = <&gpio5 13 GPIO_ACTIVE_LOW>, <&gpio5 14 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&lpuart1 {
+ /* console */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart1>;
+ status = "okay";
+};
+
+&lpuart2 {
+ /* SM */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart2>;
+ status = "reserved";
+};
+
+&lpuart5 {
+ /* X16 M.2 KEY E */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart5>;
+ status = "okay";
+};
+
+&lpuart7 {
+ /* X5 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart7>;
+ status = "okay";
+};
+
+&lpuart8 {
+ /* X15 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpuart8>;
+ linux,rs485-enabled-at-boot-time;
+ status = "okay";
+};
+
+&netc_blk_ctrl {
+ status = "okay";
+};
+
+&netc_emdio {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_emdio>;
+ status = "okay";
+
+ /* IRQ pin is AON GPIO, not usable */
+ ethphy0: ethernet-phy@0 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ reset-gpios = <&expander3 0 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <500000>;
+ reset-deassert-us = <50000>;
+ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+ ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+ ti,dp83867-rxctrl-strap-quirk;
+ ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ compatible = "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ethphy1>;
+ reset-gpios = <&expander3 1 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <500000>;
+ reset-deassert-us = <50000>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ ti,rx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+ ti,tx-internal-delay = <DP83867_RGMIIDCTL_2_50_NS>;
+ ti,fifo-depth = <DP83867_PHYCR_FIFO_DEPTH_4_B_NIB>;
+ ti,dp83867-rxctrl-strap-quirk;
+ ti,clk-output-sel = <DP83867_CLK_O_SEL_OFF>;
+ };
+};
+
+&netc_timer {
+ status = "okay";
+};
+
+&netcmix_blk_ctrl {
+ status = "okay";
+};
+
+/* X16 M2 / E-Key mPCIe */
+&pcie0 {
+ pinctrl-0 = <&pinctrl_pcie0>;
+ pinctrl-names = "default";
+ clocks = <&scmi_clk IMX95_CLK_HSIO>,
+ <&scmi_clk IMX95_CLK_HSIOPLL>,
+ <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
+ <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
+ <&pcieclk 1>;
+ clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
+ reset-gpios = <&expander2 8 GPIO_ACTIVE_LOW>;
+ /* Not supported on REV.0100 */
+ /* supports-clkreq; */
+ status = "okay";
+};
+
+/* X17 M2 / B-Key PCIe */
+&pcie1 {
+ pinctrl-0 = <&pinctrl_pcie1>;
+ pinctrl-names = "default";
+ clocks = <&scmi_clk IMX95_CLK_HSIO>,
+ <&scmi_clk IMX95_CLK_HSIOPLL>,
+ <&scmi_clk IMX95_CLK_HSIOPLL_VCO>,
+ <&scmi_clk IMX95_CLK_HSIOPCIEAUX>,
+ <&pcieclk 0>;
+ clock-names = "pcie", "pcie_bus", "pcie_phy", "pcie_aux", "ref";
+ reset-gpios = <&expander2 11 GPIO_ACTIVE_LOW>;
+ /* Not supported on REV.0100 */
+ /* supports-clkreq; */
+ status = "okay";
+};
+
+®_sdvmmc {
+ status = "okay";
+};
+
+&sai3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sai3>;
+ assigned-clocks = <&scmi_clk IMX95_CLK_AUDIOPLL1_VCO>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL2_VCO>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL1>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL2>,
+ <&scmi_clk IMX95_CLK_SAI3>;
+ assigned-clock-parents = <0>, <0>, <0>, <0>,
+ <&scmi_clk IMX95_CLK_AUDIOPLL1>;
+ assigned-clock-rates = <3932160000>,
+ <3612672000>, <393216000>,
+ <361267200>, <12288000>;
+ fsl,sai-mclk-direction-output;
+ status = "okay";
+};
+
+&scmi_bbm {
+ linux,code = <KEY_POWER>;
+};
+
+&thermal_zones {
+ a55-thermal {
+ trips {
+ cpu_active0: trip-active0 {
+ temperature = <40000>;
+ hysteresis = <5000>;
+ type = "active";
+ };
+
+ cpu_active1: trip-active1 {
+ temperature = <48000>;
+ hysteresis = <3000>;
+ type = "active";
+ };
+
+ cpu_active2: trip-active2 {
+ temperature = <60000>;
+ hysteresis = <10000>;
+ type = "active";
+ };
+ };
+
+ cooling-maps {
+ map1 {
+ trip = <&cpu_active0>;
+ cooling-device = <&fan 0 2>;
+ };
+
+ map2 {
+ trip = <&cpu_active1>;
+ cooling-device = <&fan 3 5>;
+ };
+
+ map3 {
+ trip = <&cpu_active2>;
+ cooling-device = <&fan 6 10>;
+ };
+ };
+ };
+};
+
+&tpm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tpm3>;
+ status = "okay";
+};
+
+&tpm5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tpm5>;
+};
+
+&usb2 {
+ dr_mode = "otg";
+ hnp-disable;
+ srp-disable;
+ adp-disable;
+ usb-role-switch;
+ disable-over-current;
+ samsung,picophy-pre-emp-curr-control = <3>;
+ samsung,picophy-dc-vol-level-adjust = <7>;
+ status = "okay";
+
+ port {
+ typec_hs: endpoint {
+ remote-endpoint = <&typec_con_hs>;
+ };
+ };
+};
+
+&usb3 {
+ status = "okay";
+};
+
+&usb3_dwc3 {
+ dr_mode = "host";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ hub_2_0: hub@1 {
+ compatible = "usb451,8142";
+ reg = <1>;
+ peer-hub = <&hub_3_0>;
+ reset-gpios = <&expander2 3 GPIO_ACTIVE_LOW>;
+ vdd-supply = <®_v3v3_mb>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hub_2_1: hub@1 {
+ compatible = "usb424,2514";
+ reg = <1>;
+ reset-gpios = <&expander2 4 GPIO_ACTIVE_LOW>;
+ vdd-supply = <®_v3v3_mb>;
+ vdda-supply = <®_v3v3_mb>;
+ };
+ };
+
+ hub_3_0: hub@2 {
+ compatible = "usb451,8140";
+ reg = <2>;
+ peer-hub = <&hub_2_0>;
+ reset-gpios = <&expander2 3 GPIO_ACTIVE_LOW>;
+ vdd-supply = <®_v3v3_mb>;
+ };
+};
+
+&usb3_phy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb3>;
+ vbus-supply = <®_vbus_usb3>;
+ status = "okay";
+};
+
+/* X7 µSD */
+&usdhc2 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ pinctrl-1 = <&pinctrl_usdhc2_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc2_200mhz>;
+ vmmc-supply = <®_sdvmmc>;
+ cd-gpios = <&gpio3 0 GPIO_ACTIVE_LOW>;
+ no-mmc;
+ no-sdio;
+ disable-wp;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&scmi_iomuxc {
+ pinctrl_enetc0: enetc0grp {
+ fsl,pins = <IMX95_PAD_ENET1_RD0__NETCMIX_TOP_ETH0_RGMII_RD0 0x1100>,
+ <IMX95_PAD_ENET1_RD1__NETCMIX_TOP_ETH0_RGMII_RD1 0x1100>,
+ <IMX95_PAD_ENET1_RD2__NETCMIX_TOP_ETH0_RGMII_RD2 0x1100>,
+ <IMX95_PAD_ENET1_RD3__NETCMIX_TOP_ETH0_RGMII_RD3 0x1100>,
+ <IMX95_PAD_ENET1_RXC__NETCMIX_TOP_ETH0_RGMII_RX_CLK 0x1100>,
+ <IMX95_PAD_ENET1_RX_CTL__NETCMIX_TOP_ETH0_RGMII_RX_CTL 0x1100>,
+ <IMX95_PAD_ENET1_TD0__NETCMIX_TOP_ETH0_RGMII_TD0 0x11e>,
+ <IMX95_PAD_ENET1_TD1__NETCMIX_TOP_ETH0_RGMII_TD1 0x11e>,
+ <IMX95_PAD_ENET1_TD2__NETCMIX_TOP_ETH0_RGMII_TD2 0x11e>,
+ <IMX95_PAD_ENET1_TD3__NETCMIX_TOP_ETH0_RGMII_TD3 0x11e>,
+ <IMX95_PAD_ENET1_TXC__NETCMIX_TOP_ETH0_RGMII_TX_CLK 0x11e>,
+ <IMX95_PAD_ENET1_TX_CTL__NETCMIX_TOP_ETH0_RGMII_TX_CTL 0x11e>;
+ };
+
+ pinctrl_enetc1: enetc1grp {
+ fsl,pins = <IMX95_PAD_ENET2_RD0__NETCMIX_TOP_ETH1_RGMII_RD0 0x1100>,
+ <IMX95_PAD_ENET2_RD1__NETCMIX_TOP_ETH1_RGMII_RD1 0x1100>,
+ <IMX95_PAD_ENET2_RD2__NETCMIX_TOP_ETH1_RGMII_RD2 0x1100>,
+ <IMX95_PAD_ENET2_RD3__NETCMIX_TOP_ETH1_RGMII_RD3 0x1100>,
+ <IMX95_PAD_ENET2_RXC__NETCMIX_TOP_ETH1_RGMII_RX_CLK 0x1100>,
+ <IMX95_PAD_ENET2_RX_CTL__NETCMIX_TOP_ETH1_RGMII_RX_CTL 0x1100>,
+ <IMX95_PAD_ENET2_TD0__NETCMIX_TOP_ETH1_RGMII_TD0 0x11e>,
+ <IMX95_PAD_ENET2_TD1__NETCMIX_TOP_ETH1_RGMII_TD1 0x11e>,
+ <IMX95_PAD_ENET2_TD2__NETCMIX_TOP_ETH1_RGMII_TD2 0x11e>,
+ <IMX95_PAD_ENET2_TD3__NETCMIX_TOP_ETH1_RGMII_TD3 0x11e>,
+ <IMX95_PAD_ENET2_TXC__NETCMIX_TOP_ETH1_RGMII_TX_CLK 0x11e>,
+ <IMX95_PAD_ENET2_TX_CTL__NETCMIX_TOP_ETH1_RGMII_TX_CTL 0x11e>;
+ };
+
+ pinctrl_ethphy0: ethphy0grp {
+ fsl,pins = <IMX95_PAD_PDM_BIT_STREAM0__AONMIX_TOP_GPIO1_IO_BIT9 0x1100>;
+ };
+
+ pinctrl_ethphy1: ethphy1grp {
+ fsl,pins = <IMX95_PAD_ENET1_MDC__GPIO4_IO_BIT0 0x1100>;
+ };
+
+ pinctrl_expander1: expander1grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO14__GPIO2_IO_BIT14 0x1100>;
+ };
+
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <IMX95_PAD_SAI1_TXC__AONMIX_TOP_CAN1_RX 0x1300>,
+ <IMX95_PAD_SAI1_TXD0__AONMIX_TOP_CAN1_TX 0x31e>;
+ };
+
+ pinctrl_flexcan2: flexcan2grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO25__CAN2_TX 0x31e>,
+ <IMX95_PAD_GPIO_IO27__CAN2_RX 0x1300>;
+ };
+
+ pinctrl_lpi2c7: lpi2c7grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO07__LPI2C7_SCL 0x40001b1e>,
+ <IMX95_PAD_GPIO_IO06__LPI2C7_SDA 0x40001b1e>;
+ };
+
+ pinctrl_lpi2c7_recovery: lpi2c7recoverygrp {
+ fsl,pins = <IMX95_PAD_GPIO_IO07__GPIO2_IO_BIT7 0x40001b1e>,
+ <IMX95_PAD_GPIO_IO06__GPIO2_IO_BIT6 0x40001b1e>;
+ };
+
+ pinctrl_lpspi4: lpspi4grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO37__LPSPI4_SCK 0x91e>,
+ <IMX95_PAD_GPIO_IO19__LPSPI5_SIN 0x191e>,
+ <IMX95_PAD_GPIO_IO36__LPSPI4_SOUT 0x91e>,
+ <IMX95_PAD_GPIO_IO34__GPIO5_IO_BIT14 0x91e>,
+ <IMX95_PAD_GPIO_IO33__GPIO5_IO_BIT13 0x91e>;
+ };
+
+ pinctrl_lpuart1: lpuart1grp {
+ fsl,pins = <IMX95_PAD_UART1_TXD__AONMIX_TOP_LPUART1_TX 0x31e>,
+ <IMX95_PAD_UART1_RXD__AONMIX_TOP_LPUART1_RX 0x1300>;
+ };
+
+ pinctrl_lpuart2: lpuart2grp {
+ fsl,pins = <IMX95_PAD_UART2_TXD__AONMIX_TOP_LPUART2_TX 0x31e>,
+ <IMX95_PAD_UART2_RXD__AONMIX_TOP_LPUART2_RX 0x1300>;
+ };
+
+ pinctrl_lpuart5: lpuart5grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO00__LPUART5_TX 0x31e>,
+ <IMX95_PAD_GPIO_IO01__LPUART5_RX 0x1300>,
+ <IMX95_PAD_GPIO_IO02__LPUART5_CTS_B 0x1300>,
+ <IMX95_PAD_GPIO_IO03__LPUART5_RTS_B 0x31e>;
+ };
+
+ pinctrl_lpuart7: lpuart7grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO08__LPUART7_TX 0x31e>,
+ <IMX95_PAD_GPIO_IO09__LPUART7_RX 0x1300>,
+ <IMX95_PAD_GPIO_IO10__LPUART7_CTS_B 0x1300>,
+ <IMX95_PAD_GPIO_IO11__LPUART7_RTS_B 0x31e>;
+ };
+
+ pinctrl_lpuart8: lpuart8grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO12__LPUART8_TX 0x31e>,
+ <IMX95_PAD_GPIO_IO13__LPUART8_RX 0x1300>,
+ <IMX95_PAD_GPIO_IO15__LPUART8_RTS_B 0x31e>;
+ };
+
+ pinctrl_emdio: emdiogrp {
+ fsl,pins = <IMX95_PAD_ENET2_MDC__NETCMIX_TOP_NETC_MDC 0x51e>,
+ <IMX95_PAD_ENET2_MDIO__NETCMIX_TOP_NETC_MDIO 0x51e>;
+ };
+
+ pinctrl_pcie0: pcie0grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO32__HSIOMIX_TOP_PCIE1_CLKREQ_B 0x111e>;
+ };
+
+ pinctrl_pcie1: pcie1grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO35__HSIOMIX_TOP_PCIE2_CLKREQ_B 0x111e>;
+ };
+
+ pinctrl_sai3: sai3grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO16__SAI3_TX_BCLK 0x51e>,
+ <IMX95_PAD_GPIO_IO17__SAI3_MCLK 0x51e>,
+ <IMX95_PAD_GPIO_IO20__SAI3_RX_DATA_BIT0 0x1300>,
+ <IMX95_PAD_GPIO_IO21__SAI3_TX_DATA_BIT0 0x51e>,
+ <IMX95_PAD_GPIO_IO26__SAI3_TX_SYNC 0x51e>;
+ };
+
+ pinctrl_retimer: retirmergrp {
+ fsl,pins = <IMX95_PAD_GPIO_IO29__GPIO2_IO_BIT29 0x1100>;
+ };
+
+ pinctrl_sfp: sfpgrp {
+ fsl,pins = <IMX95_PAD_GPIO_IO30__GPIO2_IO_BIT30 0x1100>,
+ <IMX95_PAD_GPIO_IO31__GPIO2_IO_BIT31 0x1100>;
+ };
+
+ pinctrl_tpm3: tpm3grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO24__TPM3_CH3 0x51e>;
+ };
+
+ pinctrl_tpm5: tpm5grp {
+ fsl,pins = <IMX95_PAD_GPIO_IO18__TPM5_CH2 0x51e>;
+ };
+
+ pinctrl_typec: typcegrp {
+ fsl,pins = <IMX95_PAD_GPIO_IO28__GPIO2_IO_BIT28 0x1100>;
+ };
+
+ pinctrl_usb3: usb3grp {
+ fsl,pins = <IMX95_PAD_ENET1_MDIO__GPIO4_IO_BIT1 0x31e>;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0 0x1100>,
+ <IMX95_PAD_SD2_CLK__USDHC2_CLK 0x51e>,
+ <IMX95_PAD_SD2_CMD__USDHC2_CMD 0x31e>,
+ <IMX95_PAD_SD2_DATA0__USDHC2_DATA0 0x131e>,
+ <IMX95_PAD_SD2_DATA1__USDHC2_DATA1 0x131e>,
+ <IMX95_PAD_SD2_DATA2__USDHC2_DATA2 0x131e>,
+ <IMX95_PAD_SD2_DATA3__USDHC2_DATA3 0x131e>,
+ <IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e>;
+ };
+
+ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+ fsl,pins = <IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0 0x1100>,
+ <IMX95_PAD_SD2_CLK__USDHC2_CLK 0x58e>,
+ <IMX95_PAD_SD2_CMD__USDHC2_CMD 0x38e>,
+ <IMX95_PAD_SD2_DATA0__USDHC2_DATA0 0x138e>,
+ <IMX95_PAD_SD2_DATA1__USDHC2_DATA1 0x138e>,
+ <IMX95_PAD_SD2_DATA2__USDHC2_DATA2 0x138e>,
+ <IMX95_PAD_SD2_DATA3__USDHC2_DATA3 0x138e>,
+ <IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e>;
+ };
+
+ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+ fsl,pins = <IMX95_PAD_SD2_CD_B__GPIO3_IO_BIT0 0x1100>,
+ <IMX95_PAD_SD2_CLK__USDHC2_CLK 0x5fe>,
+ <IMX95_PAD_SD2_CMD__USDHC2_CMD 0x3fe>,
+ <IMX95_PAD_SD2_DATA0__USDHC2_DATA0 0x13fe>,
+ <IMX95_PAD_SD2_DATA1__USDHC2_DATA1 0x13fe>,
+ <IMX95_PAD_SD2_DATA2__USDHC2_DATA2 0x13fe>,
+ <IMX95_PAD_SD2_DATA3__USDHC2_DATA3 0x13fe>,
+ <IMX95_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e>;
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/imx95-tqma9596la.dtsi b/arch/arm64/boot/dts/freescale/imx95-tqma9596la.dtsi
new file mode 100644
index 0000000000000..cc572171bf253
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/imx95-tqma9596la.dtsi
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: (GPL-2.0-or-later OR MIT)
+/*
+ * Copyright (c) 2024-2026 TQ-Systems GmbH <linux@ew.tq-group.com>,
+ * D-82229 Seefeld, Germany.
+ * Author: Alexander Stein
+ * Author: Markus Niebel
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "imx95.dtsi"
+
+/ {
+ memory@80000000 {
+ device_type = "memory";
+ /*
+ * DRAM base addr, size : 2048 MiB DRAM
+ * should be corrected by bootloader
+ */
+ reg = <0 0x80000000 0 0x80000000>;
+ };
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ linux_cma: linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ size = <0 0x28000000>;
+ alloc-ranges = <0 0x80000000 0 0x80000000>;
+ linux,cma-default;
+ };
+
+ vpu_boot: vpu_boot@a0000000 {
+ reg = <0 0xa0000000 0 0x100000>;
+ no-map;
+ };
+ };
+
+ reg_1v8: regulator-1v8 {
+ compatible = "regulator-fixed";
+ regulator-name = "V_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ reg_3v3: regulator-3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "V_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_sdvmmc: regulator-sdvmmc {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sdvmmc>;
+ regulator-name = "SD_PWR_EN";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
+ off-on-delay-us = <12000>;
+ enable-active-high;
+ /* can be enabled by mainboard with SD-Card support */
+ status = "disabled";
+ };
+};
+
+&adc1 {
+ vref-supply = <®_1v8>;
+};
+
+&flexspi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexspi1>;
+ status = "okay";
+
+ flash0: flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <66000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ vcc-supply = <®_1v8>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+ };
+};
+
+/* System Manager */
+&gpio1 {
+ status = "reserved";
+};
+
+/* System Manager */
+&lpi2c1 {
+ status = "reserved";
+};
+
+&lpi2c2 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lpi2c2>;
+ status = "okay";
+
+ pcf85063: rtc@51 {
+ compatible = "nxp,pcf85063a";
+ reg = <0x51>;
+ quartz-load-femtofarads = <7000>;
+ };
+
+ m24c64: eeprom@54 {
+ compatible = "atmel,24c64";
+ reg = <0x54>;
+ pagesize = <32>;
+ vcc-supply = <®_3v3>;
+ };
+
+ /* protectable identification memory (part of M24C64-D @54) */
+ eeprom@5c {
+ compatible = "atmel,24c64d-wl";
+ reg = <0x5c>;
+ pagesize = <32>;
+ vcc-supply = <®_3v3>;
+ };
+
+ imu@6b {
+ compatible = "st,ism330dhcx";
+ reg = <0x6b>;
+ vdd-supply = <®_3v3>;
+ vddio-supply = <®_3v3>;
+ };
+};
+
+&thermal_zones {
+ pf09-thermal {
+ polling-delay = <2000>;
+ polling-delay-passive = <250>;
+ thermal-sensors = <&scmi_sensor 2>;
+
+ trips {
+ pf09_alert: trip0 {
+ hysteresis = <2000>;
+ temperature = <140000>;
+ type = "passive";
+ };
+
+ pf09_crit: trip1 {
+ hysteresis = <2000>;
+ temperature = <155000>;
+ type = "critical";
+ };
+ };
+ };
+
+ pf53arm-thermal {
+ polling-delay = <2000>;
+ polling-delay-passive = <250>;
+ thermal-sensors = <&scmi_sensor 4>;
+
+ cooling-maps {
+ map0 {
+ trip = <&pf5301_alert>;
+ cooling-device =
+ <&A55_0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A55_1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A55_2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A55_3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A55_4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+ <&A55_5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+
+ trips {
+ pf5301_alert: trip0 {
+ hysteresis = <2000>;
+ temperature = <140000>;
+ type = "passive";
+ };
+
+ pf5301_crit: trip1 {
+ hysteresis = <2000>;
+ temperature = <155000>;
+ type = "critical";
+ };
+ };
+ };
+
+ pf53soc-thermal {
+ polling-delay = <2000>;
+ polling-delay-passive = <250>;
+ thermal-sensors = <&scmi_sensor 3>;
+
+ trips {
+ pf5302_alert: trip0 {
+ hysteresis = <2000>;
+ temperature = <140000>;
+ type = "passive";
+ };
+
+ pf5302_crit: trip1 {
+ hysteresis = <2000>;
+ temperature = <155000>;
+ type = "critical";
+ };
+ };
+ };
+};
+
+&usdhc1 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc1>;
+ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
+ bus-width = <8>;
+ non-removable;
+ no-sdio;
+ no-sd;
+ status = "okay";
+};
+
+&wdog3 {
+ status = "okay";
+};
+
+&scmi_iomuxc {
+ pinctrl_flexspi1: flexspi1grp {
+ fsl,pins = <IMX95_PAD_XSPI1_SS0_B__FLEXSPI1_A_SS0_B 0x19e>,
+ <IMX95_PAD_XSPI1_DATA0__FLEXSPI1_A_DATA_BIT0 0x19e>,
+ <IMX95_PAD_XSPI1_DATA1__FLEXSPI1_A_DATA_BIT1 0x19e>,
+ <IMX95_PAD_XSPI1_DATA2__FLEXSPI1_A_DATA_BIT2 0x19e>,
+ <IMX95_PAD_XSPI1_DATA3__FLEXSPI1_A_DATA_BIT3 0x19e>,
+ /* SION to allow clock loopback from pad */
+ <IMX95_PAD_XSPI1_SCLK__FLEXSPI1_A_SCLK 0x4000019e>,
+ <IMX95_PAD_XSPI1_DQS__FLEXSPI1_A_DQS 0x4000019e>;
+ };
+
+ pinctrl_lpi2c2: lpi2c2grp {
+ fsl,pins = <IMX95_PAD_I2C2_SCL__AONMIX_TOP_LPI2C2_SCL 0x4000191e>,
+ <IMX95_PAD_I2C2_SDA__AONMIX_TOP_LPI2C2_SDA 0x4000191e>;
+ };
+
+ pinctrl_sdvmmc: sdvmmcgrp {
+ fsl,pins = <IMX95_PAD_SD2_RESET_B__GPIO3_IO_BIT7 0x11e>;
+ };
+
+ pinctrl_usdhc1: usdhc1grp {
+ fsl,pins = <IMX95_PAD_SD1_CLK__USDHC1_CLK 0x158e>,
+ <IMX95_PAD_SD1_CMD__USDHC1_CMD 0x138e>,
+ <IMX95_PAD_SD1_DATA0__USDHC1_DATA0 0x138e>,
+ <IMX95_PAD_SD1_DATA1__USDHC1_DATA1 0x138e>,
+ <IMX95_PAD_SD1_DATA2__USDHC1_DATA2 0x138e>,
+ <IMX95_PAD_SD1_DATA3__USDHC1_DATA3 0x138e>,
+ <IMX95_PAD_SD1_DATA4__USDHC1_DATA4 0x138e>,
+ <IMX95_PAD_SD1_DATA5__USDHC1_DATA5 0x138e>,
+ <IMX95_PAD_SD1_DATA6__USDHC1_DATA6 0x138e>,
+ <IMX95_PAD_SD1_DATA7__USDHC1_DATA7 0x138e>,
+ <IMX95_PAD_SD1_STROBE__USDHC1_STROBE 0x158e>;
+ };
+
+ pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
+ fsl,pins = <IMX95_PAD_SD1_CLK__USDHC1_CLK 0x158e>,
+ <IMX95_PAD_SD1_CMD__USDHC1_CMD 0x138e>,
+ <IMX95_PAD_SD1_DATA0__USDHC1_DATA0 0x138e>,
+ <IMX95_PAD_SD1_DATA1__USDHC1_DATA1 0x138e>,
+ <IMX95_PAD_SD1_DATA2__USDHC1_DATA2 0x138e>,
+ <IMX95_PAD_SD1_DATA3__USDHC1_DATA3 0x138e>,
+ <IMX95_PAD_SD1_DATA4__USDHC1_DATA4 0x138e>,
+ <IMX95_PAD_SD1_DATA5__USDHC1_DATA5 0x138e>,
+ <IMX95_PAD_SD1_DATA6__USDHC1_DATA6 0x138e>,
+ <IMX95_PAD_SD1_DATA7__USDHC1_DATA7 0x138e>,
+ <IMX95_PAD_SD1_STROBE__USDHC1_STROBE 0x158e>;
+ };
+
+ pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
+ fsl,pins = <IMX95_PAD_SD1_CLK__USDHC1_CLK 0x15fe>,
+ <IMX95_PAD_SD1_CMD__USDHC1_CMD 0x13fe>,
+ <IMX95_PAD_SD1_DATA0__USDHC1_DATA0 0x13fe>,
+ <IMX95_PAD_SD1_DATA1__USDHC1_DATA1 0x13fe>,
+ <IMX95_PAD_SD1_DATA2__USDHC1_DATA2 0x13fe>,
+ <IMX95_PAD_SD1_DATA3__USDHC1_DATA3 0x13fe>,
+ <IMX95_PAD_SD1_DATA4__USDHC1_DATA4 0x13fe>,
+ <IMX95_PAD_SD1_DATA5__USDHC1_DATA5 0x13fe>,
+ <IMX95_PAD_SD1_DATA6__USDHC1_DATA6 0x13fe>,
+ <IMX95_PAD_SD1_DATA7__USDHC1_DATA7 0x13fe>,
+ <IMX95_PAD_SD1_STROBE__USDHC1_STROBE 0x15fe>;
+ };
+};
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 0/2] mmc: hisilicon: Convert dw-mshc bindings and fix dtbs
From: Wei Xu @ 2026-03-26 11:19 UTC (permalink / raw)
To: Bhargav Joshi, devicetree, linux-arm-kernel, robh, krzk+dt,
conor+dt, ulf.hansson, zhangfei.gao, linux-mmc
Cc: daniel.baluta, simona.toaca, d-gole, m-chawdhry, linux-kernel,
xuwei5
In-Reply-To: <20260325225439.68161-1-rougueprince47@gmail.com>
Hi Bhargav,
On 2026/3/26 6:54, Bhargav Joshi wrote:
> This series converts the Hisilicon dw-mshc text bindings to DT schema
> format and cleans up legacy node names in Hisilicon board files.
>
> While testing the new YAML schema, dtbs_check flagged the hi3660,
> hi3670, and hi6220 SoC files for using the non-standard 'dwmmc' node
> name prefix. resulting in warnings.
>
> Patch 1 Convert to DT schema
> Patch 2 updates the Hisilicon dtsi files to use standard 'mmc'
> node name.
>
> Changes in v2:
> - Patch 1:
> - Grouped compatible strings into an enum.
> - Replaced raw numbers with proper flags.
> - Fixed property order and removed invalid hex values.
> - Added explanation for clock order change in commit message.
> - Collected Acked-by tag.
> - Patch 2:
> - No code changes.
> - Collected Acked-by and Reviewed-by tags.
>
> Signed-off-by: Bhargav Joshi <rougueprince47@gmail.com>
> ---
> Note: this patch is part of the process for applying to GSoC device
> tree bindings conversion project #
> https://github.com/LinuxFoundationGSoC/ProjectIdeas/wiki/GSoC-2026-Device-Tree-Bindings
>
> - The file is enabled by arm64 defconfig (CONFIG_MMC_DW_K3=y)
> - It is used in following
> /arch/arm64/boot/dts/hisilicon/hi3660.dtsi
> -included by /arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts
> /arch/arm64/boot/dts/hisilicon/hi3670.dtsi
> -included by /arch/arm64/boot/dts/hisilicon/hi3670-hikey970.dts
>
> Bhargav Joshi (2):
> dt-bindings: mmc: hisilicon,hi3660-dw-mshc: Convert to DT schema
> arm64: dts: hisilicon: Rename dwmmc nodes to mmc
>
> .../mmc/hisilicon,hi3660-dw-mshc.yaml | 117 ++++++++++++++++++
> .../devicetree/bindings/mmc/k3-dw-mshc.txt | 73 -----------
> arch/arm64/boot/dts/hisilicon/hi3660.dtsi | 4 +-
> arch/arm64/boot/dts/hisilicon/hi3670.dtsi | 4 +-
> arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 6 +-
> 5 files changed, 124 insertions(+), 80 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/mmc/hisilicon,hi3660-dw-mshc.yaml
> delete mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt
>
Series applied to the HiSilicon arm64 dt tree.
Thanks!
Best Regards,
Wei
^ permalink raw reply
* Re: [PATCH v13 00/48] arm64: Support for Arm CCA in KVM
From: Suzuki K Poulose @ 2026-03-26 11:22 UTC (permalink / raw)
To: Gavin Shan, Steven Price, Mathieu Poirier
Cc: kvm, kvmarm, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Zenghui Yu, linux-arm-kernel,
linux-kernel, Joey Gouly, Alexandru Elisei, Christoffer Dall,
Fuad Tabba, linux-coco, Ganapatrao Kulkarni, Shanker Donthineni,
Alper Gun, Aneesh Kumar K . V, Emi Kisanuki, Vishal Annapurve
In-Reply-To: <807b844c-32f6-4094-8c24-15d7eb1d3638@redhat.com>
Hi Gavin,
On 26/03/2026 00:48, Gavin Shan wrote:
> Hi Suzuki,
>
> On 3/25/26 8:16 PM, Suzuki K Poulose wrote:
>> On 25/03/2026 06:37, Gavin Shan wrote:
>>> On 3/21/26 2:45 AM, Steven Price wrote:
>
> [...]
>
>>>
>>> In upstream TF-A repository [1], I don't see the config option
>>> 'RMM_V1_COMPAT'.
>>> would it be something else?
>>>
>>> [1] git@github.com:ARM-software/arm-trusted-firmware.git (branch:
>>> master)
>>>
>>
>> suzuki@ewhatever:trusted-firmware-a$ git grep RMM_V1_COMPAT
>> Makefile: RMM_V1_COMPAT \
>> Makefile: RMM_V1_COMPAT \
>> docs/getting_started/build-options.rst:- ``RMM_V1_COMPAT``: Boolean
>> flag to enable support for RMM v1.x compatibility
>> include/services/rmmd_svc.h:#if RMM_V1_COMPAT
>> include/services/rmmd_svc.h:#endif /* RMM_V1_COMPAT */
>> make_helpers/defaults.mk:RMM_V1_COMPAT := 1
>> services/std_svc/rmmd/rmmd_main.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_main.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_main.c:#if !RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_main.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_main.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_main.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_rmm_lfa.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_rmm_lfa.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_rmm_lfa.c:#if RMM_V1_COMPAT
>> services/std_svc/rmmd/rmmd_rmm_lfa.c:#if RMM_V1_COMPAT
>> suzuki@ewhatever:trusted-firmware-a$ git log --oneline -1
>> 8dae0862c (HEAD, origin/master, origin/integration, origin/HEAD) Merge
>> changes from topic "qti_lemans_evk" into integration
>> suzuki@ewhatever:trusted-firmware-a$ git remote get-url origin
>> https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
>>
>
> Thanks for the details. It turned out that I used the wrong TF-A
> repository. In
> the proposed repository, I'm able to see the option 'RMM_V1_COMPAT' and
> the EL3-RMM
> interface compatible issue disappears. However, there are more issues
> popped up.
>
> I build everything manually where the host is emulated by QEMU instead
> of shrinkwrap
> and FVP model. It's used to work well before. Maybe it's time to switch
> to shinkwrap
> and FVP model since device assignment (DA) isn't supported by an
> emulated host
> by QEMU and shrinkwrap and FVP model seems the only option. I need to
> learn how
> to do that later.
Thanks for the update. Yes, QEMU TF-RMM support is in progress, @Mathieu
Poirier is looking into it
>
> There are two issues I can see with the following combinations. Details
> are provided
> like below.
>
> QEMU: https://git.qemu.org/git/
> qemu.git (branch: stable-9.2)
> TF-RMM: https://git.trustedfirmware.org/TF-RMM/tf-
> rmm.git (branch: topics/rmm-v2.0-poc)
> EDK2: git@github.com:tianocore/
> edk2.git (tag: edk2-stable202411)
> TF-A: https://git.trustedfirmware.org/TF-A/trusted-firmware-
> a.git (branch: master)
> HOST: https://git.gitlab.arm.com/linux-arm/linux-
> cca.git (branch: cca-host/v13)
> BUILDROOT: https://github.com/buildroot/
> buildroot (branch: master)
> KVMTOOL: https://gitlab.arm.com/linux-arm/kvmtool-
> cca (branch: cca/v11)
> GUEST: https://github.com/torvalds/
> linux.git (branch: master)
>
> (1) The emulated host is started by the following command lines.
>
> sudo /home/gshan/sandbox/cca/host/qemu/build/qemu-system-
> aarch64 \
> -M virt,virtualization=on,secure=on,gic-
> version=3,acpi=off \
> -cpu max,x-rme=on -m 8G -smp
> 8 \
> -serial mon:stdio -monitor none -nographic -
> nodefaults \
> -bios /home/gshan/sandbox/cca/host/tf-a/
> flash.bin \
> -kernel /home/gshan/sandbox/cca/host/linux/arch/arm64/boot/
> Image \
> -initrd /home/gshan/sandbox/cca/host/buildroot/output/images/
> rootfs.cpio.xz \
> -device pcie-root-
> port,bus=pcie.0,chassis=1,id=pcie.1 \
> -device pcie-root-
> port,bus=pcie.0,chassis=2,id=pcie.2 \
> -device pcie-root-
> port,bus=pcie.0,chassis=3,id=pcie.3 \
> -device pcie-root-
> port,bus=pcie.0,chassis=4,id=pcie.4 \
> -device virtio-9p-
> device,fsdev=shr0,mount_tag=shr0 \
> -fsdev local,security_model=none,path=/home/gshan/sandbox/cca/
> guest,id=shr0 \
> -netdev tap,id=tap1,script=/etc/qemu-ifup-gshan,downscript=/etc/
> qemu-ifdown-gshan \
> -device virtio-net-pci,bus=pcie.2,netdev=tap1,mac=b8:3f:d2:1d:3e:f1
>
> (2) Issue-1: TF-RMM complains about the root complex list is invalid.
> This error is
> raised in TF-RMM::setup_root_complex_list() where the error code is
> still set to
> 0 (SUCCESS) in this failing case. The TF-RMM initialization is
> terminated early,
> but TF-A still thinks the initialization has been completely done.
>
> INFO: BL31: Initializing RMM
> INFO: RMM init start.
> RMM EL3 compat memory reservation enabled.
> Dynamic VA pool base address: 0xc0000000
> Reserved 20 pages. Remaining: 3615 pages
> Reserve mem: 20 pages at PA: 0x401f2000 (alignment 0x1000)
> Static Low VA initialized. xlat tables allocated: 20 used: 7
> Reserved 514 pages. Remaining: 3101 pages
> Reserve mem: 514 pages at PA: 0x40206000 (alignment 0x1000)
> Dynamic Low VA initialized. xlat tables allocated: 514 used: 514
> Invalid: Root Complex list
> <<<<< ERROR
> INFO: RMM init end.
>
> (3) Issue-2: The host kernel gets stuck in rmi_check_version() where
> SMC_RMI_VERSION
> is issued to TF-A, but it can't be forwarded to TF-RMM because its
> initialization
> isn't completely done (issue-1).
>
> [ 37.438253] Unpacking initramfs...
> [ 37.563460] kvm [1]: nv: 570 coarse grained trap handlers
> [ 37.581139] kvm [1]: nv: 664 fine grained trap handlers
> <... system becomes stuck here ...>
>
> So my workaround is to skip fetching root complex list from the EL3-RMM
> manifest data
> in TF-RMM::setup_root_complex_list() since it's not provided for the
> qemu platform by
^^ This may have to do with the RMM<->TF-A Manifest changes
> TF-A. With this workaround, the host can boot up into shell prompt and
> the guest can
> be started by kvmtool.
>
> host$ uname -r
> 7.0.0-rc1-gavin-gd62aa44b2590
> host$ lkvm run --realm -c 2 -m 256 \
> -k /mnt/linux/arch/arm64/boot/Image \
> -i /mnt/buildroot/output/images/rootfs.cpio.xz
> -p earlycon=uart,mmio,0x101000000
> Info: # lkvm run -k /mnt/linux/arch/arm64/boot/Image -m 256 -c 2 --
> name guest-163
> Info: Enabling Guest memfd for confidential guest
> Warning: The maximum recommended amount of VCPUs is 1
> [ 0.000000] Booting Linux on physical CPU 0x0000000000 [0x000f0510]
> [ 0.000000] Linux version 7.0.0-rc2-gavin-g0031c06807cf
> (gshan@nvidia-grace-hopper-01.khw.eng.bos2.dc.redhat.com) (gcc (GCC)
> 14.3.1 20251022 (Red Hat 14.3.1-4), GNU ld version 2.41-64.el10) #2 SMP
> PREEMPT Wed Mar 25 20:28:05 EDT 2026
> [ 0.000000] KASLR enabled
> :
> [ 267.578060] Freeing initrd memory: 4728K
> [ 267.921865] Warning: unable to open an initial console.
> [ 270.327960] Freeing unused kernel memory: 1792K
> [ 270.669368] Run /init as init process
>
Cool, thanks!
Suzuki
> Thanks,
> Gavin
>
^ permalink raw reply
* Re: [PATCH v4] arm64: dts: lx2160a: extend 32-bit, and add 16 & 64-bit pci regions
From: Josua Mayer @ 2026-03-26 11:26 UTC (permalink / raw)
To: Shawn Guo, Li Yang, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Rob Herring, Krzysztof Kozlowski, Frank Li
Cc: Yazan Shhady, Jon Nettleton, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <20260302-lx2160-pci-v4-1-30a30dc47ec6@solid-run.com>
Hi all,
This patch has never received a reply in versions v1, v2, v3 nor v4.
Is it on the wrong list? Should I be adding pci list?
Am 02.03.26 um 15:35 schrieb Josua Mayer:
> LX2160 SoC pci-e controller supports 64-bit memory regions up to 16GB,
> 32-bit regions up to 3GB and 16-bit regions up to 64k.
>
> For each pci-e controller:
> - extend the existing 32-bit regions to 3GB size
> - add 16-bit region
> - add 64-bit region
> See [1] amd [2] for boot messages showing ranges before and after.
>
> The 64-bit area flags are very particular:
> - IORESOURCE_AUTO: ensures of_bus_pci_get_flags sets prefetch flag
> (avoids "Memory resource size exceeds max for 32 bits" error during
> boot, generated by pci_parse_request_of_pci_ranges)
> - IORESOURCE_SYSRAM_DRIVER_MANAGED: ensures IORESOURCE_MEM flag is not
> cleared, as required by devm_of_pci_get_host_bridge_resources to print
> correct resource type during boot:
> MEM 0xa700000000..0xa7ffffffff -> 0xa700000000 (with this flag)
> err 0xa700000000..0xa7ffffffff -> 0xa700000000 (without)
> - IORESOURCE_MEM_64: pci address space is 64-bit
> - IORESOURCE_PREFETCH: is prefetchable
> - IORESOURCE_MEM: is memory (set implicitly when omitted in dts)
>
> IORESOURCE_BUSY is dropped since it has no effect when specified in dts.
>
> The 16GB 64-bit area is split into 4 pieces because the layerscape pcie
> driver fails to program atu for larger ranges [3].
>
> The range for 16-bit io window was defined by Jon Nettleton, and
> includes flag IORESOURCE_EXT_TYPE_BITS to support multiport io cards.
>
> Similar memory allocation with similar flags was tested with UEFI and ACPI
> on pcie3 and pcie5.
>
> This specific set of ranges was tested with nxp bsp versions lsdk-21.08,
> ls-5.15.71-2.2.0, ls-6.6.52-2.2.0, Debian 13 (v6.12.41), mainline v7.0-rc2,
> using u-boot:
> - pcie5 with a Radeon Pro WX2100 with Gnome Desktop
> - pcie3 with an ADATA NVME
>
> This fixes allocation of large, and 64-bit BARs as requested by many pci
> cards - especially graphics processors or AI accelerators, e.g.:
>
> [ 2.941187] pci 0000:01:00.0: BAR 0: no space for [mem size 0x200000000 64bit pref]
> [ 2.948834] pci 0000:01:00.0: BAR 0: failed to assign [mem size 0x200000000 64bit pref]
>
> [1] example of new allocations (pcie5):
> [ 1.716942] layerscape-pcie 3800000.pcie: host bridge /soc/pcie@3800000 ranges:
> [ 1.724261] layerscape-pcie 3800000.pcie: MEM 0xa700000000..0xa7ffffffff -> 0xa700000000
> [ 1.732795] layerscape-pcie 3800000.pcie: MEM 0xa600000000..0xa6ffffffff -> 0xa600000000
> [ 1.741325] layerscape-pcie 3800000.pcie: MEM 0xa500000000..0xa5ffffffff -> 0xa500000000
> [ 1.749861] layerscape-pcie 3800000.pcie: MEM 0xa400000000..0xa4ffffffff -> 0xa400000000
> [ 1.758389] layerscape-pcie 3800000.pcie: MEM 0xa040000000..0xa0ffffffff -> 0x0040000000
> [ 1.766915] layerscape-pcie 3800000.pcie: IO 0xa010000000..0xa01000ffff -> 0x0000000000
> [ 1.776141] layerscape-pcie 3800000.pcie: iATU: unroll F, 256 ob, 24 ib, align 4K, limit 4G
> [ 1.880382] layerscape-pcie 3800000.pcie: PCIe Gen.3 x8 link up
> [ 1.886349] layerscape-pcie 3800000.pcie: PCI host bridge to bus 0001:00
> [ 1.893046] pci_bus 0001:00: root bus resource [bus 00-ff]
> [ 1.898525] pci_bus 0001:00: root bus resource [mem 0xa700000000-0xa7ffffffff pref]
> [ 1.906174] pci_bus 0001:00: root bus resource [mem 0xa600000000-0xa6ffffffff pref]
> [ 1.913822] pci_bus 0001:00: root bus resource [mem 0xa500000000-0xa5ffffffff pref]
> [ 1.921471] pci_bus 0001:00: root bus resource [mem 0xa400000000-0xa4ffffffff pref]
> [ 1.929120] pci_bus 0001:00: root bus resource [mem 0xa040000000-0xa0ffffffff] (bus address [0x40000000-0xffffffff])
> [ 1.939633] pci_bus 0001:00: root bus resource [io 0x0000-0xffff]
> [ 1.945824] pci 0001:00:00.0: [1957:8d80] type 01 class 0x060400 PCIe Root Port
> [ 1.953146] pci 0001:00:00.0: PCI bridge to [bus 01-ff]
> [ 1.958369] pci 0001:00:00.0: bridge window [io 0x1000-0x1fff]
> [ 1.964456] pci 0001:00:00.0: bridge window [mem 0xa040000000-0xa0502fffff]
>
> [2] example of previous allocations (pcie5):
> [ 1.716744] layerscape-pcie 3800000.pcie: host bridge /soc/pcie@3800000 ranges:
> [ 1.724060] layerscape-pcie 3800000.pcie: MEM 0xa040000000..0xa07fffffff -> 0x0040000000
> [ 1.733277] layerscape-pcie 3800000.pcie: iATU: unroll F, 256 ob, 24 ib, align 4K, limit 4G
> [ 1.836220] layerscape-pcie 3800000.pcie: PCIe Gen.3 x8 link up
> [ 1.842186] layerscape-pcie 3800000.pcie: PCI host bridge to bus 0001:00
> [ 1.848883] pci_bus 0001:00: root bus resource [bus 00-ff]
> [ 1.854363] pci_bus 0001:00: root bus resource [mem 0xa040000000-0xa07fffffff] (bus address [0x40000000-0x7fffffff])
> [ 1.864892] pci 0001:00:00.0: [1957:8d80] type 01 class 0x060400 PCIe Root Port
> [ 1.872216] pci 0001:00:00.0: PCI bridge to [bus 01-ff]
> [ 1.877438] pci 0001:00:00.0: bridge window [io 0x1000-0x1fff]
> [ 1.883526] pci 0001:00:00.0: bridge window [mem 0xa040000000-0xa0502fffff]
>
> [3] error programming atu beyond 4GB:
> [ 1.716762] layerscape-pcie 3800000.pcie: host bridge /soc/pcie@3800000 ranges:
> [ 1.724080] layerscape-pcie 3800000.pcie: MEM 0xa400000000..0xa7ffffffff -> 0xa400000000
> [ 1.732615] layerscape-pcie 3800000.pcie: MEM 0xa040000000..0xa0ffffffff -> 0x0040000000
> [ 1.741142] layerscape-pcie 3800000.pcie: IO 0xa010000000..0xa01000ffff -> 0x0000000000
> [ 1.750379] layerscape-pcie 3800000.pcie: iATU: unroll F, 256 ob, 24 ib, align 4K, limit 4G
> [ 1.759089] layerscape-pcie 3800000.pcie: Failed to set MEM range [mem 0xa400000000-0xa7ffffffff flags 0x2200]
> [ 1.769089] layerscape-pcie 3800000.pcie: probe with driver layerscape-pcie failed with error -22
>
> Signed-off-by: Josua Mayer <josua@solid-run.com>
> ---
> Changes in v4
> - dropped accidentally added empty line at top of file:
> - actually drop RFC prefix
> - rebased on v7.0-rc1 and re-tested on v7.0-rc2
> - Link to v3: https://lore.kernel.org/r/20250907-lx2160-pci-v3-1-bb66cc41b8f9@solid-run.com
>
> Changes in v3:
> - dropped rfc label
> - adjusted flags
> - split 16GB area into 4x4GB sections.
> - enhance commit description with details explanation
> - Link to v2: https://lore.kernel.org/r/20240429-lx2160-pci-v2-1-1b94576d6263@solid-run.com
>
> Changes in v2:
> - adjusted flags to fix several errors during probe and bar allocation
> - explicitly tested with 2 pci cards on Debian (Linux 6.1)
> - still rfc because a limitation in designware pci driver
> - Link to v1: https://lore.kernel.org/r/20240321-lx2160-pci-v1-1-3673708f7eb6@solid-run.com
> ---
> arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi | 42 ++++++++++++++++++++++----
> 1 file changed, 36 insertions(+), 6 deletions(-)
>
> diff --git a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
> index 853b01452813a..5b48de0c853a8 100644
> --- a/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
> +++ b/arch/arm64/boot/dts/freescale/fsl-lx2160a.dtsi
> @@ -1185,7 +1185,12 @@ pcie1: pcie@3400000 {
> apio-wins = <8>;
> ppio-wins = <8>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0x80 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0x87 0x00000000 0x87 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x86 0x00000000 0x86 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x85 0x00000000 0x85 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x84 0x00000000 0x84 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0x80 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0x80 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
> @@ -1213,7 +1218,12 @@ pcie2: pcie@3500000 {
> apio-wins = <8>;
> ppio-wins = <8>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0x88 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0x8f 0x00000000 0x8f 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x8e 0x00000000 0x8e 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x8d 0x00000000 0x8d 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x8c 0x00000000 0x8c 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0x88 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0x88 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
> @@ -1241,7 +1251,12 @@ pcie3: pcie@3600000 {
> apio-wins = <256>;
> ppio-wins = <24>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0x90 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0x97 0x00000000 0x97 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x96 0x00000000 0x96 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x95 0x00000000 0x95 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x94 0x00000000 0x94 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0x90 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0x90 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
> @@ -1269,7 +1284,12 @@ pcie4: pcie@3700000 {
> apio-wins = <8>;
> ppio-wins = <8>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0x98 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0x9f 0x00000000 0x9f 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x9e 0x00000000 0x9e 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x9d 0x00000000 0x9d 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0x9c 0x00000000 0x9c 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0x98 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0x98 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
> @@ -1297,7 +1317,12 @@ pcie5: pcie@3800000 {
> apio-wins = <256>;
> ppio-wins = <24>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0xa0 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0xa7 0x00000000 0xa7 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xa6 0x00000000 0xa6 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xa5 0x00000000 0xa5 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xa4 0x00000000 0xa4 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0xa0 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0xa0 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
> @@ -1325,7 +1350,12 @@ pcie6: pcie@3900000 {
> apio-wins = <8>;
> ppio-wins = <8>;
> bus-range = <0x0 0xff>;
> - ranges = <0x82000000 0x0 0x40000000 0xa8 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
> + ranges = <0x42102200 0xaf 0x00000000 0xaf 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xae 0x00000000 0xae 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xad 0x00000000 0xad 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x42102200 0xac 0x00000000 0xac 0x00000000 0x01 0x00000000>, /* 64-Bit - prefetchable - 4GB chunk */
> + <0x02000200 0x00 0x40000000 0xa8 0x40000000 0x00 0xc0000000>, /* 32-Bit - non-prefetchable */
> + <0x01200100 0x00 0x00000000 0xa8 0x10000000 0x00 0x00010000>; /* 16-Bit IO Window */
> msi-parent = <&its 0>;
> #interrupt-cells = <1>;
> interrupt-map-mask = <0 0 0 7>;
>
> ---
> base-commit: 6de23f81a5e08be8fbf5e8d7e9febc72a5b5f27f
> change-id: 20240118-lx2160-pci-4bdb196e58f3
>
> Best regards,
- Josua Mayer
^ permalink raw reply
* Re: [PATCH v9 2/5] i2c: mux: add support for per channel bus frequency
From: Marcus Folkesson @ 2026-03-26 11:39 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
Andi Shyti, Bartosz Golaszewski, linux-i2c, linux-kernel,
linux-arm-kernel
In-Reply-To: <acKbYhbwZzv2gTnB@ashevche-desk.local>
On Tue, Mar 24, 2026 at 04:10:42PM +0200, Andy Shevchenko wrote:
[...]
>
> ...
>
> > + of_property_read_u32(child, "clock-frequency", &priv->adap.clock_hz);
>
> Wondering if we may use existing API to get i2c timings from fw description?
> i2c_parse_fw_timings() (it might be that it needs to be split for pure fwnode
> one and device wrapped).
I like the idea, even if I don't see that many other parts of the
kernel will be using it.
After this patchset, I intend to make all other bus drivers use
i2c_parse_fw_timings() for fetching their clock frequency. I will
investigate the splitup in the scope of that series.
>
> --
> With Best Regards,
> Andy Shevchenko
>
Best regards,
Marcus Folkesson
^ permalink raw reply
* Re: (subset) [PATCH v2 4/9] leds: Kconfig: drop unneeded dependency on OF_GPIO
From: Lee Jones @ 2026-03-26 12:03 UTC (permalink / raw)
To: Catalin Marinas, Will Deacon, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Linus Walleij, Lee Jones, Pavel Machek,
Wim Van Sebroeck, Guenter Roeck, Mauro Carvalho Chehab,
Greg Kroah-Hartman, Sebastian Reichel, Bartosz Golaszewski
Cc: brgl, linux-arm-kernel, linux-kernel, netdev, linux-gpio,
linux-leds, linux-watchdog, linux-media, linux-staging, linux-pm
In-Reply-To: <20260316-gpio-of-kconfig-v2-4-de2f4b00a0e4@oss.qualcomm.com>
On Mon, 16 Mar 2026 10:45:24 +0100, Bartosz Golaszewski wrote:
> OF_GPIO is selected automatically on all OF systems. Any symbols it
> controls also provide stubs so there's really no reason to select it
> explicitly.
Applied, thanks!
[4/9] leds: Kconfig: drop unneeded dependency on OF_GPIO
commit: b727ba2560a8a806680b45c9acc5a49bc39b8e43
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
From: Nicolas Frattaroli @ 2026-03-26 12:02 UTC (permalink / raw)
To: Ville Syrjälä, Dave Stevenson
Cc: Harry Wentland, Leo Li, Rodrigo Siqueira, Alex Deucher,
Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <CAPY8ntCRPgN_ayHMGXFv9OrJrdyakUcUT0rvgY5J=FvdCFb6eA@mail.gmail.com>
On Thursday, 26 March 2026 12:16:12 Central European Standard Time Dave Stevenson wrote:
> On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > > <nicolas.frattaroli@collabora.com> wrote:
> > > >
> > > > Add a new general DRM property named "color format" which can be used by
> > > > userspace to request the display driver to output a particular color
> > > > format.
> > > >
> > > > Possible options are:
> > > > - auto (setup by default, driver internally picks the color format)
> > > > - rgb
> > > > - ycbcr444
> > > > - ycbcr422
> > > > - ycbcr420
> > > >
> > > > Drivers should advertise from this list which formats they support.
> > > > Together with this list and EDID data from the sink we should be able
> > > > to relay a list of usable color formats to users to pick from.
> > > >
> > > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > > ---
> > > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > > 4 files changed, 228 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > index 26953ed6b53e..b7753454b777 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > > if (old_connector_state->max_requested_bpc !=
> > > > new_connector_state->max_requested_bpc)
> > > > new_crtc_state->connectors_changed = true;
> > > > +
> > > > + if (old_connector_state->color_format !=
> > > > + new_connector_state->color_format)
> > > > + new_crtc_state->connectors_changed = true;
> > > > +
> > > > }
> > > >
> > > > if (funcs->atomic_check)
> > > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > index 5bd5bf6661df..dee510c85e59 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > > state->privacy_screen_sw_state = val;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > state->hdmi.broadcast_rgb = val;
> > > > + } else if (property == connector->color_format_property) {
> > > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > > + drm_dbg_atomic(connector->dev,
> > > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > > + connector->base.id, connector->name, val);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + state->color_format = val;
> > > > } else if (connector->funcs->atomic_set_property) {
> > > > return connector->funcs->atomic_set_property(connector,
> > > > state, property, val);
> > > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > > *val = state->privacy_screen_sw_state;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > *val = state->hdmi.broadcast_rgb;
> > > > + } else if (property == connector->color_format_property) {
> > > > + *val = state->color_format;
> > > > } else if (connector->funcs->atomic_get_property) {
> > > > return connector->funcs->atomic_get_property(connector,
> > > > state, property, val);
> > > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > > index 47dc53c4a738..e848374dee0b 100644
> > > > --- a/drivers/gpu/drm/drm_connector.c
> > > > +++ b/drivers/gpu/drm/drm_connector.c
> > > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > > >
> > > > +static const u32 hdmi_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > +static const u32 dp_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > /*
> > > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > > * Format Table 2-120
> > > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > > }
> > > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > > >
> > > > +/**
> > > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > > + * @connector: connector to create the color format property on
> > > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > > + * values the connector supports
> > > > + *
> > > > + * Called by a driver to create a color format property. The property is
> > > > + * attached to the connector automatically on success.
> > > > + *
> > > > + * @supported_color_formats should only include color formats the connector
> > > > + * type can actually support.
> > > > + *
> > > > + * Returns:
> > > > + * 0 on success, negative errno on error
> > > > + */
> > > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > > + unsigned long supported_color_formats)
> > > > +{
> > > > + struct drm_device *dev = connector->dev;
> > > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > > + unsigned int i = 0;
> > > > + unsigned long fmt;
> > > > +
> > > > + if (connector->color_format_property)
> > > > + return 0;
> > > > +
> > > > + if (!supported_color_formats) {
> > > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + switch (connector->connector_type) {
> > > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > > + case DRM_MODE_CONNECTOR_eDP:
> > > > + if (supported_color_formats & ~dp_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + }
> > > > +
> > > > + enum_list[0].name = "AUTO";
> > > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > > +
> > > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > > + switch (fmt) {
> > > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > > + break;
> > > > + default:
> > > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > > + fmt, connector->base.id, connector->name);
> > > > + continue;
> > > > + }
> > > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > > + }
> > > > +
> > > > + connector->color_format_property =
> > > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > > + enum_list, i + 1);
> > > > +
> > > > + if (!connector->color_format_property)
> > > > + return -ENOMEM;
> > > > +
> > > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > > +
> > > > /**
> > > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > > * @old_state: old connector state to compare
> > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > --- a/include/drm/drm_connector.h
> > > > +++ b/include/drm/drm_connector.h
> > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > + * Number of valid output color format values in this enum
> > > > */
> > > > enum drm_output_color_format {
> > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > };
> > > >
> > > > +/**
> > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > + *
> > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > + * for a specific color format on a connector through the DRM "color format"
> > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > + * no specific choice has been made.
> > > > + */
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > >
> > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> >
> > On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> > compared to 8bpc 4:4:4.
>
> It does save bandwidth against 10 or 12bpc RGB 4:4:4.
>
> Or is the implication that max_bpc = 12 and
> DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
> RGB in preference to selecting 4:2:2?
Yes. Some people consider max-bpc to not be a legitimate way of requesting
an actual bpc, and don't think drivers will choose the highest bpc <= max-bpc,
and instead may negotiate a fantasy number anywhere below or equal to max-bpc.
Of course this logic could be done in userspace which knows whether the
less chroma for more bit depth trade-off is worth it, but userspace does
not know the negotiated link bpc, and my attempts at adding a property for
it are being blocked.
>
> Dave
>
> > --
> > Ville Syrjälä
> > Intel
>
^ permalink raw reply
* Re: [PATCH v6 1/5] mm: rmap: support batched checks of the references for large folios
From: Baolin Wang @ 2026-03-26 12:04 UTC (permalink / raw)
To: Lorenzo Stoakes (Oracle)
Cc: David Hildenbrand (Arm), Barry Song, akpm, catalin.marinas, will,
lorenzo.stoakes, ryan.roberts, Liam.Howlett, vbabka, rppt, surenb,
mhocko, riel, harry.yoo, jannh, willy, dev.jain, linux-mm,
linux-arm-kernel, linux-kernel
In-Reply-To: <a0181a7c-d191-483d-bbc9-678bc355a984@lucifer.local>
On 3/26/26 7:10 PM, Lorenzo Stoakes (Oracle) wrote:
> On Thu, Mar 26, 2026 at 09:47:51AM +0800, Baolin Wang wrote:
>>
>>
>> On 3/25/26 11:06 PM, Lorenzo Stoakes (Oracle) wrote:
>>> On Wed, Mar 25, 2026 at 03:58:36PM +0100, David Hildenbrand (Arm) wrote:
>>>> On 3/25/26 15:36, Lorenzo Stoakes (Oracle) wrote:
>>>>> On Mon, Mar 16, 2026 at 03:15:18PM +0100, David Hildenbrand (Arm) wrote:
>>>>>> On 3/16/26 07:25, Baolin Wang wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Sure. However, after investigating RISC‑V and x86, I found that
>>>>>>> ptep_clear_flush_young() does not flush the TLB on these architectures:
>>>>>>>
>>>>>>> int ptep_clear_flush_young(struct vm_area_struct *vma,
>>>>>>> unsigned long address, pte_t *ptep)
>>>>>>> {
>>>>>>> /*
>>>>>>> * On x86 CPUs, clearing the accessed bit without a TLB flush
>>>>>>> * doesn't cause data corruption. [ It could cause incorrect
>>>>>>> * page aging and the (mistaken) reclaim of hot pages, but the
>>>>>>> * chance of that should be relatively low. ]
>>>>>>> *
>>>>>>> * So as a performance optimization don't flush the TLB when
>>>>>>> * clearing the accessed bit, it will eventually be flushed by
>>>>>>> * a context switch or a VM operation anyway. [ In the rare
>>>>>>> * event of it not getting flushed for a long time the delay
>>>>>>> * shouldn't really matter because there's no real memory
>>>>>>> * pressure for swapout to react to. ]
>>>>>>> */
>>>>>>> return ptep_test_and_clear_young(vma, address, ptep);
>>>>>>> }
>>>>>>
>>>>>> You'd probably want an arch helper then, that tells you whether
>>>>>> a flush_tlb_range() after ptep_test_and_clear_young() is required.
>>>>>>
>>>>>> Or some special flush_tlb_range() helper.
>>>>>>
>>>>>> I agree that it requires more work.
>>
>> (Sorry, David. I forgot to reply to your email because I've had a lot to
>> sort out recently.)
>>
>> Rather than adding more arch helpers (we already have plenty for the young
>> flag check), I think we should try removing the TLB flush, as I mentioned to
>> Barry[1]. MGLRU reclaim already skips the TLB flush, and it seems to work
>> fine. What do you think?
>>
>> Here are our previous attempts to remove the TLB flush:
>>
>> My patch: https://lkml.org/lkml/2023/10/24/533
>> Barry's patch:
>> https://lore.kernel.org/lkml/20220617070555.344368-1-21cnbao@gmail.com/
>>
>> [1] https://lore.kernel.org/all/6bdc4b03-9631-4717-a3fa-2785a7930aba@linux.alibaba.com/
>>
>>>>> Sorry unclear here - does the series need more work or does a follow up patch
>>>>> need more work?
>>>>
>>>> Follow up!
>>>
>>> Ok good as in mm-stable now. Sadly means I don't get to review it but there we
>>> go.
>>
>> Actually this patchset has already been merged upstream:)
Let me try to make things clear.
> Err but this revision was sent _during_ the merge window...?
>
> Was sent on 9th Feb on Monday in merge window week 1, with a functional change
> listed:
>
> - Skip batched unmapping for uffd case, reported by Dev. Thanks.
>
> And then sent in 2nd batch on 18th Feb (see [0]).
>
> So we were ok with 1 week of 'testing' (does anybody actually test -next during
> the merge window? Was it even sent to -next?) for what appears to be a
> functional change?
I posted v5 on Dec 26th[0], and it collected quite a few Reviewed-by
tags and sat in mm-unstable for testing.
Later, Dev reported a uffd-related issue (I hope you recall that
discussion). I posted a fix[1] for it on Jan 16th, which Andrew accepted.
Since then, the v5 series (plus the fix) continued to be tested in
mm-unstable. We kept it there mainly because David mentioned he wanted
to review the series, so we were waiting for his time.
On Feb 9th, after returning from vacation, David reviewed the series
(thanks, David!). I replied to and addressed all his comments, then
posted v6 on the same day[2].
Additionally, v6 had no functional changes compared to v5 + the fix, and
it mainly addressed some coding style issues pointed out by David. I
also discussed this with David off-list, and since there were no
functional changes, my expectation was that it could still make it into
the merge window. That is why v6 was merged.
[0]
https://lore.kernel.org/linux-mm/cover.1766631066.git.baolin.wang@linux.alibaba.com/#t
[1]
https://lore.kernel.org/linux-mm/20260116162652.176054-1-baolin.wang@linux.alibaba.com/
[2]
https://lore.kernel.org/all/cover.1770645603.git.baolin.wang@linux.alibaba.com/
> And there was ongoing feedback on this and the v5 series (at [1])?
Regarding the feedback on v5, I believe everything has been addressed.
> This doesn't really feel sane?
>
> And now I'm confused as to whether mm-stable patches can collect tags, since
> presumably this was in mm-stable at the point this respin was done?
>
> Maybe I'm missing something here but this doesn't feel like a sane process?
Andrew, David, please correct me if I've missed anything. Also, please
let me know if there's anything in the process that needs to be
improved. Thanks.
^ permalink raw reply
* [PATCH net-next v2 1/4] dt-bindings: net: Add support for Airoha AN8801/R GbE PHY
From: Louis-Alexis Eyraud @ 2026-03-26 12:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Andrew Lunn, Heiner Kallweit,
Russell King
Cc: kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Louis-Alexis Eyraud
In-Reply-To: <20260326-add-airoha-an8801-support-v2-0-1a42d6b6050f@collabora.com>
From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Add a new binding to support the Airoha AN8801R Series Gigabit
Ethernet PHY.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../devicetree/bindings/net/airoha,an8801.yaml | 85 ++++++++++++++++++++++
1 file changed, 85 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/airoha,an8801.yaml b/Documentation/devicetree/bindings/net/airoha,an8801.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..b90b21b5505367309b5df8ece54ea38664f6b50f
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/airoha,an8801.yaml
@@ -0,0 +1,85 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/airoha,an8801.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Airoha AN8801R Series PHY
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The Airoha AN8801R is a low power single-port Ethernet PHY Transceiver
+ with Single-port serdes interface for 1000Base-X/RGMII; this chip is
+ compliant with 10Base-T, 100Base-TX and 1000Base-T IEEE 802.3(u,ab)
+ and supports Energy Efficient Ethernet (802.3az), Full Duplex Control
+ Flow (802.3x), auto-negotiation, crossover detect and autocorrection,
+ Wake-on-LAN with Magic Packet, and Jumbo Frame up to 9 Kilobytes.
+ This PHY also supports up to three user-configurable LEDs, which are
+ usually used for LAN Activity, 100M, 1000M indication.
+
+allOf:
+ - $ref: ethernet-phy.yaml#
+
+properties:
+ compatible:
+ enum:
+ - ethernet-phy-idc0ff.0421
+
+ reg:
+ maxItems: 1
+
+ leds: true
+
+ wakeup-source:
+ $ref: /schemas/types.yaml#/definitions/flag
+ description:
+ Enable Wake-on-LAN support
+
+required:
+ - reg
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/leds/common.h>
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet-phy@0 {
+ compatible = "ethernet-phy-idc0ff.0421";
+ reg = <0>;
+
+ leds {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ led@0 {
+ reg = <0>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ default-state = "keep";
+ };
+
+ led@1 {
+ reg = <1>;
+ color = <LED_COLOR_ID_GREEN>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <1>;
+ default-state = "keep";
+ };
+
+ led@2 {
+ reg = <2>;
+ color = <LED_COLOR_ID_YELLOW>;
+ function = LED_FUNCTION_LAN;
+ function-enumerator = <2>;
+ default-state = "keep";
+ };
+ };
+ };
+ };
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v2 2/4] net: phy: Add Airoha phy library for shared code
From: Louis-Alexis Eyraud @ 2026-03-26 12:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Andrew Lunn, Heiner Kallweit,
Russell King
Cc: kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Louis-Alexis Eyraud
In-Reply-To: <20260326-add-airoha-an8801-support-v2-0-1a42d6b6050f@collabora.com>
In preparation of Airoha AN8801R PHY support, split out the interface
functions that will be common between the already present air_en8811h
driver and the new one, and put them into a new library named
air_phy_lib.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
drivers/net/phy/Kconfig | 6 ++++++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/air_en8811h.c | 13 ++-----------
drivers/net/phy/air_phy_lib.c | 30 ++++++++++++++++++++++++++++++
drivers/net/phy/air_phy_lib.h | 14 ++++++++++++++
5 files changed, 53 insertions(+), 11 deletions(-)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index b5ee338b620d53980fbec9e83ab0de3d96ab4cc9..b6b1cde7e51fa1e470bfe210c8764a193449acb5 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -92,10 +92,16 @@ config AS21XXX_PHY
config AIR_EN8811H_PHY
tristate "Airoha EN8811H 2.5 Gigabit PHY"
+ select AIR_NET_PHYLIB
select PHY_COMMON_PROPS
help
Currently supports the Airoha EN8811H PHY.
+config AIR_NET_PHYLIB
+ tristate
+ help
+ Airoha Ethernet PHY common library
+
config AMD_PHY
tristate "AMD and Altima PHYs"
help
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 05e4878af27abeae3dfd9ab18fd29f8bf788b2a4..7cf1fa9e12cb6073a9e68c0ffa6284b361b80487 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -30,6 +30,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o
+obj-$(CONFIG_AIR_NET_PHYLIB) += air_phy_lib.o
obj-$(CONFIG_AMD_PHY) += amd.o
obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index 29ae73e65caaa9cdebe2253b5349aa6c7478dc85..be7c3426182a26fe3799b875827750e7772caadd 100644
--- a/drivers/net/phy/air_en8811h.c
+++ b/drivers/net/phy/air_en8811h.c
@@ -21,6 +21,8 @@
#include <linux/wordpart.h>
#include <linux/unaligned.h>
+#include "air_phy_lib.h"
+
#define EN8811H_PHY_ID 0x03a2a411
#define AN8811HB_PHY_ID 0xc0ff04a0
@@ -40,7 +42,6 @@
#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
-#define AIR_EXT_PAGE_ACCESS 0x1f
#define AIR_PHY_PAGE_STANDARD 0x0000
#define AIR_PHY_PAGE_EXTENDED_4 0x0004
@@ -244,16 +245,6 @@ static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
BIT(TRIGGER_NETDEV_RX) |
BIT(TRIGGER_NETDEV_TX);
-static int air_phy_read_page(struct phy_device *phydev)
-{
- return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
-}
-
-static int air_phy_write_page(struct phy_device *phydev, int page)
-{
- return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);
-}
-
static int __air_buckpbus_reg_write(struct phy_device *phydev,
u32 pbus_address, u32 pbus_data)
{
diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c
new file mode 100644
index 0000000000000000000000000000000000000000..04c4719a073f98ef75eabd54c4851f6a16391350
--- /dev/null
+++ b/drivers/net/phy/air_phy_lib.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Airoha Ethernet PHY common library
+ *
+ * Copyright (C) 2026 Airoha Technology Corp.
+ * Copyright (C) 2026 Collabora Ltd.
+ * Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
+ */
+
+#include <linux/phy.h>
+
+#include "air_phy_lib.h"
+
+#define AIR_EXT_PAGE_ACCESS 0x1f
+
+int air_phy_read_page(struct phy_device *phydev)
+{
+ return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
+}
+EXPORT_SYMBOL_GPL(air_phy_read_page);
+
+int air_phy_write_page(struct phy_device *phydev, int page)
+{
+ return __phy_write(phydev, AIR_EXT_PAGE_ACCESS, page);
+}
+EXPORT_SYMBOL_GPL(air_phy_write_page);
+
+MODULE_DESCRIPTION("Airoha PHY Library");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Louis-Alexis Eyraud");
diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h
new file mode 100644
index 0000000000000000000000000000000000000000..dd501b175a3a38e57744f79571eb1bc4ef46fdf5
--- /dev/null
+++ b/drivers/net/phy/air_phy_lib.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2026 Airoha Technology Corp.
+ * Copyright (C) 2026 Collabora Ltd.
+ * Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
+ */
+
+#ifndef __AIR_PHY_LIB_H
+#define __AIR_PHY_LIB_H
+
+int air_phy_read_page(struct phy_device *phydev);
+int air_phy_write_page(struct phy_device *phydev, int page);
+
+#endif /* __AIR_PHY_LIB_H */
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v2 0/4] Introduce Airoha AN8801R series Gigabit Ethernet PHY driver
From: Louis-Alexis Eyraud @ 2026-03-26 12:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Andrew Lunn, Heiner Kallweit,
Russell King
Cc: kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Louis-Alexis Eyraud
This series introduces the Airoha AN8801R Gigabit Ethernet PHY initial
support.
The Airoha AN8801R is a low power single-port Ethernet PHY Transceiver
with Single-port serdes interface for 1000Base-X/RGMII.
This chip is compliant with 10Base-T, 100Base-TX and 1000Base-T IEEE
802.3(u,ab) and supports:
- Energy Efficient Ethernet (802.3az)
- Full Duplex Control Flow (802.3x)
- auto-negotiation
- crossover detect and autocorrection,
- Wake-on-LAN with Magic Packet
- Jumbo Frame up to 9 Kilobytes.
This PHY also supports up to three user-configurable LEDs, which are
usually used for LAN Activity, 100M, 1000M indication.
The series provides the devicetree binding and the driver that have been
written by AngeloGioacchino Del Regno, based on downstream
implementation ([1]). The driver allows setting up PHY LEDs, 10/100M,
1000M speeds, and Wake on LAN and PHY interrupts.
Since v2, the series also adds the air_phy_lib library, which goal is to
share common code between air_en8811h and air_an8801 drivers, and its use
in them. The first shared functions are the existing BuckPbus register
accessors and air_phy_read/write_page functions coming from air_en8811h
driver.
The series is based on net-next kernel tree (sha1: d1e59a4697371) and
I have tested it on Mediatek Genio 720-EVK board (that integrates an
Airoha AN8801RIN/A Ethernet PHY) with early board hardware enablement
patches.
[1]: https://gitlab.com/mediatek/aiot/bsp/linux/-/blob/mtk-v6.6/drivers/net/phy/an8801.c
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
Changes in v2:
- Rebased on net-next (d1e59a4697371)
- Fixed dt-bindings to remove the leds property from the required ones and
add wakeup-source as valid property
- Added new reviewed-by trailer for dt_bindings
- Added new patches (2 and 3) to create air_phy_lib, to share common code
between air_en8811h and air_an8801 drivers and use it in air_en8811h.
- Remove custom BuckPBus register accessor functions and definitions from
air_an8801 and use the ones from air_phy_lib. It also fixes a build
issue on v1 due to an uninitialized variable used in
__air_buckpbus_reg_read, that is now removed from driver code
- Added air_an8801_probe function to allocate the newly added private
data structure and detect if the PHY is wakeup capable and the interrupt
can be registered as a wakeup IRQ, and perform the needed actions
- Added an8801r_suspend and an8801r_resume functions to perform specific
actions when WoL is enabled (reset its status, enable/disable the Link
Changed interrupt) and call the genphy_suspend/resume functions if
needed
- Modified an8801r_get_wol to return WoL is not supported if the PHY
device is not wakeup capable
- Modified an8801r_set_wol to return EOPNOTSUPP error code if the PHY
device is not wakeup capable, and to update the wakeup flag according
to WoL mode
- Modified an8801r_config_init to remove EEE disabling and replace
__phy_write use by phy_write_paged
- Reworked an8801r_rgmii_delay_config and its subfunctions to fix a
double return use in PHY_INTERFACE_MODE_RGMII_ID case, replace the
magic value use for default TX and RX delay and handle better the
enable/disable the inserted delays for all RGMII modes
- Merged an8801r_did_interrupt function in an8801r_handle_interrupt
- Modified the an8801r_handle_interrupt processing to process differently
the Magic Packet (to notify system wakeup) and the Link Changed
interrupt (to notify PHY state machine)
- Splitted the reset WoL status part from an8801r_ack_interrupt and fix
an issue that in some random cases made WAKEUP_CTL1 register lose the
Magic Packet WoL settings
- Modified an8801r_of_init_leds function so it does not return an error
if the leds configuration is not present in devicetree
- Removed feature field and add PHY_ALWAYS_CALL_SUSPEND flag in
airoha_driver data structure
- Link to v1: https://lore.kernel.org/r/20260304-add-airoha-an8801-support-v1-0-0ae4ee5a2f9d@collabora.com
---
AngeloGioacchino Del Regno (2):
dt-bindings: net: Add support for Airoha AN8801/R GbE PHY
net: phy: Introduce Airoha AN8801/R Gigabit Ethernet PHY driver
Louis-Alexis Eyraud (2):
net: phy: Add Airoha phy library for shared code
net: phy: air_phy_lib: Factorize BuckPBus register accessors
.../devicetree/bindings/net/airoha,an8801.yaml | 85 ++
drivers/net/phy/Kconfig | 12 +
drivers/net/phy/Makefile | 2 +
drivers/net/phy/air_an8801.c | 1115 ++++++++++++++++++++
drivers/net/phy/air_en8811h.c | 316 +-----
drivers/net/phy/air_phy_lib.c | 210 ++++
drivers/net/phy/air_phy_lib.h | 37 +
7 files changed, 1519 insertions(+), 258 deletions(-)
---
base-commit: d1e59a46973719e458bec78d00dd767d7a7ba71f
change-id: 20260303-add-airoha-an8801-support-57d544a4afed
Best regards,
--
Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
^ permalink raw reply
* [PATCH net-next v2 3/4] net: phy: air_phy_lib: Factorize BuckPBus register accessors
From: Louis-Alexis Eyraud @ 2026-03-26 12:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Andrew Lunn, Heiner Kallweit,
Russell King
Cc: kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Louis-Alexis Eyraud
In-Reply-To: <20260326-add-airoha-an8801-support-v2-0-1a42d6b6050f@collabora.com>
In preparation of Airoha AN8801R PHY support, move the BuckPBus
register accessors and definitions, present in air_en8811h driver,
into the Airoha PHY shared code (air_phy_lib), so they will be usable
by the new driver without duplicating them.
Also, update air_en8811h driver to use the new function names.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
drivers/net/phy/air_en8811h.c | 303 ++++++++----------------------------------
drivers/net/phy/air_phy_lib.c | 180 +++++++++++++++++++++++++
drivers/net/phy/air_phy_lib.h | 23 ++++
3 files changed, 259 insertions(+), 247 deletions(-)
diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index be7c3426182a26fe3799b875827750e7772caadd..a42898ae41358fe86072a55528a0ecff0eb5ec19 100644
--- a/drivers/net/phy/air_en8811h.c
+++ b/drivers/net/phy/air_en8811h.c
@@ -42,22 +42,6 @@
#define AIR_AUX_CTRL_STATUS_SPEED_1000 0x8
#define AIR_AUX_CTRL_STATUS_SPEED_2500 0xc
-#define AIR_PHY_PAGE_STANDARD 0x0000
-#define AIR_PHY_PAGE_EXTENDED_4 0x0004
-
-/* MII Registers Page 4*/
-#define AIR_BPBUS_MODE 0x10
-#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
-#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
-#define AIR_BPBUS_WR_ADDR_HIGH 0x11
-#define AIR_BPBUS_WR_ADDR_LOW 0x12
-#define AIR_BPBUS_WR_DATA_HIGH 0x13
-#define AIR_BPBUS_WR_DATA_LOW 0x14
-#define AIR_BPBUS_RD_ADDR_HIGH 0x15
-#define AIR_BPBUS_RD_ADDR_LOW 0x16
-#define AIR_BPBUS_RD_DATA_HIGH 0x17
-#define AIR_BPBUS_RD_DATA_LOW 0x18
-
/* Registers on MDIO_MMD_VEND1 */
#define EN8811H_PHY_FW_STATUS 0x8009
#define EN8811H_PHY_READY 0x02
@@ -245,183 +229,6 @@ static const unsigned long en8811h_led_trig = BIT(TRIGGER_NETDEV_FULL_DUPLEX) |
BIT(TRIGGER_NETDEV_RX) |
BIT(TRIGGER_NETDEV_TX);
-static int __air_buckpbus_reg_write(struct phy_device *phydev,
- u32 pbus_address, u32 pbus_data)
-{
- int ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
- upper_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
- lower_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
- upper_16_bits(pbus_data));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
- lower_16_bits(pbus_data));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int air_buckpbus_reg_write(struct phy_device *phydev,
- u32 pbus_address, u32 pbus_data)
-{
- int saved_page;
- int ret = 0;
-
- saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = __air_buckpbus_reg_write(phydev, pbus_address,
- pbus_data);
- if (ret < 0)
- phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
- }
-
- return phy_restore_page(phydev, saved_page, ret);
-}
-
-static int __air_buckpbus_reg_read(struct phy_device *phydev,
- u32 pbus_address, u32 *pbus_data)
-{
- int pbus_data_low, pbus_data_high;
- int ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
- upper_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
- lower_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0)
- return pbus_data_high;
-
- pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0)
- return pbus_data_low;
-
- *pbus_data = pbus_data_low | (pbus_data_high << 16);
- return 0;
-}
-
-static int air_buckpbus_reg_read(struct phy_device *phydev,
- u32 pbus_address, u32 *pbus_data)
-{
- int saved_page;
- int ret = 0;
-
- saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);
- if (ret < 0)
- phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
- }
-
- return phy_restore_page(phydev, saved_page, ret);
-}
-
-static int __air_buckpbus_reg_modify(struct phy_device *phydev,
- u32 pbus_address, u32 mask, u32 set)
-{
- int pbus_data_low, pbus_data_high;
- u32 pbus_data_old, pbus_data_new;
- int ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
- upper_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
- lower_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
- if (pbus_data_high < 0)
- return pbus_data_high;
-
- pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
- if (pbus_data_low < 0)
- return pbus_data_low;
-
- pbus_data_old = pbus_data_low | (pbus_data_high << 16);
- pbus_data_new = (pbus_data_old & ~mask) | set;
- if (pbus_data_new == pbus_data_old)
- return 0;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
- upper_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
- lower_16_bits(pbus_address));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
- upper_16_bits(pbus_data_new));
- if (ret < 0)
- return ret;
-
- ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
- lower_16_bits(pbus_data_new));
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static int air_buckpbus_reg_modify(struct phy_device *phydev,
- u32 pbus_address, u32 mask, u32 set)
-{
- int saved_page;
- int ret = 0;
-
- saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
-
- if (saved_page >= 0) {
- ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,
- set);
- if (ret < 0)
- phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
- pbus_address, ret);
- }
-
- return phy_restore_page(phydev, saved_page, ret);
-}
-
static int __air_write_buf(struct phy_device *phydev, u32 address,
const struct firmware *fw)
{
@@ -480,8 +287,8 @@ static int en8811h_wait_mcu_ready(struct phy_device *phydev)
{
int ret, reg_value;
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_FINISH);
+ ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_FINISH);
if (ret)
return ret;
@@ -506,28 +313,29 @@ static int an8811hb_check_crc(struct phy_device *phydev, u32 set1,
int ret;
/* Configure CRC */
- ret = air_buckpbus_reg_modify(phydev, set1,
- AN8811HB_CRC_RD_EN,
- AN8811HB_CRC_RD_EN);
+ ret = air_phy_buckpbus_reg_modify(phydev, set1,
+ AN8811HB_CRC_RD_EN,
+ AN8811HB_CRC_RD_EN);
if (ret < 0)
return ret;
- air_buckpbus_reg_read(phydev, set1, &pbus_value);
+ air_phy_buckpbus_reg_read(phydev, set1, &pbus_value);
do {
msleep(300);
- air_buckpbus_reg_read(phydev, mon2, &pbus_value);
+ air_phy_buckpbus_reg_read(phydev, mon2, &pbus_value);
/* We do not know what errors this check is supposed
* catch or what to do about a failure. So print the
* result and continue like the vendor driver does.
*/
if (pbus_value & AN8811HB_CRC_ST) {
- air_buckpbus_reg_read(phydev, mon3, &pbus_value);
+ air_phy_buckpbus_reg_read(phydev, mon3, &pbus_value);
phydev_dbg(phydev, "CRC Check %s!\n",
pbus_value & AN8811HB_CRC_CHECK_PASS ?
"PASS" : "FAIL");
- return air_buckpbus_reg_modify(phydev, set1,
- AN8811HB_CRC_RD_EN, 0);
+ return air_phy_buckpbus_reg_modify(phydev, set1,
+ AN8811HB_CRC_RD_EN,
+ 0);
}
} while (--retry);
@@ -539,8 +347,8 @@ static void en8811h_print_fw_version(struct phy_device *phydev)
{
struct en8811h_priv *priv = phydev->priv;
- air_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
- &priv->firmware_version);
+ air_phy_buckpbus_reg_read(phydev, EN8811H_FW_VERSION,
+ &priv->firmware_version);
phydev_info(phydev, "MD32 firmware version: %08x\n",
priv->firmware_version);
}
@@ -565,8 +373,8 @@ static int an8811hb_load_firmware(struct phy_device *phydev)
{
int ret;
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_START);
+ ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_START);
if (ret < 0)
return ret;
@@ -607,14 +415,14 @@ static int en8811h_load_firmware(struct phy_device *phydev)
if (ret < 0)
goto en8811h_load_firmware_rel1;
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_START);
+ ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_START);
if (ret < 0)
goto en8811h_load_firmware_out;
- ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
- EN8811H_FW_CTRL_2_LOADING,
- EN8811H_FW_CTRL_2_LOADING);
+ ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
+ EN8811H_FW_CTRL_2_LOADING,
+ EN8811H_FW_CTRL_2_LOADING);
if (ret < 0)
goto en8811h_load_firmware_out;
@@ -626,8 +434,8 @@ static int en8811h_load_firmware(struct phy_device *phydev)
if (ret < 0)
goto en8811h_load_firmware_out;
- ret = air_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
- EN8811H_FW_CTRL_2_LOADING, 0);
+ ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_FW_CTRL_2,
+ EN8811H_FW_CTRL_2_LOADING, 0);
if (ret < 0)
goto en8811h_load_firmware_out;
@@ -653,8 +461,8 @@ static int en8811h_restart_mcu(struct phy_device *phydev)
{
int ret;
- ret = air_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
- EN8811H_FW_CTRL_1_START);
+ ret = air_phy_buckpbus_reg_write(phydev, EN8811H_FW_CTRL_1,
+ EN8811H_FW_CTRL_1_START);
if (ret < 0)
return ret;
@@ -948,7 +756,7 @@ static unsigned long an8811hb_clk_recalc_rate(struct clk_hw *hw,
u32 pbus_value;
int ret;
- ret = air_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value);
+ ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_HWTRAP2, &pbus_value);
if (ret < 0)
return ret;
@@ -960,9 +768,9 @@ static int an8811hb_clk_enable(struct clk_hw *hw)
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
struct phy_device *phydev = priv->phydev;
- return air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV,
- AN8811HB_CLK_DRV_CKO_MASK,
- AN8811HB_CLK_DRV_CKO_MASK);
+ return air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV,
+ AN8811HB_CLK_DRV_CKO_MASK,
+ AN8811HB_CLK_DRV_CKO_MASK);
}
static void an8811hb_clk_disable(struct clk_hw *hw)
@@ -970,8 +778,8 @@ static void an8811hb_clk_disable(struct clk_hw *hw)
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
struct phy_device *phydev = priv->phydev;
- air_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV,
- AN8811HB_CLK_DRV_CKO_MASK, 0);
+ air_phy_buckpbus_reg_modify(phydev, AN8811HB_CLK_DRV,
+ AN8811HB_CLK_DRV_CKO_MASK, 0);
}
static int an8811hb_clk_is_enabled(struct clk_hw *hw)
@@ -981,7 +789,7 @@ static int an8811hb_clk_is_enabled(struct clk_hw *hw)
u32 pbus_value;
int ret;
- ret = air_buckpbus_reg_read(phydev, AN8811HB_CLK_DRV, &pbus_value);
+ ret = air_phy_buckpbus_reg_read(phydev, AN8811HB_CLK_DRV, &pbus_value);
if (ret < 0)
return ret;
@@ -1047,7 +855,7 @@ static unsigned long en8811h_clk_recalc_rate(struct clk_hw *hw,
u32 pbus_value;
int ret;
- ret = air_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value);
+ ret = air_phy_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value);
if (ret < 0)
return ret;
@@ -1059,9 +867,9 @@ static int en8811h_clk_enable(struct clk_hw *hw)
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
struct phy_device *phydev = priv->phydev;
- return air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
- EN8811H_CLK_CGM_CKO,
- EN8811H_CLK_CGM_CKO);
+ return air_phy_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
+ EN8811H_CLK_CGM_CKO,
+ EN8811H_CLK_CGM_CKO);
}
static void en8811h_clk_disable(struct clk_hw *hw)
@@ -1069,8 +877,8 @@ static void en8811h_clk_disable(struct clk_hw *hw)
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
struct phy_device *phydev = priv->phydev;
- air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
- EN8811H_CLK_CGM_CKO, 0);
+ air_phy_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
+ EN8811H_CLK_CGM_CKO, 0);
}
static int en8811h_clk_is_enabled(struct clk_hw *hw)
@@ -1080,7 +888,7 @@ static int en8811h_clk_is_enabled(struct clk_hw *hw)
u32 pbus_value;
int ret;
- ret = air_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value);
+ ret = air_phy_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value);
if (ret < 0)
return ret;
@@ -1191,9 +999,9 @@ static int an8811hb_probe(struct phy_device *phydev)
return ret;
/* Configure led gpio pins as output */
- ret = air_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT,
- AN8811HB_GPIO_OUTPUT_345,
- AN8811HB_GPIO_OUTPUT_345);
+ ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_GPIO_OUTPUT,
+ AN8811HB_GPIO_OUTPUT_345,
+ AN8811HB_GPIO_OUTPUT_345);
if (ret < 0)
return ret;
@@ -1232,9 +1040,9 @@ static int en8811h_probe(struct phy_device *phydev)
return ret;
/* Configure led gpio pins as output */
- ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
- EN8811H_GPIO_OUTPUT_345,
- EN8811H_GPIO_OUTPUT_345);
+ ret = air_phy_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
+ EN8811H_GPIO_OUTPUT_345,
+ EN8811H_GPIO_OUTPUT_345);
if (ret < 0)
return ret;
@@ -1254,9 +1062,9 @@ static int an8811hb_config_serdes_polarity(struct phy_device *phydev)
return ret;
if (pol == PHY_POL_NORMAL)
pbus_value |= AN8811HB_RX_POLARITY_NORMAL;
- ret = air_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY,
- AN8811HB_RX_POLARITY_NORMAL,
- pbus_value);
+ ret = air_phy_buckpbus_reg_modify(phydev, AN8811HB_RX_POLARITY,
+ AN8811HB_RX_POLARITY_NORMAL,
+ pbus_value);
if (ret < 0)
return ret;
@@ -1267,9 +1075,9 @@ static int an8811hb_config_serdes_polarity(struct phy_device *phydev)
pbus_value = 0;
if (pol == PHY_POL_NORMAL)
pbus_value |= AN8811HB_TX_POLARITY_NORMAL;
- return air_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY,
- AN8811HB_TX_POLARITY_NORMAL,
- pbus_value);
+ return air_phy_buckpbus_reg_modify(phydev, AN8811HB_TX_POLARITY,
+ AN8811HB_TX_POLARITY_NORMAL,
+ pbus_value);
}
static int en8811h_config_serdes_polarity(struct phy_device *phydev)
@@ -1303,9 +1111,10 @@ static int en8811h_config_serdes_polarity(struct phy_device *phydev)
if (pol == PHY_POL_NORMAL)
pbus_value |= EN8811H_POLARITY_TX_NORMAL;
- return air_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
- EN8811H_POLARITY_RX_REVERSE |
- EN8811H_POLARITY_TX_NORMAL, pbus_value);
+ return air_phy_buckpbus_reg_modify(phydev, EN8811H_POLARITY,
+ EN8811H_POLARITY_RX_REVERSE |
+ EN8811H_POLARITY_TX_NORMAL,
+ pbus_value);
}
static int an8811hb_config_init(struct phy_device *phydev)
@@ -1457,8 +1266,8 @@ static int en8811h_read_status(struct phy_device *phydev)
val & MDIO_AN_10GBT_STAT_LP2_5G);
} else {
/* Get link partner 2.5GBASE-T ability from vendor register */
- ret = air_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA,
- &pbus_value);
+ ret = air_phy_buckpbus_reg_read(phydev, EN8811H_2P5G_LPA,
+ &pbus_value);
if (ret < 0)
return ret;
linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
diff --git a/drivers/net/phy/air_phy_lib.c b/drivers/net/phy/air_phy_lib.c
index 04c4719a073f98ef75eabd54c4851f6a16391350..780ce2a17d3a58d5e3105534e9fea71bf3097b36 100644
--- a/drivers/net/phy/air_phy_lib.c
+++ b/drivers/net/phy/air_phy_lib.c
@@ -13,6 +13,186 @@
#define AIR_EXT_PAGE_ACCESS 0x1f
+static int __air_buckpbus_reg_read(struct phy_device *phydev,
+ u32 pbus_address, u32 *pbus_data)
+{
+ int pbus_data_low, pbus_data_high;
+ int ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
+ upper_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
+ lower_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
+ if (pbus_data_high < 0)
+ return pbus_data_high;
+
+ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
+ if (pbus_data_low < 0)
+ return pbus_data_low;
+
+ *pbus_data = pbus_data_low | (pbus_data_high << 16);
+ return 0;
+}
+
+static int __air_buckpbus_reg_write(struct phy_device *phydev,
+ u32 pbus_address, u32 pbus_data)
+{
+ int ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
+ upper_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
+ lower_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
+ upper_16_bits(pbus_data));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
+ lower_16_bits(pbus_data));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int __air_buckpbus_reg_modify(struct phy_device *phydev,
+ u32 pbus_address, u32 mask, u32 set)
+{
+ int pbus_data_low, pbus_data_high;
+ u32 pbus_data_old, pbus_data_new;
+ int ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_MODE, AIR_BPBUS_MODE_ADDR_FIXED);
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_HIGH,
+ upper_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_RD_ADDR_LOW,
+ lower_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ pbus_data_high = __phy_read(phydev, AIR_BPBUS_RD_DATA_HIGH);
+ if (pbus_data_high < 0)
+ return pbus_data_high;
+
+ pbus_data_low = __phy_read(phydev, AIR_BPBUS_RD_DATA_LOW);
+ if (pbus_data_low < 0)
+ return pbus_data_low;
+
+ pbus_data_old = pbus_data_low | (pbus_data_high << 16);
+ pbus_data_new = (pbus_data_old & ~mask) | set;
+ if (pbus_data_new == pbus_data_old)
+ return 0;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_HIGH,
+ upper_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_ADDR_LOW,
+ lower_16_bits(pbus_address));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_HIGH,
+ upper_16_bits(pbus_data_new));
+ if (ret < 0)
+ return ret;
+
+ ret = __phy_write(phydev, AIR_BPBUS_WR_DATA_LOW,
+ lower_16_bits(pbus_data_new));
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address,
+ u32 *pbus_data)
+{
+ int saved_page;
+ int ret = 0;
+
+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = __air_buckpbus_reg_read(phydev, pbus_address, pbus_data);
+ if (ret < 0)
+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+ }
+
+ return phy_restore_page(phydev, saved_page, ret);
+}
+EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_read);
+
+int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address,
+ u32 pbus_data)
+{
+ int saved_page;
+ int ret = 0;
+
+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = __air_buckpbus_reg_write(phydev, pbus_address,
+ pbus_data);
+ if (ret < 0)
+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+ }
+
+ return phy_restore_page(phydev, saved_page, ret);
+}
+EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_write);
+
+int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address,
+ u32 mask, u32 set)
+{
+ int saved_page;
+ int ret = 0;
+
+ saved_page = phy_select_page(phydev, AIR_PHY_PAGE_EXTENDED_4);
+
+ if (saved_page >= 0) {
+ ret = __air_buckpbus_reg_modify(phydev, pbus_address, mask,
+ set);
+ if (ret < 0)
+ phydev_err(phydev, "%s 0x%08x failed: %d\n", __func__,
+ pbus_address, ret);
+ }
+
+ return phy_restore_page(phydev, saved_page, ret);
+}
+EXPORT_SYMBOL_GPL(air_phy_buckpbus_reg_modify);
+
int air_phy_read_page(struct phy_device *phydev)
{
return __phy_read(phydev, AIR_EXT_PAGE_ACCESS);
diff --git a/drivers/net/phy/air_phy_lib.h b/drivers/net/phy/air_phy_lib.h
index dd501b175a3a38e57744f79571eb1bc4ef46fdf5..23d8e3e318398958f2bba297619f35a86f9871a9 100644
--- a/drivers/net/phy/air_phy_lib.h
+++ b/drivers/net/phy/air_phy_lib.h
@@ -8,6 +8,29 @@
#ifndef __AIR_PHY_LIB_H
#define __AIR_PHY_LIB_H
+#define AIR_PHY_PAGE_STANDARD 0x0000
+#define AIR_PHY_PAGE_EXTENDED_1 0x0001
+#define AIR_PHY_PAGE_EXTENDED_4 0x0004
+
+/* MII Registers Page 4*/
+#define AIR_BPBUS_MODE 0x10
+#define AIR_BPBUS_MODE_ADDR_FIXED 0x0000
+#define AIR_BPBUS_MODE_ADDR_INCR BIT(15)
+#define AIR_BPBUS_WR_ADDR_HIGH 0x11
+#define AIR_BPBUS_WR_ADDR_LOW 0x12
+#define AIR_BPBUS_WR_DATA_HIGH 0x13
+#define AIR_BPBUS_WR_DATA_LOW 0x14
+#define AIR_BPBUS_RD_ADDR_HIGH 0x15
+#define AIR_BPBUS_RD_ADDR_LOW 0x16
+#define AIR_BPBUS_RD_DATA_HIGH 0x17
+#define AIR_BPBUS_RD_DATA_LOW 0x18
+
+int air_phy_buckpbus_reg_modify(struct phy_device *phydev, u32 pbus_address,
+ u32 mask, u32 set);
+int air_phy_buckpbus_reg_read(struct phy_device *phydev, u32 pbus_address,
+ u32 *pbus_data);
+int air_phy_buckpbus_reg_write(struct phy_device *phydev, u32 pbus_address,
+ u32 pbus_data);
int air_phy_read_page(struct phy_device *phydev);
int air_phy_write_page(struct phy_device *phydev, int page);
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v2 4/4] net: phy: Introduce Airoha AN8801/R Gigabit Ethernet PHY driver
From: Louis-Alexis Eyraud @ 2026-03-26 12:04 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Andrew Lunn, Heiner Kallweit,
Russell King
Cc: kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel,
Louis-Alexis Eyraud
In-Reply-To: <20260326-add-airoha-an8801-support-v2-0-1a42d6b6050f@collabora.com>
From: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Introduce a driver for the Airoha AN8801R Series Gigabit Ethernet
PHY; this currently supports setting up PHY LEDs, 10/100M, 1000M
speeds, and Wake on LAN and PHY interrupts.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/air_an8801.c | 1115 ++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1122 insertions(+)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index b6b1cde7e51fa1e470bfe210c8764a193449acb5..4dd77ba487763eaf16c2b390feb237e667f76746 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -90,6 +90,12 @@ config AS21XXX_PHY
AS21210PB1 that all register with the PHY ID 0x7500 0x7500
before the firmware is loaded.
+config AIR_AN8801_PHY
+ tristate "Airoha AN8801 Gigabit PHY"
+ select AIR_NET_PHYLIB
+ help
+ Currently supports the Airoha AN8801R PHY.
+
config AIR_EN8811H_PHY
tristate "Airoha EN8811H 2.5 Gigabit PHY"
select AIR_NET_PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 7cf1fa9e12cb6073a9e68c0ffa6284b361b80487..de660ae949453d99f8a383ca0c0e3cf3f1a14922 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -29,6 +29,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m)
obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
+obj-$(CONFIG_AIR_AN8801_PHY) += air_an8801.o
obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o
obj-$(CONFIG_AIR_NET_PHYLIB) += air_phy_lib.o
obj-$(CONFIG_AMD_PHY) += amd.o
diff --git a/drivers/net/phy/air_an8801.c b/drivers/net/phy/air_an8801.c
new file mode 100644
index 0000000000000000000000000000000000000000..53ade9665fe9e08010fe208f760051f1b621a128
--- /dev/null
+++ b/drivers/net/phy/air_an8801.c
@@ -0,0 +1,1115 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Driver for the Airoha AN8801 Gigabit PHY.
+ *
+ * Copyright (C) 2025 Airoha Technology Corp.
+ * Copyright (C) 2025 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/pm_wakeirq.h>
+
+#include "air_phy_lib.h"
+
+#define AN8801R_PHY_ID 0xc0ff0421
+
+/* MII Registers */
+
+/* MII Registers - Airoha Page 1 */
+#define AN8801_EXT_REG_PHY 0x14
+#define AN8801_EXT_PHY_STATUS0 GENMASK(1, 0)
+#define AN8801_EXT_PHY_DOWNSHIFT_CTL GENMASK(3, 2) /* 2 to 5 1G auto-neg attempts (0..3) */
+#define AN8801_EXT_PHY_DOWNSHIFT_EN BIT(4)
+#define AN8801_EXT_PHY_CTRL0 BIT(5)
+#define AN8801_EXT_PHY_STATUS1 GENMASK(8, 6)
+#define AN8801_EXT_PHY_CTRL1 GENMASK(14, 9)
+
+/* MII Registers - Airoha Page 4 */
+#define AN8801_PBUS_ACCESS BIT(28)
+#define AN8801_PBUS_EPHY_ACCESS BIT(24)
+#define AN8801_PBUS_CL22_ACCESS BIT(23)
+
+/* BPBUS Registers */
+#define AN8801_BPBUS_REG_LED_GPIO 0x54
+#define AN8801_BPBUS_REG_LED_ID_SEL 0x58
+#define LED_ID_GPIO_SEL(led, gpio) ((led) << ((gpio) * 3))
+#define AN8801_BPBUS_REG_GPIO_MODE 0x70
+#define AN8801_BPBUS_REG_PHY_IRQ_GPIO 0x7c
+#define AN8801_PHY_IRQ_GPIO_NUM_MASK GENMASK(19, 16)
+#define AN8801_PHY_IRQ_GPIO_NUM 1
+
+#define AN8801_BPBUS_REG_CKO 0x1a4
+#define AN8801_CKO_OUTPUT_MODE_AUTO 3
+
+#define AN8801_BPBUS_REG_LINK_MODE 0x5054
+#define AN8801_BPBUS_LINK_MODE_1000 BIT(0)
+
+#define AN8801_BPBUS_REG_BYPASS_PTP 0x21c004
+#define AN8801_BYP_PTP_SGMII_TO_GPHY BIT(8)
+#define AN8801_BYP_PTP_RGMII_TO_GPHY BIT(0)
+
+#define AN8801_BPBUS_REG_TXDLY_STEP 0x21c024
+#define RGMII_DELAY_STEP_MASK GENMASK(2, 0)
+#define RGMII_DELAY_NO_STEP 0
+#define RGMII_DELAY_STEP_1 1
+#define RGMII_DELAY_STEP_2 2
+#define RGMII_DELAY_STEP_3 3
+#define RGMII_DELAY_STEP_4 4
+#define RGMII_DELAY_STEP_5 5
+#define RGMII_DELAY_STEP_6 6
+#define RGMII_DELAY_STEP_7 7
+#define RGMII_TXDELAY_FORCE_MODE BIT(24)
+
+#define AN8801_RGMII_TXDELAY_DEFAULT RGMII_DELAY_STEP_4 /* 1.883ns delay */
+
+#define AN8801_BPBUS_REG_RXDLY_STEP 0x21c02c
+#define RGMII_RXDELAY_ALIGN BIT(4)
+#define RGMII_RXDELAY_FORCE_MODE BIT(24)
+
+#define AN8801_RGMII_RXDELAY_DEFAULT RGMII_DELAY_NO_STEP /* 1.992ns delay */
+
+#define AN8801_BPBUS_REG_EFIFO_CTL(x) (0x270004 + (0x100 * (x))) /* 0..2 */
+#define AN8801_EFIFO_ALL_EN GENMASK(7, 0)
+#define AN8801_EFIFO_RX_EN BIT(0)
+#define AN8801_EFIFO_TX_EN BIT(1)
+#define AN8801_EFIFO_RX_CLK_EN BIT(2)
+#define AN8801_EFIFO_TX_CLK_EN BIT(3)
+#define AN8801_EFIFO_RX_EEE_EN BIT(4)
+#define AN8801_EFIFO_TX_EEE_EN BIT(5)
+#define AN8801_EFIFO_RX_ODD_NIBBLE_EN BIT(6)
+#define AN8801_EFIFO_TX_ODD_NIBBLE_EN BIT(7)
+
+#define AN8801_BPBUS_REG_WOL_MAC_16_47 0x285114
+#define AN8801_BPBUS_REG_WOL_MAC_0_15 0x285118
+
+#define AN8801_BPBUS_REG_WAKEUP_CTL1 0x285400
+#define AN8801_WOL_WAKE_MAGIC_EN GENMASK(3, 1)
+#define AN8801_WOL_WAKE_LNKCHG_EN BIT(4)
+
+#define AN8801_BPBUS_REG_WAKEUP_CTL2 0x285404
+#define AN8801_WAKE_OUT_TYPE_PULSE BIT(0) /* Set/Unset: Pulse/Static */
+#define AN8801_WAKE_OUT_POLARITY_NEG BIT(1) /* Set/Unset: Negative/Positive */
+#define AN8801_WAKE_OUT_WIDTH GENMASK(2, 3)
+#define AN8801_WAKE_OUT_84MS 0
+#define AN8801_WAKE_OUT_168MS 1
+#define AN8801_WAKE_OUT_336MS 2
+#define AN8801_WAKE_OUT_672MS 3
+#define AN8801_WAKE_OUT_EN BIT(4)
+#define AN8801_PME_WAKEUP_CLR BIT(8)
+
+#define AN8801_BPBUS_REG_WAKE_IRQ_EN 0x285700
+#define AN8801_BPBUS_REG_WAKE_IRQ_STS 0x285704
+#define AN8801_IRQ_WAKE_LNKCHG BIT(0) /* Wake on link change */
+#define AN8801_IRQ_WAKE_UNIPKT BIT(1) /* Wake on unicast packet */
+#define AN8801_IRQ_WAKE_MULPKT BIT(2) /* Wake on multicast packet */
+#define AN8801_IRQ_WAKE_BCPKT BIT(3) /* Wake on broadcast packet */
+#define AN8801_IRQ_WAKE_MAGICPKT BIT(4) /* Wake on magic packet */
+#define AN8801_IRQ_WAKE_ALL GENMASK(4, 0)
+
+/* MDIO_MMD_VEND1 Registers */
+#define AN8801_PHY_TX_PAIR_DLY_SEL_GBE 0x13
+#define AN8801_PHY_PAIR_DLY_SEL_A_GBE GENMASK(14, 12)
+#define AN8801_PHY_PAIR_DLY_SEL_B_GBE GENMASK(10, 8)
+#define AN8801_PHY_PAIR_DLY_SEL_C_GBE GENMASK(6, 4)
+#define AN8801_PHY_PAIR_DLY_SEL_D_GBE GENMASK(2, 0)
+#define AN8801_PHY_RXADC_CTRL 0xd8
+#define AN8801_PHY_RXADC_SAMP_PHSEL_A BIT(12)
+#define AN8801_PHY_RXADC_SAMP_PHSEL_B BIT(8)
+#define AN8801_PHY_RXADC_SAMP_PHSEL_C BIT(4)
+#define AN8801_PHY_RXADC_SAMP_PHSEL_D BIT(0)
+#define AN8801_PHY_RXADC_REV_0 0xd9
+#define AN8801_PHY_RXADC_REV_MASK_A GENMASK(15, 8)
+#define AN8801_PHY_RXADC_REV_MASK_B GENMASK(7, 0)
+#define AN8801_PHY_RXADC_REV_1 0xda
+#define AN8801_PHY_RXADC_REV_MASK_C GENMASK(15, 8)
+#define AN8801_PHY_RXADC_REV_MASK_D GENMASK(7, 0)
+
+/* MDIO_MMD_VEND2 Registers */
+#define LED_BCR 0x21
+#define LED_BCR_MODE_MASK GENMASK(1, 0)
+#define LED_BCR_TIME_TEST BIT(2)
+#define LED_BCR_CLK_EN BIT(3)
+#define LED_BCR_EVT_ALL BIT(4)
+#define LED_BCR_EXT_CTRL BIT(15)
+#define LED_BCR_MODE_DISABLE 0
+#define LED_BCR_MODE_2LED 1
+#define LED_BCR_MODE_3LED_1 2
+#define LED_BCR_MODE_3LED_2 3
+
+#define LED_ON_DUR 0x22
+#define LED_ON_DUR_MASK GENMASK(15, 0)
+
+#define LED_BLINK_DUR 0x23
+#define LED_BLINK_DUR_MASK GENMASK(15, 0)
+
+#define LED_ON_CTRL(i) (0x24 + ((i) * 2))
+#define LED_ON_EVT_MASK GENMASK(6, 0)
+#define LED_ON_EVT_LINK_1000M BIT(0)
+#define LED_ON_EVT_LINK_100M BIT(1)
+#define LED_ON_EVT_LINK_10M BIT(2)
+#define LED_ON_EVT_LINK_DN BIT(3)
+#define LED_ON_EVT_FDX BIT(4)
+#define LED_ON_EVT_HDX BIT(5)
+#define LED_ON_EVT_FORCE BIT(6)
+#define LED_ON_POL BIT(14)
+#define LED_ON_EN BIT(15)
+
+#define LED_BLINK_CTRL(i) (0x25 + ((i) * 2))
+#define LED_BLINK_EVT_MASK GENMASK(9, 0)
+#define LED_BLINK_EVT_1000M_TX BIT(0)
+#define LED_BLINK_EVT_1000M_RX BIT(1)
+#define LED_BLINK_EVT_100M_TX BIT(2)
+#define LED_BLINK_EVT_100M_RX BIT(3)
+#define LED_BLINK_EVT_10M_TX BIT(4)
+#define LED_BLINK_EVT_10M_RX BIT(5)
+#define LED_BLINK_EVT_COLLISION BIT(6)
+#define LED_BLINK_EVT_RX_CRC_ERR BIT(7)
+#define LED_BLINK_EVT_RX_IDLE_ERR BIT(8)
+#define LED_BLINK_EVT_FORCE BIT(9)
+
+#define AN8801R_NUM_LEDS 3
+#define AN8801_PERIOD_SHIFT 15
+#define AN8801_PERIOD_UNIT 32768 /* (1 << AN8801_PERIOD_SHIFT) */
+#define AN8801_MAX_PERIOD_MS 2147
+
+#define LED_BLINK_DURATION_UNIT 780
+#define LED_BLINK_DURATION(f) (LED_BLINK_DURATION_UNIT << (f))
+
+#define AN8801_LED_DURATION_UNIT_US 32768
+
+#define AN8801_REG_PHY_INTERNAL0 0x600
+#define AN8801_REG_PHY_INTERNAL1 0x601
+#define AN8801_PHY_INTFUNC_MASK GENMASK(15, 0) /* PHY internal functions */
+
+enum an8801r_led_fn {
+ AN8801R_LED_FN_NONE,
+ AN8801R_LED_FN_LINK,
+ AN8801R_LED_FN_ACTIVITY,
+ AN8801R_LED_FN_MAX,
+};
+
+struct an8801r_priv {
+ bool wake_magic_enabled;
+ bool wake_lnkchg_enabled;
+};
+
+static int an8801_buckpbus_reg_rmw(struct phy_device *phydev,
+ u32 addr, u32 mask, u32 set)
+{
+ return air_phy_buckpbus_reg_modify(phydev,
+ addr | AN8801_PBUS_ACCESS,
+ mask, set);
+}
+
+static int an8801_buckpbus_reg_set_bits(struct phy_device *phydev,
+ u32 addr, u32 mask)
+{
+ return air_phy_buckpbus_reg_modify(phydev,
+ addr | AN8801_PBUS_ACCESS,
+ mask, mask);
+}
+
+static int an8801_buckpbus_reg_clear_bits(struct phy_device *phydev,
+ u32 addr, u32 mask)
+{
+ return air_phy_buckpbus_reg_modify(phydev,
+ addr | AN8801_PBUS_ACCESS,
+ mask, 0);
+}
+
+static int an8801_buckpbus_reg_write(struct phy_device *phydev, u32 addr,
+ u32 data)
+{
+ return air_phy_buckpbus_reg_write(phydev,
+ addr | AN8801_PBUS_ACCESS,
+ data);
+}
+
+static int an8801_buckpbus_reg_read(struct phy_device *phydev, u32 addr,
+ u32 *data)
+{
+ return air_phy_buckpbus_reg_read(phydev,
+ addr | AN8801_PBUS_ACCESS,
+ data);
+}
+
+static u32 an8801r_led_blink_ms_to_hw(unsigned long req_ms)
+{
+ u32 req_ns, regval;
+
+ if (req_ms > AN8801_MAX_PERIOD_MS)
+ req_ms = AN8801_MAX_PERIOD_MS;
+
+ req_ns = req_ms * 1000000;
+
+ /* Round to the nearest period unit... */
+ regval = req_ns + (AN8801_PERIOD_UNIT / 2);
+
+ /* ...and now divide by the full period */
+ regval >>= AN8801_PERIOD_SHIFT;
+
+ return regval;
+}
+
+static int an8801r_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ u32 hw_delay_on, hw_delay_off;
+ bool blink;
+ int ret;
+
+ if (index >= AN8801R_NUM_LEDS)
+ return -EINVAL;
+
+ if (delay_on && delay_off) {
+ blink = true;
+
+ if (*delay_on == 0 || *delay_off == 0) {
+ *delay_on = 64;
+ *delay_off = 64;
+ }
+
+ hw_delay_on = an8801r_led_blink_ms_to_hw(*delay_on);
+ hw_delay_off = an8801r_led_blink_ms_to_hw(*delay_off);
+ } else {
+ blink = false;
+ }
+
+ if (blink) {
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_DUR,
+ LED_BLINK_DURATION(hw_delay_on));
+ if (ret)
+ goto error;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, LED_ON_DUR,
+ LED_BLINK_DURATION(hw_delay_off) >> 1);
+ if (ret)
+ goto error;
+ }
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EN, blink ? LED_ON_EN : 0);
+ if (ret)
+ return ret;
+
+ return 0;
+error:
+ phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EN, 0);
+ return ret;
+}
+
+static int an8801r_led_brightness_set(struct phy_device *phydev, u8 index,
+ enum led_brightness value)
+{
+ int ret;
+
+ if (index >= AN8801R_NUM_LEDS)
+ return -EINVAL;
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EVT_MASK,
+ (value == LED_OFF) ? 0 : LED_ON_EVT_FORCE);
+ if (ret)
+ return ret;
+
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EN, (value == LED_OFF) ? 0 : LED_ON_EN);
+}
+
+static int an8801r_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ int on, blink;
+
+ on = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index));
+ if (on < 0)
+ return on;
+
+ blink = phy_read_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index));
+ if (blink < 0)
+ return blink;
+
+ if (FIELD_GET(LED_ON_EVT_LINK_10M, on))
+ __set_bit(TRIGGER_NETDEV_LINK_10, rules);
+
+ if (FIELD_GET(LED_ON_EVT_LINK_100M, on))
+ __set_bit(TRIGGER_NETDEV_LINK_100, rules);
+
+ if (FIELD_GET(LED_ON_EVT_LINK_1000M, on))
+ __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+
+ if (FIELD_GET(LED_ON_EVT_LINK_10M, on) &&
+ FIELD_GET(LED_ON_EVT_LINK_100M, on) &&
+ FIELD_GET(LED_ON_EVT_LINK_1000M, on))
+ __set_bit(TRIGGER_NETDEV_LINK, rules);
+
+ if (FIELD_GET(LED_BLINK_EVT_10M_RX, blink) ||
+ FIELD_GET(LED_BLINK_EVT_100M_RX, blink) ||
+ FIELD_GET(LED_BLINK_EVT_1000M_RX, blink))
+ __set_bit(TRIGGER_NETDEV_RX, rules);
+
+ if (FIELD_GET(LED_BLINK_EVT_10M_TX, blink) ||
+ FIELD_GET(LED_BLINK_EVT_100M_TX, blink) ||
+ FIELD_GET(LED_BLINK_EVT_1000M_TX, blink))
+ __set_bit(TRIGGER_NETDEV_TX, rules);
+
+ if (FIELD_GET(LED_BLINK_EVT_RX_CRC_ERR, blink))
+ __set_bit(TRIGGER_NETDEV_RX_ERR, rules);
+
+ return 0;
+}
+
+static int an8801r_led_trig_to_hw(unsigned long rules, u16 *on, u16 *blink)
+{
+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ *on |= LED_ON_EVT_LINK_10M;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ *on |= LED_ON_EVT_LINK_100M;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ *on |= LED_ON_EVT_LINK_1000M;
+
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules)) {
+ *on |= LED_ON_EVT_LINK_10M;
+ *on |= LED_ON_EVT_LINK_100M;
+ *on |= LED_ON_EVT_LINK_1000M;
+ }
+
+ if (test_bit(TRIGGER_NETDEV_RX, &rules)) {
+ *blink |= LED_BLINK_EVT_10M_RX;
+ *blink |= LED_BLINK_EVT_100M_RX;
+ *blink |= LED_BLINK_EVT_1000M_RX;
+ }
+
+ if (test_bit(TRIGGER_NETDEV_TX, &rules)) {
+ *blink |= LED_BLINK_EVT_10M_TX;
+ *blink |= LED_BLINK_EVT_100M_TX;
+ *blink |= LED_BLINK_EVT_1000M_TX;
+ }
+
+ if (test_bit(TRIGGER_NETDEV_RX_ERR, &rules))
+ *blink |= LED_BLINK_EVT_RX_CRC_ERR;
+
+ if (rules && !*on && !*blink)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int an8801r_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ u16 on = 0, blink = 0;
+
+ if (index >= AN8801R_NUM_LEDS)
+ return -EINVAL;
+
+ return an8801r_led_trig_to_hw(rules, &on, &blink);
+}
+
+static int an8801r_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ u16 on = 0, blink = 0;
+ int ret;
+
+ if (index >= AN8801R_NUM_LEDS)
+ return -EINVAL;
+
+ ret = an8801r_led_trig_to_hw(rules, &on, &blink);
+ if (ret)
+ return ret;
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EVT_MASK, on);
+ if (ret)
+ return ret;
+
+ ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_BLINK_CTRL(index),
+ LED_BLINK_EVT_MASK, blink);
+
+ if (ret)
+ return ret;
+
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_EN, on | blink ? LED_ON_EN : 0);
+}
+
+static int an8801r_led_polarity_set(struct phy_device *phydev, int index,
+ unsigned long modes)
+{
+ unsigned long mode;
+ bool active_high;
+
+ if (index >= AN8801R_NUM_LEDS)
+ return -EINVAL;
+
+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+ switch (mode) {
+ case PHY_LED_ACTIVE_HIGH:
+ active_high = true;
+ break;
+ case PHY_LED_ACTIVE_LOW:
+ active_high = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND2, LED_ON_CTRL(index),
+ LED_ON_POL, active_high ? LED_ON_POL : 0);
+}
+
+static int an8801r_led_init(struct phy_device *phydev, u8 *led_cfg)
+{
+ int led_id, ret;
+
+ /* Set LED BCR Enable */
+ ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, LED_BCR,
+ LED_BCR_EXT_CTRL | LED_BCR_CLK_EN);
+ if (ret)
+ return ret;
+
+ for (led_id = 0; led_id < AN8801R_NUM_LEDS; led_id++) {
+ unsigned long led_trigger = 0;
+ u32 led_gpio = led_id + 1;
+
+ switch (led_cfg[led_id]) {
+ case AN8801R_LED_FN_LINK:
+ led_trigger = BIT(TRIGGER_NETDEV_LINK);
+ break;
+ case AN8801R_LED_FN_ACTIVITY:
+ led_trigger = BIT(TRIGGER_NETDEV_RX) |
+ BIT(TRIGGER_NETDEV_TX);
+ break;
+ default:
+ led_trigger = 0;
+ break;
+ }
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_LED_GPIO,
+ BIT(led_gpio));
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_LED_ID_SEL,
+ LED_ID_GPIO_SEL(led_id,
+ led_gpio));
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_clear_bits(phydev,
+ AN8801_BPBUS_REG_GPIO_MODE,
+ BIT(led_gpio));
+ if (ret)
+ return ret;
+
+ if (!led_trigger)
+ continue;
+
+ ret = an8801r_led_hw_control_set(phydev, led_id, led_trigger);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static int an8801r_reset_wake(struct phy_device *phydev)
+{
+ struct an8801r_priv *priv = phydev->priv;
+ u32 reg_val = 0;
+ int ret;
+
+ /* Enable wakeup clear and disable wake up output */
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2,
+ AN8801_PME_WAKEUP_CLR |
+ AN8801_WAKE_OUT_POLARITY_NEG);
+ if (ret)
+ return ret;
+
+ /* Clear WAKEUP_CTL1 register before enabling the wakeup events
+ * again
+ */
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
+ 0);
+ if (ret)
+ return ret;
+
+ if (priv->wake_magic_enabled)
+ reg_val |= AN8801_WOL_WAKE_MAGIC_EN;
+
+ if (priv->wake_lnkchg_enabled)
+ reg_val |= AN8801_WOL_WAKE_LNKCHG_EN;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
+ reg_val);
+ if (ret)
+ return ret;
+
+ /* Disable wake up clear and re-enable wake up output */
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKEUP_CTL2,
+ AN8801_WAKE_OUT_POLARITY_NEG |
+ AN8801_WAKE_OUT_EN);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int an8801r_ack_interrupt(struct phy_device *phydev)
+{
+ int ret;
+
+ /* Reset wake status */
+ ret = an8801r_reset_wake(phydev);
+ if (ret)
+ return ret;
+
+ /* Clear the interrupts by writing the reg */
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS,
+ AN8801_IRQ_WAKE_ALL);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int an8801r_config_intr(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ u32 val = FIELD_PREP(AN8801_PHY_IRQ_GPIO_NUM_MASK,
+ AN8801_PHY_IRQ_GPIO_NUM);
+
+ ret = an8801_buckpbus_reg_write(phydev,
+ AN8801_BPBUS_REG_PHY_IRQ_GPIO,
+ val);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_LNKCHG);
+ if (ret)
+ return ret;
+
+ } else {
+ ret = an8801_buckpbus_reg_write(phydev,
+ AN8801_BPBUS_REG_PHY_IRQ_GPIO,
+ 0);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_clear_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_LNKCHG);
+ if (ret)
+ return ret;
+ }
+
+ ret = an8801r_ack_interrupt(phydev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static irqreturn_t an8801r_handle_interrupt(struct phy_device *phydev)
+{
+ u32 irq_status = 0;
+ int ret;
+
+ ret = an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKE_IRQ_STS,
+ &irq_status);
+ if (ret)
+ return ret;
+
+ ret = an8801r_ack_interrupt(phydev);
+ if (ret)
+ return IRQ_NONE;
+
+ if (irq_status & AN8801_IRQ_WAKE_MAGICPKT) {
+ pm_wakeup_event(&phydev->mdio.dev, 0);
+ return IRQ_HANDLED;
+ }
+
+ if (irq_status & AN8801_IRQ_WAKE_LNKCHG) {
+ phy_trigger_machine(phydev);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static void an8801r_get_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ u32 reg_val;
+
+ /* If the PHY is not capable of waking the system, then WoL can not
+ * be supported.
+ */
+ if (!device_can_wakeup(&phydev->mdio.dev)) {
+ wol->supported = 0;
+ return;
+ }
+
+ wol->supported = WAKE_MAGIC;
+
+ an8801_buckpbus_reg_read(phydev, AN8801_BPBUS_REG_WAKEUP_CTL1,
+ ®_val);
+
+ if (reg_val & AN8801_WOL_WAKE_MAGIC_EN)
+ wol->wolopts |= WAKE_MAGIC;
+ else
+ wol->wolopts &= ~WAKE_MAGIC;
+}
+
+static int an8801r_set_wol(struct phy_device *phydev,
+ struct ethtool_wolinfo *wol)
+{
+ struct net_device *attach_dev = phydev->attached_dev;
+ const unsigned char *macaddr = attach_dev->dev_addr;
+ struct an8801r_priv *priv = phydev->priv;
+ u32 reg_val;
+ int ret;
+
+ if (!device_can_wakeup(&phydev->mdio.dev))
+ return -EOPNOTSUPP;
+
+ if (wol->wolopts & WAKE_MAGIC) {
+ /* MAC bits 16..47 */
+ reg_val = (macaddr[2] << 24) | (macaddr[3] << 16);
+ reg_val |= (macaddr[4] << 8) | (macaddr[5]);
+
+ ret = an8801_buckpbus_reg_write(phydev,
+ AN8801_BPBUS_REG_WOL_MAC_16_47,
+ reg_val);
+ if (ret)
+ return ret;
+
+ /* MAC bits 0..15 */
+ reg_val = (macaddr[0] << 8) | (macaddr[1]);
+
+ ret = an8801_buckpbus_reg_write(phydev,
+ AN8801_BPBUS_REG_WOL_MAC_0_15,
+ reg_val);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_WAKEUP_CTL1,
+ AN8801_WOL_WAKE_MAGIC_EN);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_MAGICPKT);
+ if (ret)
+ return ret;
+
+ } else {
+ ret = an8801_buckpbus_reg_clear_bits(phydev,
+ AN8801_BPBUS_REG_WAKEUP_CTL1,
+ AN8801_WOL_WAKE_MAGIC_EN);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_clear_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_MAGICPKT);
+ if (ret)
+ return ret;
+ }
+
+ priv->wake_magic_enabled = !!(wol->wolopts & WAKE_MAGIC);
+
+ device_set_wakeup_enable(&phydev->mdio.dev,
+ priv->wake_magic_enabled);
+
+ return 0;
+}
+
+static int an8801r_of_init_leds(struct phy_device *phydev, u8 *led_cfg)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *leds;
+ u32 function_enum_idx;
+ int ret;
+
+ if (!np)
+ return 0;
+
+ /* If devicetree is present, leds configuration is required */
+ leds = of_get_child_by_name(np, "leds");
+ if (!leds)
+ return 0;
+
+ for_each_available_child_of_node_scoped(leds, led) {
+ u32 led_idx;
+
+ ret = of_property_read_u32(led, "reg", &led_idx);
+ if (ret)
+ goto out;
+
+ if (led_idx >= AN8801R_NUM_LEDS) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = of_property_read_u32(led, "function-enumerator",
+ &function_enum_idx);
+ if (ret)
+ function_enum_idx = AN8801R_LED_FN_NONE;
+
+ if (function_enum_idx >= AN8801R_LED_FN_MAX) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ led_cfg[led_idx] = function_enum_idx;
+ }
+out:
+ of_node_put(leds);
+ return ret;
+}
+
+static int an8801r_rgmii_rxdelay(struct phy_device *phydev, bool enable,
+ u16 delay_steps)
+{
+ u32 reg_val;
+
+ if (delay_steps > RGMII_DELAY_STEP_MASK)
+ return -EINVAL;
+
+ if (enable) {
+ reg_val = delay_steps & RGMII_DELAY_STEP_MASK;
+
+ /* Set align bit to add extra offset for RX delay */
+ reg_val |= RGMII_RXDELAY_ALIGN;
+
+ /* Set force mode bit to enable RX delay insertion */
+ reg_val |= RGMII_RXDELAY_FORCE_MODE;
+ } else {
+ reg_val = 0;
+ }
+
+ return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_RXDLY_STEP,
+ reg_val);
+}
+
+static int an8801r_rgmii_txdelay(struct phy_device *phydev, bool enable,
+ u16 delay_steps)
+{
+ u32 reg_val;
+
+ if (delay_steps > RGMII_DELAY_STEP_MASK)
+ return -EINVAL;
+
+ if (enable) {
+ reg_val = delay_steps & RGMII_DELAY_STEP_MASK;
+
+ /* Set force mode bit to enable TX delay insertion */
+ reg_val |= RGMII_TXDELAY_FORCE_MODE;
+ } else {
+ reg_val = 0;
+ }
+
+ return an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_TXDLY_STEP,
+ reg_val);
+}
+
+static int an8801r_rgmii_delay_config(struct phy_device *phydev)
+{
+ bool enable_delay;
+ u16 delay_step;
+ int ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
+ enable_delay = true;
+ delay_step = AN8801_RGMII_TXDELAY_DEFAULT;
+ } else {
+ enable_delay = false;
+ delay_step = RGMII_DELAY_NO_STEP;
+ }
+
+ ret = an8801r_rgmii_txdelay(phydev, enable_delay, delay_step);
+ if (ret)
+ return ret;
+
+ if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
+ phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
+ enable_delay = true;
+ delay_step = AN8801_RGMII_RXDELAY_DEFAULT;
+ } else {
+ enable_delay = false;
+ delay_step = RGMII_DELAY_NO_STEP;
+ }
+
+ ret = an8801r_rgmii_rxdelay(phydev, enable_delay, delay_step);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int an8801r_config_init(struct phy_device *phydev)
+{
+ u8 led_default_function[AN8801R_NUM_LEDS] = { 0 };
+ int ret;
+
+ ret = an8801r_of_init_leds(phydev, led_default_function);
+ if (ret)
+ return ret;
+
+ /* Disable Low Power Mode (LPM) */
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL0,
+ FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x1e));
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, AN8801_REG_PHY_INTERNAL1,
+ FIELD_PREP(AN8801_PHY_INTFUNC_MASK, 0x2));
+ if (ret)
+ return ret;
+
+ /* Set the PHY to perform auto-downshift after 3 auto-negotiation
+ * attempts
+ */
+ ret = phy_write_paged(phydev, AIR_PHY_PAGE_EXTENDED_1,
+ AN8801_EXT_REG_PHY,
+ FIELD_PREP(AN8801_EXT_PHY_CTRL1, 0x1d) |
+ FIELD_PREP(AN8801_EXT_PHY_DOWNSHIFT_CTL, 1) |
+ AN8801_EXT_PHY_DOWNSHIFT_EN);
+ if (ret < 0)
+ return ret;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_BYPASS_PTP,
+ AN8801_BYP_PTP_RGMII_TO_GPHY);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(0),
+ AN8801_EFIFO_RX_EN |
+ AN8801_EFIFO_TX_EN |
+ AN8801_EFIFO_RX_CLK_EN |
+ AN8801_EFIFO_TX_CLK_EN |
+ AN8801_EFIFO_RX_EEE_EN |
+ AN8801_EFIFO_TX_EEE_EN);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(1),
+ AN8801_EFIFO_ALL_EN);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_EFIFO_CTL(2),
+ AN8801_EFIFO_ALL_EN);
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1,
+ AN8801_PHY_TX_PAIR_DLY_SEL_GBE,
+ FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_A_GBE, 4) |
+ FIELD_PREP(AN8801_PHY_PAIR_DLY_SEL_C_GBE, 4));
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_CTRL,
+ AN8801_PHY_RXADC_SAMP_PHSEL_A |
+ AN8801_PHY_RXADC_SAMP_PHSEL_C);
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_0,
+ FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_A, 1));
+ if (ret)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, AN8801_PHY_RXADC_REV_1,
+ FIELD_PREP(AN8801_PHY_RXADC_REV_MASK_C, 1));
+ if (ret)
+ return ret;
+
+ ret = an8801r_rgmii_delay_config(phydev);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_write(phydev, AN8801_BPBUS_REG_CKO,
+ AN8801_CKO_OUTPUT_MODE_AUTO);
+ if (ret)
+ return ret;
+
+ ret = an8801r_led_init(phydev, led_default_function);
+ if (ret) {
+ phydev_err(phydev, "Cannot initialize LEDs: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int an8801r_read_status(struct phy_device *phydev)
+{
+ int prev_speed, ret;
+ u32 val;
+
+ prev_speed = phydev->speed;
+
+ ret = genphy_read_status(phydev);
+ if (ret)
+ return ret;
+
+ if (phydev->link && prev_speed != phydev->speed) {
+ val = phydev->speed == SPEED_1000 ?
+ AN8801_BPBUS_LINK_MODE_1000 : 0;
+
+ return an8801_buckpbus_reg_rmw(phydev,
+ AN8801_BPBUS_REG_LINK_MODE,
+ AN8801_BPBUS_LINK_MODE_1000,
+ val);
+ };
+
+ return 0;
+}
+
+static int an8801r_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct an8801r_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->wake_lnkchg_enabled = true;
+
+ phydev->priv = priv;
+
+ /* Mark this PHY as wakeup capable and register the interrupt as a
+ * wakeup IRQ if the PHY is marked as a wakeup source in devicetree,
+ * and the interrupt is valid.
+ */
+ if (of_property_read_bool(dev->of_node, "wakeup-source") &&
+ phy_interrupt_is_valid(phydev)) {
+ device_set_wakeup_capable(dev, true);
+ devm_pm_set_wake_irq(dev, phydev->irq);
+ }
+
+ return 0;
+}
+
+static int an8801r_suspend(struct phy_device *phydev)
+{
+ struct an8801r_priv *priv = phydev->priv;
+ int ret;
+
+ /* If the PHY may wake up by a wake-on-line event, disable the link
+ * interrupt to only keep the WOL magic interrupt enabled
+ */
+ if (device_may_wakeup(&phydev->mdio.dev)) {
+ priv->wake_lnkchg_enabled = false;
+
+ ret = an8801_buckpbus_reg_clear_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_LNKCHG);
+ if (ret)
+ return ret;
+
+ /* Reset Wol status */
+ ret = an8801r_reset_wake(phydev);
+ if (ret)
+ return ret;
+ }
+
+ if (!phydev->wol_enabled)
+ return genphy_suspend(phydev);
+
+ return 0;
+}
+
+static int an8801r_resume(struct phy_device *phydev)
+{
+ struct an8801r_priv *priv = phydev->priv;
+ int ret;
+
+ ret = genphy_resume(phydev);
+ if (ret)
+ return ret;
+
+ /* Restore the interrupt enable so phylib can receive link
+ * state interrupts.
+ */
+ if (device_may_wakeup(&phydev->mdio.dev)) {
+ priv->wake_lnkchg_enabled = true;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_WAKEUP_CTL1,
+ AN8801_WOL_WAKE_LNKCHG_EN);
+ if (ret)
+ return ret;
+
+ ret = an8801_buckpbus_reg_set_bits(phydev,
+ AN8801_BPBUS_REG_WAKE_IRQ_EN,
+ AN8801_IRQ_WAKE_LNKCHG);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct phy_driver airoha_driver[] = {
+{
+ PHY_ID_MATCH_MODEL(AN8801R_PHY_ID),
+ .name = "Airoha AN8801R",
+ .probe = an8801r_probe,
+ .config_init = an8801r_config_init,
+ .suspend = an8801r_suspend,
+ .resume = an8801r_resume,
+ .config_aneg = genphy_config_aneg,
+ .read_status = an8801r_read_status,
+ .config_intr = an8801r_config_intr,
+ .handle_interrupt = an8801r_handle_interrupt,
+ .set_wol = an8801r_set_wol,
+ .get_wol = an8801r_get_wol,
+ .read_page = air_phy_read_page,
+ .write_page = air_phy_write_page,
+ .flags = PHY_ALWAYS_CALL_SUSPEND,
+ .led_brightness_set = an8801r_led_brightness_set,
+ .led_blink_set = an8801r_led_blink_set,
+ .led_hw_is_supported = an8801r_led_hw_is_supported,
+ .led_hw_control_set = an8801r_led_hw_control_set,
+ .led_hw_control_get = an8801r_led_hw_control_get,
+ .led_polarity_set = an8801r_led_polarity_set,
+} };
+module_phy_driver(airoha_driver);
+
+static struct mdio_device_id __maybe_unused an8801_tbl[] = {
+ { PHY_ID_MATCH_MODEL(AN8801R_PHY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(mdio, an8801_tbl);
+
+MODULE_DESCRIPTION("Airoha AN8801 PHY driver");
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v3 5/9] mfd: mt6397: Add support for MT6392 pmic
From: Lee Jones @ 2026-03-26 12:10 UTC (permalink / raw)
To: Luca Leonardo Scorcia
Cc: linux-mediatek, Fabien Parent, Val Packett, Dmitry Torokhov,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sen Chu,
Sean Wang, Macpaul Lin, Matthias Brugger,
AngeloGioacchino Del Regno, Linus Walleij, Liam Girdwood,
Mark Brown, Julien Massot, Gary Bisson, Louis-Alexis Eyraud,
Chen Zhong, linux-input, devicetree, linux-kernel, linux-pm,
linux-arm-kernel, linux-gpio
In-Reply-To: <20260317184507.523060-6-l.scorcia@gmail.com>
On Tue, 17 Mar 2026, Luca Leonardo Scorcia wrote:
> From: Fabien Parent <parent.f@gmail.com>
>
> Update the MT6397 MFD driver to support 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>
> ---
> drivers/mfd/mt6397-core.c | 46 +++
> 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, 584 insertions(+)
> 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 3e58d0764c7e..c4b86a44c68b 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,6 +26,7 @@
> #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>
>
> #define MT6323_RTC_BASE 0x8000
> @@ -39,6 +41,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 +70,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 +124,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"),
> +};
> +
> 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 +268,26 @@ 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",
> + .of_compatible = "mediatek,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"
> + },
> +};
> +
> static const struct mfd_cell mt6397_devs[] = {
> {
> .name = "mt6397-rtc",
> @@ -335,6 +370,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,
I'm not really sure what came over me when I accepted this 6 years ago,
but I have a _strong_ aversion to MFD data being passed through the OF APIs.
Before this patch lands, please could you refactor this driver to only
pass through an identifier through mt6397_of_match[*].data. Then, you
can match on that via a switch statement where you can allocate each
device's data structures.
This is how the vast majority of MFD drivers work so there should be
lots of examples to work through to make this trivial.
> + .cell_size = ARRAY_SIZE(mt6392_devs),
> + .irq_init = mt6397_irq_init,
> +};
--
Lee Jones [李琼斯]
^ permalink raw reply
* Re: [PATCH v11 03/22] drm: Add new general DRM property "color format"
From: Ville Syrjälä @ 2026-03-26 12:13 UTC (permalink / raw)
To: Dave Stevenson
Cc: Nicolas Frattaroli, Harry Wentland, Leo Li, Rodrigo Siqueira,
Alex Deucher, Christian König, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Sandy Huang, Heiko Stübner,
Andy Yan, Jani Nikula, Rodrigo Vivi, Joonas Lahtinen,
Tvrtko Ursulin, Dmitry Baryshkov, Sascha Hauer, Rob Herring,
Jonathan Corbet, Shuah Khan, kernel, amd-gfx, dri-devel,
linux-kernel, linux-arm-kernel, linux-rockchip, intel-gfx,
intel-xe, linux-doc, Werner Sembach, Andri Yngvason, Marius Vlad
In-Reply-To: <CAPY8ntCRPgN_ayHMGXFv9OrJrdyakUcUT0rvgY5J=FvdCFb6eA@mail.gmail.com>
On Thu, Mar 26, 2026 at 11:16:12AM +0000, Dave Stevenson wrote:
> On Wed, 25 Mar 2026 at 13:43, Ville Syrjälä
> <ville.syrjala@linux.intel.com> wrote:
> >
> > On Wed, Mar 25, 2026 at 12:49:19PM +0000, Dave Stevenson wrote:
> > > On Tue, 24 Mar 2026 at 16:02, Nicolas Frattaroli
> > > <nicolas.frattaroli@collabora.com> wrote:
> > > >
> > > > Add a new general DRM property named "color format" which can be used by
> > > > userspace to request the display driver to output a particular color
> > > > format.
> > > >
> > > > Possible options are:
> > > > - auto (setup by default, driver internally picks the color format)
> > > > - rgb
> > > > - ycbcr444
> > > > - ycbcr422
> > > > - ycbcr420
> > > >
> > > > Drivers should advertise from this list which formats they support.
> > > > Together with this list and EDID data from the sink we should be able
> > > > to relay a list of usable color formats to users to pick from.
> > > >
> > > > Co-developed-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> > > > Co-developed-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Andri Yngvason <andri@yngvason.is>
> > > > Signed-off-by: Marius Vlad <marius.vlad@collabora.com>
> > > > Reviewed-by: Maxime Ripard <mripard@kernel.org>
> > > > Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> > > > ---
> > > > drivers/gpu/drm/drm_atomic_helper.c | 5 ++
> > > > drivers/gpu/drm/drm_atomic_uapi.c | 11 ++++
> > > > drivers/gpu/drm/drm_connector.c | 108 ++++++++++++++++++++++++++++++++++++
> > > > include/drm/drm_connector.h | 104 ++++++++++++++++++++++++++++++++++
> > > > 4 files changed, 228 insertions(+)
> > > >
> > > > diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> > > > index 26953ed6b53e..b7753454b777 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_helper.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_helper.c
> > > > @@ -737,6 +737,11 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
> > > > if (old_connector_state->max_requested_bpc !=
> > > > new_connector_state->max_requested_bpc)
> > > > new_crtc_state->connectors_changed = true;
> > > > +
> > > > + if (old_connector_state->color_format !=
> > > > + new_connector_state->color_format)
> > > > + new_crtc_state->connectors_changed = true;
> > > > +
> > > > }
> > > >
> > > > if (funcs->atomic_check)
> > > > diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > index 5bd5bf6661df..dee510c85e59 100644
> > > > --- a/drivers/gpu/drm/drm_atomic_uapi.c
> > > > +++ b/drivers/gpu/drm/drm_atomic_uapi.c
> > > > @@ -935,6 +935,15 @@ static int drm_atomic_connector_set_property(struct drm_connector *connector,
> > > > state->privacy_screen_sw_state = val;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > state->hdmi.broadcast_rgb = val;
> > > > + } else if (property == connector->color_format_property) {
> > > > + if (val > INT_MAX || !drm_connector_color_format_valid(val)) {
> > > > + drm_dbg_atomic(connector->dev,
> > > > + "[CONNECTOR:%d:%s] unknown color format %llu\n",
> > > > + connector->base.id, connector->name, val);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + state->color_format = val;
> > > > } else if (connector->funcs->atomic_set_property) {
> > > > return connector->funcs->atomic_set_property(connector,
> > > > state, property, val);
> > > > @@ -1020,6 +1029,8 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
> > > > *val = state->privacy_screen_sw_state;
> > > > } else if (property == connector->broadcast_rgb_property) {
> > > > *val = state->hdmi.broadcast_rgb;
> > > > + } else if (property == connector->color_format_property) {
> > > > + *val = state->color_format;
> > > > } else if (connector->funcs->atomic_get_property) {
> > > > return connector->funcs->atomic_get_property(connector,
> > > > state, property, val);
> > > > diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
> > > > index 47dc53c4a738..e848374dee0b 100644
> > > > --- a/drivers/gpu/drm/drm_connector.c
> > > > +++ b/drivers/gpu/drm/drm_connector.c
> > > > @@ -1388,6 +1388,18 @@ static const u32 hdmi_colorspaces =
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_D65) |
> > > > BIT(DRM_MODE_COLORIMETRY_DCI_P3_RGB_THEATER);
> > > >
> > > > +static const u32 hdmi_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > +static const u32 dp_colorformats =
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
> > > > + BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR420);
> > > > +
> > > > /*
> > > > * As per DP 1.4a spec, 2.2.5.7.5 VSC SDP Payload for Pixel Encoding/Colorimetry
> > > > * Format Table 2-120
> > > > @@ -2940,6 +2952,102 @@ int drm_connector_attach_colorspace_property(struct drm_connector *connector)
> > > > }
> > > > EXPORT_SYMBOL(drm_connector_attach_colorspace_property);
> > > >
> > > > +/**
> > > > + * drm_connector_attach_color_format_property - create and attach color format property
> > > > + * @connector: connector to create the color format property on
> > > > + * @supported_color_formats: bitmask of bit-shifted &enum drm_output_color_format
> > > > + * values the connector supports
> > > > + *
> > > > + * Called by a driver to create a color format property. The property is
> > > > + * attached to the connector automatically on success.
> > > > + *
> > > > + * @supported_color_formats should only include color formats the connector
> > > > + * type can actually support.
> > > > + *
> > > > + * Returns:
> > > > + * 0 on success, negative errno on error
> > > > + */
> > > > +int drm_connector_attach_color_format_property(struct drm_connector *connector,
> > > > + unsigned long supported_color_formats)
> > > > +{
> > > > + struct drm_device *dev = connector->dev;
> > > > + struct drm_prop_enum_list enum_list[DRM_CONNECTOR_COLOR_FORMAT_COUNT];
> > > > + unsigned int i = 0;
> > > > + unsigned long fmt;
> > > > +
> > > > + if (connector->color_format_property)
> > > > + return 0;
> > > > +
> > > > + if (!supported_color_formats) {
> > > > + drm_err(dev, "No supported color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + if (supported_color_formats & ~GENMASK(DRM_OUTPUT_COLOR_FORMAT_COUNT - 1, 0)) {
> > > > + drm_err(dev, "Unknown color formats provided on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > +
> > > > + switch (connector->connector_type) {
> > > > + case DRM_MODE_CONNECTOR_HDMIA:
> > > > + case DRM_MODE_CONNECTOR_HDMIB:
> > > > + if (supported_color_formats & ~hdmi_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for HDMI on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + case DRM_MODE_CONNECTOR_DisplayPort:
> > > > + case DRM_MODE_CONNECTOR_eDP:
> > > > + if (supported_color_formats & ~dp_colorformats) {
> > > > + drm_err(dev, "Color formats not allowed for DP on [CONNECTOR:%d:%s]\n",
> > > > + connector->base.id, connector->name);
> > > > + return -EINVAL;
> > > > + }
> > > > + break;
> > > > + }
> > > > +
> > > > + enum_list[0].name = "AUTO";
> > > > + enum_list[0].type = DRM_CONNECTOR_COLOR_FORMAT_AUTO;
> > > > +
> > > > + for_each_set_bit(fmt, &supported_color_formats, DRM_OUTPUT_COLOR_FORMAT_COUNT) {
> > > > + switch (fmt) {
> > > > + case DRM_OUTPUT_COLOR_FORMAT_RGB444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_RGB444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR444:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR444;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR422:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR422;
> > > > + break;
> > > > + case DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > + enum_list[++i].type = DRM_CONNECTOR_COLOR_FORMAT_YCBCR420;
> > > > + break;
> > > > + default:
> > > > + drm_warn(dev, "Unknown supported format %ld on [CONNECTOR:%d:%s]\n",
> > > > + fmt, connector->base.id, connector->name);
> > > > + continue;
> > > > + }
> > > > + enum_list[i].name = drm_hdmi_connector_get_output_format_name(fmt);
> > > > + }
> > > > +
> > > > + connector->color_format_property =
> > > > + drm_property_create_enum(dev, DRM_MODE_PROP_ENUM, "color format",
> > > > + enum_list, i + 1);
> > > > +
> > > > + if (!connector->color_format_property)
> > > > + return -ENOMEM;
> > > > +
> > > > + drm_object_attach_property(&connector->base, connector->color_format_property,
> > > > + DRM_CONNECTOR_COLOR_FORMAT_AUTO);
> > > > +
> > > > + return 0;
> > > > +}
> > > > +EXPORT_SYMBOL(drm_connector_attach_color_format_property);
> > > > +
> > > > /**
> > > > * drm_connector_atomic_hdr_metadata_equal - checks if the hdr metadata changed
> > > > * @old_state: old connector state to compare
> > > > diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
> > > > index af8b92d2d5b7..bd549f912b76 100644
> > > > --- a/include/drm/drm_connector.h
> > > > +++ b/include/drm/drm_connector.h
> > > > @@ -571,14 +571,102 @@ enum drm_colorspace {
> > > > * YCbCr 4:2:2 output format (ie. with horizontal subsampling)
> > > > * @DRM_OUTPUT_COLOR_FORMAT_YCBCR420:
> > > > * YCbCr 4:2:0 output format (ie. with horizontal and vertical subsampling)
> > > > + * @DRM_OUTPUT_COLOR_FORMAT_COUNT:
> > > > + * Number of valid output color format values in this enum
> > > > */
> > > > enum drm_output_color_format {
> > > > DRM_OUTPUT_COLOR_FORMAT_RGB444 = 0,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR444,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR422,
> > > > DRM_OUTPUT_COLOR_FORMAT_YCBCR420,
> > > > + DRM_OUTPUT_COLOR_FORMAT_COUNT,
> > > > };
> > > >
> > > > +/**
> > > > + * enum drm_connector_color_format - Connector Color Format Request
> > > > + *
> > > > + * This enum, unlike &enum drm_output_color_format, is used to specify requests
> > > > + * for a specific color format on a connector through the DRM "color format"
> > > > + * property. The difference is that it has an "AUTO" value to specify that
> > > > + * no specific choice has been made.
> > > > + */
> > > > +enum drm_connector_color_format {
> > > > + /**
> > > > + * @DRM_CONNECTOR_COLOR_FORMAT_AUTO: The driver or display protocol
> > > > + * helpers should pick a suitable color format. All implementations of a
> > > > + * specific display protocol must behave the same way with "AUTO", but
> > > > + * different display protocols do not necessarily have the same "AUTO"
> > > > + * semantics.
> > > > + *
> > > > + * For HDMI, "AUTO" picks RGB, but falls back to YCbCr 4:2:0 if the
> > > > + * bandwidth required for full-scale RGB is not available, or the mode
> > > > + * is YCbCr 4:2:0-only, as long as the mode and output both support
> > > > + * YCbCr 4:2:0.
> > >
> > > Is there a reason you propose dropping back to YCbCr 4:2:0 without
> > > trying YCbCr 4:2:2 first? Minimising the subsampling is surely
> > > beneficial, and vc4 for one can do 4:2:2 but not 4:2:0.
> >
> > On HDMI 4:2:2 is always 12bpc, so it doesn't save any bandwidth
> > compared to 8bpc 4:4:4.
>
> It does save bandwidth against 10 or 12bpc RGB 4:4:4.
>
> Or is the implication that max_bpc = 12 and
> DRM_CONNECTOR_COLOR_FORMAT_AUTO should drop bpc down to 8 and select
> RGB in preference to selecting 4:2:2?
Yeah, YCbCr has all kinds of extra complications compared to RGB, so
the policy is to use RGB if possible, and only fall back to YCbCr as a
last resort. And in that case 4:2:0 is the only thing that can help.
--
Ville Syrjälä
Intel
^ permalink raw reply
* Re: [PATCH v9 0/5] I2C Mux per channel bus speed
From: Marcus Folkesson @ 2026-03-26 12:17 UTC (permalink / raw)
To: Wolfram Sang, Peter Rosin, Michael Hennerich, Bartosz Golaszewski,
Andi Shyti, Andy Shevchenko, Bartosz Golaszewski
Cc: linux-i2c, linux-kernel, linux-arm-kernel
In-Reply-To: <20260324-i2c-mux-v9-0-5292b0608243@gmail.com>
On Tue, Mar 24, 2026 at 02:54:14PM +0100, Marcus Folkesson wrote:
> This was a RFC on how to implement a feature to have different bus
> speeds on different channels with an I2C multiplexer/switch.
> As no major complaints on the design came up during the review, I
> decided to submit the series without the RFC tag.
>
> The benefit with this feature is that you may group devices after
> the fastest bus speed they can handle.
> A real-world example is that you could have e.g. a display running @400kHz
> and a smart battery running @100kHz using the same I2C controller.
>
> There are many corner cases where this may cause a problem for some
> hardware topologies. I've tried to describe those I could think of
> in the documentation, see Patch #5.
>
> E.g. one risk is that if the mux driver does not disconnect channels
> when Idle, this may cause a higher frequency to "leak" through to
> devices that are supposed to run at lower bus speed.
> This is not only a "problem" for changing bus speed but could also be
> an issue for potential address conflicts.
>
> This patchset has been used and tested heavily the last months
> on a custom board based on a da850 (DaVinci) platform.
>
> The implementation is split up into several patches:
>
> Patch #1 Introduce a callback for the i2c controller to set bus speed
> Patch #2 Introduce functionality to adjust bus speed depending on mux
> channel.
> Patch #3 Cleanup i2c-davinci driver a bit to prepare it for set_clk_freq
> Parch #4 Implement set_clk_freq for the i2c-davinci driver
> Parch #5 Update documentation with this feature
>
> Signed-off-by: Marcus Folkesson <marcus.folkesson@gmail.com>
> ---
Peter,
Do you have any feedback on this new approach?
Thanks in advance,
Marcus
^ permalink raw reply
* Re: [PATCH 0/4] Add i.MX94 remoteproc support and reset vector handling improvements
From: Peng Fan @ 2026-03-26 12:20 UTC (permalink / raw)
To: Daniel Baluta
Cc: Mathieu Poirier, Bjorn Andersson, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, linux-remoteproc,
devicetree, imx, linux-arm-kernel, linux-kernel, Peng Fan
In-Reply-To: <80c7815b-26d9-4876-a44f-3e17b6338dc6@oss.nxp.com>
On Wed, Mar 25, 2026 at 10:41:29AM +0200, Daniel Baluta wrote:
>On 3/23/26 16:32, Mathieu Poirier wrote:
>> On Fri, Mar 20, 2026 at 11:19:06AM +0200, Daniel Baluta wrote:
>>> On 3/12/26 14:36, Peng Fan (OSS) wrote:
>>>> This series adds remoteproc support for the i.MX94 family, including the
>>>> CM70, CM71, and CM33S cores, and introduces a new device‑tree property to
>>>> correctly derive the hardware reset vector for Cortex‑M processors whose
>>>> ELF entry point does not directly correspond to the actual reset address.
>>>>
>>>> Background:
>>>> Cortex‑M processors fetch their initial SP and PC from a fixed reset vector
>>>> table. While ELF images embed the entry point (e_entry), this value is
>>>> not always aligned to the hardware reset address. On platforms such as
>>>> i.MX94 CM33S, masking is required to compute the correct reset vector
>>>> address before programming the SoC reset registers.
>>> What happens if the reset vector is at 0 and the e_entry point is at 0x800...?
>>>
>>> In this case masking will no longer work! Can we implement a generic approach?
>>>
>> I will wait to see an R-B from Daniel before looking at this set.
>>
>> Thanks,
>> Mathieu
>>
>>
>Hi Mathieu, Peng,
>
>Patchseries mostly looks good to me. The only blocking issue here is how to correctly specify the hardware reset address.
>
>I see two options here:
>
>1) Create a special section in TCM that holds the PC/Stack initial value as concluded here [1]. But this
>
>doesn't work in all the cases
>
>2) Add a per device data that holds the hardware reset mask that gets applied to entry address read from ELF.
>
>I'm fine going with option 2) and that's because this change is IMX rproc driver specific, it scales well and will be maintained by Peng.
Thanks, I will go with option 2.
Thanks
Peng
>
>thanks,
>
>Daniel.
>
>[1] https://lore.kernel.org/linux-remoteproc/38476dd0-07a6-310f-1fba-2b3021a5b007@kontron.de/
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox