From nobody Wed Dec 17 10:42:37 2025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E95F4C83F3F for ; Mon, 4 Sep 2023 07:57:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S242617AbjIDH5Q (ORCPT ); Mon, 4 Sep 2023 03:57:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45894 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S242040AbjIDH5O (ORCPT ); Mon, 4 Sep 2023 03:57:14 -0400 Received: from mail-sh.amlogic.com (mail-sh.amlogic.com [58.32.228.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DFBDD138; Mon, 4 Sep 2023 00:56:21 -0700 (PDT) Received: from droid06.amlogic.com (10.18.11.248) by mail-sh.amlogic.com (10.18.11.5) with Microsoft SMTP Server id 15.1.2507.13; Mon, 4 Sep 2023 15:56:21 +0800 From: Yu Tu To: Neil Armstrong , Jerome Brunet , Michael Turquette , "Stephen Boyd" , Rob Herring , "Krzysztof Kozlowski" , Conor Dooley , Kevin Hilman , "Martin Blumenstingl" , , , , , CC: , , Yu Tu Subject: [PATCH V11 3/4] clk: meson: S4: add support for Amlogic S4 SoC PLL clock driver Date: Mon, 4 Sep 2023 15:55:03 +0800 Message-ID: <20230904075504.23263-4-yu.tu@amlogic.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20230904075504.23263-1-yu.tu@amlogic.com> References: <20230904075504.23263-1-yu.tu@amlogic.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Originating-IP: [10.18.11.248] Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add the S4 PLL clock controller driver in the S4 SoC family. Signed-off-by: Yu Tu --- drivers/clk/meson/Kconfig | 12 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/s4-pll.c | 867 +++++++++++++++++++++++++++++++++++++ drivers/clk/meson/s4-pll.h | 38 ++ 4 files changed, 918 insertions(+) create mode 100644 drivers/clk/meson/s4-pll.c create mode 100644 drivers/clk/meson/s4-pll.h diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig index 135da8f2d0b1..e90982d77598 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -144,4 +144,16 @@ config COMMON_CLK_G12A help Support for the clock controller on Amlogic S905D2, S905X2 and S905Y2 devices, aka g12a. Say Y if you want peripherals to work. + +config COMMON_CLK_S4_PLL + tristate "S4 SoC PLL clock controllers support" + depends on ARM64 + default y + select COMMON_CLK_MESON_MPLL + select COMMON_CLK_MESON_PLL + select COMMON_CLK_MESON_REGMAP + help + Support for the PLL clock controller on Amlogic S805X2 and S905Y4 devic= es, + AKA S4. Say Y if you want the board to work, because PLLs are the paren= t of + most peripherals. endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index cd961cc4f4db..612cee923890 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -22,3 +22,4 @@ obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) +=3D a1-periphera= ls.o obj-$(CONFIG_COMMON_CLK_GXBB) +=3D gxbb.o gxbb-aoclk.o obj-$(CONFIG_COMMON_CLK_G12A) +=3D g12a.o g12a-aoclk.o obj-$(CONFIG_COMMON_CLK_MESON8B) +=3D meson8b.o meson8-ddr.o +obj-$(CONFIG_COMMON_CLK_S4_PLL) +=3D s4-pll.o diff --git a/drivers/clk/meson/s4-pll.c b/drivers/clk/meson/s4-pll.c new file mode 100644 index 000000000000..8dfaeccaadc2 --- /dev/null +++ b/drivers/clk/meson/s4-pll.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR MIT) +/* + * Amlogic S4 PLL Clock Controller Driver + * + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "s4-pll.h" +#include "meson-clkc-utils.h" +#include + +static DEFINE_SPINLOCK(meson_clk_lock); + +/* + * These clock are a fixed value (fixed_pll is 2GHz) that is initialized b= y ROMcode. + * The chip was changed fixed pll for security reasons. Fixed PLL register= s are not writable + * in the kernel phase. Write of fixed PLL-related register will cause the= system to crash. + * Meanwhile, these clock won't ever change at runtime. + * For the above reasons, we can only use ro_ops for fixed PLL related clo= cks. + */ +static struct clk_regmap s4_fixed_pll_dco =3D { + .data =3D &(struct meson_clk_pll_data){ + .en =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 28, + .width =3D 1, + }, + .m =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 0, + .width =3D 8, + }, + .n =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 10, + .width =3D 5, + }, + .l =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 31, + .width =3D 1, + }, + .rst =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 29, + .width =3D 1, + }, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fixed_pll_dco", + .ops =3D &meson_clk_pll_ro_ops, + .parent_data =3D (const struct clk_parent_data []) { + { .fw_name =3D "xtal", } + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fixed_pll =3D { + .data =3D &(struct clk_regmap_div_data){ + .offset =3D ANACTRL_FIXPLL_CTRL0, + .shift =3D 16, + .width =3D 2, + .flags =3D CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fixed_pll", + .ops =3D &clk_regmap_divider_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents =3D 1, + /* + * This clock won't ever change at runtime so + * CLK_SET_RATE_PARENT is not required + */ + }, +}; + +static struct clk_fixed_factor s4_fclk_div2_div =3D { + .mult =3D 1, + .div =3D 2, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div2_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div2 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 24, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div2", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div2_div.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div3_div =3D { + .mult =3D 1, + .div =3D 3, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div3_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div3 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 20, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div3", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div3_div.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div4_div =3D { + .mult =3D 1, + .div =3D 4, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div4_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div4 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 21, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div4", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div4_div.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div5_div =3D { + .mult =3D 1, + .div =3D 5, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div5_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div5 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 22, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div5", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div5_div.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div7_div =3D { + .mult =3D 1, + .div =3D 7, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div7_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_fixed_pll.hw }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div7 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 23, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div7", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div7_div.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_fixed_factor s4_fclk_div2p5_div =3D { + .mult =3D 2, + .div =3D 5, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div2p5_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fixed_pll.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_fclk_div2p5 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_FIXPLL_CTRL1, + .bit_idx =3D 25, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "fclk_div2p5", + .ops =3D &clk_regmap_gate_ro_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fclk_div2p5_div.hw + }, + .num_parents =3D 1, + }, +}; + +static const struct pll_mult_range s4_gp0_pll_mult_range =3D { + .min =3D 125, + .max =3D 250, +}; + +/* + * Internal gp0 pll emulation configuration parameters + */ +static const struct reg_sequence s4_gp0_init_regs[] =3D { + { .reg =3D ANACTRL_GP0PLL_CTRL1, .def =3D 0x00000000 }, + { .reg =3D ANACTRL_GP0PLL_CTRL2, .def =3D 0x00000000 }, + { .reg =3D ANACTRL_GP0PLL_CTRL3, .def =3D 0x48681c00 }, + { .reg =3D ANACTRL_GP0PLL_CTRL4, .def =3D 0x88770290 }, + { .reg =3D ANACTRL_GP0PLL_CTRL5, .def =3D 0x39272000 }, + { .reg =3D ANACTRL_GP0PLL_CTRL6, .def =3D 0x56540000 } +}; + +static struct clk_regmap s4_gp0_pll_dco =3D { + .data =3D &(struct meson_clk_pll_data){ + .en =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 28, + .width =3D 1, + }, + .m =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 0, + .width =3D 8, + }, + .n =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 10, + .width =3D 5, + }, + .l =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 31, + .width =3D 1, + }, + .rst =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 29, + .width =3D 1, + }, + .range =3D &s4_gp0_pll_mult_range, + .init_regs =3D s4_gp0_init_regs, + .init_count =3D ARRAY_SIZE(s4_gp0_init_regs), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "gp0_pll_dco", + .ops =3D &meson_clk_pll_ops, + .parent_data =3D (const struct clk_parent_data []) { + { .fw_name =3D "xtal", } + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_gp0_pll =3D { + .data =3D &(struct clk_regmap_div_data){ + .offset =3D ANACTRL_GP0PLL_CTRL0, + .shift =3D 16, + .width =3D 3, + .flags =3D (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "gp0_pll", + .ops =3D &clk_regmap_divider_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_gp0_pll_dco.hw + }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +/* + * Internal hifi pll emulation configuration parameters + */ +static const struct reg_sequence s4_hifi_init_regs[] =3D { + { .reg =3D ANACTRL_HIFIPLL_CTRL1, .def =3D 0x00010e56 }, + { .reg =3D ANACTRL_HIFIPLL_CTRL2, .def =3D 0x00000000 }, + { .reg =3D ANACTRL_HIFIPLL_CTRL3, .def =3D 0x6a285c00 }, + { .reg =3D ANACTRL_HIFIPLL_CTRL4, .def =3D 0x65771290 }, + { .reg =3D ANACTRL_HIFIPLL_CTRL5, .def =3D 0x39272000 }, + { .reg =3D ANACTRL_HIFIPLL_CTRL6, .def =3D 0x56540000 } +}; + +static struct clk_regmap s4_hifi_pll_dco =3D { + .data =3D &(struct meson_clk_pll_data){ + .en =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 28, + .width =3D 1, + }, + .m =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 0, + .width =3D 8, + }, + .n =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 10, + .width =3D 5, + }, + .l =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 31, + .width =3D 1, + }, + .rst =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 29, + .width =3D 1, + }, + .range =3D &s4_gp0_pll_mult_range, + .init_regs =3D s4_hifi_init_regs, + .init_count =3D ARRAY_SIZE(s4_hifi_init_regs), + .flags =3D CLK_MESON_PLL_ROUND_CLOSEST, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "hifi_pll_dco", + .ops =3D &meson_clk_pll_ops, + .parent_data =3D (const struct clk_parent_data []) { + { .fw_name =3D "xtal", } + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_hifi_pll =3D { + .data =3D &(struct clk_regmap_div_data){ + .offset =3D ANACTRL_HIFIPLL_CTRL0, + .shift =3D 16, + .width =3D 2, + .flags =3D (CLK_DIVIDER_POWER_OF_TWO | + CLK_DIVIDER_ROUND_CLOSEST), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "hifi_pll", + .ops =3D &clk_regmap_divider_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_hifi_pll_dco.hw + }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll_dco =3D { + .data =3D &(struct meson_clk_pll_data){ + .en =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 28, + .width =3D 1, + }, + .m =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 0, + .width =3D 8, + }, + .n =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 10, + .width =3D 5, + }, + .l =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 31, + .width =3D 1, + }, + .rst =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 29, + .width =3D 1, + }, + .range =3D &s4_gp0_pll_mult_range, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "hdmi_pll_dco", + .ops =3D &meson_clk_pll_ops, + .parent_data =3D (const struct clk_parent_data []) { + { .fw_name =3D "xtal", } + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_hdmi_pll_od =3D { + .data =3D &(struct clk_regmap_div_data){ + .offset =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 16, + .width =3D 4, + .flags =3D CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "hdmi_pll_od", + .ops =3D &clk_regmap_divider_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_hdmi_pll_dco.hw + }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_regmap s4_hdmi_pll =3D { + .data =3D &(struct clk_regmap_div_data){ + .offset =3D ANACTRL_HDMIPLL_CTRL0, + .shift =3D 20, + .width =3D 2, + .flags =3D CLK_DIVIDER_POWER_OF_TWO, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "hdmi_pll", + .ops =3D &clk_regmap_divider_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_hdmi_pll_od.hw + }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_fixed_factor s4_mpll_50m_div =3D { + .mult =3D 1, + .div =3D 80, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll_50m_div", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_mpll_50m =3D { + .data =3D &(struct clk_regmap_mux_data){ + .offset =3D ANACTRL_FIXPLL_CTRL3, + .mask =3D 0x1, + .shift =3D 5, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll_50m", + .ops =3D &clk_regmap_mux_ro_ops, + .parent_data =3D (const struct clk_parent_data []) { + { .fw_name =3D "xtal", }, + { .hw =3D &s4_mpll_50m_div.hw }, + }, + .num_parents =3D 2, + }, +}; + +static struct clk_fixed_factor s4_mpll_prediv =3D { + .mult =3D 1, + .div =3D 2, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll_prediv", + .ops =3D &clk_fixed_factor_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_fixed_pll_dco.hw + }, + .num_parents =3D 1, + }, +}; + +static const struct reg_sequence s4_mpll0_init_regs[] =3D { + { .reg =3D ANACTRL_MPLL_CTRL2, .def =3D 0x40000033 } +}; + +static struct clk_regmap s4_mpll0_div =3D { + .data =3D &(struct meson_clk_mpll_data){ + .sdm =3D { + .reg_off =3D ANACTRL_MPLL_CTRL1, + .shift =3D 0, + .width =3D 14, + }, + .sdm_en =3D { + .reg_off =3D ANACTRL_MPLL_CTRL1, + .shift =3D 30, + .width =3D 1, + }, + .n2 =3D { + .reg_off =3D ANACTRL_MPLL_CTRL1, + .shift =3D 20, + .width =3D 9, + }, + .ssen =3D { + .reg_off =3D ANACTRL_MPLL_CTRL1, + .shift =3D 29, + .width =3D 1, + }, + .lock =3D &meson_clk_lock, + .init_regs =3D s4_mpll0_init_regs, + .init_count =3D ARRAY_SIZE(s4_mpll0_init_regs), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll0_div", + .ops =3D &meson_clk_mpll_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_mpll0 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_MPLL_CTRL1, + .bit_idx =3D 31, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll0", + .ops =3D &clk_regmap_gate_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_mpll0_div.hw }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll1_init_regs[] =3D { + { .reg =3D ANACTRL_MPLL_CTRL4, .def =3D 0x40000033 } +}; + +static struct clk_regmap s4_mpll1_div =3D { + .data =3D &(struct meson_clk_mpll_data){ + .sdm =3D { + .reg_off =3D ANACTRL_MPLL_CTRL3, + .shift =3D 0, + .width =3D 14, + }, + .sdm_en =3D { + .reg_off =3D ANACTRL_MPLL_CTRL3, + .shift =3D 30, + .width =3D 1, + }, + .n2 =3D { + .reg_off =3D ANACTRL_MPLL_CTRL3, + .shift =3D 20, + .width =3D 9, + }, + .ssen =3D { + .reg_off =3D ANACTRL_MPLL_CTRL3, + .shift =3D 29, + .width =3D 1, + }, + .lock =3D &meson_clk_lock, + .init_regs =3D s4_mpll1_init_regs, + .init_count =3D ARRAY_SIZE(s4_mpll1_init_regs), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll1_div", + .ops =3D &meson_clk_mpll_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_mpll1 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_MPLL_CTRL3, + .bit_idx =3D 31, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll1", + .ops =3D &clk_regmap_gate_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_mpll1_div.hw }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll2_init_regs[] =3D { + { .reg =3D ANACTRL_MPLL_CTRL6, .def =3D 0x40000033 } +}; + +static struct clk_regmap s4_mpll2_div =3D { + .data =3D &(struct meson_clk_mpll_data){ + .sdm =3D { + .reg_off =3D ANACTRL_MPLL_CTRL5, + .shift =3D 0, + .width =3D 14, + }, + .sdm_en =3D { + .reg_off =3D ANACTRL_MPLL_CTRL5, + .shift =3D 30, + .width =3D 1, + }, + .n2 =3D { + .reg_off =3D ANACTRL_MPLL_CTRL5, + .shift =3D 20, + .width =3D 9, + }, + .ssen =3D { + .reg_off =3D ANACTRL_MPLL_CTRL5, + .shift =3D 29, + .width =3D 1, + }, + .lock =3D &meson_clk_lock, + .init_regs =3D s4_mpll2_init_regs, + .init_count =3D ARRAY_SIZE(s4_mpll2_init_regs), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll2_div", + .ops =3D &meson_clk_mpll_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_mpll2 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_MPLL_CTRL5, + .bit_idx =3D 31, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll2", + .ops =3D &clk_regmap_gate_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_mpll2_div.hw }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +static const struct reg_sequence s4_mpll3_init_regs[] =3D { + { .reg =3D ANACTRL_MPLL_CTRL8, .def =3D 0x40000033 } +}; + +static struct clk_regmap s4_mpll3_div =3D { + .data =3D &(struct meson_clk_mpll_data){ + .sdm =3D { + .reg_off =3D ANACTRL_MPLL_CTRL7, + .shift =3D 0, + .width =3D 14, + }, + .sdm_en =3D { + .reg_off =3D ANACTRL_MPLL_CTRL7, + .shift =3D 30, + .width =3D 1, + }, + .n2 =3D { + .reg_off =3D ANACTRL_MPLL_CTRL7, + .shift =3D 20, + .width =3D 9, + }, + .ssen =3D { + .reg_off =3D ANACTRL_MPLL_CTRL7, + .shift =3D 29, + .width =3D 1, + }, + .lock =3D &meson_clk_lock, + .init_regs =3D s4_mpll3_init_regs, + .init_count =3D ARRAY_SIZE(s4_mpll3_init_regs), + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll3_div", + .ops =3D &meson_clk_mpll_ops, + .parent_hws =3D (const struct clk_hw *[]) { + &s4_mpll_prediv.hw + }, + .num_parents =3D 1, + }, +}; + +static struct clk_regmap s4_mpll3 =3D { + .data =3D &(struct clk_regmap_gate_data){ + .offset =3D ANACTRL_MPLL_CTRL7, + .bit_idx =3D 31, + }, + .hw.init =3D &(struct clk_init_data){ + .name =3D "mpll3", + .ops =3D &clk_regmap_gate_ops, + .parent_hws =3D (const struct clk_hw *[]) { &s4_mpll3_div.hw }, + .num_parents =3D 1, + .flags =3D CLK_SET_RATE_PARENT, + }, +}; + +/* Array of all clocks provided by this provider */ +static struct clk_hw *s4_pll_hw_clks[] =3D { + [CLKID_FIXED_PLL_DCO] =3D &s4_fixed_pll_dco.hw, + [CLKID_FIXED_PLL] =3D &s4_fixed_pll.hw, + [CLKID_FCLK_DIV2_DIV] =3D &s4_fclk_div2_div.hw, + [CLKID_FCLK_DIV2] =3D &s4_fclk_div2.hw, + [CLKID_FCLK_DIV3_DIV] =3D &s4_fclk_div3_div.hw, + [CLKID_FCLK_DIV3] =3D &s4_fclk_div3.hw, + [CLKID_FCLK_DIV4_DIV] =3D &s4_fclk_div4_div.hw, + [CLKID_FCLK_DIV4] =3D &s4_fclk_div4.hw, + [CLKID_FCLK_DIV5_DIV] =3D &s4_fclk_div5_div.hw, + [CLKID_FCLK_DIV5] =3D &s4_fclk_div5.hw, + [CLKID_FCLK_DIV7_DIV] =3D &s4_fclk_div7_div.hw, + [CLKID_FCLK_DIV7] =3D &s4_fclk_div7.hw, + [CLKID_FCLK_DIV2P5_DIV] =3D &s4_fclk_div2p5_div.hw, + [CLKID_FCLK_DIV2P5] =3D &s4_fclk_div2p5.hw, + [CLKID_GP0_PLL_DCO] =3D &s4_gp0_pll_dco.hw, + [CLKID_GP0_PLL] =3D &s4_gp0_pll.hw, + [CLKID_HIFI_PLL_DCO] =3D &s4_hifi_pll_dco.hw, + [CLKID_HIFI_PLL] =3D &s4_hifi_pll.hw, + [CLKID_HDMI_PLL_DCO] =3D &s4_hdmi_pll_dco.hw, + [CLKID_HDMI_PLL_OD] =3D &s4_hdmi_pll_od.hw, + [CLKID_HDMI_PLL] =3D &s4_hdmi_pll.hw, + [CLKID_MPLL_50M_DIV] =3D &s4_mpll_50m_div.hw, + [CLKID_MPLL_50M] =3D &s4_mpll_50m.hw, + [CLKID_MPLL_PREDIV] =3D &s4_mpll_prediv.hw, + [CLKID_MPLL0_DIV] =3D &s4_mpll0_div.hw, + [CLKID_MPLL0] =3D &s4_mpll0.hw, + [CLKID_MPLL1_DIV] =3D &s4_mpll1_div.hw, + [CLKID_MPLL1] =3D &s4_mpll1.hw, + [CLKID_MPLL2_DIV] =3D &s4_mpll2_div.hw, + [CLKID_MPLL2] =3D &s4_mpll2.hw, + [CLKID_MPLL3_DIV] =3D &s4_mpll3_div.hw, + [CLKID_MPLL3] =3D &s4_mpll3.hw, +}; + +static struct clk_regmap *const s4_pll_clk_regmaps[] =3D { + &s4_fixed_pll_dco, + &s4_fixed_pll, + &s4_fclk_div2, + &s4_fclk_div3, + &s4_fclk_div4, + &s4_fclk_div5, + &s4_fclk_div7, + &s4_fclk_div2p5, + &s4_gp0_pll_dco, + &s4_gp0_pll, + &s4_hifi_pll_dco, + &s4_hifi_pll, + &s4_hdmi_pll_dco, + &s4_hdmi_pll_od, + &s4_hdmi_pll, + &s4_mpll_50m, + &s4_mpll0_div, + &s4_mpll0, + &s4_mpll1_div, + &s4_mpll1, + &s4_mpll2_div, + &s4_mpll2, + &s4_mpll3_div, + &s4_mpll3, +}; + +static const struct reg_sequence s4_init_regs[] =3D { + { .reg =3D ANACTRL_MPLL_CTRL0, .def =3D 0x00000543 }, +}; + +static struct regmap_config clkc_regmap_config =3D { + .reg_bits =3D 32, + .val_bits =3D 32, + .reg_stride =3D 4, +}; + +static struct meson_clk_hw_data s4_pll_clks =3D { + .hws =3D s4_pll_hw_clks, + .num =3D ARRAY_SIZE(s4_pll_hw_clks), +}; + +static int meson_s4_pll_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct regmap *regmap; + void __iomem *base; + int ret, i; + + base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return dev_err_probe(dev, PTR_ERR(base), + "can't ioremap resource\n"); + + regmap =3D devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "can't init regmap mmio region\n"); + + ret =3D regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_r= egs)); + if (ret) + return dev_err_probe(dev, ret, + "Failed to init registers\n"); + + /* Populate regmap for the regmap backed clocks */ + for (i =3D 0; i < ARRAY_SIZE(s4_pll_clk_regmaps); i++) + s4_pll_clk_regmaps[i]->map =3D regmap; + + /* Register clocks */ + for (i =3D 0; i < s4_pll_clks.num; i++) { + /* array might be sparse */ + if (!s4_pll_clks.hws[i]) + continue; + + ret =3D devm_clk_hw_register(dev, s4_pll_clks.hws[i]); + if (ret) + return dev_err_probe(dev, ret, + "clock[%d] registration failed\n", i); + } + + return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get, + &s4_pll_clks); +} + +static const struct of_device_id clkc_match_table[] =3D { + { + .compatible =3D "amlogic,s4-pll-clkc", + }, + {} +}; + +static struct platform_driver s4_driver =3D { + .probe =3D meson_s4_pll_probe, + .driver =3D { + .name =3D "s4-pll-clkc", + .of_match_table =3D clkc_match_table, + }, +}; + +module_platform_driver(s4_driver); +MODULE_AUTHOR("Yu Tu "); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/s4-pll.h b/drivers/clk/meson/s4-pll.h new file mode 100644 index 000000000000..ff7d58302f2a --- /dev/null +++ b/drivers/clk/meson/s4-pll.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved + * Author: Yu Tu + */ + +#ifndef __MESON_S4_PLL_H__ +#define __MESON_S4_PLL_H__ + +#define ANACTRL_FIXPLL_CTRL0 0x040 +#define ANACTRL_FIXPLL_CTRL1 0x044 +#define ANACTRL_FIXPLL_CTRL3 0x04c +#define ANACTRL_GP0PLL_CTRL0 0x080 +#define ANACTRL_GP0PLL_CTRL1 0x084 +#define ANACTRL_GP0PLL_CTRL2 0x088 +#define ANACTRL_GP0PLL_CTRL3 0x08c +#define ANACTRL_GP0PLL_CTRL4 0x090 +#define ANACTRL_GP0PLL_CTRL5 0x094 +#define ANACTRL_GP0PLL_CTRL6 0x098 +#define ANACTRL_HIFIPLL_CTRL0 0x100 +#define ANACTRL_HIFIPLL_CTRL1 0x104 +#define ANACTRL_HIFIPLL_CTRL2 0x108 +#define ANACTRL_HIFIPLL_CTRL3 0x10c +#define ANACTRL_HIFIPLL_CTRL4 0x110 +#define ANACTRL_HIFIPLL_CTRL5 0x114 +#define ANACTRL_HIFIPLL_CTRL6 0x118 +#define ANACTRL_MPLL_CTRL0 0x180 +#define ANACTRL_MPLL_CTRL1 0x184 +#define ANACTRL_MPLL_CTRL2 0x188 +#define ANACTRL_MPLL_CTRL3 0x18c +#define ANACTRL_MPLL_CTRL4 0x190 +#define ANACTRL_MPLL_CTRL5 0x194 +#define ANACTRL_MPLL_CTRL6 0x198 +#define ANACTRL_MPLL_CTRL7 0x19c +#define ANACTRL_MPLL_CTRL8 0x1a0 +#define ANACTRL_HDMIPLL_CTRL0 0x1c0 + +#endif /* __MESON_S4_PLL_H__ */ --=20 2.33.1