2023-03-01 18:38:36

by Dmitry Rokosov

[permalink] [raw]
Subject: [PATCH v9 0/5] add Amlogic A1 clock controller drivers

A1 SoC has four clock controllers on the board: PLL, Peripherals, CPU,
and Audio. The audio clock controller is different from others, but the
rest are very similar from a functional and regmap point of view.
This patch series add support for Amlogic A1 PLL and Peripherals clock
drivers.
It blocks all A1 peripherals mainline support and a couple of patch series,
which were already reviewed and acked, but weren't merged due to pending
clock controller drivers series, e.g.
https://lore.kernel.org/linux-amlogic/[email protected]/

TODO: CPU and Audio clock controllers are not included in this patch
series, it will be sent later. The following clks from these controllers
are not supported for now:
* Audio clks - vad, mclk_vad, mclk_d, resample_a, locker_in, mclk_b,
pdmdclk, pdmsysclk, eqdrc, spdifin, mclk_a, audio2_toaudiotop,
audio2_tovad, audio2_toddr_vad, audio2_tdmin_vad, audio2_pdm,
audio2_ddr_arb, audio_audiolocker, audio_eqdrc, audio_resamplea,
audio_spdifin, audio_toddrb, audio_toddra, audio_frddrb, audio_frddra,
audio_tdmoutb, audio_tdmouta, audio_loopbacka, audio_tdminlb,
audio_tdminb, audio_tdmina, audio_ddr_arb, mclk_c

* CPU clks: cpu_fixed_source_sel0, cpu_fixed_source_div0,
cpu_fixed_source_sel1, cpu_fixed_source_div1, cpu_clk

Validation:
* to double check all clk flags run below helper script:
pushd /sys/kernel/debug/clk
for f in *; do
if [[ -f "$f/clk_flags" ]]; then
flags="$(cat $f/clk_flags | awk '{$1=$1};1' | sed ':a;N;$!ba;s/\n/ | /g')"
echo -e "$f: $flags"
fi
done
popd
* to trace current clks state use '/sys/kernel/debug/clk/clk_dump' node
with jq post-processing:
cat /sys/kernel/debug/clk/clk_dump | jq '.' > clk_dump.json

Changes v9 since v8 at [9]:
- remove common a1-clkc driver for the first version of a1 clock
controllers as Jerome suggested (it will be discussed after s4 and
a1 clks landed, hope so)
- replace inherited a1-pll clk_pll_ops with common ops and
introduce custom A1 PLL logic under MESON_PARM_APPLICABLE()
conditions
- rename xtal depended clocks in PLL and Peripherals domains
- remove 'a1_' prefix for all clocks, because they are already
inside A1 driver, it's redundant
- change udelay() to usleep_range() as preferred for small msec
amount
- purge all double quotes from the yaml schemas
- use proper dt node names following kernel guidelines
https://devicetree-specification.readthedocs.io/en/latest/chapter2-devicetree-basics.html#generic-names-recommendation
- use devm_platform_ioremap_resource() instead of simple
devm_ioremap_resource()
- mark all dspX clocks as CLK_IGNORE_UNUSED, because we do not want
to touch these clocks during CCF initialization due to possible
workload execution on it started from bootloader; in this case
bootloader already made all initialization stuff for dspX
- also mark all dspX with NO_REPARENT tag, because from dspX clocks
we want to select proper clk source from device tree

Changes v8 since v7 at [8]:
- introduced a1-clkc common driver for all A1 clock controllers
- exported meson_clk_pll_wait_lock symbol
- supported meson-a1-clkc common driver in the a1-pll and a1 clkc
- inherited a1-pll from the base clk-pll driver, implemented own
version of init/enable/disable/enabled routines; rate calculating
logic is fully the same
- aligned CLKID-related definitions with CLKID list from order
perspective to remove holes and permutations
- corrected Kconfig dependencies and types
- provided correct MODULE_AUTHORs()
- optimized and fixed up some clock relationships
- removed unused register offset definitions
- fixed up A1 PLL and Peripherals clkc dtb_check errors
- fixed clk_summary kernel panic due to missing a1_pad_ctrl
clk_regmap definition
- included PLL and Peripherals clk controllers to the base a1 dts
- The previous v7 version [8] had several logic and style problems,
all of them are resolved in this version. Original Jian Hu v7 patches
are not touched, and all additional fixes are implemented in separate
patches. Patch "clk: meson: add support for A1 PLL clock ops" is
removed, because a1-pll clk driver inherits all stuff from clk-pll
base driver, just implements custom init/enable/disable/is_enabled
callbacks.

Changes v7 since v6 at [7]:
- fix 'dt_binding_check' compiling error
- add acked-by

Changes v6 since v5 at [6]:
- fix yaml file
- add rst/current_en/l_detect parm detection
- remove 'meson_eeclkc_data' in a1.c and a1-pll.c

Changes v5 since v4 at [5]:
- change yaml GPL
- drop meson-eeclk.c patch, add probe function in each driver
- add CLK_IS_CRITICAL for sys_clk clock, drop the flag for sys_a
and sys_b
- add new parm for pll, add protection for rst parm
- drop flag for a1_fixed_pll
- remove the same comment for fclk_div, add "refer to"
- add critical flag for a1_sys_clk
- remove rtc table
- rename a1_dspa_en_dspa and a1_dspb_en_dspb
- remove useless comment

Changes v4 since v3 at [3]:
- fix reparenting orphan failed, it depends on jerome's patch [4]
- fix changelist in v3 about reparenting orphan
- remove the dts patch

Changes v3 since v2 at [2]:
- add probe function for A1
- separate the clock driver into two patch
- change some clock flags and ops
- add support for a1 PLL ops
- add A1 clock node
- fix reparenting orphan clock failed, registering xtal_fixpll
and xtal_hifipll after the provider registration, it is not
a best way.

Changes v2 since v1 at [1]:
- place A1 config alphabetically
- add actual reason for RO ops, CLK_IS_CRITICAL, CLK_IGNORE_UNUSED
- separate the driver into two driver: peripheral and pll driver
- delete CLK_IGNORE_UNUSED flag for pwm b/c/d/e/f clock, dsp clock
- delete the change in Kconfig.platforms, address to Kevin alone
- remove the useless comments
- modify the meson pll driver to support A1 PLLs

[1] https://lkml.kernel.org/r/[email protected]
[2] https://lkml.kernel.org/r/[email protected]
[3] https://lkml.kernel.org/r/[email protected]
[4] https://lkml.kernel.org/r/[email protected]
[5] https://lkml.kernel.org/r/[email protected]
[6] https://lkml.kernel.org/r/[email protected]
[7] https://lkml.kernel.org/r/[email protected]
[8] https://lore.kernel.org/linux-amlogic/[email protected]/
[9] https://lore.kernel.org/linux-amlogic/[email protected]/

Dmitry Rokosov (4):
clk: meson: a1: add Amlogic A1 PLL clock controller driver
dt-bindings: clock: meson: add A1 PLL clock controller bindings
clk: meson: a1: add Amlogic A1 Peripherals clock controller driver
dt-bindings: clock: meson: add A1 Peripherals clock controller
bindings

Jian Hu (1):
clk: meson: add support for A1 PLL clock ops

.../bindings/clock/amlogic,a1-clkc.yaml | 73 +
.../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +
MAINTAINERS | 1 +
drivers/clk/meson/Kconfig | 18 +
drivers/clk/meson/Makefile | 2 +
drivers/clk/meson/a1-pll.c | 365 +++
drivers/clk/meson/a1-pll.h | 47 +
drivers/clk/meson/a1.c | 2291 +++++++++++++++++
drivers/clk/meson/a1.h | 116 +
drivers/clk/meson/clk-pll.c | 47 +-
drivers/clk/meson/clk-pll.h | 2 +
include/dt-bindings/clock/a1-clkc.h | 102 +
include/dt-bindings/clock/a1-pll-clkc.h | 20 +
13 files changed, 3136 insertions(+), 7 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
create mode 100644 drivers/clk/meson/a1-pll.c
create mode 100644 drivers/clk/meson/a1-pll.h
create mode 100644 drivers/clk/meson/a1.c
create mode 100644 drivers/clk/meson/a1.h
create mode 100644 include/dt-bindings/clock/a1-clkc.h
create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h

--
2.36.0



2023-03-01 18:38:29

by Dmitry Rokosov

[permalink] [raw]
Subject: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings

Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
clock controller bindings.
Also include new A1 clock controller dt bindings to MAINTAINERS.

