From patchwork Fri Sep 25 22:51:09 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 3466 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114]) by mxe881.netcup.net (Postfix) with ESMTPS id DF7CC1C1CCD for ; Sat, 26 Sep 2026 00:56:14 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=arm.com; spf=pass (sender IP is 172.105.105.114) smtp.mailfrom=linux-sunxi+bounces-26256-noreply=patchwork.local@lists.linux.dev smtp.helo=tor.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.105.105.114 as permitted sender) client-ip=172.105.105.114; envelope-from=linux-sunxi+bounces-26256-noreply=patchwork.local@lists.linux.dev; helo=tor.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by tor.lore.kernel.org (Postfix) with ESMTP id D54982C62D for ; Fri, 25 Sep 2026 22:56:13 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8836A4E1C77; Fri, 25 Sep 2026 22:56:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="jHrRAf/Q" X-Original-To: linux-sunxi@lists.linux.dev Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D258950AC32 for ; Fri, 25 Sep 2026 22:56:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376972; cv=none; b=o1zoRwJNcJjvC8zN7D2q0aTX4SvTpa105Vucn6/w102wU+3D+XrVRmt/Il3cAiWY3E/5x5hv0lVXwBxOaWtGiNexvKuhCUz398IVxfxYLWrOh/Kc/obdpxO0obWuUX7/4CUKizMh7acwkPI6cwcbSDkwdndEz/orIoZ7enTAp3k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376972; c=relaxed/simple; bh=MlmHbpVFjJLWGpCkIIoq1m9CmdLtsfdILAJsxbN9izA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=S6QpWiZ4xugiK/4CG5ZMZuZbKZ7aBdBED6WvlJrFh+qz6g8qBlZDRa98ZswNxjdLCRUVMjc6vdkx87rvaYlbAfUaCIFR+DrY31mXZGB9YQj6Me7EYdwwv3fNBo5rR6EU3FQQKzinWgr442CndP20o/Bx8SS45tvkCW3BkMd5lyg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=jHrRAf/Q; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A050316F8; Fri, 25 Sep 2026 15:56:03 -0700 (PDT) Received: from ryzen.fritz.box (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6C1513F632; Fri, 25 Sep 2026 15:56:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1790376967; bh=MlmHbpVFjJLWGpCkIIoq1m9CmdLtsfdILAJsxbN9izA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jHrRAf/QNu3dWT2v5NDeRgaWI2YshsmDD2WOOoKb/THbvwrImfDa2Q/5Fh4LLNdOD AsLwpOsII+XDn0B6HLC41GI21dDHBh4eM4T6XBTOEZxMlDDfFBQ8rErBywqixOmBux 3zmLHY600OzYMCQD3r7USdKOcKbuyA+IhaTcf7VM= From: Andre Przywara To: Stephen Boyd , Brian Masney , Jerome Brunet , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Subject: [PATCH v3 1/4] clk: sunxi-ng: generalise update bit Date: Sat, 26 Sep 2026 00:51:09 +0200 Message-ID: <20260925225112.14081-2-andre.przywara@arm.com> X-Mailer: git-send-email 2.46.4 In-Reply-To: <20260925225112.14081-1-andre.przywara@arm.com> References: <20260925225112.14081-1-andre.przywara@arm.com> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Rspamd-Server: rspamd-worker-8404 X-Spamd-Result: default: False [-0.66 / 15.00]; BAYES_HAM(-5.50)[100.00%]; RBL_SENDERSCORE(2.00)[172.105.105.114:from]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; MAILLIST(-0.15)[generic]; BAD_REP_POLICIES(0.10)[]; MIME_GOOD(-0.10)[text/plain]; HAS_LIST_UNSUB(-0.01)[]; TAGGED_RCPT(0.00)[clk,dt]; FROM_HAS_DN(0.00)[]; PRECEDENCE_BULK(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[tor.lore.kernel.org:rdns,tor.lore.kernel.org:helo,arm.com:email,arm.com:dkim]; RCPT_COUNT_TWELVE(0.00)[13]; FORGED_SENDER_MAILLIST(0.00)[]; R_DKIM_ALLOW(0.00)[arm.com:s=foss]; FROM_NEQ_ENVFROM(0.00)[andre.przywara@arm.com,linux-sunxi@lists.linux.dev]; ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1]; DKIM_TRACE(0.00)[arm.com:+]; DMARC_POLICY_ALLOW(0.00)[arm.com,none]; R_SPF_ALLOW(0.00)[+ip4:172.105.105.114]; RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[100.90.174.1:received,217.140.110.172:received]; TO_DN_SOME(0.00)[]; RCVD_COUNT_FIVE(0.00)[6]; FREEMAIL_TO(0.00)[kernel.org,redhat.com,baylibre.com,gmail.com,sholland.org]; MIME_TRACE(0.00)[0:+]; TAGGED_FROM(0.00)[bounces-26256-noreply=patchwork.local]; FORGED_RECIPIENTS_MAILLIST(0.00)[]; ASN(0.00)[asn:63949, ipnet:172.105.96.0/20, country:SG]; RCVD_TLS_LAST(0.00)[]; RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[172.105.105.114:from] X-Rspamd-Queue-Id: DF7CC1C1CCD X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= A few of the Allwinner A523 CCU clock registers introduced an "update" bit, which must be set for changes to the other bits to take effect. Of the three clocks where this was used, it was always bit 27, so we just encoded this as a single bit feature flag. Now the CPU PLL also features the update bit, but puts it at bit 26, so this flag trick won't work anymore. Add an "update_bit" field to the common sunxi clock struct, which takes a bitmask, so we can encode any bit to use, even potentially multiple of them. As uninitialised fields are set to 0, we can use this as a default bitmask to set, so can OR this in unconditionally. It turns out that the "update key" feature is doing something very similar, so just convert it over to also use this same bitmask approach. Change the existing update bit users to use this new encoding, and add support for the ccu_nm clock on the way, since we will need it there shortly. Signed-off-by: Andre Przywara Reviewed-by: Chen-Yu Tsai --- drivers/clk/sunxi-ng/ccu-sun55i-a523.c | 12 ++++++------ drivers/clk/sunxi-ng/ccu-sun6i-rtc.c | 4 ++-- drivers/clk/sunxi-ng/ccu_common.h | 8 +++----- drivers/clk/sunxi-ng/ccu_div.c | 3 +-- drivers/clk/sunxi-ng/ccu_gate.c | 6 ++---- drivers/clk/sunxi-ng/ccu_mp.h | 8 +++++--- drivers/clk/sunxi-ng/ccu_mux.c | 8 +------- drivers/clk/sunxi-ng/ccu_nm.c | 1 + 8 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c index 20dad06b37ca3..35cddab0749b3 100644 --- a/drivers/clk/sunxi-ng/ccu-sun55i-a523.c +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523.c @@ -386,8 +386,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(mbus_clk, "mbus", mbus_parents, 0, 0, /* no P */ 24, 3, /* mux */ BIT(31), /* gate */ - CLK_IS_CRITICAL, - CCU_FEATURE_UPDATE_BIT); + BIT(27), /* update*/ + CLK_IS_CRITICAL, 0); static const struct clk_hw *mbus_hws[] = { &mbus_clk.common.hw }; @@ -590,8 +590,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(iommu_clk, "iommu", iommu_parents, 0, 0, /* no P */ 24, 3, /* mux */ BIT(31), /* gate */ - CLK_SET_RATE_PARENT, - CCU_FEATURE_UPDATE_BIT); + BIT(27), /* update */ + CLK_SET_RATE_PARENT, 0); static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", apb0_hws, 0x7bc, BIT(0), 0); @@ -609,8 +609,8 @@ static SUNXI_CCU_MP_DATA_WITH_MUX_GATE_FEAT(dram_clk, "dram", dram_parents, 0, 0, /* no P */ 24, 3, /* mux */ BIT(31), /* gate */ - CLK_IS_CRITICAL, - CCU_FEATURE_UPDATE_BIT); + BIT(27), /* update*/ + CLK_IS_CRITICAL, 0); static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws, 0x804, BIT(0), 0); diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c index 98ae10307f438..dde56529f281d 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-rtc.c @@ -214,7 +214,7 @@ static struct ccu_mux osc32k_clk = { .mux = _SUNXI_CCU_MUX(0, 1), .common = { .reg = LOSC_CTRL_REG, - .features = CCU_FEATURE_KEY_FIELD, + .update_bits = CCU_MUX_KEY_VALUE, .hw.init = &osc32k_init_data, }, }; @@ -280,7 +280,7 @@ static struct ccu_mux rtc_32k_clk = { .mux = _SUNXI_CCU_MUX(1, 1), .common = { .reg = LOSC_CTRL_REG, - .features = CCU_FEATURE_KEY_FIELD, + .update_bits = CCU_MUX_KEY_VALUE, .hw.init = &rtc_32k_init_data, }, }; diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index d9dc24ad55039..e0ed861735beb 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -17,17 +17,14 @@ #define CCU_FEATURE_LOCK_REG BIT(5) #define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6) #define CCU_FEATURE_SIGMA_DELTA_MOD BIT(7) -#define CCU_FEATURE_KEY_FIELD BIT(8) #define CCU_FEATURE_CLOSEST_RATE BIT(9) #define CCU_FEATURE_DUAL_DIV BIT(10) -#define CCU_FEATURE_UPDATE_BIT BIT(11) -#define CCU_FEATURE_IOSC_CALIBRATION BIT(12) +#define CCU_FEATURE_IOSC_CALIBRATION BIT(11) /* MMC timing mode switch bit */ #define CCU_MMC_NEW_TIMING_MODE BIT(30) -/* Some clocks need this bit to actually apply register changes */ -#define CCU_SUNXI_UPDATE_BIT BIT(27) +#define CCU_MUX_KEY_VALUE 0x16aa0000 struct device_node; @@ -36,6 +33,7 @@ struct ccu_common { u16 reg; u16 lock_reg; u32 prediv; + u32 update_bits; unsigned long min_rate; unsigned long max_rate; diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index c385e0160f13b..a6e81bac18d6e 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -119,8 +119,7 @@ static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate, reg = readl(cd->common.base + cd->common.reg); reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift); - if (cd->common.features & CCU_FEATURE_UPDATE_BIT) - reg |= CCU_SUNXI_UPDATE_BIT; + reg |= cd->common.update_bits; writel(reg | (val << cd->div.shift), cd->common.base + cd->common.reg); diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c index 30673fe4e3c2c..532e661b5f4b1 100644 --- a/drivers/clk/sunxi-ng/ccu_gate.c +++ b/drivers/clk/sunxi-ng/ccu_gate.c @@ -20,8 +20,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate) spin_lock_irqsave(common->lock, flags); reg = readl(common->base + common->reg); - if (common->features & CCU_FEATURE_UPDATE_BIT) - reg |= CCU_SUNXI_UPDATE_BIT; + reg |= common->update_bits; writel(reg & ~gate, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); @@ -46,8 +45,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate) spin_lock_irqsave(common->lock, flags); reg = readl(common->base + common->reg); - if (common->features & CCU_FEATURE_UPDATE_BIT) - reg |= CCU_SUNXI_UPDATE_BIT; + reg |= common->update_bits; writel(reg | gate, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index bb09c649bfa35..6ebb48438b5d4 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -131,7 +131,8 @@ struct ccu_mp { _mshift, _mwidth, \ _pshift, _pwidth, \ _muxshift, _muxwidth, \ - _gate, _flags, _features) \ + _gate, _key_update, \ + _flags, _features) \ struct ccu_mp _struct = { \ .enable = _gate, \ .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ @@ -140,6 +141,7 @@ struct ccu_mp { .common = { \ .reg = _reg, \ .features = _features, \ + .update_bits = _key_update, \ .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ _parents, \ &ccu_mp_ops, \ @@ -156,7 +158,7 @@ struct ccu_mp { _reg, _mshift, _mwidth, \ _pshift, _pwidth, \ _muxshift, _muxwidth, \ - _gate, _flags, 0) + _gate, 0, _flags, 0) #define SUNXI_CCU_DUALDIV_MUX_GATE(_struct, _name, _parents, _reg, \ _mshift, _mwidth, \ @@ -167,7 +169,7 @@ struct ccu_mp { _reg, _mshift, _mwidth, \ _pshift, _pwidth, \ _muxshift, _muxwidth, \ - _gate, _flags, \ + _gate, 0, _flags, \ CCU_FEATURE_DUAL_DIV) #define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 4503c9780c39f..3bb2ba5e809a3 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -12,8 +12,6 @@ #include "ccu_gate.h" #include "ccu_mux.h" -#define CCU_MUX_KEY_VALUE 0x16aa0000 - static u16 ccu_mux_get_prediv(struct ccu_common *common, struct ccu_mux_internal *cm, int parent_index) @@ -203,11 +201,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common, reg = readl(common->base + common->reg); - /* The key field always reads as zero. */ - if (common->features & CCU_FEATURE_KEY_FIELD) - reg |= CCU_MUX_KEY_VALUE; - if (common->features & CCU_FEATURE_UPDATE_BIT) - reg |= CCU_SUNXI_UPDATE_BIT; + reg |= common->update_bits; reg &= ~GENMASK(cm->width + cm->shift - 1, cm->shift); writel(reg | (index << cm->shift), common->base + common->reg); diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index df01ed3b37a6b..80aad0650f348 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -219,6 +219,7 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, reg |= (_nm.n - nm->n.offset) << nm->n.shift; reg |= (_nm.m - nm->m.offset) << nm->m.shift; + reg |= nm->common.update_bits; writel(reg, nm->common.base + nm->common.reg); spin_unlock_irqrestore(nm->common.lock, flags); From patchwork Fri Sep 25 22:51:10 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 3468 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id 5B0A51C1C7C for ; Sat, 26 Sep 2026 00:57:24 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=arm.com; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-26257-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-26257-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 141C2407E0 for ; Fri, 25 Sep 2026 22:56:16 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7E8CE509F04; Fri, 25 Sep 2026 22:56:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="ch2MCgeR" X-Original-To: linux-sunxi@lists.linux.dev Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8A4C8501F42 for ; Fri, 25 Sep 2026 22:56:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376975; cv=none; b=dR1/2agm5D+/I3jBzFYLcjw1T+JkBs2NfcPJpbHycsbvr1NuIdNPcvZ4p3BqwzWktaKdSd4d5NZVHaKVyTgfEH7DzjDwL0lIBIfXlR8p51+/K+kLwRliUFG7wK/CGudQH7GLlmIh5hKYa2tivDB136W1xaKufYFEuUzCBLhDfmo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376975; c=relaxed/simple; bh=3blP0nDMtGN6vIpTbQx5TZFpZ7wvhmdDuk7aLl94D6A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=faW4z6s+N6/N5/9LSbk24Q2DuhSO1hLoS3mKFaHuaS+LgYrRpCqqX5UyA8Q6S4VkbQ4tEdhEa/96KtXlZe6y7t17IULgYraeU420RWSDLjsnfj/1ajUg65XTPDz8zBehBqoZ8nXT6zhfk7hNdbnDISQG4hrRXL7oTfzLkn6S4qs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=ch2MCgeR; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D055C169C; Fri, 25 Sep 2026 15:56:06 -0700 (PDT) Received: from ryzen.fritz.box (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 847D13F632; Fri, 25 Sep 2026 15:56:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1790376970; bh=3blP0nDMtGN6vIpTbQx5TZFpZ7wvhmdDuk7aLl94D6A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ch2MCgeRNQuiON+68rcbbb1+lleArxnuaZiRb/vxJl69WhNsvrBnGE+afWZP6d3kr 9qlTxF4HXyAlE1Xfi8rwBIGbAT4phq4kPTy/oj4mLFMjpF1aRl061uZus9VuNiObNr B4LXW0zlGp+GmcFVxcBoJTW+nZCvvglCa2NTgctk= From: Andre Przywara To: Stephen Boyd , Brian Masney , Jerome Brunet , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Subject: [PATCH v3 2/4] dt-bindings: clock: sun55i-a523-ccu: Add A523 CPU CCU clock controller Date: Sat, 26 Sep 2026 00:51:10 +0200 Message-ID: <20260925225112.14081-3-andre.przywara@arm.com> X-Mailer: git-send-email 2.46.4 In-Reply-To: <20260925225112.14081-1-andre.przywara@arm.com> References: <20260925225112.14081-1-andre.przywara@arm.com> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= There are four clock controllers in the A523 SoC, but only three are described in the DT binding so far. Add a description for the CPU CCU, which provides separate clocks for the two CPU clusters and the DSU interconnect. Signed-off-by: Andre Przywara --- .../clock/allwinner,sun55i-a523-ccu.yaml | 38 ++++++++++++++++++- .../dt-bindings/clock/sun55i-a523-cpu-ccu.h | 13 +++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 include/dt-bindings/clock/sun55i-a523-cpu-ccu.h diff --git a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml index 58be701a720ea..8d5481fb63ae8 100644 --- a/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml +++ b/Documentation/devicetree/bindings/clock/allwinner,sun55i-a523-ccu.yaml @@ -19,6 +19,7 @@ properties: compatible: enum: - allwinner,sun55i-a523-ccu + - allwinner,sun55i-a523-cpu-ccu - allwinner,sun55i-a523-mcu-ccu - allwinner,sun55i-a523-r-ccu @@ -35,12 +36,23 @@ properties: required: - "#clock-cells" - - "#reset-cells" - compatible - reg - clocks - clock-names +if: + properties: + compatible: + contains: + const: allwinner,sun55i-a523-cpu-ccu +then: + properties: + "#reset-cells": false +else: + required: + - "#reset-cells" + allOf: - if: properties: @@ -64,6 +76,30 @@ allOf: - const: iosc - const: losc-fanout + - if: + properties: + compatible: + enum: + - allwinner,sun55i-a523-cpu-ccu + + then: + properties: + clocks: + items: + - description: High Frequency Oscillator (usually at 24MHz) + - description: Low Frequency Oscillator (usually at 32kHz) + - description: Internal Oscillator + - description: Peripherals PLL 0 (1200 MHz output) + - description: Peripherals PLL 0 (600 MHz output) + + clock-names: + items: + - const: hosc + - const: losc + - const: iosc + - const: pll-periph0-2x + - const: pll-periph0-600m + - if: properties: compatible: diff --git a/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h new file mode 100644 index 0000000000000..042f2310f64de --- /dev/null +++ b/include/dt-bindings/clock/sun55i-a523-cpu-ccu.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR MIT) */ +/* + * Copyright 2025 Arm Ltd. + */ + +#ifndef _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_ +#define _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_ + +#define CLK_CPU_L 7 +#define CLK_CPU_DSU 8 +#define CLK_CPU_B 9 + +#endif /* _DT_BINDINGS_CLK_SUN55I_A523_CPU_CCU_H_ */ From patchwork Fri Sep 25 22:51:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 3467 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sto.lore.kernel.org (sto.lore.kernel.org [172.232.135.74]) by mxe881.netcup.net (Postfix) with ESMTPS id D961F1C1C7C for ; Sat, 26 Sep 2026 00:56:43 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=arm.com; spf=pass (sender IP is 172.232.135.74) smtp.mailfrom=linux-sunxi+bounces-26258-noreply=patchwork.local@lists.linux.dev smtp.helo=sto.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.232.135.74 as permitted sender) client-ip=172.232.135.74; envelope-from=linux-sunxi+bounces-26258-noreply=patchwork.local@lists.linux.dev; helo=sto.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sto.lore.kernel.org (Postfix) with ESMTP id 1777A606699 for ; Fri, 25 Sep 2026 22:56:19 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 437B55013D5; Fri, 25 Sep 2026 22:56:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="dnkfq5IW" X-Original-To: linux-sunxi@lists.linux.dev Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 5A98E50AC1F for ; Fri, 25 Sep 2026 22:56:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376978; cv=none; b=W29vemi0dsgJbxdRfyjRTpRouD6CMyxWpinYhuiDAnE9nMJPOzDxdmQc9NdxkNs8GxOmXo6kMoBrNBXR5Zv3zDhmBoZcR0tkwxMvJTADWzjOZjlLbwr5jXZl64wyNFDz6xYGXmp3FKEaT7u2XBu+2KO5eOWRffT6ATsSQLxsMTw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376978; c=relaxed/simple; bh=qfpp5+5JkkoAYOyrvSG6KAf8EvSoq7d1du0nH5PfF8g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lNVk7a71FIcr0fQU3U0Zqz0PxYoX9db4TedewY1cqpko5Irly2+TNiD+nIPkYk+qIA9BgGIO/motofUK1tQc4bf69aK+MvGJb1oGb0MzWQw+YibNv2+Cq3m9KVe64pfl0D3tVAZjyI6ECyq62MF4RY/lGcG4xQbFvVEvqZ3o2HA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=dnkfq5IW; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1D7941C01; Fri, 25 Sep 2026 15:56:10 -0700 (PDT) Received: from ryzen.fritz.box (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id B171A3F632; Fri, 25 Sep 2026 15:56:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1790376973; bh=qfpp5+5JkkoAYOyrvSG6KAf8EvSoq7d1du0nH5PfF8g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dnkfq5IWoMq6y/8XNgXFwNRf83bC4Unes4iUc3MywojZ6pjEE2YfqzCyHz01oBbMc NtyAtDRYLNLZSMvxlsP7GRCOv+0jjur4zvoCNVFw7fYf4os6RMGNUCqwJOh0Jks45l +dTXkzZB7qeOKxgMqQfpQWjzLTGmXIUNQp0Kymyw= From: Andre Przywara To: Stephen Boyd , Brian Masney , Jerome Brunet , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Subject: [PATCH v3 3/4] clk: sunxi-ng: add support for the A523/T527 CPU CCU Date: Sat, 26 Sep 2026 00:51:11 +0200 Message-ID: <20260925225112.14081-4-andre.przywara@arm.com> X-Mailer: git-send-email 2.46.4 In-Reply-To: <20260925225112.14081-1-andre.przywara@arm.com> References: <20260925225112.14081-1-andre.przywara@arm.com> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= The A523 contains a separate CCU block for the CPU PLLs. This includes one CPU clock per cluster, plus the DSU PLL, which clocks the part that connects the two clusters. There is also a "backup" PLL, which can be used to clock the cores when the main PLLs are reprogrammed. Those PLLs are then connected via MUXes to the two clusters and the DSU. Describe those clocks and their relationship, to allow the kernel to adjust the core frequency. Signed-off-by: Andre Przywara --- drivers/clk/sunxi-ng/Kconfig | 5 + drivers/clk/sunxi-ng/Makefile | 2 + drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c | 378 +++++++++++++++++++++ drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h | 24 ++ drivers/clk/sunxi-ng/ccu_div.h | 5 + 5 files changed, 414 insertions(+) create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c create mode 100644 drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 6af2d020e03e9..b2d8efa231cf2 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -67,6 +67,11 @@ config SUN55I_A523_R_CCU default ARCH_SUNXI depends on ARM64 || COMPILE_TEST +config SUN55I_A523_CPU_CCU + tristate "Support for the Allwinner A523/T527 CPU CCU" + default ARCH_SUNXI + depends on ARM64 || COMPILE_TEST + config SUN4I_A10_CCU tristate "Support for the Allwinner A10/A20 CCU" default ARCH_SUNXI diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index a1c4087d72417..309ff5a089ecf 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_SUN50I_H616_CCU) += sun50i-h616-ccu.o obj-$(CONFIG_SUN55I_A523_CCU) += sun55i-a523-ccu.o obj-$(CONFIG_SUN55I_A523_MCU_CCU) += sun55i-a523-mcu-ccu.o obj-$(CONFIG_SUN55I_A523_R_CCU) += sun55i-a523-r-ccu.o +obj-$(CONFIG_SUN55I_A523_CPU_CCU) += sun55i-a523-cpu-ccu.o obj-$(CONFIG_SUN4I_A10_CCU) += sun4i-a10-ccu.o obj-$(CONFIG_SUN5I_CCU) += sun5i-ccu.o obj-$(CONFIG_SUN6I_A31_CCU) += sun6i-a31-ccu.o @@ -64,6 +65,7 @@ sun50i-h616-ccu-y += ccu-sun50i-h616.o sun55i-a523-ccu-y += ccu-sun55i-a523.o sun55i-a523-mcu-ccu-y += ccu-sun55i-a523-mcu.o sun55i-a523-r-ccu-y += ccu-sun55i-a523-r.o +sun55i-a523-cpu-ccu-y += ccu-sun55i-a523-cpu.o sun4i-a10-ccu-y += ccu-sun4i-a10.o sun5i-ccu-y += ccu-sun5i.o sun6i-a31-ccu-y += ccu-sun6i-a31.o diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c new file mode 100644 index 0000000000000..ef1b05b2a9b58 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2023-2025 Arm Ltd. + * + * There are four PLLs: one for the little cluster (cores 0-3: PLL1), one for + * the "big" cluster (cores 4-7: PLL3), one for the DSU interconnect (probably + * its SCLK, driving the L3 cache: PLL2), and one undocumented "backup" PLL0, + * which can be used to drive either or both clusters, while the original PLLs + * are re-programmed (and re-lock). + * PLL[123] are the same, with a multiplier, a predivider, and two separate + * divider fields. For PLL1 till PLL3 there is an additional shift field, in + * the mux clock - although that applies only to the PLL, not the other sources. + * The two clusters and the DSU are connected to a mux clock each, selecting + * from various sources, including the PLL-PERIPH0-600M clock, again useful + * during DVFS operations: + * + * PLL-PERI0-600M (from the main CCU) + * | + * +-------+-----------+ + * / \ \ + * +------+ / +------+ \ +------+ \ +------+ + * | PLL1 | | | PLL0 | | | PLL3 | | | PLL2 | + * +------+ | +------+ | +------+ | +------+ + * \ | ^ | / | / + * DIV | / \ | DIV | DIV (plus 24MHz, + * \ | / \ | / \ / 32KHz, + * +---------+ +---------+ +---------+ 16MHz, + * \ CPU-L / \ CPU-B / \ DSU / for each mux) + * \ / \ / \ / + * +---+ +---+ +---+ + * | | | + * +-------+-----------+-----DSU-----+----+ + * | +---+---+ +---+---+ | + * | | cores | | cores | | + * | | 0-3 | | 4-7 | +------------+ + * | +-------+ +-------+ | L3 cache | + * +-------------------------+------------+ + */ + +#include +#include +#include +#include +#include +#include + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_nm.h" +#include "ccu_mult.h" + +#include +#include "ccu-sun55i-a523-cpu.h" + +/* + * The 24 MHz oscillator, the root of most of the clock tree. + * .fw_name is the string used in the DT "clock-names" property, used to + * identify the corresponding clock in the "clocks" property. + */ +static const struct clk_parent_data osc24M[] = { + { .fw_name = "hosc" } +}; + +/* + * Undocumented PLL, mux-able to both clusters, usable as an interim PLL + * during DVFS clock rate changes. Bits [23:16] and [4:2] are RAZ/WI, which + * looks like the DDR or VIDEO PLLs, and not like the other CPU PLLs. + * Bits [1:0] are not dividers, as they don't have any effect on the frequency. + */ +#define SUN55I_A523_PLL_CPU_0_REG 0x00 + +static struct ccu_mult pll_cpu_0_clk = { + .enable = BIT(27), + .lock = BIT(28), + .mult = _SUNXI_CCU_MULT(8, 8), + .common = { + .reg = 0x00, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-0", osc24M, + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; +static const struct clk_parent_data pll_cpu_0_hws[] = { + { .hw = &pll_cpu_0_clk.common.hw }, +}; + +/* + * The PLLs are input * N / P / (M0 * M1). Model them as NM, by ignoring the + * predivider P and the only 2-bit wide M0, and fixing them to 1 in probe(). + * Using NKMP wouldn't be better, because the "P" in there is a shift. + * The actual enable bit is bit 31, which we set once in probe, along with + * some other control bits, as the manual recommends to not touch them + * during runtime. + */ +#define SUN55I_A523_PLL_CPU_L_REG 0x04 +static struct ccu_nm pll_cpu_l_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108), + .m = _SUNXI_CCU_DIV(0, 3), /* M1 */ + .common = { + .reg = 0x04, + .update_bits = BIT(26), + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-l", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE | + CLK_IS_CRITICAL), + }, +}; +static const struct clk_parent_data pll_cpu_l_hws[] = { + { .hw = &pll_cpu_l_clk.common.hw }, +}; + +#define SUN55I_A523_PLL_CPU_DSU_REG 0x08 +static struct ccu_nm pll_cpu_dsu_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108), + .m = _SUNXI_CCU_DIV(0, 3), /* M1 */ + .common = { + .reg = 0x08, + .update_bits = BIT(26), + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-dsu", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE | + CLK_IS_CRITICAL), + }, +}; +static const struct clk_parent_data pll_cpu_dsu_hws[] = { + { .hw = &pll_cpu_dsu_clk.common.hw }, +}; + +#define SUN55I_A523_PLL_CPU_B_REG 0x0c +static struct ccu_nm pll_cpu_b_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 20, 108), + .m = _SUNXI_CCU_DIV(0, 3), /* M1 */ + .common = { + .reg = 0x0c, + .update_bits = BIT(26), + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpu-b", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE | + CLK_IS_CRITICAL), + }, +}; +static const struct clk_parent_data pll_cpu_b_hws[] = { + { .hw = &pll_cpu_b_clk.common.hw }, +}; + +/* + * These are just the divider parts of the CPU clocks, even when the mux + * field is in the same register. As the divider only applied to the CPU + * clocks, this has to be handled separately. + */ +static SUNXI_CCU_P_DATA(pll_cpu_l_div_clk, "pll-cpu-l-div", + pll_cpu_l_hws, 0x60, + 16, 2, /* P */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_P_DATA(pll_cpu_b_div_clk, "pll-cpu-b-div", + pll_cpu_b_hws, 0x064, + 16, 2, /* P */ + CLK_SET_RATE_PARENT); +static SUNXI_CCU_P_DATA(pll_cpu_dsu_div_clk, "pll-cpu-dsu-div", + pll_cpu_dsu_hws, 0x06c, + 16, 2, /* P */ + CLK_SET_RATE_PARENT); + +static const struct clk_parent_data cpu_l_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_cpu_l_div_clk.common.hw }, + { .fw_name = "pll-periph0-600m" }, + { .hw = &pll_cpu_0_clk.common.hw }, +}; + +static SUNXI_CCU_MUX_DATA(cpu_l_clk, "cpu-l", cpu_l_parents, 0x60, + 24, 3, /* mux */ + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +static const struct clk_parent_data cpu_b_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_cpu_b_div_clk.common.hw }, + { .fw_name = "pll-periph0-600m" }, + { .hw = &pll_cpu_0_clk.common.hw }, +}; + +static SUNXI_CCU_MUX_DATA(cpu_b_clk, "cpu-b", cpu_b_parents, 0x64, + 24, 3, /* mux */ + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +/* + * Register 0x68 holds gate bits for the two cluster clocks and the DSU. + * We leave them alone in the kernel, that's something for TF-A or the SCP. + */ + +static const struct clk_parent_data cpu_dsu_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_cpu_dsu_div_clk.common.hw }, + { .fw_name = "pll-periph0-2x" }, + { .fw_name = "pll-periph0-600m" }, +}; + +static SUNXI_CCU_MUX_DATA(cpu_dsu_clk, "cpu-dsu", cpu_dsu_parents, 0x6c, + 24, 3, /* mux */ + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +static struct ccu_common *sun55i_a523_cpu_ccu_clks[] = { + &pll_cpu_0_clk.common, + &pll_cpu_l_clk.common, + &pll_cpu_b_clk.common, + &pll_cpu_dsu_clk.common, + &pll_cpu_l_div_clk.common, + &pll_cpu_b_div_clk.common, + &pll_cpu_dsu_div_clk.common, + &cpu_l_clk.common, + &cpu_b_clk.common, + &cpu_dsu_clk.common, +}; + +static struct clk_hw_onecell_data sun55i_a523_cpu_hw_clks = { + .hws = { + [CLK_PLL_CPU_0] = &pll_cpu_0_clk.common.hw, + [CLK_PLL_CPU_L] = &pll_cpu_l_clk.common.hw, + [CLK_PLL_CPU_DSU] = &pll_cpu_dsu_clk.common.hw, + [CLK_PLL_CPU_B] = &pll_cpu_b_clk.common.hw, + [CLK_DIV_CPU_L] = &pll_cpu_l_div_clk.common.hw, + [CLK_DIV_CPU_DSU] = &pll_cpu_dsu_div_clk.common.hw, + [CLK_DIV_CPU_B] = &pll_cpu_b_div_clk.common.hw, + [CLK_CPU_L] = &cpu_l_clk.common.hw, + [CLK_CPU_DSU] = &cpu_dsu_clk.common.hw, + [CLK_CPU_B] = &cpu_b_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static const struct sunxi_ccu_desc sun55i_a523_cpu_ccu_desc = { + .ccu_clks = sun55i_a523_cpu_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun55i_a523_cpu_ccu_clks), + + .hw_clks = &sun55i_a523_cpu_hw_clks, +}; + +static const u32 pll_regs[] = { + SUN55I_A523_PLL_CPU_0_REG, + SUN55I_A523_PLL_CPU_L_REG, + SUN55I_A523_PLL_CPU_DSU_REG, + SUN55I_A523_PLL_CPU_B_REG, +}; + +static struct ccu_mux_nb sun55i_a523_cpu_l_nb = { + .common = &cpu_l_clk.common, + .cm = &cpu_l_clk.mux, + .delay_us = 1, /* manual doesn't really say */ + .bypass_index = 4, /* PLL_PERI0@600MHz, as recommended by manual */ +}; +static struct ccu_mux_nb sun55i_a523_cpu_b_nb = { + .common = &cpu_b_clk.common, + .cm = &cpu_b_clk.mux, + .delay_us = 1, /* manual doesn't really say */ + .bypass_index = 4, /* PLL_PERI0@600MHz, as recommended by manual */ +}; +static struct ccu_mux_nb sun55i_a523_cpu_dsu_nb = { + .common = &cpu_dsu_clk.common, + .cm = &cpu_dsu_clk.mux, + .delay_us = 1, /* manual doesn't really say */ + .bypass_index = 5, /* PLL_PERI0@600MHz, as recommended by manual */ +}; + +static int sun55i_a523_start_pll(void __iomem *reg) +{ + u32 val = readl(reg); + + /* check if the bootloader had the PLL already running and locked */ + if ((val & GENMASK(31, 28)) == GENMASK(31, 28)) { + /* If the dividers are already set to 1 (encoded as 0) ... */ + if (!(val & GENMASK(21, 16))) + return 0; + + /* + * The PLL is already running, but the P and M0 dividers are + * not programmed to 1, which we assume in our formula above. + * If we just clear them, the frequency jumps up by at least + * a factor of 2, probably crashing the system. + * So we need TODO: + * - remux the consumer (a different register!) + * - gate the PLL + * - set the factor to match M0==P==1 + * - ungate the PLL + * - wait for the PLL to lock + * - remux + * For now just be a diva: U-Boot does the right thing already. + */ + return -EEXIST; + } + + /* set the enable, the LDO and the lock bits, and clear dividers */ + val |= BIT(31) | BIT(30) | BIT(29) | BIT(26); + val &= ~GENMASK(21, 16); /* covering PLL_P and PLL_M0 */ + writel(val, reg); + + /* wait for the lock bit */ + return readl_relaxed_poll_timeout(reg, val, val & BIT(28), 100, 70000); +} + +static int sun55i_a523_cpu_ccu_probe(struct platform_device *pdev) +{ + const struct sunxi_ccu_desc *desc; + void __iomem *reg; + int i, ret; + + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* + * The user manual recommends to keep the PLLs running, and just + * gate their output if they are not needed, to avoid interference + * with other PLLs, since they share a power domain. + * To comply with this, we use this output gate as the CCF enable bit, + * so we need to enable all PLLs here. + */ + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { + ret = sun55i_a523_start_pll(reg + pll_regs[i]); + if (ret) + return ret; + } + + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, desc); + if (ret) + return ret; + + /* Reparent CPUs/DSU during PLL rate changes */ + ccu_mux_notifier_register(pll_cpu_l_clk.common.hw.clk, + &sun55i_a523_cpu_l_nb); + ccu_mux_notifier_register(pll_cpu_b_clk.common.hw.clk, + &sun55i_a523_cpu_b_nb); + ccu_mux_notifier_register(pll_cpu_dsu_clk.common.hw.clk, + &sun55i_a523_cpu_dsu_nb); + + return ret; +} + +static const struct of_device_id sun55i_a523_cpu_ccu_ids[] = { + { + .compatible = "allwinner,sun55i-a523-cpu-ccu", + .data = &sun55i_a523_cpu_ccu_desc, + }, + { } +}; +MODULE_DEVICE_TABLE(of, sun55i_a523_cpu_ccu_ids); + +static struct platform_driver sun55i_a523_cpu_ccu_driver = { + .probe = sun55i_a523_cpu_ccu_probe, + .driver = { + .name = "sun55i-a523-cpu-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun55i_a523_cpu_ccu_ids, + }, +}; +module_platform_driver(sun55i_a523_cpu_ccu_driver); + +MODULE_IMPORT_NS("SUNXI_CCU"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h new file mode 100644 index 0000000000000..484343b2c4fa6 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun55i-a523-cpu.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2025 Arm Ltd. + */ + +#ifndef _CCU_SUN55I_A523_CPU_H +#define _CCU_SUN55I_A523_CPU_H + +#include + +/* The PLL clocks itself and the pure divider clocks are not exported. */ + +#define CLK_PLL_CPU_0 0 +#define CLK_PLL_CPU_L 1 +#define CLK_PLL_CPU_DSU 2 +#define CLK_PLL_CPU_B 3 + +#define CLK_DIV_CPU_L 4 +#define CLK_DIV_CPU_DSU 5 +#define CLK_DIV_CPU_B 6 + +#define CLK_NUMBER (CLK_CPU_B + 1) + +#endif /* _CCU_SUN55I_A523_CPU_H */ diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index a30a92780a051..e5a15857a0547 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -292,6 +292,11 @@ struct ccu_div { }, \ } +#define SUNXI_CCU_P_DATA(_struct, _name, _parents, _reg, \ + _pshift, _pwidth, _flags) \ + SUNXI_CCU_P_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _pshift, _pwidth, 0, 0, 0, _flags) + static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); From patchwork Fri Sep 25 22:51:12 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 3469 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id DB24B1C1C7C for ; Sat, 26 Sep 2026 00:57:40 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=arm.com; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-26259-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-26259-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 871B62C33B for ; Fri, 25 Sep 2026 22:56:19 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 64D774EE844; Fri, 25 Sep 2026 22:56:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="C0/z1680" X-Original-To: linux-sunxi@lists.linux.dev Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 6ECA04FECC5 for ; Fri, 25 Sep 2026 22:56:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376979; cv=none; b=kiYuxZU8vnDrtz4+ypR8pg0fssIJmiyPiivhx9PC9uRKYzUBKFLw0Ep9AtOFCLqF7GLbGL5SZUc30jSzOXbq7V2yoR3UnvCXRyrZEoHUjbDLl9OFjPEBQiH63xu/hGbnPv5HU1kSo4syaBOCuNBujbdC5g5xeWxiF5RhfTenZPA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790376979; c=relaxed/simple; bh=sg8jvCBQyHW5vy7uXNNvXeP1MR1xgM2tRjcrl/rYpoI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NfVGJZr36syQCGKKIJJCdxX83zkfeTlgzII8QXHJuneSofNnelvGYHHLDiooLuNXaHM4RXCfLgBeaS/boOkb1C4DfVuPhXDJuBQFnhRI3h55EpCUlTyxlLrUgcNGMWjIQ4rISmJv+d3Lw1YwAd8WFKzZhuK1DDFQ8nfnZYJBCqw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=C0/z1680; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 32E57169C; Fri, 25 Sep 2026 15:56:13 -0700 (PDT) Received: from ryzen.fritz.box (usa-sjc-mx-foss1.foss.arm.com [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id F2B6A3F632; Fri, 25 Sep 2026 15:56:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1790376976; bh=sg8jvCBQyHW5vy7uXNNvXeP1MR1xgM2tRjcrl/rYpoI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C0/z1680uzcUHf+WVyfZ1DXvoFESy73F+hQHAeXDeDoQuFwWBRhL3mTO0OijoLw94 r6RDOhkdkQg39alkChkbqiQDxpJh/rsOM3MmCUTJXCrGEChJVJiKrlYzmCLXaIADQY dEhB7h175rw3UbF2pbPM5Tm3ORXQYdeRv0nhihi0= From: Andre Przywara To: Stephen Boyd , Brian Masney , Jerome Brunet , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Chen-Yu Tsai , Jernej Skrabec , Samuel Holland Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev Subject: [PATCH v3 4/4] arm64: dts: allwinner: a523: add CPU clocks Date: Sat, 26 Sep 2026 00:51:12 +0200 Message-ID: <20260925225112.14081-5-andre.przywara@arm.com> X-Mailer: git-send-email 2.46.4 In-Reply-To: <20260925225112.14081-1-andre.przywara@arm.com> References: <20260925225112.14081-1-andre.przywara@arm.com> Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Rspamd-Server: rspamd-worker-8404 X-Spamd-Result: default: False [-0.66 / 15.00]; BAYES_HAM(-5.50)[100.00%]; RBL_SENDERSCORE(2.00)[172.234.253.10:from]; SUSPICIOUS_RECIPS(1.50)[]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; MAILLIST(-0.15)[generic]; BAD_REP_POLICIES(0.10)[]; MIME_GOOD(-0.10)[text/plain]; HAS_LIST_UNSUB(-0.01)[]; TAGGED_RCPT(0.00)[clk,dt]; FROM_HAS_DN(0.00)[]; PRECEDENCE_BULK(0.00)[]; RCVD_VIA_SMTP_AUTH(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[sea.lore.kernel.org:rdns,sea.lore.kernel.org:helo]; RCPT_COUNT_TWELVE(0.00)[13]; FORGED_SENDER_MAILLIST(0.00)[]; R_DKIM_ALLOW(0.00)[arm.com:s=foss]; RCVD_COUNT_FIVE(0.00)[6]; ARC_ALLOW(0.00)[subspace.kernel.org:s=arc-20240116:i=1]; DKIM_TRACE(0.00)[arm.com:+]; DMARC_POLICY_ALLOW(0.00)[arm.com,none]; R_SPF_ALLOW(0.00)[+ip4:172.234.253.10]; TO_DN_SOME(0.00)[]; FROM_NEQ_ENVFROM(0.00)[andre.przywara@arm.com,linux-sunxi@lists.linux.dev]; FREEMAIL_TO(0.00)[kernel.org,redhat.com,baylibre.com,gmail.com,sholland.org]; MIME_TRACE(0.00)[0:+]; TAGGED_FROM(0.00)[bounces-26259-noreply=patchwork.local]; FORGED_RECIPIENTS_MAILLIST(0.00)[]; ASN(0.00)[asn:63949, ipnet:172.234.224.0/19, country:SG]; RCVD_TLS_LAST(0.00)[]; RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[172.234.253.10:from] X-Rspamd-Queue-Id: DB24B1C1C7C X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= The Allwinner A523 family of SoCs feature a separate clock unit for the CPU PLLs and muxes, including one for the DSU interconnect. Add a DT node for the CPU clock controller, and list all the clocks from the other CCUs that this controller needs. Also list the clock source for each CPU: there is one clock for each cluster of four cores, suffixed L and B, for little and big (although all cores are of the same Cortex-A55 type). Signed-off-by: Andre Przywara --- .../arm64/boot/dts/allwinner/sun55i-a523.dtsi | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi index 85ef492ffeae7..d8aa13af3935e 100644 --- a/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi +++ b/arch/arm64/boot/dts/allwinner/sun55i-a523.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ cpu0: cpu@0 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x000>; + clocks = <&cpu_ccu CLK_CPU_L>; enable-method = "psci"; }; @@ -32,6 +34,7 @@ cpu1: cpu@100 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x100>; + clocks = <&cpu_ccu CLK_CPU_L>; enable-method = "psci"; }; @@ -39,6 +42,7 @@ cpu2: cpu@200 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x200>; + clocks = <&cpu_ccu CLK_CPU_L>; enable-method = "psci"; }; @@ -46,6 +50,7 @@ cpu3: cpu@300 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x300>; + clocks = <&cpu_ccu CLK_CPU_L>; enable-method = "psci"; }; @@ -53,6 +58,7 @@ cpu4: cpu@400 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x400>; + clocks = <&cpu_ccu CLK_CPU_B>; enable-method = "psci"; }; @@ -60,6 +66,7 @@ cpu5: cpu@500 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x500>; + clocks = <&cpu_ccu CLK_CPU_B>; enable-method = "psci"; }; @@ -67,6 +74,7 @@ cpu6: cpu@600 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x600>; + clocks = <&cpu_ccu CLK_CPU_B>; enable-method = "psci"; }; @@ -74,6 +82,7 @@ cpu7: cpu@700 { compatible = "arm,cortex-a55"; device_type = "cpu"; reg = <0x700>; + clocks = <&cpu_ccu CLK_CPU_B>; enable-method = "psci"; }; }; @@ -1144,5 +1153,17 @@ npu: npu@7122000 { resets = <&mcu_ccu RST_BUS_MCU_NPU>; power-domains = <&ppu PD_NPU>; }; + + cpu_ccu: clock-controller@8817000 { + compatible = "allwinner,sun55i-a523-cpu-ccu"; + reg = <0x08817000 0x80>; + clocks = <&osc24M>, <&rtc CLK_OSC32K>, + <&rtc CLK_IOSC>, <&ccu CLK_PLL_PERIPH0_2X>, + <&ccu CLK_PLL_PERIPH0_600M>; + clock-names = "hosc", "losc", + "iosc", "pll-periph0-2x", + "pll-periph0-600m"; + #clock-cells = <1>; + }; }; };