lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAGb2v65aMMVu8W1PW+6NZM+YM72YFV9_FWVWtj6QHJ1CgetEsA@mail.gmail.com>
Date: Sun, 25 Jan 2026 12:32:00 +0800
From: Chen-Yu Tsai <wens@...nel.org>
To: Junhui Liu <junhui.liu@...moral.tech>
Cc: Michael Turquette <mturquette@...libre.com>, Stephen Boyd <sboyd@...nel.org>, 
	Jernej Skrabec <jernej.skrabec@...il.com>, Samuel Holland <samuel@...lland.org>, 
	Alexandre Belloni <alexandre.belloni@...tlin.com>, Rob Herring <robh@...nel.org>, 
	Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley <conor+dt@...nel.org>, 
	Maxime Ripard <mripard@...nel.org>, linux-clk@...r.kernel.org, 
	linux-arm-kernel@...ts.infradead.org, linux-sunxi@...ts.linux.dev, 
	linux-kernel@...r.kernel.org, linux-rtc@...r.kernel.org, 
	devicetree@...r.kernel.org
Subject: Re: [PATCH 4/7] clk: sunxi-ng: Extract common RTC CCU clock logic

On Wed, Jan 21, 2026 at 7:04 PM Junhui Liu <junhui.liu@...moral.tech> wrote:
>
> Extract the IOSC and 32k clock logic from ccu-sun6i-rtc into a shared
> module to simplify adding RTC CCU support for new SoCs. This is needed
> because newer Allwinner SoCs introduce additional DCXO/HOSC logic that
> prevents direct reuse of the existing driver.
>
> Signed-off-by: Junhui Liu <junhui.liu@...moral.tech>
> ---
>  drivers/clk/sunxi-ng/Makefile        |   3 +
>  drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 152 +----------------------------------
>  drivers/clk/sunxi-ng/ccu_rtc.c       | 136 +++++++++++++++++++++++++++++++
>  drivers/clk/sunxi-ng/ccu_rtc.h       |  37 +++++++++
>  4 files changed, 177 insertions(+), 151 deletions(-)
>
> diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
> index a1c4087d7241..c3f810a025a8 100644
> --- a/drivers/clk/sunxi-ng/Makefile
> +++ b/drivers/clk/sunxi-ng/Makefile
> @@ -23,6 +23,9 @@ sunxi-ccu-y                   += ccu_nkmp.o
>  sunxi-ccu-y                    += ccu_nm.o
>  sunxi-ccu-y                    += ccu_mp.o
>
> +# RTC clocks
> +sunxi-ccu-y                    += ccu_rtc.o
> +
>  # SoC support
>  obj-$(CONFIG_SUNIV_F1C100S_CCU)        += suniv-f1c100s-ccu.o
>  obj-$(CONFIG_SUN20I_D1_CCU)    += sun20i-d1-ccu.o
> diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> index 6f888169412c..562ba752bcec 100644
> --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c
> @@ -14,37 +14,12 @@
>
>  #include "ccu_common.h"
>
> -#include "ccu_div.h"
>  #include "ccu_gate.h"
>  #include "ccu_mux.h"
> +#include "ccu_rtc.h"
>
>  #include "ccu-sun6i-rtc.h"
>
> -#define IOSC_ACCURACY                  300000000 /* 30% */
> -#define IOSC_RATE                      16000000
> -
> -#define LOSC_RATE                      32768
> -#define LOSC_RATE_SHIFT                        15
> -
> -#define LOSC_CTRL_REG                  0x0
> -#define LOSC_CTRL_KEY                  0x16aa0000
> -
> -#define IOSC_32K_CLK_DIV_REG           0x8
> -#define IOSC_32K_CLK_DIV               GENMASK(4, 0)
> -#define IOSC_32K_PRE_DIV               32
> -
> -#define IOSC_CLK_CALI_REG              0xc
> -#define IOSC_CLK_CALI_DIV_ONES         22
> -#define IOSC_CLK_CALI_EN               BIT(1)
> -#define IOSC_CLK_CALI_SRC_SEL          BIT(0)
> -
> -#define LOSC_OUT_GATING_REG            0x60
> -
> -#define DCXO_CTRL_REG                  0x160
> -#define DCXO_CTRL_CLK16M_RC_EN         BIT(0)
> -
> -#define SUN6I_RTC_AUX_ID(_name)                "rtc_sun6i." #_name
> -
>  struct sun6i_rtc_match_data {
>         bool                            have_ext_osc32k         : 1;
>         bool                            have_iosc_calibration   : 1;
> @@ -53,137 +28,12 @@ struct sun6i_rtc_match_data {
>         u8                              osc32k_fanout_nparents;
>  };
>
> -static int ccu_iosc_enable(struct clk_hw *hw)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -
> -       return ccu_gate_helper_enable(cm, DCXO_CTRL_CLK16M_RC_EN);
> -}
> -
> -static void ccu_iosc_disable(struct clk_hw *hw)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -
> -       return ccu_gate_helper_disable(cm, DCXO_CTRL_CLK16M_RC_EN);
> -}
> -
> -static int ccu_iosc_is_enabled(struct clk_hw *hw)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -
> -       return ccu_gate_helper_is_enabled(cm, DCXO_CTRL_CLK16M_RC_EN);
> -}
> -
> -static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
> -                                         unsigned long parent_rate)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -
> -       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> -               u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
> -
> -               /*
> -                * Recover the IOSC frequency by shifting the ones place of
> -                * (fixed-point divider * 32768) into bit zero.
> -                */
> -               if (reg & IOSC_CLK_CALI_EN)
> -                       return reg >> (IOSC_CLK_CALI_DIV_ONES - LOSC_RATE_SHIFT);
> -       }
> -
> -       return IOSC_RATE;
> -}
> -
> -static unsigned long ccu_iosc_recalc_accuracy(struct clk_hw *hw,
> -                                             unsigned long parent_accuracy)
> -{
> -       return IOSC_ACCURACY;
> -}
> -
> -static const struct clk_ops ccu_iosc_ops = {
> -       .enable                 = ccu_iosc_enable,
> -       .disable                = ccu_iosc_disable,
> -       .is_enabled             = ccu_iosc_is_enabled,
> -       .recalc_rate            = ccu_iosc_recalc_rate,
> -       .recalc_accuracy        = ccu_iosc_recalc_accuracy,
> -};
> -
>  static struct ccu_common iosc_clk = {
>         .reg            = DCXO_CTRL_REG,
>         .hw.init        = CLK_HW_INIT_NO_PARENT("iosc", &ccu_iosc_ops,
>                                                 CLK_GET_RATE_NOCACHE),
>  };
>
> -static int ccu_iosc_32k_prepare(struct clk_hw *hw)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -       u32 val;
> -
> -       if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
> -               return 0;
> -
> -       val = readl(cm->base + IOSC_CLK_CALI_REG);
> -       writel(val | IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL,
> -              cm->base + IOSC_CLK_CALI_REG);
> -
> -       return 0;
> -}
> -
> -static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -       u32 val;
> -
> -       if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
> -               return;
> -
> -       val = readl(cm->base + IOSC_CLK_CALI_REG);
> -       writel(val & ~(IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL),
> -              cm->base + IOSC_CLK_CALI_REG);
> -}
> -
> -static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
> -                                             unsigned long parent_rate)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -       u32 val;
> -
> -       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> -               val = readl(cm->base + IOSC_CLK_CALI_REG);
> -
> -               /* Assume the calibrated 32k clock is accurate. */
> -               if (val & IOSC_CLK_CALI_SRC_SEL)
> -                       return LOSC_RATE;
> -       }
> -
> -       val = readl(cm->base + IOSC_32K_CLK_DIV_REG) & IOSC_32K_CLK_DIV;
> -
> -       return parent_rate / IOSC_32K_PRE_DIV / (val + 1);
> -}
> -
> -static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
> -                                                 unsigned long parent_accuracy)
> -{
> -       struct ccu_common *cm = hw_to_ccu_common(hw);
> -       u32 val;
> -
> -       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> -               val = readl(cm->base + IOSC_CLK_CALI_REG);
> -
> -               /* Assume the calibrated 32k clock is accurate. */
> -               if (val & IOSC_CLK_CALI_SRC_SEL)
> -                       return 0;
> -       }
> -
> -       return parent_accuracy;
> -}
> -
> -static const struct clk_ops ccu_iosc_32k_ops = {
> -       .prepare                = ccu_iosc_32k_prepare,
> -       .unprepare              = ccu_iosc_32k_unprepare,
> -       .recalc_rate            = ccu_iosc_32k_recalc_rate,
> -       .recalc_accuracy        = ccu_iosc_32k_recalc_accuracy,
> -};
> -
>  static struct ccu_common iosc_32k_clk = {
>         .hw.init        = CLK_HW_INIT_HW("iosc-32k", &iosc_clk.hw,
>                                          &ccu_iosc_32k_ops,
> diff --git a/drivers/clk/sunxi-ng/ccu_rtc.c b/drivers/clk/sunxi-ng/ccu_rtc.c
> new file mode 100644
> index 000000000000..cfc10218517c
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu_rtc.c
> @@ -0,0 +1,136 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2021 Samuel Holland <samuel@...lland.org>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +
> +#include "ccu_common.h"
> +
> +#include "ccu_gate.h"
> +#include "ccu_rtc.h"
> +
> +static int ccu_iosc_enable(struct clk_hw *hw)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +
> +       return ccu_gate_helper_enable(cm, DCXO_CTRL_CLK16M_RC_EN);
> +}
> +
> +static void ccu_iosc_disable(struct clk_hw *hw)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +
> +       return ccu_gate_helper_disable(cm, DCXO_CTRL_CLK16M_RC_EN);
> +}
> +
> +static int ccu_iosc_is_enabled(struct clk_hw *hw)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +
> +       return ccu_gate_helper_is_enabled(cm, DCXO_CTRL_CLK16M_RC_EN);
> +}
> +
> +static unsigned long ccu_iosc_recalc_rate(struct clk_hw *hw,
> +                                         unsigned long parent_rate)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +
> +       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> +               u32 reg = readl(cm->base + IOSC_CLK_CALI_REG);
> +               /*
> +                * Recover the IOSC frequency by shifting the ones place of
> +                * (fixed-point divider * 32768) into bit zero.
> +                */
> +               if (reg & IOSC_CLK_CALI_EN)
> +                       return reg >> (IOSC_CLK_CALI_DIV_ONES - LOSC_RATE_SHIFT);
> +       }
> +
> +       return IOSC_RATE;
> +}
> +
> +static unsigned long ccu_iosc_recalc_accuracy(struct clk_hw *hw,
> +                                             unsigned long parent_accuracy)
> +{
> +       return IOSC_ACCURACY;
> +}
> +
> +const struct clk_ops ccu_iosc_ops = {
> +       .enable                 = ccu_iosc_enable,
> +       .disable                = ccu_iosc_disable,
> +       .is_enabled             = ccu_iosc_is_enabled,
> +       .recalc_rate            = ccu_iosc_recalc_rate,
> +       .recalc_accuracy        = ccu_iosc_recalc_accuracy,
> +};