Signed-off-by: Jian Hu <[email protected]>
Signed-off-by: Dmitry Rokosov <[email protected]>
---
.../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +++++++++++++++++++
MAINTAINERS | 1 +
include/dt-bindings/clock/a1-pll-clkc.h | 20 +++++++
3 files changed, 80 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
new file mode 100644
index 000000000000..8bd2c948df86
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
@@ -0,0 +1,59 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a1-pll-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic Meson A/C serials PLL Clock Control Unit
+
+maintainers:
+ - Neil Armstrong <[email protected]>
+ - Jerome Brunet <[email protected]>
+ - Jian Hu <[email protected]>
+ - Dmitry Rokosov <[email protected]>
+
+properties:
+ compatible:
+ const: amlogic,a1-pll-clkc
+
+ '#clock-cells':
+ const: 1
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: input fixpll_in
+ - description: input hifipll_in
+
+ clock-names:
+ items:
+ - const: fixpll_in
+ - const: hifipll_in
+
+required:
+ - compatible
+ - '#clock-cells'
+ - reg
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/a1-clkc.h>
+ apb {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@7c80 {
+ compatible = "amlogic,a1-pll-clkc";
+ reg = <0 0x7c80 0 0x18c>;
+ #clock-cells = <1>;
+ clocks = <&clkc_periphs CLKID_FIXPLL_IN>,
+ <&clkc_periphs CLKID_HIFIPLL_IN>;
+ clock-names = "fixpll_in", "hifipll_in";
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index 39ff1a717625..8438bc9bd636 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1895,6 +1895,7 @@ L: [email protected]
S: Maintained
F: Documentation/devicetree/bindings/clock/amlogic*
F: drivers/clk/meson/
+F: include/dt-bindings/clock/a1*
F: include/dt-bindings/clock/gxbb*
F: include/dt-bindings/clock/meson*

diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
new file mode 100644
index 000000000000..3a559518c6e6
--- /dev/null
+++ b/include/dt-bindings/clock/a1-pll-clkc.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#ifndef __A1_PLL_CLKC_H
+#define __A1_PLL_CLKC_H
+
+#define CLKID_FIXED_PLL 1
+#define CLKID_FCLK_DIV2 6
+#define CLKID_FCLK_DIV3 7
+#define CLKID_FCLK_DIV5 8
+#define CLKID_FCLK_DIV7 9
+#define CLKID_HIFI_PLL 10
+
+#endif /* __A1_PLL_CLKC_H */
--
2.36.0


2023-03-01 18:38:39

by Dmitry Rokosov

[permalink] [raw]
Subject: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver

Introduce PLL clock controller for Amlogic A1 SoC family.

Signed-off-by: Jian Hu <[email protected]>
Signed-off-by: Dmitry Rokosov <[email protected]>
---
drivers/clk/meson/Kconfig | 10 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a1-pll.c | 365 +++++++++++++++++++++++++++++++++++++
drivers/clk/meson/a1-pll.h | 47 +++++
4 files changed, 423 insertions(+)
create mode 100644 drivers/clk/meson/a1-pll.c
create mode 100644 drivers/clk/meson/a1-pll.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index fc002c155bc3..f56da2a4b000 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -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
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 6eca2a406ee3..2f17f475a48f 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -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
diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
new file mode 100644
index 000000000000..c565f9b2a8dd
--- /dev/null
+++ b/drivers/clk/meson/a1-pll.c
@@ -0,0 +1,365 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "meson-a1-clkc.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,
+ /*
+ * It is enough that the fdiv leaf has critical flag,
+ * No critical or unused flag here.
+ */
+ },
+};
+
+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 = 0x01f18440 },
+};
+
+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.
+ * About critical, refer to fclk_div2.
+ */
+ .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.
+ * About critical, refer to fclk_div2.
+ */
+ .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 provided by this provider */
+static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
+ .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;
+ struct clk_hw *hw;
+ 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;
+
+ for (clkid = 0; clkid < a1_pll_hw_onecell_data.num; clkid++) {
+ hw = a1_pll_hw_onecell_data.hws[clkid];
+ err = devm_clk_hw_register(dev, hw);
+ if (err)
+ return dev_err_probe(dev, err,
+ "clock registration failed\n");
+ }
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ &a1_pll_hw_onecell_data);
+}
+
+#ifdef CONFIG_OF
+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);
+#endif /* CONFIG_OF */
+
+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 <[email protected]>");
+MODULE_AUTHOR("Dmitry Rokosov <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
new file mode 100644
index 000000000000..de2eebce98af
--- /dev/null
+++ b/drivers/clk/meson/a1-pll.h
@@ -0,0 +1,47 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Amlogic Meson-A1 PLL Clock Controller internals
+ *
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#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
+
+/*
+ * CLKID index values
+ *
+ * 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
+
+/* include the CLKIDs that have been made part of the DT binding */
+#include <dt-bindings/clock/a1-pll-clkc.h>
+
+#endif /* __A1_PLL_H */
--
2.36.0


2023-03-01 18:38:43

by Dmitry Rokosov

[permalink] [raw]
Subject: [PATCH v9 5/5] dt-bindings: clock: meson: add A1 Peripherals clock controller bindings

Add the documentation for Amlogic A1 Peripherals clock driver,
and A1 Peripherals clock controller bindings.

Signed-off-by: Jian Hu <[email protected]>
Signed-off-by: Dmitry Rokosov <[email protected]>
---
.../bindings/clock/amlogic,a1-clkc.yaml | 73 +++++++++++++
include/dt-bindings/clock/a1-clkc.h | 102 ++++++++++++++++++
2 files changed, 175 insertions(+)
create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
create mode 100644 include/dt-bindings/clock/a1-clkc.h

diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
new file mode 100644
index 000000000000..3dc86e912dea
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
@@ -0,0 +1,73 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/clock/amlogic,a1-clkc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Amlogic Meson A/C serials Peripheral Clock Control Unit
+
+maintainers:
+ - Neil Armstrong <[email protected]>
+ - Jerome Brunet <[email protected]>
+ - Jian Hu <[email protected]>
+ - Dmitry Rokosov <[email protected]>
+
+properties:
+ compatible:
+ const: amlogic,a1-clkc
+
+ '#clock-cells':
+ const: 1
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: input fixed pll div2
+ - description: input fixed pll div3
+ - description: input fixed pll div5
+ - description: input fixed pll div7
+ - description: input hifi pll
+ - description: input oscillator (usually at 24MHz)
+
+ clock-names:
+ items:
+ - const: fclk_div2
+ - const: fclk_div3
+ - const: fclk_div5
+ - const: fclk_div7
+ - const: hifi_pll
+ - const: xtal
+
+required:
+ - compatible
+ - '#clock-cells'
+ - reg
+ - clocks
+ - clock-names
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/a1-pll-clkc.h>
+ apb {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ clock-controller@800 {
+ compatible = "amlogic,a1-clkc";
+ reg = <0 0x800 0 0x104>;
+ #clock-cells = <1>;
+ clocks = <&clkc_pll CLKID_FCLK_DIV2>,
+ <&clkc_pll CLKID_FCLK_DIV3>,
+ <&clkc_pll CLKID_FCLK_DIV5>,
+ <&clkc_pll CLKID_FCLK_DIV7>,
+ <&clkc_pll CLKID_HIFI_PLL>,
+ <&xtal>;
+ clock-names = "fclk_div2", "fclk_div3",
+ "fclk_div5", "fclk_div7",
+ "hifi_pll", "xtal";
+ };
+ };
diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h
new file mode 100644
index 000000000000..271eefb989f3
--- /dev/null
+++ b/include/dt-bindings/clock/a1-clkc.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#ifndef __A1_CLKC_H
+#define __A1_CLKC_H
+
+#define CLKID_FIXPLL_IN 1
+#define CLKID_USB_PHY_IN 2
+#define CLKID_USB_CTRL_IN 3
+#define CLKID_HIFIPLL_IN 4
+#define CLKID_SYSPLL_IN 5
+#define CLKID_DDS_IN 6
+#define CLKID_SYS 7
+#define CLKID_CLKTREE 8
+#define CLKID_RESET_CTRL 9
+#define CLKID_ANALOG_CTRL 10
+#define CLKID_PWR_CTRL 11
+#define CLKID_PAD_CTRL 12
+#define CLKID_SYS_CTRL 13
+#define CLKID_TEMP_SENSOR 14
+#define CLKID_AM2AXI_DIV 15
+#define CLKID_SPICC_B 16
+#define CLKID_SPICC_A 17
+#define CLKID_MSR 18
+#define CLKID_AUDIO 19
+#define CLKID_JTAG_CTRL 20
+#define CLKID_SARADC_EN 21
+#define CLKID_PWM_EF 22
+#define CLKID_PWM_CD 23
+#define CLKID_PWM_AB 24
+#define CLKID_CEC 25
+#define CLKID_I2C_S 26
+#define CLKID_IR_CTRL 27
+#define CLKID_I2C_M_D 28
+#define CLKID_I2C_M_C 29
+#define CLKID_I2C_M_B 30
+#define CLKID_I2C_M_A 31
+#define CLKID_ACODEC 32
+#define CLKID_OTP 33
+#define CLKID_SD_EMMC_A 34
+#define CLKID_USB_PHY 35
+#define CLKID_USB_CTRL 36
+#define CLKID_SYS_DSPB 37
+#define CLKID_SYS_DSPA 38
+#define CLKID_DMA 39
+#define CLKID_IRQ_CTRL 40
+#define CLKID_NIC 41
+#define CLKID_GIC 42
+#define CLKID_UART_C 43
+#define CLKID_UART_B 44
+#define CLKID_UART_A 45
+#define CLKID_SYS_PSRAM 46
+#define CLKID_RSA 47
+#define CLKID_CORESIGHT 48
+#define CLKID_AM2AXI_VAD 49
+#define CLKID_AUDIO_VAD 50
+#define CLKID_AXI_DMC 51
+#define CLKID_AXI_PSRAM 52
+#define CLKID_RAMB 53
+#define CLKID_RAMA 54
+#define CLKID_AXI_SPIFC 55
+#define CLKID_AXI_NIC 56
+#define CLKID_AXI_DMA 57
+#define CLKID_CPU_CTRL 58
+#define CLKID_ROM 59
+#define CLKID_PROC_I2C 60
+#define CLKID_DSPA_SEL 61
+#define CLKID_DSPB_SEL 62
+#define CLKID_DSPA_EN 63
+#define CLKID_DSPA_EN_NIC 64
+#define CLKID_DSPB_EN 65
+#define CLKID_DSPB_EN_NIC 66
+#define CLKID_RTC 67
+#define CLKID_CECA_32K 68
+#define CLKID_CECB_32K 69
+#define CLKID_24M 70
+#define CLKID_12M 71
+#define CLKID_FCLK_DIV2_DIVN 72
+#define CLKID_GEN 73
+#define CLKID_SARADC_SEL 74
+#define CLKID_SARADC 75
+#define CLKID_PWM_A 76
+#define CLKID_PWM_B 77
+#define CLKID_PWM_C 78
+#define CLKID_PWM_D 79
+#define CLKID_PWM_E 80
+#define CLKID_PWM_F 81
+#define CLKID_SPICC 82
+#define CLKID_TS 83
+#define CLKID_SPIFC 84
+#define CLKID_USB_BUS 85
+#define CLKID_SD_EMMC 86
+#define CLKID_PSRAM 87
+#define CLKID_DMC 88
+
+#endif /* __A1_CLKC_H */
--
2.36.0


2023-03-01 18:38:47

by Dmitry Rokosov

[permalink] [raw]
Subject: [PATCH v9 4/5] clk: meson: a1: add Amlogic A1 Peripherals clock controller driver

Introduce Peripherals clock controller for Amlogic A1 SoC family.

Signed-off-by: Jian Hu <[email protected]>
Signed-off-by: Dmitry Rokosov <[email protected]>
---
drivers/clk/meson/Kconfig | 10 +
drivers/clk/meson/Makefile | 1 +
drivers/clk/meson/a1.c | 2291 ++++++++++++++++++++++++++++++++++++
drivers/clk/meson/a1.h | 116 ++
4 files changed, 2418 insertions(+)
create mode 100644 drivers/clk/meson/a1.c
create mode 100644 drivers/clk/meson/a1.h

diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
index f56da2a4b000..970892b07043 100644
--- a/drivers/clk/meson/Kconfig
+++ b/drivers/clk/meson/Kconfig
@@ -109,6 +109,16 @@ config COMMON_CLK_A1_PLL
device, A1 SoC Family. Say Y if you want A1 PLL clock controller
to work.

+config COMMON_CLK_A1
+ tristate "Meson A1 SoC clock controller support"
+ depends on ARM64
+ select COMMON_CLK_MESON_DUALDIV
+ select COMMON_CLK_MESON_REGMAP
+ help
+ Support for the Peripherals clock controller on Amlogic A113L based
+ device, A1 SoC Family. Say Y if you want A1 Peripherals clock
+ controller to work.
+
config COMMON_CLK_G12A
tristate "G12 and SM1 SoC clock controllers support"
depends on ARM64
diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
index 2f17f475a48f..0e6f293c05d4 100644
--- a/drivers/clk/meson/Makefile
+++ b/drivers/clk/meson/Makefile
@@ -17,6 +17,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_A1) += a1.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
diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
new file mode 100644
index 000000000000..62468c49aac9
--- /dev/null
+++ b/drivers/clk/meson/a1.c
@@ -0,0 +1,2291 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include "a1.h"
+#include "clk-dualdiv.h"
+#include "clk-regmap.h"
+#include "meson-a1-clkc.h"
+
+static struct clk_regmap xtal_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "xtal_in",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fixpll_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "fixpll_in",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap usb_phy_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 2,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "usb_phy_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap usb_ctrl_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 3,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "usb_ctrl_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap hifipll_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 4,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "hifipll_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap syspll_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 5,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "syspll_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap dds_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_OSCIN_CTRL,
+ .bit_idx = 6,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dds_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap rtc_32k_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = RTC_BY_OSCIN_CTRL0,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_32k_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static const struct meson_clk_dualdiv_param clk_32k_div_table[] = {
+ {
+ .dual = 1,
+ .n1 = 733,
+ .m1 = 8,
+ .n2 = 732,
+ .m2 = 11,
+ },
+ {}
+};
+
+static struct clk_regmap rtc_32k_div = {
+ .data = &(struct meson_clk_dualdiv_data){
+ .n1 = {
+ .reg_off = RTC_BY_OSCIN_CTRL0,
+ .shift = 0,
+ .width = 12,
+ },
+ .n2 = {
+ .reg_off = RTC_BY_OSCIN_CTRL0,
+ .shift = 12,
+ .width = 12,
+ },
+ .m1 = {
+ .reg_off = RTC_BY_OSCIN_CTRL1,
+ .shift = 0,
+ .width = 12,
+ },
+ .m2 = {
+ .reg_off = RTC_BY_OSCIN_CTRL1,
+ .shift = 12,
+ .width = 12,
+ },
+ .dual = {
+ .reg_off = RTC_BY_OSCIN_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .table = clk_32k_div_table,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "rtc_32k_div",
+ .ops = &meson_clk_dualdiv_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_32k_in.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap rtc_32k_xtal = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = RTC_BY_OSCIN_CTRL1,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "rtc_32k_xtal",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_32k_in.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap rtc_32k_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = RTC_CTRL,
+ .mask = 0x3,
+ .shift = 0,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "rtc_32k_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_32k_xtal.hw,
+ &rtc_32k_div.hw,
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+struct clk_regmap rtc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = RTC_BY_OSCIN_CTRL0,
+ .bit_idx = 30,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "rtc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &rtc_32k_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static u32 mux_table_sys[] = { 0, 1, 2, 3, 7 };
+static const struct clk_parent_data sys_parents[] = {
+ { .fw_name = "xtal" },
+ { .fw_name = "fclk_div2" },
+ { .fw_name = "fclk_div3" },
+ { .fw_name = "fclk_div5" },
+ { .hw = &rtc.hw },
+};
+
+static struct clk_regmap sys_b_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SYS_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 26,
+ .table = mux_table_sys,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_b_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_data = sys_parents,
+ .num_parents = ARRAY_SIZE(sys_parents),
+ },
+};
+
+static struct clk_regmap sys_b_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SYS_CLK_CTRL0,
+ .shift = 16,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_b_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sys_b_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sys_b = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_CLK_CTRL0,
+ .bit_idx = 29,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sys_b",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sys_b_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sys_a_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SYS_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 10,
+ .table = mux_table_sys,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_a_sel",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_data = sys_parents,
+ .num_parents = ARRAY_SIZE(sys_parents),
+ },
+};
+
+static struct clk_regmap sys_a_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SYS_CLK_CTRL0,
+ .shift = 0,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys_a_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sys_a_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sys_a = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SYS_CLK_CTRL0,
+ .bit_idx = 13,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sys_a",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sys_a_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sys = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SYS_CLK_CTRL0,
+ .mask = 0x1,
+ .shift = 31,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sys",
+ .ops = &clk_regmap_mux_ro_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sys_a.hw,
+ &sys_b.hw,
+ },
+ .num_parents = 2,
+ /*
+ * This clock is used by APB bus which is set in boot ROM code
+ * 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_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
+static const struct clk_parent_data dsp_ab_parent_data[] = {
+ { .fw_name = "xtal", },
+ { .fw_name = "fclk_div2", },
+ { .fw_name = "fclk_div3", },
+ { .fw_name = "fclk_div5", },
+ { .fw_name = "hifi_pll", },
+ { .hw = &rtc.hw },
+};
+
+static struct clk_regmap dspa_a_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPA_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 10,
+ .table = mux_table_dsp_ab,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspa_a_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dsp_ab_parent_data,
+ .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
+ /* DSPA_A clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspa_a_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = DSPA_CLK_CTRL0,
+ .shift = 0,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspa_a_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_a_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa_a = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPA_CLK_CTRL0,
+ .bit_idx = 13,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_a",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_a_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPA_A accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspa_b_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPA_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 26,
+ .table = mux_table_dsp_ab,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspa_b_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dsp_ab_parent_data,
+ .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
+ /* DSPA_B clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspa_b_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = DSPA_CLK_CTRL0,
+ .shift = 16,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspa_b_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_b_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspa_b = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPA_CLK_CTRL0,
+ .bit_idx = 29,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_b",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_b_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPA_B accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspa_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPA_CLK_CTRL0,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspa_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_a.hw,
+ &dspa_b.hw,
+ },
+ .num_parents = 2,
+ /* DSPA clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspa_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPA_CLK_EN,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_sel.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPA_EN accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspa_en_nic = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPA_CLK_EN,
+ .bit_idx = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspa_en_nic",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspa_sel.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPA_EN_NIC accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspb_a_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPB_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 10,
+ .table = mux_table_dsp_ab,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspb_a_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dsp_ab_parent_data,
+ .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
+ /* DSPB_A clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspb_a_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = DSPB_CLK_CTRL0,
+ .shift = 0,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspb_a_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_a_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspb_a = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPB_CLK_CTRL0,
+ .bit_idx = 13,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspb_a",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_a_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPB_A accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspb_b_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPB_CLK_CTRL0,
+ .mask = 0x7,
+ .shift = 26,
+ .table = mux_table_dsp_ab,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspb_b_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = dsp_ab_parent_data,
+ .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
+ /* DSPB_B clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspb_b_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = DSPB_CLK_CTRL0,
+ .shift = 16,
+ .width = 10,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspb_b_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_b_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dspb_b = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPB_CLK_CTRL0,
+ .bit_idx = 29,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspb_b",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_b_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPB_B accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspb_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DSPB_CLK_CTRL0,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dspb_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_a.hw,
+ &dspb_b.hw,
+ },
+ .num_parents = 2,
+ /* DSPB clk parent should be set statically from dt */
+ .flags = CLK_SET_RATE_NO_REPARENT,
+ },
+};
+
+static struct clk_regmap dspb_en = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPB_CLK_EN,
+ .bit_idx = 1,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspb_en",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_sel.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPB_EN accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap dspb_en_nic = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DSPB_CLK_EN,
+ .bit_idx = 0,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dspb_en_nic",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dspb_sel.hw
+ },
+ .num_parents = 1,
+ /*
+ * DSPB_EN_NIC accelerator clk, cannot be disabled by CCF if it
+ * has been set by bootloader
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
+ },
+};
+
+static struct clk_regmap clk_24m = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CLK12_24_CTRL,
+ .bit_idx = 11,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "24m",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_fixed_factor clk_24m_div2 = {
+ .mult = 1,
+ .div = 2,
+ .hw.init = &(struct clk_init_data){
+ .name = "24m_div2",
+ .ops = &clk_fixed_factor_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &clk_24m.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap clk_12m = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CLK12_24_CTRL,
+ .bit_idx = 10,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "12m",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &clk_24m_div2.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div2_divn_pre = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = CLK12_24_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div2_divn_pre",
+ .ops = &clk_regmap_divider_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "fclk_div2",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap fclk_div2_divn = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CLK12_24_CTRL,
+ .bit_idx = 12,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "fclk_div2_divn",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &fclk_div2_divn_pre.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/*
+ * the index 2 is sys_pll_div16, it will be completed in the CPU clock ctrl,
+ * the index 4 is the clock measurement source, it relies on
+ * the clock measurement register configuration.
+ */
+static u32 gen_table[] = { 0, 1, 3, 5, 6, 7, 8 };
+static const struct clk_parent_data gen_parent_data[] = {
+ { .fw_name = "xtal", },
+ { .hw = &rtc.hw },
+ { .fw_name = "hifi_pll", },
+ { .fw_name = "fclk_div2", },
+ { .fw_name = "fclk_div3", },
+ { .fw_name = "fclk_div5", },
+ { .fw_name = "fclk_div7", },
+};
+
+static struct clk_regmap gen_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = GEN_CLK_CTRL,
+ .mask = 0xf,
+ .shift = 12,
+ .table = gen_table,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "gen_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = gen_parent_data,
+ .num_parents = ARRAY_SIZE(gen_parent_data),
+ },
+};
+
+static struct clk_regmap gen_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = GEN_CLK_CTRL,
+ .shift = 0,
+ .width = 11,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "gen_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &gen_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap gen = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = GEN_CLK_CTRL,
+ .bit_idx = 11,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "gen",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &gen_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap saradc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SAR_ADC_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "saradc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .fw_name = "xtal", },
+ { .hw = &sys.hw, },
+ },
+ .num_parents = 2,
+ },
+};
+
+static struct clk_regmap saradc_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SAR_ADC_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "saradc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &saradc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap saradc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SAR_ADC_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "saradc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &saradc_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data pwm_abcd_parents[] = {
+ { .fw_name = "xtal", },
+ { .hw = &sys.hw },
+ { .hw = &rtc.hw },
+};
+
+static struct clk_regmap pwm_a_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .mask = 0x1,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_a_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_abcd_parents,
+ .num_parents = ARRAY_SIZE(pwm_abcd_parents),
+ },
+};
+
+static struct clk_regmap pwm_a_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_a_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_a_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_a = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_a",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_a_div.hw
+ },
+ .num_parents = 1,
+ /*
+ * The CPU working voltage is controlled by pwm_a
+ * in BL2 firmware. The clock is required by the platform
+ * to operate correctly. Add the CLK_IS_CRITICAL flag to
+ * avoid changing at runtime.
+ * About critical, refer to sys
+ */
+ .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
+ },
+};
+
+static struct clk_regmap pwm_b_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .mask = 0x1,
+ .shift = 25,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_b_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_abcd_parents,
+ .num_parents = ARRAY_SIZE(pwm_abcd_parents),
+ },
+};
+
+static struct clk_regmap pwm_b_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .shift = 16,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_b_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_b_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_b = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_AB_CTRL,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_b",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_b_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_c_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .mask = 0x1,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_c_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_abcd_parents,
+ .num_parents = ARRAY_SIZE(pwm_abcd_parents),
+ },
+};
+
+static struct clk_regmap pwm_c_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_c_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_c_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_c = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_c",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_c_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_d_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .mask = 0x1,
+ .shift = 25,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_d_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_abcd_parents,
+ .num_parents = ARRAY_SIZE(pwm_abcd_parents),
+ },
+};
+
+static struct clk_regmap pwm_d_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .shift = 16,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_d_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_d_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_d = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_CD_CTRL,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_d",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_d_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data pwm_ef_parents[] = {
+ { .fw_name = "xtal", },
+ { .hw = &sys.hw },
+ { .fw_name = "fclk_div5", },
+ { .hw = &rtc.hw },
+};
+
+static struct clk_regmap pwm_e_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_e_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_ef_parents,
+ .num_parents = ARRAY_SIZE(pwm_ef_parents),
+ },
+};
+
+static struct clk_regmap pwm_e_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_e_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_e_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_e = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_e",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_e_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_f_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .mask = 0x3,
+ .shift = 25,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_f_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = pwm_ef_parents,
+ .num_parents = ARRAY_SIZE(pwm_ef_parents),
+ },
+};
+
+static struct clk_regmap pwm_f_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .shift = 16,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "pwm_f_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_f_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap pwm_f = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PWM_CLK_EF_CTRL,
+ .bit_idx = 24,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "pwm_f",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &pwm_f_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+/*
+ * spicc clk
+ * fdiv2 |\ |\ _____
+ * ---------| |---DIV--| | | | spicc out
+ * ---------| | | |-----|GATE |---------
+ * ..... |/ | / |_____|
+ * --------------------|/
+ * 24M
+ */
+static const struct clk_parent_data spicc_spifc_parents[] = {
+ { .fw_name = "fclk_div2"},
+ { .fw_name = "fclk_div3"},
+ { .fw_name = "fclk_div5"},
+ { .fw_name = "hifi_pll" },
+};
+
+static struct clk_regmap spicc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SPICC_CLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spicc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = spicc_spifc_parents,
+ .num_parents = ARRAY_SIZE(spicc_spifc_parents),
+ },
+};
+
+static struct clk_regmap spicc_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SPICC_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spicc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spicc_sel2 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SPICC_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spicc_sel2",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .hw = &spicc_div.hw },
+ { .fw_name = "xtal", },
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spicc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SPICC_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spicc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spicc_sel2.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap ts_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = TS_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ts_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap ts = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = TS_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "ts",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &ts_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spifc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SPIFC_CLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spifc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = spicc_spifc_parents,
+ .num_parents = ARRAY_SIZE(spicc_spifc_parents),
+ },
+};
+
+static struct clk_regmap spifc_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SPIFC_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spifc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spifc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spifc_sel2 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SPIFC_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "spifc_sel2",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .hw = &spifc_div.hw },
+ { .fw_name = "xtal", },
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap spifc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SPIFC_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "spifc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &spifc_sel2.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data usb_bus_parents[] = {
+ { .fw_name = "xtal", },
+ { .hw = &sys.hw },
+ { .fw_name = "fclk_div3", },
+ { .fw_name = "fclk_div5", },
+};
+
+static struct clk_regmap usb_bus_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = USB_BUSCLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "usb_bus_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = usb_bus_parents,
+ .num_parents = ARRAY_SIZE(usb_bus_parents),
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap usb_bus_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = USB_BUSCLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "usb_bus_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &usb_bus_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap usb_bus = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = USB_BUSCLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "usb_bus",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &usb_bus_div.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static const struct clk_parent_data sd_emmc_psram_dmc_parents[] = {
+ { .fw_name = "fclk_div2", },
+ { .fw_name = "fclk_div3", },
+ { .fw_name = "fclk_div5", },
+ { .fw_name = "hifi_pll", },
+};
+
+static struct clk_regmap sd_emmc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SD_EMMC_CLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sd_emmc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = sd_emmc_psram_dmc_parents,
+ .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
+ },
+};
+
+static struct clk_regmap sd_emmc_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = SD_EMMC_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sd_emmc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sd_emmc_sel2 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = SD_EMMC_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "sd_emmc_sel2",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .hw = &sd_emmc_div.hw },
+ { .fw_name = "xtal", },
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap sd_emmc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = SD_EMMC_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "sd_emmc",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &sd_emmc_sel2.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap psram_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PSRAM_CLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "psram_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = sd_emmc_psram_dmc_parents,
+ .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
+ },
+};
+
+static struct clk_regmap psram_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = PSRAM_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "psram_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &psram_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap psram_sel2 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = PSRAM_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "psram_sel2",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .hw = &psram_div.hw },
+ { .fw_name = "xtal", },
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap psram = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = PSRAM_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "psram",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &psram_sel2.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dmc_sel = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DMC_CLK_CTRL,
+ .mask = 0x3,
+ .shift = 9,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dmc_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = sd_emmc_psram_dmc_parents,
+ .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
+ },
+};
+
+static struct clk_regmap dmc_div = {
+ .data = &(struct clk_regmap_div_data){
+ .offset = DMC_CLK_CTRL,
+ .shift = 0,
+ .width = 8,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dmc_div",
+ .ops = &clk_regmap_divider_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dmc_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dmc_sel2 = {
+ .data = &(struct clk_regmap_mux_data){
+ .offset = DMC_CLK_CTRL,
+ .mask = 0x1,
+ .shift = 15,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "dmc_sel2",
+ .ops = &clk_regmap_mux_ops,
+ .parent_data = (const struct clk_parent_data []) {
+ { .hw = &dmc_div.hw },
+ { .fw_name = "xtal", },
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap dmc = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = DMC_CLK_CTRL,
+ .bit_idx = 8,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "dmc",
+ .ops = &clk_regmap_gate_ro_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &dmc_sel2.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap ceca_32k_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CECA_CLK_CTRL0,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "ceca_32k_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap ceca_32k_div = {
+ .data = &(struct meson_clk_dualdiv_data){
+ .n1 = {
+ .reg_off = CECA_CLK_CTRL0,
+ .shift = 0,
+ .width = 12,
+ },
+ .n2 = {
+ .reg_off = CECA_CLK_CTRL0,
+ .shift = 12,
+ .width = 12,
+ },
+ .m1 = {
+ .reg_off = CECA_CLK_CTRL1,
+ .shift = 0,
+ .width = 12,
+ },
+ .m2 = {
+ .reg_off = CECA_CLK_CTRL1,
+ .shift = 12,
+ .width = 12,
+ },
+ .dual = {
+ .reg_off = CECA_CLK_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .table = clk_32k_div_table,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ceca_32k_div",
+ .ops = &meson_clk_dualdiv_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &ceca_32k_in.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap ceca_32k_sel_pre = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CECA_CLK_CTRL1,
+ .mask = 0x1,
+ .shift = 24,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ceca_32k_sel_pre",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &ceca_32k_div.hw,
+ &ceca_32k_in.hw,
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap ceca_32k_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CECA_CLK_CTRL1,
+ .mask = 0x1,
+ .shift = 31,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ceca_32k_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &ceca_32k_sel_pre.hw,
+ &rtc.hw,
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap ceca_32k_out = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CECA_CLK_CTRL0,
+ .bit_idx = 30,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "ceca_32k_out",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &ceca_32k_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap cecb_32k_in = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CECB_CLK_CTRL0,
+ .bit_idx = 31,
+ },
+ .hw.init = &(struct clk_init_data) {
+ .name = "cecb_32k_in",
+ .ops = &clk_regmap_gate_ops,
+ .parent_data = &(const struct clk_parent_data) {
+ .fw_name = "xtal",
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap cecb_32k_div = {
+ .data = &(struct meson_clk_dualdiv_data){
+ .n1 = {
+ .reg_off = CECB_CLK_CTRL0,
+ .shift = 0,
+ .width = 12,
+ },
+ .n2 = {
+ .reg_off = CECB_CLK_CTRL0,
+ .shift = 12,
+ .width = 12,
+ },
+ .m1 = {
+ .reg_off = CECB_CLK_CTRL1,
+ .shift = 0,
+ .width = 12,
+ },
+ .m2 = {
+ .reg_off = CECB_CLK_CTRL1,
+ .shift = 12,
+ .width = 12,
+ },
+ .dual = {
+ .reg_off = CECB_CLK_CTRL0,
+ .shift = 28,
+ .width = 1,
+ },
+ .table = clk_32k_div_table,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cecb_32k_div",
+ .ops = &meson_clk_dualdiv_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &cecb_32k_in.hw
+ },
+ .num_parents = 1,
+ },
+};
+
+static struct clk_regmap cecb_32k_sel_pre = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CECB_CLK_CTRL1,
+ .mask = 0x1,
+ .shift = 24,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cecb_32k_sel_pre",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &cecb_32k_div.hw,
+ &cecb_32k_in.hw,
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap cecb_32k_sel = {
+ .data = &(struct clk_regmap_mux_data) {
+ .offset = CECB_CLK_CTRL1,
+ .mask = 0x1,
+ .shift = 31,
+ .flags = CLK_MUX_ROUND_CLOSEST,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cecb_32k_sel",
+ .ops = &clk_regmap_mux_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &cecb_32k_sel_pre.hw,
+ &rtc.hw,
+ },
+ .num_parents = 2,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+static struct clk_regmap cecb_32k_out = {
+ .data = &(struct clk_regmap_gate_data){
+ .offset = CECB_CLK_CTRL0,
+ .bit_idx = 30,
+ },
+ .hw.init = &(struct clk_init_data){
+ .name = "cecb_32k_out",
+ .ops = &clk_regmap_gate_ops,
+ .parent_hws = (const struct clk_hw *[]) {
+ &cecb_32k_sel.hw
+ },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+};
+
+#define MESON_GATE(_name, _reg, _bit) \
+ MESON_PCLK(_name, _reg, _bit, &sys.hw)
+
+static MESON_GATE(clktree, SYS_CLK_EN0, 0);
+static MESON_GATE(reset_ctrl, SYS_CLK_EN0, 1);
+static MESON_GATE(analog_ctrl, SYS_CLK_EN0, 2);
+static MESON_GATE(pwr_ctrl, SYS_CLK_EN0, 3);
+static MESON_GATE(pad_ctrl, SYS_CLK_EN0, 4);
+static MESON_GATE(sys_ctrl, SYS_CLK_EN0, 5);
+static MESON_GATE(temp_sensor, SYS_CLK_EN0, 6);
+static MESON_GATE(am2axi_dev, SYS_CLK_EN0, 7);
+static MESON_GATE(spicc_b, SYS_CLK_EN0, 8);
+static MESON_GATE(spicc_a, SYS_CLK_EN0, 9);
+static MESON_GATE(msr, SYS_CLK_EN0, 10);
+static MESON_GATE(audio, SYS_CLK_EN0, 11);
+static MESON_GATE(jtag_ctrl, SYS_CLK_EN0, 12);
+static MESON_GATE(saradc_en, SYS_CLK_EN0, 13);
+static MESON_GATE(pwm_ef, SYS_CLK_EN0, 14);
+static MESON_GATE(pwm_cd, SYS_CLK_EN0, 15);
+static MESON_GATE(pwm_ab, SYS_CLK_EN0, 16);
+static MESON_GATE(cec, SYS_CLK_EN0, 17);
+static MESON_GATE(i2c_s, SYS_CLK_EN0, 18);
+static MESON_GATE(ir_ctrl, SYS_CLK_EN0, 19);
+static MESON_GATE(i2c_m_d, SYS_CLK_EN0, 20);
+static MESON_GATE(i2c_m_c, SYS_CLK_EN0, 21);
+static MESON_GATE(i2c_m_b, SYS_CLK_EN0, 22);
+static MESON_GATE(i2c_m_a, SYS_CLK_EN0, 23);
+static MESON_GATE(acodec, SYS_CLK_EN0, 24);
+static MESON_GATE(otp, SYS_CLK_EN0, 25);
+static MESON_GATE(sd_emmc_a, SYS_CLK_EN0, 26);
+static MESON_GATE(usb_phy, SYS_CLK_EN0, 27);
+static MESON_GATE(usb_ctrl, SYS_CLK_EN0, 28);
+static MESON_GATE(sys_dspb, SYS_CLK_EN0, 29);
+static MESON_GATE(sys_dspa, SYS_CLK_EN0, 30);
+static MESON_GATE(dma, SYS_CLK_EN0, 31);
+static MESON_GATE(irq_ctrl, SYS_CLK_EN1, 0);
+static MESON_GATE(nic, SYS_CLK_EN1, 1);
+static MESON_GATE(gic, SYS_CLK_EN1, 2);
+static MESON_GATE(uart_c, SYS_CLK_EN1, 3);
+static MESON_GATE(uart_b, SYS_CLK_EN1, 4);
+static MESON_GATE(uart_a, SYS_CLK_EN1, 5);
+static MESON_GATE(sys_psram, SYS_CLK_EN1, 6);
+static MESON_GATE(rsa, SYS_CLK_EN1, 8);
+static MESON_GATE(coresight, SYS_CLK_EN1, 9);
+static MESON_GATE(am2axi_vad, AXI_CLK_EN, 0);
+static MESON_GATE(audio_vad, AXI_CLK_EN, 1);
+static MESON_GATE(axi_dmc, AXI_CLK_EN, 3);
+static MESON_GATE(axi_psram, AXI_CLK_EN, 4);
+static MESON_GATE(ramb, AXI_CLK_EN, 5);
+static MESON_GATE(rama, AXI_CLK_EN, 6);
+static MESON_GATE(axi_spifc, AXI_CLK_EN, 7);
+static MESON_GATE(axi_nic, AXI_CLK_EN, 8);
+static MESON_GATE(axi_dma, AXI_CLK_EN, 9);
+static MESON_GATE(cpu_ctrl, AXI_CLK_EN, 10);
+static MESON_GATE(rom, AXI_CLK_EN, 11);
+static MESON_GATE(prod_i2c, AXI_CLK_EN, 12);
+
+/* Array of all clocks provided by this provider */
+static struct clk_hw_onecell_data a1_periphs_hw_onecell_data = {
+ .hws = {
+ [CLKID_XTAL_IN] = &xtal_in.hw,
+ [CLKID_FIXPLL_IN] = &fixpll_in.hw,
+ [CLKID_USB_PHY_IN] = &usb_phy_in.hw,
+ [CLKID_USB_CTRL_IN] = &usb_ctrl_in.hw,
+ [CLKID_HIFIPLL_IN] = &hifipll_in.hw,
+ [CLKID_SYSPLL_IN] = &syspll_in.hw,
+ [CLKID_DDS_IN] = &dds_in.hw,
+ [CLKID_SYS] = &sys.hw,
+ [CLKID_CLKTREE] = &clktree.hw,
+ [CLKID_RESET_CTRL] = &reset_ctrl.hw,
+ [CLKID_ANALOG_CTRL] = &analog_ctrl.hw,
+ [CLKID_PWR_CTRL] = &pwr_ctrl.hw,
+ [CLKID_PAD_CTRL] = &pad_ctrl.hw,
+ [CLKID_SYS_CTRL] = &sys_ctrl.hw,
+ [CLKID_TEMP_SENSOR] = &temp_sensor.hw,
+ [CLKID_AM2AXI_DIV] = &am2axi_dev.hw,
+ [CLKID_SPICC_B] = &spicc_b.hw,
+ [CLKID_SPICC_A] = &spicc_a.hw,
+ [CLKID_MSR] = &msr.hw,
+ [CLKID_AUDIO] = &audio.hw,
+ [CLKID_JTAG_CTRL] = &jtag_ctrl.hw,
+ [CLKID_SARADC_EN] = &saradc_en.hw,
+ [CLKID_PWM_EF] = &pwm_ef.hw,
+ [CLKID_PWM_CD] = &pwm_cd.hw,
+ [CLKID_PWM_AB] = &pwm_ab.hw,
+ [CLKID_CEC] = &cec.hw,
+ [CLKID_I2C_S] = &i2c_s.hw,
+ [CLKID_IR_CTRL] = &ir_ctrl.hw,
+ [CLKID_I2C_M_D] = &i2c_m_d.hw,
+ [CLKID_I2C_M_C] = &i2c_m_c.hw,
+ [CLKID_I2C_M_B] = &i2c_m_b.hw,
+ [CLKID_I2C_M_A] = &i2c_m_a.hw,
+ [CLKID_ACODEC] = &acodec.hw,
+ [CLKID_OTP] = &otp.hw,
+ [CLKID_SD_EMMC_A] = &sd_emmc_a.hw,
+ [CLKID_USB_PHY] = &usb_phy.hw,
+ [CLKID_USB_CTRL] = &usb_ctrl.hw,
+ [CLKID_SYS_DSPB] = &sys_dspb.hw,
+ [CLKID_SYS_DSPA] = &sys_dspa.hw,
+ [CLKID_DMA] = &dma.hw,
+ [CLKID_IRQ_CTRL] = &irq_ctrl.hw,
+ [CLKID_NIC] = &nic.hw,
+ [CLKID_GIC] = &gic.hw,
+ [CLKID_UART_C] = &uart_c.hw,
+ [CLKID_UART_B] = &uart_b.hw,
+ [CLKID_UART_A] = &uart_a.hw,
+ [CLKID_SYS_PSRAM] = &sys_psram.hw,
+ [CLKID_RSA] = &rsa.hw,
+ [CLKID_CORESIGHT] = &coresight.hw,
+ [CLKID_AM2AXI_VAD] = &am2axi_vad.hw,
+ [CLKID_AUDIO_VAD] = &audio_vad.hw,
+ [CLKID_AXI_DMC] = &axi_dmc.hw,
+ [CLKID_AXI_PSRAM] = &axi_psram.hw,
+ [CLKID_RAMB] = &ramb.hw,
+ [CLKID_RAMA] = &rama.hw,
+ [CLKID_AXI_SPIFC] = &axi_spifc.hw,
+ [CLKID_AXI_NIC] = &axi_nic.hw,
+ [CLKID_AXI_DMA] = &axi_dma.hw,
+ [CLKID_CPU_CTRL] = &cpu_ctrl.hw,
+ [CLKID_ROM] = &rom.hw,
+ [CLKID_PROC_I2C] = &prod_i2c.hw,
+ [CLKID_DSPA_SEL] = &dspa_sel.hw,
+ [CLKID_DSPB_SEL] = &dspb_sel.hw,
+ [CLKID_DSPA_EN] = &dspa_en.hw,
+ [CLKID_DSPA_EN_NIC] = &dspa_en_nic.hw,
+ [CLKID_DSPB_EN] = &dspb_en.hw,
+ [CLKID_DSPB_EN_NIC] = &dspb_en_nic.hw,
+ [CLKID_RTC] = &rtc.hw,
+ [CLKID_CECA_32K] = &ceca_32k_out.hw,
+ [CLKID_CECB_32K] = &cecb_32k_out.hw,
+ [CLKID_24M] = &clk_24m.hw,
+ [CLKID_12M] = &clk_12m.hw,
+ [CLKID_FCLK_DIV2_DIVN] = &fclk_div2_divn.hw,
+ [CLKID_GEN] = &gen.hw,
+ [CLKID_SARADC_SEL] = &saradc_sel.hw,
+ [CLKID_SARADC] = &saradc.hw,
+ [CLKID_PWM_A] = &pwm_a.hw,
+ [CLKID_PWM_B] = &pwm_b.hw,
+ [CLKID_PWM_C] = &pwm_c.hw,
+ [CLKID_PWM_D] = &pwm_d.hw,
+ [CLKID_PWM_E] = &pwm_e.hw,
+ [CLKID_PWM_F] = &pwm_f.hw,
+ [CLKID_SPICC] = &spicc.hw,
+ [CLKID_TS] = &ts.hw,
+ [CLKID_SPIFC] = &spifc.hw,
+ [CLKID_USB_BUS] = &usb_bus.hw,
+ [CLKID_SD_EMMC] = &sd_emmc.hw,
+ [CLKID_PSRAM] = &psram.hw,
+ [CLKID_DMC] = &dmc.hw,
+ [CLKID_SYS_A_SEL] = &sys_a_sel.hw,
+ [CLKID_SYS_A_DIV] = &sys_a_div.hw,
+ [CLKID_SYS_A] = &sys_a.hw,
+ [CLKID_SYS_B_SEL] = &sys_b_sel.hw,
+ [CLKID_SYS_B_DIV] = &sys_b_div.hw,
+ [CLKID_SYS_B] = &sys_b.hw,
+ [CLKID_DSPA_A_SEL] = &dspa_a_sel.hw,
+ [CLKID_DSPA_A_DIV] = &dspa_a_div.hw,
+ [CLKID_DSPA_A] = &dspa_a.hw,
+ [CLKID_DSPA_B_SEL] = &dspa_b_sel.hw,
+ [CLKID_DSPA_B_DIV] = &dspa_b_div.hw,
+ [CLKID_DSPA_B] = &dspa_b.hw,
+ [CLKID_DSPB_A_SEL] = &dspb_a_sel.hw,
+ [CLKID_DSPB_A_DIV] = &dspb_a_div.hw,
+ [CLKID_DSPB_A] = &dspb_a.hw,
+ [CLKID_DSPB_B_SEL] = &dspb_b_sel.hw,
+ [CLKID_DSPB_B_DIV] = &dspb_b_div.hw,
+ [CLKID_DSPB_B] = &dspb_b.hw,
+ [CLKID_RTC_32K_IN] = &rtc_32k_in.hw,
+ [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw,
+ [CLKID_RTC_32K_XTAL] = &rtc_32k_xtal.hw,
+ [CLKID_RTC_32K_SEL] = &rtc_32k_sel.hw,
+ [CLKID_CECB_32K_IN] = &cecb_32k_in.hw,
+ [CLKID_CECB_32K_DIV] = &cecb_32k_div.hw,
+ [CLKID_CECB_32K_SEL_PRE] = &cecb_32k_sel_pre.hw,
+ [CLKID_CECB_32K_SEL] = &cecb_32k_sel.hw,
+ [CLKID_CECA_32K_IN] = &ceca_32k_in.hw,
+ [CLKID_CECA_32K_DIV] = &ceca_32k_div.hw,
+ [CLKID_CECA_32K_SEL_PRE] = &ceca_32k_sel_pre.hw,
+ [CLKID_CECA_32K_SEL] = &ceca_32k_sel.hw,
+ [CLKID_DIV2_PRE] = &fclk_div2_divn_pre.hw,
+ [CLKID_24M_DIV2] = &clk_24m_div2.hw,
+ [CLKID_GEN_SEL] = &gen_sel.hw,
+ [CLKID_GEN_DIV] = &gen_div.hw,
+ [CLKID_SARADC_DIV] = &saradc_div.hw,
+ [CLKID_PWM_A_SEL] = &pwm_a_sel.hw,
+ [CLKID_PWM_A_DIV] = &pwm_a_div.hw,
+ [CLKID_PWM_B_SEL] = &pwm_b_sel.hw,
+ [CLKID_PWM_B_DIV] = &pwm_b_div.hw,
+ [CLKID_PWM_C_SEL] = &pwm_c_sel.hw,
+ [CLKID_PWM_C_DIV] = &pwm_c_div.hw,
+ [CLKID_PWM_D_SEL] = &pwm_d_sel.hw,
+ [CLKID_PWM_D_DIV] = &pwm_d_div.hw,
+ [CLKID_PWM_E_SEL] = &pwm_e_sel.hw,
+ [CLKID_PWM_E_DIV] = &pwm_e_div.hw,
+ [CLKID_PWM_F_SEL] = &pwm_f_sel.hw,
+ [CLKID_PWM_F_DIV] = &pwm_f_div.hw,
+ [CLKID_SPICC_SEL] = &spicc_sel.hw,
+ [CLKID_SPICC_DIV] = &spicc_div.hw,
+ [CLKID_SPICC_SEL2] = &spicc_sel2.hw,
+ [CLKID_TS_DIV] = &ts_div.hw,
+ [CLKID_SPIFC_SEL] = &spifc_sel.hw,
+ [CLKID_SPIFC_DIV] = &spifc_div.hw,
+ [CLKID_SPIFC_SEL2] = &spifc_sel2.hw,
+ [CLKID_USB_BUS_SEL] = &usb_bus_sel.hw,
+ [CLKID_USB_BUS_DIV] = &usb_bus_div.hw,
+ [CLKID_SD_EMMC_SEL] = &sd_emmc_sel.hw,
+ [CLKID_SD_EMMC_DIV] = &sd_emmc_div.hw,
+ [CLKID_SD_EMMC_SEL2] = &sd_emmc_sel2.hw,
+ [CLKID_PSRAM_SEL] = &psram_sel.hw,
+ [CLKID_PSRAM_DIV] = &psram_div.hw,
+ [CLKID_PSRAM_SEL2] = &psram_sel2.hw,
+ [CLKID_DMC_SEL] = &dmc_sel.hw,
+ [CLKID_DMC_DIV] = &dmc_div.hw,
+ [CLKID_DMC_SEL2] = &dmc_sel2.hw,
+ [NR_CLKS] = NULL,
+ },
+ .num = NR_CLKS,
+};
+
+/* Convenience table to populate regmap in .probe */
+static struct clk_regmap *const a1_periphs_regmaps[] = {
+ &xtal_in,
+ &fixpll_in,
+ &usb_phy_in,
+ &usb_ctrl_in,
+ &hifipll_in,
+ &syspll_in,
+ &dds_in,
+ &sys,
+ &clktree,
+ &reset_ctrl,
+ &analog_ctrl,
+ &pwr_ctrl,
+ &pad_ctrl,
+ &sys_ctrl,
+ &temp_sensor,
+ &am2axi_dev,
+ &spicc_b,
+ &spicc_a,
+ &msr,
+ &audio,
+ &jtag_ctrl,
+ &saradc_en,
+ &pwm_ef,
+ &pwm_cd,
+ &pwm_ab,
+ &cec,
+ &i2c_s,
+ &ir_ctrl,
+ &i2c_m_d,
+ &i2c_m_c,
+ &i2c_m_b,
+ &i2c_m_a,
+ &acodec,
+ &otp,
+ &sd_emmc_a,
+ &usb_phy,
+ &usb_ctrl,
+ &sys_dspb,
+ &sys_dspa,
+ &dma,
+ &irq_ctrl,
+ &nic,
+ &gic,
+ &uart_c,
+ &uart_b,
+ &uart_a,
+ &sys_psram,
+ &rsa,
+ &coresight,
+ &am2axi_vad,
+ &audio_vad,
+ &axi_dmc,
+ &axi_psram,
+ &ramb,
+ &rama,
+ &axi_spifc,
+ &axi_nic,
+ &axi_dma,
+ &cpu_ctrl,
+ &rom,
+ &prod_i2c,
+ &dspa_sel,
+ &dspb_sel,
+ &dspa_en,
+ &dspa_en_nic,
+ &dspb_en,
+ &dspb_en_nic,
+ &rtc,
+ &ceca_32k_out,
+ &cecb_32k_out,
+ &clk_24m,
+ &clk_12m,
+ &fclk_div2_divn,
+ &gen,
+ &saradc_sel,
+ &saradc,
+ &pwm_a,
+ &pwm_b,
+ &pwm_c,
+ &pwm_d,
+ &pwm_e,
+ &pwm_f,
+ &spicc,
+ &ts,
+ &spifc,
+ &usb_bus,
+ &sd_emmc,
+ &psram,
+ &dmc,
+ &sys_a_sel,
+ &sys_a_div,
+ &sys_a,
+ &sys_b_sel,
+ &sys_b_div,
+ &sys_b,
+ &dspa_a_sel,
+ &dspa_a_div,
+ &dspa_a,
+ &dspa_b_sel,
+ &dspa_b_div,
+ &dspa_b,
+ &dspb_a_sel,
+ &dspb_a_div,
+ &dspb_a,
+ &dspb_b_sel,
+ &dspb_b_div,
+ &dspb_b,
+ &rtc_32k_in,
+ &rtc_32k_div,
+ &rtc_32k_xtal,
+ &rtc_32k_sel,
+ &cecb_32k_in,
+ &cecb_32k_div,
+ &cecb_32k_sel_pre,
+ &cecb_32k_sel,
+ &ceca_32k_in,
+ &ceca_32k_div,
+ &ceca_32k_sel_pre,
+ &ceca_32k_sel,
+ &fclk_div2_divn_pre,
+ &gen_sel,
+ &gen_div,
+ &saradc_div,
+ &pwm_a_sel,
+ &pwm_a_div,
+ &pwm_b_sel,
+ &pwm_b_div,
+ &pwm_c_sel,
+ &pwm_c_div,
+ &pwm_d_sel,
+ &pwm_d_div,
+ &pwm_e_sel,
+ &pwm_e_div,
+ &pwm_f_sel,
+ &pwm_f_div,
+ &spicc_sel,
+ &spicc_div,
+ &spicc_sel2,
+ &ts_div,
+ &spifc_sel,
+ &spifc_div,
+ &spifc_sel2,
+ &usb_bus_sel,
+ &usb_bus_div,
+ &sd_emmc_sel,
+ &sd_emmc_div,
+ &sd_emmc_sel2,
+ &psram_sel,
+ &psram_div,
+ &psram_sel2,
+ &dmc_sel,
+ &dmc_div,
+ &dmc_sel2,
+};
+
+static struct regmap_config a1_periphs_regmap_cfg = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int meson_a1_periphs_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct clk_hw *hw;
+ 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_periphs_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_periphs_regmaps); i++)
+ a1_periphs_regmaps[i]->map = map;
+
+ for (clkid = 0; clkid < a1_periphs_hw_onecell_data.num; clkid++) {
+ hw = a1_periphs_hw_onecell_data.hws[clkid];
+ err = devm_clk_hw_register(dev, hw);
+ if (err)
+ return dev_err_probe(dev, err,
+ "clock registration failed\n");
+ }
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
+ &a1_periphs_hw_onecell_data);
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id a1_periphs_clkc_match_table[] = {
+ { .compatible = "amlogic,a1-clkc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, a1_periphs_clkc_match_table);
+#endif /* CONFIG_OF */
+
+static struct platform_driver a1_periphs_clkc_driver = {
+ .probe = meson_a1_periphs_probe,
+ .driver = {
+ .name = "a1-clkc",
+ .of_match_table = of_match_ptr(a1_periphs_clkc_match_table),
+ },
+};
+
+module_platform_driver(a1_periphs_clkc_driver);
+MODULE_AUTHOR("Jian Hu <[email protected]>");
+MODULE_AUTHOR("Dmitry Rokosov <[email protected]>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
new file mode 100644
index 000000000000..e0e28542c9b2
--- /dev/null
+++ b/drivers/clk/meson/a1.h
@@ -0,0 +1,116 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Amlogic Meson-A1 Peripheral Clock Controller internals
+ *
+ * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
+ * Author: Jian Hu <[email protected]>
+ *
+ * Copyright (c) 2023, SberDevices. All Rights Reserved.
+ * Author: Dmitry Rokosov <[email protected]>
+ */
+
+#ifndef __A1_H
+#define __A1_H
+
+/* peripheral clock controller register offset */
+#define SYS_OSCIN_CTRL 0x0
+#define RTC_BY_OSCIN_CTRL0 0x4
+#define RTC_BY_OSCIN_CTRL1 0x8
+#define RTC_CTRL 0xc
+#define SYS_CLK_CTRL0 0x10
+#define SYS_CLK_EN0 0x1c
+#define SYS_CLK_EN1 0x20
+#define AXI_CLK_EN 0x24
+#define DSPA_CLK_EN 0x28
+#define DSPB_CLK_EN 0x2c
+#define DSPA_CLK_CTRL0 0x30
+#define DSPB_CLK_CTRL0 0x34
+#define CLK12_24_CTRL 0x38
+#define GEN_CLK_CTRL 0x3c
+#define SAR_ADC_CLK_CTRL 0xc0
+#define PWM_CLK_AB_CTRL 0xc4
+#define PWM_CLK_CD_CTRL 0xc8
+#define PWM_CLK_EF_CTRL 0xcc
+#define SPICC_CLK_CTRL 0xd0
+#define TS_CLK_CTRL 0xd4
+#define SPIFC_CLK_CTRL 0xd8
+#define USB_BUSCLK_CTRL 0xdc
+#define SD_EMMC_CLK_CTRL 0xe0
+#define CECA_CLK_CTRL0 0xe4
+#define CECA_CLK_CTRL1 0xe8
+#define CECB_CLK_CTRL0 0xec
+#define CECB_CLK_CTRL1 0xf0
+#define PSRAM_CLK_CTRL 0xf4
+#define DMC_CLK_CTRL 0xf8
+
+#define CLKID_XTAL_IN 0
+#define CLKID_SYS_A_SEL 89
+#define CLKID_SYS_A_DIV 90
+#define CLKID_SYS_A 91
+#define CLKID_SYS_B_SEL 92
+#define CLKID_SYS_B_DIV 93
+#define CLKID_SYS_B 94
+#define CLKID_DSPA_A_SEL 95
+#define CLKID_DSPA_A_DIV 96
+#define CLKID_DSPA_A 97
+#define CLKID_DSPA_B_SEL 98
+#define CLKID_DSPA_B_DIV 99
+#define CLKID_DSPA_B 100
+#define CLKID_DSPB_A_SEL 101
+#define CLKID_DSPB_A_DIV 102
+#define CLKID_DSPB_A 103
+#define CLKID_DSPB_B_SEL 104
+#define CLKID_DSPB_B_DIV 105
+#define CLKID_DSPB_B 106
+#define CLKID_RTC_32K_IN 107
+#define CLKID_RTC_32K_DIV 108
+#define CLKID_RTC_32K_XTAL 109
+#define CLKID_RTC_32K_SEL 110
+#define CLKID_CECB_32K_IN 111
+#define CLKID_CECB_32K_DIV 112
+#define CLKID_CECB_32K_SEL_PRE 113
+#define CLKID_CECB_32K_SEL 114
+#define CLKID_CECA_32K_IN 115
+#define CLKID_CECA_32K_DIV 116
+#define CLKID_CECA_32K_SEL_PRE 117
+#define CLKID_CECA_32K_SEL 118
+#define CLKID_DIV2_PRE 119
+#define CLKID_24M_DIV2 120
+#define CLKID_GEN_SEL 121
+#define CLKID_GEN_DIV 122
+#define CLKID_SARADC_DIV 123
+#define CLKID_PWM_A_SEL 124
+#define CLKID_PWM_A_DIV 125
+#define CLKID_PWM_B_SEL 126
+#define CLKID_PWM_B_DIV 127
+#define CLKID_PWM_C_SEL 128
+#define CLKID_PWM_C_DIV 129
+#define CLKID_PWM_D_SEL 130
+#define CLKID_PWM_D_DIV 131
+#define CLKID_PWM_E_SEL 132
+#define CLKID_PWM_E_DIV 133
+#define CLKID_PWM_F_SEL 134
+#define CLKID_PWM_F_DIV 135
+#define CLKID_SPICC_SEL 136
+#define CLKID_SPICC_DIV 137
+#define CLKID_SPICC_SEL2 138
+#define CLKID_TS_DIV 139
+#define CLKID_SPIFC_SEL 140
+#define CLKID_SPIFC_DIV 141
+#define CLKID_SPIFC_SEL2 142
+#define CLKID_USB_BUS_SEL 143
+#define CLKID_USB_BUS_DIV 144
+#define CLKID_SD_EMMC_SEL 145
+#define CLKID_SD_EMMC_DIV 146
+#define CLKID_SD_EMMC_SEL2 147
+#define CLKID_PSRAM_SEL 148
+#define CLKID_PSRAM_DIV 149
+#define CLKID_PSRAM_SEL2 150
+#define CLKID_DMC_SEL 151
+#define CLKID_DMC_DIV 152
+#define CLKID_DMC_SEL2 153
+#define NR_CLKS 154
+
+#include <dt-bindings/clock/a1-clkc.h>
+
+#endif /* __A1_H */
--
2.36.0


2023-03-01 19:47:55

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings


On Wed, 01 Mar 2023 21:37:57 +0300, Dmitry Rokosov wrote:
> Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
> clock controller bindings.
> Also include new A1 clock controller dt bindings to MAINTAINERS.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> .../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +++++++++++++++++++
> MAINTAINERS | 1 +
> include/dt-bindings/clock/a1-pll-clkc.h | 20 +++++++
> 3 files changed, 80 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.example.dts:18:18: fatal error: dt-bindings/clock/a1-clkc.h: No such file or directory
18 | #include <dt-bindings/clock/a1-clkc.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.lib:434: Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.example.dtb] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1508: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


2023-03-01 19:48:03

by Rob Herring (Arm)

[permalink] [raw]
Subject: Re: [PATCH v9 5/5] dt-bindings: clock: meson: add A1 Peripherals clock controller bindings


On Wed, 01 Mar 2023 21:37:59 +0300, Dmitry Rokosov wrote:
> Add the documentation for Amlogic A1 Peripherals clock driver,
> and A1 Peripherals clock controller bindings.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> .../bindings/clock/amlogic,a1-clkc.yaml | 73 +++++++++++++
> include/dt-bindings/clock/a1-clkc.h | 102 ++++++++++++++++++
> 2 files changed, 175 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> create mode 100644 include/dt-bindings/clock/a1-clkc.h
>

My bot found errors running 'make DT_CHECKER_FLAGS=-m dt_binding_check'
on your patch (DT_CHECKER_FLAGS is new in v5.13):

yamllint warnings/errors:

dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/clock/amlogic,a1-clkc.example.dts:18:18: fatal error: dt-bindings/clock/a1-pll-clkc.h: No such file or directory
18 | #include <dt-bindings/clock/a1-pll-clkc.h>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make[1]: *** [scripts/Makefile.lib:434: Documentation/devicetree/bindings/clock/amlogic,a1-clkc.example.dtb] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:1508: dt_binding_check] Error 2

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/[email protected]

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


2023-03-02 10:04:29

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver

Hi Dmitry,

I love your patch! Yet something to improve:

[auto build test ERROR on clk/clk-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Dmitry-Rokosov/clk-meson-add-support-for-A1-PLL-clock-ops/20230302-024110
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
patch link: https://lore.kernel.org/r/20230301183759.16163-3-ddrokosov%40sberdevices.ru
patch subject: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver
config: arm64-allyesconfig (https://download.01.org/0day-ci/archive/20230302/[email protected]/config)
compiler: aarch64-linux-gcc (GCC) 12.1.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/7f065968cd67b07045e9dda1d9b8fabb06f2100d
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Dmitry-Rokosov/clk-meson-add-support-for-A1-PLL-clock-ops/20230302-024110
git checkout 7f065968cd67b07045e9dda1d9b8fabb06f2100d
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm64 olddefconfig
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <[email protected]>
| Link: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/clk/meson/a1-pll.c:13:10: fatal error: meson-a1-clkc.h: No such file or directory
13 | #include "meson-a1-clkc.h"
| ^~~~~~~~~~~~~~~~~
compilation terminated.


vim +13 drivers/clk/meson/a1-pll.c

> 13 #include "meson-a1-clkc.h"
14 #include "a1-pll.h"
15 #include "clk-regmap.h"
16

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests

2023-03-03 08:28:54

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings

On 01/03/2023 19:37, Dmitry Rokosov wrote:
> Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
> clock controller bindings.
> Also include new A1 clock controller dt bindings to MAINTAINERS.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> .../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +++++++++++++++++++
> MAINTAINERS | 1 +
> include/dt-bindings/clock/a1-pll-clkc.h | 20 +++++++
> 3 files changed, 80 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> new file mode 100644
> index 000000000000..8bd2c948df86
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/amlogic,a1-pll-clkc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic Meson A/C serials PLL Clock Control Unit
> +
> +maintainers:
> + - Neil Armstrong <[email protected]>
> + - Jerome Brunet <[email protected]>
> + - Jian Hu <[email protected]>
> + - Dmitry Rokosov <[email protected]>
> +
> +properties:
> + compatible:
> + const: amlogic,a1-pll-clkc
> +
> + '#clock-cells':
> + const: 1
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: input fixpll_in
> + - description: input hifipll_in
> +
> + clock-names:
> + items:
> + - const: fixpll_in
> + - const: hifipll_in
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - clocks
> + - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/a1-clkc.h>

Does not look like you tested the bindings. Please run `make
dt_binding_check` (see
Documentation/devicetree/bindings/writing-schema.rst for instructions).

> + apb {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + clock-controller@7c80 {
> + compatible = "amlogic,a1-pll-clkc";
> + reg = <0 0x7c80 0 0x18c>;
> + #clock-cells = <1>;
> + clocks = <&clkc_periphs CLKID_FIXPLL_IN>,
> + <&clkc_periphs CLKID_HIFIPLL_IN>;
> + clock-names = "fixpll_in", "hifipll_in";
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 39ff1a717625..8438bc9bd636 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1895,6 +1895,7 @@ L: [email protected]
> S: Maintained
> F: Documentation/devicetree/bindings/clock/amlogic*
> F: drivers/clk/meson/
> +F: include/dt-bindings/clock/a1*
> F: include/dt-bindings/clock/gxbb*
> F: include/dt-bindings/clock/meson*
>
> diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h

Filename matching bindings, so amlogic,a1-pll-clkc.h

> new file mode 100644
> index 000000000000..3a559518c6e6
> --- /dev/null
> +++ b/include/dt-bindings/clock/a1-pll-clkc.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */

Any particular reason for using license other than in binding? Was it
intentional (e.g. because it is derivative work)?

> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>


Best regards,
Krzysztof


2023-03-03 08:30:17

by Krzysztof Kozlowski

[permalink] [raw]
Subject: Re: [PATCH v9 5/5] dt-bindings: clock: meson: add A1 Peripherals clock controller bindings

On 01/03/2023 19:37, Dmitry Rokosov wrote:
> Add the documentation for Amlogic A1 Peripherals clock driver,
> and A1 Peripherals clock controller bindings.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> .../bindings/clock/amlogic,a1-clkc.yaml | 73 +++++++++++++
> include/dt-bindings/clock/a1-clkc.h | 102 ++++++++++++++++++
> 2 files changed, 175 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> create mode 100644 include/dt-bindings/clock/a1-clkc.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> new file mode 100644
> index 000000000000..3dc86e912dea
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> @@ -0,0 +1,73 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/amlogic,a1-clkc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic Meson A/C serials Peripheral Clock Control Unit
> +
> +maintainers:
> + - Neil Armstrong <[email protected]>
> + - Jerome Brunet <[email protected]>
> + - Jian Hu <[email protected]>
> + - Dmitry Rokosov <[email protected]>
> +
> +properties:
> + compatible:
> + const: amlogic,a1-clkc
> +
> + '#clock-cells':
> + const: 1
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: input fixed pll div2
> + - description: input fixed pll div3
> + - description: input fixed pll div5
> + - description: input fixed pll div7
> + - description: input hifi pll
> + - description: input oscillator (usually at 24MHz)
> +
> + clock-names:
> + items:
> + - const: fclk_div2
> + - const: fclk_div3
> + - const: fclk_div5
> + - const: fclk_div7
> + - const: hifi_pll
> + - const: xtal
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - clocks
> + - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/a1-pll-clkc.h>

Eh, this explains bisectability problem.

Please do not sent patchets which are not bisectable. You can hard-code
the IDs in the example, they don't really matter.

> + apb {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + clock-controller@800 {
> + compatible = "amlogic,a1-clkc";
> + reg = <0 0x800 0 0x104>;
> + #clock-cells = <1>;
> + clocks = <&clkc_pll CLKID_FCLK_DIV2>,
> + <&clkc_pll CLKID_FCLK_DIV3>,
> + <&clkc_pll CLKID_FCLK_DIV5>,
> + <&clkc_pll CLKID_FCLK_DIV7>,
> + <&clkc_pll CLKID_HIFI_PLL>,
> + <&xtal>;
> + clock-names = "fclk_div2", "fclk_div3",
> + "fclk_div5", "fclk_div7",
> + "hifi_pll", "xtal";
> + };
> + };
> diff --git a/include/dt-bindings/clock/a1-clkc.h b/include/dt-bindings/clock/a1-clkc.h

Same comment for filename as for previous patch.



Best regards,
Krzysztof


2023-03-03 09:11:50

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings

Hello Krzysztof,

Thank you for quick review!

On Fri, Mar 03, 2023 at 09:28:22AM +0100, Krzysztof Kozlowski wrote:
> On 01/03/2023 19:37, Dmitry Rokosov wrote:
> > Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
> > clock controller bindings.
> > Also include new A1 clock controller dt bindings to MAINTAINERS.
> >
> > Signed-off-by: Jian Hu <[email protected]>
> > Signed-off-by: Dmitry Rokosov <[email protected]>
> > ---
> > .../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +++++++++++++++++++
> > MAINTAINERS | 1 +
> > include/dt-bindings/clock/a1-pll-clkc.h | 20 +++++++
> > 3 files changed, 80 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> > create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
> >

[...]

> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/clock/a1-clkc.h>
>
> Does not look like you tested the bindings. Please run `make
> dt_binding_check` (see
> Documentation/devicetree/bindings/writing-schema.rst for instructions).
>

I always run dt binding tests before sending the patch series.
It's 'must have' prerequisite along with checkpatch.

The first one (dt_binding_check):
$ make ARCH=arm64 INSTALL_MOD_PATH=${INSTALL_MOD_PATH} \
CROSS_COMPILE="${CROSS_COMPILE}" DEPMOD=${DEPMOD}
INSTALL_MOD_STRIP=1 -C ${KERNEL_PATH} \
dt_binding_check DT_SCHEMA_FILES=${DT_SCHEMA_PATH}

The second one (dtbs_check):
$ make ARCH=arm64 INSTALL_MOD_PATH=${INSTALL_MOD_PATH} \
CROSS_COMPILE="${CROSS_COMPILE}" DEPMOD=${DEPMOD} \
INSTALL_MOD_STRIP=1 -C ${KERNEL_PATH} \
dtbs_check DT_SCHEMA_FILES=${DT_SCHEMA_PATH}

But, as you mentioned in the another patchset, I didn't take into account
bisectability. In other words, I didn't execute above sanity check on the
each patchset.
Thank you for good catch, I'll fix it in the today v10 patch series.

> > + apb {
> > + #address-cells = <2>;
> > + #size-cells = <2>;
> > +
> > + clock-controller@7c80 {
> > + compatible = "amlogic,a1-pll-clkc";
> > + reg = <0 0x7c80 0 0x18c>;
> > + #clock-cells = <1>;
> > + clocks = <&clkc_periphs CLKID_FIXPLL_IN>,
> > + <&clkc_periphs CLKID_HIFIPLL_IN>;
> > + clock-names = "fixpll_in", "hifipll_in";
> > + };
> > + };
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 39ff1a717625..8438bc9bd636 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -1895,6 +1895,7 @@ L: [email protected]
> > S: Maintained
> > F: Documentation/devicetree/bindings/clock/amlogic*
> > F: drivers/clk/meson/
> > +F: include/dt-bindings/clock/a1*
> > F: include/dt-bindings/clock/gxbb*
> > F: include/dt-bindings/clock/meson*
> >
> > diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
>
> Filename matching bindings, so amlogic,a1-pll-clkc.h

You are totally right. But looks like other amlogic clock bindings don't
follow this rule.
So I'll change my patch series and send another patch series with fixup other
amlogic clock bindings.
>
> > new file mode 100644
> > index 000000000000..3a559518c6e6
> > --- /dev/null
> > +++ b/include/dt-bindings/clock/a1-pll-clkc.h
> > @@ -0,0 +1,20 @@
> > +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
>
> Any particular reason for using license other than in binding? Was it
> intentional (e.g. because it is derivative work)?
>

No reason, actually. I've just used license which was introduced in the
previous patch series versions by Jian Hu. I suppose, standard license
usage should be okay.

[...]

--
Thank you,
Dmitry

2023-03-03 09:15:02

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 5/5] dt-bindings: clock: meson: add A1 Peripherals clock controller bindings

On Fri, Mar 03, 2023 at 09:29:59AM +0100, Krzysztof Kozlowski wrote:
> On 01/03/2023 19:37, Dmitry Rokosov wrote:
> > Add the documentation for Amlogic A1 Peripherals clock driver,
> > and A1 Peripherals clock controller bindings.
> >
> > Signed-off-by: Jian Hu <[email protected]>
> > Signed-off-by: Dmitry Rokosov <[email protected]>
> > ---
> > .../bindings/clock/amlogic,a1-clkc.yaml | 73 +++++++++++++
> > include/dt-bindings/clock/a1-clkc.h | 102 ++++++++++++++++++
> > 2 files changed, 175 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> > create mode 100644 include/dt-bindings/clock/a1-clkc.h
> >
> > diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-clkc.yaml
> > new file mode 100644
> > index 000000000000..3dc86e912dea

[...]

> > +
> > +examples:
> > + - |
> > + #include <dt-bindings/clock/a1-pll-clkc.h>
>
> Eh, this explains bisectability problem.
>
> Please do not sent patchets which are not bisectable. You can hard-code
> the IDs in the example, they don't really matter.
>

Yep, my fault. As I mentioned in the other patchset, I've executed dt bindings
checkers on the total patch series, not on each patchset. Sorry for
that.

[...]

--
Thank you,
Dmitry

2023-03-06 11:31:54

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver


On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:

> Introduce PLL clock controller for Amlogic A1 SoC family.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> drivers/clk/meson/Kconfig | 10 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a1-pll.c | 365 +++++++++++++++++++++++++++++++++++++
> drivers/clk/meson/a1-pll.h | 47 +++++
> 4 files changed, 423 insertions(+)
> create mode 100644 drivers/clk/meson/a1-pll.c
> create mode 100644 drivers/clk/meson/a1-pll.h
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index fc002c155bc3..f56da2a4b000 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -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
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 6eca2a406ee3..2f17f475a48f 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -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
> diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
> new file mode 100644
> index 000000000000..c565f9b2a8dd
> --- /dev/null
> +++ b/drivers/clk/meson/a1-pll.c
> @@ -0,0 +1,365 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include "meson-a1-clkc.h"

As pointed out by the kernel robot, there is a problem here

> +#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,
> + /*
> + * It is enough that the fdiv leaf has critical flag,
> + * No critical or unused flag here.
> + */

The comment is not useful

> + },
> +};
> +
> +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 = 0x01f18440 },

This last poke should not bits otherwise handled by parms.
This is a rate init in disguise.

> +};
> +
> +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 = {

What is this ?

> + .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.
> + * About critical, refer to fclk_div2.

This last line is not useful. Same for other occurences

> + */
> + .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.
> + * About critical, refer to fclk_div2.
> + */
> + .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 provided by this provider */
> +static struct clk_hw_onecell_data a1_pll_hw_onecell_data = {
> + .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;
> + struct clk_hw *hw;
> + 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;
> +
> + for (clkid = 0; clkid < a1_pll_hw_onecell_data.num; clkid++) {
> + hw = a1_pll_hw_onecell_data.hws[clkid];
> + err = devm_clk_hw_register(dev, hw);
> + if (err)
> + return dev_err_probe(dev, err,
> + "clock registration failed\n");
> + }
> +
> + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> + &a1_pll_hw_onecell_data);
> +}
> +
> +#ifdef CONFIG_OF

This config is selected by ARM64 which this driver depends on

> +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);
> +#endif /* CONFIG_OF */
> +
> +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 <[email protected]>");
> +MODULE_AUTHOR("Dmitry Rokosov <[email protected]>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/clk/meson/a1-pll.h b/drivers/clk/meson/a1-pll.h
> new file mode 100644
> index 000000000000..de2eebce98af
> --- /dev/null
> +++ b/drivers/clk/meson/a1-pll.h
> @@ -0,0 +1,47 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Amlogic Meson-A1 PLL Clock Controller internals
> + *
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>
> + */
> +
> +#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
> +
> +/*
> + * CLKID index values
> + *
> + * 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
> +
> +/* include the CLKIDs that have been made part of the DT binding */
> +#include <dt-bindings/clock/a1-pll-clkc.h>
> +
> +#endif /* __A1_PLL_H */


2023-03-06 11:34:40

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings


On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:

> Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
> clock controller bindings.
> Also include new A1 clock controller dt bindings to MAINTAINERS.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>

patch order is wrong.
Bindings before drivers please.

> ---
> .../bindings/clock/amlogic,a1-pll-clkc.yaml | 59 +++++++++++++++++++
> MAINTAINERS | 1 +
> include/dt-bindings/clock/a1-pll-clkc.h | 20 +++++++
> 3 files changed, 80 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> create mode 100644 include/dt-bindings/clock/a1-pll-clkc.h
>
> diff --git a/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> new file mode 100644
> index 000000000000..8bd2c948df86
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/amlogic,a1-pll-clkc.yaml
> @@ -0,0 +1,59 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/amlogic,a1-pll-clkc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Amlogic Meson A/C serials PLL Clock Control Unit
> +
> +maintainers:
> + - Neil Armstrong <[email protected]>
> + - Jerome Brunet <[email protected]>
> + - Jian Hu <[email protected]>
> + - Dmitry Rokosov <[email protected]>
> +
> +properties:
> + compatible:
> + const: amlogic,a1-pll-clkc
> +
> + '#clock-cells':
> + const: 1
> +
> + reg:
> + maxItems: 1
> +
> + clocks:
> + items:
> + - description: input fixpll_in
> + - description: input hifipll_in
> +
> + clock-names:
> + items:
> + - const: fixpll_in
> + - const: hifipll_in
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - clocks
> + - clock-names
> +
> +additionalProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/a1-clkc.h>
> + apb {
> + #address-cells = <2>;
> + #size-cells = <2>;
> +
> + clock-controller@7c80 {
> + compatible = "amlogic,a1-pll-clkc";
> + reg = <0 0x7c80 0 0x18c>;
> + #clock-cells = <1>;
> + clocks = <&clkc_periphs CLKID_FIXPLL_IN>,
> + <&clkc_periphs CLKID_HIFIPLL_IN>;
> + clock-names = "fixpll_in", "hifipll_in";
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 39ff1a717625..8438bc9bd636 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1895,6 +1895,7 @@ L: [email protected]
> S: Maintained
> F: Documentation/devicetree/bindings/clock/amlogic*
> F: drivers/clk/meson/
> +F: include/dt-bindings/clock/a1*
> F: include/dt-bindings/clock/gxbb*
> F: include/dt-bindings/clock/meson*
>
> diff --git a/include/dt-bindings/clock/a1-pll-clkc.h b/include/dt-bindings/clock/a1-pll-clkc.h
> new file mode 100644
> index 000000000000..3a559518c6e6
> --- /dev/null
> +++ b/include/dt-bindings/clock/a1-pll-clkc.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>
> + */
> +
> +#ifndef __A1_PLL_CLKC_H
> +#define __A1_PLL_CLKC_H
> +
> +#define CLKID_FIXED_PLL 1
> +#define CLKID_FCLK_DIV2 6
> +#define CLKID_FCLK_DIV3 7
> +#define CLKID_FCLK_DIV5 8
> +#define CLKID_FCLK_DIV7 9
> +#define CLKID_HIFI_PLL 10
> +
> +#endif /* __A1_PLL_CLKC_H */


2023-03-06 11:48:54

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 4/5] clk: meson: a1: add Amlogic A1 Peripherals clock controller driver


On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:

> Introduce Peripherals clock controller for Amlogic A1 SoC family.
>
> Signed-off-by: Jian Hu <[email protected]>
> Signed-off-by: Dmitry Rokosov <[email protected]>
> ---
> drivers/clk/meson/Kconfig | 10 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a1.c | 2291 ++++++++++++++++++++++++++++++++++++
> drivers/clk/meson/a1.h | 116 ++
> 4 files changed, 2418 insertions(+)
> create mode 100644 drivers/clk/meson/a1.c
> create mode 100644 drivers/clk/meson/a1.h
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index f56da2a4b000..970892b07043 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -109,6 +109,16 @@ config COMMON_CLK_A1_PLL
> device, A1 SoC Family. Say Y if you want A1 PLL clock controller
> to work.
>
> +config COMMON_CLK_A1
> + tristate "Meson A1 SoC clock controller support"
> + depends on ARM64
> + select COMMON_CLK_MESON_DUALDIV
> + select COMMON_CLK_MESON_REGMAP
> + help
> + Support for the Peripherals clock controller on Amlogic A113L based
> + device, A1 SoC Family. Say Y if you want A1 Peripherals clock
> + controller to work.
> +
> config COMMON_CLK_G12A
> tristate "G12 and SM1 SoC clock controllers support"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 2f17f475a48f..0e6f293c05d4 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -17,6 +17,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_A1) += a1.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
> diff --git a/drivers/clk/meson/a1.c b/drivers/clk/meson/a1.c
> new file mode 100644
> index 000000000000..62468c49aac9
> --- /dev/null
> +++ b/drivers/clk/meson/a1.c
> @@ -0,0 +1,2291 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include "a1.h"
> +#include "clk-dualdiv.h"
> +#include "clk-regmap.h"
> +#include "meson-a1-clkc.h"
> +
> +static struct clk_regmap xtal_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 0,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "xtal_in",
> + .ops = &clk_regmap_gate_ro_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap fixpll_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 1,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "fixpll_in",
> + .ops = &clk_regmap_gate_ro_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap usb_phy_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 2,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "usb_phy_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap usb_ctrl_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 3,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "usb_ctrl_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap hifipll_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 4,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "hifipll_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap syspll_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 5,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "syspll_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap dds_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_OSCIN_CTRL,
> + .bit_idx = 6,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dds_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap rtc_32k_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = RTC_BY_OSCIN_CTRL0,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_32k_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static const struct meson_clk_dualdiv_param clk_32k_div_table[] = {
> + {
> + .dual = 1,
> + .n1 = 733,
> + .m1 = 8,
> + .n2 = 732,
> + .m2 = 11,
> + },
> + {}
> +};
> +
> +static struct clk_regmap rtc_32k_div = {
> + .data = &(struct meson_clk_dualdiv_data){
> + .n1 = {
> + .reg_off = RTC_BY_OSCIN_CTRL0,
> + .shift = 0,
> + .width = 12,
> + },
> + .n2 = {
> + .reg_off = RTC_BY_OSCIN_CTRL0,
> + .shift = 12,
> + .width = 12,
> + },
> + .m1 = {
> + .reg_off = RTC_BY_OSCIN_CTRL1,
> + .shift = 0,
> + .width = 12,
> + },
> + .m2 = {
> + .reg_off = RTC_BY_OSCIN_CTRL1,
> + .shift = 12,
> + .width = 12,
> + },
> + .dual = {
> + .reg_off = RTC_BY_OSCIN_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .table = clk_32k_div_table,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "rtc_32k_div",
> + .ops = &meson_clk_dualdiv_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_32k_in.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap rtc_32k_xtal = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = RTC_BY_OSCIN_CTRL1,
> + .bit_idx = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "rtc_32k_xtal",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_32k_in.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap rtc_32k_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = RTC_CTRL,
> + .mask = 0x3,
> + .shift = 0,
> + .flags = CLK_MUX_ROUND_CLOSEST,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "rtc_32k_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_32k_xtal.hw,
> + &rtc_32k_div.hw,
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +struct clk_regmap rtc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = RTC_BY_OSCIN_CTRL0,
> + .bit_idx = 30,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "rtc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &rtc_32k_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static u32 mux_table_sys[] = { 0, 1, 2, 3, 7 };
> +static const struct clk_parent_data sys_parents[] = {
> + { .fw_name = "xtal" },
> + { .fw_name = "fclk_div2" },
> + { .fw_name = "fclk_div3" },
> + { .fw_name = "fclk_div5" },
> + { .hw = &rtc.hw },
> +};
> +
> +static struct clk_regmap sys_b_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SYS_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 26,
> + .table = mux_table_sys,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sys_b_sel",
> + .ops = &clk_regmap_mux_ro_ops,
> + .parent_data = sys_parents,
> + .num_parents = ARRAY_SIZE(sys_parents),
> + },
> +};
> +
> +static struct clk_regmap sys_b_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SYS_CLK_CTRL0,
> + .shift = 16,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sys_b_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sys_b_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sys_b = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_CLK_CTRL0,
> + .bit_idx = 29,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sys_b",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sys_b_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sys_a_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SYS_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 10,
> + .table = mux_table_sys,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sys_a_sel",
> + .ops = &clk_regmap_mux_ro_ops,
> + .parent_data = sys_parents,
> + .num_parents = ARRAY_SIZE(sys_parents),
> + },
> +};
> +
> +static struct clk_regmap sys_a_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SYS_CLK_CTRL0,
> + .shift = 0,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sys_a_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sys_a_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sys_a = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SYS_CLK_CTRL0,
> + .bit_idx = 13,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sys_a",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sys_a_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sys = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SYS_CLK_CTRL0,
> + .mask = 0x1,
> + .shift = 31,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sys",
> + .ops = &clk_regmap_mux_ro_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sys_a.hw,
> + &sys_b.hw,
> + },
> + .num_parents = 2,
> + /*
> + * This clock is used by APB bus which is set in boot ROM code
> + * 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_SET_RATE_PARENT | CLK_IS_CRITICAL,
> + },
> +};
> +
> +static u32 mux_table_dsp_ab[] = { 0, 1, 2, 3, 4, 7 };
> +static const struct clk_parent_data dsp_ab_parent_data[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fclk_div2", },
> + { .fw_name = "fclk_div3", },
> + { .fw_name = "fclk_div5", },
> + { .fw_name = "hifi_pll", },
> + { .hw = &rtc.hw },
> +};
> +
> +static struct clk_regmap dspa_a_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPA_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 10,
> + .table = mux_table_dsp_ab,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspa_a_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dsp_ab_parent_data,
> + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> + /* DSPA_A clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_a_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = DSPA_CLK_CTRL0,
> + .shift = 0,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspa_a_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_a_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_a = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPA_CLK_CTRL0,
> + .bit_idx = 13,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_a",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_a_div.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPA_A accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader

Then IGNORE_UNUSED is wrong. use RO ops with you must retain the
bootloader config.

Note that it is usually a bad idea to depend on the bootloader config.
Things tends to go bad when other bootloader version join the fun, like
upstream u-boot

Same for the other occurences

> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspa_b_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPA_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 26,
> + .table = mux_table_dsp_ab,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspa_b_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dsp_ab_parent_data,
> + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> + /* DSPA_B clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_b_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = DSPA_CLK_CTRL0,
> + .shift = 16,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspa_b_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_b_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_b = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPA_CLK_CTRL0,
> + .bit_idx = 29,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_b",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_b_div.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPA_B accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspa_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPA_CLK_CTRL0,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspa_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_a.hw,
> + &dspa_b.hw,
> + },
> + .num_parents = 2,
> + /* DSPA clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspa_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPA_CLK_EN,
> + .bit_idx = 1,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_en",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_sel.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPA_EN accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspa_en_nic = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPA_CLK_EN,
> + .bit_idx = 0,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspa_en_nic",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspa_sel.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPA_EN_NIC accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,

All this just highlight the lack of proper drivers to handle the clock,
like remote proc one.

> + },
> +};
> +
> +static struct clk_regmap dspb_a_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPB_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 10,
> + .table = mux_table_dsp_ab,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspb_a_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dsp_ab_parent_data,
> + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> + /* DSPB_A clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspb_a_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = DSPB_CLK_CTRL0,
> + .shift = 0,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspb_a_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_a_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspb_a = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPB_CLK_CTRL0,
> + .bit_idx = 13,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspb_a",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_a_div.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPB_A accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspb_b_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPB_CLK_CTRL0,
> + .mask = 0x7,
> + .shift = 26,
> + .table = mux_table_dsp_ab,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspb_b_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = dsp_ab_parent_data,
> + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> + /* DSPB_B clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspb_b_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = DSPB_CLK_CTRL0,
> + .shift = 16,
> + .width = 10,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspb_b_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_b_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dspb_b = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPB_CLK_CTRL0,
> + .bit_idx = 29,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspb_b",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_b_div.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPB_B accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspb_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DSPB_CLK_CTRL0,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dspb_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_a.hw,
> + &dspb_b.hw,
> + },
> + .num_parents = 2,
> + /* DSPB clk parent should be set statically from dt */
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap dspb_en = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPB_CLK_EN,
> + .bit_idx = 1,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspb_en",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_sel.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPB_EN accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap dspb_en_nic = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DSPB_CLK_EN,
> + .bit_idx = 0,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dspb_en_nic",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dspb_sel.hw
> + },
> + .num_parents = 1,
> + /*
> + * DSPB_EN_NIC accelerator clk, cannot be disabled by CCF if it
> + * has been set by bootloader
> + */
> + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> + },
> +};
> +
> +static struct clk_regmap clk_24m = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CLK12_24_CTRL,
> + .bit_idx = 11,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "24m",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_fixed_factor clk_24m_div2 = {
> + .mult = 1,
> + .div = 2,
> + .hw.init = &(struct clk_init_data){
> + .name = "24m_div2",
> + .ops = &clk_fixed_factor_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &clk_24m.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap clk_12m = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CLK12_24_CTRL,
> + .bit_idx = 10,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "12m",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &clk_24m_div2.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap fclk_div2_divn_pre = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = CLK12_24_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "fclk_div2_divn_pre",
> + .ops = &clk_regmap_divider_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "fclk_div2",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap fclk_div2_divn = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CLK12_24_CTRL,
> + .bit_idx = 12,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "fclk_div2_divn",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &fclk_div2_divn_pre.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +/*
> + * the index 2 is sys_pll_div16, it will be completed in the CPU clock ctrl,

I don't get this, what do you mean ?

> + * the index 4 is the clock measurement source, it relies on
> + * the clock measurement register configuration.

Obviously ... What mean here is that clock measurement is a debug
feature and should be considered

> + */
> +static u32 gen_table[] = { 0, 1, 3, 5, 6, 7, 8 };
> +static const struct clk_parent_data gen_parent_data[] = {
> + { .fw_name = "xtal", },
> + { .hw = &rtc.hw },
> + { .fw_name = "hifi_pll", },
> + { .fw_name = "fclk_div2", },
> + { .fw_name = "fclk_div3", },
> + { .fw_name = "fclk_div5", },
> + { .fw_name = "fclk_div7", },
> +};
> +
> +static struct clk_regmap gen_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = GEN_CLK_CTRL,
> + .mask = 0xf,
> + .shift = 12,
> + .table = gen_table,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "gen_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = gen_parent_data,
> + .num_parents = ARRAY_SIZE(gen_parent_data),
> + },
> +};
> +
> +static struct clk_regmap gen_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = GEN_CLK_CTRL,
> + .shift = 0,
> + .width = 11,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "gen_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &gen_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap gen = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = GEN_CLK_CTRL,
> + .bit_idx = 11,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "gen",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &gen_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap saradc_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SAR_ADC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "saradc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .fw_name = "xtal", },
> + { .hw = &sys.hw, },
> + },
> + .num_parents = 2,
> + },
> +};
> +
> +static struct clk_regmap saradc_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SAR_ADC_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "saradc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &saradc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap saradc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SAR_ADC_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "saradc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &saradc_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data pwm_abcd_parents[] = {
> + { .fw_name = "xtal", },
> + { .hw = &sys.hw },
> + { .hw = &rtc.hw },
> +};
> +
> +static struct clk_regmap pwm_a_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .mask = 0x1,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_a_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_abcd_parents,
> + .num_parents = ARRAY_SIZE(pwm_abcd_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_a_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_a_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_a_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_a = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_a",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_a_div.hw
> + },
> + .num_parents = 1,
> + /*
> + * The CPU working voltage is controlled by pwm_a
> + * in BL2 firmware. The clock is required by the platform
> + * to operate correctly. Add the CLK_IS_CRITICAL flag to
> + * avoid changing at runtime.
> + * About critical, refer to sys
> + */

PWM_A required by the BL2 ... really ? Looks really fishy to me.

Is it possible it is used by regulator instead ?

> + .flags = CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
> + },
> +};
> +
> +static struct clk_regmap pwm_b_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .mask = 0x1,
> + .shift = 25,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_b_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_abcd_parents,
> + .num_parents = ARRAY_SIZE(pwm_abcd_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_b_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .shift = 16,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_b_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_b_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_b = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_AB_CTRL,
> + .bit_idx = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_b",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_b_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_c_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .mask = 0x1,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_c_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_abcd_parents,
> + .num_parents = ARRAY_SIZE(pwm_abcd_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_c_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_c_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_c_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_c = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_c",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_c_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_d_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .mask = 0x1,
> + .shift = 25,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_d_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_abcd_parents,
> + .num_parents = ARRAY_SIZE(pwm_abcd_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_d_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .shift = 16,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_d_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_d_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_d = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_CD_CTRL,
> + .bit_idx = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_d",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_d_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data pwm_ef_parents[] = {
> + { .fw_name = "xtal", },
> + { .hw = &sys.hw },
> + { .fw_name = "fclk_div5", },
> + { .hw = &rtc.hw },
> +};
> +
> +static struct clk_regmap pwm_e_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_e_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_ef_parents,
> + .num_parents = ARRAY_SIZE(pwm_ef_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_e_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_e_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_e_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_e = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_e",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_e_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_f_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .mask = 0x3,
> + .shift = 25,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_f_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = pwm_ef_parents,
> + .num_parents = ARRAY_SIZE(pwm_ef_parents),
> + },
> +};
> +
> +static struct clk_regmap pwm_f_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .shift = 16,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "pwm_f_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_f_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap pwm_f = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PWM_CLK_EF_CTRL,
> + .bit_idx = 24,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "pwm_f",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &pwm_f_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +/*
> + * spicc clk
> + * fdiv2 |\ |\ _____
> + * ---------| |---DIV--| | | | spicc out
> + * ---------| | | |-----|GATE |---------
> + * ..... |/ | / |_____|
> + * --------------------|/
> + * 24M
> + */
> +static const struct clk_parent_data spicc_spifc_parents[] = {
> + { .fw_name = "fclk_div2"},
> + { .fw_name = "fclk_div3"},
> + { .fw_name = "fclk_div5"},
> + { .fw_name = "hifi_pll" },
> +};
> +
> +static struct clk_regmap spicc_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SPICC_CLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spicc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = spicc_spifc_parents,
> + .num_parents = ARRAY_SIZE(spicc_spifc_parents),
> + },
> +};
> +
> +static struct clk_regmap spicc_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SPICC_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spicc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spicc_sel2 = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SPICC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spicc_sel2",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &spicc_div.hw },
> + { .fw_name = "xtal", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spicc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SPICC_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spicc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spicc_sel2.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap ts_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = TS_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ts_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap ts = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = TS_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "ts",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &ts_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spifc_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SPIFC_CLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spifc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = spicc_spifc_parents,
> + .num_parents = ARRAY_SIZE(spicc_spifc_parents),
> + },
> +};
> +
> +static struct clk_regmap spifc_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SPIFC_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spifc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spifc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spifc_sel2 = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SPIFC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "spifc_sel2",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &spifc_div.hw },
> + { .fw_name = "xtal", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap spifc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SPIFC_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "spifc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &spifc_sel2.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data usb_bus_parents[] = {
> + { .fw_name = "xtal", },
> + { .hw = &sys.hw },
> + { .fw_name = "fclk_div3", },
> + { .fw_name = "fclk_div5", },
> +};
> +
> +static struct clk_regmap usb_bus_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = USB_BUSCLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "usb_bus_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = usb_bus_parents,
> + .num_parents = ARRAY_SIZE(usb_bus_parents),
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap usb_bus_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = USB_BUSCLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "usb_bus_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &usb_bus_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap usb_bus = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = USB_BUSCLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "usb_bus",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &usb_bus_div.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static const struct clk_parent_data sd_emmc_psram_dmc_parents[] = {
> + { .fw_name = "fclk_div2", },
> + { .fw_name = "fclk_div3", },
> + { .fw_name = "fclk_div5", },
> + { .fw_name = "hifi_pll", },
> +};
> +
> +static struct clk_regmap sd_emmc_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SD_EMMC_CLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sd_emmc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = sd_emmc_psram_dmc_parents,
> + .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = SD_EMMC_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sd_emmc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sd_emmc_sel2 = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = SD_EMMC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "sd_emmc_sel2",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &sd_emmc_div.hw },
> + { .fw_name = "xtal", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap sd_emmc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = SD_EMMC_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sd_emmc",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &sd_emmc_sel2.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap psram_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PSRAM_CLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "psram_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = sd_emmc_psram_dmc_parents,
> + .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
> + },
> +};
> +
> +static struct clk_regmap psram_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = PSRAM_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "psram_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &psram_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap psram_sel2 = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = PSRAM_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "psram_sel2",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &psram_div.hw },
> + { .fw_name = "xtal", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap psram = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = PSRAM_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "psram",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &psram_sel2.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dmc_sel = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DMC_CLK_CTRL,
> + .mask = 0x3,
> + .shift = 9,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dmc_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = sd_emmc_psram_dmc_parents,
> + .num_parents = ARRAY_SIZE(sd_emmc_psram_dmc_parents),
> + },
> +};
> +
> +static struct clk_regmap dmc_div = {
> + .data = &(struct clk_regmap_div_data){
> + .offset = DMC_CLK_CTRL,
> + .shift = 0,
> + .width = 8,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dmc_div",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dmc_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dmc_sel2 = {
> + .data = &(struct clk_regmap_mux_data){
> + .offset = DMC_CLK_CTRL,
> + .mask = 0x1,
> + .shift = 15,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "dmc_sel2",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &dmc_div.hw },
> + { .fw_name = "xtal", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap dmc = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = DMC_CLK_CTRL,
> + .bit_idx = 8,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "dmc",
> + .ops = &clk_regmap_gate_ro_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &dmc_sel2.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap ceca_32k_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CECA_CLK_CTRL0,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "ceca_32k_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap ceca_32k_div = {
> + .data = &(struct meson_clk_dualdiv_data){
> + .n1 = {
> + .reg_off = CECA_CLK_CTRL0,
> + .shift = 0,
> + .width = 12,
> + },
> + .n2 = {
> + .reg_off = CECA_CLK_CTRL0,
> + .shift = 12,
> + .width = 12,
> + },
> + .m1 = {
> + .reg_off = CECA_CLK_CTRL1,
> + .shift = 0,
> + .width = 12,
> + },
> + .m2 = {
> + .reg_off = CECA_CLK_CTRL1,
> + .shift = 12,
> + .width = 12,
> + },
> + .dual = {
> + .reg_off = CECA_CLK_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .table = clk_32k_div_table,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ceca_32k_div",
> + .ops = &meson_clk_dualdiv_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &ceca_32k_in.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap ceca_32k_sel_pre = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CECA_CLK_CTRL1,
> + .mask = 0x1,
> + .shift = 24,
> + .flags = CLK_MUX_ROUND_CLOSEST,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ceca_32k_sel_pre",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &ceca_32k_div.hw,
> + &ceca_32k_in.hw,
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap ceca_32k_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CECA_CLK_CTRL1,
> + .mask = 0x1,
> + .shift = 31,
> + .flags = CLK_MUX_ROUND_CLOSEST,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ceca_32k_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &ceca_32k_sel_pre.hw,
> + &rtc.hw,
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap ceca_32k_out = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CECA_CLK_CTRL0,
> + .bit_idx = 30,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ceca_32k_out",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &ceca_32k_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap cecb_32k_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CECB_CLK_CTRL0,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "cecb_32k_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap cecb_32k_div = {
> + .data = &(struct meson_clk_dualdiv_data){
> + .n1 = {
> + .reg_off = CECB_CLK_CTRL0,
> + .shift = 0,
> + .width = 12,
> + },
> + .n2 = {
> + .reg_off = CECB_CLK_CTRL0,
> + .shift = 12,
> + .width = 12,
> + },
> + .m1 = {
> + .reg_off = CECB_CLK_CTRL1,
> + .shift = 0,
> + .width = 12,
> + },
> + .m2 = {
> + .reg_off = CECB_CLK_CTRL1,
> + .shift = 12,
> + .width = 12,
> + },
> + .dual = {
> + .reg_off = CECB_CLK_CTRL0,
> + .shift = 28,
> + .width = 1,
> + },
> + .table = clk_32k_div_table,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "cecb_32k_div",
> + .ops = &meson_clk_dualdiv_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &cecb_32k_in.hw
> + },
> + .num_parents = 1,
> + },
> +};
> +
> +static struct clk_regmap cecb_32k_sel_pre = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CECB_CLK_CTRL1,
> + .mask = 0x1,
> + .shift = 24,
> + .flags = CLK_MUX_ROUND_CLOSEST,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "cecb_32k_sel_pre",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &cecb_32k_div.hw,
> + &cecb_32k_in.hw,
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap cecb_32k_sel = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = CECB_CLK_CTRL1,
> + .mask = 0x1,
> + .shift = 31,
> + .flags = CLK_MUX_ROUND_CLOSEST,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "cecb_32k_sel",
> + .ops = &clk_regmap_mux_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &cecb_32k_sel_pre.hw,
> + &rtc.hw,
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +static struct clk_regmap cecb_32k_out = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = CECB_CLK_CTRL0,
> + .bit_idx = 30,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "cecb_32k_out",
> + .ops = &clk_regmap_gate_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &cecb_32k_sel.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
> +};
> +
> +#define MESON_GATE(_name, _reg, _bit) \
> + MESON_PCLK(_name, _reg, _bit, &sys.hw)
> +
> +static MESON_GATE(clktree, SYS_CLK_EN0, 0);
> +static MESON_GATE(reset_ctrl, SYS_CLK_EN0, 1);
> +static MESON_GATE(analog_ctrl, SYS_CLK_EN0, 2);
> +static MESON_GATE(pwr_ctrl, SYS_CLK_EN0, 3);
> +static MESON_GATE(pad_ctrl, SYS_CLK_EN0, 4);
> +static MESON_GATE(sys_ctrl, SYS_CLK_EN0, 5);
> +static MESON_GATE(temp_sensor, SYS_CLK_EN0, 6);
> +static MESON_GATE(am2axi_dev, SYS_CLK_EN0, 7);
> +static MESON_GATE(spicc_b, SYS_CLK_EN0, 8);
> +static MESON_GATE(spicc_a, SYS_CLK_EN0, 9);
> +static MESON_GATE(msr, SYS_CLK_EN0, 10);
> +static MESON_GATE(audio, SYS_CLK_EN0, 11);
> +static MESON_GATE(jtag_ctrl, SYS_CLK_EN0, 12);
> +static MESON_GATE(saradc_en, SYS_CLK_EN0, 13);
> +static MESON_GATE(pwm_ef, SYS_CLK_EN0, 14);
> +static MESON_GATE(pwm_cd, SYS_CLK_EN0, 15);
> +static MESON_GATE(pwm_ab, SYS_CLK_EN0, 16);
> +static MESON_GATE(cec, SYS_CLK_EN0, 17);
> +static MESON_GATE(i2c_s, SYS_CLK_EN0, 18);
> +static MESON_GATE(ir_ctrl, SYS_CLK_EN0, 19);
> +static MESON_GATE(i2c_m_d, SYS_CLK_EN0, 20);
> +static MESON_GATE(i2c_m_c, SYS_CLK_EN0, 21);
> +static MESON_GATE(i2c_m_b, SYS_CLK_EN0, 22);
> +static MESON_GATE(i2c_m_a, SYS_CLK_EN0, 23);
> +static MESON_GATE(acodec, SYS_CLK_EN0, 24);
> +static MESON_GATE(otp, SYS_CLK_EN0, 25);
> +static MESON_GATE(sd_emmc_a, SYS_CLK_EN0, 26);
> +static MESON_GATE(usb_phy, SYS_CLK_EN0, 27);
> +static MESON_GATE(usb_ctrl, SYS_CLK_EN0, 28);
> +static MESON_GATE(sys_dspb, SYS_CLK_EN0, 29);
> +static MESON_GATE(sys_dspa, SYS_CLK_EN0, 30);
> +static MESON_GATE(dma, SYS_CLK_EN0, 31);
> +static MESON_GATE(irq_ctrl, SYS_CLK_EN1, 0);
> +static MESON_GATE(nic, SYS_CLK_EN1, 1);
> +static MESON_GATE(gic, SYS_CLK_EN1, 2);
> +static MESON_GATE(uart_c, SYS_CLK_EN1, 3);
> +static MESON_GATE(uart_b, SYS_CLK_EN1, 4);
> +static MESON_GATE(uart_a, SYS_CLK_EN1, 5);
> +static MESON_GATE(sys_psram, SYS_CLK_EN1, 6);
> +static MESON_GATE(rsa, SYS_CLK_EN1, 8);
> +static MESON_GATE(coresight, SYS_CLK_EN1, 9);
> +static MESON_GATE(am2axi_vad, AXI_CLK_EN, 0);
> +static MESON_GATE(audio_vad, AXI_CLK_EN, 1);
> +static MESON_GATE(axi_dmc, AXI_CLK_EN, 3);
> +static MESON_GATE(axi_psram, AXI_CLK_EN, 4);
> +static MESON_GATE(ramb, AXI_CLK_EN, 5);
> +static MESON_GATE(rama, AXI_CLK_EN, 6);
> +static MESON_GATE(axi_spifc, AXI_CLK_EN, 7);
> +static MESON_GATE(axi_nic, AXI_CLK_EN, 8);
> +static MESON_GATE(axi_dma, AXI_CLK_EN, 9);
> +static MESON_GATE(cpu_ctrl, AXI_CLK_EN, 10);
> +static MESON_GATE(rom, AXI_CLK_EN, 11);
> +static MESON_GATE(prod_i2c, AXI_CLK_EN, 12);
> +
> +/* Array of all clocks provided by this provider */
> +static struct clk_hw_onecell_data a1_periphs_hw_onecell_data = {
> + .hws = {
> + [CLKID_XTAL_IN] = &xtal_in.hw,
> + [CLKID_FIXPLL_IN] = &fixpll_in.hw,
> + [CLKID_USB_PHY_IN] = &usb_phy_in.hw,
> + [CLKID_USB_CTRL_IN] = &usb_ctrl_in.hw,
> + [CLKID_HIFIPLL_IN] = &hifipll_in.hw,
> + [CLKID_SYSPLL_IN] = &syspll_in.hw,
> + [CLKID_DDS_IN] = &dds_in.hw,
> + [CLKID_SYS] = &sys.hw,
> + [CLKID_CLKTREE] = &clktree.hw,
> + [CLKID_RESET_CTRL] = &reset_ctrl.hw,
> + [CLKID_ANALOG_CTRL] = &analog_ctrl.hw,
> + [CLKID_PWR_CTRL] = &pwr_ctrl.hw,
> + [CLKID_PAD_CTRL] = &pad_ctrl.hw,
> + [CLKID_SYS_CTRL] = &sys_ctrl.hw,
> + [CLKID_TEMP_SENSOR] = &temp_sensor.hw,
> + [CLKID_AM2AXI_DIV] = &am2axi_dev.hw,
> + [CLKID_SPICC_B] = &spicc_b.hw,
> + [CLKID_SPICC_A] = &spicc_a.hw,
> + [CLKID_MSR] = &msr.hw,
> + [CLKID_AUDIO] = &audio.hw,
> + [CLKID_JTAG_CTRL] = &jtag_ctrl.hw,
> + [CLKID_SARADC_EN] = &saradc_en.hw,
> + [CLKID_PWM_EF] = &pwm_ef.hw,
> + [CLKID_PWM_CD] = &pwm_cd.hw,
> + [CLKID_PWM_AB] = &pwm_ab.hw,
> + [CLKID_CEC] = &cec.hw,
> + [CLKID_I2C_S] = &i2c_s.hw,
> + [CLKID_IR_CTRL] = &ir_ctrl.hw,
> + [CLKID_I2C_M_D] = &i2c_m_d.hw,
> + [CLKID_I2C_M_C] = &i2c_m_c.hw,
> + [CLKID_I2C_M_B] = &i2c_m_b.hw,
> + [CLKID_I2C_M_A] = &i2c_m_a.hw,
> + [CLKID_ACODEC] = &acodec.hw,
> + [CLKID_OTP] = &otp.hw,
> + [CLKID_SD_EMMC_A] = &sd_emmc_a.hw,
> + [CLKID_USB_PHY] = &usb_phy.hw,
> + [CLKID_USB_CTRL] = &usb_ctrl.hw,
> + [CLKID_SYS_DSPB] = &sys_dspb.hw,
> + [CLKID_SYS_DSPA] = &sys_dspa.hw,
> + [CLKID_DMA] = &dma.hw,
> + [CLKID_IRQ_CTRL] = &irq_ctrl.hw,
> + [CLKID_NIC] = &nic.hw,
> + [CLKID_GIC] = &gic.hw,
> + [CLKID_UART_C] = &uart_c.hw,
> + [CLKID_UART_B] = &uart_b.hw,
> + [CLKID_UART_A] = &uart_a.hw,
> + [CLKID_SYS_PSRAM] = &sys_psram.hw,
> + [CLKID_RSA] = &rsa.hw,
> + [CLKID_CORESIGHT] = &coresight.hw,
> + [CLKID_AM2AXI_VAD] = &am2axi_vad.hw,
> + [CLKID_AUDIO_VAD] = &audio_vad.hw,
> + [CLKID_AXI_DMC] = &axi_dmc.hw,
> + [CLKID_AXI_PSRAM] = &axi_psram.hw,
> + [CLKID_RAMB] = &ramb.hw,
> + [CLKID_RAMA] = &rama.hw,
> + [CLKID_AXI_SPIFC] = &axi_spifc.hw,
> + [CLKID_AXI_NIC] = &axi_nic.hw,
> + [CLKID_AXI_DMA] = &axi_dma.hw,
> + [CLKID_CPU_CTRL] = &cpu_ctrl.hw,
> + [CLKID_ROM] = &rom.hw,
> + [CLKID_PROC_I2C] = &prod_i2c.hw,
> + [CLKID_DSPA_SEL] = &dspa_sel.hw,
> + [CLKID_DSPB_SEL] = &dspb_sel.hw,
> + [CLKID_DSPA_EN] = &dspa_en.hw,
> + [CLKID_DSPA_EN_NIC] = &dspa_en_nic.hw,
> + [CLKID_DSPB_EN] = &dspb_en.hw,
> + [CLKID_DSPB_EN_NIC] = &dspb_en_nic.hw,
> + [CLKID_RTC] = &rtc.hw,
> + [CLKID_CECA_32K] = &ceca_32k_out.hw,
> + [CLKID_CECB_32K] = &cecb_32k_out.hw,
> + [CLKID_24M] = &clk_24m.hw,
> + [CLKID_12M] = &clk_12m.hw,
> + [CLKID_FCLK_DIV2_DIVN] = &fclk_div2_divn.hw,
> + [CLKID_GEN] = &gen.hw,
> + [CLKID_SARADC_SEL] = &saradc_sel.hw,
> + [CLKID_SARADC] = &saradc.hw,
> + [CLKID_PWM_A] = &pwm_a.hw,
> + [CLKID_PWM_B] = &pwm_b.hw,
> + [CLKID_PWM_C] = &pwm_c.hw,
> + [CLKID_PWM_D] = &pwm_d.hw,
> + [CLKID_PWM_E] = &pwm_e.hw,
> + [CLKID_PWM_F] = &pwm_f.hw,
> + [CLKID_SPICC] = &spicc.hw,
> + [CLKID_TS] = &ts.hw,
> + [CLKID_SPIFC] = &spifc.hw,
> + [CLKID_USB_BUS] = &usb_bus.hw,
> + [CLKID_SD_EMMC] = &sd_emmc.hw,
> + [CLKID_PSRAM] = &psram.hw,
> + [CLKID_DMC] = &dmc.hw,
> + [CLKID_SYS_A_SEL] = &sys_a_sel.hw,
> + [CLKID_SYS_A_DIV] = &sys_a_div.hw,
> + [CLKID_SYS_A] = &sys_a.hw,
> + [CLKID_SYS_B_SEL] = &sys_b_sel.hw,
> + [CLKID_SYS_B_DIV] = &sys_b_div.hw,
> + [CLKID_SYS_B] = &sys_b.hw,
> + [CLKID_DSPA_A_SEL] = &dspa_a_sel.hw,
> + [CLKID_DSPA_A_DIV] = &dspa_a_div.hw,
> + [CLKID_DSPA_A] = &dspa_a.hw,
> + [CLKID_DSPA_B_SEL] = &dspa_b_sel.hw,
> + [CLKID_DSPA_B_DIV] = &dspa_b_div.hw,
> + [CLKID_DSPA_B] = &dspa_b.hw,
> + [CLKID_DSPB_A_SEL] = &dspb_a_sel.hw,
> + [CLKID_DSPB_A_DIV] = &dspb_a_div.hw,
> + [CLKID_DSPB_A] = &dspb_a.hw,
> + [CLKID_DSPB_B_SEL] = &dspb_b_sel.hw,
> + [CLKID_DSPB_B_DIV] = &dspb_b_div.hw,
> + [CLKID_DSPB_B] = &dspb_b.hw,
> + [CLKID_RTC_32K_IN] = &rtc_32k_in.hw,
> + [CLKID_RTC_32K_DIV] = &rtc_32k_div.hw,
> + [CLKID_RTC_32K_XTAL] = &rtc_32k_xtal.hw,
> + [CLKID_RTC_32K_SEL] = &rtc_32k_sel.hw,
> + [CLKID_CECB_32K_IN] = &cecb_32k_in.hw,
> + [CLKID_CECB_32K_DIV] = &cecb_32k_div.hw,
> + [CLKID_CECB_32K_SEL_PRE] = &cecb_32k_sel_pre.hw,
> + [CLKID_CECB_32K_SEL] = &cecb_32k_sel.hw,
> + [CLKID_CECA_32K_IN] = &ceca_32k_in.hw,
> + [CLKID_CECA_32K_DIV] = &ceca_32k_div.hw,
> + [CLKID_CECA_32K_SEL_PRE] = &ceca_32k_sel_pre.hw,
> + [CLKID_CECA_32K_SEL] = &ceca_32k_sel.hw,
> + [CLKID_DIV2_PRE] = &fclk_div2_divn_pre.hw,
> + [CLKID_24M_DIV2] = &clk_24m_div2.hw,
> + [CLKID_GEN_SEL] = &gen_sel.hw,
> + [CLKID_GEN_DIV] = &gen_div.hw,
> + [CLKID_SARADC_DIV] = &saradc_div.hw,
> + [CLKID_PWM_A_SEL] = &pwm_a_sel.hw,
> + [CLKID_PWM_A_DIV] = &pwm_a_div.hw,
> + [CLKID_PWM_B_SEL] = &pwm_b_sel.hw,
> + [CLKID_PWM_B_DIV] = &pwm_b_div.hw,
> + [CLKID_PWM_C_SEL] = &pwm_c_sel.hw,
> + [CLKID_PWM_C_DIV] = &pwm_c_div.hw,
> + [CLKID_PWM_D_SEL] = &pwm_d_sel.hw,
> + [CLKID_PWM_D_DIV] = &pwm_d_div.hw,
> + [CLKID_PWM_E_SEL] = &pwm_e_sel.hw,
> + [CLKID_PWM_E_DIV] = &pwm_e_div.hw,
> + [CLKID_PWM_F_SEL] = &pwm_f_sel.hw,
> + [CLKID_PWM_F_DIV] = &pwm_f_div.hw,
> + [CLKID_SPICC_SEL] = &spicc_sel.hw,
> + [CLKID_SPICC_DIV] = &spicc_div.hw,
> + [CLKID_SPICC_SEL2] = &spicc_sel2.hw,
> + [CLKID_TS_DIV] = &ts_div.hw,
> + [CLKID_SPIFC_SEL] = &spifc_sel.hw,
> + [CLKID_SPIFC_DIV] = &spifc_div.hw,
> + [CLKID_SPIFC_SEL2] = &spifc_sel2.hw,
> + [CLKID_USB_BUS_SEL] = &usb_bus_sel.hw,
> + [CLKID_USB_BUS_DIV] = &usb_bus_div.hw,
> + [CLKID_SD_EMMC_SEL] = &sd_emmc_sel.hw,
> + [CLKID_SD_EMMC_DIV] = &sd_emmc_div.hw,
> + [CLKID_SD_EMMC_SEL2] = &sd_emmc_sel2.hw,
> + [CLKID_PSRAM_SEL] = &psram_sel.hw,
> + [CLKID_PSRAM_DIV] = &psram_div.hw,
> + [CLKID_PSRAM_SEL2] = &psram_sel2.hw,
> + [CLKID_DMC_SEL] = &dmc_sel.hw,
> + [CLKID_DMC_DIV] = &dmc_div.hw,
> + [CLKID_DMC_SEL2] = &dmc_sel2.hw,
> + [NR_CLKS] = NULL,
> + },
> + .num = NR_CLKS,
> +};
> +
> +/* Convenience table to populate regmap in .probe */
> +static struct clk_regmap *const a1_periphs_regmaps[] = {
> + &xtal_in,
> + &fixpll_in,
> + &usb_phy_in,
> + &usb_ctrl_in,
> + &hifipll_in,
> + &syspll_in,
> + &dds_in,
> + &sys,
> + &clktree,
> + &reset_ctrl,
> + &analog_ctrl,
> + &pwr_ctrl,
> + &pad_ctrl,
> + &sys_ctrl,
> + &temp_sensor,
> + &am2axi_dev,
> + &spicc_b,
> + &spicc_a,
> + &msr,
> + &audio,
> + &jtag_ctrl,
> + &saradc_en,
> + &pwm_ef,
> + &pwm_cd,
> + &pwm_ab,
> + &cec,
> + &i2c_s,
> + &ir_ctrl,
> + &i2c_m_d,
> + &i2c_m_c,
> + &i2c_m_b,
> + &i2c_m_a,
> + &acodec,
> + &otp,
> + &sd_emmc_a,
> + &usb_phy,
> + &usb_ctrl,
> + &sys_dspb,
> + &sys_dspa,
> + &dma,
> + &irq_ctrl,
> + &nic,
> + &gic,
> + &uart_c,
> + &uart_b,
> + &uart_a,
> + &sys_psram,
> + &rsa,
> + &coresight,
> + &am2axi_vad,
> + &audio_vad,
> + &axi_dmc,
> + &axi_psram,
> + &ramb,
> + &rama,
> + &axi_spifc,
> + &axi_nic,
> + &axi_dma,
> + &cpu_ctrl,
> + &rom,
> + &prod_i2c,
> + &dspa_sel,
> + &dspb_sel,
> + &dspa_en,
> + &dspa_en_nic,
> + &dspb_en,
> + &dspb_en_nic,
> + &rtc,
> + &ceca_32k_out,
> + &cecb_32k_out,
> + &clk_24m,
> + &clk_12m,
> + &fclk_div2_divn,
> + &gen,
> + &saradc_sel,
> + &saradc,
> + &pwm_a,
> + &pwm_b,
> + &pwm_c,
> + &pwm_d,
> + &pwm_e,
> + &pwm_f,
> + &spicc,
> + &ts,
> + &spifc,
> + &usb_bus,
> + &sd_emmc,
> + &psram,
> + &dmc,
> + &sys_a_sel,
> + &sys_a_div,
> + &sys_a,
> + &sys_b_sel,
> + &sys_b_div,
> + &sys_b,
> + &dspa_a_sel,
> + &dspa_a_div,
> + &dspa_a,
> + &dspa_b_sel,
> + &dspa_b_div,
> + &dspa_b,
> + &dspb_a_sel,
> + &dspb_a_div,
> + &dspb_a,
> + &dspb_b_sel,
> + &dspb_b_div,
> + &dspb_b,
> + &rtc_32k_in,
> + &rtc_32k_div,
> + &rtc_32k_xtal,
> + &rtc_32k_sel,
> + &cecb_32k_in,
> + &cecb_32k_div,
> + &cecb_32k_sel_pre,
> + &cecb_32k_sel,
> + &ceca_32k_in,
> + &ceca_32k_div,
> + &ceca_32k_sel_pre,
> + &ceca_32k_sel,
> + &fclk_div2_divn_pre,
> + &gen_sel,
> + &gen_div,
> + &saradc_div,
> + &pwm_a_sel,
> + &pwm_a_div,
> + &pwm_b_sel,
> + &pwm_b_div,
> + &pwm_c_sel,
> + &pwm_c_div,
> + &pwm_d_sel,
> + &pwm_d_div,
> + &pwm_e_sel,
> + &pwm_e_div,
> + &pwm_f_sel,
> + &pwm_f_div,
> + &spicc_sel,
> + &spicc_div,
> + &spicc_sel2,
> + &ts_div,
> + &spifc_sel,
> + &spifc_div,
> + &spifc_sel2,
> + &usb_bus_sel,
> + &usb_bus_div,
> + &sd_emmc_sel,
> + &sd_emmc_div,
> + &sd_emmc_sel2,
> + &psram_sel,
> + &psram_div,
> + &psram_sel2,
> + &dmc_sel,
> + &dmc_div,
> + &dmc_sel2,
> +};
> +
> +static struct regmap_config a1_periphs_regmap_cfg = {
> + .reg_bits = 32,
> + .val_bits = 32,
> + .reg_stride = 4,
> +};
> +
> +static int meson_a1_periphs_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct clk_hw *hw;
> + 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_periphs_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_periphs_regmaps); i++)
> + a1_periphs_regmaps[i]->map = map;
> +
> + for (clkid = 0; clkid < a1_periphs_hw_onecell_data.num; clkid++) {
> + hw = a1_periphs_hw_onecell_data.hws[clkid];
> + err = devm_clk_hw_register(dev, hw);
> + if (err)
> + return dev_err_probe(dev, err,
> + "clock registration failed\n");
> + }
> +
> + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> + &a1_periphs_hw_onecell_data);
> +}
> +
> +#ifdef CONFIG_OF

