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: <20260121-a733-rtc-v1-4-d359437f23a7@pigmoral.tech>
Date: Wed, 21 Jan 2026 18:59:10 +0800
From: Junhui Liu <junhui.liu@...moral.tech>
To: Michael Turquette <mturquette@...libre.com>, 
 Stephen Boyd <sboyd@...nel.org>, Chen-Yu Tsai <wens@...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>
Cc: 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, 
 Junhui Liu <junhui.liu@...moral.tech>
Subject: [PATCH 4/7] clk: sunxi-ng: Extract common RTC CCU clock logic

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,
+};
+
+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,
+};
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)
+
+#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