You need to export the symbol.

> +
> +static int ccu_iosc_32k_prepare(struct clk_hw *hw)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +       u32 val;
> +
> +       if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
> +               return 0;
> +
> +       val = readl(cm->base + IOSC_CLK_CALI_REG);
> +       writel(val | IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL,
> +              cm->base + IOSC_CLK_CALI_REG);
> +
> +       return 0;
> +}
> +
> +static void ccu_iosc_32k_unprepare(struct clk_hw *hw)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +       u32 val;
> +
> +       if (!(cm->features & CCU_FEATURE_IOSC_CALIBRATION))
> +               return;
> +
> +       val = readl(cm->base + IOSC_CLK_CALI_REG);
> +       writel(val & ~(IOSC_CLK_CALI_EN | IOSC_CLK_CALI_SRC_SEL),
> +              cm->base + IOSC_CLK_CALI_REG);
> +}
> +
> +static unsigned long ccu_iosc_32k_recalc_rate(struct clk_hw *hw,
> +                                             unsigned long parent_rate)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +       u32 val;
> +
> +       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> +               val = readl(cm->base + IOSC_CLK_CALI_REG);
> +
> +               /* Assume the calibrated 32k clock is accurate. */
> +               if (val & IOSC_CLK_CALI_SRC_SEL)
> +                       return LOSC_RATE;
> +       }
> +
> +       val = readl(cm->base + IOSC_32K_CLK_DIV_REG) & IOSC_32K_CLK_DIV;
> +
> +       return parent_rate / IOSC_32K_PRE_DIV / (val + 1);
> +}
> +
> +static unsigned long ccu_iosc_32k_recalc_accuracy(struct clk_hw *hw,
> +                                                 unsigned long parent_accuracy)
> +{
> +       struct ccu_common *cm = hw_to_ccu_common(hw);
> +       u32 val;
> +
> +       if (cm->features & CCU_FEATURE_IOSC_CALIBRATION) {
> +               val = readl(cm->base + IOSC_CLK_CALI_REG);
> +
> +               /* Assume the calibrated 32k clock is accurate. */
> +               if (val & IOSC_CLK_CALI_SRC_SEL)
> +                       return 0;
> +       }
> +
> +       return parent_accuracy;
> +}
> +
> +const struct clk_ops ccu_iosc_32k_ops = {
> +       .prepare                = ccu_iosc_32k_prepare,
> +       .unprepare              = ccu_iosc_32k_unprepare,
> +       .recalc_rate            = ccu_iosc_32k_recalc_rate,
> +       .recalc_accuracy        = ccu_iosc_32k_recalc_accuracy,
> +};