Same as the PLL driver

> +static const struct of_device_id a1_periphs_clkc_match_table[] = {
> + { .compatible = "amlogic,a1-clkc", },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, a1_periphs_clkc_match_table);
> +#endif /* CONFIG_OF */
> +
> +static struct platform_driver a1_periphs_clkc_driver = {
> + .probe = meson_a1_periphs_probe,
> + .driver = {
> + .name = "a1-clkc",
> + .of_match_table = of_match_ptr(a1_periphs_clkc_match_table),
> + },
> +};
> +
> +module_platform_driver(a1_periphs_clkc_driver);
> +MODULE_AUTHOR("Jian Hu <[email protected]>");
> +MODULE_AUTHOR("Dmitry Rokosov <[email protected]>");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/clk/meson/a1.h b/drivers/clk/meson/a1.h
> new file mode 100644
> index 000000000000..e0e28542c9b2
> --- /dev/null
> +++ b/drivers/clk/meson/a1.h
> @@ -0,0 +1,116 @@
> +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
> +/*
> + * Amlogic Meson-A1 Peripheral Clock Controller internals
> + *
> + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> + * Author: Jian Hu <[email protected]>
> + *
> + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> + * Author: Dmitry Rokosov <[email protected]>
> + */
> +
> +#ifndef __A1_H
> +#define __A1_H
> +
> +/* peripheral clock controller register offset */
> +#define SYS_OSCIN_CTRL 0x0
> +#define RTC_BY_OSCIN_CTRL0 0x4
> +#define RTC_BY_OSCIN_CTRL1 0x8
> +#define RTC_CTRL 0xc
> +#define SYS_CLK_CTRL0 0x10
> +#define SYS_CLK_EN0 0x1c
> +#define SYS_CLK_EN1 0x20
> +#define AXI_CLK_EN 0x24
> +#define DSPA_CLK_EN 0x28
> +#define DSPB_CLK_EN 0x2c
> +#define DSPA_CLK_CTRL0 0x30
> +#define DSPB_CLK_CTRL0 0x34
> +#define CLK12_24_CTRL 0x38
> +#define GEN_CLK_CTRL 0x3c
> +#define SAR_ADC_CLK_CTRL 0xc0
> +#define PWM_CLK_AB_CTRL 0xc4
> +#define PWM_CLK_CD_CTRL 0xc8
> +#define PWM_CLK_EF_CTRL 0xcc
> +#define SPICC_CLK_CTRL 0xd0
> +#define TS_CLK_CTRL 0xd4
> +#define SPIFC_CLK_CTRL 0xd8
> +#define USB_BUSCLK_CTRL 0xdc
> +#define SD_EMMC_CLK_CTRL 0xe0
> +#define CECA_CLK_CTRL0 0xe4
> +#define CECA_CLK_CTRL1 0xe8
> +#define CECB_CLK_CTRL0 0xec
> +#define CECB_CLK_CTRL1 0xf0
> +#define PSRAM_CLK_CTRL 0xf4
> +#define DMC_CLK_CTRL 0xf8
> +
> +#define CLKID_XTAL_IN 0
> +#define CLKID_SYS_A_SEL 89
> +#define CLKID_SYS_A_DIV 90
> +#define CLKID_SYS_A 91
> +#define CLKID_SYS_B_SEL 92
> +#define CLKID_SYS_B_DIV 93
> +#define CLKID_SYS_B 94
> +#define CLKID_DSPA_A_SEL 95
> +#define CLKID_DSPA_A_DIV 96
> +#define CLKID_DSPA_A 97
> +#define CLKID_DSPA_B_SEL 98
> +#define CLKID_DSPA_B_DIV 99
> +#define CLKID_DSPA_B 100
> +#define CLKID_DSPB_A_SEL 101
> +#define CLKID_DSPB_A_DIV 102
> +#define CLKID_DSPB_A 103
> +#define CLKID_DSPB_B_SEL 104
> +#define CLKID_DSPB_B_DIV 105
> +#define CLKID_DSPB_B 106
> +#define CLKID_RTC_32K_IN 107
> +#define CLKID_RTC_32K_DIV 108
> +#define CLKID_RTC_32K_XTAL 109
> +#define CLKID_RTC_32K_SEL 110
> +#define CLKID_CECB_32K_IN 111
> +#define CLKID_CECB_32K_DIV 112
> +#define CLKID_CECB_32K_SEL_PRE 113
> +#define CLKID_CECB_32K_SEL 114
> +#define CLKID_CECA_32K_IN 115
> +#define CLKID_CECA_32K_DIV 116
> +#define CLKID_CECA_32K_SEL_PRE 117
> +#define CLKID_CECA_32K_SEL 118
> +#define CLKID_DIV2_PRE 119
> +#define CLKID_24M_DIV2 120
> +#define CLKID_GEN_SEL 121
> +#define CLKID_GEN_DIV 122
> +#define CLKID_SARADC_DIV 123
> +#define CLKID_PWM_A_SEL 124
> +#define CLKID_PWM_A_DIV 125
> +#define CLKID_PWM_B_SEL 126
> +#define CLKID_PWM_B_DIV 127
> +#define CLKID_PWM_C_SEL 128
> +#define CLKID_PWM_C_DIV 129
> +#define CLKID_PWM_D_SEL 130
> +#define CLKID_PWM_D_DIV 131
> +#define CLKID_PWM_E_SEL 132
> +#define CLKID_PWM_E_DIV 133
> +#define CLKID_PWM_F_SEL 134
> +#define CLKID_PWM_F_DIV 135
> +#define CLKID_SPICC_SEL 136
> +#define CLKID_SPICC_DIV 137
> +#define CLKID_SPICC_SEL2 138
> +#define CLKID_TS_DIV 139
> +#define CLKID_SPIFC_SEL 140
> +#define CLKID_SPIFC_DIV 141
> +#define CLKID_SPIFC_SEL2 142
> +#define CLKID_USB_BUS_SEL 143
> +#define CLKID_USB_BUS_DIV 144
> +#define CLKID_SD_EMMC_SEL 145
> +#define CLKID_SD_EMMC_DIV 146
> +#define CLKID_SD_EMMC_SEL2 147
> +#define CLKID_PSRAM_SEL 148
> +#define CLKID_PSRAM_DIV 149
> +#define CLKID_PSRAM_SEL2 150
> +#define CLKID_DMC_SEL 151
> +#define CLKID_DMC_DIV 152
> +#define CLKID_DMC_SEL2 153
> +#define NR_CLKS 154
> +
> +#include <dt-bindings/clock/a1-clkc.h>
> +
> +#endif /* __A1_H */


