[v13,4/6] clk: meson: a1: add Amlogic A1 PLL clock controller driver
Commit Message
Introduce PLL clock controller for Amlogic A1 SoC family.
The clock unit is an APB slave module that is designed for generating all
of the internal and system clocks.
The SoC uses an external 24MHz crystal; there are 4 internal PLLs:
SYS_PLL/HIFI_PLL/USB_PLL/(FIXPLL), these PLLs generate 27 clock sources.
Signed-off-by: Jian Hu <jian.hu@amlogic.com>
Signed-off-by: Dmitry Rokosov <ddrokosov@sberdevices.ru>
---
drivers/clk/meson/Kconfig | 10 ++
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a1-pll.c | 356 +++++++++++++++++++++++++++++++++++++
drivers/clk/meson/a1-pll.h | 47 +++++
4 files changed, 414 insertions(+)
create mode 100644 drivers/clk/meson/a1-pll.c
create mode 100644 drivers/clk/meson/a1-pll.h
Comments
Hello Dmitry,
currently Jerome is busy so I am trying to continue where he left off.
I have followed the previous iterations a bit but may have missed some
details. So apologies if I'm repeating some questions that Jerome
previously asked.
On Wed, Apr 5, 2023 at 9:59 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
[...]
> +config COMMON_CLK_A1_PLL
> + tristate "Meson A1 SoC PLL controller support"
Should this be "Amlogic A1 SoC PLL controller support"?
My understanding is that the "meson" name was dropped for this
generation of SoCs.
[...]
> +static const struct of_device_id a1_pll_clkc_match_table[] = {
> + { .compatible = "amlogic,a1-pll-clkc", },
> + {},
nit-pick: please drop the comma after {}
This empty entry is a sentinel, no other entries are supposed to come
after this - so a trailing comma is not necessary.
[...]
> +/* PLL register offset */
> +#define ANACTRL_FIXPLL_CTRL0 0x0
> +#define ANACTRL_FIXPLL_CTRL1 0x4
> +#define ANACTRL_FIXPLL_STS 0x14
> +#define ANACTRL_HIFIPLL_CTRL0 0xc0
> +#define ANACTRL_HIFIPLL_CTRL1 0xc4
> +#define ANACTRL_HIFIPLL_CTRL2 0xc8
> +#define ANACTRL_HIFIPLL_CTRL3 0xcc
> +#define ANACTRL_HIFIPLL_CTRL4 0xd0
> +#define ANACTRL_HIFIPLL_STS 0xd4
Here I have a question that will potentially affect patch 3/6
("dt-bindings: clock: meson: add A1 PLL clock controller bindings").
In the cover-letter you mentioned that quite a few clocks have been omitted.
Any dt-bindings that we create need to be stable going forward. That
means: the dt-bindings will always need to describe what the hardware
is capable of, not what the driver implements.
So my question is: do we have all needed inputs described in the
dt-bindings (even though we're omitting quite a few registers here
that will only be added/used in the future)?
Older SoCs require (temporarily) using the XTAL clock for CPU clock
tree changes. To make a long story short: I'm wondering if - at least
- the XTAL clock input is missing.
PS: I don't have an A1 datasheet nor a vendor kernel source (and even
less a board for testing). So I can't verify any of this myself and
I'm asking questions instead.
Best regards,
Martin
Hello Martin,
On Sun, Apr 23, 2023 at 11:12:27PM +0200, Martin Blumenstingl wrote:
> Hello Dmitry,
>
> currently Jerome is busy so I am trying to continue where he left off.
> I have followed the previous iterations a bit but may have missed some
> details. So apologies if I'm repeating some questions that Jerome
> previously asked.
>
Thank you very much for your effort! Please feel free to ask any
questions you may have, without any hesitation.
> On Wed, Apr 5, 2023 at 9:59 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
> [...]
> > +config COMMON_CLK_A1_PLL
> > + tristate "Meson A1 SoC PLL controller support"
> Should this be "Amlogic A1 SoC PLL controller support"?
> My understanding is that the "meson" name was dropped for this
> generation of SoCs.
>
> [...]
Yep, that's good point. Will change it in the next version.
> > +static const struct of_device_id a1_pll_clkc_match_table[] = {
> > + { .compatible = "amlogic,a1-pll-clkc", },
> > + {},
> nit-pick: please drop the comma after {}
> This empty entry is a sentinel, no other entries are supposed to come
> after this - so a trailing comma is not necessary.
>
> [...]
OK
> > +/* PLL register offset */
> > +#define ANACTRL_FIXPLL_CTRL0 0x0
> > +#define ANACTRL_FIXPLL_CTRL1 0x4
> > +#define ANACTRL_FIXPLL_STS 0x14
> > +#define ANACTRL_HIFIPLL_CTRL0 0xc0
> > +#define ANACTRL_HIFIPLL_CTRL1 0xc4
> > +#define ANACTRL_HIFIPLL_CTRL2 0xc8
> > +#define ANACTRL_HIFIPLL_CTRL3 0xcc
> > +#define ANACTRL_HIFIPLL_CTRL4 0xd0
> > +#define ANACTRL_HIFIPLL_STS 0xd4
> Here I have a question that will potentially affect patch 3/6
> ("dt-bindings: clock: meson: add A1 PLL clock controller bindings").
> In the cover-letter you mentioned that quite a few clocks have been omitted.
> Any dt-bindings that we create need to be stable going forward. That
> means: the dt-bindings will always need to describe what the hardware
> is capable of, not what the driver implements.
> So my question is: do we have all needed inputs described in the
> dt-bindings (even though we're omitting quite a few registers here
> that will only be added/used in the future)?
> Older SoCs require (temporarily) using the XTAL clock for CPU clock
> tree changes. To make a long story short: I'm wondering if - at least
> - the XTAL clock input is missing.
The Amlogic A1 clock engine comprises four clock controllers for
peripherals, PLL, CPU, and audio. While the first two have been
introduced in the current patch series, the last two will be sent in the
next iteration.
Presently, the PLL controller driver includes all the required bindings,
and the peripherals controller driver has all bindings except for the
CPU-related clock.
However, I do not believe this to be a significant issue. The clock DT
bindings are organized to simplify the process of introducing new bindings,
whether public or private. For instance, we may add new bindings to
include/dt-bindings at the end of the list and increase the overall number,
without disrupting the DT bindings ABI (the old numbers will remain
unchanged).
>
> PS: I don't have an A1 datasheet nor a vendor kernel source (and even
> less a board for testing). So I can't verify any of this myself and
> I'm asking questions instead.
>
Hello Dmitry,
(I'm aware you already posted a v14 - but I'm still replying here to
continue the discussion on one question I had to keep the context)
On Tue, Apr 25, 2023 at 2:33 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
[...]
> > > +/* PLL register offset */
> > > +#define ANACTRL_FIXPLL_CTRL0 0x0
> > > +#define ANACTRL_FIXPLL_CTRL1 0x4
> > > +#define ANACTRL_FIXPLL_STS 0x14
> > > +#define ANACTRL_HIFIPLL_CTRL0 0xc0
> > > +#define ANACTRL_HIFIPLL_CTRL1 0xc4
> > > +#define ANACTRL_HIFIPLL_CTRL2 0xc8
> > > +#define ANACTRL_HIFIPLL_CTRL3 0xcc
> > > +#define ANACTRL_HIFIPLL_CTRL4 0xd0
> > > +#define ANACTRL_HIFIPLL_STS 0xd4
> > Here I have a question that will potentially affect patch 3/6
> > ("dt-bindings: clock: meson: add A1 PLL clock controller bindings").
> > In the cover-letter you mentioned that quite a few clocks have been omitted.
> > Any dt-bindings that we create need to be stable going forward. That
> > means: the dt-bindings will always need to describe what the hardware
> > is capable of, not what the driver implements.
> > So my question is: do we have all needed inputs described in the
> > dt-bindings (even though we're omitting quite a few registers here
> > that will only be added/used in the future)?
> > Older SoCs require (temporarily) using the XTAL clock for CPU clock
> > tree changes. To make a long story short: I'm wondering if - at least
> > - the XTAL clock input is missing.
>
> The Amlogic A1 clock engine comprises four clock controllers for
> peripherals, PLL, CPU, and audio. While the first two have been
> introduced in the current patch series, the last two will be sent in the
> next iteration.
I (think that I) understand this part.
> Presently, the PLL controller driver includes all the required bindings,
> and the peripherals controller driver has all bindings except for the
> CPU-related clock.
Let's stick to the PLL controller bindings for the next part.
My understanding is that the PLL clock controller registers
(ANACTRL_*) are managing the following clocks:
- fixed_pll
- sys_pll
- hifi_pll
- whatever "AUDDDS" is
- and some miscellaneous registers like ANACTRL_POR_CNTL and
ANACTRL_MISCTOP_CTRL0
I *think* you got the dt-bindings correct:
Even though the driver part does not support the hifi_pll yet, this IP
block seems to have a "hifipll_in" clock input.
Since the dt-bindings describes the hardware it may describe (for
example) clock inputs that are not used by the driver yet.
If you agree with my statement from above I'll be able to make my
original question more specific:
Since we know that we have all the required inputs for fixed_pll,
sys_pll and hifi_pll - do you know what AUDDDS is and whether it
requires any specific clock inputs (other than "fixpll_in" and
"hifipll_in")?
> However, I do not believe this to be a significant issue. The clock DT
> bindings are organized to simplify the process of introducing new bindings,
> whether public or private. For instance, we may add new bindings to
> include/dt-bindings at the end of the list and increase the overall number,
> without disrupting the DT bindings ABI (the old numbers will remain
> unchanged).
Yep, this part is clear to me. I should have been more specific that I
was asking about the inputs that are described in the .yaml file, not
the clock IDs.
Best regards,
Martin
Hello Martin,
I apologize for the delayed response as I was on vacation without email
access. I hope this is not a problem.
On Mon, May 01, 2023 at 08:39:20PM +0200, Martin Blumenstingl wrote:
> Hello Dmitry,
>
> (I'm aware you already posted a v14 - but I'm still replying here to
> continue the discussion on one question I had to keep the context)
>
Sure, please find, my thoughts below.
> On Tue, Apr 25, 2023 at 2:33 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
> [...]
> > > > +/* PLL register offset */
> > > > +#define ANACTRL_FIXPLL_CTRL0 0x0
> > > > +#define ANACTRL_FIXPLL_CTRL1 0x4
> > > > +#define ANACTRL_FIXPLL_STS 0x14
> > > > +#define ANACTRL_HIFIPLL_CTRL0 0xc0
> > > > +#define ANACTRL_HIFIPLL_CTRL1 0xc4
> > > > +#define ANACTRL_HIFIPLL_CTRL2 0xc8
> > > > +#define ANACTRL_HIFIPLL_CTRL3 0xcc
> > > > +#define ANACTRL_HIFIPLL_CTRL4 0xd0
> > > > +#define ANACTRL_HIFIPLL_STS 0xd4
> > > Here I have a question that will potentially affect patch 3/6
> > > ("dt-bindings: clock: meson: add A1 PLL clock controller bindings").
> > > In the cover-letter you mentioned that quite a few clocks have been omitted.
> > > Any dt-bindings that we create need to be stable going forward. That
> > > means: the dt-bindings will always need to describe what the hardware
> > > is capable of, not what the driver implements.
> > > So my question is: do we have all needed inputs described in the
> > > dt-bindings (even though we're omitting quite a few registers here
> > > that will only be added/used in the future)?
> > > Older SoCs require (temporarily) using the XTAL clock for CPU clock
> > > tree changes. To make a long story short: I'm wondering if - at least
> > > - the XTAL clock input is missing.
> >
> > The Amlogic A1 clock engine comprises four clock controllers for
> > peripherals, PLL, CPU, and audio. While the first two have been
> > introduced in the current patch series, the last two will be sent in the
> > next iteration.
> I (think that I) understand this part.
>
> > Presently, the PLL controller driver includes all the required bindings,
> > and the peripherals controller driver has all bindings except for the
> > CPU-related clock.
> Let's stick to the PLL controller bindings for the next part.
> My understanding is that the PLL clock controller registers
> (ANACTRL_*) are managing the following clocks:
> - fixed_pll
> - sys_pll
> - hifi_pll
> - whatever "AUDDDS" is
> - and some miscellaneous registers like ANACTRL_POR_CNTL and
> ANACTRL_MISCTOP_CTRL0
>
> I *think* you got the dt-bindings correct:
> Even though the driver part does not support the hifi_pll yet, this IP
> block seems to have a "hifipll_in" clock input.
> Since the dt-bindings describes the hardware it may describe (for
> example) clock inputs that are not used by the driver yet.
>
> If you agree with my statement from above I'll be able to make my
> original question more specific:
> Since we know that we have all the required inputs for fixed_pll,
> sys_pll and hifi_pll - do you know what AUDDDS is and whether it
> requires any specific clock inputs (other than "fixpll_in" and
> "hifipll_in")?
>
To be honest, I have prepared A1 peripherals and A1 PLL drivers based on very
poor Amlogic datasheets and custom 4.19-based vendor drivers.
The vendor driver has an AUDDDS clock in the PLL clock part, but it is not
used anywhere. Unfortunately, as usual, the datasheet doesn't provide any
information or explanation about what it is. However, the driver has a few
lines of comments that indicate:
/*
* aud dds clock is not pll clock, not divider clock,
* No clock model can describe it.
* So we regard it as a gate, and the gate ops
* should realize lonely.
*/
Additionally, the vendor driver states that AUDDDS has a 49Mhz clock,
but I do not see any relationship with other clocks (including the exported
GENCLK).
Jian did not include it in the first version of the PLL driver, and I have
decided not to change it either.
I also noticed a few lines of AUDDDS initialization sequences in the vendor
driver, which may affect CPU clock objects (from my point of view).
However, they are currently under development, and I will try to figure it
out with Amlogic support.
> > However, I do not believe this to be a significant issue. The clock DT
> > bindings are organized to simplify the process of introducing new bindings,
> > whether public or private. For instance, we may add new bindings to
> > include/dt-bindings at the end of the list and increase the overall number,
> > without disrupting the DT bindings ABI (the old numbers will remain
> > unchanged).
> Yep, this part is clear to me. I should have been more specific that I
> was asking about the inputs that are described in the .yaml file, not
> the clock IDs.
Actually, AUDDDS has an xtal2dds parent clock, and if we need to have
the AUDDDS clock in the PLL driver, we should add one more link between
peripherals and PLL drivers.
Let me know if you have any questions.
Hi Dmitry.
On Thu, May 11, 2023 at 3:26 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
[...]
> > If you agree with my statement from above I'll be able to make my
> > original question more specific:
> > Since we know that we have all the required inputs for fixed_pll,
> > sys_pll and hifi_pll - do you know what AUDDDS is and whether it
> > requires any specific clock inputs (other than "fixpll_in" and
> > "hifipll_in")?
> >
>
> To be honest, I have prepared A1 peripherals and A1 PLL drivers based on very
> poor Amlogic datasheets and custom 4.19-based vendor drivers.
> The vendor driver has an AUDDDS clock in the PLL clock part, but it is not
> used anywhere. Unfortunately, as usual, the datasheet doesn't provide any
> information or explanation about what it is. However, the driver has a few
> lines of comments that indicate:
>
> /*
> * aud dds clock is not pll clock, not divider clock,
> * No clock model can describe it.
> * So we regard it as a gate, and the gate ops
> * should realize lonely.
> */
>
> Additionally, the vendor driver states that AUDDDS has a 49Mhz clock,
> but I do not see any relationship with other clocks (including the exported
> GENCLK).
> Jian did not include it in the first version of the PLL driver, and I have
> decided not to change it either.
>
> I also noticed a few lines of AUDDDS initialization sequences in the vendor
> driver, which may affect CPU clock objects (from my point of view).
> However, they are currently under development, and I will try to figure it
> out with Amlogic support.
>
> > > However, I do not believe this to be a significant issue. The clock DT
> > > bindings are organized to simplify the process of introducing new bindings,
> > > whether public or private. For instance, we may add new bindings to
> > > include/dt-bindings at the end of the list and increase the overall number,
> > > without disrupting the DT bindings ABI (the old numbers will remain
> > > unchanged).
> > Yep, this part is clear to me. I should have been more specific that I
> > was asking about the inputs that are described in the .yaml file, not
> > the clock IDs.
>
> Actually, AUDDDS has an xtal2dds parent clock, and if we need to have
> the AUDDDS clock in the PLL driver, we should add one more link between
> peripherals and PLL drivers.
>
> Let me know if you have any questions.
I have no questions - all I can say is that:
- I like your approach of clarifying details of the AUDDDS clock with Amlogic
- and I fully agree with your conclusion that (depending on what
Amlogic says) we need one more link from the PLL driver to the AUDDDS
clock
Thank you for your persistence with this series, I'm sure it will pay
off in the long run!
Best regards,
Martin
Hello Martin,
As I promised before, I'm now back with the vendor's reply regarding
AUDDDS. The information is still incomplete, but I have provided the
available details below. Please take a look.
On Sun, May 14, 2023 at 10:53:53PM +0200, Martin Blumenstingl wrote:
> Hi Dmitry.
>
> On Thu, May 11, 2023 at 3:26 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
> [...]
> > > If you agree with my statement from above I'll be able to make my
> > > original question more specific:
> > > Since we know that we have all the required inputs for fixed_pll,
> > > sys_pll and hifi_pll - do you know what AUDDDS is and whether it
> > > requires any specific clock inputs (other than "fixpll_in" and
> > > "hifipll_in")?
> > >
> >
> > To be honest, I have prepared A1 peripherals and A1 PLL drivers based on very
> > poor Amlogic datasheets and custom 4.19-based vendor drivers.
> > The vendor driver has an AUDDDS clock in the PLL clock part, but it is not
> > used anywhere. Unfortunately, as usual, the datasheet doesn't provide any
> > information or explanation about what it is. However, the driver has a few
> > lines of comments that indicate:
> >
> > /*
> > * aud dds clock is not pll clock, not divider clock,
> > * No clock model can describe it.
> > * So we regard it as a gate, and the gate ops
> > * should realize lonely.
> > */
> >
> > Additionally, the vendor driver states that AUDDDS has a 49Mhz clock,
> > but I do not see any relationship with other clocks (including the exported
> > GENCLK).
> > Jian did not include it in the first version of the PLL driver, and I have
> > decided not to change it either.
> >
> > I also noticed a few lines of AUDDDS initialization sequences in the vendor
> > driver, which may affect CPU clock objects (from my point of view).
> > However, they are currently under development, and I will try to figure it
> > out with Amlogic support.
> >
> > > > However, I do not believe this to be a significant issue. The clock DT
> > > > bindings are organized to simplify the process of introducing new bindings,
> > > > whether public or private. For instance, we may add new bindings to
> > > > include/dt-bindings at the end of the list and increase the overall number,
> > > > without disrupting the DT bindings ABI (the old numbers will remain
> > > > unchanged).
> > > Yep, this part is clear to me. I should have been more specific that I
> > > was asking about the inputs that are described in the .yaml file, not
> > > the clock IDs.
> >
> > Actually, AUDDDS has an xtal2dds parent clock, and if we need to have
> > the AUDDDS clock in the PLL driver, we should add one more link between
> > peripherals and PLL drivers.
> >
> > Let me know if you have any questions.
> I have no questions - all I can say is that:
> - I like your approach of clarifying details of the AUDDDS clock with Amlogic
> - and I fully agree with your conclusion that (depending on what
> Amlogic says) we need one more link from the PLL driver to the AUDDDS
> clock
>
> Thank you for your persistence with this series, I'm sure it will pay
> off in the long run!
AUDDDS is a direct digital synthesizer used as a clock source. It is
not used as default. You need to modify some clk registers in dts to
enable it. Basically, it is used for audio.
In A1 design, you can use AUD DDS as a clock source and it is not
necessary. It is not used in the Amlogic default setting.
According to the vendor, it is not necessary and is currently disabled
by default. While we don't have much information about AUDDDS, the
vendor suggests that it's not a commonly used clock object in A1
projects and it may be skipped if not needed.
Based on all above information, I suppose we can skip it now.
Hello Dmitry,
On Mon, May 29, 2023 at 3:49 PM Dmitry Rokosov <ddrokosov@sberdevices.ru> wrote:
>
> Hello Martin,
>
> As I promised before, I'm now back with the vendor's reply regarding
> AUDDDS. The information is still incomplete, but I have provided the
> available details below. Please take a look.
Great, thank you for following up!
[...]
> AUDDDS is a direct digital synthesizer used as a clock source. It is
> not used as default. You need to modify some clk registers in dts to
> enable it. Basically, it is used for audio.
>
> In A1 design, you can use AUD DDS as a clock source and it is not
> necessary. It is not used in the Amlogic default setting.
>
> According to the vendor, it is not necessary and is currently disabled
> by default. While we don't have much information about AUDDDS, the
> vendor suggests that it's not a commonly used clock object in A1
> projects and it may be skipped if not needed.
My goal is to make the dt-bindings match the hardware implementation...
> Based on all above information, I suppose we can skip it now.
...but in this case we simply don't have enough information (other
than some register names and a high level description that it can be
used as a clock) to do that.
I still think we did the best we could for now, so I agree with you:
let's skip it for now (and hope that retrofitting it later - if we
ever need it - won't be a problem).
Best regards,
Martin
@@ -99,6 +99,16 @@ config COMMON_CLK_AXG_AUDIO
Support for the audio clock controller on AmLogic A113D devices,
aka axg, Say Y if you want audio subsystem to work.
+config COMMON_CLK_A1_PLL
+ tristate "Meson A1 SoC PLL controller support"
+ depends on ARM64
+ select COMMON_CLK_MESON_REGMAP
+ select COMMON_CLK_MESON_PLL
+ help
+ Support for the PLL clock controller on Amlogic A113L based
+ device, A1 SoC Family. Say Y if you want A1 PLL clock controller
+ to work.
+
config COMMON_CLK_G12A
tristate "G12 and SM1 SoC clock controllers support"
depends on ARM64
@@ -16,6 +16,7 @@ obj-$(CONFIG_COMMON_CLK_MESON_VID_PLL_DIV) += vid-pll-div.o
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_GXBB) += gxbb.o gxbb-aoclk.o
obj-$(CONFIG_COMMON_CLK_G12A) += g12a.o g12a-aoclk.o
obj-$(CONFIG_COMMON_CLK_MESON8B) += meson8b.o meson8-ddr.o
new file mode 100644
@@ -0,0 +1,356 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <ddrokosov@sberdevices.ru>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "a1-pll.h"
+#include "clk-regmap.h"
+
+static struct clk_regmap fixed_pll_dco = {
+ .data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = ANACTRL_FIXPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = ANACTRL_FIXPLL_CTRL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .n = {
+ .reg_off = ANACTRL_FIXPLL_CTRL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .frac = {
+ .reg_off = ANACTRL_FIXPLL_CTRL1,
+ .shift = 0,
+ .width = 19,
+ },
+ .l = {
+ .reg_off = ANACTRL_FIXPLL_STS,
+ .shift = 31,
+ .width = 1,
+ },
+ .rst = {
+ .reg_off = ANACTRL_FIXPLL_CTRL0,
+ .shift = 29,
+ .width = 1,
+ },
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fixed_pll_dco",
+ .ops = &meson_clk_pll_ro_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fixpll_in",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fixed_pll = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_FIXPLL_CTRL0,
+ .bit_idx = 20,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "fixed_pll",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fixed_pll_dco.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct pll_mult_range hifi_pll_mult_range = {
+ .min = 32,
+ .max = 64,
+};
+
+static const struct reg_sequence hifi_init_regs[] = {
+ { .reg = ANACTRL_HIFIPLL_CTRL1, .def = 0x01800000 },
+ { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00001100 },
+ { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x100a1100 },
+ { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x00302000 },
+ { .reg = ANACTRL_HIFIPLL_CTRL0, .def = 0x01f18000 },
+};
+
+static struct clk_regmap hifi_pll = {
+ .data = &(struct meson_clk_pll_data){
+ .en = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .m = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 0,
+ .width = 8,
+ },
+ .n = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 10,
+ .width = 5,
+ },
+ .frac = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL1,
+ .shift = 0,
+ .width = 19,
+ },
+ .l = {
+ .reg_off = ANACTRL_HIFIPLL_STS,
+ .shift = 31,
+ .width = 1,
+ },
+ .current_en = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL0,
+ .shift = 26,
+ .width = 1,
+ },
+ .l_detect = {
+ .reg_off = ANACTRL_HIFIPLL_CTRL2,
+ .shift = 6,
+ .width = 1,
+ },
+ .range = &hifi_pll_mult_range,
+ .init_regs = hifi_init_regs,
+ .init_count = ARRAY_SIZE(hifi_init_regs),
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "hifi_pll",
+ .ops = &meson_clk_pll_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "hifipll_in",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor fclk_div2_div = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div2_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fixed_pll.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div2 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_FIXPLL_CTRL0,
+ .bit_idx = 21,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div2",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_div2_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * This clock is used by DDR clock in BL2 firmware
+ * and is required by the platform to operate correctly.
+ * Until the following condition are met, we need this clock to
+ * be marked as critical:
+ * a) Mark the clock used by a firmware resource, if possible
+ * b) CCF has a clock hand-off mechanism to make the sure the
+ * clock stays on until the proper driver comes along
+ */
+ .flags = CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_fixed_factor fclk_div3_div = {
+ .mult = 1,
+ .div = 3,
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div3_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fixed_pll.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div3 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_FIXPLL_CTRL0,
+ .bit_idx = 22,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div3",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_div3_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * This clock is used by APB bus which is set in boot ROM code
+ * and is required by the platform to operate correctly.
+ */
+ .flags = CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_fixed_factor fclk_div5_div = {
+ .mult = 1,
+ .div = 5,
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div5_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fixed_pll.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div5 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_FIXPLL_CTRL0,
+ .bit_idx = 23,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div5",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_div5_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * This clock is used by AXI bus which setted in Romcode
+ * and is required by the platform to operate correctly.
+ */
+ .flags = CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_fixed_factor fclk_div7_div = {
+ .mult = 1,
+ .div = 7,
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div7_div",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fixed_pll.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div7 = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = ANACTRL_FIXPLL_CTRL0,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div7",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_div7_div.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+/* Array of all clocks registered by this provider */
+static struct clk_hw_onecell_data a1_pll_clks = {
+ .hws = {
+ [CLKID_FIXED_PLL_DCO] = &fixed_pll_dco.hw,
+ [CLKID_FIXED_PLL] = &fixed_pll.hw,
+ [CLKID_FCLK_DIV2_DIV] = &fclk_div2_div.hw,
+ [CLKID_FCLK_DIV3_DIV] = &fclk_div3_div.hw,
+ [CLKID_FCLK_DIV5_DIV] = &fclk_div5_div.hw,
+ [CLKID_FCLK_DIV7_DIV] = &fclk_div7_div.hw,
+ [CLKID_FCLK_DIV2] = &fclk_div2.hw,
+ [CLKID_FCLK_DIV3] = &fclk_div3.hw,
+ [CLKID_FCLK_DIV5] = &fclk_div5.hw,
+ [CLKID_FCLK_DIV7] = &fclk_div7.hw,
+ [CLKID_HIFI_PLL] = &hifi_pll.hw,
+ [NR_PLL_CLKS] = NULL,
+ },
+ .num = NR_PLL_CLKS,
+};
+
+static struct clk_regmap *const a1_pll_regmaps[] = {
+ &fixed_pll_dco,
+ &fixed_pll,
+ &fclk_div2,
+ &fclk_div3,
+ &fclk_div5,
+ &fclk_div7,
+ &hifi_pll,
+};
+
+static struct regmap_config a1_pll_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int meson_a1_pll_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ void __iomem *base;
+ struct regmap *map;
+ int clkid, i, err;
+
+ base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(base))
+ return dev_err_probe(dev, PTR_ERR(base),
+ "can't ioremap resource\n");
+
+ map = devm_regmap_init_mmio(dev, base, &a1_pll_regmap_cfg);
+ if (IS_ERR(map))
+ return dev_err_probe(dev, PTR_ERR(map),
+ "can't init regmap mmio region\n");
+
+ /* Populate regmap for the regmap backed clocks */
+ for (i = 0; i < ARRAY_SIZE(a1_pll_regmaps); i++)
+ a1_pll_regmaps[i]->map = map;
+
+ /* Register clocks */
+ for (clkid = 0; clkid < a1_pll_clks.num; clkid++) {
+ err = devm_clk_hw_register(dev, a1_pll_clks.hws[clkid]);
+ if (err)
+ return dev_err_probe(dev, err,
+ "clock[%d] registration failed\n",
+ clkid);
+ }
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ &a1_pll_clks);
+}
+
+static const struct of_device_id a1_pll_clkc_match_table[] = {
+ { .compatible = "amlogic,a1-pll-clkc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, a1_pll_clkc_match_table);
+
+static struct platform_driver a1_pll_clkc_driver = {
+ .probe = meson_a1_pll_probe,
+ .driver = {
+ .name = "a1-pll-clkc",
+ .of_match_table = of_match_ptr(a1_pll_clkc_match_table),
+ },
+};
+
+module_platform_driver(a1_pll_clkc_driver);
+MODULE_AUTHOR("Jian Hu <jian.hu@amlogic.com>");
+MODULE_AUTHOR("Dmitry Rokosov <ddrokosov@sberdevices.ru>");
+MODULE_LICENSE("GPL");
new file mode 100644
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Amlogic Meson-A1 PLL Clock Controller internals
+ *
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <jian.hu@amlogic.com>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <ddrokosov@sberdevices.ru>
+ */
+
+#ifndef __A1_PLL_H
+#define __A1_PLL_H
+
+#include "clk-pll.h"
+
+/* PLL register offset */
+#define ANACTRL_FIXPLL_CTRL0 0x0
+#define ANACTRL_FIXPLL_CTRL1 0x4
+#define ANACTRL_FIXPLL_STS 0x14
+#define ANACTRL_HIFIPLL_CTRL0 0xc0
+#define ANACTRL_HIFIPLL_CTRL1 0xc4
+#define ANACTRL_HIFIPLL_CTRL2 0xc8
+#define ANACTRL_HIFIPLL_CTRL3 0xcc
+#define ANACTRL_HIFIPLL_CTRL4 0xd0
+#define ANACTRL_HIFIPLL_STS 0xd4
+
+/* include the CLKIDs that have been made part of the DT binding */
+#include <dt-bindings/clock/amlogic,a1-pll-clkc.h>
+
+/*
+ * CLKID index values for internal clocks
+ *
+ * These indices are entirely contrived and do not map onto the hardware.
+ * It has now been decided to expose everything by default in the DT header:
+ * include/dt-bindings/clock/a1-pll-clkc.h. Only the clocks ids we don't want
+ * to expose, such as the internal muxes and dividers of composite clocks,
+ * will remain defined here.
+ */
+#define CLKID_FIXED_PLL_DCO 0
+#define CLKID_FCLK_DIV2_DIV 2
+#define CLKID_FCLK_DIV3_DIV 3
+#define CLKID_FCLK_DIV5_DIV 4
+#define CLKID_FCLK_DIV7_DIV 5
+#define NR_PLL_CLKS 11
+
+#endif /* __A1_PLL_H */