From nobody Mon Sep 15 07:47:09 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 06078C46467 for ; Mon, 16 Jan 2023 08:00:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232169AbjAPIAT (ORCPT ); Mon, 16 Jan 2023 03:00:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33352 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229930AbjAPIAH (ORCPT ); Mon, 16 Jan 2023 03:00:07 -0500 Received: from mail-sh.amlogic.com (mail-sh.amlogic.com [58.32.228.43]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B92B510AA6; Sun, 15 Jan 2023 23:59:19 -0800 (PST) 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, 16 Jan 2023 15:44:14 +0800 From: Yu Tu To: , , , , , Rob Herring , "Neil Armstrong" , Jerome Brunet , Kevin Hilman , Michael Turquette , Stephen Boyd , "Krzysztof Kozlowski" , Martin Blumenstingl CC: "kelvin . zhang" , "qi . duan" , Yu Tu Subject: [PATCH V6 2/3] clk: meson: S4: add support for Amlogic S4 SoC PLL clock driver Date: Mon, 16 Jan 2023 15:42:13 +0800 Message-ID: <20230116074214.2326-3-yu.tu@amlogic.com> X-Mailer: git-send-email 2.33.1 In-Reply-To: <20230116074214.2326-1-yu.tu@amlogic.com> References: <20230116074214.2326-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 | 13 + drivers/clk/meson/Makefile | 1 + drivers/clk/meson/s4-pll.c | 875 +++++++++++++++++++++++++++++++++++++ drivers/clk/meson/s4-pll.h | 88 ++++ 4 files changed, 977 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 fc002c155bc3..a663c90a3f3b 100644 --- a/drivers/clk/meson/Kconfig +++ b/drivers/clk/meson/Kconfig @@ -115,4 +115,17 @@ 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. Amlogic S805X2 and S905Y4 devices include AQ222 and AQ229. + Say Y if you want the board to work, because plls are the parent of most + peripherals. endmenu diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile index 6eca2a406ee3..376f49cc13f1 100644 --- a/drivers/clk/meson/Makefile +++ b/drivers/clk/meson/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) +=3D axg-audio.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..227d4fd7547d --- /dev/null +++ b/drivers/clk/meson/s4-pll.c @@ -0,0 +1,875 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Amlogic Meson-S4 PLL Clock Controller Driver + * + * Copyright (c) 2021 Amlogic, inc. + * Author: Yu Tu + */ + +#include +#include +#include + +#include "clk-mpll.h" +#include "clk-pll.h" +#include "clk-regmap.h" +#include "s4-pll.h" + +static DEFINE_SPINLOCK(meson_clk_lock); + +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, + }, + .frac =3D { + .reg_off =3D ANACTRL_FIXPLL_CTRL1, + .shift =3D 0, + .width =3D 17, + }, + .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, + }, + .frac =3D { + .reg_off =3D ANACTRL_GP0PLL_CTRL1, + .shift =3D 0, + .width =3D 17, + }, + .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, + }, + .frac =3D { + .reg_off =3D ANACTRL_HIFIPLL_CTRL1, + .shift =3D 0, + .width =3D 17, + }, + .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, + }, + .frac =3D { + .reg_off =3D ANACTRL_HDMIPLL_CTRL1, + .shift =3D 0, + .width =3D 17, + }, + .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_onecell_data s4_pll_hw_onecell_data =3D { + .hws =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, + [NR_PLL_CLKS] =3D NULL + }, + .num =3D NR_PLL_CLKS, +}; + +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 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 PTR_ERR(base); + + regmap =3D devm_regmap_init_mmio(dev, base, &clkc_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret =3D regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_r= egs)); + if (ret) { + dev_err(dev, "Failed to init registers\n"); + return ret; + } + + /* 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; + + for (i =3D 0; i < s4_pll_hw_onecell_data.num; i++) { + /* array might be sparse */ + if (!s4_pll_hw_onecell_data.hws[i]) + continue; + + ret =3D devm_clk_hw_register(dev, s4_pll_hw_onecell_data.hws[i]); + if (ret) { + dev_err(dev, "Clock registration failed\n"); + return ret; + } + } + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + &s4_pll_hw_onecell_data); +} + +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_LICENSE("GPL"); diff --git a/drivers/clk/meson/s4-pll.h b/drivers/clk/meson/s4-pll.h new file mode 100644 index 000000000000..332f2d7b94b4 --- /dev/null +++ b/drivers/clk/meson/s4-pll.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ +/* + * Copyright (c) 2021 Amlogic, inc. + * Author: Yu Tu + */ + +#ifndef __MESON_S4_PLL_H__ +#define __MESON_S4_PLL_H__ + +/* ANA_CTRL - Registers + * REG_BASE: REGISTER_BASE_ADDR =3D 0xfe008000 + */ +#define ANACTRL_FIXPLL_CTRL0 0x040 +#define ANACTRL_FIXPLL_CTRL1 0x044 +#define ANACTRL_FIXPLL_CTRL2 0x048 +#define ANACTRL_FIXPLL_CTRL3 0x04c +#define ANACTRL_FIXPLL_CTRL4 0x050 +#define ANACTRL_FIXPLL_CTRL5 0x054 +#define ANACTRL_FIXPLL_CTRL6 0x058 +#define ANACTRL_FIXPLL_STS 0x05c +#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_GP0PLL_STS 0x09c +#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_HIFIPLL_STS 0x11c +#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_MPLL_STS 0x1a4 +#define ANACTRL_HDMIPLL_CTRL0 0x1c0 +#define ANACTRL_HDMIPLL_CTRL1 0x1c4 +#define ANACTRL_HDMIPLL_CTRL2 0x1c8 +#define ANACTRL_HDMIPLL_CTRL3 0x1cc +#define ANACTRL_HDMIPLL_CTRL4 0x1d0 +#define ANACTRL_HDMIPLL_CTRL5 0x1d4 +#define ANACTRL_HDMIPLL_CTRL6 0x1d8 +#define ANACTRL_HDMIPLL_STS 0x1dc +#define ANACTRL_HDMIPLL_VLOCK 0x1e4 + +/* + * 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 heade= r: + * include/dt-bindings/clock/axg-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 4 +#define CLKID_FCLK_DIV4_DIV 6 +#define CLKID_FCLK_DIV5_DIV 8 +#define CLKID_FCLK_DIV7_DIV 10 +#define CLKID_FCLK_DIV2P5_DIV 12 +#define CLKID_GP0_PLL_DCO 14 +#define CLKID_HIFI_PLL_DCO 16 +#define CLKID_HDMI_PLL_DCO 18 +#define CLKID_HDMI_PLL_OD 19 +#define CLKID_MPLL_50M_DIV 21 +#define CLKID_MPLL_PREDIV 23 +#define CLKID_MPLL0_DIV 24 +#define CLKID_MPLL1_DIV 26 +#define CLKID_MPLL2_DIV 28 +#define CLKID_MPLL3_DIV 30 + +#define NR_PLL_CLKS 32 +/* include the CLKIDs that have been made part of the DT binding */ +#include + +#endif /* __MESON_S4_PLL_H__ */ --=20 2.33.1