2023-03-06 19:05:48

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 4/5] clk: meson: a1: add Amlogic A1 Peripherals clock controller driver

Hello Jerome,

Thanks a lot for such detailed review. Please find my comments and
thoughts below.

On Mon, Mar 06, 2023 at 12:38:22PM +0100, Jerome Brunet wrote:
>
> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
>
> > Introduce Peripherals clock controller for Amlogic A1 SoC family.
> >
> > Signed-off-by: Jian Hu <[email protected]>
> > Signed-off-by: Dmitry Rokosov <[email protected]>

[...]

> > +static struct clk_regmap dspa_a_sel = {
> > + .data = &(struct clk_regmap_mux_data){
> > + .offset = DSPA_CLK_CTRL0,
> > + .mask = 0x7,
> > + .shift = 10,
> > + .table = mux_table_dsp_ab,
> > + },
> > + .hw.init = &(struct clk_init_data){
> > + .name = "dspa_a_sel",
> > + .ops = &clk_regmap_mux_ops,
> > + .parent_data = dsp_ab_parent_data,
> > + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> > + /* DSPA_A clk parent should be set statically from dt */
> > + .flags = CLK_SET_RATE_NO_REPARENT,
> > + },
> > +};
> > +
> > +static struct clk_regmap dspa_a_div = {
> > + .data = &(struct clk_regmap_div_data){
> > + .offset = DSPA_CLK_CTRL0,
> > + .shift = 0,
> > + .width = 10,
> > + },
> > + .hw.init = &(struct clk_init_data){
> > + .name = "dspa_a_div",
> > + .ops = &clk_regmap_divider_ops,
> > + .parent_hws = (const struct clk_hw *[]) {
> > + &dspa_a_sel.hw
> > + },
> > + .num_parents = 1,
> > + .flags = CLK_SET_RATE_PARENT,
> > + },
> > +};
> > +
> > +static struct clk_regmap dspa_a = {
> > + .data = &(struct clk_regmap_gate_data){
> > + .offset = DSPA_CLK_CTRL0,
> > + .bit_idx = 13,
> > + },
> > + .hw.init = &(struct clk_init_data) {
> > + .name = "dspa_a",
> > + .ops = &clk_regmap_gate_ops,
> > + .parent_hws = (const struct clk_hw *[]) {
> > + &dspa_a_div.hw
> > + },
> > + .num_parents = 1,
> > + /*
> > + * DSPA_A accelerator clk, cannot be disabled by CCF if it
> > + * has been set by bootloader
>
> Then IGNORE_UNUSED is wrong. use RO ops with you must retain the
> bootloader config.

I thought UNUSED logic will disable 'unused' clock during
initialization. Or do you mean it's not relevant for ro ops clock,
because disable() callback is not defined?

>
> Note that it is usually a bad idea to depend on the bootloader config.
> Things tends to go bad when other bootloader version join the fun, like
> upstream u-boot

To be honest, I don't have the ability to test such behavior on our side,
because in my hands I have SoC SKUs w/o DSP only.
But theoretically DSP FW can be started already from the bootloader, and
then we shouldn't touch this clock.
May be CCF has device tree tricks to solve such situations, don't know
actually. On the other hand, appropriate driver logic would be a nice
exit here.

[...]

> > +static struct clk_regmap dspa_en_nic = {
> > + .data = &(struct clk_regmap_gate_data){
> > + .offset = DSPA_CLK_EN,
> > + .bit_idx = 0,
> > + },
> > + .hw.init = &(struct clk_init_data) {
> > + .name = "dspa_en_nic",
> > + .ops = &clk_regmap_gate_ops,
> > + .parent_hws = (const struct clk_hw *[]) {
> > + &dspa_sel.hw
> > + },
> > + .num_parents = 1,
> > + /*
> > + * DSPA_EN_NIC accelerator clk, cannot be disabled by CCF if it
> > + * has been set by bootloader
> > + */
> > + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>
> All this just highlight the lack of proper drivers to handle the clock,
> like remote proc one.
>

Okay, let's imagine we have such a driver. If DSP is already running,
we can skip the clock setup on this driver side. Hmmm. It looks like
a proper solution...

I would prefer to tag it with TODO and mark DSP clocks with ro_ops till
we don't have such a driver.

[...]

> > +
> > +static struct clk_regmap fclk_div2_divn = {
> > + .data = &(struct clk_regmap_gate_data){
> > + .offset = CLK12_24_CTRL,
> > + .bit_idx = 12,
> > + },
> > + .hw.init = &(struct clk_init_data){
> > + .name = "fclk_div2_divn",
> > + .ops = &clk_regmap_gate_ops,
> > + .parent_hws = (const struct clk_hw *[]) {
> > + &fclk_div2_divn_pre.hw
> > + },
> > + .num_parents = 1,
> > + .flags = CLK_SET_RATE_PARENT,
> > + },
> > +};
> > +
> > +/*
> > + * the index 2 is sys_pll_div16, it will be completed in the CPU clock ctrl,
>
> I don't get this, what do you mean ?
>

I mean, it will be implemented in the CPU clock controller driver in the
next patch series. Agree, I have to make a rephrase.

> > + * the index 4 is the clock measurement source, it relies on
> > + * the clock measurement register configuration.
>
> Obviously ... What mean here is that clock measurement is a debug
> feature and should be considered
>

Should I mark it with TODO tag? I prefer to implement 'must have' logic
first. Clock measurement are optional from my point of view.

[...]

> > +static struct clk_regmap pwm_a = {
> > + .data = &(struct clk_regmap_gate_data){
> > + .offset = PWM_CLK_AB_CTRL,
> > + .bit_idx = 8,
> > + },
> > + .hw.init = &(struct clk_init_data) {
> > + .name = "pwm_a",
> > + .ops = &clk_regmap_gate_ops,
> > + .parent_hws = (const struct clk_hw *[]) {
> > + &pwm_a_div.hw
> > + },
> > + .num_parents = 1,
> > + /*
> > + * The CPU working voltage is controlled by pwm_a
> > + * in BL2 firmware. The clock is required by the platform
> > + * to operate correctly. Add the CLK_IS_CRITICAL flag to
> > + * avoid changing at runtime.
> > + * About critical, refer to sys
> > + */
>
> PWM_A required by the BL2 ... really ? Looks really fishy to me.
>
> Is it possible it is used by regulator instead ?
>

Honestly, this comment's information was grabbed from Amlogic custom
driver. It has such words:

/*
* add CLK_IGNORE_UNUSED flag for pwm controller GATE
* clk core will disable unused clock, it may disable
* vddcore voltage which contrlled by one pwm in bl21.
* add the flag to avoid changing cpu voltage.
*/

We don't have bl21 source code in the hands, so I can't check
unfortunately. But I have no reasons to don't trust Amlogic custom
clk driver decisions about low level bootloaders roles.

[...]

> > +static int meson_a1_periphs_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct clk_hw *hw;
> > + 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_periphs_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_periphs_regmaps); i++)
> > + a1_periphs_regmaps[i]->map = map;
> > +
> > + for (clkid = 0; clkid < a1_periphs_hw_onecell_data.num; clkid++) {
> > + hw = a1_periphs_hw_onecell_data.hws[clkid];
> > + err = devm_clk_hw_register(dev, hw);
> > + if (err)
> > + return dev_err_probe(dev, err,
> > + "clock registration failed\n");
> > + }
> > +
> > + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> > + &a1_periphs_hw_onecell_data);
> > +}
> > +
> > +#ifdef CONFIG_OF
>
> Same as the PLL driver
>

