* [PATCH net-next v4 0/2] airoha: add the capability to configure GDM3/GDM4 as WAN/LAN on demand
From: Lorenzo Bianconi @ 2026-06-10 13:33 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lorenzo Bianconi
Cc: linux-arm-kernel, linux-mediatek, netdev, Madhur Agrawal
Add the capability to configure GDM3/GDM4 as WAN/LAN on demand when QoS
offload is created or destroyed.
Make dev->qdma an RCU pointer so the TX path can safely dereference it
without holding RTNL.
Introduce airoha_qdma_start() and airoha_qdma_stop() helpers.
---
Changes in v4:
- Move back QDMA TX/RX DMA enable to airoha_dev_open()/airoha_dev_stop().
- Configure GDM3/4 as WAN if GDM2 is not available in ndo_init()
callback.
- Protect qdma pointer in airoha_gdm_dev struct using RCU.
- Rely on rtnl_dereference() to access qdma pointer in the control path.
- Add airoha_qdma_start() and airoha_qdma_stop() utility routines in
patch 1/2
- Link to v3: https://lore.kernel.org/r/20260608-airoha-ethtool-priv_flags-v3-1-3e8e3dc3f715@kernel.org
Changes in v3:
- Do not introduce ethtool private flags support to configure LAN/WAN
for GDM3/4 and rely on tc qdisc offload for it instead.
- Set GDM3/4 ports as LAN by default.
- Move QDMA TX/RX DMA enable from airoha_dev_open() to airoha_probe()
and the corresponding disable from airoha_dev_stop() to airoha_qdma_cleanup().
- Link to v2: https://lore.kernel.org/r/20260607-airoha-ethtool-priv_flags-v2-1-742c7aa1e182@kernel.org
Changes in v2:
- Rework airoha_dev_set_wan_flag routine
- Enable GDM_STRIP_CRC_MASK in airoha_disable_gdm2_loopback()
- Do not always reset REG_SRC_PORT_FC_MAP6 in
airoha_disable_gdm2_loopback() but use the same condition used in
airoha_enable_gdm2_loopback().
- Link to v1: https://lore.kernel.org/r/20260606-airoha-ethtool-priv_flags-v1-1-401b2c9fe9f1@kernel.org
---
Lorenzo Bianconi (2):
net: airoha: refactor QDMA start/stop into reusable helpers
net: airoha: defer GDM3/GDM4 WAN mode and GDM2 loopback to QoS offload
drivers/net/ethernet/airoha/airoha_eth.c | 273 +++++++++++++++++++++++++-----
drivers/net/ethernet/airoha/airoha_eth.h | 24 ++-
drivers/net/ethernet/airoha/airoha_ppe.c | 18 +-
drivers/net/ethernet/airoha/airoha_regs.h | 1 +
4 files changed, 267 insertions(+), 49 deletions(-)
---
base-commit: 5855479abc796c3b5d7b2f2ca147d68fc56cae1f
change-id: 20260606-airoha-ethtool-priv_flags-b6aa70caa780
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply
* Re: [PATCH v9 6/7] pinctrl: s32cc: implement GPIO functionality
From: Khristine Andreea Barbulescu @ 2026-06-10 13:33 UTC (permalink / raw)
To: Linus Walleij
Cc: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla,
Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <CAD++jLme25qcWpzVa44VwTmnAf+Rt7suF8DgUs5tGyM_UyNbyw@mail.gmail.com>
On 6/9/2026 1:33 AM, Linus Walleij wrote:
> Hi Khristine,
>
> On Tue, Jun 2, 2026 at 10:05 AM Khristine Andreea Barbulescu
> <khristineandreea.barbulescu@oss.nxp.com> wrote:
>
>> The new version (v10) has been updated to use gpio-regmap, with a virtual
>> regmap bridge dispatching GPIO accesses to the underlying SIUL2 register
>> blocks.
>>
>> I am not fully convinced this is the cleanest model, though.
>> SIUL2 does not expose GPIO as one regular register space: direction is in
>> MSCR, input values are read from PGPDI, and output values are written through
>> PGPDO. These are backed by separate regmaps in the driver, while gpio-regmap
>> expects a single regmap.
>
> OK I did miss that detail earlier, I definitely thought it was using a single
> regmap.
>
>> So the current path becomes:
>> gpio-regmap -> virtual regmap -> MSCR/PGPDI/PGPDO regmap
>>
>> The version was updated this way so we can review the approach on top of the
>> current code. If this is still the preferred direction, it can be polished
>> further. Otherwise, I think direct gpio_chip callbacks using the existing regmap
>> helpers might be a simpler fit for this hardware.
>>
>> What do you think would be the preferred direction for the next revision?
>
> I'm pretty much happy with either version.
>
> I see your point as to why you don't want to use gpio-regmap.
>
> I also think the virtual regmap thing looks pretty OK, it's complex
> but the driver is complex anyway.
>
> What could make the gpio-regmap approach is that it will probably
> get extended with get/set_multiple() at some point and then you
> will get that improvement for free.
>
> But I think you are the best person to choose what to use here,
> if you don't think the virtual regmap looks good, then trust your
> intuition and go back to the old design.
>
> Yours,
> Linus Walleij
Hi Linus,
Thank you for the feedback!
Since you consider that the current virtual regmap approach
looks fine and also highlighted the future improvement we
would get with get/set_multiple() in the future, I will
keep the gpio-regmap approach for now.
Best regards, Khristine
^ permalink raw reply
* Re: [PATCH 17/37] drm/display: bridge-connector: protect dynconn creation and destruction with a mutex
From: Luca Ceresoli @ 2026-06-10 13:30 UTC (permalink / raw)
To: Maxime Ripard, Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Inki Dae, Jagan Teki,
Marek Szyprowski, Marek Vasut, Stefan Agner, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel
In-Reply-To: <20260608-garrulous-silver-junglefowl-ea4dbe@houat>
On Mon Jun 8, 2026 at 1:49 PM CEST, Maxime Ripard wrote:
> On Tue, May 19, 2026 at 12:37:34PM +0200, Luca Ceresoli wrote:
>> Bridge hotplug will make the connector dynamically created and destroyed
>> based on hotplug events.
>>
>> In preparation for that, add a mutex to mutually exclude connector creation
>> and destruction.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>
> What is the source of concurrency, and what are you protecting against
> exactly with that lock?
With bridge hotplug, the connector creation and destruction can be
triggered by different code paths, so we need to prevent to:
* start destroying a connector that has not been created fully yet
* start creating a connector while the previous one is still
being destroyed
Both conditions might happen startig with patch 36.
So I guess I'll just squash this patch into patch 36. The commit message
will become quite verbose but it amkes sense to do it all at once.
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* Re: [PATCH 4/4] ASoC: meson: aiu: use aiu-formatter-i2s to format I2S output data
From: Jerome Brunet @ 2026-06-10 13:27 UTC (permalink / raw)
To: Valerio Setti
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Neil Armstrong,
Kevin Hilman, Martin Blumenstingl, linux-kernel, linux-sound,
linux-arm-kernel, linux-amlogic, Mark Brown
In-Reply-To: <a5aa2965-3651-4927-acff-51eee2e4ab4a@baylibre.com>
On jeu. 28 mai 2026 at 17:01, Valerio Setti <vsetti@baylibre.com> wrote:
> On 5/22/26 18:24, Valerio Setti wrote:
>> On 5/22/26 01:15, Mark Brown wrote:
>>> On Fri, May 15, 2026 at 05:10:40PM +0200, Valerio Setti wrote:
>>>> Create a new DAPM widget for "I2S formatter" and place it on the path
>>>> between FIFO and output DAI interface. Remove I2S output formatting code
>>>> from aiu-encoder-i2s since it's now implemented from aiu-formatter-i2s.
>>>
>>> This series, it looks like this specific patch, is breaking pcm-test on
>>> my libretech Le Potato board, the clocking looks to be seriously messed
>>> up. I'm getting:
>>>
>>> [...]
>>>
>>> Full log:
>>>
>>> https://lava.sirena.org.uk/scheduler/job/2786342#L1934
>>>
>>> The prior patches seem to test fine, it's this one that seems to
>>> introduce the issue.
>> Thanks a lot for the heads up and please apologize for the problem.
>> I wasn't aware of these testing tools so I based my testing on playing
>> with userspace alsa tools on the physical board that I have.
>> I will take a look at it ASAP and send a properly tested v2.
>>
>
> Hi!
>
> I investigated a bit on the issue caused by my v1 patch series and I think
> I've found the root cause. I suspect my patch series helped discovering a
> misbehavior that was already present, so I'm seeking for suggestions on the
> proper way to proceed.
>
> # First: the background
>
> By default on OdroidC2/LePotato boards the only available audio playback is
> through HDMI. From DAI point of view the flow is as follows:
>
> "I2S FIFO" -> "I2S Encoder Playback" -> "CODEC CTRL HDMI I2S IN" -> "HDMI
> CTRL SRC" (mixer) -> "CODEC CTRL HDMI OUT Capture"
>
> In this chain the mixer "HDMI CTRL SRC" by default starts as "DISABLED" so
> it should prevent "CODEC CTRL HDMI OUT Capture" from receiving data.
Yes, leaving registers to their default state (even if it is not a
working configuration) and relying on mixer path to be setup was done on
purpose.
There is not a single configuration that would work/please everyone,
especially on AXG but the same could be said about the GX
series.
Not hardcoding any such configuration in the driver was the only sane
choice, even if it may seem to weird to have pipelines that do not work
by default.
>
> # What changed before/after the last commit of my patch series?
>
> - Before: "aiu-encoder-i2s.c" was calling "aiu_encoder_i2s_setup_desc()" in
> "hw_params()". Audio playback shouldn't work in this condition because as
> I mentioned "HDMI CTRL SRC"="DISABLED" by default, but apparently
> configuring the AIU_I2S_SOURCE_DESC register is enough to make the
> playback to work properly.
Nice :'(
>
> - After: those configurations are only set when "aiu_formatter_i2s_prepare"
> is called which happens if "I2S Formatter" widget is enabled. Since "HDMI
> CTRL SRC"="DISABLED" then "I2S Formatter" is not powered up and therefore
> its callbacks are not called and the playback fails.
>
> Simply issuing the following command:
> $ amixer sset 'AIU HDMI CTRL SRC' 'I2S'
>
> resolves the problem and all pcm-tests pass.
> This also explains why I didn't catch this issue before sending the v1
> series: I tested with NXP SGTL5000 codec, not the HDMI one.
>
> # Final question
>
> I have 2 alternative proposals for this:
>
> - Change the default value of "HDMI CTRL SRC" so that at boot it's set to
> some working configuration (ex: "I2S"). This should be done somewhere in
> "aiu-codec-ctrl" I think.
> - Run the 'amixer' command above before running ALSA tests.
>
> Any suggestion on what's the best approach?
As Mark suggested, let be nice on the user and poke the register on
probe. Just add a big fat comment around it so it is clear why you are
doing it (and why it is not something to be copied)
>
> Thanks a lot.
--
Jerome
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: remoteproc: imx_rproc: document optional "memory-region-names"
From: Laurentiu Mihalcea @ 2026-06-10 13:27 UTC (permalink / raw)
To: Francesco Dolcini
Cc: Krzysztof Kozlowski, Bjorn Andersson, Mathieu Poirier,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Sascha Hauer,
Peng Fan, Fabio Estevam, Daniel Baluta, linux-remoteproc,
devicetree, imx, linux-arm-kernel, linux-kernel
In-Reply-To: <aik69L0xCW13TCZE@gaggiata.pivistrello.it>
On 6/10/2026 3:22 AM, Francesco Dolcini wrote:
> On Wed, Jun 10, 2026 at 02:10:37AM -0700, Laurentiu Mihalcea wrote:
>>
>>
>> On 6/10/2026 12:37 AM, Krzysztof Kozlowski wrote:
>>> On Fri, Jun 05, 2026 at 04:36:18AM -0700, Laurentiu Mihalcea wrote:
>>>> From: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
>>>>
>>>> The names of the carveout regions are derived using the names of the
>>>> reserved memory devicetree nodes, which are referenced using the
>>>> "memory-region" property. This adds a restriction on the names of said
>>>> devicetree nodes, often bearing specific names such as: "vdevbuffer",
>>>> "vdev0vring0", "rsc-table", etc... This goes against the devicetree
>>>> specification's recommendation, which states that the devicetree node
>>>> names should be generic.
>>>
>>> No, it does not. Names like rsc-table feels exactly like DT spec is
>>> asking - for a name matching purpose. Are you sure you read the spec?
>>
>> Quoting from the spec:
>>
>> "The name of a node should be somewhat generic, reflecting the function of the
>> device and not its precise programming model"
>>
>> and looking at the examples provided in "2.2.2 Generic Names Recommendation",
>> wouldn't "memory" be a more appropriate choice for the DT node name instead of
>> "rsc-table" since it's more generic, while still matching the purpose
>> of the device? Or perhaps I'm interpreting this the wrong way?
>
> Please see
> https://lore.kernel.org/all/CAL_JsqKRW-=er+DCTob0HmQv9OyVt7yiej-Yht6UR-mcW=LHUg@mail.gmail.com/
Thanks for the link, Francesco! Things are a bit clearer now. Based on this and the
comments I've received so far, I'll drop the binding and rproc driver-related changes
in V3.
^ permalink raw reply
* [PATCH net-next v2] net: airoha: simplify WAN device check in airoha_dev_init()
From: Lorenzo Bianconi @ 2026-06-10 13:25 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Lorenzo Bianconi
Cc: linux-arm-kernel, linux-mediatek, netdev
airoha_register_gdm_devices() iterates eth->ports[] in order, so GDM2's
netdev is always registered before GDM3/GDM4. This means the explicit
check for eth->ports[1] && eth->ports[1]->devs[0] is a redundant
special-case of what airoha_get_wan_gdm_dev() already covers, since
GDM2 is always marked as WAN during its own ndo_init.
Remove the redundant check and rely solely on airoha_get_wan_gdm_dev()
which handles both the GDM2-present and GDM2-absent cases.
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
---
Changes in v2:
- Rebase on top of net-next.
- Link to v1: https://lore.kernel.org/r/20260606-airoha-eth-simplify-dev-init-v1-1-f08f8e404049@kernel.org
---
drivers/net/ethernet/airoha/airoha_eth.c | 12 ++----------
1 file changed, 2 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c
index 5a8e84fa9918..b333a7b309c2 100644
--- a/drivers/net/ethernet/airoha/airoha_eth.c
+++ b/drivers/net/ethernet/airoha/airoha_eth.c
@@ -2004,18 +2004,10 @@ static int airoha_dev_init(struct net_device *netdev)
switch (port->id) {
case AIROHA_GDM3_IDX:
- case AIROHA_GDM4_IDX: {
- struct airoha_eth *eth = dev->eth;
-
- /* GDM2 supports a single net_device */
- if (eth->ports[1] && eth->ports[1]->devs[0])
- break;
-
- if (airoha_get_wan_gdm_dev(eth))
+ case AIROHA_GDM4_IDX:
+ if (airoha_get_wan_gdm_dev(dev->eth))
break;
-
fallthrough;
- }
case AIROHA_GDM2_IDX:
/* GDM2 is always used as wan */
dev->flags |= AIROHA_PRIV_F_WAN;
---
base-commit: 5855479abc796c3b5d7b2f2ca147d68fc56cae1f
change-id: 20260606-airoha-eth-simplify-dev-init-5d53c7cc004e
Best regards,
--
Lorenzo Bianconi <lorenzo@kernel.org>
^ permalink raw reply related
* Re: [PATCH 18/37] drm/bridge: samsung-dsim: remove the panel_bridge on host_detach
From: Luca Ceresoli @ 2026-06-10 13:24 UTC (permalink / raw)
To: Maxime Ripard, Luca Ceresoli
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Inki Dae, Jagan Teki,
Marek Szyprowski, Marek Vasut, Stefan Agner, Frank Li,
Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Hui Pu,
Ian Ray, Thomas Petazzoni, dri-devel, linux-kernel, imx,
linux-arm-kernel
In-Reply-To: <20260608-nano-kangaroo-of-piety-b5ab3d@houat>
On Mon Jun 8, 2026 at 1:53 PM CEST, Maxime Ripard wrote:
> On Tue, May 19, 2026 at 12:37:35PM +0200, Luca Ceresoli wrote:
>> In preparation for DRM bridge hot-plugging, we need to handle the dynamic
>> lifetime of the following bridge in case the samsung-dsim is always present
>> and the following bridge (next_bridge) is hot-unplugged.
>>
>> Based on the 'if (!IS_ERR(panel))' check in samsung_dsim_host_attach(), the
>> next_bridge could be A) a panel bridge created by this driver via
>> devm_drm_panel_bridge_add() or B) a pre-existing bridge obtained via
>> of_drm_find_and_get_bridge().
>>
>> For case B) we need to put that reference when the next_bridge is removed,
>> which is already handled by calling drm_bridge_clear_and_put() in
>> samsung_dsim_host_detach() and in the samsung_dsim_host_attach() error
>> management code.
>>
>> In case A) we additionally have to remove the panel bridge. Currently it is
>> created by devm_drm_panel_bridge_add(), which adds two devm actions with
>> the refcounted panel bridge:
>>
>> - drm_bridge_put_void() via devm_drm_bridge_alloc() on panel->dev
>> - devm_drm_panel_bridge_release() via devm_drm_panel_bridge_add_typed()
>> on the consumer device (samsung-dsim)
>>
>> The first action is OK: being tied to panel->dev it will happen when the
>> panel is unplugged.
>>
>> The second action is bound to the consumer device, so the devm semantics is
>> not useful here when introducing hotplug. Indeed we need to drop the
>> next_bridge in samsung_dsim_host_detach() anyway, before the driver .remove
>> function, in order to support {add, {attach, detach} x N, remove} hotplug
>> event sequences.
>>
>> Thus move to the non-devm drm_panel_bridge_add() along with the matching
>> drm_panel_bridge_remove(), so the lifetime of the panel-bridge is tied to
>> the host_attach/host_detach cycle and not the whole samsung-dsim device
>> lifetime.
>>
>> Signed-off-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
>>
>> ---
>>
>> In a previous discussion with Maxime he mentioned a plan to make every
>> drm_panel always have a wrapping bridge. With that done, all the code
>> handling the panel and adding the panel_bridge would become useless here
>> (and in many other places) and could be entirely removed. This patch is a
>> temporary solution until that happens. The best pointer I could find to
>> that discussion is [0], but there might be more recent material I could not
>> find at the moment.
>>
>> [0] https://lore.kernel.org/lkml/20250218-faithful-white-magpie-da9ac9@houat/
>> ---
>> drivers/gpu/drm/bridge/samsung-dsim.c | 17 ++++++++++++++---
>> include/drm/bridge/samsung-dsim.h | 2 ++
>> 2 files changed, 16 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
>> index 5b799619e07e..2af287221e22 100644
>> --- a/drivers/gpu/drm/bridge/samsung-dsim.c
>> +++ b/drivers/gpu/drm/bridge/samsung-dsim.c
>> @@ -1951,14 +1951,16 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>> if (!remote)
>> return -ENODEV;
>>
>> + dsi->panel_bridge_added = false;
>> panel = of_drm_find_panel(remote);
>> if (!IS_ERR(panel)) {
>> - next_bridge = devm_drm_panel_bridge_add(dev, panel);
>> + next_bridge = drm_panel_bridge_add(panel);
>> if (IS_ERR(next_bridge)) {
>> ret = PTR_ERR(next_bridge);
>> next_bridge = NULL; // Inhibit the cleanup action on an ERR_PTR
>> } else {
>> drm_bridge_get(next_bridge);
>> + dsi->panel_bridge_added = true;
>> }
>> } else {
>> next_bridge = of_drm_find_and_get_bridge(remote);
>> @@ -1989,7 +1991,7 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>> if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO)) {
>> ret = samsung_dsim_register_te_irq(dsi, &device->dev);
>> if (ret)
>> - goto err_remove_bridge;
>> + goto err_remove_panel_bridge;
>> }
>>
>> // The next bridge can be used by host_ops->attach
>> @@ -2011,8 +2013,12 @@ static int samsung_dsim_host_attach(struct mipi_dsi_host *host,
>> drm_bridge_clear_and_put(&dsi->bridge.next_bridge);
>> if (!(device->mode_flags & MIPI_DSI_MODE_VIDEO))
>> samsung_dsim_unregister_te_irq(dsi);
>> -err_remove_bridge:
>> +err_remove_panel_bridge:
>> drm_bridge_remove(&dsi->bridge);
>> + if (dsi->panel_bridge_added) {
>> + drm_panel_bridge_remove(next_bridge);
>> + dsi->panel_bridge_added = false;
>> + }
>
> This is a pretty big abstraction leak. We don't want to have that in
> everything driver. The removal path should be the same for both cases,
> and it's not something the driver should take care of.
Yes. The comment after the '---' separator was meant to discuss this
concern:
> In a previous discussion with Maxime he mentioned a plan to make every
> drm_panel always have a wrapping bridge. With that done, all the code
> handling the panel and adding the panel_bridge would become useless here
> (and in many other places) and could be entirely removed. This patch is a
> temporary solution until that happens. The best pointer I could find to
> that discussion is [0], but there might be more recent material I could not
> find at the moment.
Do you have any update about that plan?
Luca
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply
* [PATCH v4 2/2] pmdomain: imx: Fix i.MX8MP VC8000E power up sequence
From: Peng Fan (OSS) @ 2026-06-10 14:39 UTC (permalink / raw)
To: Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Daniel Baluta
Cc: linux-pm, imx, linux-arm-kernel, linux-kernel, Peng Fan, stable
In-Reply-To: <20260610-b4-imx8mp-vc8000e-pm-v4-1-v4-0-ea58ce929c84@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Per errata[1]:
ERR050531: VPU_NOC power down handshake may hang during VC8000E/VPUMIX
power up/down cycling.
Description: VC8000E reset de-assertion edge and AXI clock may have a
timing issue.
Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off
both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to
VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is
de-asserted by HW)
Add a bool variable is_errata_err050531 in
'struct imx8m_blk_ctrl_domain_data' to represent whether the workaround
is needed. If is_errata_err050531 is true, first clear the clk before
powering up gpc, then enable the clk after powering up gpc.
[1] https://www.nxp.com/webapp/Download?colCode=IMX8MP_1P33A
Fixes: a1a5f15f7f6cb ("soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl")
Cc: stable@vger.kernel.org
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/pmdomain/imx/imx8m-blk-ctrl.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index e13a47eeed75..99d100e1d923 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -54,6 +54,15 @@ struct imx8m_blk_ctrl_domain_data {
* register.
*/
u32 mipi_phy_rst_mask;
+
+ /*
+ * VC8000E reset de-assertion edge and AXI clock may have a timing issue.
+ * Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off
+ * both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to
+ * VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is
+ * de-asserted by HW)
+ */
+ bool is_errata_err050531;
};
#define DOMAIN_MAX_CLKS 4
@@ -108,7 +117,11 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
dev_err(bc->dev, "failed to enable clocks\n");
goto bus_put;
}
- regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+
+ if (data->is_errata_err050531)
+ regmap_clear_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+ else
+ regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
/* power up upstream GPC domain */
ret = pm_runtime_get_sync(domain->power_dev);
@@ -117,6 +130,9 @@ static int imx8m_blk_ctrl_power_on(struct generic_pm_domain *genpd)
goto clk_disable;
}
+ if (data->is_errata_err050531)
+ regmap_set_bits(bc->regmap, BLK_CLK_EN, data->clk_mask);
+
/* wait for reset to propagate */
udelay(5);
@@ -511,6 +527,7 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[]
.clk_mask = BIT(2),
.path_names = (const char *[]){"vc8000e"},
.num_paths = 1,
+ .is_errata_err050531 = true,
},
};
--
2.51.0
^ permalink raw reply related
* [PATCH v4 1/2] pmdomain: imx: Fix i.MX8MP power notifier
From: Peng Fan (OSS) @ 2026-06-10 14:39 UTC (permalink / raw)
To: Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Daniel Baluta
Cc: linux-pm, imx, linux-arm-kernel, linux-kernel, Peng Fan, stable
In-Reply-To: <20260610-b4-imx8mp-vc8000e-pm-v4-1-v4-0-ea58ce929c84@nxp.com>
From: Peng Fan <peng.fan@nxp.com>
Using imx8mm_vpu_power_notifier() for i.MX8MP is wrong, as it ungates
the VPU clocks to provide the ADB clock, which is necessary on i.MX8MM,
but on i.MX8MP there is a separate gate (bit 3) for the NoC. So add
imx8mp_vpu_power_notifier() for i.MX8MP.
Fixes: a1a5f15f7f6cb ("soc: imx: imx8m-blk-ctrl: add i.MX8MP VPU blk ctrl")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
drivers/pmdomain/imx/imx8m-blk-ctrl.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/drivers/pmdomain/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
index 19e992d2ee3b..e13a47eeed75 100644
--- a/drivers/pmdomain/imx/imx8m-blk-ctrl.c
+++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c
@@ -514,9 +514,34 @@ static const struct imx8m_blk_ctrl_domain_data imx8mp_vpu_blk_ctl_domain_data[]
},
};
+static int imx8mp_vpu_power_notifier(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl,
+ power_nb);
+
+ if (action == GENPD_NOTIFY_ON) {
+ /*
+ * On power up we have no software backchannel to the GPC to
+ * wait for the ADB handshake to happen, so we just delay for a
+ * bit. On power down the GPC driver waits for the handshake.
+ */
+
+ udelay(5);
+
+ /* set "fuse" bits to enable the VPUs */
+ regmap_set_bits(bc->regmap, 0x8, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0xc, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0x10, 0xffffffff);
+ regmap_set_bits(bc->regmap, 0x14, 0xffffffff);
+ }
+
+ return NOTIFY_OK;
+}
+
static const struct imx8m_blk_ctrl_data imx8mp_vpu_blk_ctl_dev_data = {
.max_reg = 0x18,
- .power_notifier_fn = imx8mm_vpu_power_notifier,
+ .power_notifier_fn = imx8mp_vpu_power_notifier,
.domains = imx8mp_vpu_blk_ctl_domain_data,
.num_domains = ARRAY_SIZE(imx8mp_vpu_blk_ctl_domain_data),
};
--
2.51.0
^ permalink raw reply related
* [PATCH v4 0/2] pmdomain: imx: Fix i.MX8MP VC8000E power up sequence
From: Peng Fan (OSS) @ 2026-06-10 14:39 UTC (permalink / raw)
To: Ulf Hansson, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Daniel Baluta
Cc: linux-pm, imx, linux-arm-kernel, linux-kernel, Peng Fan, stable
There is an errata for i.MX8MP VC8000E:
ERR050531: VPU_NOC power down handshake may hang during VC8000E/VPUMIX
power up/down cycling.
Description: VC8000E reset de-assertion edge and AXI clock may have a
timing issue.
Workaround: Set bit2 (vc8000e_clk_en) of BLK_CLK_EN_CSR to 0 to gate off
both AXI clock and VC8000E clock sent to VC8000E and AXI clock sent to
VPU_NOC m_v_2 interface during VC8000E power up(VC8000E reset is
de-asserted by HW)
This patchset is to fix the errata. More info could be found in each
patch commit.
Sorry for sending v4 at 7.1-rc7, no rush for 7.1.
Signed-off-by: Peng Fan <peng.fan@nxp.com>
---
Changes in v4:
- Add R-b
- Set is_errata_err050531 to true for vc8000e
- Link to v3: https://lore.kernel.org/r/20260409-imx8mp-vc8000e-pm-v3-0-3e023eaa245b@nxp.com
Changes in v3:
- Separate power up notifier fix into patch 1
- Link to v2: https://lore.kernel.org/r/20260228-imx8mp-vc8000e-pm-v2-1-fd255a0d5958@nxp.com
Changes in v2:
- Add errata link in commit message
- Add comment for is_errata_err050531
- Link to v1: https://lore.kernel.org/r/20260128-imx8mp-vc8000e-pm-v1-1-6c171451c732@nxp.com
---
Peng Fan (2):
pmdomain: imx: Fix i.MX8MP power notifier
pmdomain: imx: Fix i.MX8MP VC8000E power up sequence
drivers/pmdomain/imx/imx8m-blk-ctrl.c | 46 +++++++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
---
base-commit: 49e02880ec0a8c378e811bc9d85da188d7c6204c
change-id: 20260610-b4-imx8mp-vc8000e-pm-v4-1-a978b40c59d0
Best regards,
--
Peng Fan <peng.fan@nxp.com>
^ permalink raw reply
* [PATCH v11 5/6] pinctrl: s32cc: implement GPIO functionality
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
From: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
The updated SIUL2 block groups pinctrl, GPIO data access
and interrupt control within the same hardware unit.
The SIUL2 driver is therefore structured as a monolithic
pinctrl/GPIO driver.
GPIO data access and direction handling are implemented using the
gpio-regmap library backed by a virtual regmap. The virtual regmap
translates the gpio-regmap register model to the underlying SIUL2
registers: MSCR for direction, PGPDI for input values and PGPDO for
output values.
The existing pinctrl GPIO callbacks are used for the request/free path:
they switch the pad to GPIO mode on request and restore the previous
MSCR configuration when the GPIO is released.
This change came as a result of upstream review in the
following series:
https://lore.kernel.org/linux-gpio/20260120115923.3463866-4-khristineandreea.barbulescu@oss.nxp.com/T/#m543c9edbdde74bdc68b6a2364e8b975356c33043
https://lore.kernel.org/all/20260504131148.3622697-7-khristineandreea.barbulescu@oss.nxp.com/
Support both SIUL2 DT layouts:
- legacy pinctrl-only binding
- extended pinctrl/GPIO/irqchip binding
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
drivers/pinctrl/nxp/Kconfig | 3 +-
drivers/pinctrl/nxp/pinctrl-s32.h | 35 +-
drivers/pinctrl/nxp/pinctrl-s32cc.c | 709 +++++++++++++++++++++++++---
drivers/pinctrl/nxp/pinctrl-s32g2.c | 47 +-
4 files changed, 721 insertions(+), 73 deletions(-)
diff --git a/drivers/pinctrl/nxp/Kconfig b/drivers/pinctrl/nxp/Kconfig
index abca7ef97003..711c0fe11565 100644
--- a/drivers/pinctrl/nxp/Kconfig
+++ b/drivers/pinctrl/nxp/Kconfig
@@ -1,10 +1,11 @@
# SPDX-License-Identifier: GPL-2.0-only
config PINCTRL_S32CC
bool
- depends on ARCH_S32 && OF
+ depends on ARCH_S32 && OF && GPIOLIB
select GENERIC_PINCTRL_GROUPS
select GENERIC_PINMUX_FUNCTIONS
select GENERIC_PINCONF
+ select GPIO_REGMAP
select REGMAP_MMIO
config PINCTRL_S32G2
diff --git a/drivers/pinctrl/nxp/pinctrl-s32.h b/drivers/pinctrl/nxp/pinctrl-s32.h
index 8715befd5f05..028578a090e4 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32.h
+++ b/drivers/pinctrl/nxp/pinctrl-s32.h
@@ -2,7 +2,7 @@
*
* S32 pinmux core definitions
*
- * Copyright 2016-2020, 2022 NXP
+ * Copyright 2016-2020, 2022, 2026 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
* Copyright (C) 2012 Linaro Ltd.
@@ -34,11 +34,42 @@ struct s32_pin_range {
unsigned int end;
};
+/**
+ * struct s32_gpio_range - contiguous GPIO pin range within a SIUL2 module
+ * @gpio_base: first GPIO line offset in the GPIO range
+ * @pin_base: first pinctrl pin number mapped by this GPIO range
+ * @gpio_num: number of consecutive GPIO pins in the range
+ * @sparse: true if the PGPD layout is non-linear (resolved via pad map only);
+ * pins not found in the pad map are invalid for this range
+ */
+struct s32_gpio_range {
+ unsigned int gpio_base;
+ unsigned int pin_base;
+ unsigned int gpio_num;
+ bool sparse;
+};
+
+/**
+ * struct s32_gpio_pad_map - mapping between GPIO ranges and PGPD pads
+ * @gpio_start: first GPIO line offset in the range
+ * @gpio_end: last GPIO line offset in the range
+ * @pad: PGPD pad number serving the range
+ */
+struct s32_gpio_pad_map {
+ unsigned int gpio_start;
+ unsigned int gpio_end;
+ unsigned int pad;
+};
+
struct s32_pinctrl_soc_data {
const struct pinctrl_pin_desc *pins;
unsigned int npins;
const struct s32_pin_range *mem_pin_ranges;
unsigned int mem_regions;
+ const struct s32_gpio_range *gpio_ranges;
+ unsigned int num_gpio_ranges;
+ const struct s32_gpio_pad_map *gpio_pad_maps;
+ unsigned int num_gpio_pad_maps;
};
struct s32_pinctrl_soc_info {
@@ -53,6 +84,8 @@ struct s32_pinctrl_soc_info {
#define S32_PINCTRL_PIN(pin) PINCTRL_PIN(pin, #pin)
#define S32_PIN_RANGE(_start, _end) { .start = _start, .end = _end }
+#define S32_GPIO_RANGE(gpio, pin, num) \
+ { .gpio_base = gpio, .pin_base = pin, .gpio_num = num }
int s32_pinctrl_probe(struct platform_device *pdev,
const struct s32_pinctrl_soc_data *soc_data);
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 89a4eb2000ee..b8fb0db42949 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -2,7 +2,7 @@
/*
* Core driver for the S32 CC (Common Chassis) pin controller
*
- * Copyright 2017-2022,2024 NXP
+ * Copyright 2017-2022,2024-2026 NXP
* Copyright (C) 2022 SUSE LLC
* Copyright 2015-2016 Freescale Semiconductor, Inc.
*/
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
+#include <linux/gpio/regmap.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -39,6 +40,40 @@
#define S32_MSCR_ODE BIT(20)
#define S32_MSCR_OBE BIT(21)
+#define S32_GPIO_OP_SHIFT 16
+#define S32_GPIO_OP_MASK GENMASK(19, 16)
+
+#define S32_GPIO_OP_DIR 0 /* MSCR direction */
+#define S32_GPIO_OP_DAT BIT(S32_GPIO_OP_SHIFT) /* PGPDI read */
+#define S32_GPIO_OP_SET BIT(S32_GPIO_OP_SHIFT + 1) /* PGPDO write */
+
+/*
+ * [15:12] = GPIO bank / gpio range index
+ * [11:0] = real register offset or pin id
+ */
+#define S32_GPIO_BANK_SHIFT 12
+#define S32_GPIO_BANK_MASK GENMASK(15, 12)
+#define S32_GPIO_REG_MASK GENMASK(11, 0)
+
+#define S32_GPIO_ENCODE(bank, off) \
+ ((((bank) << S32_GPIO_BANK_SHIFT) & S32_GPIO_BANK_MASK) | \
+ ((off) & S32_GPIO_REG_MASK))
+
+#define S32_GPIO_DECODE_BANK(reg) \
+ (((reg) & S32_GPIO_BANK_MASK) >> S32_GPIO_BANK_SHIFT)
+
+#define S32_GPIO_DECODE_OFF(reg) \
+ ((reg) & S32_GPIO_REG_MASK)
+
+/*
+ * PGPDOs are 16bit registers that come in big endian
+ * order if they are grouped in pairs of two.
+ *
+ * For example, the order is PGPDO1, PGPDO0, PGPDO3, PGPDO2...
+ */
+#define S32_PGPD(N) (((N) ^ 1) * 2)
+#define S32_PGPD_SIZE 16
+
enum s32_write_type {
S32_PINCONF_UPDATE_ONLY,
S32_PINCONF_OVERWRITE,
@@ -72,6 +107,18 @@ struct s32_pinctrl_mem_region {
char name[8];
};
+/*
+ * struct s32_gpio_regmaps - GPIO register maps for a SIUL2 instance
+ * @pgpdo: regmap for Parallel GPIO Pad Data Out registers
+ * @pgpdi: regmap for Parallel GPIO Pad Data In registers
+ * @range: GPIO range info
+ */
+struct s32_gpio_regmaps {
+ struct regmap *pgpdo;
+ struct regmap *pgpdi;
+ const struct s32_gpio_range *range;
+};
+
/*
* struct gpio_pin_config - holds pin configuration for GPIO's
* @pin_id: Pin ID for this GPIO
@@ -98,6 +145,12 @@ struct s32_pinctrl_context {
* @pctl: a pointer to the pinctrl device structure
* @regions: reserved memory regions with start/end pin
* @info: structure containing information about the pin
+ * @gpio_regmaps: PGPDO/PGPDI regmaps for each SIUL2 module
+ * @num_gpio_regmaps: number of GPIO regmap entries
+ * @gpio_regmap: regmap bridging gpio-regmap to SIUL2 registers
+ * @gpio_rgm: gpio-regmap instance registered for this controller
+ * @ngpio: total number of GPIO line offsets
+ * @gpio_names: GPIO line names array passed to gpio-regmap
* @gpio_configs: saved configurations for GPIO pins
* @gpio_configs_lock: lock for the `gpio_configs` list
* @saved_context: configuration saved over system sleep
@@ -107,6 +160,12 @@ struct s32_pinctrl {
struct pinctrl_dev *pctl;
struct s32_pinctrl_mem_region *regions;
struct s32_pinctrl_soc_info *info;
+ struct s32_gpio_regmaps *gpio_regmaps;
+ unsigned int num_gpio_regmaps;
+ struct regmap *gpio_regmap;
+ struct gpio_regmap *gpio_rgm;
+ unsigned int ngpio;
+ const char *const *gpio_names;
struct list_head gpio_configs;
spinlock_t gpio_configs_lock;
#ifdef CONFIG_PM_SLEEP
@@ -356,88 +415,84 @@ static int s32_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
return info->nfunctions;
}
-static const char *s32_pmx_get_func_name(struct pinctrl_dev *pctldev,
- unsigned int selector)
-{
- struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- const struct s32_pinctrl_soc_info *info = ipctl->info;
-
- return info->functions[selector].name;
-}
-
-static int s32_pmx_get_groups(struct pinctrl_dev *pctldev,
- unsigned int selector,
- const char * const **groups,
- unsigned int * const num_groups)
-{
- struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- const struct s32_pinctrl_soc_info *info = ipctl->info;
-
- *groups = info->functions[selector].groups;
- *num_groups = info->functions[selector].ngroups;
-
- return 0;
-}
-
static int s32_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned int offset)
+ unsigned int pin)
{
struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct gpio_pin_config *gpio_pin;
+ struct gpio_pin_config *gpio_pin __free(kfree) = NULL;
unsigned int config;
- unsigned long flags;
int ret;
- ret = s32_regmap_read(pctldev, offset, &config);
+ ret = s32_regmap_read(pctldev, pin, &config);
if (ret)
return ret;
- /* Save current configuration */
- gpio_pin = kmalloc_obj(*gpio_pin);
+ gpio_pin = kmalloc_obj(*gpio_pin, GFP_KERNEL);
if (!gpio_pin)
return -ENOMEM;
- gpio_pin->pin_id = offset;
+ gpio_pin->pin_id = pin;
gpio_pin->config = config;
- INIT_LIST_HEAD(&gpio_pin->list);
-
- spin_lock_irqsave(&ipctl->gpio_configs_lock, flags);
- list_add(&gpio_pin->list, &ipctl->gpio_configs);
- spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags);
/* GPIO pin means SSS = 0 */
- config &= ~S32_MSCR_SSS_MASK;
+ ret = s32_regmap_update(pctldev, pin,
+ S32_MSCR_SSS_MASK | S32_MSCR_IBE,
+ S32_MSCR_IBE);
+ if (ret)
+ return ret;
+
+ scoped_guard(spinlock_irqsave, &ipctl->gpio_configs_lock)
+ list_add(&no_free_ptr(gpio_pin)->list, &ipctl->gpio_configs);
- return s32_regmap_write(pctldev, offset, config);
+ return 0;
}
static void s32_pmx_gpio_disable_free(struct pinctrl_dev *pctldev,
struct pinctrl_gpio_range *range,
- unsigned int offset)
+ unsigned int pin)
{
struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
- struct gpio_pin_config *gpio_pin, *tmp;
+ struct gpio_pin_config *gpio_pin, *found = NULL;
unsigned long flags;
- int ret;
spin_lock_irqsave(&ipctl->gpio_configs_lock, flags);
-
- list_for_each_entry_safe(gpio_pin, tmp, &ipctl->gpio_configs, list) {
- if (gpio_pin->pin_id == offset) {
- ret = s32_regmap_write(pctldev, gpio_pin->pin_id,
- gpio_pin->config);
- if (ret != 0)
- goto unlock;
-
+ list_for_each_entry(gpio_pin, &ipctl->gpio_configs, list) {
+ if (gpio_pin->pin_id == pin) {
list_del(&gpio_pin->list);
- kfree(gpio_pin);
+ found = gpio_pin;
break;
}
}
-
-unlock:
spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags);
+
+ if (found) {
+ s32_regmap_write(pctldev, found->pin_id, found->config);
+ kfree(found);
+ }
+}
+
+static const char *s32_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned int selector)
+{
+ struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct s32_pinctrl_soc_info *info = ipctl->info;
+
+ return info->functions[selector].name;
+}
+
+static int s32_pmx_get_groups(struct pinctrl_dev *pctldev,
+ unsigned int selector,
+ const char * const **groups,
+ unsigned int * const num_groups)
+{
+ struct s32_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct s32_pinctrl_soc_info *info = ipctl->info;
+
+ *groups = info->functions[selector].groups;
+ *num_groups = info->functions[selector].ngroups;
+
+ return 0;
}
static int s32_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
@@ -649,9 +704,9 @@ static void s32_pinconf_dbg_show(struct pinctrl_dev *pctldev,
ret = s32_regmap_read(pctldev, pin_id, &config);
if (ret)
- return;
-
- seq_printf(s, "0x%x", config);
+ seq_printf(s, "error %d", ret);
+ else
+ seq_printf(s, "0x%x", config);
}
static void s32_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
@@ -669,8 +724,11 @@ static void s32_pinconf_group_dbg_show(struct pinctrl_dev *pctldev,
for (i = 0; i < grp->data.npins; i++) {
name = pin_get_name(pctldev, grp->data.pins[i]);
ret = s32_regmap_read(pctldev, grp->data.pins[i], &config);
- if (ret)
- return;
+ if (ret) {
+ seq_printf(s, "%s: error %d\n", name, ret);
+ continue;
+ }
+
seq_printf(s, "%s: 0x%x\n", name, config);
}
}
@@ -683,6 +741,477 @@ static const struct pinconf_ops s32_pinconf_ops = {
.pin_config_group_dbg_show = s32_pinconf_group_dbg_show,
};
+static void s32_gpio_free_saved_configs(void *data)
+{
+ struct s32_pinctrl *ipctl = data;
+ struct gpio_pin_config *gpio_pin, *tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipctl->gpio_configs_lock, flags);
+ list_for_each_entry_safe(gpio_pin, tmp, &ipctl->gpio_configs, list) {
+ list_del(&gpio_pin->list);
+ kfree(gpio_pin);
+ }
+ spin_unlock_irqrestore(&ipctl->gpio_configs_lock, flags);
+}
+
+static unsigned int s32_pin2pad(unsigned int pin)
+{
+ return pin / S32_PGPD_SIZE;
+}
+
+static u16 s32_pin2mask(unsigned int pin)
+{
+ /*
+ * From Reference manual :
+ * PGPDOx[PPDOy] = GPDO(x × 16) + (15 - y)[PDO_(x × 16) + (15 - y)]
+ */
+ return BIT(S32_PGPD_SIZE - 1 - pin % S32_PGPD_SIZE);
+}
+
+static int s32_gpio_get_range(struct s32_pinctrl *ipctl,
+ unsigned int gpio,
+ unsigned int *pin,
+ unsigned int *bank)
+{
+ const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data;
+ const struct s32_gpio_range *range;
+ int i;
+
+ for (i = 0; i < soc_data->num_gpio_ranges; i++) {
+ range = &soc_data->gpio_ranges[i];
+
+ if (gpio < range->gpio_base ||
+ gpio >= range->gpio_base + range->gpio_num)
+ continue;
+
+ if (pin)
+ *pin = range->pin_base + gpio - range->gpio_base;
+
+ if (bank)
+ *bank = i;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int s32_gpio_pad_map_xlate(struct s32_pinctrl *ipctl,
+ unsigned int gpio,
+ unsigned int *reg_offset,
+ u16 *mask)
+{
+ const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data;
+ const struct s32_gpio_pad_map *map;
+ unsigned int bit;
+ int i;
+
+ if (!soc_data->gpio_pad_maps || !soc_data->num_gpio_pad_maps)
+ return -EINVAL;
+
+ for (i = 0; i < soc_data->num_gpio_pad_maps; i++) {
+ map = &soc_data->gpio_pad_maps[i];
+
+ if (gpio < map->gpio_start || gpio > map->gpio_end)
+ continue;
+
+ bit = gpio - map->gpio_start;
+ *mask = BIT(S32_PGPD_SIZE - 1 - bit);
+ *reg_offset = S32_PGPD(map->pad);
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static bool s32_gpio_pin_is_sparse(struct s32_pinctrl *ipctl, unsigned int pin)
+{
+ const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data;
+ const struct s32_gpio_range *range;
+ int i;
+
+ for (i = 0; i < soc_data->num_gpio_ranges; i++) {
+ range = &soc_data->gpio_ranges[i];
+ if (pin >= range->pin_base &&
+ pin < range->pin_base + range->gpio_num)
+ return range->sparse;
+ }
+
+ return false;
+}
+
+static int s32_gpio_xlate_pgpd(struct s32_pinctrl *ipctl,
+ unsigned int pin,
+ unsigned int *reg_offset,
+ u16 *mask)
+{
+ int ret;
+
+ /*
+ * Try the pad map first. For sparse ranges (SIUL2_1), only pins
+ * listed in the pad map are valid, return the error directly without
+ * falling back to the linear layout.
+ * For linear ranges (SIUL2_0), fall back to the linear pad-to-PGPD
+ * formula if no pad map entry matches.
+ */
+ ret = s32_gpio_pad_map_xlate(ipctl, pin, reg_offset, mask);
+ if (ret != -EINVAL)
+ return ret;
+
+ if (s32_gpio_pin_is_sparse(ipctl, pin))
+ return -EINVAL;
+
+ /* Linear layout fallback for non-sparse ranges. */
+ *mask = s32_pin2mask(pin);
+ *reg_offset = S32_PGPD(s32_pin2pad(pin));
+
+ return 0;
+}
+
+static int s32_gpio_reg_mask_xlate(struct gpio_regmap *gpio,
+ unsigned int base, unsigned int offset,
+ unsigned int *reg, unsigned int *mask)
+{
+ struct s32_pinctrl *ipctl = gpio_regmap_get_drvdata(gpio);
+ unsigned int pgpd_reg, pin, bank;
+ u16 pgpd_mask;
+ int ret;
+
+ ret = s32_gpio_get_range(ipctl, offset, &pin, &bank);
+ if (ret)
+ return ret;
+
+ switch (base) {
+ case S32_GPIO_OP_DIR:
+ /*
+ * Direction is controlled through MSCR OBE.
+ * Encode the real pin id in the virtual register.
+ */
+ *reg = S32_GPIO_OP_DIR | pin;
+ *mask = S32_MSCR_OBE;
+ return 0;
+
+ case S32_GPIO_OP_DAT:
+ case S32_GPIO_OP_SET:
+ ret = s32_gpio_xlate_pgpd(ipctl, pin, &pgpd_reg, &pgpd_mask);
+ if (ret)
+ return ret;
+ /*
+ * Encode both the GPIO bank and the real PGPD register offset.
+ */
+ *reg = base | S32_GPIO_ENCODE(bank, pgpd_reg);
+ *mask = pgpd_mask;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int s32_gpio_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct s32_pinctrl *ipctl = context;
+ unsigned int op = reg & S32_GPIO_OP_MASK;
+ unsigned int vreg = reg & ~S32_GPIO_OP_MASK;
+ unsigned int bank;
+ unsigned int offset;
+ struct regmap *map;
+
+ switch (op) {
+ case S32_GPIO_OP_DIR:
+ /*
+ * Lower bits contain the real MSCR pin id.
+ */
+ offset = S32_GPIO_DECODE_OFF(vreg);
+
+ return s32_regmap_read(ipctl->pctl, offset, val);
+
+ case S32_GPIO_OP_DAT:
+ bank = S32_GPIO_DECODE_BANK(vreg);
+ offset = S32_GPIO_DECODE_OFF(vreg);
+
+ if (bank >= ipctl->num_gpio_regmaps)
+ return -EINVAL;
+
+ map = ipctl->gpio_regmaps[bank].pgpdi;
+ if (!map)
+ return -ENODEV;
+
+ return regmap_read(map, offset, val);
+
+ case S32_GPIO_OP_SET:
+ /*
+ * gpio-regmap uses update_bits() for set, so it needs to read
+ * the output register before writing the updated value.
+ */
+ bank = S32_GPIO_DECODE_BANK(vreg);
+ offset = S32_GPIO_DECODE_OFF(vreg);
+
+ if (bank >= ipctl->num_gpio_regmaps)
+ return -EINVAL;
+
+ map = ipctl->gpio_regmaps[bank].pgpdo;
+ if (!map)
+ return -ENODEV;
+
+ return regmap_read(map, offset, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int s32_gpio_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct s32_pinctrl *ipctl = context;
+ unsigned int op = reg & S32_GPIO_OP_MASK;
+ unsigned int vreg = reg & ~S32_GPIO_OP_MASK;
+ unsigned int bank, offset, config;
+ struct regmap *map;
+
+ switch (op) {
+ case S32_GPIO_OP_DIR:
+ /*
+ * gpio-regmap sets S32_MSCR_OBE for output and clears it for
+ * input. Keep IBE enabled for GPIOs in both cases.
+ */
+ offset = S32_GPIO_DECODE_OFF(vreg);
+
+ config = S32_MSCR_IBE;
+ if (val & S32_MSCR_OBE)
+ config |= S32_MSCR_OBE;
+
+ return s32_regmap_update(ipctl->pctl, offset,
+ S32_MSCR_OBE | S32_MSCR_IBE,
+ config);
+
+ case S32_GPIO_OP_SET:
+ bank = S32_GPIO_DECODE_BANK(vreg);
+ offset = S32_GPIO_DECODE_OFF(vreg);
+
+ if (bank >= ipctl->num_gpio_regmaps)
+ return -EINVAL;
+
+ map = ipctl->gpio_regmaps[bank].pgpdo;
+ if (!map)
+ return -ENODEV;
+
+ return regmap_write(map, offset, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct regmap_bus s32_gpio_regmap_bus = {
+ .reg_read = s32_gpio_reg_read,
+ .reg_write = s32_gpio_reg_write,
+};
+
+static const struct regmap_config s32_gpio_regmap_config = {
+ .name = "s32-gpio",
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 1,
+ .max_register = S32_GPIO_OP_SET | S32_GPIO_BANK_MASK | S32_GPIO_REG_MASK,
+ .cache_type = REGCACHE_NONE,
+ .fast_io = true,
+};
+
+static int s32_gpio_get_ngpio(const struct s32_pinctrl_soc_data *soc_data,
+ unsigned int *ngpio)
+{
+ const struct s32_gpio_range *range;
+ unsigned int end, max = 0;
+ int i;
+
+ if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges)
+ return -EINVAL;
+
+ for (i = 0; i < soc_data->num_gpio_ranges; i++) {
+ range = &soc_data->gpio_ranges[i];
+
+ if (!range->gpio_num)
+ return -EINVAL;
+
+ end = range->gpio_base + range->gpio_num;
+
+ /*
+ * gpio_ranges must be ordered by gpio_base and must not overlap.
+ * The GPIO line space size is derived from the highest range end.
+ */
+ if (i > 0 && range->gpio_base < max)
+ return -EINVAL;
+
+ if (end > max)
+ max = end;
+ }
+
+ *ngpio = max;
+
+ return 0;
+}
+
+static int s32_init_gpio_regmap(struct platform_device *pdev,
+ struct s32_pinctrl *ipctl)
+{
+ ipctl->gpio_regmap =
+ devm_regmap_init(&pdev->dev, &s32_gpio_regmap_bus,
+ ipctl, &s32_gpio_regmap_config);
+ if (IS_ERR(ipctl->gpio_regmap))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(ipctl->gpio_regmap),
+ "Failed to init GPIO regmap\n");
+
+ return 0;
+}
+
+static int s32_init_valid_mask(struct gpio_chip *chip, unsigned long *mask,
+ unsigned int ngpios)
+{
+ struct gpio_regmap *gpio = gpiochip_get_data(chip);
+ struct s32_pinctrl *ipctl = gpio_regmap_get_drvdata(gpio);
+ unsigned int gpio_num, pin, reg_offset;
+ u16 pgpd_mask;
+ int ret;
+
+ bitmap_zero(mask, ngpios);
+
+ for (gpio_num = 0; gpio_num < ngpios; gpio_num++) {
+ ret = s32_gpio_get_range(ipctl, gpio_num, &pin, NULL);
+ if (ret)
+ continue;
+
+ ret = s32_gpio_xlate_pgpd(ipctl, pin, ®_offset, &pgpd_mask);
+ if (ret)
+ continue;
+
+ bitmap_set(mask, gpio_num, 1);
+ }
+
+ return 0;
+}
+
+static int s32_gpio_populate_names(struct s32_pinctrl *ipctl)
+{
+ char **names;
+ unsigned int gpio;
+ unsigned int pin;
+ char port;
+ int ret;
+
+ names = devm_kcalloc(ipctl->dev, ipctl->ngpio, sizeof(*names),
+ GFP_KERNEL);
+ if (!names)
+ return -ENOMEM;
+
+ for (gpio = 0; gpio < ipctl->ngpio; gpio++) {
+ ret = s32_gpio_get_range(ipctl, gpio, &pin, NULL);
+ if (ret)
+ continue;
+
+ port = 'A' + pin / 16;
+
+ names[gpio] = devm_kasprintf(ipctl->dev, GFP_KERNEL,
+ "P%c_%02u", port, pin & 0xf);
+ if (!names[gpio])
+ return -ENOMEM;
+ }
+
+ ipctl->gpio_names = (const char *const *)names;
+
+ return 0;
+}
+
+static int s32_pinctrl_init_gpio_regmaps(struct platform_device *pdev,
+ struct s32_pinctrl *ipctl)
+{
+ const struct s32_pinctrl_soc_data *soc_data = ipctl->info->soc_data;
+ static const struct regmap_config pgpd_config = {
+ .reg_bits = 32,
+ .val_bits = 16,
+ .reg_stride = 2,
+ };
+ struct regmap_config cfg;
+ struct resource *res;
+ void __iomem *base;
+ unsigned int pgpdo_idx, pgpdi_idx;
+ unsigned int i;
+
+ if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges)
+ return 0;
+
+ ipctl->num_gpio_regmaps = soc_data->num_gpio_ranges;
+ ipctl->gpio_regmaps = devm_kcalloc(&pdev->dev, ipctl->num_gpio_regmaps,
+ sizeof(*ipctl->gpio_regmaps),
+ GFP_KERNEL);
+ if (!ipctl->gpio_regmaps)
+ return -ENOMEM;
+
+ for (i = 0; i < ipctl->num_gpio_regmaps; i++) {
+ ipctl->gpio_regmaps[i].range = &soc_data->gpio_ranges[i];
+
+ /*
+ * GPIO resources are placed after the pinctrl regions
+ */
+ pgpdo_idx = soc_data->mem_regions + i * 2;
+ pgpdi_idx = soc_data->mem_regions + i * 2 + 1;
+
+ /* PGPDO */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, pgpdo_idx);
+ if (!res)
+ return dev_err_probe(&pdev->dev, -ENOENT,
+ "Missing PGPDO resource %u\n", i);
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ cfg = pgpd_config;
+ cfg.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pgpdo%u", i);
+ if (!cfg.name)
+ return -ENOMEM;
+
+ cfg.max_register = resource_size(res) - cfg.reg_stride;
+
+ ipctl->gpio_regmaps[i].pgpdo =
+ devm_regmap_init_mmio(&pdev->dev, base, &cfg);
+ if (IS_ERR(ipctl->gpio_regmaps[i].pgpdo))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(ipctl->gpio_regmaps[i].pgpdo),
+ "Failed to init PGPDO regmap %u\n", i);
+
+ /* PGPDI */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, pgpdi_idx);
+ if (!res)
+ return dev_err_probe(&pdev->dev, -ENOENT,
+ "Missing PGPDI resource %u\n", i);
+
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ cfg = pgpd_config;
+ cfg.name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "pgpdi%u", i);
+ if (!cfg.name)
+ return -ENOMEM;
+
+ cfg.max_register = resource_size(res) - cfg.reg_stride;
+
+ ipctl->gpio_regmaps[i].pgpdi =
+ devm_regmap_init_mmio(&pdev->dev, base, &cfg);
+ if (IS_ERR(ipctl->gpio_regmaps[i].pgpdi))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(ipctl->gpio_regmaps[i].pgpdi),
+ "Failed to init PGPDI regmap %u\n", i);
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_PM_SLEEP
static bool s32_pinctrl_should_save(struct s32_pinctrl *ipctl,
unsigned int pin)
@@ -709,8 +1238,7 @@ int s32_pinctrl_suspend(struct device *dev)
const struct pinctrl_pin_desc *pin;
const struct s32_pinctrl_soc_info *info = ipctl->info;
struct s32_pinctrl_context *saved_context = &ipctl->saved_context;
- int i;
- int ret;
+ int i, ret;
unsigned int config;
for (i = 0; i < info->soc_data->npins; i++) {
@@ -721,7 +1249,7 @@ int s32_pinctrl_suspend(struct device *dev)
ret = s32_regmap_read(ipctl->pctl, pin->number, &config);
if (ret)
- return -EINVAL;
+ return ret;
saved_context->pads[i] = config;
}
@@ -736,7 +1264,7 @@ int s32_pinctrl_resume(struct device *dev)
const struct s32_pinctrl_soc_info *info = ipctl->info;
const struct pinctrl_pin_desc *pin;
struct s32_pinctrl_context *saved_context = &ipctl->saved_context;
- int ret, i;
+ int i, ret;
for (i = 0; i < info->soc_data->npins; i++) {
pin = &info->soc_data->pins[i];
@@ -745,7 +1273,7 @@ int s32_pinctrl_resume(struct device *dev)
continue;
ret = s32_regmap_write(ipctl->pctl, pin->number,
- saved_context->pads[i]);
+ saved_context->pads[i]);
if (ret)
return ret;
}
@@ -927,13 +1455,15 @@ static int s32_pinctrl_probe_dt(struct platform_device *pdev,
int s32_pinctrl_probe(struct platform_device *pdev,
const struct s32_pinctrl_soc_data *soc_data)
{
- struct s32_pinctrl *ipctl;
- int ret;
- struct pinctrl_desc *s32_pinctrl_desc;
- struct s32_pinctrl_soc_info *info;
#ifdef CONFIG_PM_SLEEP
struct s32_pinctrl_context *saved_context;
#endif
+ struct gpio_regmap_config gpio_cfg = {};
+ struct pinctrl_desc *s32_pinctrl_desc;
+ struct s32_pinctrl_soc_info *info;
+ struct s32_pinctrl *ipctl;
+ unsigned int ngpio;
+ int ret;
if (!soc_data || !soc_data->pins || !soc_data->npins) {
dev_err(&pdev->dev, "wrong pinctrl info\n");
@@ -959,6 +1489,11 @@ int s32_pinctrl_probe(struct platform_device *pdev,
INIT_LIST_HEAD(&ipctl->gpio_configs);
spin_lock_init(&ipctl->gpio_configs_lock);
+ ret = devm_add_action_or_reset(&pdev->dev,
+ s32_gpio_free_saved_configs, ipctl);
+ if (ret)
+ return ret;
+
s32_pinctrl_desc =
devm_kzalloc(&pdev->dev, sizeof(*s32_pinctrl_desc), GFP_KERNEL);
if (!s32_pinctrl_desc)
@@ -978,6 +1513,11 @@ int s32_pinctrl_probe(struct platform_device *pdev,
return ret;
}
+ ret = s32_pinctrl_init_gpio_regmaps(pdev, ipctl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to init GPIO regmaps\n");
+
ret = devm_pinctrl_register_and_init(&pdev->dev, s32_pinctrl_desc,
ipctl, &ipctl->pctl);
if (ret)
@@ -999,7 +1539,42 @@ int s32_pinctrl_probe(struct platform_device *pdev,
return dev_err_probe(&pdev->dev, ret,
"Failed to enable pinctrl\n");
- dev_info(&pdev->dev, "Initialized S32 pinctrl driver\n");
+ /* Setup GPIO if GPIO ranges are defined */
+ if (!soc_data->gpio_ranges || !soc_data->num_gpio_ranges)
+ return 0;
+
+ ret = s32_gpio_get_ngpio(soc_data, &ngpio);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Invalid GPIO ranges\n");
+
+ ipctl->ngpio = ngpio;
+
+ ret = s32_gpio_populate_names(ipctl);
+ if (ret)
+ return ret;
+
+ ret = s32_init_gpio_regmap(pdev, ipctl);
+ if (ret)
+ return ret;
+
+ gpio_cfg.parent = &pdev->dev;
+ gpio_cfg.fwnode = dev_fwnode(&pdev->dev);
+ gpio_cfg.label = dev_name(&pdev->dev);
+ gpio_cfg.regmap = ipctl->gpio_regmap;
+ gpio_cfg.ngpio = ngpio;
+ gpio_cfg.names = ipctl->gpio_names;
+ gpio_cfg.reg_dir_out_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_DIR);
+ gpio_cfg.reg_dat_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_DAT);
+ gpio_cfg.reg_set_base = GPIO_REGMAP_ADDR(S32_GPIO_OP_SET);
+ gpio_cfg.reg_mask_xlate = s32_gpio_reg_mask_xlate;
+ gpio_cfg.init_valid_mask = s32_init_valid_mask;
+ gpio_cfg.drvdata = ipctl;
+
+ ipctl->gpio_rgm = devm_gpio_regmap_register(&pdev->dev, &gpio_cfg);
+ if (IS_ERR(ipctl->gpio_rgm))
+ return dev_err_probe(&pdev->dev,
+ PTR_ERR(ipctl->gpio_rgm),
+ "Unable to add gpio_regmap chip\n");
return 0;
}
diff --git a/drivers/pinctrl/nxp/pinctrl-s32g2.c b/drivers/pinctrl/nxp/pinctrl-s32g2.c
index c49d28793b69..f9546c67a269 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32g2.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32g2.c
@@ -3,7 +3,7 @@
* NXP S32G pinctrl driver
*
* Copyright 2015-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2018, 2020-2022 NXP
+ * Copyright 2017-2018, 2020-2022, 2025-2026 NXP
* Copyright (C) 2022 SUSE LLC
*/
@@ -773,17 +773,48 @@ static const struct s32_pin_range s32_pin_ranges_siul2[] = {
S32_PIN_RANGE(942, 1007),
};
-static const struct s32_pinctrl_soc_data s32_pinctrl_data = {
+static const struct s32_gpio_range s32_gpio_ranges_siul2[] = {
+ S32_GPIO_RANGE(0, 0, 102),
+ /* SIUL2_1: sparse layout, PGPD mapping required for all pins */
+ { .gpio_base = 112, .pin_base = 112, .gpio_num = 79, .sparse = true },
+};
+
+/*
+ * SIUL2_1 GPIO ranges mapped to sparse PGPD pads.
+ *
+ * SIUL2_1 does not expose GPIO data registers as a linear pad
+ * sequence. Each entry describes a contiguous GPIO offset range
+ * and the PGPD pad servicing that range.
+ */
+static const struct s32_gpio_pad_map s32g_gpio_pad_maps[] = {
+ { 112, 122, 7 }, /* PH_00 .. PH_10 -> PGPD7 */
+ { 144, 159, 9 }, /* PJ_00 .. PJ_15 -> PGPD9 */
+ { 160, 175, 10 }, /* PK_00 .. PK_15 -> PGPD10 */
+ { 176, 190, 11 }, /* PL_00 .. PL_14 -> PGPD11 */
+};
+
+/* Legacy data for old DT bindings without GPIO support */
+static const struct s32_pinctrl_soc_data legacy_s32g_pinctrl_data = {
+ .pins = s32_pinctrl_pads_siul2,
+ .npins = ARRAY_SIZE(s32_pinctrl_pads_siul2),
+ .mem_pin_ranges = s32_pin_ranges_siul2,
+ .mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2),
+};
+
+static const struct s32_pinctrl_soc_data s32g_pinctrl_data = {
.pins = s32_pinctrl_pads_siul2,
.npins = ARRAY_SIZE(s32_pinctrl_pads_siul2),
.mem_pin_ranges = s32_pin_ranges_siul2,
.mem_regions = ARRAY_SIZE(s32_pin_ranges_siul2),
+ .gpio_ranges = s32_gpio_ranges_siul2,
+ .num_gpio_ranges = ARRAY_SIZE(s32_gpio_ranges_siul2),
+ .gpio_pad_maps = s32g_gpio_pad_maps,
+ .num_gpio_pad_maps = ARRAY_SIZE(s32g_gpio_pad_maps),
};
static const struct of_device_id s32_pinctrl_of_match[] = {
{
.compatible = "nxp,s32g2-siul2-pinctrl",
- .data = &s32_pinctrl_data,
},
{ /* sentinel */ }
};
@@ -792,8 +823,16 @@ MODULE_DEVICE_TABLE(of, s32_pinctrl_of_match);
static int s32g_pinctrl_probe(struct platform_device *pdev)
{
const struct s32_pinctrl_soc_data *soc_data;
+ struct device_node *np = pdev->dev.of_node;
- soc_data = of_device_get_match_data(&pdev->dev);
+ /*
+ * Legacy DTs only describe the pinctrl resources.
+ * New DT changes extend the same node with GPIO resources.
+ */
+ if (of_property_present(np, "gpio-controller"))
+ soc_data = &s32g_pinctrl_data;
+ else
+ soc_data = &legacy_s32g_pinctrl_data;
return s32_pinctrl_probe(pdev, soc_data);
}
--
2.34.1
^ permalink raw reply related
* [PATCH v11 4/6] dt-bindings: pinctrl: s32g2-siul2: describe GPIO and EIRQ resources
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
Extend the S32G2 SIUL2 pinctrl binding to describe the GPIO data and
external interrupt resources present in the same SIUL2 hardware block.
Besides the MSCR and IMCR registers used for pin multiplexing and pad
configuration, SIUL2 also contains PGPDO and PGPDI registers
for GPIO data and EIRQ registers for external interrupt control.
Add GPIO controller properties because the SIUL2 block also provides
GPIO functionality, and gpio-ranges are needed to describe the
mapping between GPIO lines and pin controller pins.
Document the interrupt controller properties. The SIUL2 block
contains EIRQ hardware as part of the same register space. IRQ support
itself will be added in a follow-up patch series.
Update the example accordingly to show the complete SIUL2 register
layout, including the GPIO data and EIRQ register windows.
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
.../pinctrl/nxp,s32g2-siul2-pinctrl.yaml | 90 +++++++++++++++++--
1 file changed, 84 insertions(+), 6 deletions(-)
diff --git a/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml
index a24286e4def6..36f2393fa406 100644
--- a/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/nxp,s32g2-siul2-pinctrl.yaml
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-# Copyright 2022 NXP
+# Copyright 2022, 2026 NXP
%YAML 1.2
---
$id: http://devicetree.org/schemas/pinctrl/nxp,s32g2-siul2-pinctrl.yaml#
@@ -17,8 +17,10 @@ description: |
SIUL2_0 @ 0x4009c000
SIUL2_1 @ 0x44010000
- Every SIUL2 region has multiple register types, and here only MSCR and
- IMCR registers need to be revealed for kernel to configure pinmux.
+ Every SIUL2 region has multiple register types. MSCR and IMCR registers
+ need to be revealed for kernel to configure pinmux. PGPDO and PGPDI
+ registers are used for GPIO output/input operations. EIRQ registers
+ are used for external interrupt configuration.
Please note that some register indexes are reserved in S32G2, such as
MSCR102-MSCR111, MSCR123-MSCR143, IMCR84-IMCR118 and IMCR398-IMCR429.
@@ -29,14 +31,22 @@ properties:
- nxp,s32g2-siul2-pinctrl
reg:
+ minItems: 6
description: |
- A list of MSCR/IMCR register regions to be reserved.
+ A list of MSCR/IMCR/PGPDO/PGPDI/EIRQ register regions to be reserved.
- MSCR (Multiplexed Signal Configuration Register)
An MSCR register can configure the associated pin as either a GPIO pin
or a function output pin depends on the selected signal source.
- IMCR (Input Multiplexed Signal Configuration Register)
An IMCR register can configure the associated pin as function input
pin depends on the selected signal source.
+ - PGPDO (Parallel GPIO Pad Data Out Register)
+ A PGPDO register is used to set the output value of a GPIO pin.
+ - PGPDI (Parallel GPIO Pad Data In Register)
+ A PGPDI register is used to read the input value of a GPIO pin.
+ - EIRQ (External Interrupt Request)
+ EIRQ registers are used to configure and manage external interrupts.
+
items:
- description: MSCR registers group 0 in SIUL2_0
- description: MSCR registers group 1 in SIUL2_1
@@ -44,6 +54,28 @@ properties:
- description: IMCR registers group 0 in SIUL2_0
- description: IMCR registers group 1 in SIUL2_1
- description: IMCR registers group 2 in SIUL2_1
+ - description: PGPDO registers in SIUL2_0
+ - description: PGPDI registers in SIUL2_0
+ - description: PGPDO registers in SIUL2_1
+ - description: PGPDI registers in SIUL2_1
+ - description: EIRQ registers in SIUL2_1
+
+ gpio-controller: true
+
+ "#gpio-cells":
+ const: 2
+
+ gpio-ranges:
+ minItems: 1
+ maxItems: 4
+
+ interrupt-controller: true
+
+ "#interrupt-cells":
+ const: 2
+
+ interrupts:
+ maxItems: 1
patternProperties:
'-pins$':
@@ -86,11 +118,38 @@ required:
- compatible
- reg
+oneOf:
+ - description: Legacy pinctrl-only node
+ properties:
+ reg:
+ maxItems: 6
+
+ gpio-controller: false
+ "#gpio-cells": false
+ gpio-ranges: false
+ interrupt-controller: false
+ "#interrupt-cells": false
+ interrupts: false
+
+ - description: Pinctrl node with GPIO and external interrupt support
+ required:
+ - gpio-controller
+ - "#gpio-cells"
+ - gpio-ranges
+ - interrupt-controller
+ - "#interrupt-cells"
+ - interrupts
+ properties:
+ reg:
+ minItems: 11
+
additionalProperties: false
examples:
- |
- pinctrl@4009c240 {
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ pinctrl: pinctrl@4009c240 {
compatible = "nxp,s32g2-siul2-pinctrl";
/* MSCR0-MSCR101 registers on siul2_0 */
@@ -104,7 +163,26 @@ examples:
/* IMCR119-IMCR397 registers on siul2_1 */
<0x44010c1c 0x45c>,
/* IMCR430-IMCR495 registers on siul2_1 */
- <0x440110f8 0x108>;
+ <0x440110f8 0x108>,
+ /* PGPDO registers on siul2_0 */
+ <0x4009d700 0x10>,
+ /* PGPDI registers on siul2_0 */
+ <0x4009d740 0x10>,
+ /* PGPDO registers on siul2_1 */
+ <0x44011700 0x18>,
+ /* PGPDI registers on siul2_1 */
+ <0x44011740 0x18>,
+ /* EIRQ registers on siul2_1 */
+ <0x44010010 0x34>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 0 102>,
+ <&pinctrl 112 112 79>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>;
llce-can0-pins {
llce-can0-grp0 {
--
2.34.1
^ permalink raw reply related
* [PATCH v11 6/6] arm64: dts: s32g: describe GPIO and EIRQ resources in SIUL2 pinctrl node
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
Update the SIUL2 pinctrl node to describe the additional register
ranges and DT properties used by the updated SIUL2 driver.
Besides the MSCR and IMCR ranges used for pinmux and pin
configuration, the SIUL2 block also provides PGPDO and
PGPDI registers for GPIO output and input operations,
as well as an EIRQ register window for external interrupt configuration.
The driver supports both legacy pinctrl-only DTs and
extended DTs with GPIO and IRQ.
Reflect these resources in the SIUL2 pinctrl node by adding:
- the PGPDO and PGPDI register ranges
- the EIRQ register range
- gpio-controller, #gpio-cells and gpio-ranges
- interrupt-controller, #interrupt-cells and interrupts
Keep the hardware description aligned with the updated SIUL2
driver, where pinctrl, GPIO data access and the EIRQ register
block are described under the same device node.
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
arch/arm64/boot/dts/freescale/s32g2.dtsi | 23 +++++++++++++++++++++--
arch/arm64/boot/dts/freescale/s32g3.dtsi | 23 +++++++++++++++++++++--
2 files changed, 42 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/boot/dts/freescale/s32g2.dtsi b/arch/arm64/boot/dts/freescale/s32g2.dtsi
index 51d00dac12de..f21c8d19bcfe 100644
--- a/arch/arm64/boot/dts/freescale/s32g2.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g2.dtsi
@@ -3,7 +3,7 @@
* NXP S32G2 SoC family
*
* Copyright (c) 2021 SUSE LLC
- * Copyright 2017-2021, 2024-2025 NXP
+ * Copyright 2017-2021, 2024-2026 NXP
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
@@ -135,7 +135,26 @@ pinctrl: pinctrl@4009c240 {
/* IMCR119-IMCR397 registers on siul2_1 */
<0x44010c1c 0x45c>,
/* IMCR430-IMCR495 registers on siul2_1 */
- <0x440110f8 0x108>;
+ <0x440110f8 0x108>,
+ /* PGPDO registers on siul2_0 */
+ <0x4009d700 0x10>,
+ /* PGPDI registers on siul2_0 */
+ <0x4009d740 0x10>,
+ /* PGPDO registers on siul2_1 */
+ <0x44011700 0x18>,
+ /* PGPDI registers on siul2_1 */
+ <0x44011740 0x18>,
+ /* EIRQ window: DISR0..IFEER0 */
+ <0x44010010 0x34>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 0 102>,
+ <&pinctrl 112 112 79>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>;
jtag_pins: jtag-pins {
jtag-grp0 {
diff --git a/arch/arm64/boot/dts/freescale/s32g3.dtsi b/arch/arm64/boot/dts/freescale/s32g3.dtsi
index e314f3c7d61d..f5825881fd69 100644
--- a/arch/arm64/boot/dts/freescale/s32g3.dtsi
+++ b/arch/arm64/boot/dts/freescale/s32g3.dtsi
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/*
- * Copyright 2021-2025 NXP
+ * Copyright 2021-2026 NXP
*
* Authors: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
* Ciprian Costea <ciprianmarian.costea@nxp.com>
@@ -193,7 +193,26 @@ pinctrl: pinctrl@4009c240 {
/* IMCR119-IMCR397 registers on siul2_1 */
<0x44010c1c 0x45c>,
/* IMCR430-IMCR495 registers on siul2_1 */
- <0x440110f8 0x108>;
+ <0x440110f8 0x108>,
+ /* PGPDO registers on siul2_0 */
+ <0x4009d700 0x10>,
+ /* PGPDI registers on siul2_0 */
+ <0x4009d740 0x10>,
+ /* PGPDO registers on siul2_1 */
+ <0x44011700 0x18>,
+ /* PGPDI registers on siul2_1 */
+ <0x44011740 0x18>,
+ /* EIRQ window: DISR0..IFEER0 */
+ <0x44010010 0x34>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ gpio-ranges = <&pinctrl 0 0 102>,
+ <&pinctrl 112 112 79>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>;
jtag_pins: jtag-pins {
jtag-grp0 {
--
2.34.1
^ permalink raw reply related
* [PATCH v11 1/6] pinctrl: s32cc: add/fix some comments
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
Add/fix some comments and print statements.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32cc.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index fe7cd641fddd..4f88c24e62a2 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -60,6 +60,12 @@ static u32 get_pin_func(u32 pinmux)
return pinmux & GENMASK(3, 0);
}
+/*
+ * struct s32_pinctrl_mem_region - memory region for a set of SIUL2 registers
+ * @map: regmap used for this range
+ * @pin_range: the pins controlled by these registers
+ * @name: name of the current range
+ */
struct s32_pinctrl_mem_region {
struct regmap *map;
const struct s32_pin_range *pin_range;
@@ -67,7 +73,7 @@ struct s32_pinctrl_mem_region {
};
/*
- * Holds pin configuration for GPIO's.
+ * struct gpio_pin_config - holds pin configuration for GPIO's
* @pin_id: Pin ID for this GPIO
* @config: Pin settings
* @list: Linked list entry for each gpio pin
@@ -79,20 +85,22 @@ struct gpio_pin_config {
};
/*
- * Pad config save/restore for power suspend/resume.
+ * struct s32_pinctrl_context - pad config save/restore for suspend/resume
+ * @pads: saved values for the pards
*/
struct s32_pinctrl_context {
unsigned int *pads;
};
/*
+ * struct s32_pinctrl - private driver data
* @dev: a pointer back to containing device
* @pctl: a pointer to the pinctrl device structure
* @regions: reserved memory regions with start/end pin
* @info: structure containing information about the pin
- * @gpio_configs: Saved configurations for GPIO pins
- * @gpiop_configs_lock: lock for the `gpio_configs` list
- * @s32_pinctrl_context: Configuration saved over system sleep
+ * @gpio_configs: saved configurations for GPIO pins
+ * @gpio_configs_lock: lock for the `gpio_configs` list
+ * @saved_context: configuration saved over system sleep
*/
struct s32_pinctrl {
struct device *dev;
@@ -974,7 +982,7 @@ int s32_pinctrl_probe(struct platform_device *pdev,
ipctl);
if (IS_ERR(ipctl->pctl))
return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl),
- "could not register s32 pinctrl driver\n");
+ "Could not register s32 pinctrl driver\n");
#ifdef CONFIG_PM_SLEEP
saved_context = &ipctl->saved_context;
--
2.34.1
^ permalink raw reply related
* [PATCH v11 2/6] pinctrl: s32cc: remove inline specifiers
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
Remove unnecessary inline specifiers from static functions.
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32cc.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 4f88c24e62a2..2645a92df0ba 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -131,13 +131,13 @@ s32_get_region(struct pinctrl_dev *pctldev, unsigned int pin)
return NULL;
}
-static inline int s32_check_pin(struct pinctrl_dev *pctldev,
- unsigned int pin)
+static int s32_check_pin(struct pinctrl_dev *pctldev,
+ unsigned int pin)
{
return s32_get_region(pctldev, pin) ? 0 : -EINVAL;
}
-static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
+static int s32_regmap_read(struct pinctrl_dev *pctldev,
unsigned int pin, unsigned int *val)
{
struct s32_pinctrl_mem_region *region;
@@ -153,7 +153,7 @@ static inline int s32_regmap_read(struct pinctrl_dev *pctldev,
return regmap_read(region->map, offset, val);
}
-static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
+static int s32_regmap_write(struct pinctrl_dev *pctldev,
unsigned int pin,
unsigned int val)
{
@@ -171,7 +171,7 @@ static inline int s32_regmap_write(struct pinctrl_dev *pctldev,
}
-static inline int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
+static int s32_regmap_update(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned int mask, unsigned int val)
{
struct s32_pinctrl_mem_region *region;
@@ -484,8 +484,8 @@ static int s32_get_slew_regval(int arg)
return -EINVAL;
}
-static inline void s32_pin_set_pull(enum pin_config_param param,
- unsigned int *mask, unsigned int *config)
+static void s32_pin_set_pull(enum pin_config_param param,
+ unsigned int *mask, unsigned int *config)
{
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
--
2.34.1
^ permalink raw reply related
* [PATCH v11 3/6] pinctrl: s32cc: change to "devm_pinctrl_register_and_init"
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
In-Reply-To: <20260610132116.1998140-1-khristineandreea.barbulescu@oss.nxp.com>
From: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Switch from "devm_pinctrl_register" to "devm_pinctrl_register_and_init"
and "pinctrl_enable" since this is the recommended way.
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Andrei Stefanescu <andrei.stefanescu@oss.nxp.com>
Signed-off-by: Khristine Andreea Barbulescu <khristineandreea.barbulescu@oss.nxp.com>
---
drivers/pinctrl/nxp/pinctrl-s32cc.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/drivers/pinctrl/nxp/pinctrl-s32cc.c b/drivers/pinctrl/nxp/pinctrl-s32cc.c
index 2645a92df0ba..89a4eb2000ee 100644
--- a/drivers/pinctrl/nxp/pinctrl-s32cc.c
+++ b/drivers/pinctrl/nxp/pinctrl-s32cc.c
@@ -978,10 +978,10 @@ int s32_pinctrl_probe(struct platform_device *pdev,
return ret;
}
- ipctl->pctl = devm_pinctrl_register(&pdev->dev, s32_pinctrl_desc,
- ipctl);
- if (IS_ERR(ipctl->pctl))
- return dev_err_probe(&pdev->dev, PTR_ERR(ipctl->pctl),
+ ret = devm_pinctrl_register_and_init(&pdev->dev, s32_pinctrl_desc,
+ ipctl, &ipctl->pctl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
"Could not register s32 pinctrl driver\n");
#ifdef CONFIG_PM_SLEEP
@@ -994,7 +994,12 @@ int s32_pinctrl_probe(struct platform_device *pdev,
return -ENOMEM;
#endif
- dev_info(&pdev->dev, "initialized s32 pinctrl driver\n");
+ ret = pinctrl_enable(ipctl->pctl);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret,
+ "Failed to enable pinctrl\n");
+
+ dev_info(&pdev->dev, "Initialized S32 pinctrl driver\n");
return 0;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v11 0/6] gpio: siul2-s32g2: add initial GPIO driver
From: Khristine Andreea Barbulescu @ 2026-06-10 13:21 UTC (permalink / raw)
To: Linus Walleij, Bartosz Golaszewski, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Chester Lin, Matthias Brugger,
Ghennadi Procopciuc, Larisa Grigore, Lee Jones, Shawn Guo,
Sascha Hauer, Fabio Estevam, Dong Aisheng, Jacky Bai,
Greg Kroah-Hartman, Rafael J. Wysocki, Srinivas Kandagatla
Cc: Alberto Ruiz, Christophe Lizzi, devicetree, Enric Balletbo,
Eric Chanudet, imx, linux-arm-kernel, linux-gpio, linux-kernel,
NXP S32 Linux Team, Pengutronix Kernel Team, Vincent Guittot
This patch series adds support for basic GPIO
operations using gpio-regmap.
There are two SIUL2 hardware modules: SIUL2_0 and SIUL2_1.
However, this driver exports both as a single GPIO driver.
This is because the interrupt registers are located only
in SIUL2_1, even for GPIOs that are part of SIUL2_0.
There are two gaps in the GPIO ranges:
- 102-111(inclusive) are invalid
- 123-143(inclusive) are invalid
Writing and reading GPIO values is done via the PGPDO/PGPDI
registers(Parallel GPIO Pad Data Output/Input) which are
16 bit registers, each bit corresponding to a GPIO.
Note that the PGPDO order is similar to a big-endian grouping
of two registers:
PGPDO1, PGPDO0, PGPDO3, PGPDO2, PGPDO5, PGPDO4, gap, PGPDO6.
v11 -> v10:
- add GPIOLIB as explicit Kconfig dependency
- mark regmap config as fast_io to avoid mutex overhead
- propagate regmap errors in debug show callback and
suspend/resume paths instead of silently discarding them
- introduce a per-range sparse flag to handle SIUL2 instances
with a non-linear PGPD layout
- dt-bindings: drop redundant minItems from legacy oneOf branch,
add gpio-controller: false and related properties to prevent
GPIO/IRQ properties without the required reg entries and
drop maxItems from the GPIO+IRQ branch
v10 -> v9:
- implement GPIO via gpio-regmap backed by a regmap for
PGPDO/PGPDI register translation
- remove the successful probe message from the driver
- switch back to a single compatible string for both the
legacy and extended binding layout
- update binding: GPIO/IRQ properties required only
when extended reg layout is used
- remove unnecessary return value checks for MMIO
regmap operations
- replace kernel-doc style comments with regular comments
- solve relevant sashiko.dev findings
- rework GPIO request handling to preserve pinctrl ownership
- use __free(kfree) and no_free_ptr() in GPIO request path cleanup
v9 -> v8
- remove the SIUL2 syscon child nodes from the
device tree and DT bindings
- remove syscon child handling from the MFD
and pinctrl drivers
- remove the MFD driver and use a single monolithic
pinctrl/gpio/irqchip driver
- add a new compatible for the pinctrl+gpio binding
while keeping the previous compatible for the legacy
pinctrl-only binding
- update bindings to include the PGPDO/PGPDI and
IRQ register regions in the DT node for the
pinctrl/gpio/irq binding
- add IRQ-related entries in the bindings to
document the intended hierarchy; IRQ support
itself will be added in a future patch series
- update DT nodes to match the new hierarchy and
compatible scheme
- fix dtb warnings
- reorder commits: bug fixes, API changes, DT bindings,
driver implementation, DTS changes
- split commits further to separate minor
style-only adjustments
v8 -> v7
- remove all ': true' lines from properties in dt bindings
- remove NVMEM MFD cell from SIUL2 in dtsi
- remove NVMEM driver and configs
- expose SoC information via syscon cells SIUL2_0
and SIUL2_1 in MFD driver
- add SIUL2_0 and SIUL2_1 syscon nodes in dtsi
- add patternProperties for "^siul2_[0-1]$" for syscon nodes
- update example to include syscon cells with proper format
- remove `reg` property from pinctrl node in dt binding
- update Kconfig help text to reflect new syscon structure
instead of NVMEM for SoC information
- squash deprecated SIUL2 pinctrl binding with new MFD binding
- dropped "nxp,s32g3-siul2" from MFD driver match table
- fixed commit messages
- fixed dtb warnings
v7 -> v6
- fixed MAINTAINERS wrong file path
- add unevaluatedProperties, change siul2 node name, remove
jtag_pins label in the device tree schema
- change compatible definition in schema
- change node name in dtsi
- mentioned binding deprecation in commit messages
- split mfd cell conversion commit in two: one for the
previous refactoring, one for the mfd cell conversion
- removed Acked-by: Linus Walleij from commit:
"pinctrl: s32: convert the driver into an mfd cell"
because of changes to that commit
- deprecate the nxp,s32g2-siul2-pinctrl binding
- add NVMEM MFD cell for SIUL2
- made the GPIO driver not export invalid pins
(there are some gaps 102-111, 123-143)
- removed the need for gpio-reserved-ranges
- force initialized pinctrl_desc->num_custom_params to 0
v6 -> v5
- removed description for reg in the dt-bindings and added
maxItems
- dropped label for example in the dt-bindings
- simplified the example in the dt-bindings
- changed dt-bindings filename to nxp,s32g2-siul2.yaml
- changed title in the dt-bindings
- dropped minItmes from gpio-ranges/gpio-reserved-ranges
and added maxItems to gpio-reserved-ranges
- added required block for -grp[0-9]$ nodes
- switch to using "" as quotes
- kernel test robot: fixed frame sizes, added description
for reg_name, fixed typo in gpio_configs_lock, removed
uninitialized ret variable usage
- ordered includes in nxp-siul2.c, switched to dev-err-probe
added a mention that other commits will add nvmem functionality
to the mfd driver
- switched spin_lock_irqsave to scoped_guard statement
- switched dev_err to dev_err_probe in pinctrl-s32cc in places
reached during the probing part
v5 -> v4
- fixed di_div error
- fixed dt-bindings error
- added Co-developed-by tags
- added new MFD driver nxp-siul2.c
- made the old pinctrl driver an MFD cell
- added the GPIO driver in the existing SIUL2 pinctrl one
- Switch from "devm_pinctrl_register" to
"devm_pinctrl_register_and_init"
v4 -> v3
- removed useless parentheses
- added S32G3 fallback compatible
- fixed comment alignment
- fixed dt-bindings license
- fixed modpost: "__udivdi3"
- moved MAINTAINERS entry to have the new GPIO driver
together with other files related to S32G
v3 -> v2
- fix dt-bindings schema id
- add maxItems to gpio-ranges
- removed gpio label from dt-bindings example
- added changelog for the MAINTAINERS commit and
added separate entry for the SIUL2 GPIO driver
- added guard(raw_spinlock_irqsave) in
'siul2_gpio_set_direction'
- updated the description for
'devm_platform_get_and_ioremap_resource_byname'
v2 -> v1
dt-bindings:
- changed filename to match compatible
- fixed commit messages
- removed dt-bindings unnecessary properties descriptions
- added minItems for the interrupts property
driver:
- added depends on ARCH_S32 || COMPILE_TEST to Kconfig
- added select REGMAP_MMIO to Kconfig
- remove unnecessary include
- add of_node_put after `siul2_get_gpio_pinspec`
- removed inline from function definitions
- removed match data and moved the previous platdata
definition to the top of the file to be visible
- replace bitmap_set/clear with __clear_bit/set_bit
and devm_bitmap_zalloc with devm_kzalloc
- switched to gpiochip_generic_request/free/config
- fixed dev_err format for size_t reported by
kernel test robot
- add platform_get_and_ioremap_resource_byname wrapper
Andrei Stefanescu (2):
pinctrl: s32cc: change to "devm_pinctrl_register_and_init"
pinctrl: s32cc: implement GPIO functionality
Khristine Andreea Barbulescu (4):
pinctrl: s32cc: add/fix some comments
pinctrl: s32cc: remove inline specifiers
dt-bindings: pinctrl: s32g2-siul2: describe GPIO and EIRQ resources
arm64: dts: s32g: describe GPIO and EIRQ resources in SIUL2 pinctrl
node
.../pinctrl/nxp,s32g2-siul2-pinctrl.yaml | 90 ++-
arch/arm64/boot/dts/freescale/s32g2.dtsi | 23 +-
arch/arm64/boot/dts/freescale/s32g3.dtsi | 23 +-
drivers/pinctrl/nxp/Kconfig | 3 +-
drivers/pinctrl/nxp/pinctrl-s32.h | 35 +-
drivers/pinctrl/nxp/pinctrl-s32cc.c | 756 ++++++++++++++++--
drivers/pinctrl/nxp/pinctrl-s32g2.c | 47 +-
7 files changed, 877 insertions(+), 100 deletions(-)
--
2.34.1
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 13:20 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
Hi Will,
On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>> - A PE executes a Device-nGnR* store followed by a younger
>> Device-nGnR* load.
>> - The store is not a store-release.
>> - The accesses target the same peripheral and do not overlap in bytes.
>> - There is at most one intervening Device-nGnR* store in program
>> order, and there are no intervening Device-nGnR* loads.
>> - There is no DSB, and no DMB that orders loads, between the store and
>> the load.
>> - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.
>
>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.
Based on the existing code comments and after reviewing this path again,
__const_memcpy_toio_aligned32() and __const_memcpy_toio_aligned64()
appear to be intended for WC regions. Since the erratum is scoped to
Device-nGnR* accesses, and WC mappings are Normal-NC on arm64, I don’t
think the STLR workaround should apply to these helpers by default.
Applying it there would also break the contiguous STR grouping that
this path relies on for write combining.
-Shanker
^ permalink raw reply
* Re: [PATCH v3 0/9] ARM: dts: aspeed: anacapa: restructure devicetree for development-phase
From: Andrew Jeffery @ 2026-06-10 13:04 UTC (permalink / raw)
To: u8813345, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Joel Stanley
Cc: devicetree, linux-arm-kernel, linux-aspeed, linux-kernel,
colin.huang2, Carl Lee, Rex Fu, Andy Chung, Peter Shen
In-Reply-To: <20260602-anacapa-devlop-phase-devicetree-v3-0-7c93c5df8d9b@gmail.com>
On Tue, 2026-06-02 at 21:24 +0800, Colin Huang via B4 Relay wrote:
> This series refactors the Anacapa BMC devicetree layout to better support
> development-phase hardware revisions (EVT1/EVT2/DVT) while keeping a platform
> entrypoint.
>
> Signed-off-by: Colin Huang <u8813345@gmail.com>
> ---
> Changes in v3:
> - Restructure the EVT2 devicetree to inherit from the EVT1 devicetree, making it incremental rather than standalone.
> - Add the DVT devicetree, inheriting from the EVT2 devicetree.
> - Enable MCTP and FRU support for the NIC.
> - Align PDB fan GPIO numbering.
> - Add an EEPROM device node for the NFC adaptor board.
> - Add an additional EEPROM device node for the SCM.
> - Add shunt resistor values for HSC monitors
> - Link to v2: https://lore.kernel.org/r/20260409-anacapa-devlop-phase-devicetree-v2-0-68f328671653@gmail.com
>
So just to check, the changes in patches 5-8 inclusive are applicable
to all of EVT1, EVT2 and DVT (given the way you've structured the
includes)?
> Changes in v2:
> - Fix dtbs_check fail.
> Validated by following command:
> make dt_binding_check DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml
> make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa.dtb
> make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa-evt1.dtb
> make CHECK_DTBS=y DT_SCHEMA_FILES=arm/aspeed/aspeed.yaml aspeed/aspeed-bmc-facebook-anacapa-evt2.dtb
> - Link to v1: https://lore.kernel.org/r/20260407-anacapa-devlop-phase-devicetree-v1-0-97b96367cac3@gmail.com
>
> ---
> Andy Chung (1):
> ARM: dts: aspeed: anacapa: Enable MCTP and FRU for NIC
>
> Carl Lee (1):
> ARM: dts: aspeed: anacapa: Add eeprom device node for NFC adaptor board
>
> Colin Huang (5):
> dt-bindings: arm: aspeed: add Anacapa EVT1 EVT2 DVT board
> ARM: dts: aspeed: anacapa: add EVT1 devicetree and point wrapper to it
> ARM: dts: aspeed: anacapa: add EVT2 devicetree inheriting EVT1
> ARM: dts: aspeed: anacapa: add DVT devicetree inheriting EVT2
> ARM: dts: aspeed: anacapa: add additional EEPROM node for SCM
If you need to respin this series for some reason, can you please
capitalise the first word of the short description (the bit after the
last ':') for the commits above and the one below?
>
> Peter Shen (1):
> ARM: dts: aspeed: anacapa: evt2: add shunt resistor values for HSC monitors
>
> Rex Fu (1):
> ARM: dts: aspeed: anacapa: Align PDB fan GPIO numbering
>
> .../devicetree/bindings/arm/aspeed/aspeed.yaml | 3 +
> .../dts/aspeed/aspeed-bmc-facebook-anacapa-dvt.dts | 178 +++
> .../aspeed/aspeed-bmc-facebook-anacapa-evt1.dts | 1179 ++++++++++++++++++++
> .../aspeed/aspeed-bmc-facebook-anacapa-evt2.dts | 228 ++++
> .../dts/aspeed/aspeed-bmc-facebook-anacapa.dts | 1077 +-----------------
> 5 files changed, 1589 insertions(+), 1076 deletions(-)
> ---
> base-commit: 7ca1caf017d34396397b19fb4de9ecef256f4acc
> change-id: 20260407-anacapa-devlop-phase-devicetree-4101d3f312c0
>
> Best regards,
Andrew
^ permalink raw reply
* Re: [PATCH] ASoC: meson: axg-tdm-formatter: Use guard() for mutex locks
From: Jerome Brunet @ 2026-06-10 12:54 UTC (permalink / raw)
To: phucduc.bui
Cc: Mark Brown, Liam Girdwood, Neil Armstrong, Kevin Hilman,
Martin Blumenstingl, Jaroslav Kysela, Takashi Iwai, linux-sound,
linux-arm-kernel, linux-amlogic, linux-kernel
In-Reply-To: <20260610102153.83367-1-phucduc.bui@gmail.com>
On mer. 10 juin 2026 at 17:21, phucduc.bui@gmail.com wrote:
> From: bui duc phuc <phucduc.bui@gmail.com>
>
> Clean up the code using guard() for mutex locks.
> Merely code refactoring, and no behavior change.
I suppose it is OK but it does not seem to really clean anything and
make the code easier to follow in that instance, from my perspective at
least.
If there is policy to systematically use guard() whenever
possible then OK, otherwise it seems unnecessary.
>
> Signed-off-by: bui duc phuc <phucduc.bui@gmail.com>
> ---
> sound/soc/meson/axg-tdm-formatter.c | 22 ++++++++--------------
> 1 file changed, 8 insertions(+), 14 deletions(-)
>
> diff --git a/sound/soc/meson/axg-tdm-formatter.c b/sound/soc/meson/axg-tdm-formatter.c
> index f451e4dce442..a6ba401104d5 100644
> --- a/sound/soc/meson/axg-tdm-formatter.c
> +++ b/sound/soc/meson/axg-tdm-formatter.c
> @@ -157,20 +157,19 @@ static int axg_tdm_formatter_attach(struct axg_tdm_formatter *formatter)
> struct axg_tdm_stream *ts = formatter->stream;
> int ret = 0;
>
> - mutex_lock(&ts->lock);
> + guard(mutex)(&ts->lock);
>
> /* Catch up if the stream is already running when we attach */
> if (ts->ready) {
> ret = axg_tdm_formatter_enable(formatter);
> if (ret) {
> pr_err("failed to enable formatter\n");
> - goto out;
> + return ret;
> }
> }
>
> list_add_tail(&formatter->list, &ts->formatter_list);
> -out:
> - mutex_unlock(&ts->lock);
> +
> return ret;
> }
>
> @@ -178,9 +177,8 @@ static void axg_tdm_formatter_dettach(struct axg_tdm_formatter *formatter)
> {
> struct axg_tdm_stream *ts = formatter->stream;
>
> - mutex_lock(&ts->lock);
> - list_del(&formatter->list);
> - mutex_unlock(&ts->lock);
> + scoped_guard(mutex, &ts->lock)
> + list_del(&formatter->list);
>
> axg_tdm_formatter_disable(formatter);
> }
> @@ -330,7 +328,7 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
> struct axg_tdm_formatter *formatter;
> int ret = 0;
>
> - mutex_lock(&ts->lock);
> + guard(mutex)(&ts->lock);
> ts->ready = true;
>
> /* Start all the formatters attached to the stream */
> @@ -338,12 +336,10 @@ int axg_tdm_stream_start(struct axg_tdm_stream *ts)
> ret = axg_tdm_formatter_enable(formatter);
> if (ret) {
> pr_err("failed to start tdm stream\n");
> - goto out;
> + return ret;
> }
> }
>
> -out:
> - mutex_unlock(&ts->lock);
> return ret;
> }
> EXPORT_SYMBOL_GPL(axg_tdm_stream_start);
> @@ -352,15 +348,13 @@ void axg_tdm_stream_stop(struct axg_tdm_stream *ts)
> {
> struct axg_tdm_formatter *formatter;
>
> - mutex_lock(&ts->lock);
> + guard(mutex)(&ts->lock);
> ts->ready = false;
>
> /* Stop all the formatters attached to the stream */
> list_for_each_entry(formatter, &ts->formatter_list, list) {
> axg_tdm_formatter_disable(formatter);
> }
> -
> - mutex_unlock(&ts->lock);
> }
> EXPORT_SYMBOL_GPL(axg_tdm_stream_stop);
--
Jerome
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Shanker Donthineni @ 2026-06-10 12:53 UTC (permalink / raw)
To: Will Deacon
Cc: Catalin Marinas, linux-arm-kernel, Vladimir Murzin, Mark Rutland,
linux-kernel, linux-doc, Vikram Sethi, Jason Sequeira, jgg
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
Hi Will,
On 6/10/2026 6:28 AM, Will Deacon wrote:
> External email: Use caution opening links or attachments
>
>
> [+Jason G]
>
> On Fri, Jun 05, 2026 at 09:45:51AM -0500, Shanker Donthineni wrote:
>> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
>> observed by a peripheral before an older, non-overlapping Device-nGnR*
>> store to the same peripheral. This breaks the program-order guarantee
>> that software expects for Device-nGnR* accesses and can leave a
>> peripheral in an incorrect state, as a load is observed before an
>> earlier store takes effect.
>>
>> The erratum can occur only when all of the following apply:
>>
>> - A PE executes a Device-nGnR* store followed by a younger
>> Device-nGnR* load.
>> - The store is not a store-release.
>> - The accesses target the same peripheral and do not overlap in bytes.
>> - There is at most one intervening Device-nGnR* store in program
>> order, and there are no intervening Device-nGnR* loads.
>> - There is no DSB, and no DMB that orders loads, between the store and
>> the load.
>> - Specific micro-architectural and timing conditions occur.
>>
>> Two ways to restore ordering: insert a barrier (any DSB, or a DMB that
>> orders loads) between the store and the load, or make the store a
>> store-release. A load-acquire on the load side would not help, because
>> acquire semantics do not prevent a load from being observed ahead of an
>> older store; only the store side (release or a barrier) closes the
>> window.
> I think you can drop the paragraph above. A store-release isn't enough
> to order against a later load in the architecture either, so we're
> clearly in micro-architecture territory and I don't think you need to
> describe mechanisms that don't work here.
Thanks, Will. I’ll drop paragraph and avoid describing store-release
as an architectural ordering mechanism here.
>> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
>> to stlr* (Store-Release), which removes the "store is not a
>> store-release" condition for every device write the kernel issues.
>> Because writel() and writel_relaxed() are both built on __raw_writel()
>> in asm-generic/io.h, patching the raw variants covers both the
>> non-relaxed and relaxed APIs without touching the higher layers. Note
>> that writel()'s own barrier sits before the store, so it does not order
>> the store against a subsequent readl(); the store-release promotion is
>> what provides that ordering.
> Sashiko points out that you're missing __const_memcpy_toio_aligned32().
I’ll also cover __const_memcpy_toio_aligned32(); it currently emits plain
STRs directly and can bypass the raw write helper workaround. I’ll audit
the aligned64 path at the same time.
>> Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
>> ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
>> parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
>> the plain str* sequence.
>>
>> Note: stlr* only supports base-register addressing, so the raw accessors
>> can no longer use the offset addressing introduced by commit d044d6ba6f02
>> ("arm64: io: permit offset addressing"). The str* and stlr* alternates
>> share a single inline-asm operand and the sequence is selected at boot,
>> so the operand form is fixed at compile time; unaffected CPUs keep using
>> str* but also revert to base-register addressing. This keeps the store
>> side as simple as the existing load-side patching (load-acquire) and
>> avoids adding complexity to the device write path; retaining offset
>> addressing only for str* would otherwise require a runtime branch on
>> every write.
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?
For the offset-addressing concern, I’ll rework the raw accessors so
unaffected CPUs keep the existing offset-addressed STR sequence, and
only CPUs with ARM64_WORKAROUND_DEVICE_STORE_RELEASE take the base-register
STLR path.
I’ll post a v3 using the patched branch from alternative_has_cap_unlikely(),
and include the memcpy_toio() aligned-helper coverage as shown below.
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
/*
* Generic IO read/write. These perform native-endian accesses.
*/
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+ return alternative_has_cap_unlikely(
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
#define __raw_writeb __raw_writeb
static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
volatile u8 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeb_stlr(val, addr);
+ return;
+ }
+
asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
volatile u16 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writew_stlr(val, addr);
+ return;
+ }
+
asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
volatile u32 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writel_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
volatile u64 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeq_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -147,6 +201,12 @@ static __always_inline void
__const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writel_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
__const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writeq_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %x0, [%8, #8 * 0]\n"
I'll post v3 patch with jump instruction patch.
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -22,10 +22,46 @@
/*
* Generic IO read/write. These perform native-endian accesses.
*/
+static __always_inline bool arm64_needs_device_store_release(void)
+{
+ return alternative_has_cap_unlikely(
+ ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
+}
+
+static __always_inline void __raw_writeb_stlr(u8 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writew_stlr(u16 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlrh %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writel_stlr(u32 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %w0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
+static __always_inline void __raw_writeq_stlr(u64 val,
+ volatile void __iomem *addr)
+{
+ asm volatile("stlr %x0, [%1]" : : "rZ" (val), "r" (addr));
+}
+
#define __raw_writeb __raw_writeb
static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
volatile u8 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeb_stlr(val, addr);
+ return;
+ }
+
asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -33,6 +69,12 @@ static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
volatile u16 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writew_stlr(val, addr);
+ return;
+ }
+
asm volatile("strh %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -40,6 +82,12 @@ static __always_inline void __raw_writew(u16 val, volatile void __iomem *addr)
static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
volatile u32 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writel_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %w0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -47,6 +95,12 @@ static __always_inline void __raw_writel(u32 val, volatile void __iomem *addr)
static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
volatile u64 __iomem *ptr = addr;
+
+ if (arm64_needs_device_store_release()) {
+ __raw_writeq_stlr(val, addr);
+ return;
+ }
+
asm volatile("str %x0, %1" : : "rZ" (val), "Qo" (*ptr));
}
@@ -147,6 +201,12 @@ static __always_inline void
__const_memcpy_toio_aligned32(volatile u32 __iomem *to, const u32 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writel_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %w0, [%8, #4 * 0]\n"
@@ -204,6 +264,12 @@ static __always_inline void
__const_memcpy_toio_aligned64(volatile u64 __iomem *to, const u64 *from,
size_t count)
{
+ if (arm64_needs_device_store_release()) {
+ while (count--)
+ __raw_writeq_stlr(*from++, to++);
+ return;
+ }
+
switch (count) {
case 8:
asm volatile("str %x0, [%8, #8 * 0]\n"
-Shanker
^ permalink raw reply
* Re: [PATCH v2 2/2] soc: aspeed: add host-side PCIe BMC device driver
From: Andrew Jeffery @ 2026-06-10 12:51 UTC (permalink / raw)
To: Grégoire Layet, joel
Cc: andrew, jacky_chou, yh_chung, ninad, linux-aspeed,
linux-arm-kernel, linux-kernel
In-Reply-To: <13d18d25f53e0a084a8c17219804b305d4667c6b.1780929570.git.gregoire.layet@9elements.com>
On Mon, 2026-06-08 at 14:51 +0000, Grégoire Layet wrote:
> Taken from ASPEED 6.18 Kernel SDK
>
> Add support for VUART over PCIe between BMC and host.
> This add host side driver.
>
> Signed-off-by: Jacky Chou <jacky_chou@aspeedtech.com>
> Signed-off-by: aspeedyh <yh_chung@aspeedtech.com>
> Signed-off-by: Grégoire Layet <gregoire.layet@9elements.com>
> Tested-by: Grégoire Layet <gregoire.layet@9elements.com>
> ---
> drivers/soc/aspeed/Kconfig | 8 +
> drivers/soc/aspeed/Makefile | 1 +
> drivers/soc/aspeed/aspeed-host-bmc-dev.c | 249 +++++++++++++++++++++++
Again, I'd rather we avoid drivers/soc/aspeed.
> 3 files changed, 258 insertions(+)
> create mode 100644 drivers/soc/aspeed/aspeed-host-bmc-dev.c
>
> diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig
> index 3e1fcf3c3268..5deefb64e8c7 100644
> --- a/drivers/soc/aspeed/Kconfig
> +++ b/drivers/soc/aspeed/Kconfig
> @@ -11,6 +11,14 @@ config ASPEED_BMC_DEV
> Enable support for the ASPEED AST2600 BMC Device.
> This exposes the PCIe-to-LPC bridge of the BMC to the host over PCIe.
>
> +config ASPEED_HOST_BMC_DEV
> + tristate "ASPEED Host BMC Device"
> + depends on PCI
> + depends on SERIAL_8250
> + help
> + Enable support for the ASPEED AST2600 BMC Device on the Host.
> + This configure the PCIe and setup two 8250 compatible VUART ports.
> +
> config ASPEED_LPC_CTRL
> tristate "ASPEED LPC firmware cycle control"
> select REGMAP
> diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
> index fab0d247df66..3fd3f6d8d36e 100644
> --- a/drivers/soc/aspeed/Makefile
> +++ b/drivers/soc/aspeed/Makefile
> @@ -1,5 +1,6 @@
> # SPDX-License-Identifier: GPL-2.0-only
> obj-$(CONFIG_ASPEED_BMC_DEV) += aspeed-bmc-dev.o
> +obj-$(CONFIG_ASPEED_HOST_BMC_DEV) += aspeed-host-bmc-dev.o
> obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o
> obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
> obj-$(CONFIG_ASPEED_UART_ROUTING) += aspeed-uart-routing.o
> diff --git a/drivers/soc/aspeed/aspeed-host-bmc-dev.c b/drivers/soc/aspeed/aspeed-host-bmc-dev.c
> new file mode 100644
> index 000000000000..7cb52a770fb6
> --- /dev/null
> +++ b/drivers/soc/aspeed/aspeed-host-bmc-dev.c
> @@ -0,0 +1,249 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +// Copyright (C) ASPEED Technology Inc.
> +
> +#include <linux/init.h>
> +#include <linux/version.h>
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/pci.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial_8250.h>
> +
> +static DEFINE_IDA(bmc_device_ida);
> +
> +#define VUART_MAX_PARMS 2
Given the one supported piece of hardware we could avoid the associated
loops and rather extract loop bodies to functions and call the function
twice.
> +#define MAX_MSI_NUM 8
> +#define BMC_MULTI_MSI 32
> +
> +#define DRIVER_NAME "aspeed-host-bmc-dev"
> +
> +enum aspeed_platform_id {
> + ASPEED,
> +};
> +
> +enum msi_index {
> + VUART0_MSI,
> + VUART1_MSI,
> +};
> +
> +/* Match msi_index */
> +static int ast2600_msi_idx_table[MAX_MSI_NUM] = { 16, 15 };
> +
> +struct aspeed_platform {
> + int (*setup)(struct pci_dev *pdev);
> +};
> +
> +struct aspeed_pci_bmc_dev {
> + struct device *dev;
> + struct aspeed_platform *platform;
> + kernel_ulong_t driver_data;
> + int id;
> +
> + unsigned long message_bar_base;
> + unsigned long message_bar_size;
> + void __iomem *msg_bar_reg;
> +
> + struct uart_8250_port uart[VUART_MAX_PARMS];
> + int uart_line[VUART_MAX_PARMS];
> +
> + /* Interrupt
> + * The index of array is using to enum msi_index
> + */
> + int *msi_idx_table;
> +};
> +
> +static void aspeed_pci_setup_irq_resource(struct pci_dev *pdev)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +
> + /* Assign static msi index table by platform */
> + pci_bmc_dev->msi_idx_table = ast2600_msi_idx_table;
> +
> + if (pci_alloc_irq_vectors(pdev, 1, BMC_MULTI_MSI, PCI_IRQ_INTX | PCI_IRQ_MSI) <= 1)
> + /* Set all msi index to the first vector */
> + memset(pci_bmc_dev->msi_idx_table, 0, sizeof(int) * MAX_MSI_NUM);
> +}
> +
> +static int aspeed_pci_bmc_device_setup_vuart(struct pci_dev *pdev)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> + struct device *dev = &pdev->dev;
> + u16 vuart_ioport;
> + int ret, i;
> +
> + for (i = 0; i < VUART_MAX_PARMS; i++) {
> + /* Assign the line to non-exist device */
> + pci_bmc_dev->uart_line[i] = -ENOENT;
> + vuart_ioport = 0x3F8 - (i * 0x100);
> + pci_bmc_dev->uart[i].port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
> + pci_bmc_dev->uart[i].port.uartclk = 115200 * 16;
> + pci_bmc_dev->uart[i].port.irq =
> + pci_irq_vector(pdev, pci_bmc_dev->msi_idx_table[VUART0_MSI + i]);
> + pci_bmc_dev->uart[i].port.dev = dev;
> + pci_bmc_dev->uart[i].port.iotype = UPIO_MEM32;
> + pci_bmc_dev->uart[i].port.iobase = 0;
> + pci_bmc_dev->uart[i].port.mapbase =
> + pci_bmc_dev->message_bar_base + (vuart_ioport << 2);
> + pci_bmc_dev->uart[i].port.membase = 0;
> + pci_bmc_dev->uart[i].port.type = PORT_16550A;
> + pci_bmc_dev->uart[i].port.flags |= (UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE);
> + pci_bmc_dev->uart[i].port.regshift = 2;
> + ret = serial8250_register_8250_port(&pci_bmc_dev->uart[i]);
> + if (ret < 0) {
> + dev_err_probe(dev, ret, "Can't setup PCIe VUART\n");
> + return ret;
> + }
> + pci_bmc_dev->uart_line[i] = ret;
> + }
> + return 0;
> +}
> +
> +static void aspeed_pci_host_bmc_device_release_vuart(struct pci_dev *pdev)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> + int i;
> +
> + for (i = 0; i < VUART_MAX_PARMS; i++) {
> + if (pci_bmc_dev->uart_line[i] >= 0)
> + serial8250_unregister_port(pci_bmc_dev->uart_line[i]);
> + }
> +}
> +
> +static int aspeed_pci_host_setup(struct pci_dev *pdev)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> + int rc = 0;
> +
> + /* Get Message BAR */
> + pci_bmc_dev->message_bar_base = pci_resource_start(pdev, 1);
> + pci_bmc_dev->message_bar_size = pci_resource_len(pdev, 1);
> + pci_bmc_dev->msg_bar_reg = pci_ioremap_bar(pdev, 1);
> + if (!pci_bmc_dev->msg_bar_reg)
> + return -ENOMEM;
> +
> + if (pdev->revision < 0x27) {
> + /* AST2600 ERRTA40: dummy read */
Can you please rather document what problem this is actually solving.
> + (void)__raw_readl((void __iomem *)pci_bmc_dev->msg_bar_reg);
> + } else {
> + /* AST2700 not supported */
> + pr_err("AST2700 detected but not supported");
This logs an error but rc = 0 on return. Perhaps drop the log message
and return an appropriate error code?
> + goto out_free0;
> + }
> +
> + rc = aspeed_pci_bmc_device_setup_vuart(pdev);
> + if (rc) {
> + pr_err("Cannot setup Virtual UART");
> + goto out_free0;
> + }
> +
> + return 0;
> +
> +out_free0:
> + pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
> +
> + return rc;
> +}
> +
> +static struct aspeed_platform aspeed_pcie_host[] = {
> + { .setup = aspeed_pci_host_setup },
> + { 0 }
> +};
> +
> +static int aspeed_pci_host_bmc_device_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev;
> + int rc = 0;
> +
> + pr_info("ASPEED BMC PCI ID %04x:%04x, IRQ=%u\n", pdev->vendor, pdev->device, pdev->irq);
I think we could do without this.
> +
> + pci_bmc_dev = devm_kzalloc(&pdev->dev, sizeof(*pci_bmc_dev), GFP_KERNEL);
> + if (!pci_bmc_dev)
> + return -ENOMEM;
> +
> + /* Get platform id */
> + pci_bmc_dev->driver_data = ent->driver_data;
> + pci_bmc_dev->platform = &aspeed_pcie_host[ent->driver_data];
> +
> + pci_bmc_dev->id = ida_alloc(&bmc_device_ida, GFP_KERNEL);
This seems unnecessary.
> + if (pci_bmc_dev->id < 0)
> + return pci_bmc_dev->id;
> +
> + rc = pci_enable_device(pdev);
> + if (rc) {
> + dev_err(&pdev->dev, "pci_enable_device() returned error %d\n", rc);
> + return rc;
> + }
> +
> + pci_set_master(pdev);
> + pci_set_drvdata(pdev, pci_bmc_dev);
> +
> + /* Prepare IRQ resource */
> + aspeed_pci_setup_irq_resource(pdev);
> +
> + /* Setup BMC PCI device */
> + rc = pci_bmc_dev->platform->setup(pdev);
As with patch 1 this indirection seems unnecessary.
> + if (rc) {
> + dev_err(&pdev->dev, "ASPEED PCIe Host device returned error %d\n", rc);
> + pci_free_irq_vectors(pdev);
> + pci_disable_device(pdev);
> + return rc;
> + }
> +
> + return 0;
> +}
> +
> +static void aspeed_pci_host_bmc_device_remove(struct pci_dev *pdev)
> +{
> + struct aspeed_pci_bmc_dev *pci_bmc_dev = pci_get_drvdata(pdev);
> +
> + if (pci_bmc_dev->driver_data == ASPEED)
This condition seems unnecessary as the value shouldn't be anything
else.
> + aspeed_pci_host_bmc_device_release_vuart(pdev);
> +
> + ida_free(&bmc_device_ida, pci_bmc_dev->id);
> +
> + pci_iounmap(pdev, pci_bmc_dev->msg_bar_reg);
> +
> + pci_free_irq_vectors(pdev);
> + pci_disable_device(pdev);
> +}
> +
> +/**
> + * This table holds the list of (VendorID,DeviceID) supported by this driver
> + *
> + */
I think that's self-evident and prefer the comment be removed.
> +static struct pci_device_id aspeed_host_bmc_dev_pci_ids[] = {
> + /* ASPEED BMC Device */
> + { PCI_DEVICE(0x1A03, 0x2402), .class = 0xFF0000, .class_mask = 0xFFFF00,
> + .driver_data = ASPEED },
> + {
> + 0,
> + }
> +};
> +
> +MODULE_DEVICE_TABLE(pci, aspeed_host_bmc_dev_pci_ids);
> +
> +static struct pci_driver aspeed_host_bmc_dev_driver = {
> + .name = DRIVER_NAME,
> + .id_table = aspeed_host_bmc_dev_pci_ids,
> + .probe = aspeed_pci_host_bmc_device_probe,
> + .remove = aspeed_pci_host_bmc_device_remove,
> +};
> +
> +static int __init aspeed_host_bmc_device_init(void)
> +{
> + return pci_register_driver(&aspeed_host_bmc_dev_driver);
> +}
> +
> +static void aspeed_host_bmc_device_exit(void)
> +{
> + /* unregister pci driver */
> + pci_unregister_driver(&aspeed_host_bmc_dev_driver);
> +}
> +
> +late_initcall(aspeed_host_bmc_device_init);
> +module_exit(aspeed_host_bmc_device_exit);
module_driver() could be used here.
> +
> +MODULE_AUTHOR("Ryan Chen <ryan_chen@aspeedtech.com>");
> +MODULE_DESCRIPTION("ASPEED Host BMC DEVICE Driver");
> +MODULE_LICENSE("GPL");
^ permalink raw reply
* Re: [PATCH 0/3] tty: serial: Add Cortina-Access UART driver and platform support
From: Arnd Bergmann @ 2026-06-10 12:50 UTC (permalink / raw)
To: Jason Li, jason.li, Greg Kroah-Hartman, Jiri Slaby
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Catalin Marinas,
Will Deacon, linux-serial, linux-arm-kernel, devicetree,
linux-kernel
In-Reply-To: <20260610112821.3030099-2-jason.li@cortina-access.com>
On Wed, Jun 10, 2026, at 13:28, Jason Li wrote:
> This series adds Linux kernel support for the UART controller integrated
> in Cortina-Access SoCs, with CA8289 (Venus) as the first supported device.
Hi Jason,
Thanks a lot for your submission!
I'm glad to see Cortina Access is getting back to upstreaming
this support, I see that you first tries this in 2021 but
didn't get very far at the time. The last submission was v4,
so it would make sense to cound this one as v5 and continue
with v6 next time.
You have already received a number of comments, so I'll skip
looking at the details for the moment and let you work through
them.
Regarding how to split up the patch series between uart and
soc, I think sending them together during the review phase
as you do here makes sense, but as they are loosely coupled,
I think we will likely merge them separately. For simplicity,
I would then just put the MAINTAINERS entry and the bindings
for the vendor and board into the series for the soc tree.
It would also help me if you could add some more context about
the SoC into the patch description for the patch that adds
the arm64 platform, in particular:
- is this the only one you are planning to upstream at this
point, or do you already have plans for other SoCs in this
family?
- do you expect to see full support for actual end-user
products using these chips?
- is there any shared lineage with the cortina-systems
(storlink/storm, now marvell) gemini 32-bit chips that we
already support, or with any of the Realtek SoCs that
are also being upstreamed now?
Arnd
^ permalink raw reply
* Re: [PATCH v2] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Jason Gunthorpe @ 2026-06-10 12:50 UTC (permalink / raw)
To: Will Deacon
Cc: Shanker Donthineni, Catalin Marinas, linux-arm-kernel,
Vladimir Murzin, Mark Rutland, linux-kernel, linux-doc,
Vikram Sethi, Jason Sequeira
In-Reply-To: <ailKYTOX23EMnJsK@willie-the-truck>
On Wed, Jun 10, 2026 at 12:28:33PM +0100, Will Deacon wrote:
> > Note: stlr* only supports base-register addressing, so the raw accessors
> > can no longer use the offset addressing introduced by commit d044d6ba6f02
> > ("arm64: io: permit offset addressing"). The str* and stlr* alternates
> > share a single inline-asm operand and the sequence is selected at boot,
> > so the operand form is fixed at compile time; unaffected CPUs keep using
> > str* but also revert to base-register addressing. This keeps the store
> > side as simple as the existing load-side patching (load-acquire) and
> > avoids adding complexity to the device write path; retaining offset
> > addressing only for str* would otherwise require a runtime branch on
> > every write.
>
> I seem to remember Jason caring about that, possibly because some CPUs
> are very picky about write-combining?
I think it was more a fall out of the work there, after looking at the
assembly this minor edit to the constraint made a nice codegen
impact. It is certainly a shame to loose it for this bug.
If we care about write combining we can't have a branch anyhow, but
that is most important for the specific memcpy operations (which will
need a branch)
Jason
^ permalink raw reply
* Re: [PATCH v3 2/2] clk: amlogic: Add A9 peripherals clock controller driver
From: Jerome Brunet @ 2026-06-10 12:49 UTC (permalink / raw)
To: Jian Hu via B4 Relay
Cc: Neil Armstrong, Michael Turquette, Stephen Boyd, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Xianwei Zhao, Kevin Hilman,
Martin Blumenstingl, jian.hu, linux-amlogic, linux-clk,
devicetree, linux-kernel, linux-arm-kernel
In-Reply-To: <20260610-a9_peripherals-v3-2-d07a78085f71@amlogic.com>
On mer. 10 juin 2026 at 16:14, Jian Hu via B4 Relay <devnull+jian.hu.amlogic.com@kernel.org> wrote:
> From: Jian Hu <jian.hu@amlogic.com>
>
> Add the peripherals clock controller driver for the Amlogic A9 SoC family.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
> drivers/clk/meson/Kconfig | 15 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a9-peripherals.c | 1925 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 1941 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index cf8cf3f9e4ee..86d2e270e1b8 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -132,6 +132,21 @@ config COMMON_CLK_A1_PERIPHERALS
> device, A1 SoC Family. Say Y if you want A1 Peripherals clock
> controller to work.
>
> +config COMMON_CLK_A9_PERIPHERALS
> + tristate "Amlogic A9 SoC peripherals clock controller support"
> + depends on ARM64 || COMPILE_TEST
> + default ARCH_MESON
> + select COMMON_CLK_MESON_REGMAP
> + select COMMON_CLK_MESON_CLKC_UTILS
> + select COMMON_CLK_MESON_DUALDIV
> + select COMMON_CLK_MESON_VID_PLL_DIV
> + imply COMMON_CLK_SCMI
> + imply COMMON_CLK_A9_PLL
> + help
> + Support for the peripherals clock controller on Amlogic A311Y3 based
> + device, AKA A9. Peripherals are required by most peripheral to operate.
> + Say Y if you want A9 peripherals clock controller to work.
> +
> config COMMON_CLK_C3_PLL
> tristate "Amlogic C3 PLL clock controller"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index c6719694a242..bccd9ace9201 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -19,6 +19,7 @@ obj-$(CONFIG_COMMON_CLK_AXG) += axg.o axg-aoclk.o
> obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o
> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a9-peripherals.c b/drivers/clk/meson/a9-peripherals.c
> new file mode 100644
> index 000000000000..fef48613e186
> --- /dev/null
> +++ b/drivers/clk/meson/a9-peripherals.c
> @@ -0,0 +1,1925 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
> + */
> +
> +#include <dt-bindings/clock/amlogic,a9-peripherals-clkc.h>
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +#include "vid-pll-div.h"
> +
> +#define SYS_CLK_EN0_REG0 0x30
> +#define SYS_CLK_EN0_REG1 0x34
> +#define SYS_CLK_EN0_REG2 0x38
> +#define SYS_CLK_EN0_REG3 0x3c
> +#define SD_EMMC_CLK_CTRL0 0x90
> +#define SD_EMMC_CLK_CTRL1 0x94
> +#define PWM_CLK_H_CTRL 0xbc
> +#define PWM_CLK_I_CTRL 0xc0
> +#define PWM_CLK_J_CTRL 0xc4
> +#define PWM_CLK_K_CTRL 0xc8
> +#define PWM_CLK_L_CTRL 0xcc
> +#define PWM_CLK_M_CTRL 0xd0
> +#define PWM_CLK_N_CTRL 0xd4
> +#define SPISG_CLK_CTRL 0x100
> +#define SPISG_CLK_CTRL1 0x104
> +#define SAR_CLK_CTRL 0x150
> +#define AMFC_CLK_CTRL 0x154
> +#define NNA_CLK_CTRL 0x15c
> +#define USB_CLK_CTRL 0x160
> +#define PCIE_TL_CLK_CTRL 0x164
> +#define CMPR_CLK_CTRL 0x168
> +#define DEWARP_CLK_CTRL 0x16c
> +#define SC_CLK_CTRL 0x170
> +#define DPTX_CLK_CTRL 0x178
> +#define ISP_CLK_CTRL 0x17c
> +#define CVE_CLK_CTRL 0x180
> +#define PP_CLK_CTRL 0x184
> +#define GLB_CLK_CTRL 0x188
> +#define USB_CLK_CTRL0 0x18c
> +#define USB_CLK_CTRL1 0x190
> +#define CAN_CLK_CTRL 0x194
> +#define CAN_CLK_CTRL1 0x198
> +#define I3C_CLK_CTRL 0x19c
> +#define TS_CLK_CTRL 0x1a0
> +#define ETH_CLK_CTRL 0x1a4
> +#define GEN_CLK_CTRL 0x1a8
> +#define CLK12_24_CTRL 0x1ac
> +#define MALI_CLK_CTRL 0x200
> +#define MALI_STACK_CLK_CTRL 0x204
> +#define DSPA_CLK_CTRL 0x220
> +#define HEVCF_CLK_CTRL 0x240
> +#define HCODEC_CLK_CTRL 0x244
> +#define VPU_CLK_CTRL 0x260
> +#define VAPB_CLK_CTRL 0x268
> +#define VPU_CLKB_CTRL 0x280
> +#define HDMI_CLK_CTRL 0x284
> +#define HTX_CLK_CTRL 0x28c
> +#define HTX_CLK_CTRL1 0x290
> +#define HRX_CLK_CTRL 0x294
> +#define HRX_CLK_CTRL1 0x298
> +#define HRX_CLK_CTRL2 0x29c
> +#define HRX_CLK_CTRL3 0x2a0
> +#define VID_LOCK_CLK_CTRL 0x2a4
> +#define VDIN_MEAS_CLK_CTRL 0x2a8
> +#define VID_PLL_CLK_DIV 0x2b0
> +#define VID_CLK_CTRL 0x2c0
> +#define VID_CLK_CTRL2 0x2c4
> +#define VID_CLK_DIV 0x2c8
> +#define VIID_CLK_DIV 0x2cc
> +#define VIID_CLK_CTRL 0x2d0
> +#define MIPI_CSI_PHY_CLK_CTRL 0x2e0
> +#define DSI_MEAS_CLK_CTRL 0x2f4
> +
> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \
> + MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
> +
> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
> + MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A9_COMP_GATE(_name, _reg, _bit, _iflags) \
> + MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
> +
> +static const struct clk_parent_data a9_sys_pclk_parents = { .fw_name = "sys" };
> +
> +#define A9_SYS_PCLK(_name, _reg, _bit) \
> + MESON_PCLK(a9_##_name, _reg, _bit, &a9_sys_pclk_parents, 0)
> +
> +static A9_SYS_PCLK(sys_am_axi, SYS_CLK_EN0_REG0, 0);
> +static A9_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi, SYS_CLK_EN0_REG0, 3);
> +static A9_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG0, 4);
> +static A9_SYS_PCLK(sys_amfc, SYS_CLK_EN0_REG0, 5);
> +static A9_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6);
> +static A9_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 7);
> +static A9_SYS_PCLK(sys_eth_axi, SYS_CLK_EN0_REG0, 8);
> +static A9_SYS_PCLK(sys_dp_apb, SYS_CLK_EN0_REG0, 9);
> +static A9_SYS_PCLK(sys_edptx_apb, SYS_CLK_EN0_REG0, 10);
> +static A9_SYS_PCLK(sys_u3hsg, SYS_CLK_EN0_REG0, 11);
> +static A9_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14);
> +static A9_SYS_PCLK(sys_glb, SYS_CLK_EN0_REG0, 15);
> +static A9_SYS_PCLK(sys_combo_dphy_apb, SYS_CLK_EN0_REG0, 17);
> +static A9_SYS_PCLK(sys_hdmirx_apb, SYS_CLK_EN0_REG0, 18);
> +static A9_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG0, 19);
> +static A9_SYS_PCLK(sys_mipi_dsi_phy, SYS_CLK_EN0_REG0, 20);
> +static A9_SYS_PCLK(sys_can0, SYS_CLK_EN0_REG0, 21);
> +static A9_SYS_PCLK(sys_can1, SYS_CLK_EN0_REG0, 22);
> +static A9_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24);
> +static A9_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25);
> +static A9_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26);
> +static A9_SYS_PCLK(sys_sc, SYS_CLK_EN0_REG0, 27);
> +static A9_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28);
> +static A9_SYS_PCLK(sys_mipi_isp, SYS_CLK_EN0_REG0, 29);
> +static A9_SYS_PCLK(sys_msr, SYS_CLK_EN0_REG0, 30);
> +static A9_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0);
> +static A9_SYS_PCLK(sys_mipi_dsi_b, SYS_CLK_EN0_REG1, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi1_phy, SYS_CLK_EN0_REG1, 2);
> +static A9_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3);
> +static A9_SYS_PCLK(sys_eth_1g_mac, SYS_CLK_EN0_REG1, 4);
> +static A9_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5);
> +static A9_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10);
> +static A9_SYS_PCLK(sys_ts_a55, SYS_CLK_EN0_REG1, 11);
> +static A9_SYS_PCLK(sys_eth_1g_axi, SYS_CLK_EN0_REG1, 12);
> +static A9_SYS_PCLK(sys_ts_dos, SYS_CLK_EN0_REG1, 13);
> +static A9_SYS_PCLK(sys_u3drd_b, SYS_CLK_EN0_REG1, 14);
> +static A9_SYS_PCLK(sys_ts_core, SYS_CLK_EN0_REG1, 15);
> +static A9_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG1, 16);
> +static A9_SYS_PCLK(sys_csi_dig_clkin, SYS_CLK_EN0_REG1, 18);
> +static A9_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG1, 19);
> +static A9_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 20);
> +static A9_SYS_PCLK(sys_spisg, SYS_CLK_EN0_REG1, 21);
> +static A9_SYS_PCLK(sys_u3drd_1, SYS_CLK_EN0_REG1, 22);
> +static A9_SYS_PCLK(sys_u2h, SYS_CLK_EN0_REG1, 23);
> +static A9_SYS_PCLK(sys_pcie_mac_a, SYS_CLK_EN0_REG1, 24);
> +static A9_SYS_PCLK(sys_u3drd_a, SYS_CLK_EN0_REG1, 25);
> +static A9_SYS_PCLK(sys_u2drd, SYS_CLK_EN0_REG1, 26);
> +static A9_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27);
> +static A9_SYS_PCLK(sys_pcie_mac_b, SYS_CLK_EN0_REG1, 28);
> +static A9_SYS_PCLK(sys_periph, SYS_CLK_EN0_REG1, 29);
> +static A9_SYS_PCLK(sys_pio, SYS_CLK_EN0_REG2, 0);
> +static A9_SYS_PCLK(sys_i3c, SYS_CLK_EN0_REG2, 1);
> +static A9_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2);
> +static A9_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3);
> +static A9_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4);
> +static A9_SYS_PCLK(sys_i2c_m_i, SYS_CLK_EN0_REG2, 5);
> +static A9_SYS_PCLK(sys_i2c_m_g, SYS_CLK_EN0_REG2, 6);
> +static A9_SYS_PCLK(sys_i2c_m_h, SYS_CLK_EN0_REG2, 7);
> +static A9_SYS_PCLK(sys_hdmi20_aes, SYS_CLK_EN0_REG2, 9);
> +static A9_SYS_PCLK(sys_csi2_host, SYS_CLK_EN0_REG2, 16);
> +static A9_SYS_PCLK(sys_csi2_adapt, SYS_CLK_EN0_REG2, 17);
> +static A9_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21);
> +static A9_SYS_PCLK(sys_pp_dma, SYS_CLK_EN0_REG2, 22);
> +static A9_SYS_PCLK(sys_pp_wrapper, SYS_CLK_EN0_REG2, 23);
> +static A9_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25);
> +static A9_SYS_PCLK(sys_csi2_phy, SYS_CLK_EN0_REG2, 27);
> +static A9_SYS_PCLK(sys_saradc, SYS_CLK_EN0_REG2, 28);
> +static A9_SYS_PCLK(sys_pwm_j, SYS_CLK_EN0_REG2, 30);
> +static A9_SYS_PCLK(sys_pwm_i, SYS_CLK_EN0_REG2, 31);
> +static A9_SYS_PCLK(sys_pwm_h, SYS_CLK_EN0_REG3, 0);
> +static A9_SYS_PCLK(sys_pwm_n, SYS_CLK_EN0_REG3, 8);
> +static A9_SYS_PCLK(sys_pwm_m, SYS_CLK_EN0_REG3, 9);
> +static A9_SYS_PCLK(sys_pwm_l, SYS_CLK_EN0_REG3, 10);
> +static A9_SYS_PCLK(sys_pwm_k, SYS_CLK_EN0_REG3, 11);
> +
> +/* Channel 5 is unconnected. */
> +static u32 a9_sd_emmc_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 };
> +static const struct clk_parent_data a9_sd_emmc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "gp1", },
> + { .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL0, 9, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL0, 0, 7);
> +static A9_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL0, 8, 0);
> +
> +static A9_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL0, 25, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL0, 16, 7);
> +static A9_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL0, 24, 0);
> +
> +static A9_COMP_SEL(sd_emmc_c, SD_EMMC_CLK_CTRL1, 9, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_c, SD_EMMC_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(sd_emmc_c, SD_EMMC_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_pwm_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", }
> +};
> +
> +static A9_COMP_SEL(pwm_h, PWM_CLK_H_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_h, PWM_CLK_H_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_h, PWM_CLK_H_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_i, PWM_CLK_I_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_i, PWM_CLK_I_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_i, PWM_CLK_I_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_j, PWM_CLK_J_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_j, PWM_CLK_J_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_j, PWM_CLK_J_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_k, PWM_CLK_K_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_k, PWM_CLK_K_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_k, PWM_CLK_K_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_l, PWM_CLK_L_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_l, PWM_CLK_L_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_l, PWM_CLK_L_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_m, PWM_CLK_M_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_m, PWM_CLK_M_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_m, PWM_CLK_M_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_n, PWM_CLK_N_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_n, PWM_CLK_N_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_n, PWM_CLK_N_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_spisg_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(spisg, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg, SPISG_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(spisg, SPISG_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(spisg1, SPISG_CLK_CTRL, 25, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg1, SPISG_CLK_CTRL, 16, 6);
> +static A9_COMP_GATE(spisg1, SPISG_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(spisg2, SPISG_CLK_CTRL1, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg2, SPISG_CLK_CTRL1, 0, 6);
> +static A9_COMP_GATE(spisg2, SPISG_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_saradc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", }
> +};
> +
> +static A9_COMP_SEL(saradc, SAR_CLK_CTRL, 9, 0x7, a9_saradc_parents, NULL);
> +static A9_COMP_DIV(saradc, SAR_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(saradc, SAR_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_amfc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(amfc, AMFC_CLK_CTRL, 9, 0x7, a9_amfc_parents, NULL);
> +static A9_COMP_DIV(amfc, AMFC_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(amfc, AMFC_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_nna_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "gp2", },
> + { .fw_name = "hifi0", }
> +};
> +
> +static A9_COMP_SEL(nna, NNA_CLK_CTRL, 9, 0x7, a9_nna_parents, NULL);
> +static A9_COMP_DIV(nna, NNA_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(nna, NNA_CLK_CTRL, 8, 0);
> +
> +/* Channel 5 and 6 are unconnected. */
> +static u32 a9_usb_250m_parents_val_table[] = { 0, 1, 2, 3, 4, 7 };
> +static const struct clk_parent_data a9_usb_250m_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(usb_250m, USB_CLK_CTRL, 9, 0x7, a9_usb_250m_parents,
> + a9_usb_250m_parents_val_table);
> +static A9_COMP_DIV(usb_250m, USB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(usb_250m, USB_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_usb_48m_pre_parents[] = {
> + { .fw_name = "gp0", },
> + { .fw_name = "gp1", },
> + { .fw_name = "gp2", },
> + { .fw_name = "fdiv2", },
> +};
> +
> +static A9_COMP_SEL(usb_48m_pre, USB_CLK_CTRL, 25, 0x3, a9_usb_48m_pre_parents,
> + NULL);
> +static A9_COMP_DIV(usb_48m_pre, USB_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(usb_48m_pre, USB_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_pcie_tl_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(pcie_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents,
> + NULL);
> +static A9_COMP_DIV(pcie_tl, PCIE_TL_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(pcie_tl, PCIE_TL_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pcie1_tl, PCIE_TL_CLK_CTRL, 25, 0x7, a9_pcie_tl_parents,
> + NULL);
> +static A9_COMP_DIV(pcie1_tl, PCIE_TL_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(pcie1_tl, PCIE_TL_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_cmpr_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(cmpr, CMPR_CLK_CTRL, 25, 0x7, a9_cmpr_parents, NULL);
> +static A9_COMP_DIV(cmpr, CMPR_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(cmpr, CMPR_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_dewarpa_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "gp0", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(dewarpa, DEWARP_CLK_CTRL, 9, 0x7, a9_dewarpa_parents, NULL);
> +static A9_COMP_DIV(dewarpa, DEWARP_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dewarpa, DEWARP_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_sc_parents[] = {
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(sc_pre, SC_CLK_CTRL, 9, 0x7, a9_sc_parents, NULL);
> +static A9_COMP_DIV(sc_pre, SC_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(sc_pre, SC_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_sc = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = SC_CLK_CTRL,
> + .shift = 16,
> + .width = 4,
> + },
> + .hw.init = CLK_HW_INIT_HW("sc", &a9_sc_pre.hw,
> + &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_dptx_apb2_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(dptx_apb2, DPTX_CLK_CTRL, 9, 0x7, a9_dptx_apb2_parents, NULL);
> +static A9_COMP_DIV(dptx_apb2, DPTX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dptx_apb2, DPTX_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_dptx_aud_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", }
> +};
> +
> +static A9_COMP_SEL(dptx_aud, DPTX_CLK_CTRL, 25, 0x7, a9_dptx_aud_parents, NULL);
> +static A9_COMP_DIV(dptx_aud, DPTX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dptx_aud, DPTX_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_isp_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(isp, ISP_CLK_CTRL, 9, 0x7, a9_isp_parents, NULL);
> +static A9_COMP_DIV(isp, ISP_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(isp, ISP_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_cve_vge_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(cve, CVE_CLK_CTRL, 9, 0x7, a9_cve_vge_parents, NULL);
> +static A9_COMP_DIV(cve, CVE_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(cve, CVE_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(vge, CVE_CLK_CTRL, 25, 0x7, a9_cve_vge_parents, NULL);
> +static A9_COMP_DIV(vge, CVE_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vge, CVE_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_pp_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(pp, PP_CLK_CTRL, 9, 0x7, a9_pp_parents, NULL);
> +static A9_COMP_DIV(pp, PP_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(pp, PP_CLK_CTRL, 8, 0);
> +
> +/* Channel 6 is unconnected. */
> +static u32 a9_glb_parents_val_table[] = { 0, 1, 2, 3, 4, 5, 7 };
> +static struct clk_regmap a9_dspa;
What is this ?
> +
> +static const struct clk_parent_data a9_glb_parents[] = {
> + { .fw_name = "xtal", },
> + { .hw = &a9_dspa.hw },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .hw = &a9_isp.hw },
> + { .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(glb, GLB_CLK_CTRL, 9, 0x7, a9_glb_parents,
> + a9_glb_parents_val_table);
> +static A9_COMP_DIV(glb, GLB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(glb, GLB_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_in = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = USB_CLK_CTRL,
> + .bit_idx = 31,
> + },
> + .hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv_in", &a9_usb_48m_pre.hw,
> + &clk_regmap_gate_ops, 0),
Same comment as on the AO controller
> +};
> +
> +static const struct meson_clk_dualdiv_param a9_usb_48m_dualdiv_div_table[] = {
> + { 733, 732, 8, 11, 1 },
> + { /* sentinel */ }
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_div = {
> + .data = &(struct meson_clk_dualdiv_data) {
> + .n1 = {
> + .reg_off = USB_CLK_CTRL0,
> + .shift = 0,
> + .width = 12,
> + },
> + .n2 = {
> + .reg_off = USB_CLK_CTRL0,
> + .shift = 12,
> + .width = 12,
> + },
> + .m1 = {
> + .reg_off = USB_CLK_CTRL1,
> + .shift = 0,
> + .width = 12,
> + },
> + .m2 = {
> + .reg_off = USB_CLK_CTRL1,
> + .shift = 12,
> + .width = 12,
> + },
> + .dual = {
> + .reg_off = USB_CLK_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .table = a9_usb_48m_dualdiv_div_table,
> + },
> + .hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv_div", &a9_usb_48m_dualdiv_in.hw,
> + &meson_clk_dualdiv_ops, 0),
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = USB_CLK_CTRL1,
> + .mask = 0x1,
> + .shift = 24,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("usb_48m_dualdiv_sel",
> + ((const struct clk_hw *[]) {
> + &a9_usb_48m_dualdiv_in.hw,
> + &a9_usb_48m_dualdiv_div.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_usb_48m_dualdiv = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = USB_CLK_CTRL0,
> + .bit_idx = 30,
> + },
> + .hw.init = CLK_HW_INIT_HW("usb_48m_dualdiv", &a9_usb_48m_dualdiv_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_usb_48m = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = USB_CLK_CTRL1,
> + .mask = 0x3,
> + .shift = 30,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("usb_48m",
> + ((const struct clk_hw *[]) {
> + &a9_usb_48m_pre.hw,
> + &a9_usb_48m_dualdiv.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/* Channel 3 is unconnected. */
You meant 3rd I guess but this is misleading and confusing with the
table bellow. Channel 2 would be more appropriate I think, since those
are 0-based.
> +static u32 a9_can_pe_parents_val_table[] = { 0, 1, 3 };
> +static const struct clk_parent_data a9_can_pe_parents[] = {
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(can_pe, CAN_CLK_CTRL, 9, 0x7, a9_can_pe_parents,
> + a9_can_pe_parents_val_table);
> +static A9_COMP_DIV(can_pe, CAN_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(can_pe, CAN_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(can1_pe, CAN_CLK_CTRL, 25, 0x7, a9_can_pe_parents,
> + a9_can_pe_parents_val_table);
> +static A9_COMP_DIV(can1_pe, CAN_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(can1_pe, CAN_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_can_filter_parents[] = {
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(can_filter, CAN_CLK_CTRL1, 9, 0x7, a9_can_filter_parents,
> + NULL);
> +static A9_COMP_DIV(can_filter, CAN_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(can_filter, CAN_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(can1_filter, CAN_CLK_CTRL1, 25, 0x7, a9_can_filter_parents,
> + NULL);
> +static A9_COMP_DIV(can1_filter, CAN_CLK_CTRL1, 16, 7);
> +static A9_COMP_GATE(can1_filter, CAN_CLK_CTRL1, 24, 0);
> +
> +static const struct clk_parent_data a9_i3c_parents[] = {
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(i3c, I3C_CLK_CTRL, 9, 0x7, a9_i3c_parents, NULL);
> +static A9_COMP_DIV(i3c, I3C_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(i3c, I3C_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_ts_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = TS_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = CLK_HW_INIT_FW_NAME("ts_div", "xtal",
> + &clk_regmap_divider_ops, 0),
> +};
> +
> +static struct clk_regmap a9_ts = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = TS_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("ts", &a9_ts_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_eth_125m_div = {
> + .mult = 1,
> + .div = 8,
> + .hw.init = CLK_HW_INIT_FW_NAME("eth_125m_div", "fdiv2",
> + &clk_fixed_factor_ops, 0),
> +};
> +
> +static struct clk_regmap a9_eth_125m = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = ETH_CLK_CTRL,
> + .bit_idx = 7,
> + },
> + .hw.init = CLK_HW_INIT_HW("eth_125m", &a9_eth_125m_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/*
> + * Channel 1, 2, 3, 4, 5 and 6 are unconnected,
> + * ext_rmii connects external PAD. Do not automatically reparent.
> + */
> +static u32 a9_eth_rmii_parents_val_table[] = { 0, 7 };
> +static const struct clk_parent_data a9_eth_rmii_parents[] = {
> + { .fw_name = "fdiv2", },
> + { .fw_name = "ext_rmii", }
> +};
> +
> +static struct clk_regmap a9_eth_rmii_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = ETH_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 9,
> + .table = a9_eth_rmii_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_DATA("eth_rmii_sel",
> + a9_eth_rmii_parents,
> + &clk_regmap_mux_ops, CLK_SET_RATE_NO_REPARENT),
> +};
> +
> +static struct clk_regmap a9_eth_rmii_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = ETH_CLK_CTRL,
> + .shift = 0,
> + .width = 7,
> + },
> + .hw.init = CLK_HW_INIT_HW("eth_rmii_div", &a9_eth_rmii_sel.hw,
> + &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_eth_rmii = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = ETH_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("eth_rmii", &a9_eth_rmii_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/*
> + * Channel 3(ddr_dpll_pt_clk) is manged by the DDR module;
> + * channel 12(msr_clk) is manged by clock measures module.
> + * channel 16(audio_dac1_clk) is manged by audio module.
Some why can't you expose those then ? gen clk is used for debugging
AFAIK. The clock above are worth debugging I think
Please be consistent with the CaSing.
> + * Channel 10, 11, 13, 14 are not connected.
> + */
> +static u32 a9_gen_parents_val_table[] = { 0, 1, 2, 4, 5, 6, 7, 8, 9, 15, 17, 18,
> + 19, 20, 21, 22, 23, 24, 25, 26};
> +static struct clk_regmap a9_vid_pll;
> +
> +static const struct clk_parent_data a9_gen_parents[] = {
> + { .fw_name = "xtal" },
> + { .fw_name = "rtc" },
> + { .fw_name = "sysplldiv16" },
> + { .hw = &a9_vid_pll.hw },
> + { .fw_name = "gp0" },
> + { .fw_name = "hifi1" },
> + { .fw_name = "hifi0" },
> + { .fw_name = "gp1" },
> + { .fw_name = "gp2" },
> + { .fw_name = "dsudiv16" },
> + { .fw_name = "cpudiv16" },
> + { .fw_name = "a78div16" },
> + { .fw_name = "fdiv2" },
> + { .fw_name = "fdiv2p5" },
> + { .fw_name = "fdiv3" },
> + { .fw_name = "fdiv4" },
> + { .fw_name = "fdiv5" },
> + { .fw_name = "fdiv7" },
> + { .fw_name = "mclk0" },
> + { .fw_name = "mclk1" }
> +};
> +
> +static A9_COMP_SEL(gen, GEN_CLK_CTRL, 12, 0x1f, a9_gen_parents,
> + a9_gen_parents_val_table);
> +static A9_COMP_DIV(gen, GEN_CLK_CTRL, 0, 11);
> +static A9_COMP_GATE(gen, GEN_CLK_CTRL, 11, 0);
> +
> +static struct clk_regmap a9_24m_in = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = CLK12_24_CTRL,
> + .bit_idx = 11,
> + },
> + .hw.init = CLK_HW_INIT_FW_NAME("24m_in", "xtal",
> + &clk_regmap_gate_ops, 0),
> +};
> +
> +static struct clk_regmap a9_12_24m = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = CLK12_24_CTRL,
> + .shift = 10,
> + .width = 1,
> + },
> + .hw.init = CLK_HW_INIT_HW("12_24m", &a9_24m_in.hw,
> + &clk_regmap_divider_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_mali_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "gp1", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(mali_0, MALI_CLK_CTRL, 9, 0x7, a9_mali_parents, NULL);
> +static A9_COMP_DIV(mali_0, MALI_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(mali_0, MALI_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(mali_1, MALI_CLK_CTRL, 25, 0x7, a9_mali_parents, NULL);
> +static A9_COMP_DIV(mali_1, MALI_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(mali_1, MALI_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_mali = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = MALI_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("mali",
> + ((const struct clk_hw *[]) {
> + &a9_mali_0.hw,
> + &a9_mali_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static A9_COMP_SEL(mali_stack_0, MALI_STACK_CLK_CTRL, 9, 0x7, a9_mali_parents,
> + NULL);
> +static A9_COMP_DIV(mali_stack_0, MALI_STACK_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(mali_stack_0, MALI_STACK_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(mali_stack_1, MALI_STACK_CLK_CTRL, 25, 0x7, a9_mali_parents,
> + NULL);
> +static A9_COMP_DIV(mali_stack_1, MALI_STACK_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(mali_stack_1, MALI_STACK_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_mali_stack = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = MALI_STACK_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("mali_stack",
> + ((const struct clk_hw *[]) {
> + &a9_mali_stack_0.hw,
> + &a9_mali_stack_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_dspa_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "gp2", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "rtc", }
> +};
> +
> +static A9_COMP_SEL(dspa_0, DSPA_CLK_CTRL, 9, 0x7, a9_dspa_parents, NULL);
> +static A9_COMP_DIV(dspa_0, DSPA_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dspa_0, DSPA_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(dspa_1, DSPA_CLK_CTRL, 25, 0x7, a9_dspa_parents, NULL);
> +static A9_COMP_DIV(dspa_1, DSPA_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dspa_1, DSPA_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_dspa = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPA_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("dspa",
> + ((const struct clk_hw *[]) {
> + &a9_dspa_0.hw,
> + &a9_dspa_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hevcf_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp1", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(hevcf_0, HEVCF_CLK_CTRL, 9, 0x7, a9_hevcf_parents, NULL);
> +static A9_COMP_DIV(hevcf_0, HEVCF_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hevcf_0, HEVCF_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(hevcf_1, HEVCF_CLK_CTRL, 25, 0x7, a9_hevcf_parents, NULL);
> +static A9_COMP_DIV(hevcf_1, HEVCF_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hevcf_1, HEVCF_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_hevcf = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HEVCF_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hevcf",
> + ((const struct clk_hw *[]) {
> + &a9_hevcf_0.hw,
> + &a9_hevcf_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hcodec_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp0", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(hcodec_0, HCODEC_CLK_CTRL, 9, 0x7, a9_hcodec_parents, NULL);
> +static A9_COMP_DIV(hcodec_0, HCODEC_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hcodec_0, HCODEC_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(hcodec_1, HCODEC_CLK_CTRL, 25, 0x7, a9_hcodec_parents, NULL);
> +static A9_COMP_DIV(hcodec_1, HCODEC_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hcodec_1, HCODEC_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_hcodec = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HCODEC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hcodec",
> + ((const struct clk_hw *[]) {
> + &a9_hcodec_0.hw,
> + &a9_hcodec_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_vpu_parents[] = {
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "vid1", },
> + { .fw_name = "fdiv2", },
> + { .hw = &a9_vid_pll.hw },
> + { .fw_name = "vid2", },
> + { .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(vpu_0, VPU_CLK_CTRL, 9, 0x7, a9_vpu_parents, NULL);
> +static A9_COMP_DIV(vpu_0, VPU_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vpu_0, VPU_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(vpu_1, VPU_CLK_CTRL, 25, 0x7, a9_vpu_parents, NULL);
> +static A9_COMP_DIV(vpu_1, VPU_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vpu_1, VPU_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_vpu = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VPU_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("vpu",
> + ((const struct clk_hw *[]) {
> + &a9_vpu_0.hw,
> + &a9_vpu_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_vapb_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "fdiv2", },
> + { .hw = &a9_vid_pll.hw },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(vapb_0, VAPB_CLK_CTRL, 9, 0x7, a9_vapb_parents, NULL);
> +static A9_COMP_DIV(vapb_0, VAPB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vapb_0, VAPB_CLK_CTRL, 8, CLK_SET_RATE_GATE);
> +
> +static A9_COMP_SEL(vapb_1, VAPB_CLK_CTRL, 25, 0x7, a9_vapb_parents, NULL);
> +static A9_COMP_DIV(vapb_1, VAPB_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(vapb_1, VAPB_CLK_CTRL, 24, CLK_SET_RATE_GATE);
> +
> +static struct clk_regmap a9_vapb = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VAPB_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("vapb",
> + ((const struct clk_hw *[]) {
> + &a9_vapb_0.hw,
> + &a9_vapb_1.hw,
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_ge2d = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = VAPB_CLK_CTRL,
> + .bit_idx = 30,
> + },
> + .hw.init = CLK_HW_INIT_HW("ge2d", &a9_vapb.hw,
> + &clk_regmap_gate_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_vpu_clkb_tmp_parents[] = {
> + { .hw = &a9_vpu.hw },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(vpu_clkb_tmp, VPU_CLKB_CTRL, 25, 0x7, a9_vpu_clkb_tmp_parents,
> + NULL);
> +static A9_COMP_DIV(vpu_clkb_tmp, VPU_CLKB_CTRL, 16, 4);
> +static A9_COMP_GATE(vpu_clkb_tmp, VPU_CLKB_CTRL, 24, 0);
> +
> +static struct clk_regmap a9_vpu_clkb_div = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = VPU_CLKB_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("vpu_clkb_div", &a9_vpu_clkb_tmp.hw,
> + &clk_regmap_divider_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vpu_clkb = {
> + .data = &(struct clk_regmap_gate_data) {
> + .offset = VPU_CLKB_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("vpu_clkb", &a9_vpu_clkb_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_hdmi_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(hdmitx_sys, HDMI_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_sys, HDMI_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmitx_sys, HDMI_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmitx_prif, HTX_CLK_CTRL, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_prif, HTX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmitx_prif, HTX_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmitx_200m, HTX_CLK_CTRL, 25, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_200m, HTX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hdmitx_200m, HTX_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(hdmitx_aud, HTX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents, NULL);
> +static A9_COMP_DIV(hdmitx_aud, HTX_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(hdmitx_aud, HTX_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_5m, HRX_CLK_CTRL, 9, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_5m, HRX_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(hdmirx_5m, HRX_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_2m, HRX_CLK_CTRL, 25, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_2m, HRX_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(hdmirx_2m, HRX_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_cfg, HRX_CLK_CTRL1, 9, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_cfg, HRX_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(hdmirx_cfg, HRX_CLK_CTRL1, 8, 0);
> +
> +static A9_COMP_SEL(hdmirx_hdcp2x, HRX_CLK_CTRL1, 25, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_hdcp2x, HRX_CLK_CTRL1, 16, 7);
> +static A9_COMP_GATE(hdmirx_hdcp2x, HRX_CLK_CTRL1, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_acr_ref, HRX_CLK_CTRL2, 25, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_acr_ref, HRX_CLK_CTRL2, 16, 7);
> +static A9_COMP_GATE(hdmirx_acr_ref, HRX_CLK_CTRL2, 24, 0);
> +
> +static A9_COMP_SEL(hdmirx_meter, HRX_CLK_CTRL3, 9, 0x7, a9_hdmi_parents,
> + NULL);
> +static A9_COMP_DIV(hdmirx_meter, HRX_CLK_CTRL3, 0, 7);
> +static A9_COMP_GATE(hdmirx_meter, HRX_CLK_CTRL3, 8, 0);
> +
> +static struct clk_regmap a9_enc, a9_enc1;
What is this again ?? and please come up with better names.
> +
> +static const struct clk_parent_data a9_vid_lock_parents[] = {
> + { .fw_name = "xtal", },
> + { .hw = &a9_enc.hw },
> + { .hw = &a9_enc1.hw }
> +};
> +
> +static A9_COMP_SEL(vid_lock, VID_LOCK_CLK_CTRL, 9, 0x7, a9_vid_lock_parents,
> + NULL);
> +static A9_COMP_DIV(vid_lock, VID_LOCK_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vid_lock, VID_LOCK_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_vdin_meas_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", }
> +};
> +
> +static A9_COMP_SEL(vdin_meas, VDIN_MEAS_CLK_CTRL, 9, 0x7, a9_vdin_meas_parents,
> + NULL);
> +static A9_COMP_DIV(vdin_meas, VDIN_MEAS_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(vdin_meas, VDIN_MEAS_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_vid_pll_div = {
> + .data = &(struct meson_vid_pll_div_data){
> + .val = {
> + .reg_off = VID_PLL_CLK_DIV,
> + .shift = 0,
> + .width = 15,
> + },
> + .sel = {
> + .reg_off = VID_PLL_CLK_DIV,
> + .shift = 16,
> + .width = 2,
> + },
> + },
> + .hw.init = CLK_HW_INIT_FW_NAME("vid_pll_div", "hdmiout2",
> + &meson_vid_pll_div_ro_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vid_pll_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VID_PLL_CLK_DIV,
> + .mask = 0x1,
> + .shift = 18,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_DATA("vid_pll_sel",
> + ((const struct clk_parent_data []) {
> + { .hw = &a9_vid_pll_div.hw },
> + { .fw_name = "hdmiout2" }
> + }), &clk_regmap_mux_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vid_pll = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_PLL_CLK_DIV,
> + .bit_idx = 19,
> + },
> + .hw.init = CLK_HW_INIT_HW("vid_pll", &a9_vid_pll_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vid_pll_vclk = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HDMI_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_DATA("vid_pll_vclk",
> + ((const struct clk_parent_data []) {
> + { .hw = &a9_vid_pll.hw },
> + { .fw_name = "hdmipix" }
> + }), &clk_regmap_mux_ops, 0),
> +};
> +
> +static const struct clk_parent_data a9_vclk_parents[] = {
> + { .hw = &a9_vid_pll_vclk.hw },
> + { .fw_name = "pix0", },
> + { .fw_name = "vid1", },
> + { .fw_name = "pix1", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "vid2", }
> +};
> +
> +static struct clk_regmap a9_vclk_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VID_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 16,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_DATA("vclk_sel", a9_vclk_parents,
> + &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vclk_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_DIV,
> + .bit_idx = 16,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_in", &a9_vclk_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = VID_CLK_DIV,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div", &a9_vclk_in.hw,
> + &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 19,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk", &a9_vclk_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div1_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 0,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div1_en", &a9_vclk.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div2_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 1,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div2_en", &a9_vclk.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
Looks to me all this div_en / div repeating pattern would be easier to review
with tiny macro .
> +
> +static struct clk_fixed_factor a9_vclk_div2 = {
> + .mult = 1,
> + .div = 2,
> + .hw.init = CLK_HW_INIT_HW("vclk_div2", &a9_vclk_div2_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div4_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 2,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div4_en", &a9_vclk.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div4 = {
> + .mult = 1,
> + .div = 4,
> + .hw.init = CLK_HW_INIT_HW("vclk_div4", &a9_vclk_div4_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div6_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 3,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div6_en", &a9_vclk.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div6 = {
> + .mult = 1,
> + .div = 6,
> + .hw.init = CLK_HW_INIT_HW("vclk_div6", &a9_vclk_div6_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk_div12_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL,
> + .bit_idx = 4,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk_div12_en", &a9_vclk.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk_div12 = {
> + .mult = 1,
> + .div = 12,
> + .hw.init = CLK_HW_INIT_HW("vclk_div12", &a9_vclk_div12_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VIID_CLK_CTRL,
> + .mask = 0x7,
> + .shift = 16,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_DATA("vclk2_sel", a9_vclk_parents,
> + &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vclk2_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_DIV,
> + .bit_idx = 16,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_in", &a9_vclk2_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = VIID_CLK_DIV,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div", &a9_vclk2_in.hw,
> + &clk_regmap_divider_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 19,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2", &a9_vclk2_div.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div1_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 0,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div1_en", &a9_vclk2.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div2_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 1,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div2_en", &a9_vclk2.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div2 = {
> + .mult = 1,
> + .div = 2,
> + .hw.init = CLK_HW_INIT_HW("vclk2_div2", &a9_vclk2_div2_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div4_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 2,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div4_en", &a9_vclk2.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div4 = {
> + .mult = 1,
> + .div = 4,
> + .hw.init = CLK_HW_INIT_HW("vclk2_div4", &a9_vclk2_div4_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div6_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 3,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div6_en", &a9_vclk2.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div6 = {
> + .mult = 1,
> + .div = 6,
> + .hw.init = CLK_HW_INIT_HW("vclk2_div6", &a9_vclk2_div6_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_vclk2_div12_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VIID_CLK_CTRL,
> + .bit_idx = 4,
> + },
> + .hw.init = CLK_HW_INIT_HW("vclk2_div12_en", &a9_vclk2.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_fixed_factor a9_vclk2_div12 = {
> + .mult = 1,
> + .div = 12,
> + .hw.init = CLK_HW_INIT_HW("vclk2_div12", &a9_vclk2_div12_en.hw,
> + &clk_fixed_factor_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +/* Channel 5, 6 and 7 are unconnected */
> +static u32 a9_vid_parents_val_table[] = { 0, 1, 2, 3, 4, 8, 9, 10, 11, 12 };
> +static const struct clk_hw *a9_vid_parents[] = {
> + &a9_vclk_div1_en.hw,
> + &a9_vclk_div2.hw,
> + &a9_vclk_div4.hw,
> + &a9_vclk_div6.hw,
> + &a9_vclk_div12.hw,
> + &a9_vclk2_div1_en.hw,
> + &a9_vclk2_div2.hw,
> + &a9_vclk2_div4.hw,
> + &a9_vclk2_div6.hw,
> + &a9_vclk2_div12.hw
> +};
> +
> +static struct clk_regmap a9_vdac_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VIID_CLK_DIV,
> + .mask = 0xf,
> + .shift = 28,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("vdac_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_vdac = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 4,
> + },
> + .hw.init = CLK_HW_INIT_HW("vdac", &a9_vdac_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_enc_sel = {
Should this be enc0 then ? for consistency ?
Same applies to similar instance (it is the same discussion we already
had on the T7 I believe)
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VIID_CLK_DIV,
> + .mask = 0xf,
> + .shift = 12,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("enc_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_enc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 10,
> + },
> + .hw.init = CLK_HW_INIT_HW("enc", &a9_enc_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_enc1_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = VIID_CLK_DIV,
> + .mask = 0xf,
> + .shift = 8,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("enc1_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_enc1 = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 11,
> + },
> + .hw.init = CLK_HW_INIT_HW("enc1", &a9_enc1_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx_pixel_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HDMI_CLK_CTRL,
> + .mask = 0xf,
> + .shift = 16,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx_pixel_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx_pixel = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 5,
> + },
> + .hw.init = CLK_HW_INIT_HW("hdmitx_pixel", &a9_hdmitx_pixel_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx_fe_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HDMI_CLK_CTRL,
> + .mask = 0xf,
> + .shift = 20,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx_fe_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx_fe = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 9,
> + },
> + .hw.init = CLK_HW_INIT_HW("hdmitx_fe", &a9_hdmitx_fe_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_pixel_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HDMI_CLK_CTRL,
> + .mask = 0xf,
> + .shift = 24,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx1_pixel_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_pixel = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 12,
> + },
> + .hw.init = CLK_HW_INIT_HW("hdmitx1_pixel", &a9_hdmitx1_pixel_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_fe_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = HDMI_CLK_CTRL,
> + .mask = 0xf,
> + .shift = 28,
> + .table = a9_vid_parents_val_table,
> + },
> + .hw.init = CLK_HW_INIT_PARENTS_HW("hdmitx1_fe_sel", a9_vid_parents
> + , &clk_regmap_mux_ops, 0),
> +};
> +
> +static struct clk_regmap a9_hdmitx1_fe = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = VID_CLK_CTRL2,
> + .bit_idx = 13,
> + },
> + .hw.init = CLK_HW_INIT_HW("hdmitx1_fe", &a9_hdmitx1_fe_sel.hw,
> + &clk_regmap_gate_ops, CLK_SET_RATE_PARENT),
> +};
> +
> +static const struct clk_parent_data a9_csi_phy_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 9, 0x7,
> + a9_csi_phy_parents, NULL);
> +static A9_COMP_DIV(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(csi_phy, MIPI_CSI_PHY_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_dsi_meas_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .hw = &a9_vid_pll.hw },
> + { .fw_name = "gp0", },
> + { .fw_name = "vid1", },
> + { .fw_name = "vid2", }
> +};
> +
> +static A9_COMP_SEL(dsi_meas, DSI_MEAS_CLK_CTRL, 9, 0x7,
> + a9_dsi_meas_parents, NULL);
> +static A9_COMP_DIV(dsi_meas, DSI_MEAS_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dsi_meas, DSI_MEAS_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(dsi_b_meas, DSI_MEAS_CLK_CTRL, 25, 0x7,
> + a9_dsi_meas_parents, NULL);
> +static A9_COMP_DIV(dsi_b_meas, DSI_MEAS_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(dsi_b_meas, DSI_MEAS_CLK_CTRL, 24, 0);
> +
> +static struct clk_hw *a9_peripherals_hw_clks[] = {
> + [CLKID_SYS_AM_AXI] = &a9_sys_am_axi.hw,
> + [CLKID_SYS_DOS] = &a9_sys_dos.hw,
> + [CLKID_SYS_MIPI_DSI] = &a9_sys_mipi_dsi.hw,
> + [CLKID_SYS_ETH_PHY] = &a9_sys_eth_phy.hw,
> + [CLKID_SYS_AMFC] = &a9_sys_amfc.hw,
> + [CLKID_SYS_MALI] = &a9_sys_mali.hw,
> + [CLKID_SYS_NNA] = &a9_sys_nna.hw,
> + [CLKID_SYS_ETH_AXI] = &a9_sys_eth_axi.hw,
> + [CLKID_SYS_DP_APB] = &a9_sys_dp_apb.hw,
> + [CLKID_SYS_EDPTX_APB] = &a9_sys_edptx_apb.hw,
> + [CLKID_SYS_U3HSG] = &a9_sys_u3hsg.hw,
> + [CLKID_SYS_AUCPU] = &a9_sys_aucpu.hw,
> + [CLKID_SYS_GLB] = &a9_sys_glb.hw,
> + [CLKID_SYS_COMBO_DPHY_APB] = &a9_sys_combo_dphy_apb.hw,
> + [CLKID_SYS_HDMIRX_APB] = &a9_sys_hdmirx_apb.hw,
> + [CLKID_SYS_HDMIRX_PCLK] = &a9_sys_hdmirx_pclk.hw,
> + [CLKID_SYS_MIPI_DSI_PHY] = &a9_sys_mipi_dsi_phy.hw,
> + [CLKID_SYS_CAN0] = &a9_sys_can0.hw,
> + [CLKID_SYS_CAN1] = &a9_sys_can1.hw,
> + [CLKID_SYS_SD_EMMC_A] = &a9_sys_sd_emmc_a.hw,
> + [CLKID_SYS_SD_EMMC_B] = &a9_sys_sd_emmc_b.hw,
> + [CLKID_SYS_SD_EMMC_C] = &a9_sys_sd_emmc_c.hw,
> + [CLKID_SYS_SC] = &a9_sys_sc.hw,
> + [CLKID_SYS_ACODEC] = &a9_sys_acodec.hw,
> + [CLKID_SYS_MIPI_ISP] = &a9_sys_mipi_isp.hw,
> + [CLKID_SYS_MSR] = &a9_sys_msr.hw,
> + [CLKID_SYS_AUDIO] = &a9_sys_audio.hw,
> + [CLKID_SYS_MIPI_DSI_B] = &a9_sys_mipi_dsi_b.hw,
> + [CLKID_SYS_MIPI_DSI1_PHY] = &a9_sys_mipi_dsi1_phy.hw,
> + [CLKID_SYS_ETH] = &a9_sys_eth.hw,
> + [CLKID_SYS_ETH_1G_MAC] = &a9_sys_eth_1g_mac.hw,
> + [CLKID_SYS_UART_A] = &a9_sys_uart_a.hw,
> + [CLKID_SYS_UART_F] = &a9_sys_uart_f.hw,
> + [CLKID_SYS_TS_A55] = &a9_sys_ts_a55.hw,
> + [CLKID_SYS_ETH_1G_AXI] = &a9_sys_eth_1g_axi.hw,
> + [CLKID_SYS_TS_DOS] = &a9_sys_ts_dos.hw,
> + [CLKID_SYS_U3DRD_B] = &a9_sys_u3drd_b.hw,
> + [CLKID_SYS_TS_CORE] = &a9_sys_ts_core.hw,
> + [CLKID_SYS_TS_PLL] = &a9_sys_ts_pll.hw,
> + [CLKID_SYS_CSI_DIG_CLKIN] = &a9_sys_csi_dig_clkin.hw,
> + [CLKID_SYS_CVE] = &a9_sys_cve.hw,
> + [CLKID_SYS_GE2D] = &a9_sys_ge2d.hw,
> + [CLKID_SYS_SPISG] = &a9_sys_spisg.hw,
> + [CLKID_SYS_U3DRD_1] = &a9_sys_u3drd_1.hw,
> + [CLKID_SYS_U2H] = &a9_sys_u2h.hw,
> + [CLKID_SYS_PCIE_MAC_A] = &a9_sys_pcie_mac_a.hw,
> + [CLKID_SYS_U3DRD_A] = &a9_sys_u3drd_a.hw,
> + [CLKID_SYS_U2DRD] = &a9_sys_u2drd.hw,
> + [CLKID_SYS_PCIE_PHY] = &a9_sys_pcie_phy.hw,
> + [CLKID_SYS_PCIE_MAC_B] = &a9_sys_pcie_mac_b.hw,
> + [CLKID_SYS_PERIPH] = &a9_sys_periph.hw,
> + [CLKID_SYS_PIO] = &a9_sys_pio.hw,
> + [CLKID_SYS_I3C] = &a9_sys_i3c.hw,
> + [CLKID_SYS_I2C_M_E] = &a9_sys_i2c_m_e.hw,
> + [CLKID_SYS_I2C_M_F] = &a9_sys_i2c_m_f.hw,
> + [CLKID_SYS_HDMITX_APB] = &a9_sys_hdmitx_apb.hw,
> + [CLKID_SYS_I2C_M_I] = &a9_sys_i2c_m_i.hw,
> + [CLKID_SYS_I2C_M_G] = &a9_sys_i2c_m_g.hw,
> + [CLKID_SYS_I2C_M_H] = &a9_sys_i2c_m_h.hw,
> + [CLKID_SYS_HDMI20_AES] = &a9_sys_hdmi20_aes.hw,
> + [CLKID_SYS_CSI2_HOST] = &a9_sys_csi2_host.hw,
> + [CLKID_SYS_CSI2_ADAPT] = &a9_sys_csi2_adapt.hw,
> + [CLKID_SYS_DSPA] = &a9_sys_dspa.hw,
> + [CLKID_SYS_PP_DMA] = &a9_sys_pp_dma.hw,
> + [CLKID_SYS_PP_WRAPPER] = &a9_sys_pp_wrapper.hw,
> + [CLKID_SYS_VPU_INTR] = &a9_sys_vpu_intr.hw,
> + [CLKID_SYS_CSI2_PHY] = &a9_sys_csi2_phy.hw,
> + [CLKID_SYS_SARADC] = &a9_sys_saradc.hw,
> + [CLKID_SYS_PWM_J] = &a9_sys_pwm_j.hw,
> + [CLKID_SYS_PWM_I] = &a9_sys_pwm_i.hw,
> + [CLKID_SYS_PWM_H] = &a9_sys_pwm_h.hw,
> + [CLKID_SYS_PWM_N] = &a9_sys_pwm_n.hw,
> + [CLKID_SYS_PWM_M] = &a9_sys_pwm_m.hw,
> + [CLKID_SYS_PWM_L] = &a9_sys_pwm_l.hw,
> + [CLKID_SYS_PWM_K] = &a9_sys_pwm_k.hw,
> + [CLKID_SD_EMMC_A_SEL] = &a9_sd_emmc_a_sel.hw,
> + [CLKID_SD_EMMC_A_DIV] = &a9_sd_emmc_a_div.hw,
> + [CLKID_SD_EMMC_A] = &a9_sd_emmc_a.hw,
> + [CLKID_SD_EMMC_B_SEL] = &a9_sd_emmc_b_sel.hw,
> + [CLKID_SD_EMMC_B_DIV] = &a9_sd_emmc_b_div.hw,
> + [CLKID_SD_EMMC_B] = &a9_sd_emmc_b.hw,
> + [CLKID_SD_EMMC_C_SEL] = &a9_sd_emmc_c_sel.hw,
> + [CLKID_SD_EMMC_C_DIV] = &a9_sd_emmc_c_div.hw,
> + [CLKID_SD_EMMC_C] = &a9_sd_emmc_c.hw,
> + [CLKID_PWM_H_SEL] = &a9_pwm_h_sel.hw,
> + [CLKID_PWM_H_DIV] = &a9_pwm_h_div.hw,
> + [CLKID_PWM_H] = &a9_pwm_h.hw,
> + [CLKID_PWM_I_SEL] = &a9_pwm_i_sel.hw,
> + [CLKID_PWM_I_DIV] = &a9_pwm_i_div.hw,
> + [CLKID_PWM_I] = &a9_pwm_i.hw,
> + [CLKID_PWM_J_SEL] = &a9_pwm_j_sel.hw,
> + [CLKID_PWM_J_DIV] = &a9_pwm_j_div.hw,
> + [CLKID_PWM_J] = &a9_pwm_j.hw,
> + [CLKID_PWM_K_SEL] = &a9_pwm_k_sel.hw,
> + [CLKID_PWM_K_DIV] = &a9_pwm_k_div.hw,
> + [CLKID_PWM_K] = &a9_pwm_k.hw,
> + [CLKID_PWM_L_SEL] = &a9_pwm_l_sel.hw,
> + [CLKID_PWM_L_DIV] = &a9_pwm_l_div.hw,
> + [CLKID_PWM_L] = &a9_pwm_l.hw,
> + [CLKID_PWM_M_SEL] = &a9_pwm_m_sel.hw,
> + [CLKID_PWM_M_DIV] = &a9_pwm_m_div.hw,
> + [CLKID_PWM_M] = &a9_pwm_m.hw,
> + [CLKID_PWM_N_SEL] = &a9_pwm_n_sel.hw,
> + [CLKID_PWM_N_DIV] = &a9_pwm_n_div.hw,
> + [CLKID_PWM_N] = &a9_pwm_n.hw,
> + [CLKID_SPISG_SEL] = &a9_spisg_sel.hw,
> + [CLKID_SPISG_DIV] = &a9_spisg_div.hw,
> + [CLKID_SPISG] = &a9_spisg.hw,
> + [CLKID_SPISG1_SEL] = &a9_spisg1_sel.hw,
> + [CLKID_SPISG1_DIV] = &a9_spisg1_div.hw,
> + [CLKID_SPISG1] = &a9_spisg1.hw,
> + [CLKID_SPISG2_SEL] = &a9_spisg2_sel.hw,
> + [CLKID_SPISG2_DIV] = &a9_spisg2_div.hw,
> + [CLKID_SPISG2] = &a9_spisg2.hw,
> + [CLKID_SARADC_SEL] = &a9_saradc_sel.hw,
> + [CLKID_SARADC_DIV] = &a9_saradc_div.hw,
> + [CLKID_SARADC] = &a9_saradc.hw,
> + [CLKID_AMFC_SEL] = &a9_amfc_sel.hw,
> + [CLKID_AMFC_DIV] = &a9_amfc_div.hw,
> + [CLKID_AMFC] = &a9_amfc.hw,
> + [CLKID_NNA_SEL] = &a9_nna_sel.hw,
> + [CLKID_NNA_DIV] = &a9_nna_div.hw,
> + [CLKID_NNA] = &a9_nna.hw,
> + [CLKID_USB_250M_SEL] = &a9_usb_250m_sel.hw,
> + [CLKID_USB_250M_DIV] = &a9_usb_250m_div.hw,
> + [CLKID_USB_250M] = &a9_usb_250m.hw,
> + [CLKID_USB_48M_PRE_SEL] = &a9_usb_48m_pre_sel.hw,
> + [CLKID_USB_48M_PRE_DIV] = &a9_usb_48m_pre_div.hw,
> + [CLKID_USB_48M_PRE] = &a9_usb_48m_pre.hw,
> + [CLKID_PCIE_TL_SEL] = &a9_pcie_tl_sel.hw,
> + [CLKID_PCIE_TL_DIV] = &a9_pcie_tl_div.hw,
> + [CLKID_PCIE_TL] = &a9_pcie_tl.hw,
> + [CLKID_PCIE1_TL_SEL] = &a9_pcie1_tl_sel.hw,
> + [CLKID_PCIE1_TL_DIV] = &a9_pcie1_tl_div.hw,
> + [CLKID_PCIE1_TL] = &a9_pcie1_tl.hw,
> + [CLKID_CMPR_SEL] = &a9_cmpr_sel.hw,
> + [CLKID_CMPR_DIV] = &a9_cmpr_div.hw,
> + [CLKID_CMPR] = &a9_cmpr.hw,
> + [CLKID_DEWARPA_SEL] = &a9_dewarpa_sel.hw,
> + [CLKID_DEWARPA_DIV] = &a9_dewarpa_div.hw,
> + [CLKID_DEWARPA] = &a9_dewarpa.hw,
> + [CLKID_SC_PRE_SEL] = &a9_sc_pre_sel.hw,
> + [CLKID_SC_PRE_DIV] = &a9_sc_pre_div.hw,
> + [CLKID_SC_PRE] = &a9_sc_pre.hw,
> + [CLKID_SC] = &a9_sc.hw,
> + [CLKID_DPTX_APB2_SEL] = &a9_dptx_apb2_sel.hw,
> + [CLKID_DPTX_APB2_DIV] = &a9_dptx_apb2_div.hw,
> + [CLKID_DPTX_APB2] = &a9_dptx_apb2.hw,
> + [CLKID_DPTX_AUD_SEL] = &a9_dptx_aud_sel.hw,
> + [CLKID_DPTX_AUD_DIV] = &a9_dptx_aud_div.hw,
> + [CLKID_DPTX_AUD] = &a9_dptx_aud.hw,
> + [CLKID_ISP_SEL] = &a9_isp_sel.hw,
> + [CLKID_ISP_DIV] = &a9_isp_div.hw,
> + [CLKID_ISP] = &a9_isp.hw,
> + [CLKID_CVE_SEL] = &a9_cve_sel.hw,
> + [CLKID_CVE_DIV] = &a9_cve_div.hw,
> + [CLKID_CVE] = &a9_cve.hw,
> + [CLKID_VGE_SEL] = &a9_vge_sel.hw,
> + [CLKID_VGE_DIV] = &a9_vge_div.hw,
> + [CLKID_VGE] = &a9_vge.hw,
> + [CLKID_PP_SEL] = &a9_pp_sel.hw,
> + [CLKID_PP_DIV] = &a9_pp_div.hw,
> + [CLKID_PP] = &a9_pp.hw,
> + [CLKID_GLB_SEL] = &a9_glb_sel.hw,
> + [CLKID_GLB_DIV] = &a9_glb_div.hw,
> + [CLKID_GLB] = &a9_glb.hw,
> + [CLKID_USB_48M_DUALDIV_IN] = &a9_usb_48m_dualdiv_in.hw,
> + [CLKID_USB_48M_DUALDIV_DIV] = &a9_usb_48m_dualdiv_div.hw,
> + [CLKID_USB_48M_DUALDIV_SEL] = &a9_usb_48m_dualdiv_sel.hw,
> + [CLKID_USB_48M_DUALDIV] = &a9_usb_48m_dualdiv.hw,
> + [CLKID_USB_48M] = &a9_usb_48m.hw,
> + [CLKID_CAN_PE_SEL] = &a9_can_pe_sel.hw,
> + [CLKID_CAN_PE_DIV] = &a9_can_pe_div.hw,
> + [CLKID_CAN_PE] = &a9_can_pe.hw,
> + [CLKID_CAN1_PE_SEL] = &a9_can1_pe_sel.hw,
> + [CLKID_CAN1_PE_DIV] = &a9_can1_pe_div.hw,
> + [CLKID_CAN1_PE] = &a9_can1_pe.hw,
> + [CLKID_CAN_FILTER_SEL] = &a9_can_filter_sel.hw,
> + [CLKID_CAN_FILTER_DIV] = &a9_can_filter_div.hw,
> + [CLKID_CAN_FILTER] = &a9_can_filter.hw,
> + [CLKID_CAN1_FILTER_SEL] = &a9_can1_filter_sel.hw,
> + [CLKID_CAN1_FILTER_DIV] = &a9_can1_filter_div.hw,
> + [CLKID_CAN1_FILTER] = &a9_can1_filter.hw,
> + [CLKID_I3C_SEL] = &a9_i3c_sel.hw,
> + [CLKID_I3C_DIV] = &a9_i3c_div.hw,
> + [CLKID_I3C] = &a9_i3c.hw,
> + [CLKID_TS_DIV] = &a9_ts_div.hw,
> + [CLKID_TS] = &a9_ts.hw,
> + [CLKID_ETH_125M_DIV] = &a9_eth_125m_div.hw,
> + [CLKID_ETH_125M] = &a9_eth_125m.hw,
> + [CLKID_ETH_RMII_SEL] = &a9_eth_rmii_sel.hw,
> + [CLKID_ETH_RMII_DIV] = &a9_eth_rmii_div.hw,
> + [CLKID_ETH_RMII] = &a9_eth_rmii.hw,
> + [CLKID_GEN_SEL] = &a9_gen_sel.hw,
> + [CLKID_GEN_DIV] = &a9_gen_div.hw,
> + [CLKID_GEN] = &a9_gen.hw,
> + [CLKID_CLK24M_IN] = &a9_24m_in.hw,
> + [CLKID_CLK12_24M] = &a9_12_24m.hw,
> + [CLKID_MALI_0_SEL] = &a9_mali_0_sel.hw,
> + [CLKID_MALI_0_DIV] = &a9_mali_0_div.hw,
> + [CLKID_MALI_0] = &a9_mali_0.hw,
> + [CLKID_MALI_1_SEL] = &a9_mali_1_sel.hw,
> + [CLKID_MALI_1_DIV] = &a9_mali_1_div.hw,
> + [CLKID_MALI_1] = &a9_mali_1.hw,
> + [CLKID_MALI] = &a9_mali.hw,
> + [CLKID_MALI_STACK_0_SEL] = &a9_mali_stack_0_sel.hw,
> + [CLKID_MALI_STACK_0_DIV] = &a9_mali_stack_0_div.hw,
> + [CLKID_MALI_STACK_0] = &a9_mali_stack_0.hw,
> + [CLKID_MALI_STACK_1_SEL] = &a9_mali_stack_1_sel.hw,
> + [CLKID_MALI_STACK_1_DIV] = &a9_mali_stack_1_div.hw,
> + [CLKID_MALI_STACK_1] = &a9_mali_stack_1.hw,
> + [CLKID_MALI_STACK] = &a9_mali_stack.hw,
> + [CLKID_DSPA_0_SEL] = &a9_dspa_0_sel.hw,
> + [CLKID_DSPA_0_DIV] = &a9_dspa_0_div.hw,
> + [CLKID_DSPA_0] = &a9_dspa_0.hw,
> + [CLKID_DSPA_1_SEL] = &a9_dspa_1_sel.hw,
> + [CLKID_DSPA_1_DIV] = &a9_dspa_1_div.hw,
> + [CLKID_DSPA_1] = &a9_dspa_1.hw,
> + [CLKID_DSPA] = &a9_dspa.hw,
> + [CLKID_HEVCF_0_SEL] = &a9_hevcf_0_sel.hw,
> + [CLKID_HEVCF_0_DIV] = &a9_hevcf_0_div.hw,
> + [CLKID_HEVCF_0] = &a9_hevcf_0.hw,
> + [CLKID_HEVCF_1_SEL] = &a9_hevcf_1_sel.hw,
> + [CLKID_HEVCF_1_DIV] = &a9_hevcf_1_div.hw,
> + [CLKID_HEVCF_1] = &a9_hevcf_1.hw,
> + [CLKID_HEVCF] = &a9_hevcf.hw,
> + [CLKID_HCODEC_0_SEL] = &a9_hcodec_0_sel.hw,
> + [CLKID_HCODEC_0_DIV] = &a9_hcodec_0_div.hw,
> + [CLKID_HCODEC_0] = &a9_hcodec_0.hw,
> + [CLKID_HCODEC_1_SEL] = &a9_hcodec_1_sel.hw,
> + [CLKID_HCODEC_1_DIV] = &a9_hcodec_1_div.hw,
> + [CLKID_HCODEC_1] = &a9_hcodec_1.hw,
> + [CLKID_HCODEC] = &a9_hcodec.hw,
> + [CLKID_VPU_0_SEL] = &a9_vpu_0_sel.hw,
> + [CLKID_VPU_0_DIV] = &a9_vpu_0_div.hw,
> + [CLKID_VPU_0] = &a9_vpu_0.hw,
> + [CLKID_VPU_1_SEL] = &a9_vpu_1_sel.hw,
> + [CLKID_VPU_1_DIV] = &a9_vpu_1_div.hw,
> + [CLKID_VPU_1] = &a9_vpu_1.hw,
> + [CLKID_VPU] = &a9_vpu.hw,
> + [CLKID_VAPB_0_SEL] = &a9_vapb_0_sel.hw,
> + [CLKID_VAPB_0_DIV] = &a9_vapb_0_div.hw,
> + [CLKID_VAPB_0] = &a9_vapb_0.hw,
> + [CLKID_VAPB_1_SEL] = &a9_vapb_1_sel.hw,
> + [CLKID_VAPB_1_DIV] = &a9_vapb_1_div.hw,
> + [CLKID_VAPB_1] = &a9_vapb_1.hw,
> + [CLKID_VAPB] = &a9_vapb.hw,
> + [CLKID_GE2D] = &a9_ge2d.hw,
> + [CLKID_VPU_CLKB_TMP_SEL] = &a9_vpu_clkb_tmp_sel.hw,
> + [CLKID_VPU_CLKB_TMP_DIV] = &a9_vpu_clkb_tmp_div.hw,
> + [CLKID_VPU_CLKB_TMP] = &a9_vpu_clkb_tmp.hw,
> + [CLKID_VPU_CLKB_DIV] = &a9_vpu_clkb_div.hw,
> + [CLKID_VPU_CLKB] = &a9_vpu_clkb.hw,
> + [CLKID_HDMITX_SYS_SEL] = &a9_hdmitx_sys_sel.hw,
> + [CLKID_HDMITX_SYS_DIV] = &a9_hdmitx_sys_div.hw,
> + [CLKID_HDMITX_SYS] = &a9_hdmitx_sys.hw,
> + [CLKID_HDMITX_PRIF_SEL] = &a9_hdmitx_prif_sel.hw,
> + [CLKID_HDMITX_PRIF_DIV] = &a9_hdmitx_prif_div.hw,
> + [CLKID_HDMITX_PRIF] = &a9_hdmitx_prif.hw,
> + [CLKID_HDMITX_200M_SEL] = &a9_hdmitx_200m_sel.hw,
> + [CLKID_HDMITX_200M_DIV] = &a9_hdmitx_200m_div.hw,
> + [CLKID_HDMITX_200M] = &a9_hdmitx_200m.hw,
> + [CLKID_HDMITX_AUD_SEL] = &a9_hdmitx_aud_sel.hw,
> + [CLKID_HDMITX_AUD_DIV] = &a9_hdmitx_aud_div.hw,
> + [CLKID_HDMITX_AUD] = &a9_hdmitx_aud.hw,
> + [CLKID_HDMIRX_5M_SEL] = &a9_hdmirx_5m_sel.hw,
> + [CLKID_HDMIRX_5M_DIV] = &a9_hdmirx_5m_div.hw,
> + [CLKID_HDMIRX_5M] = &a9_hdmirx_5m.hw,
> + [CLKID_HDMIRX_2M_SEL] = &a9_hdmirx_2m_sel.hw,
> + [CLKID_HDMIRX_2M_DIV] = &a9_hdmirx_2m_div.hw,
> + [CLKID_HDMIRX_2M] = &a9_hdmirx_2m.hw,
> + [CLKID_HDMIRX_CFG_SEL] = &a9_hdmirx_cfg_sel.hw,
> + [CLKID_HDMIRX_CFG_DIV] = &a9_hdmirx_cfg_div.hw,
> + [CLKID_HDMIRX_CFG] = &a9_hdmirx_cfg.hw,
> + [CLKID_HDMIRX_HDCP2X_SEL] = &a9_hdmirx_hdcp2x_sel.hw,
> + [CLKID_HDMIRX_HDCP2X_DIV] = &a9_hdmirx_hdcp2x_div.hw,
> + [CLKID_HDMIRX_HDCP2X] = &a9_hdmirx_hdcp2x.hw,
> + [CLKID_HDMIRX_ACR_REF_SEL] = &a9_hdmirx_acr_ref_sel.hw,
> + [CLKID_HDMIRX_ACR_REF_DIV] = &a9_hdmirx_acr_ref_div.hw,
> + [CLKID_HDMIRX_ACR_REF] = &a9_hdmirx_acr_ref.hw,
> + [CLKID_HDMIRX_METER_SEL] = &a9_hdmirx_meter_sel.hw,
> + [CLKID_HDMIRX_METER_DIV] = &a9_hdmirx_meter_div.hw,
> + [CLKID_HDMIRX_METER] = &a9_hdmirx_meter.hw,
> + [CLKID_VID_LOCK_SEL] = &a9_vid_lock_sel.hw,
> + [CLKID_VID_LOCK_DIV] = &a9_vid_lock_div.hw,
> + [CLKID_VID_LOCK] = &a9_vid_lock.hw,
> + [CLKID_VDIN_MEAS_SEL] = &a9_vdin_meas_sel.hw,
> + [CLKID_VDIN_MEAS_DIV] = &a9_vdin_meas_div.hw,
> + [CLKID_VDIN_MEAS] = &a9_vdin_meas.hw,
> + [CLKID_VID_PLL_DIV] = &a9_vid_pll_div.hw,
> + [CLKID_VID_PLL_SEL] = &a9_vid_pll_sel.hw,
> + [CLKID_VID_PLL] = &a9_vid_pll.hw,
> + [CLKID_VID_PLL_VCLK] = &a9_vid_pll_vclk.hw,
> + [CLKID_VCLK_SEL] = &a9_vclk_sel.hw,
> + [CLKID_VCLK_IN] = &a9_vclk_in.hw,
> + [CLKID_VCLK_DIV] = &a9_vclk_div.hw,
> + [CLKID_VCLK] = &a9_vclk.hw,
> + [CLKID_VCLK_DIV1_EN] = &a9_vclk_div1_en.hw,
> + [CLKID_VCLK_DIV2_EN] = &a9_vclk_div2_en.hw,
> + [CLKID_VCLK_DIV2] = &a9_vclk_div2.hw,
> + [CLKID_VCLK_DIV4_EN] = &a9_vclk_div4_en.hw,
> + [CLKID_VCLK_DIV4] = &a9_vclk_div4.hw,
> + [CLKID_VCLK_DIV6_EN] = &a9_vclk_div6_en.hw,
> + [CLKID_VCLK_DIV6] = &a9_vclk_div6.hw,
> + [CLKID_VCLK_DIV12_EN] = &a9_vclk_div12_en.hw,
> + [CLKID_VCLK_DIV12] = &a9_vclk_div12.hw,
> + [CLKID_VCLK2_SEL] = &a9_vclk2_sel.hw,
> + [CLKID_VCLK2_IN] = &a9_vclk2_in.hw,
> + [CLKID_VCLK2_DIV] = &a9_vclk2_div.hw,
> + [CLKID_VCLK2] = &a9_vclk2.hw,
> + [CLKID_VCLK2_DIV1_EN] = &a9_vclk2_div1_en.hw,
> + [CLKID_VCLK2_DIV2_EN] = &a9_vclk2_div2_en.hw,
> + [CLKID_VCLK2_DIV2] = &a9_vclk2_div2.hw,
> + [CLKID_VCLK2_DIV4_EN] = &a9_vclk2_div4_en.hw,
> + [CLKID_VCLK2_DIV4] = &a9_vclk2_div4.hw,
> + [CLKID_VCLK2_DIV6_EN] = &a9_vclk2_div6_en.hw,
> + [CLKID_VCLK2_DIV6] = &a9_vclk2_div6.hw,
> + [CLKID_VCLK2_DIV12_EN] = &a9_vclk2_div12_en.hw,
> + [CLKID_VCLK2_DIV12] = &a9_vclk2_div12.hw,
> + [CLKID_VDAC_SEL] = &a9_vdac_sel.hw,
> + [CLKID_VDAC] = &a9_vdac.hw,
> + [CLKID_ENC_SEL] = &a9_enc_sel.hw,
> + [CLKID_ENC] = &a9_enc.hw,
> + [CLKID_ENC1_SEL] = &a9_enc1_sel.hw,
> + [CLKID_ENC1] = &a9_enc1.hw,
> + [CLKID_HDMITX_PIXEL_SEL] = &a9_hdmitx_pixel_sel.hw,
> + [CLKID_HDMITX_PIXEL] = &a9_hdmitx_pixel.hw,
> + [CLKID_HDMITX_FE_SEL] = &a9_hdmitx_fe_sel.hw,
> + [CLKID_HDMITX_FE] = &a9_hdmitx_fe.hw,
> + [CLKID_HDMITX1_PIXEL_SEL] = &a9_hdmitx1_pixel_sel.hw,
> + [CLKID_HDMITX1_PIXEL] = &a9_hdmitx1_pixel.hw,
> + [CLKID_HDMITX1_FE_SEL] = &a9_hdmitx1_fe_sel.hw,
> + [CLKID_HDMITX1_FE] = &a9_hdmitx1_fe.hw,
> + [CLKID_CSI_PHY_SEL] = &a9_csi_phy_sel.hw,
> + [CLKID_CSI_PHY_DIV] = &a9_csi_phy_div.hw,
> + [CLKID_CSI_PHY] = &a9_csi_phy.hw,
> + [CLKID_DSI_MEAS_SEL] = &a9_dsi_meas_sel.hw,
> + [CLKID_DSI_MEAS_DIV] = &a9_dsi_meas_div.hw,
> + [CLKID_DSI_MEAS] = &a9_dsi_meas.hw,
> + [CLKID_DSI_B_MEAS_SEL] = &a9_dsi_b_meas_sel.hw,
> + [CLKID_DSI_B_MEAS_DIV] = &a9_dsi_b_meas_div.hw,
> + [CLKID_DSI_B_MEAS] = &a9_dsi_b_meas.hw,
> +};
> +
> +static const struct meson_clkc_data a9_peripherals_clkc_data = {
> + .hw_clks = {
> + .hws = a9_peripherals_hw_clks,
> + .num = ARRAY_SIZE(a9_peripherals_hw_clks),
> + },
> +};
> +
> +static const struct of_device_id a9_peripherals_clkc_match_table[] = {
> + {
> + .compatible = "amlogic,a9-peripherals-clkc",
> + .data = &a9_peripherals_clkc_data,
> + },
> + { /* sentinel */ }
> +};
> +
> +MODULE_DEVICE_TABLE(of, a9_peripherals_clkc_match_table);
> +
> +static struct platform_driver a9_peripherals_clkc_driver = {
> + .probe = meson_clkc_mmio_probe,
> + .driver = {
> + .name = "a9-peripherals-clkc",
> + .of_match_table = a9_peripherals_clkc_match_table,
> + },
> +};
> +module_platform_driver(a9_peripherals_clkc_driver);
> +
> +MODULE_DESCRIPTION("Amlogic A9 Peripherals Clock Controller driver");
> +MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
> +MODULE_LICENSE("GPL");
> +MODULE_IMPORT_NS("CLK_MESON");
--
Jerome
^ 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