Same here.

> diff --git a/drivers/clk/sunxi-ng/ccu_rtc.h b/drivers/clk/sunxi-ng/ccu_rtc.h
> new file mode 100644
> index 000000000000..1c44c2206a25
> --- /dev/null
> +++ b/drivers/clk/sunxi-ng/ccu_rtc.h
> @@ -0,0 +1,37 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2021 Samuel Holland <samuel@...lland.org>
> + */
> +
> +#ifndef _CCU_RTC_H_
> +#define _CCU_RTC_H_
> +
> +#define IOSC_ACCURACY                  300000000 /* 30% */
> +#define IOSC_RATE                      16000000
> +
> +#define LOSC_RATE                      32768
> +#define LOSC_RATE_SHIFT                        15
> +
> +#define LOSC_CTRL_REG                  0x0
> +#define LOSC_CTRL_KEY                  0x16aa0000
> +
> +#define IOSC_32K_CLK_DIV_REG           0x8
> +#define IOSC_32K_CLK_DIV               GENMASK(4, 0)
> +#define IOSC_32K_PRE_DIV               32
> +
> +#define IOSC_CLK_CALI_REG              0xc
> +#define IOSC_CLK_CALI_DIV_ONES         22
> +#define IOSC_CLK_CALI_EN               BIT(1)
> +#define IOSC_CLK_CALI_SRC_SEL          BIT(0)
> +
> +#define LOSC_OUT_GATING_REG            0x60
> +
> +#define DCXO_CTRL_REG                  0x160
> +#define DCXO_CTRL_CLK16M_RC_EN         BIT(0)

Please keep all internals in the .c file.

ChenYu


> +
> +#define SUN6I_RTC_AUX_ID(_name)                "rtc_sun6i." #_name
> +
> +extern const struct clk_ops ccu_iosc_ops;
> +extern const struct clk_ops ccu_iosc_32k_ops;
> +
> +#endif /* _CCU_RTC_H_ */
>
> --
> 2.52.0
>
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