Sure, good point.

[...]

--
Thank you,
Dmitry

2023-03-06 19:07:26

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 3/5] dt-bindings: clock: meson: add A1 PLL clock controller bindings

On Mon, Mar 06, 2023 at 12:33:48PM +0100, Jerome Brunet wrote:
>
> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
>
> > Add the documentation for Amlogic A1 PLL clock driver, and A1 PLL
> > clock controller bindings.
> > Also include new A1 clock controller dt bindings to MAINTAINERS.
> >
> > Signed-off-by: Jian Hu <[email protected]>
> > Signed-off-by: Dmitry Rokosov <[email protected]>
>
> patch order is wrong.
> Bindings before drivers please.

Totally agreed with you. That's why I see Rob's kernel robot errors.
Will be rebased in the next version.

[...]

--
Thank you,
Dmitry

2023-03-06 20:05:58

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver

On Mon, Mar 06, 2023 at 12:17:23PM +0100, Jerome Brunet wrote:
>
> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
>
> > Introduce PLL clock controller for Amlogic A1 SoC family.
> >
> > Signed-off-by: Jian Hu <[email protected]>
> > Signed-off-by: Dmitry Rokosov <[email protected]>
> > ---
> > drivers/clk/meson/Kconfig | 10 +
> > drivers/clk/meson/Makefile | 1 +
> > drivers/clk/meson/a1-pll.c | 365 +++++++++++++++++++++++++++++++++++++
> > drivers/clk/meson/a1-pll.h | 47 +++++
> > 4 files changed, 423 insertions(+)
> > create mode 100644 drivers/clk/meson/a1-pll.c
> > create mode 100644 drivers/clk/meson/a1-pll.h
> >

[...]

> > diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
> > new file mode 100644
> > index 000000000000..c565f9b2a8dd
> > --- /dev/null
> > +++ b/drivers/clk/meson/a1-pll.c
> > @@ -0,0 +1,365 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
> > + * Author: Jian Hu <[email protected]>
> > + *
> > + * Copyright (c) 2023, SberDevices. All Rights Reserved.
> > + * Author: Dmitry Rokosov <[email protected]>
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/of_device.h>
> > +#include <linux/platform_device.h>
> > +#include "meson-a1-clkc.h"
>
> As pointed out by the kernel robot, there is a problem here
>

My fault. Really sorry for that.

[...]

> > +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,
> > + /*
> > + * It is enough that the fdiv leaf has critical flag,
> > + * No critical or unused flag here.
> > + */
>
> The comment is not useful
>

OK

> > + },
> > +};
> > +
> > +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 = 0x01f18440 },
>
> This last poke should not bits otherwise handled by parms.
> This is a rate init in disguise.
>

I believe, you are talking about hifi_pll clk_regmap conflicts with
hifi_init_regs. The above init sequence shouldn't affect pll regmap setup,
it doesn't touch them (we assume that default bit values are all zero):

.en = {
.reg_off = ANACTRL_HIFIPLL_CTRL0,
.shift = 28,
.width = 1,
},
// init_value = 0x01f18440
// en_mask = 0x10000000

.m = {
.reg_off = ANACTRL_HIFIPLL_CTRL0,
.shift = 0,
.width = 8,
},
// init_value = 0x01f18440
// m_mask = 0x0000000f

.n = {
.reg_off = ANACTRL_HIFIPLL_CTRL0,
.shift = 10,
.width = 5,
},
// init_value = 0x01f18440
// n_mask = 0x00007c00
^
oops, one overlap
but why we can't set init value for pre_sel?

.frac = {
.reg_off = ANACTRL_HIFIPLL_CTRL1,
.shift = 0,
.width = 19,
},
// init_value = 0x01800000
// frac_mask = 0x0007ffff

.current_en = {
.reg_off = ANACTRL_HIFIPLL_CTRL0,
.shift = 26,
.width = 1,
},
// init_value = 0x01f18440
// current_en_mask = 0x04000000

.l_detect = {
.reg_off = ANACTRL_HIFIPLL_CTRL2,
.shift = 6,
.width = 1,
},
// init_value = 0x00001100
// l_detect_mask = 0x00000040

> > +};
> > +
> > +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 = {
>
> What is this ?
>

Lock detection module.

This is IP module included to new PLL power-on sequence. From clk-pll.c
patchset:

/*
* Compared with the previous SoCs, self-adaption current module
* is newly added for A1, keep the new power-on sequence to enable the
* PLL. The sequence is:
* 1. enable the pll, delay for 10us
* 2. enable the pll self-adaption current module, delay for 40us
* 3. enable the lock detect module
*/

[...]

> > +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.
> > + * About critical, refer to fclk_div2.
>
> This last line is not useful. Same for other occurences
>

Good point. Copy-paste detected :-)

[...]

> > +static int meson_a1_pll_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct clk_hw *hw;
> > + 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;
> > +
> > + for (clkid = 0; clkid < a1_pll_hw_onecell_data.num; clkid++) {
> > + hw = a1_pll_hw_onecell_data.hws[clkid];
> > + err = devm_clk_hw_register(dev, hw);
> > + if (err)
> > + return dev_err_probe(dev, err,
> > + "clock registration failed\n");
> > + }
> > +
> > + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
> > + &a1_pll_hw_onecell_data);
> > +}
> > +
> > +#ifdef CONFIG_OF
>
> This config is selected by ARM64 which this driver depends on
>

Make sense, thanks a lot!

[...]

--
Thank you,
Dmitry

2023-03-09 14:22:13

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver


On Mon 06 Mar 2023 at 23:05, Dmitry Rokosov <[email protected]> wrote:

> On Mon, Mar 06, 2023 at 12:17:23PM +0100, Jerome Brunet wrote:
>>
>> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
>>
>> > Introduce PLL clock controller for Amlogic A1 SoC family.
>> >
>> > Signed-off-by: Jian Hu <[email protected]>
>> > Signed-off-by: Dmitry Rokosov <[email protected]>
>> > ---
>> > drivers/clk/meson/Kconfig | 10 +
>> > drivers/clk/meson/Makefile | 1 +
>> > drivers/clk/meson/a1-pll.c | 365 +++++++++++++++++++++++++++++++++++++
>> > drivers/clk/meson/a1-pll.h | 47 +++++
>> > 4 files changed, 423 insertions(+)
>> > create mode 100644 drivers/clk/meson/a1-pll.c
>> > create mode 100644 drivers/clk/meson/a1-pll.h
>> >
>
> [...]
>
>> > diff --git a/drivers/clk/meson/a1-pll.c b/drivers/clk/meson/a1-pll.c
>> > new file mode 100644
>> > index 000000000000..c565f9b2a8dd
>> > --- /dev/null
>> > +++ b/drivers/clk/meson/a1-pll.c
>> > @@ -0,0 +1,365 @@
>> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
>> > +/*
>> > + * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
>> > + * Author: Jian Hu <[email protected]>
>> > + *
>> > + * Copyright (c) 2023, SberDevices. All Rights Reserved.
>> > + * Author: Dmitry Rokosov <[email protected]>
>> > + */
>> > +
>> > +#include <linux/clk-provider.h>
>> > +#include <linux/of_device.h>
>> > +#include <linux/platform_device.h>
>> > +#include "meson-a1-clkc.h"
>>
>> As pointed out by the kernel robot, there is a problem here
>>
>
> My fault. Really sorry for that.
>
> [...]
>
>> > +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,
>> > + /*
>> > + * It is enough that the fdiv leaf has critical flag,
>> > + * No critical or unused flag here.
>> > + */
>>
>> The comment is not useful
>>
>
> OK
>
>> > + },
>> > +};
>> > +
>> > +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 = 0x01f18440 },
>>
>> This last poke should not bits otherwise handled by parms.
>> This is a rate init in disguise.
>>
>
> I believe, you are talking about hifi_pll clk_regmap conflicts with
> hifi_init_regs. The above init sequence shouldn't affect pll regmap setup,
> it doesn't touch them (we assume that default bit values are all zero):
>
> .en = {
> .reg_off = ANACTRL_HIFIPLL_CTRL0,
> .shift = 28,
> .width = 1,
> },
> // init_value = 0x01f18440
> // en_mask = 0x10000000
>
> .m = {
> .reg_off = ANACTRL_HIFIPLL_CTRL0,
> .shift = 0,
> .width = 8,
> },
> // init_value = 0x01f18440
> // m_mask = 0x0000000f

mask is 0xff with width 8

>
> .n = {
> .reg_off = ANACTRL_HIFIPLL_CTRL0,
> .shift = 10,
> .width = 5,
> },
> // init_value = 0x01f18440
> // n_mask = 0x00007c00
> ^
> oops, one overlap
> but why we can't set init value for pre_sel?
>
> .frac = {
> .reg_off = ANACTRL_HIFIPLL_CTRL1,
> .shift = 0,
> .width = 19,
> },
> // init_value = 0x01800000
> // frac_mask = 0x0007ffff
>
> .current_en = {
> .reg_off = ANACTRL_HIFIPLL_CTRL0,
> .shift = 26,
> .width = 1,
> },
> // init_value = 0x01f18440
> // current_en_mask = 0x04000000
>
> .l_detect = {
> .reg_off = ANACTRL_HIFIPLL_CTRL2,
> .shift = 6,
> .width = 1,
> },
> // init_value = 0x00001100
> // l_detect_mask = 0x00000040
>
>> > +};
>> > +
>> > +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 = {
>>
>> What is this ?
>>
>
> Lock detection module.
>
> This is IP module included to new PLL power-on sequence. From clk-pll.c
> patchset:
>
> /*
> * Compared with the previous SoCs, self-adaption current module
> * is newly added for A1, keep the new power-on sequence to enable the
> * PLL. The sequence is:
> * 1. enable the pll, delay for 10us
> * 2. enable the pll self-adaption current module, delay for 40us
> * 3. enable the lock detect module
> */

Ok. I missed this is the PLL driver

>
> [...]
>
>> > +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.
>> > + * About critical, refer to fclk_div2.
>>
>> This last line is not useful. Same for other occurences
>>
>
> Good point. Copy-paste detected :-)
>
> [...]
>
>> > +static int meson_a1_pll_probe(struct platform_device *pdev)
>> > +{
>> > + struct device *dev = &pdev->dev;
>> > + struct clk_hw *hw;
>> > + 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;
>> > +
>> > + for (clkid = 0; clkid < a1_pll_hw_onecell_data.num; clkid++) {
>> > + hw = a1_pll_hw_onecell_data.hws[clkid];
>> > + err = devm_clk_hw_register(dev, hw);
>> > + if (err)
>> > + return dev_err_probe(dev, err,
>> > + "clock registration failed\n");
>> > + }
>> > +
>> > + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
>> > + &a1_pll_hw_onecell_data);
>> > +}
>> > +
>> > +#ifdef CONFIG_OF
>>
>> This config is selected by ARM64 which this driver depends on
>>
>
> Make sense, thanks a lot!
>
> [...]


2023-03-09 14:43:17

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 4/5] clk: meson: a1: add Amlogic A1 Peripherals clock controller driver


On Mon 06 Mar 2023 at 22:05, Dmitry Rokosov <[email protected]> wrote:

> Hello Jerome,
>
> Thanks a lot for such detailed review. Please find my comments and
> thoughts below.
>
> On Mon, Mar 06, 2023 at 12:38:22PM +0100, Jerome Brunet wrote:
>>
>> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
>>
>> > Introduce Peripherals clock controller for Amlogic A1 SoC family.
>> >
>> > Signed-off-by: Jian Hu <[email protected]>
>> > Signed-off-by: Dmitry Rokosov <[email protected]>
>
> [...]
>
>> > +static struct clk_regmap dspa_a_sel = {
>> > + .data = &(struct clk_regmap_mux_data){
>> > + .offset = DSPA_CLK_CTRL0,
>> > + .mask = 0x7,
>> > + .shift = 10,
>> > + .table = mux_table_dsp_ab,
>> > + },
>> > + .hw.init = &(struct clk_init_data){
>> > + .name = "dspa_a_sel",
>> > + .ops = &clk_regmap_mux_ops,
>> > + .parent_data = dsp_ab_parent_data,
>> > + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
>> > + /* DSPA_A clk parent should be set statically from dt */
>> > + .flags = CLK_SET_RATE_NO_REPARENT,
>> > + },
>> > +};
>> > +
>> > +static struct clk_regmap dspa_a_div = {
>> > + .data = &(struct clk_regmap_div_data){
>> > + .offset = DSPA_CLK_CTRL0,
>> > + .shift = 0,
>> > + .width = 10,
>> > + },
>> > + .hw.init = &(struct clk_init_data){
>> > + .name = "dspa_a_div",
>> > + .ops = &clk_regmap_divider_ops,
>> > + .parent_hws = (const struct clk_hw *[]) {
>> > + &dspa_a_sel.hw
>> > + },
>> > + .num_parents = 1,
>> > + .flags = CLK_SET_RATE_PARENT,
>> > + },
>> > +};
>> > +
>> > +static struct clk_regmap dspa_a = {
>> > + .data = &(struct clk_regmap_gate_data){
>> > + .offset = DSPA_CLK_CTRL0,
>> > + .bit_idx = 13,
>> > + },
>> > + .hw.init = &(struct clk_init_data) {
>> > + .name = "dspa_a",
>> > + .ops = &clk_regmap_gate_ops,
>> > + .parent_hws = (const struct clk_hw *[]) {
>> > + &dspa_a_div.hw
>> > + },
>> > + .num_parents = 1,
>> > + /*
>> > + * DSPA_A accelerator clk, cannot be disabled by CCF if it
>> > + * has been set by bootloader
>>
>> Then IGNORE_UNUSED is wrong. use RO ops with you must retain the
>> bootloader config.
>
> I thought UNUSED logic will disable 'unused' clock during
> initialization. Or do you mean it's not relevant for ro ops clock,
> because disable() callback is not defined?

It does. It does no prevent a disable if the clock is enabled then
disabled. So what is here works as long as no driver touches this
clock. In such case you are better off with RO ops.

>
>>
>> Note that it is usually a bad idea to depend on the bootloader config.
>> Things tends to go bad when other bootloader version join the fun, like
>> upstream u-boot
>
> To be honest, I don't have the ability to test such behavior on our side,
> because in my hands I have SoC SKUs w/o DSP only.

Then maybe you should leave these clocks out for now.

> But theoretically DSP FW can be started already from the bootloader, and
> then we shouldn't touch this clock.

In theory the bootloader can do it all, why bother booting linux ... :P

> May be CCF has device tree tricks to solve such situations, don't know
> actually. On the other hand, appropriate driver logic would be a nice
> exit here.

If you have a DSP, it is likely to have something to communicate with
the OS at some point, or at least monitor. Such driver would need to
handle to clocks properly.

Since you can test this, I strongly suggest to leave this out for now.

>
> [...]
>
>> > +static struct clk_regmap dspa_en_nic = {
>> > + .data = &(struct clk_regmap_gate_data){
>> > + .offset = DSPA_CLK_EN,
>> > + .bit_idx = 0,
>> > + },
>> > + .hw.init = &(struct clk_init_data) {
>> > + .name = "dspa_en_nic",
>> > + .ops = &clk_regmap_gate_ops,
>> > + .parent_hws = (const struct clk_hw *[]) {
>> > + &dspa_sel.hw
>> > + },
>> > + .num_parents = 1,
>> > + /*
>> > + * DSPA_EN_NIC accelerator clk, cannot be disabled by CCF if it
>> > + * has been set by bootloader
>> > + */
>> > + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
>>
>> All this just highlight the lack of proper drivers to handle the clock,
>> like remote proc one.
>>
>
> Okay, let's imagine we have such a driver. If DSP is already running,
> we can skip the clock setup on this driver side. Hmmm. It looks like
> a proper solution...
>
> I would prefer to tag it with TODO and mark DSP clocks with ro_ops till
> we don't have such a driver.
>
> [...]
>
>> > +
>> > +static struct clk_regmap fclk_div2_divn = {
>> > + .data = &(struct clk_regmap_gate_data){
>> > + .offset = CLK12_24_CTRL,
>> > + .bit_idx = 12,
>> > + },
>> > + .hw.init = &(struct clk_init_data){
>> > + .name = "fclk_div2_divn",
>> > + .ops = &clk_regmap_gate_ops,
>> > + .parent_hws = (const struct clk_hw *[]) {
>> > + &fclk_div2_divn_pre.hw
>> > + },
>> > + .num_parents = 1,
>> > + .flags = CLK_SET_RATE_PARENT,
>> > + },
>> > +};
>> > +
>> > +/*
>> > + * the index 2 is sys_pll_div16, it will be completed in the CPU clock ctrl,
>>
>> I don't get this, what do you mean ?
>>
>
> I mean, it will be implemented in the CPU clock controller driver in the
> next patch series. Agree, I have to make a rephrase.
>
>> > + * the index 4 is the clock measurement source, it relies on
>> > + * the clock measurement register configuration.
>>
>> Obviously ... What mean here is that clock measurement is a debug
>> feature and should be considered
>>

Arff sorry, "should *NOT* be considered"

>
> Should I mark it with TODO tag? I prefer to implement 'must have' logic
> first. Clock measurement are optional from my point of view.
>
> [...]
>
>> > +static struct clk_regmap pwm_a = {
>> > + .data = &(struct clk_regmap_gate_data){
>> > + .offset = PWM_CLK_AB_CTRL,
>> > + .bit_idx = 8,
>> > + },
>> > + .hw.init = &(struct clk_init_data) {
>> > + .name = "pwm_a",
>> > + .ops = &clk_regmap_gate_ops,
>> > + .parent_hws = (const struct clk_hw *[]) {
>> > + &pwm_a_div.hw
>> > + },
>> > + .num_parents = 1,
>> > + /*
>> > + * The CPU working voltage is controlled by pwm_a
>> > + * in BL2 firmware. The clock is required by the platform
>> > + * to operate correctly. Add the CLK_IS_CRITICAL flag to
>> > + * avoid changing at runtime.
>> > + * About critical, refer to sys
>> > + */
>>
>> PWM_A required by the BL2 ... really ? Looks really fishy to me.
>>
>> Is it possible it is used by regulator instead ?
>>
>
> Honestly, this comment's information was grabbed from Amlogic custom
> driver. It has such words:
>
> /*
> * add CLK_IGNORE_UNUSED flag for pwm controller GATE
> * clk core will disable unused clock, it may disable
> * vddcore voltage which contrlled by one pwm in bl21.
> * add the flag to avoid changing cpu voltage.
> */
>
> We don't have bl21 source code in the hands, so I can't check
> unfortunately. But I have no reasons to don't trust Amlogic custom
> clk driver decisions about low level bootloaders roles.

So it is a regulator. Not the BL2(1)

There are several reasons why this is wrong:
* CLK_IGNORE_UNUSED would be wrong for reasons I already mentionned
* CLK_SET_RATE_PARENT | CLK_IS_CRITICAL is not great either because
nothing prevents the rate to be changed to an absurdly low value, which
would not go well with a DVFS PWM.
* This bakes power contraints specific to your board in the SoC clock
controller. Another board, another BL21 could have different
contraints. We can't lock all PWM clock sources. This is not
appropriate.

You need to properly describe your regualtors in DT.

>
> [...]
>
>> > +static int meson_a1_periphs_probe(struct platform_device *pdev)
>> > +{
>> > + struct device *dev = &pdev->dev;
>> > + struct clk_hw *hw;
>> > + 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_periphs_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_periphs_regmaps); i++)
>> > + a1_periphs_regmaps[i]->map = map;
>> > +
>> > + for (clkid = 0; clkid < a1_periphs_hw_onecell_data.num; clkid++) {
>> > + hw = a1_periphs_hw_onecell_data.hws[clkid];
>> > + err = devm_clk_hw_register(dev, hw);
>> > + if (err)
>> > + return dev_err_probe(dev, err,
>> > + "clock registration failed\n");
>> > + }
>> > +
>> > + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
>> > + &a1_periphs_hw_onecell_data);
>> > +}
>> > +
>> > +#ifdef CONFIG_OF
>>
>> Same as the PLL driver
>>
>
> Sure, good point.
>
> [...]


2023-03-09 18:29:09

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver

On Thu, Mar 09, 2023 at 03:20:23PM +0100, Jerome Brunet wrote:
>
> On Mon 06 Mar 2023 at 23:05, Dmitry Rokosov <[email protected]> wrote:
>
> > On Mon, Mar 06, 2023 at 12:17:23PM +0100, Jerome Brunet wrote:
> >>
> >> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
> >>
> >> > Introduce PLL clock controller for Amlogic A1 SoC family.
> >> >
> >> > Signed-off-by: Jian Hu <[email protected]>
> >> > Signed-off-by: Dmitry Rokosov <[email protected]>

[...]

> >> > + },
> >> > +};
> >> > +
> >> > +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 = 0x01f18440 },
> >>
> >> This last poke should not bits otherwise handled by parms.
> >> This is a rate init in disguise.
> >>
> >
> > I believe, you are talking about hifi_pll clk_regmap conflicts with
> > hifi_init_regs. The above init sequence shouldn't affect pll regmap setup,
> > it doesn't touch them (we assume that default bit values are all zero):
> >
> > .en = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> > .shift = 28,
> > .width = 1,
> > },
> > // init_value = 0x01f18440
> > // en_mask = 0x10000000
> >
> > .m = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> > .shift = 0,
> > .width = 8,
> > },
> > // init_value = 0x01f18440
> > // m_mask = 0x0000000f
>
> mask is 0xff with width 8
>

Ah, you're right. Anyway, I think this is just init value and it's okay
to set it during initialization and rewrite after in parameter
propagation stage.

> >
> > .n = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> > .shift = 10,
> > .width = 5,
> > },
> > // init_value = 0x01f18440
> > // n_mask = 0x00007c00
> > ^
> > oops, one overlap
> > but why we can't set init value for pre_sel?
> >
> > .frac = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL1,
> > .shift = 0,
> > .width = 19,
> > },
> > // init_value = 0x01800000
> > // frac_mask = 0x0007ffff
> >
> > .current_en = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> > .shift = 26,
> > .width = 1,
> > },
> > // init_value = 0x01f18440
> > // current_en_mask = 0x04000000
> >
> > .l_detect = {
> > .reg_off = ANACTRL_HIFIPLL_CTRL2,
> > .shift = 6,
> > .width = 1,
> > },
> > // init_value = 0x00001100
> > // l_detect_mask = 0x00000040
> >
> >> > +};
> >> > +
> >> > +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 = {
> >>
> >> What is this ?
> >>
> >
> > Lock detection module.
> >
> > This is IP module included to new PLL power-on sequence. From clk-pll.c
> > patchset:
> >
> > /*
> > * Compared with the previous SoCs, self-adaption current module
> > * is newly added for A1, keep the new power-on sequence to enable the
> > * PLL. The sequence is:
> > * 1. enable the pll, delay for 10us
> > * 2. enable the pll self-adaption current module, delay for 40us
> > * 3. enable the lock detect module
> > */
>
> Ok. I missed this is the PLL driver
>

No problem.

[...]

--
Thank you,
Dmitry

2023-03-09 18:59:09

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 4/5] clk: meson: a1: add Amlogic A1 Peripherals clock controller driver

On Thu, Mar 09, 2023 at 03:22:08PM +0100, Jerome Brunet wrote:
>
> On Mon 06 Mar 2023 at 22:05, Dmitry Rokosov <[email protected]> wrote:
>
> > Hello Jerome,
> >
> > Thanks a lot for such detailed review. Please find my comments and
> > thoughts below.
> >
> > On Mon, Mar 06, 2023 at 12:38:22PM +0100, Jerome Brunet wrote:
> >>
> >> On Wed 01 Mar 2023 at 21:37, Dmitry Rokosov <[email protected]> wrote:
> >>
> >> > Introduce Peripherals clock controller for Amlogic A1 SoC family.
> >> >
> >> > Signed-off-by: Jian Hu <[email protected]>
> >> > Signed-off-by: Dmitry Rokosov <[email protected]>
> >
> > [...]
> >
> >> > +static struct clk_regmap dspa_a_sel = {
> >> > + .data = &(struct clk_regmap_mux_data){
> >> > + .offset = DSPA_CLK_CTRL0,
> >> > + .mask = 0x7,
> >> > + .shift = 10,
> >> > + .table = mux_table_dsp_ab,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data){
> >> > + .name = "dspa_a_sel",
> >> > + .ops = &clk_regmap_mux_ops,
> >> > + .parent_data = dsp_ab_parent_data,
> >> > + .num_parents = ARRAY_SIZE(dsp_ab_parent_data),
> >> > + /* DSPA_A clk parent should be set statically from dt */
> >> > + .flags = CLK_SET_RATE_NO_REPARENT,
> >> > + },
> >> > +};
> >> > +
> >> > +static struct clk_regmap dspa_a_div = {
> >> > + .data = &(struct clk_regmap_div_data){
> >> > + .offset = DSPA_CLK_CTRL0,
> >> > + .shift = 0,
> >> > + .width = 10,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data){
> >> > + .name = "dspa_a_div",
> >> > + .ops = &clk_regmap_divider_ops,
> >> > + .parent_hws = (const struct clk_hw *[]) {
> >> > + &dspa_a_sel.hw
> >> > + },
> >> > + .num_parents = 1,
> >> > + .flags = CLK_SET_RATE_PARENT,
> >> > + },
> >> > +};
> >> > +
> >> > +static struct clk_regmap dspa_a = {
> >> > + .data = &(struct clk_regmap_gate_data){
> >> > + .offset = DSPA_CLK_CTRL0,
> >> > + .bit_idx = 13,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data) {
> >> > + .name = "dspa_a",
> >> > + .ops = &clk_regmap_gate_ops,
> >> > + .parent_hws = (const struct clk_hw *[]) {
> >> > + &dspa_a_div.hw
> >> > + },
> >> > + .num_parents = 1,
> >> > + /*
> >> > + * DSPA_A accelerator clk, cannot be disabled by CCF if it
> >> > + * has been set by bootloader
> >>
> >> Then IGNORE_UNUSED is wrong. use RO ops with you must retain the
> >> bootloader config.
> >
> > I thought UNUSED logic will disable 'unused' clock during
> > initialization. Or do you mean it's not relevant for ro ops clock,
> > because disable() callback is not defined?
>
> It does. It does no prevent a disable if the clock is enabled then
> disabled. So what is here works as long as no driver touches this
> clock. In such case you are better off with RO ops.
>

Okay. But for dspX clocks I'm going to listen to your suggestion and
leave this out with default parameters.

> >
> >>
> >> Note that it is usually a bad idea to depend on the bootloader config.
> >> Things tends to go bad when other bootloader version join the fun, like
> >> upstream u-boot
> >
> > To be honest, I don't have the ability to test such behavior on our side,
> > because in my hands I have SoC SKUs w/o DSP only.
>
> Then maybe you should leave these clocks out for now.
>

Sure, agree.

> > But theoretically DSP FW can be started already from the bootloader, and
> > then we shouldn't touch this clock.
>
> In theory the bootloader can do it all, why bother booting linux ... :P
>

Exactly! It depends on your goals and motivation :-)

> > May be CCF has device tree tricks to solve such situations, don't know
> > actually. On the other hand, appropriate driver logic would be a nice
> > exit here.
>
> If you have a DSP, it is likely to have something to communicate with
> the OS at some point, or at least monitor. Such driver would need to
> handle to clocks properly.
>
> Since you can test this, I strongly suggest to leave this out for now.
>

Okay, it's the best decision in such situation.

> >
> > [...]
> >
> >> > +static struct clk_regmap dspa_en_nic = {
> >> > + .data = &(struct clk_regmap_gate_data){
> >> > + .offset = DSPA_CLK_EN,
> >> > + .bit_idx = 0,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data) {
> >> > + .name = "dspa_en_nic",
> >> > + .ops = &clk_regmap_gate_ops,
> >> > + .parent_hws = (const struct clk_hw *[]) {
> >> > + &dspa_sel.hw
> >> > + },
> >> > + .num_parents = 1,
> >> > + /*
> >> > + * DSPA_EN_NIC accelerator clk, cannot be disabled by CCF if it
> >> > + * has been set by bootloader
> >> > + */
> >> > + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
> >>
> >> All this just highlight the lack of proper drivers to handle the clock,
> >> like remote proc one.
> >>
> >
> > Okay, let's imagine we have such a driver. If DSP is already running,
> > we can skip the clock setup on this driver side. Hmmm. It looks like
> > a proper solution...
> >
> > I would prefer to tag it with TODO and mark DSP clocks with ro_ops till
> > we don't have such a driver.
> >
> > [...]
> >
> >> > +
> >> > +static struct clk_regmap fclk_div2_divn = {
> >> > + .data = &(struct clk_regmap_gate_data){
> >> > + .offset = CLK12_24_CTRL,
> >> > + .bit_idx = 12,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data){
> >> > + .name = "fclk_div2_divn",
> >> > + .ops = &clk_regmap_gate_ops,
> >> > + .parent_hws = (const struct clk_hw *[]) {
> >> > + &fclk_div2_divn_pre.hw
> >> > + },
> >> > + .num_parents = 1,
> >> > + .flags = CLK_SET_RATE_PARENT,
> >> > + },
> >> > +};
> >> > +
> >> > +/*
> >> > + * the index 2 is sys_pll_div16, it will be completed in the CPU clock ctrl,
> >>
> >> I don't get this, what do you mean ?
> >>
> >
> > I mean, it will be implemented in the CPU clock controller driver in the
> > next patch series. Agree, I have to make a rephrase.
> >
> >> > + * the index 4 is the clock measurement source, it relies on
> >> > + * the clock measurement register configuration.
> >>
> >> Obviously ... What mean here is that clock measurement is a debug
> >> feature and should be considered
> >>
>
> Arff sorry, "should *NOT* be considered"
>

Yep, in the current patch (and at all I suppose) it should not be
considered. But IMHO I need to comment out why index 4 is missing.

> >
> > Should I mark it with TODO tag? I prefer to implement 'must have' logic
> > first. Clock measurement are optional from my point of view.
> >
> > [...]
> >
> >> > +static struct clk_regmap pwm_a = {
> >> > + .data = &(struct clk_regmap_gate_data){
> >> > + .offset = PWM_CLK_AB_CTRL,
> >> > + .bit_idx = 8,
> >> > + },
> >> > + .hw.init = &(struct clk_init_data) {
> >> > + .name = "pwm_a",
> >> > + .ops = &clk_regmap_gate_ops,
> >> > + .parent_hws = (const struct clk_hw *[]) {
> >> > + &pwm_a_div.hw
> >> > + },
> >> > + .num_parents = 1,
> >> > + /*
> >> > + * The CPU working voltage is controlled by pwm_a
> >> > + * in BL2 firmware. The clock is required by the platform
> >> > + * to operate correctly. Add the CLK_IS_CRITICAL flag to
> >> > + * avoid changing at runtime.
> >> > + * About critical, refer to sys
> >> > + */
> >>
> >> PWM_A required by the BL2 ... really ? Looks really fishy to me.
> >>
> >> Is it possible it is used by regulator instead ?
> >>
> >
> > Honestly, this comment's information was grabbed from Amlogic custom
> > driver. It has such words:
> >
> > /*
> > * add CLK_IGNORE_UNUSED flag for pwm controller GATE
> > * clk core will disable unused clock, it may disable
> > * vddcore voltage which contrlled by one pwm in bl21.
> > * add the flag to avoid changing cpu voltage.
> > */
> >
> > We don't have bl21 source code in the hands, so I can't check
> > unfortunately. But I have no reasons to don't trust Amlogic custom
> > clk driver decisions about low level bootloaders roles.
>
> So it is a regulator. Not the BL2(1)
>
> There are several reasons why this is wrong:
> * CLK_IGNORE_UNUSED would be wrong for reasons I already mentionned
> * CLK_SET_RATE_PARENT | CLK_IS_CRITICAL is not great either because
> nothing prevents the rate to be changed to an absurdly low value, which
> would not go well with a DVFS PWM.
> * This bakes power contraints specific to your board in the SoC clock
> controller. Another board, another BL21 could have different
> contraints. We can't lock all PWM clock sources. This is not
> appropriate.
>
> You need to properly describe your regualtors in DT.
>

I've got deeper and checked other board configurations. Now I see what
you mean. Voltage regulations should happen using vddcpu driver and pwm
clk is used to control core voltage. Thank you for pointing me to this
architecture problem.
In the next patch I will change pwm_a flags to the default value with
CLK_SET_RATE_PARENT.

[...]

--
Thank you,
Dmitry

2023-03-13 09:21:33

by Jerome Brunet

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver


On Thu 09 Mar 2023 at 21:28, Dmitry Rokosov <[email protected]> wrote:

>> >>
>> >> This last poke should not bits otherwise handled by parms.
>> >> This is a rate init in disguise.
>> >>
>> >
>> > I believe, you are talking about hifi_pll clk_regmap conflicts with
>> > hifi_init_regs. The above init sequence shouldn't affect pll regmap setup,
>> > it doesn't touch them (we assume that default bit values are all zero):
>> >
>> > .en = {
>> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
>> > .shift = 28,
>> > .width = 1,
>> > },
>> > // init_value = 0x01f18440
>> > // en_mask = 0x10000000
>> >
>> > .m = {
>> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
>> > .shift = 0,
>> > .width = 8,
>> > },
>> > // init_value = 0x01f18440
>> > // m_mask = 0x0000000f
>>
>> mask is 0xff with width 8
>>
>
> Ah, you're right. Anyway, I think this is just init value and it's okay
> to set it during initialization and rewrite after in parameter
> propagation stage.
>

... But the magic pokes are there only to initialize the unmanaged part
of the clock regs. I'd like it to be clear and stay that way.

So please, clear the managed fields from the initial poke table.



2023-03-13 10:25:28

by Dmitry Rokosov

[permalink] [raw]
Subject: Re: [PATCH v9 2/5] clk: meson: a1: add Amlogic A1 PLL clock controller driver

On Mon, Mar 13, 2023 at 10:18:02AM +0100, Jerome Brunet wrote:
>
> On Thu 09 Mar 2023 at 21:28, Dmitry Rokosov <[email protected]> wrote:
>
> >> >>
> >> >> This last poke should not bits otherwise handled by parms.
> >> >> This is a rate init in disguise.
> >> >>
> >> >
> >> > I believe, you are talking about hifi_pll clk_regmap conflicts with
> >> > hifi_init_regs. The above init sequence shouldn't affect pll regmap setup,
> >> > it doesn't touch them (we assume that default bit values are all zero):
> >> >
> >> > .en = {
> >> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> >> > .shift = 28,
> >> > .width = 1,
> >> > },
> >> > // init_value = 0x01f18440
> >> > // en_mask = 0x10000000
> >> >
> >> > .m = {
> >> > .reg_off = ANACTRL_HIFIPLL_CTRL0,
> >> > .shift = 0,
> >> > .width = 8,
> >> > },
> >> > // init_value = 0x01f18440
> >> > // m_mask = 0x0000000f
> >>
> >> mask is 0xff with width 8
> >>
> >
> > Ah, you're right. Anyway, I think this is just init value and it's okay
> > to set it during initialization and rewrite after in parameter
> > propagation stage.
> >
>
> ... But the magic pokes are there only to initialize the unmanaged part
> of the clock regs. I'd like it to be clear and stay that way.
>
> So please, clear the managed fields from the initial poke table.

I've double checked hifi_pll clk. In the my current configuration no any
clks inherited from it. Therefore its 'enable_count' equals to 0.
And of course in the such situation the rate must be zeroed as well.
It means you are right at all. I'll remove pre_sel and fbkdiv hifi_pll
pre-setup in the next version.
Thank you for hunted down!

--
Thank you,
Dmitry