From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wm1-f49.google.com (mail-wm1-f49.google.com [209.85.128.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2E7E53C6A41 for ; Thu, 16 Jul 2026 21:35:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237757; cv=none; b=NRXbtalIDzG3mawiM/MyaXyU8eeo3XpAdjjPb4jCwzV5tB574vycpkDSSr6cO1fe/+cS8kPZoXTPOEGKggbuIDMc3A1xTKF6caPxAQVxcLN6nZEGgdYdraZG2PzLbFCfhV4PBrhqZ9ZnXP66XAiMwETHhWq/VXCqt5JcNID0KgA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237757; c=relaxed/simple; bh=MWgeMQguSvX0yNa9AkilnGzLi/Gpu4RxxeyumH/X22g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mupCjpLpMmvySzFxEpzW70pmLDwRFWre4vdymddYmDqTSRkwKtXtwGPKruFhiZAdfLte9WVL3pt/85+HPLj3wY6PxHv+NyDiI8C2FnKj7/y0XA5avVpl1MeI/jTgfWstVOGvHw64RUoMkVtrP2kyVNd/f+HeFjxKucnJ04LvuzA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=EAyD52IZ; arc=none smtp.client-ip=209.85.128.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="EAyD52IZ" Received: by mail-wm1-f49.google.com with SMTP id 5b1f17b1804b1-493bb510ce4so48740135e9.1 for ; Thu, 16 Jul 2026 14:35:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237754; x=1784842554; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=1Cbd7RpSigAze/UtmT1+z+tOpgI5gcPixymoRHCvScg=; b=EAyD52IZ7vwRc00V4kJ+cnovL26UBPelQ8JjcJVkaPGoko5wInT2RV+vw7m9u1FmuQ DNg7Rjgu6xIDpysPY++A7o4iwl5DmLHGJryyy5X81duvrHfd5Ft6LxOLcicjW6lA5RDW gUKCH5U5hVn+JJkqizOkmfmlS5CFxYZYyrAR4H50Ic5R/BjRz3sXlunzeJCO78xRLI5L Vznn/2QNYCNANEd6mRfopSdHryF9Ia7f4hfo40sFT5z32zMYTHfwbWaOvpYBx451PdOS kZ5KtOjbiCXxL8WkQH3kqwqdgPKp+wr08yLsSBBTZgUe/NMV9QNxa+M6V8QnuQ2DDxh/ R1lA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237754; x=1784842554; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=1Cbd7RpSigAze/UtmT1+z+tOpgI5gcPixymoRHCvScg=; b=JoIgKwCC4t1VuACOjU6tng4ojIifT6gHhxNz6W8vU64f9hg/qOnZ3817CA7rVTO+qA jI3+hCX0wwcwBcCeHPvWEf+I38e/cwNseP385o3LIkDrwoA7tMXIIxoC3/8/Izs5w6sC pOPAyE24YxaoZKuIRRQt64i8BqMqCzH9csN10x+v/xNpo0R5VeLPA4o8EVhCOMa/SZgX bBzNGnSVOwXJFQh8Yv4yHhpAMdRj3big0vtaKCSSsq4onnZfZJlK6G8qlOhx8bw0vtTT LXra2jP0PGxGcZOMvUc84QW/FQFAohxF8PxLFWqEm2TPh9w4D13r8onA5ewf39W7ULQG vUtw== X-Forwarded-Encrypted: i=1; AHgh+Rq24wpBq+rVcBMhyLwKpRM6NrA3yMWuONStvHlZCcZ6+YMLbajp3IJFTkGe83pMY1CVntMqWXDnoyzkYJE=@vger.kernel.org X-Gm-Message-State: AOJu0YyDJ6DDJif5xKPWPvrRfIRViXQ6a7YbEIo2W9BYd6lLtN/icd6N U3dSly7MW1iaymSCd1VUAkloLmIBDLZbvEOUxW5kBmcss0ZKuLd4fG13 X-Gm-Gg: AfdE7cntDv0Tq5OqU/TcOWrS9APY/DT1+fd/eJU5fRTOFdPfHxQ27QU42wVAA7UkmVq lFuVO8SD2r8x3Eff4gRxwavOcjYJZg3shWnDSa8x5uVNgAZlXsWobtZufbdja/kf1gHovExCiYM o6Txmyd0DVokAmR9cUxNed6V+unGVzxy4ATCLv3kRAEF5HTQs0yunZnkgCgJJIVf6ABS+Fhx9Yw VQonEGR83PeCNimFCPV9tpp5ICTVis3MBmap2Wio1Jy3YRrFZThNQcjTkf6ttLsz+IMNbKx4B0j kjrU3v8un5ODbwxxtcsce0Ur3jTDQaFlfmZRpXCz8JLpo39E8jv9ITqJ1hQfH0N1kF7CpAwrsmH d4/Dij9L+1r0nFbvd6jOFb/zXSbJudeoztz2ZAlXJ9GJfwn193zvlg1jK4wk8TJ0zH3G5TrvIiA ffZl2U+6G5lONI X-Received: by 2002:a05:600c:6217:b0:492:4363:e7d6 with SMTP id 5b1f17b1804b1-49538cc1510mr144373665e9.37.1784237754220; Thu, 16 Jul 2026 14:35:54 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.35.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:35:53 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:37 +0300 Subject: [PATCH v7 01/13] dt-bindings: phy: Add zx297520v3 USB phy documentation Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-1-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=5153; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=MWgeMQguSvX0yNa9AkilnGzLi/Gpu4RxxeyumH/X22g=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xcWZOmOXtOLohhzgy+hM6oOkxf17Sa7bRM oer1RlHKaCJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKD6w/+MJmxYIyepRX+FyR6Y2BS1xstCgAxbVa V2LfZHa60uXTnOQjweIZny/aZvtk9oG1fmQcB29kMUwDm50sZITCqWBMWRL2E+xjVH9r55CG47a csbwc6VvJWAohr4URm4L+nTQarehBpqczIbo+wh0HVKczceIp7areXGL/5/eYHfNCCExjcxzvyr 84/h3Bq82p+gHYpmtOTWvezhrV5LXVS6nG0+y0wJBOs1xLcUJj5YiQjr6PnzVDswSIYVz4gP3N3 bOwg8Nk2+pd+Uxjdw7+AbIiR8BaaFwwRcvQx1zr/3TdU2aCn5cNzoAFd64ZjJrIW3jHrlJBRfpA Om0s+tWSwC2XMqxF5epTfzM5P7uo2yC2QxbCG2GmDa5kek03rFQVL36ALPJX500QQthmvGttASu GqOG7LEUA52ljXfs8kLRU3QL1pde2ZN4QP6kyFl4yT9+8KlF22hGWc4BV0Byk82CY9nnteMzj5Y NehEK9+olrStownN5eU1Y/XRUOBdsr5yjaiUlnGfB2w93dUe7GNJdPDm427SQ62gAQ2p0P2Wv3t dUOpqRXXJTdKaL//MCZ3rw+QPL5AegBy9YyKISXQGBoUjg50L2aH7pdLNS15x1c43zbNmwDKhYh oOTzG68KamAIZoheKX+RVCRcs+Xm8gO3gwdge8ZC5xHGJOIc27to= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This binding will be used as a subnode of topcrm, which will be added in the next patch. Why is this a child node and not #phy-cells added to topcrm itself, like clocks and resets as writing-bindings.rst suggests? Because of_phy_provider_register checks if the of_node the PHY provider is added to belongs to the device or is a child of the device, so I can't put the PHY driver into an MFD (or AUX) child without its own node. Signed-off-by: Stefan D=C3=B6singer --- How do I handle examples? It would be identical to the example in topcrm. The example needs the reset defines from the next patch in either case. --- .../bindings/phy/zte,zx297520v3-usb-phy.yaml | 96 ++++++++++++++++++= ++++ MAINTAINERS | 2 + include/dt-bindings/phy/phy-zte-zx297520v3-usb.h | 12 +++ 3 files changed, 110 insertions(+) diff --git a/Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.y= aml b/Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml new file mode 100644 index 000000000000..8bad9365d5cc --- /dev/null +++ b/Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/phy/zte,zx297520v3-usb-phy.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 USB and HSIC PHY + +maintainers: + - Stefan D=C3=B6singer + +description: | + This PHY is found on zx297520v3 boards. It has no configurability on its= own, + but it does require a correct reset and wait sequence to initialize. It = can + provide interrupt notification when USB is connected and disconnected. + + The phy is a component of the board's topcrm controller. The hardware ne= eds to + be declared as a child node of the zte,zx297520v3-topcrm node. + + The register space and IRQs always account for two PHYs: One USB 2.0 OTG= phy + and a HSIC PHY. Not all boards have both. If one is missing, the corresp= onding + ready flag will never be set. + + The "include/dt-bindings/phy/phy-zte-zx297520v3-usb.h" header contains t= he + definition for the PHY indices. + +properties: + compatible: + const: zte,zx297520v3-usb-phy + + reg: + maxItems: 1 + + interrupts: + items: + - description: IRQ reporting USB connection + - description: IRQ reporting USB disconnection + - description: IRQ reporting HSIC connection + - description: IRQ reporting HSIC disconnection + + interrupt-names: + items: + - const: usb-up + - const: usb-down + - const: hsic-up + - const: hsic-down + + resets: + items: + - description: USB phy reset + - description: HSIC phy reset + + reset-names: + items: + - const: usb + - const: hsic + + "#phy-cells": + const: 1 + +required: + - compatible + - reg + - interrupts + - interrupt-names + - resets + - reset-names + - "#phy-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + topcrm: clock-controller { + compatible =3D "zte,zx297520v3-topcrm", "syscon"; + #address-cells =3D <1>; + #size-cells =3D <0>; + #reset-cells =3D <1>; + + usb-phy@84 { + compatible =3D "zte,zx297520v3-usb-phy"; + reg =3D <0x84>; + interrupts =3D , + , + , + ; + interrupt-names =3D "usb-up", "usb-down", "hsic-up", "hsic-down"; + resets =3D <&topcrm 18>, + <&topcrm 20>; + reset-names =3D "usb", "hsic"; + #phy-cells =3D <1>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 8729cea57c3d..cb50c2e3b4ea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3878,8 +3878,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated f= or non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: include/dt-bindings/phy/phy-zte-zx297520v3-usb.h =20 ARM/ZYNQ ARCHITECTURE M: Michal Simek diff --git a/include/dt-bindings/phy/phy-zte-zx297520v3-usb.h b/include/dt-= bindings/phy/phy-zte-zx297520v3-usb.h new file mode 100644 index 000000000000..8a0a3ccbdd63 --- /dev/null +++ b/include/dt-bindings/phy/phy-zte-zx297520v3-usb.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan D=C3=B6singer. + */ + +#ifndef __DT_BINDINGS_PHY_USB_ZX297520V3_H +#define __DT_BINDINGS_PHY_USB_ZX297520V3_H + +#define ZX297520V3_USB_PHY 0 +#define ZX297520V3_HSIC_PHY 1 + +#endif /* __DT_BINDINGS_PHY_USB_ZX297520V3_H */ --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6AF57222590 for ; Thu, 16 Jul 2026 21:36:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237762; cv=none; b=m1pNtFbYrbwL+cNxM/2U6Gu22iwY5vLpUBIwO3R2USDzHlBcqyXYpp2eiN/FuTn5yDziv0g5/FrivUL8EYCKbu0EIAGeyDwwFkKWf/Dd7HwXK4sHeg2sTDCYASssuhYqoIe/3Q2KaFADGIUsoTQlkvbRWWAUSX5FkYbLRlvVHuc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237762; c=relaxed/simple; bh=MQOZUN5sOfzC0LslhdTuSv6dboTN5sRWAZchx7fQT2w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=UgSo3WMGRVJY7vzdu08XB+QSUVba7Htgk4ORpTcO8c97wD2McpewPR+TsQhAOW/cazcLbUKkh835Wyg1pM4bExDLvHe7zpdAeK5xcCO+/wsi0Tf9cSdShIXiegaLMQuc19yuuivN0ca4/g4ILViskGP0+1kn9/gEteVXNuTMRB4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=WKgF2MaG; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WKgF2MaG" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-493ec555a26so46702855e9.0 for ; Thu, 16 Jul 2026 14:36:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237759; x=1784842559; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=2ba7h/YS4G0id6u8P/3TJ7kh/2tCKNINWqwY3DjpUpw=; b=WKgF2MaGFz2SX/VNRnijfIA7TfNEBZaaQnjFYW0bHS/MCWl1ukx6PRRYSlMI1zcgT5 XJ9PKuKKDj7TVSbOZJec7J0LZQ5IejgEJP8k9Np6sxBRamTmHS5eBf2sxKmFJZ1LraKQ ojX7ckboGsJDAYJMKJNH6Ib78UEJx4aYo/HF1D5/8MTFr7QiNLhG+XJuf+m0/aQI9AKi IzM8k48GwTmY9v4+qUsk7g8B8m/Xt3mMPw8lJmqyMQZg0fgHP+tELksnn0Qt910wT60l lMzAfn+30/FCsIin+jI75GYv8yVJZVSjhSPDko2fShSdeYqKzEIulNskUAxR1o2wlIGE ddMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237759; x=1784842559; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=2ba7h/YS4G0id6u8P/3TJ7kh/2tCKNINWqwY3DjpUpw=; b=KO60BVUGw0PqYZMmqQ00YoHclOwRxaXPBMVsdHGNXmk36Q6iBrqUywCcpREWob2vYJ 7doRBJjEDW5gh0ZCWlxBNwoPM+JTArUeGgEJm8Q0yY9GEcFU9YlBY7WIxfQxk3jWIOMy f/C5itYsvqZneXZxKWTwt7PdeQyoyYzMY3sRSs8mKf+CFVsbsmMAk0HqSLqdUW8H1P2X Q2sYD0NQbf2ncP0Wb8VyoWL1TfNq7F8UPSA6+qoFA4077ZvbhhxhncF5G39D67c7Pjo4 qxdyO0Px7bdz+rujL/WI2cNmtwEQ3a4HLlhV6+98W6HYKl9xppirzjWSSpjQwa9Y/IbD n7tQ== X-Forwarded-Encrypted: i=1; AHgh+RoHSUuQGl7yKE0jojO4LAnKhDTdnViOEOBbzVZC/YFW9a2kL5G7R0dTeIDdav5UJM0uLRgYUE4JHJVBod4=@vger.kernel.org X-Gm-Message-State: AOJu0YyTcoKNGHXpOlyKeR38zqTU/henrQ9y40H6K3WeVwiQqdtlIpho QkLx1PC33e9FHa5Rgpb0qJY2lQ4K97mNuaOxr77DTe3KRI5iu8JZSm+M X-Gm-Gg: AfdE7cn19+ZYfGqSqimkC65u+z5d+vY5Y6y2vReMaWqaGN5Ym4clD0GAMGauRcD5LTt nKwi02pVmD6EdEaVAAsrA7ZtnB92wEoUzzear2OsvwZZrEZhWo94YTWsV2UphQZAUp/dobzMVAm m0YwYjFoOrbCQ7vDZA2S2pXAdFADQ1mIx5+omiqbmVJViOw2S62Jg1Dw1UDdg0YDZcnMUO7hOY8 1Il3dvkOKqm/QmEehG4i/r4Cside0mgyWXSmPlcAIzYR3ya3dMyc7jQfhYEWKdJO/DbB9NJYI50 d256bfnxFqDoUe6gLfqbzPN0NfKOMu8KktmYz2REd1D/2ZnHFGZS4R6HesW7Ia09KdSTSkP0QlS ugKsdxR/YCEPboPntPIET8usRY42zaC7gY4i8vWKCVdeNI28Za716oze5+b3nLg1hF3UernQAi7 uiM5g8TE4MNofA X-Received: by 2002:a05:600c:a08e:b0:493:f639:9b2f with SMTP id 5b1f17b1804b1-4953c390347mr101375915e9.39.1784237758557; Thu, 16 Jul 2026 14:35:58 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.35.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:35:57 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:38 +0300 Subject: [PATCH v7 02/13] dt-bindings: clk: zte: Add zx297520v3 top clock and reset controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-2-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=12301; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=MQOZUN5sOfzC0LslhdTuSv6dboTN5sRWAZchx7fQT2w=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xtGznIdCfPJUfhgpJxhbIOzG4d7e6HVqQl mjsxRVgYGOJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLL9hAAnsDmDKYLfHgDXsIYjqgRZOLaah6TPK6 nF9CDj0IxuXvayU0vUpYD1Z9g6hs4QIZJfj/PdQUWqlob7lECKBfK6EluEeE6iYrvv8SRsGMYsH TeMQX1xie2y9Zv+hieDpJwv8gjwer20SlGOLmyTaUJW7d2oJc1W3dU7MQqnDeDbjPFmbCVdJuQ6 lree89rZTBwR2oZH1zw/iPuqREGEKo9eIxR/cOsWLolUgbV+8PArylZ1bovU2wFuTHJlcYIQILr rk3i0Tk7MMlv0ibU2ADMxTVMtaoTh7+Zged9qZ9wBdWlQYC363wCkCnw8HLXTpB7t4ouMbjqHWL VbdhJc4NxhCdF4CgwkHkDfDRaeegBmtJ4AO1du+7Ae4wCpl+vZtUwJmLJVuWtnnJo7LN1JcOHd6 W0t9jDshQo+iw5KXLES3C5UazEyymANB4DZBDQuzebu08EjwsmzZoPAU271oXizisM6/mojp3QX yoJRmD5rsyBbNXD50t6OiWlA5GWalKN0Ut+vJ25EIX/uk21yub0z+Y5RJ7Ld/kePpLs7M+Sm/yw Upcv5gyDfxD10ZWJ+FGDxwq7kpbaS57IrBRkOioKqDcMbDL1IsrY5f+v8TOWB86EbsDZMDJTDmp H2NI5kV7jB0uBGgQwcsMbviPMvhZ0dE1mR4LWtWSKRGXSAJe7cTc= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 These SoCs have 3 clock and reset controllers: Top, Matrix and LSP. Clocks go from oscillator -> top -> matrix -> LSP, with a register in top controlling most clocks that get passed to matrix and a register in matrix controlling all the clocks that get passed to LSP. Generally every device has two clocks (one work clock, and one that connects it to the bus, I call it PCLK), two reset bits (I don't know what the difference is - sometimes asserting one is enough to reset the device, sometimes both need to be asserted). PCLK and WCLK are controlled by individual gates. Some devices have a mux and/or a divider for their work clock. Some devices, like the GPIO controller, only have reset bits and no clocks. The top clock controller is fed by a 26mhz external oscillator and has 4 PLLs to generate other clock rates. ZTE's kernel mostly relies on the boot ROM to set up PLLs, but one LTE-Related PLL is not configured on some boards. Therefore my driver contains code to program PLLs. It produces identical settings as the boot ROM for the pre-programmed frequencies. Not all clocks will have an explicit user in the end. I am defining a lot of them simply to shut them off. The boot loader sets up a few of the proprietary timers, which will send regular IRQs (although the kernel of course doesn't need to listen to them). I don't plan to add a driver for the proprietary timer as I see no use for them - the ARM arch timer works just fine. I will add a driver for the very similar proprietary watchdog though. The clock list in this patch is pretty complete but not exhaustive. There are other bits that are enabled, but I couldn't deduce what they are controlling by trial and error. Some of them seem to do nothing. Others cause an instant hang of the board when disabled. It is quite likely that a handful more clocks will be added in the future, but not a large number. Signed-off-by: Stefan D=C3=B6singer --- Changes v6->v7: *) Moved the bingings back into clock/ (Krzysztof). use clock-controller@ in example and in the later DTSI patch. *) With as lucky find in strings in LTE's cpko.ko blob I could make sense of the register that controls which clocks get passed from PLLs into the clock distribution inside topcrm. Importantly that also narrows which clocks can possibly be passed to Matrix, so I could slim down the bindings considerably. *) Add a usb phy child node with the phy schema added in the previous patch. I don't expect the USB status register to ever be in another place, so the binding expresses the @84 expectation. Changes v5->v6: Set value for syscon-reboot example (Sashiko). It was my intention to set only the lowest bit, and I think Sashiko is right that without 'value' being set, all other bits are actively set to 0. It shouldn't matter given my understanding of the hardware (afaics all other bits are ignored), but actively clearing bits was not my intention. I haven't changed the name match for "syscon-reboot". I see plenty of examples of hardcoding this string as opposed to having a regex for syscon-reboot@12345678 in other bindings. Changes v4->v5: Rename from zte,zx297520v3-topclk to zte,zx297520v3-topcrm and move to soc/zte Fix path in MAINTAINERS Add syscon-reboot node to the binding Give the USB and HSIC PHY resets their own reset control --- .../bindings/clock/zte,zx297520v3-topcrm.yaml | 123 +++++++++++++++++= ++++ MAINTAINERS | 3 + include/dt-bindings/clock/zte,zx297520v3-clk.h | 66 +++++++++++ include/dt-bindings/reset/zte,zx297520v3-reset.h | 32 ++++++ 4 files changed, 224 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.= yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml new file mode 100644 index 000000000000..454997063573 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml @@ -0,0 +1,123 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-topcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC top clock and reset controller + +maintainers: + - Stefan D=C3=B6singer + +description: | + The zx297520v3 top clock and reset controller generates clocks for core + devices on the board like the main bus, USB and timers. In addition to c= locks + it has reset controls for peripherals, a global board reset, watchdog re= set + controls and a USB status register. + + The controller has two clock inputs: a 26 MHz and a 32 KHz external + oscillator. They need to be provided as input clocks. The controller pro= vides + PLL output frequencies to downstream clock controllers. + + The USB PHY functionality is exposed as a child node documented in + zte,zx297520v3-usb-phy.yaml. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. The resets are + defined in the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. + +properties: + compatible: + items: + - const: zte,zx297520v3-topcrm + - const: syscon + + reg: + maxItems: 1 + + clocks: + items: + - description: 26 MHz external oscillator + - description: 32 KHz external oscillator + + clock-names: + items: + - const: osc26m + - const: osc32k + + "#address-cells": + const: 1 + + "#size-cells": + const: 0 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + + syscon-reboot: + type: object + $ref: /schemas/power/reset/syscon-reboot.yaml# + description: + Reboot method for the SoC. + + usb-phy@84: + type: object + $ref: /schemas/phy/zte,zx297520v3-usb-phy.yaml# + description: + USB and HSIC PHY controller. + +required: + - compatible + - reg + - clocks + - clock-names + - syscon-reboot + - usb-phy@84 + - "#address-cells" + - "#size-cells" + - "#clock-cells" + - "#reset-cells" + +unevaluatedProperties: false + +examples: + - | + #include + #include + #include + #include + + topcrm: clock-controller@13b000 { + compatible =3D "zte,zx297520v3-topcrm", "syscon"; + reg =3D <0x0013b000 0x400>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + #address-cells =3D <1>; + #size-cells =3D <0>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + + syscon-reboot { + compatible =3D "syscon-reboot"; + offset =3D <0x0>; + mask =3D <0x1>; + value =3D <0x1>; + }; + + usb-phy@84 { + compatible =3D "zte,zx297520v3-usb-phy"; + reg =3D <0x84>; + interrupts =3D , + , + , + ; + interrupt-names =3D "usb-up", "usb-down", "hsic-up", "hsic-down"; + resets =3D <&topcrm ZX297520V3_USB_PHY_RESET>, + <&topcrm ZX297520V3_HSIC_PHY_RESET>; + reset-names =3D "usb", "hsic"; + #phy-cells =3D <1>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index cb50c2e3b4ea..5f962b9947ab 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3878,10 +3878,13 @@ L: linux-arm-kernel@lists.infradead.org (moderated = for non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/phy-zte-zx297520v3-usb.h +F: include/dt-bindings/reset/zte,zx297520v3-reset.h =20 ARM/ZYNQ ARCHITECTURE M: Michal Simek diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bi= ndings/clock/zte,zx297520v3-clk.h new file mode 100644 index 000000000000..1f010ff4e6ca --- /dev/null +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan D=C3=B6singer. + */ + +#ifndef __DT_BINDINGS_CLOCK_ZX297520V3_H +#define __DT_BINDINGS_CLOCK_ZX297520V3_H + +#define ZX297520V3_M0_WCLK 1 +#define ZX297520V3_SRAM1_PCLK 2 +#define ZX297520V3_SRAM2_PCLK 3 +#define ZX297520V3_UART0_WCLK 4 +#define ZX297520V3_UART0_PCLK 5 +#define ZX297520V3_I2C0_WCLK 6 +#define ZX297520V3_I2C0_PCLK 7 +#define ZX297520V3_RTC_WCLK 8 +#define ZX297520V3_RTC_PCLK 9 +#define ZX297520V3_LPM_GSM_WCLK 10 +#define ZX297520V3_LPM_GSM_PCLK 11 +#define ZX297520V3_LPM_LTE_WCLK 12 +#define ZX297520V3_LPM_LTE_PCLK 13 +#define ZX297520V3_LPM_TD_WCLK 14 +#define ZX297520V3_LPM_TD_PCLK 15 +#define ZX297520V3_LPM_W_WCLK 16 +#define ZX297520V3_LPM_W_PCLK 17 +#define ZX297520V3_TIMER_T08_WCLK 18 +#define ZX297520V3_TIMER_T08_PCLK 19 +#define ZX297520V3_TIMER_T09_WCLK 20 +#define ZX297520V3_TIMER_T09_PCLK 21 +#define ZX297520V3_MPLL 22 +#define ZX297520V3_MPLL_D5 23 +#define ZX297520V3_DPLL 24 +#define ZX297520V3_GPLL 25 +#define ZX297520V3_GPLL_D2 26 +#define ZX297520V3_GATED_OSC26M 27 +#define ZX297520V3_PMM_WCLK 28 +#define ZX297520V3_PMM_PCLK 29 +#define ZX297520V3_OUT0_WCLK 30 +#define ZX297520V3_OUT1_WCLK 31 +#define ZX297520V3_OUT2_WCLK 32 +#define ZX297520V3_OUT32K_WCLK 33 +#define ZX297520V3_RMIIPHY_WCLK 34 +#define ZX297520V3_TIMER_T12_WCLK 35 +#define ZX297520V3_TIMER_T12_PCLK 36 +#define ZX297520V3_TIMER_T13_WCLK 37 +#define ZX297520V3_TIMER_T13_PCLK 38 +#define ZX297520V3_TIMER_T14_WCLK 39 +#define ZX297520V3_TIMER_T14_PCLK 40 +#define ZX297520V3_TIMER_T15_WCLK 41 +#define ZX297520V3_TIMER_T15_PCLK 42 +#define ZX297520V3_TIMER_T16_WCLK 43 +#define ZX297520V3_TIMER_T16_PCLK 44 +#define ZX297520V3_TIMER_T17_WCLK 45 +#define ZX297520V3_TIMER_T17_PCLK 46 +#define ZX297520V3_WDT_T18_WCLK 47 +#define ZX297520V3_WDT_T18_PCLK 48 +#define ZX297520V3_USIM1_WCLK 49 +#define ZX297520V3_USIM1_PCLK 50 +#define ZX297520V3_AHB_WCLK 51 +#define ZX297520V3_AHB_PCLK 52 +#define ZX297520V3_USB_WCLK 53 +#define ZX297520V3_USB_PCLK 54 +#define ZX297520V3_HSIC_WCLK 55 +#define ZX297520V3_HSIC_PCLK 56 + +#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-= bindings/reset/zte,zx297520v3-reset.h new file mode 100644 index 000000000000..43db72bb59de --- /dev/null +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * Copyright (C) Stefan D=C3=B6singer. + */ + +#ifndef __DT_BINDINGS_RESET_ZX297520V3_H +#define __DT_BINDINGS_RESET_ZX297520V3_H + +#define ZX297520V3_ZSP_RESET 0 +#define ZX297520V3_UART0_RESET 1 +#define ZX297520V3_I2C0_RESET 2 +#define ZX297520V3_RTC_RESET 3 +#define ZX297520V3_TIMER_T08_RESET 4 +#define ZX297520V3_TIMER_T09_RESET 5 +#define ZX297520V3_PMM_RESET 6 +#define ZX297520V3_GPIO_RESET 7 +#define ZX297520V3_GPIO8_RESET 8 +#define ZX297520V3_TIMER_T12_RESET 9 +#define ZX297520V3_TIMER_T13_RESET 10 +#define ZX297520V3_TIMER_T14_RESET 11 +#define ZX297520V3_TIMER_T15_RESET 12 +#define ZX297520V3_TIMER_T16_RESET 13 +#define ZX297520V3_TIMER_T17_RESET 14 +#define ZX297520V3_WDT_T18_RESET 15 +#define ZX297520V3_USIM1_RESET 16 +#define ZX297520V3_AHB_RESET 17 +#define ZX297520V3_USB_PHY_RESET 18 +#define ZX297520V3_USB_RESET 19 +#define ZX297520V3_HSIC_PHY_RESET 20 +#define ZX297520V3_HSIC_RESET 21 + +#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CBD703C870E for ; Thu, 16 Jul 2026 21:36:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237766; cv=none; b=SzNa/DVsLxH+O7A9Mp0JlFgkfWJ47Ac4CrcHvJZmL2TaC7HSersTZhL3FcJUozZ+vbmjsx+4pPit/52BCd/pck6AmjPjiLd92anXTmY9PCQ20GFDSYXMrR9MuKtqa6PXK1q5IZXJqHecmQLlhOiIG366OmFSI04SgU7YaM1Nsog= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237766; c=relaxed/simple; bh=Jx+q10fDqymoLmvzemEkN3kNUvh3kYeIHQr2ES223+g=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=G6s1hCsgM2SUAhATyspFmdUSrME7Rw1V4WPSFuKcoerAhopmWmUaNBhUu1XpalVB8xHpolmqPJTyakm/6MSPOKeskqljAB4mEfac6B/Q/UJdkViEnRIfY6wvC3AOu7iq0Aha7uXneyOBpXn6NtTzKFp6o8F2/UUUBGTOW9KISXc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=fzrN/xLY; arc=none smtp.client-ip=209.85.221.45 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fzrN/xLY" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-475881b9a4bso3647249f8f.3 for ; Thu, 16 Jul 2026 14:36:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237763; x=1784842563; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=km69BcPb9PrPYwpxcKjbK1SQK4wWTF79y2vSAA6YjyE=; b=fzrN/xLYmWLpWAqtMxsoHsGUPIw82SdTGdmhWNJwP9TCQO5DBPxfpeBpjNXaSjhFaV 3F3OiA/VHDHrw8I5tSPg3vtYjGlX+mK09GVVMuwCIg2myzwUo81XzD23bIaUArhmzYz5 fWwcNMgyh5tqw5c1IAjjKrorvSAQ+jLNJ3pdqMaINv7z47Wf7DulVKf3BXyUHb1hQelW dOGq93C9yMXA9RYrLlvT/Vrm6ET1PRbWZkhSa/aYkHxXfTr9nARs7OSNKo6FXf6/wBKK 9h5hGnCVBvQO138r8MiiCll/VSSwSxAfwy8iUGbDzn8i1gdkz7Z+P9sY8OtcxYTZp0U+ /Z+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237763; x=1784842563; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=km69BcPb9PrPYwpxcKjbK1SQK4wWTF79y2vSAA6YjyE=; b=grbaIXUXHsPmykG6kqx58gz6YvroLktC3865kW2edMpDnLBpvPtQA6ptly0Gp49w69 xofrlGa1Dor0W8K/LTxIpBRo4irGPi0ZQctql+wKzmMHRcJKa7aKX3OM80Br5VkZoowi vqq0H+YtGAuP3Khke2Pf81HMAOkiux3V0dIaAbTiVewr+70dSqpvvkHqjwoCK0sKot8l n2L1gjuaOLj+KwZZpFsz4rp8HNAz7YRmKlVNcLbrchJi4PTf0FyJ5d0up4FW4GfvKyp+ tx9yyGNY+t56621uxcrHIR8wD1s4Vb3yAt3Gfbl+nJ6qNt7PYl6W89UKOet2CFSOO2Wg xifA== X-Forwarded-Encrypted: i=1; AHgh+RrRgYPmv/gyrSOQ0AirJvVHAN8gxMFQzSt0x1oHh5/MgmT7ff7VEuXOu0/sn699HCV0M2Bv2dlWF7hiYLk=@vger.kernel.org X-Gm-Message-State: AOJu0Yw/Ig7fP8Q9h4X3CRXzJretx3P5923jGNeVNgdpc/OSBVAi5U7f 3Dv8OnrDBVcQvnPHwnQ9YX90/sW5p8G0AceICxqeYBCPkDjAr11QZzOq X-Gm-Gg: AfdE7cnI9JLpbWbl/toz2+mqtMEHPw+awfTlvDEPtPmPST/4M3UQ35EmJHmjkRD9iHK YiNzhqIMeXjW8mMmaldvR4UUnZH1lvYpPoRoqG/+sHj0qErt6rmKIoxb+GCp7KFd3iG3R5olicG Fp3BDZDwjA+5Fy6PKDEjqgXD+b9t5lnbEYa35qXpXV6Kvk/wl9dYswsZSRpnZHHBg8lExCBzBTf 2h1xx16CW+6wwHOWKN6A+hO7jl8PKthQ6IzWxheYijLCBcRJZkn0xgJTf3jVxDyUYmplL0Aqojg b+K34FdsMzVG/vP799fZ7ZPN6fJX20l3FCsNLaM/8I7wDFp+brfGs5Gq6qZqHOeNDtC35eZq0yF 21lsYyLfMXU6rIsdkqcGVgLcj/4lNIeybXAL4Mx8gGX0P9/6AKBEecvdc77Wp+dHYAk2a8hAZdU tmzenhPeE65XnA X-Received: by 2002:a05:6000:2dc5:b0:46e:1815:6a83 with SMTP id ffacd0b85a97d-47f6088b5b9mr937456f8f.29.1784237762829; Thu, 16 Jul 2026 14:36:02 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.35.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:02 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:39 +0300 Subject: [PATCH v7 03/13] dt-bindings: clk: zte: Add zx297520v3 matrix clock and reset controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-3-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8790; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=Jx+q10fDqymoLmvzemEkN3kNUvh3kYeIHQr2ES223+g=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xSu2gSqcQRCgsE8V5zhgmhe0wndVU/WgoJ ANDD4JiUaeJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiIwXA/+KYHZ8ptN2bw+UZR9Yer1+hLy2/sJDWT CEnLCWXpqFR/qgGkKF4SFm6/FZZCAWG9Q4oMQJrcGwoUT73Zf2FcS55Rl906tGy2E9kh0puDVaB U9VgTxxiJUqgXBYjfLLroDtpQyu9ivI3ZJl2lOaYA/s8aTtehrU01XLF1ETwWQXQ/Tnpyx44HYE YNIeFcBOaUggHxoy3r7mVWFCVRYoSUpRHCRIPHXJavx5ErzI4IsJF3GJIbTjkQmfSS9H8MQm1EQ WmByUfTpo1G44tnEnAGO2dF+9rN+RlhHO6XSBo4HBXx8Z3p5pFZnCa6c07IoACqhsF2XE3Zj9cs TtM6JQj1vqjsW4xA/cavll9fakpJNpL8PJ/lqg4lnA2Ikz+XVazyK6ftzfvu2xS4W4JW+jVnxD8 aVD+WdCV8QSkxEbOwzvmSwyvFmoNJkqgxKY66ZZ1yvRNAZOVJFEiuHmMt+yvhZQsbSETdQG5zxD /vHh5GYCMYKQWKc6VmxvsN9/LVWMVXcRZ/Ze10GRcmaJKiTm1RcepQ3TqDwgAo2TyToLXmBkj9V bbRV5av40oZiHXrn26bgNLa2s5RnVXzMHmjZ2YlbiiEMBvHIBYY0Y3fAQc27E10wEgqmpRtkEFy Lp1P6AAsn9GS+H+MEtz3clrHZ5Xh5WbC28vJy9+TWU0P2CMs92X4= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This controller contains clocks and resets for high speed devices on the zx297520v3 board and hardware spinlocks that I expect will be necessary to communicate correctly with the LTE DSP firmware blob. I don't know much about the hwlocks yet other than that they exist, so there is no header yet adding meaning to their indices. Presumably that meaning doesn't exist in hardware and is de facto defined by ZTE's firmware blobs running on the rprocs. A simple MFD driver will instantiate independent clock, reset and hwlock drivers. Signed-off-by: Stefan D=C3=B6singer --- v6->v7: *) Moved it back to clock/ *) Remove syscon compatible again. I looked into remaining unknown registers and I am convinced that there is no odd misc register left that can't be exposed as a proper subsystem provider. The controls in 0x100 that ZTE's DRAM reading code exercises are auto clock gating controls and the actual mailbox is in a different controller. Unknown registers in 0x120-0x12c are a frequency voting mechanism for the AXI bus clock. The driver will participate in that voting rather than set the frequency via 0x0. If need be it could be exposed as #interconnect-cells, but it won't necessitate "syscon". *) Reduce the number of input clocks to match register controls in topclk's input control that affect matrix and LSP. *) Add DDR mux and gates. Not to change them, but to make sure CCF knows about which PLL is feeding the sysmem memory Changes v5->v6: Add syscon compatible - Conor suggested this after v4 and I forgot it in v5. v4->v5: Move binding to soc/zte Remove topclk from the example Add #hwlock-cells for hw spinlock registers Add more clocks I stumbled into: sram0 and another LTE related device v3->v4: Split matrixclk into its own controller again because syscon/regmap deals poorly with device nodes that have more than one memory region. As a consequence I am passing all PLL outputs generated on Topclk down to Matrixclk. --- .../bindings/clock/zte,zx297520v3-matrixcrm.yaml | 91 ++++++++++++++++++= ++++ MAINTAINERS | 1 + include/dt-bindings/clock/zte,zx297520v3-clk.h | 41 ++++++++++ include/dt-bindings/reset/zte,zx297520v3-reset.h | 12 +++ 4 files changed, 145 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixc= rm.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.= yaml new file mode 100644 index 000000000000..55b1a42836c7 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml @@ -0,0 +1,91 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-matrixcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC matrix clock and reset controller + +maintainers: + - Stefan D=C3=B6singer + +description: | + This controller contains clock and reset controls for high speed devices= on + the zx297520v3 board: The CPU, RAM, SDIO and Ethernet clocks and resets = are + found here. This controller requires PLL-generated clocks from Topcrm as= well + as the fixed 26 MHz and 32 KHz oscillators found on this board. + + This controller also contains hardware mutex registers for synchronizati= on + with different processors on this board. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. Resets are defi= ned in + the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. + +properties: + compatible: + const: zte,zx297520v3-matrixcrm + + reg: + maxItems: 1 + + clocks: + items: + - description: 26 MHz external oscillator + - description: 32 KHz external oscillator + - description: Main PLL output from topcrm (usually 624 MHz) + - description: Main PLL subdivision factor 5 + - description: Dpll output from topcrm (usually 491.52 MHz) + - description: Gpll output from topcrm (usually 200 MHz) + - description: Gpll subdivision factor 2 + - description: osc26m work clock from topcrm + + clock-names: + items: + - const: osc26m + - const: osc32k + - const: mpll + - const: mpll-d5 + - const: dpll + - const: gpll + - const: gpll-d2 + - const: wclk-osc26m + + "#clock-cells": + const: 1 + + "#hwlock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - "#clock-cells" + - "#hwlock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + clock-controller@1306000 { + compatible =3D "zte,zx297520v3-matrixcrm"; + reg =3D <0x01306000 0x400>; + clocks =3D <&osc26m>, <&osc32k>, + <&topcrm ZX297520V3_MPLL>, <&topcrm ZX297520V3_MPLL_D5>, + <&topcrm ZX297520V3_DPLL>, <&topcrm ZX297520V3_GPLL>, + <&topcrm ZX297520V3_GPLL_D2>, <&topcrm ZX297520V3_GATED_OSC26M>; + clock-names =3D "osc26m", "osc32k", "mpll", "mpll-d5", "dpll", + "gpll", "gpll-d2", "wclk-osc26m"; + #clock-cells =3D <1>; + #hwlock-cells =3D <1>; + #reset-cells =3D <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 5f962b9947ab..6d153d2cba79 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3878,6 +3878,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated fo= r non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bi= ndings/clock/zte,zx297520v3-clk.h index 1f010ff4e6ca..09ee3de679d9 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -63,4 +63,45 @@ #define ZX297520V3_HSIC_WCLK 55 #define ZX297520V3_HSIC_PCLK 56 =20 +#define ZX297520V3_SYS_TIMER_WCLK 1 +#define ZX297520V3_CPU_WCLK 2 +#define ZX297520V3_CPU_PCLK 3 +#define ZX297520V3_ZSP_WCLK 4 +#define ZX297520V3_DDR_CTRL_PCLK 5 +#define ZX297520V3_DDR_CTRL_WCLK 6 +#define ZX297520V3_EDCP_WCLK 7 +#define ZX297520V3_EDCP_PCLK 8 +#define ZX297520V3_SD0_WCLK 9 +#define ZX297520V3_SD0_PCLK 10 +#define ZX297520V3_SD0_CDET 11 +#define ZX297520V3_SD1_WCLK 12 +#define ZX297520V3_SD1_PCLK 13 +#define ZX297520V3_SD1_CDET 14 +#define ZX297520V3_NAND_WCLK 15 +#define ZX297520V3_NAND_PCLK 16 +#define ZX297520V3_DMA_PCLK 17 +#define ZX297520V3_MBOX_PCLK 18 +#define ZX297520V3_PDCFG_WCLK 19 +#define ZX297520V3_PDCFG_PCLK 20 +#define ZX297520V3_SSC_WCLK 21 +#define ZX297520V3_SSC_PCLK 22 +#define ZX297520V3_AXI_WCLK 23 +#define ZX297520V3_GMAC_WCLK 24 +#define ZX297520V3_GMAC_PCLK 25 +#define ZX297520V3_GMAC_AHB 26 +#define ZX297520V3_VOU_WCLK 27 +#define ZX297520V3_VOU_PCLK 28 +#define ZX297520V3_LSP_MPLL_D5_WCLK 29 +#define ZX297520V3_LSP_MPLL_D4_WCLK 30 +#define ZX297520V3_LSP_MPLL_D6_WCLK 31 +#define ZX297520V3_LSP_MPLL_D8_WCLK 32 +#define ZX297520V3_LSP_MPLL_D12_WCLK 33 +#define ZX297520V3_LSP_OSC26M_WCLK 34 +#define ZX297520V3_LSP_OSC32K_WCLK 35 +#define ZX297520V3_LSP_PCLK 36 +#define ZX297520V3_LSP_TDM_WCLK 37 +#define ZX297520V3_LSP_DPLL_D4_WCLK 38 +#define ZX297520V3_SRAM0_PCLK 39 +#define ZX297520V3_GSM_CFG_PCLK 40 + #endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-= bindings/reset/zte,zx297520v3-reset.h index 43db72bb59de..4682d4a599c6 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -29,4 +29,16 @@ #define ZX297520V3_HSIC_PHY_RESET 20 #define ZX297520V3_HSIC_RESET 21 =20 +#define ZX297520V3_CPU_RESET 0 +#define ZX297520V3_DDR_CTRL_RESET 1 +#define ZX297520V3_EDCP_RESET 2 +#define ZX297520V3_SD0_RESET 3 +#define ZX297520V3_SD1_RESET 4 +#define ZX297520V3_NAND_RESET 5 +#define ZX297520V3_PDCFG_RESET 6 +#define ZX297520V3_SSC_RESET 7 +#define ZX297520V3_GMAC_RESET 8 +#define ZX297520V3_VOU_RESET 9 +#define ZX297520V3_LSP_RESET 10 + #endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D3EAE3C98BA for ; Thu, 16 Jul 2026 21:36:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237770; cv=none; b=sGRo7ODxpVGhNeLuiW9fr10AwsN5NTBeAOwWC1LKr7i3QKmt6EAuCydBbXw1hew+AxLG2+X5cUPWw9p6SYktxexfMWVf4i+XPrwKZwzVqop67m2a7ddHUzO6rCLyReBWryd5MxAoNSshBycR5cVvh71WPUCCv9cofQnJ5eAjtW4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237770; c=relaxed/simple; bh=gYcmT5SJ16KzbPHs7e4lJ3zArzZ0tzAmOzulOMxIRpc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lx9WXtgFCBUoAM1QHhEmrBpkpHkZPgzJAfAYzHUQqYra6UL9JR0/mfcAJhfFVDhC73S2Fh2oYfNi/kfmGLk65pCuWFhbLhH1rnDeqBzRL7qTkM5sYowcziXv5NCmAxQJsckSTmf06gsDpmh9zpEptwYWUmDLN9HpdX86I7YA0nA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=n3yTOW8y; arc=none smtp.client-ip=209.85.221.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="n3yTOW8y" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-47df6a5202bso4750344f8f.0 for ; Thu, 16 Jul 2026 14:36:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237767; x=1784842567; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=5DP6p2yHa/CcMRK7GLBZhA5Xgmib1P3Zs9Lq82vtGTA=; b=n3yTOW8yEy2W40F4wM1O+6IWQG1V7ivLM5moZv9/hxay16RfA2StWzGZSiD7iAplTK 599GVsTtOpnCRDBJg3Jtusp5H5AmPMUa3x1wi7gHGdKfxdFG0h0hV1f2yw/n9Pf2YCPO G54i88SS4fI2QXXr8/s674xDCWLJ2G9GLZTFfLphqs21Qzoj/vuVpbIHFxxTBNUsJvOo wwzSAGgKPL7uS5DEiId/U6xDQc/uJT2Q/46vpqDOzmOyjLJU0PBIjewy6AI9sMm6trH9 zDo8tPRFanc9yFjxc4pLT3Jsfsq7unYXZqMWVwe48njUJ9CZPB1LKNXAwQooOhmkCt5N V0FQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237767; x=1784842567; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=5DP6p2yHa/CcMRK7GLBZhA5Xgmib1P3Zs9Lq82vtGTA=; b=QG3QLj9sEcnwWLRj0sJpHSkM4Cwz4IFAmeoBfIQhXGwPR8023GvIJ67SdSLdl8w6XG KTAAzfUe2EjPqrDX1viAe93kwFFCWNxLiJCzxgOHDoa5/Ce1D/TzALOrEJikwdKYzWVw r4dVI76j/NX4U48EnlTttEShGSllmyNeLO9YGolf01nRwm2s6dJzIUrG9fuGzdIej/Wh H8+/SShhxCTko9RX10XeBWukFXg8Y3+UxcBu1aPBsSQDY8EODWHSE3yi9pHEguPMCv0A 6v5vTaSO6v2vLjdHeKL46CiLQAzbp52I37u5ensHlVKaQ2nPimbWcbVcHgE86SBaf9ZM HmAA== X-Forwarded-Encrypted: i=1; AHgh+RogacUcsBWlO397L8zisi82znYImkFRxwBj5HBaoWboKvvd6Ns2GxKkUxnQktNLc8rF46Df7RH2YZBHWCY=@vger.kernel.org X-Gm-Message-State: AOJu0Yw4m8U8ISfa/J0ArNYRS1lzILM/q/84YWpl64L1I3+3ALe4lJbc LMKTKiPJjukFww3i5cj94qKTjBQeTYvEO247O3vTMmfFcFFViOBAEjvF X-Gm-Gg: AfdE7cnLgHd8E00hwy+TLNpbVhzKMDdrUP0ErKUUeiOZLSLJ+/W/LcQ2UsPHs2NzCTI uz93AlKGsV62zo+PzqiDbHsf93D0zAKPga1CZ2hgxZe3E0XZtORzlDRC8S3Wr9cBNXr9x57VAKv NQ5WfydowToepNhCl8dv/L3yRX68Hf1wn1X7xPFT2x1WqaRfQvktSCoildeTJ3/XL2D+l2/+Ion +bDGZuTyaIWHOjMzvpmZeweu2GrkeK56GUgZzmHkxescXgyUeZqqP+NN1s+ELxRfC3n4moVK7DZ w/LfkwrXyyQAxson0Rk2HkfM9UgKqfdgTUODfV8GeVG9BnOkCcJtD8NYvMA5onoP/UpS2lf/3BA WfgE8ZTP+1o3HaHep4f84qA+oKYDuKkZQmZzhWmMpgyKMyTnodQ6Oqr1zVk5OuqYEGgJi559cny JntWA5reOPRkOi X-Received: by 2002:a05:6000:186c:b0:473:1089:154f with SMTP id ffacd0b85a97d-47f4fc51420mr10659026f8f.0.1784237766986; Thu, 16 Jul 2026 14:36:06 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:06 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:40 +0300 Subject: [PATCH v7 04/13] dt-bindings: clk: zte: Add zx297520v3 LSP clock and reset controller Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-4-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8283; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=gYcmT5SJ16KzbPHs7e4lJ3zArzZ0tzAmOzulOMxIRpc=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xOb3DS42wYGwsdjarwcr/mneZNil63T/4W 6o9UDh/HuyJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLlUw/7B8NHuS3CQ4Jg8Utn8bD8c8ESTEyjkhw BJQL3pXovBw22uKXEVinoBrVTuV7hmoWmszohC8SmhHu7q6dPnrNXPZ5zLeYtQFiZCGrNLbv1Ky TG+CjFIIhfPqZWTWP4FhBHjerLMTYFEkq6vkLG04Xz/fW0I6X5sD+KwVJin0sH+qTC+zfH/UN5w 5rbankHqxVw8BYyRKitRduCoAXoSbuX5W6eyvE2ltCeiSW5W7aZTixIG0TxmirB9J7BoJMaG/Ly JNqk/zfaMwIy34srMdPa/OxV0prFYw4PgYXyz2ke8LFTHmlsTENYPsv20Y6NjWF7tqUhnjepKTo wSNLO5JjCRqXPyG9URkDS8K2FOnKDkUf+NgsnbYFs32sCq27ArageaFMNvGCgIesaPxAsvsg8Gd rzT4bkKrVeeGu1ZHmGPhNPGjHNokBbO8e8iAFFIX7NW8Bo4kQMoCFPF1TdBlOLLw0BTS9c4bDXU eiawR7GNl2enC+ktT652nSzAut3oMdjInYXIW7JqK9WaVHjDkihcDU9QEP+jjwPKwiZL4A+SwAs 4jGP4w1Nf9kTRpz+0W5CxYXoZ3ICY8w7t7ZZtjgtNtREWYuokPEHewO2DEo3w2c11ocuYrr4jWQ YxBHOjX8T4LrMRvfdzs9Sq/GyBtRVyUxItK9hwGdH6rlxzLSublQ= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 The clock controller of the zx297520v3 Low Speed Peripherals is relatively clean. One register per device with gates, muxes and resets and for some devices a divider. There are even bits in the matrix controller to control propagation of clock lines down to LSP. The clocks are sorted by register address and I am convinced that the device list is complete. There are however a few more registers that are likely extra dividers for TDM and I2S devices Signed-off-by: Stefan D=C3=B6singer Reviewed-by: Krzysztof Kozlowski --- Patch changelog: v5: Rename from lspclk to lspcrm Remove matrixcrm from example v4: Order properties compatible->reg->clocks->clock->names->#cells --- .../bindings/clock/zte,zx297520v3-lspcrm.yaml | 101 +++++++++++++++++= ++++ MAINTAINERS | 1 + include/dt-bindings/clock/zte,zx297520v3-clk.h | 37 ++++++++ include/dt-bindings/reset/zte,zx297520v3-reset.h | 19 ++++ 4 files changed, 158 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.= yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml new file mode 100644 index 000000000000..3ef8fad3c93a --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml @@ -0,0 +1,101 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-lspcrm.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: ZTE zx297520v3 SoC LSP clock and reset controller + +maintainers: + - Stefan D=C3=B6singer + +description: | + This clock and reset controller controls low speed peripherals on the bo= ard. + This is a relatively isolated subsystem containing UART, I2C, I2S and SPI + devices. The controller is responsible for bringing the devices out of r= eset + and enabling their clocks as needed. + + The controller receives its clock signals from the matrix controller and= need + to be declared as clock inputs. + + All available clocks are defined as preprocessor macros in the + "include/dt-bindings/clock/zte,zx297520v3-clk.h" header. Resets are defi= ned in + the "include/dt-bindings/reset/zte,zx297520v3-reset.h" header. + +properties: + compatible: + const: zte,zx297520v3-lspcrm + + reg: + maxItems: 1 + + clocks: + items: + - description: Main PLL divided by 5 output from matrixcrm (124.8 MH= z) + - description: Main PLL divided by 4 output from matrixcrm (156 MHz) + - description: Main PLL divided by 6 output from matrixcrm (104 MHz) + - description: Main PLL divided by 8 output from matrixcrm (78 MHz) + - description: Main PLL divided by 12 output from matrixcrm (52 MHz) + - description: Main oscillator output from matrixcrm (26 MHz) + - description: Timer oscillator output from matrixcrm (32 KHz) + - description: LSP pclk output from matrixcrm (26 MHz) + - description: TDM wclk mux output from matrixcrm + - description: DPLL divided by 4 output from matrixcrm (122.88 MHz) + + clock-names: + items: + - const: mpll-d5 + - const: mpll-d4 + - const: mpll-d6 + - const: mpll-d8 + - const: mpll-d12 + - const: osc26m + - const: osc32k + - const: pclk + - const: tdm-wclk + - const: dpll-d4 + + resets: + maxItems: 1 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + +required: + - compatible + - reg + - clocks + - clock-names + - resets + - "#clock-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + + clock-controller@1400000 { + compatible =3D "zte,zx297520v3-lspcrm"; + reg =3D <0x01400000 0x100>; + clocks =3D <&matrixcrm ZX297520V3_LSP_MPLL_D5_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D4_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D6_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D8_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D12_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC26M_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC32K_WCLK>, + <&matrixcrm ZX297520V3_LSP_PCLK>, + <&matrixcrm ZX297520V3_LSP_TDM_WCLK>, + <&matrixcrm ZX297520V3_LSP_DPLL_D4_WCLK>; + clock-names =3D "mpll-d5", "mpll-d4", "mpll-d6", "mpll-d8", "mpll-= d12", + "osc26m", "osc32k", "pclk", "tdm-wclk", "dpll-d4"; + resets =3D <&matrixcrm ZX297520V3_LSP_RESET>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 6d153d2cba79..a135ec070314 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3878,6 +3878,7 @@ L: linux-arm-kernel@lists.infradead.org (moderated fo= r non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/bindings/clock/zte,zx297520v3-lspcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bi= ndings/clock/zte,zx297520v3-clk.h index 09ee3de679d9..2c947f467373 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -104,4 +104,41 @@ #define ZX297520V3_SRAM0_PCLK 39 #define ZX297520V3_GSM_CFG_PCLK 40 =20 +#define ZX297520V3_TIMER_L1_WCLK 1 +#define ZX297520V3_TIMER_L1_PCLK 2 +#define ZX297520V3_WDT_L2_WCLK 3 +#define ZX297520V3_WDT_L2_PCLK 4 +#define ZX297520V3_WDT_L3_WCLK 5 +#define ZX297520V3_WDT_L3_PCLK 6 +#define ZX297520V3_PWM_WCLK 7 +#define ZX297520V3_PWM_PCLK 8 +#define ZX297520V3_I2S0_WCLK 9 +#define ZX297520V3_I2S0_PCLK 10 +#define ZX297520V3_I2S1_WCLK 11 +#define ZX297520V3_I2S1_PCLK 12 +#define ZX297520V3_QSPI_WCLK 13 +#define ZX297520V3_QSPI_PCLK 14 +#define ZX297520V3_UART1_WCLK 15 +#define ZX297520V3_UART1_PCLK 16 +#define ZX297520V3_I2C1_WCLK 17 +#define ZX297520V3_I2C1_PCLK 18 +#define ZX297520V3_SPI0_WCLK 19 +#define ZX297520V3_SPI0_PCLK 20 +#define ZX297520V3_TIMER_LB_WCLK 21 +#define ZX297520V3_TIMER_LB_PCLK 22 +#define ZX297520V3_TIMER_LC_WCLK 23 +#define ZX297520V3_TIMER_LC_PCLK 24 +#define ZX297520V3_UART2_WCLK 25 +#define ZX297520V3_UART2_PCLK 26 +#define ZX297520V3_WDT_LE_WCLK 27 +#define ZX297520V3_WDT_LE_PCLK 28 +#define ZX297520V3_TIMER_LF_WCLK 29 +#define ZX297520V3_TIMER_LF_PCLK 30 +#define ZX297520V3_SPI1_WCLK 31 +#define ZX297520V3_SPI1_PCLK 32 +#define ZX297520V3_TIMER_L11_WCLK 33 +#define ZX297520V3_TIMER_L11_PCLK 34 +#define ZX297520V3_TDM_WCLK 35 +#define ZX297520V3_TDM_PCLK 36 + #endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/reset/zte,zx297520v3-reset.h b/include/dt-= bindings/reset/zte,zx297520v3-reset.h index 4682d4a599c6..69eef84b2f29 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -41,4 +41,23 @@ #define ZX297520V3_VOU_RESET 9 #define ZX297520V3_LSP_RESET 10 =20 +#define ZX297520V3_TIMER_L1_RESET 0 +#define ZX297520V3_WDT_L2_RESET 1 +#define ZX297520V3_WDT_L3_RESET 2 +#define ZX297520V3_PWM_RESET 3 +#define ZX297520V3_I2S0_RESET 4 +#define ZX297520V3_I2S1_RESET 5 +#define ZX297520V3_QSPI_RESET 6 +#define ZX297520V3_UART1_RESET 7 +#define ZX297520V3_I2C1_RESET 8 +#define ZX297520V3_SPI0_RESET 9 +#define ZX297520V3_TIMER_LB_RESET 10 +#define ZX297520V3_TIMER_LC_RESET 11 +#define ZX297520V3_UART2_RESET 12 +#define ZX297520V3_WDT_LE_RESET 13 +#define ZX297520V3_TIMER_LF_RESET 14 +#define ZX297520V3_SPI1_RESET 15 +#define ZX297520V3_TIMER_L11_RESET 16 +#define ZX297520V3_TDM_RESET 17 + #endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 02FE43C8733 for ; Thu, 16 Jul 2026 21:36:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237774; cv=none; b=bGk55aNc6E7S6is7C7ujEFotOy/zdmaIFcdgiiJaeRrpoNzEFtzW4PnFCEbDdkpwFYsNgIutZFPbVG6uVbf9gGiU/1nuf8Xdw/m6qCAfk1SD7Dnk2j9hyVrBNdJomY9ZmzstKPc0ioFx9PyZTi1w5uAzmU1hYIc9nxajb+uAVcc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237774; c=relaxed/simple; bh=2mYvcwfD2/84sfiGKwxlDrpz4RSNk3vhfW5QKBkhpwQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Klxia0X6kzN4sti4fZonH5lpzX/JX4UKehUpDeMJvRw4ANDSaXUERZRnsz/aHwhZtPxjdKZq85HNmfOPClMJ5e41AMbk+IhqSMKNld5gzgn8qsRCHl85BEBsYetuK8hnXwj77tVrQsyB5wD26STztdRQ1WCJn/D8vJ9Jw/Rx1a4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=sjdbQsm/; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sjdbQsm/" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-47f365afc5aso3075190f8f.0 for ; Thu, 16 Jul 2026 14:36:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237771; x=1784842571; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=RGGKwNQS8rE2EFNG1SfW+LC4ffRUcLaY6ky+4U7wPJk=; b=sjdbQsm/9M9giToUHwTreDyfJkvd4ZrLoluKC5BSgKKoakyMZ5/osIlCpJ/LPTFhRU 3cCPZ7VrMqQfj+s6GfK/j+WKHewV/Qm5fxLVl65PfEy380GFQyidg9NTsvoYLDnKns07 +4aamLfXIt735wi+dv3BrI/KmFg2x7liTPaNroCRT6XMUOTFuIHudx2s4IRpFxn1TRj/ s3cRjwqNiQkFurGDxYG514MoOMpRnh/jbgAtOE/NNAgnG3higtB9j+p2LBUPDSaXyw57 tGWEoFCAwAycg98wp7gE3RIyKyHl9AviF4yaF4LVYXRBiVBosxQEEOwHmRmAYiXlFwAn VENQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237771; x=1784842571; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=RGGKwNQS8rE2EFNG1SfW+LC4ffRUcLaY6ky+4U7wPJk=; b=iusdOQkNM1jLirx/DB6/h1IFuk23TN7cLCQ3gZpm+rec8K13S2s/AwhbJpUoh24ifj ZGWJBjRVAlXdGUOzZkvfOERU+t3cv0K724VXOBDo1gHDABG5GopUTbbRwyonfaQX1jzD /onCDgmeofq4pPgjqEE2tk/oU5RPSKrJQ0qohHUKrU4SOGMe1CU3Xi9iFvyAou8k6ckN fIMlJkss1Jh8a2AxXYgXluEQi7b74G3MXtcbK5Hrbq7oUsbzoLmk2nY2fE+yrZCE92j+ MgTZfuz78z0LZq0/ETab3Ovm1gisF6Cgjji1ZHgX3ZF06J2mUGLcaJMdo4Y3z9HXGm5P kKmQ== X-Forwarded-Encrypted: i=1; AHgh+RoTjbpdkD8/Y6wL8ds2Y3q57G1nwI7H3NPoFsEboSBLpwU59/barN9zkOMnRLlGVdc7/uWvAMb3qmuutn0=@vger.kernel.org X-Gm-Message-State: AOJu0YzlhBD8YrVrMZsi0v8U5NEi5TRWkNRFSA+n27YGBHWNO0WBmeu1 fx/9UuxnOI/MUo28KPGe5xaANBLLba3DjUbSGA0KYgLqYvejpCqkzMV7 X-Gm-Gg: AfdE7ckqSI14/ajHwcOxlL+HVvRvquh+7M4JOGNXA4xq/SxM4tNBkyCIK6NkrYdOqje ZC29Awj8teWe7aiVxlDSZ4Y38hm4OWuVRCecSg5HVuPdZ/MeQs+Cbr3ex+r+6h9GXz3pA99ORC/ rLTkcoG4VCzQdWAqXTkPP00YZ64VTSQsIJ6tsncgGdeQ1WgIh3PuJBkWD37HdRiI1vM+j0b2NIQ nK8GLmkhRaZuMDAet4jrdIyArSKBsHjWZhZrLxMLUHtHQ4MnaWlQRch4t0JZeEvvZFA80UIKc0d T6tXx9nxszXw95xaM4u9+FLkQqOQ7lv7V0N7NslsyDhKHhRwmVBTNUUj5bPmr2zQTk30sM86qe0 yDQqrbE1IEnqAL16rVmqRnlGlQ28MAF2B0wiDu0QRQEIjK2pFnoBCcjOjys3Aod3Gu+zijMRp/6 gCM4jLrwnFbB09 X-Received: by 2002:a5d:5f55:0:b0:47f:5567:19b5 with SMTP id ffacd0b85a97d-47f55765ccfmr8162327f8f.29.1784237770976; Thu, 16 Jul 2026 14:36:10 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:10 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:41 +0300 Subject: [PATCH v7 05/13] mfd: zx297520v3: Add a clock and reset MFD driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-5-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=6631; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=2mYvcwfD2/84sfiGKwxlDrpz4RSNk3vhfW5QKBkhpwQ=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xjOd7pc5cdAkEb0DBDo3qus4da37vTAruc GGmlJG9IXmJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKGHRAAoS2DLKD2/vbCxKerpZKCDtshILMZB7C oHbpCgwrJFOqpFTY+SgxgovJnf52uLrH9S2mkq54vEp1Alqvsx9mrb0V30xi53hvCNhd+TC82zv 0Toqnqe1BlZ3Q/U9r4cron+6lM3gG8ZB9osO79lpAnct+c+qvsJX0W0e16zktj7IcfwjyLabapf LoOU77cCV1zY4pcuzxJ/zgfRS8RM0+tpU3sX8c+dX6dVFlx4lbooVt0/lY10GoDU/xQaDoqdP/1 rgL4oRqmmygZr9dabI++hf00epfRgqxnUzJydnDy9Gncd38mwIFwbs3ROb6uqWFOlNlTX2CwpFt d3BXDf78VW4Y0vlJ3YVltScH2kNCsvJyC1MV6htlSsivYbx2YPmKENfBB88bXa7/s3912BvkmHs r9VTd6p30jSH/3MXSHXkFSw6jRVroRAqxVgywOfFWHPGQPa22QA5C3cb/HzRGQB+cwqPovATMuX V8YVPm9I8eZI7N8luqqQsbpAwzFjXVnpjW6iUgqH9Fug3iMWYDyMQKrYetsNEL10S53Za34O06B 9wXyy6U0qCWBOIC9IRUD9dF0/Ze4b9DOWSf4vNbCnxvoxOJdkzvhu2Hv0ktQrx7vCYh0Hkvcahl fa8OoLIPgM2j16fnDKtRKBjbpn002VphYs3OAZNMz+asrd0Q5w0I= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This driver registers child devices for the zx297520v3 clock and reset controllers. The clk-zx297520v3 and reset-zte-zx297520v3 submitted in the next patches will drive the respective functionalities. Signed-off-by: Stefan D=C3=B6singer --- Changes v6: Make the ZTE SoC driver section depend on HAS_IOMEM (Sashiko). The entire MFD section, which contains MFD_CORE, depends on HAS_IOMEM even with COMPILE_TEST. Add a NULL ptr check for of_device_get_match_data (Sashiko). While not uniform, rave-sp, rohm-bd9576, atc260x, da9052-i2c protect against incorrect manual attachment that way. Add lspclk here as well in an attempt to satisfy both Conor Dooley, who asks for MFD for top and matrix, and Philipp Zabel, who prefers aux but at least wants the reset driver limited to one driver type. Changes v5: Use MFD instead of Aux bus for top and matrix crm because of extra functionality: Reboot in top, hwlock in Matrix. LSP clocks stay with the aux bus and are thus not handled in this driver. The clk driver will bind directly to the lspcrm node. --- MAINTAINERS | 1 + drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/zte/Kconfig | 20 ++++++++ drivers/soc/zte/Makefile | 3 ++ drivers/soc/zte/zx297520v3-crm.c | 99 ++++++++++++++++++++++++++++++++++++= ++++ 6 files changed, 125 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a135ec070314..6ca3312aa746 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3884,6 +3884,7 @@ F: Documentation/devicetree/bindings/clock/zte,zx2975= 20v3-topcrm.yaml F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/soc/zte/ F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/phy-zte-zx297520v3-usb.h F: include/dt-bindings/reset/zte,zx297520v3-reset.h diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index a2d65adffb80..5cc1ade4ce52 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -31,5 +31,6 @@ source "drivers/soc/ux500/Kconfig" source "drivers/soc/versatile/Kconfig" source "drivers/soc/vt8500/Kconfig" source "drivers/soc/xilinx/Kconfig" +source "drivers/soc/zte/Kconfig" =20 endmenu diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index c9e689080ceb..63b3f340256c 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_ARCH_U8500) +=3D ux500/ obj-y +=3D versatile/ obj-y +=3D vt8500/ obj-y +=3D xilinx/ +obj-y +=3D zte/ diff --git a/drivers/soc/zte/Kconfig b/drivers/soc/zte/Kconfig new file mode 100644 index 000000000000..0e954e6ce2a9 --- /dev/null +++ b/drivers/soc/zte/Kconfig @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if HAS_IOMEM && (ARCH_ZTE || COMPILE_TEST) + +menu "ZTE SoC drivers" + +config ZTE_ZX297520V3_CRM + tristate "ZTE zx297520v3 Clock and Reset Manager" + select MFD_CORE + default SOC_ZX297520V3 + help + Say yes here to enable the driver for the ZTE zx297520v3 clock and + reset manager MFD driver. This driver provides the host device for + the clock and reset drivers and is required to boot the SoC. You + will also need to enable CLK_ZTE_ZX297520V3 and RESET_ZTE_ZX297520V3 + to build the actual clock and reset submodule drivers. + +endmenu + +endif diff --git a/drivers/soc/zte/Makefile b/drivers/soc/zte/Makefile new file mode 100644 index 000000000000..090ba8aa06c1 --- /dev/null +++ b/drivers/soc/zte/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_ZTE_ZX297520V3_CRM) +=3D zx297520v3-crm.o diff --git a/drivers/soc/zte/zx297520v3-crm.c b/drivers/soc/zte/zx297520v3-= crm.c new file mode 100644 index 000000000000..8b82ccba4e90 --- /dev/null +++ b/drivers/soc/zte/zx297520v3-crm.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ + +#include +#include +#include +#include +#include + +struct zx297520v3_crm_data { + const struct mfd_cell *cells; + unsigned int num_cells; +}; + +static const struct mfd_cell zx297520v3_topcrm_devs[] =3D { + { + .name =3D "zx297520v3-topclk", + }, + { + .name =3D "zx297520v3-topreset", + }, + { + .name =3D "syscon-reboot", + .of_compatible =3D "syscon-reboot", + }, + { + .name =3D "zx297520v3-usb-phy", + .of_compatible =3D "zte,zx297520v3-usb-phy", + }, +}; + +static const struct zx297520v3_crm_data zx297520v3_topcrm_data =3D { + .cells =3D zx297520v3_topcrm_devs, + .num_cells =3D ARRAY_SIZE(zx297520v3_topcrm_devs), +}; + +static const struct mfd_cell zx297520v3_matrixcrm_devs[] =3D { + { + .name =3D "zx297520v3-matrixclk", + }, + { + .name =3D "zx297520v3-matrixreset", + }, + /* A set of hwlock controllers is found here as well, but no driver is im= plemented yet */ +}; + +static const struct zx297520v3_crm_data zx297520v3_matrixcrm_data =3D { + .cells =3D zx297520v3_matrixcrm_devs, + .num_cells =3D ARRAY_SIZE(zx297520v3_matrixcrm_devs), +}; + +static const struct mfd_cell zx297520v3_lspcrm_devs[] =3D { + { + .name =3D "zx297520v3-lspclk", + }, + { + .name =3D "zx297520v3-lspreset", + }, +}; + +static const struct zx297520v3_crm_data zx297520v3_lspcrm_data =3D { + .cells =3D zx297520v3_lspcrm_devs, + .num_cells =3D ARRAY_SIZE(zx297520v3_lspcrm_devs), +}; + +static int zx297520v3_crm_probe(struct platform_device *pdev) +{ + const struct zx297520v3_crm_data *data; + + data =3D of_device_get_match_data(&pdev->dev); + if (!data) + return -ENODEV; + + return devm_mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, data->cells, + data->num_cells, NULL, 0, NULL); +} + +static const struct of_device_id of_match_zx297520v3_crm[] =3D { + { .compatible =3D "zte,zx297520v3-topcrm", .data =3D &zx297520v3_topcrm_d= ata }, + { .compatible =3D "zte,zx297520v3-matrixcrm", .data =3D &zx297520v3_matri= xcrm_data }, + { .compatible =3D "zte,zx297520v3-lspcrm", .data =3D &zx297520v3_lspcrm_d= ata }, + { } +}; +MODULE_DEVICE_TABLE(of, of_match_zx297520v3_crm); + +static struct platform_driver zx297520v3_crm =3D { + .probe =3D zx297520v3_crm_probe, + .driver =3D { + .name =3D "zx297520v3-crm", + .of_match_table =3D of_match_zx297520v3_crm, + }, +}; +module_platform_driver(zx297520v3_crm); + +MODULE_AUTHOR("Stefan D=C3=B6singer "); +MODULE_DESCRIPTION("ZTE zx297520v3 CRM MFD host driver"); +MODULE_LICENSE("GPL"); --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wm1-f54.google.com (mail-wm1-f54.google.com [209.85.128.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ADB083CAE70 for ; Thu, 16 Jul 2026 21:36:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237779; cv=none; b=ifDwJ2LxxWKhuptbRXHt7/cgctmPr9eKJDVs2Igx9Wh6XRZU89w94g7FEndFF8ycxO/D0FIV2CoXP9e4ecehlr6LsqgsdsInvRQyen0e6Qdlnp5yOPIcihAAvEPx3fmLHK6Fkv5Wzh2bTsqOlXUOG922m95w+dkRadCLS53UTOo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237779; c=relaxed/simple; bh=C5xKHsMuzaBYcEFc16GfaBkK5o1oYFjlxMRTNW9V63E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uSI2wt+lGeT9V1dwtzSZZC0x8mnA2xNrpNXTK1uPhKYALA8/h9b9LFRC48z6fufXwsMDslW3BihphDYLvLAx0/H1Us4HZLaTfW4QuTNqud4IUoYBnnOo6yytJ3nvb5fclSZuFjhhaS8oKLGljdSt4wr0nBqY63qdHRvvGLXOvq4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=AFmTGeZO; arc=none smtp.client-ip=209.85.128.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AFmTGeZO" Received: by mail-wm1-f54.google.com with SMTP id 5b1f17b1804b1-495437bb891so6187345e9.1 for ; Thu, 16 Jul 2026 14:36:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237776; x=1784842576; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=+mAie+4SRqYB5ehQZsR75LVrdIpVXjXA+qRH2nIqf3c=; b=AFmTGeZOo/ZQhls145BwlbMWT+p9JkvH81ZpCjlV7ZzUQCKKkQg6/MO5UdVFkeCec/ YbxH6aySnPvDbk2A//VlcX9eY4DcIeNBesJUhAqdOO+o13sHoJ8xsJgIyIsVwT4VTrGA irY+K7j+J+sdROXzF6RP7jS10fVEZH2uYagLXc8ZzZ679WMbbOmmpQZGnPtg29Conmbf SYnFHhxvh51ZV+bYZGVr9frK+O/4F0MyfjrVLfo+aHGWKxi45mA+zBCV/5O92UyNW8av 2GvIJdzEE/6TJtNlzVeQNl0UgSSQv9AxzoCvyIgEk9EiE5qOb1Wv9rt2r8cWgH7xvzpN vxag== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237776; x=1784842576; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=+mAie+4SRqYB5ehQZsR75LVrdIpVXjXA+qRH2nIqf3c=; b=lrCfd/GPAV8IAOyAzcYqurS1nIm49x7NCWIRyYtKlIn1r5WkDjF8LF9n8q4z5fmm5O Pv7ZqqmpfsYTFmu3+cmFM71SNrdDR1a7xLk3WDUhV/FwBLMHyIMYIJhGbQ004LvRTpVb QkpZn/z644ufgGx/xw0Q4RlT7TgT4ZaNG4NSGz3sbGM2Rq3fk5g+BrB0MAMmMOgvcdMT dR/Npqffa8gaLSoRDCzFdF39rKjCRzEDrhsT8la5MZKgbjIURxYBDkOrw01K5HGJmKg2 Nm4FKQLYgUa+ZM1+c9BKBOwcjjT+AnA7/tRVQj213B38pOjZzE8v5eeYfzSo7Mysj3rW 9NPQ== X-Forwarded-Encrypted: i=1; AHgh+RoSTwkwTa4XYpMOV3qFCbzZc2AUu9+1EWwO/LJcNYbKSeAI/gqywcwBFgWBfkaA8IqlOCKZhrtFT2qNz3E=@vger.kernel.org X-Gm-Message-State: AOJu0YwajOl/Dxr2t+2A/54Tv7ada7bRbujCR5kCp5ExWi1cirSMnqiE 19740n5mQumoBjSYaq0dW93M16CFi5p4jFrrfFPW7U11ePQqJXatAZkct2RUr4bd4Gey4w== X-Gm-Gg: AfdE7clyl/HnMTQ1QSYCGqc82haDH9nva4G387yPC3d4s2F73OEdrexbqoNXpm46WXY 0ELIavQUCD3XIy4AsQ1l70gGomTFCM6xt+QHV1pqG0la1LoKBr7TeXYmlVQw0pS438cW/kbN6wj OqireBV8HjP9k7IOzmYdKDzzkBZIK+pvewvhTIuJoEyzGqacCu/TXBj2ojVs+GS+aicpiu7ahyQ wWlxSocr/maYSw1jGkZToJggUfw19wIk5gXZpsD8+T+w/fg1eMDtuqHLvML8Q6o34K40q5MYIzg uVojox7/feuhHpP6uchoD0dAqgut+1/7oa+T2fOirM/QFYa5hOdnivLPQR/anHEFtruDVsL+xDX YkVDM/2S9iExpc38tcSMl7ci4Sr1NEV+HWUbXj90hxIu4Q4wf4Gij+CkMnH7Ttv+sgb94FrojmX JgvMzT9emK0pUO X-Received: by 2002:a05:600c:a48:b0:493:b4a3:5ab0 with SMTP id 5b1f17b1804b1-4954288882bmr50519625e9.13.1784237775629; Thu, 16 Jul 2026 14:36:15 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:14 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:42 +0300 Subject: [PATCH v7 06/13] clk: zte: Add Clock registration infrastructure Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-6-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=12642; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=C5xKHsMuzaBYcEFc16GfaBkK5o1oYFjlxMRTNW9V63E=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xti7TkPF9z6pIDzJfNXj1b/BzbhKQGRF9K TeXXhygafaJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiImPA//QyTRrt/qagmCe12CJycWOEDtslxoiz1 6pGKp/qb+XM2zsb62ozc1nWhpjI19jo3f1WETKCR0ODpKgTJUmBj+lhQ87fQrl9XRDHvEuxXars BHUgHY7lCDlcudxmTaoRabCgihzh7JnbOplWKSqBMHrYw010QtSId4T3OxT6HaeiEKwCWDGf5TJ vIeeT3mJlfg4et1C8hB3KChIDRz2a/r14L/2gIN8dEvQEYBdjMFA1DFX8expxfOP/7zcfwfnpQS fhX6BkRKJTq7YSO+goMcVTeV1BISGzmtuIOTHWwDLy1zXzQ9jSbqe+LdNmGykl3urXnMHBBe99x ubtzm2JNmjO3i1GW90eH+aEoBHQ5Jt8z0qLyi8q/WdC93xFOdNqf4jeS31X/TDZh4Dp0ulUpWDC OKzcSBZUImz7wWQe2AUlndMhdM1OVHj7DLK7PTffrNUnPuHcdn5xMKfCmcxMRuk6GaV5YgYZOUN hi21dgcA5jrNl3A7qDh6INzNoCzaoRe0n/BnjrofyZCYS2oeEJ/EFFD8kGLeALFzaC5xt0WvkWe fMhhRQEh11DLGLHEnci0TU3JdGApzyBsvbUZu0R6xBXqaQC2lcOemUhD/oemdD/jGtNYWt3ABjX xaCa3dkdD7bLVhMKq8Cu3fRzA+BE/5ct3R1x2mp7BD/OGQyZPyOY= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 The next patches will implement the regmap clocks and PLL driver. The actual hardware specific clock listing will live in a separate module. Signed-off-by: Stefan D=C3=B6singer --- Version 7: *) Add fixed dividers to handle PLL subdivisions *) Never register PLLs directly as exported clocks - everything on this SoC goes through a gate before it leaves a controller. Version 6: *) Remove auxdev now that LSP clocks also use MFD *) Error codepath fixes pointed out by Sashiko. Version 5: *) Pass the static clk data instead of calling get_match_data to prepare for operating as an MFD child. *) Don't use devm_kzalloc to allocate the auxiliary_device structure. I guess Sashiko is right, and that's what "Because once the device is placed on the bus the parent driver can not tell what other code may have a reference to this data" is trying to dell me. *) Fix error check for device_node_to_regmap. --- MAINTAINERS | 1 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/zte/Kconfig | 16 +++++ drivers/clk/zte/Makefile | 5 ++ drivers/clk/zte/clk-regmap.c | 34 ++++++++++ drivers/clk/zte/clk-zx.c | 155 +++++++++++++++++++++++++++++++++++++++= ++++ drivers/clk/zte/clk-zx.h | 90 +++++++++++++++++++++++++ drivers/clk/zte/pll-zx.c | 16 +++++ 9 files changed, 319 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 6ca3312aa746..f88a2eda737a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3884,6 +3884,7 @@ F: Documentation/devicetree/bindings/clock/zte,zx2975= 20v3-topcrm.yaml F: Documentation/devicetree/bindings/phy/zte,zx297520v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/clk/zte/ F: drivers/soc/zte/ F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/phy-zte-zx297520v3-usb.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1717ce75a907..6f0a863951ca 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -545,6 +545,7 @@ source "drivers/clk/uniphier/Kconfig" source "drivers/clk/visconti/Kconfig" source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" +source "drivers/clk/zte/Kconfig" source "drivers/clk/zynqmp/Kconfig" =20 # Kunit test cases diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index cc108a75a900..13a5478f1112 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -167,5 +167,6 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) +=3D x86/ endif obj-y +=3D xilinx/ +obj-$(CONFIG_COMMON_CLK_ZTE) +=3D zte/ obj-$(CONFIG_ARCH_ZYNQ) +=3D zynq/ obj-$(CONFIG_COMMON_CLK_ZYNQMP) +=3D zynqmp/ diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig new file mode 100644 index 000000000000..0222549dd211 --- /dev/null +++ b/drivers/clk/zte/Kconfig @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE Clock Drivers +# + +config COMMON_CLK_ZTE + tristate "Clock driver for ZTE SoCs" + depends on ARCH_ZTE || COMPILE_TEST + default ARCH_ZTE + select MFD_SYSCON + help + This option selects common clock infrastructure for ZTE based SoCs. + You will need to enable one or more SoC specific drivers to make use + of this. + + Enable this if you are building a kernel for a ZTE designed board. diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile new file mode 100644 index 000000000000..27db07293165 --- /dev/null +++ b/drivers/clk/zte/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_COMMON_CLK_ZTE) +=3D clk-zte.o + +clk-zte-y +=3D clk-zx.o pll-zx.o clk-regmap.o diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c new file mode 100644 index 000000000000..984abeb45ab2 --- /dev/null +++ b/drivers/clk/zte/clk-regmap.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 MediaTek Inc. + * Copyright (c) 2018 BayLibre, SAS. + * Copyright (c) 2026 Stefan D=C3=B6singer. + * Author: Stefan D=C3=B6singer + */ + +#include +#include +#include +#include + +#include "clk-zx.h" + +int zx_clk_register_gates(struct device *dev, struct regmap *regmap, + const struct zx_gate_desc *desc, unsigned int num, + struct clk_hw_onecell_data *clocks) +{ + return -ENODEV; +} + +int zx_clk_register_dividers(struct device *dev, struct regmap *regmap, + const struct zx_div_desc *desc, unsigned int num) +{ + return -ENODEV; +} + +int zx_clk_register_muxes(struct device *dev, struct regmap *regmap, + const struct zx_mux_desc *desc, unsigned int num, + struct clk_hw_onecell_data *clocks) +{ + return -ENODEV; +} diff --git a/drivers/clk/zte/clk-zx.c b/drivers/clk/zte/clk-zx.c new file mode 100644 index 000000000000..db4fad2b4b05 --- /dev/null +++ b/drivers/clk/zte/clk-zx.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ + +#include +#include +#include +#include +#include +#include + +#include "clk-zx.h" + +static int zx_clk_register_fixed_dividers(struct device *dev, struct regma= p *regmap, + const struct zx_fixed_divider_desc *desc, + unsigned int num) +{ + struct clk_hw *clk; + unsigned int i; + + for (i =3D 0; i < num; ++i) { + clk =3D devm_clk_hw_register_fixed_factor(dev, desc[i].name, desc[i].par= ent, + CLK_SET_RATE_PARENT, 1, desc[i].div); + if (IS_ERR(clk)) { + return dev_err_probe(dev, PTR_ERR(clk), "Failed to register clk %s\n", + desc[i].name); + } + } + + return 0; +} + +static void zx_delete_clk_provider(void *data) +{ + of_clk_del_provider(data); +} + +static void zx_clk_disable_unprepare_put(void *data) +{ + clk_disable_unprepare(data); + clk_put(data); +} + +int zx_clk_common_probe(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data) +{ + unsigned int public_clk_count =3D 1, highest_id =3D 0; + struct clk_hw_onecell_data *clocks; + struct regmap *map; + struct clk *clk; + unsigned int i; + int res; + + map =3D device_node_to_regmap(of_node); + if (IS_ERR(map)) + return PTR_ERR(map); + + for (i =3D 0; i < data->num_muxes; ++i) { + if (data->muxes[i].id) { + if (data->muxes[i].id > highest_id) + highest_id =3D data->muxes[i].id; + public_clk_count++; + } + } + for (i =3D 0; i < data->num_gates; ++i) { + if (data->gates[i].id) { + if (data->gates[i].id > highest_id) + highest_id =3D data->gates[i].id; + public_clk_count++; + } + } + + if (WARN_ON(public_clk_count !=3D highest_id + 1)) + return -EINVAL; + + clocks =3D devm_kzalloc(dev, struct_size(clocks, hws, public_clk_count), = GFP_KERNEL); + if (!clocks) + return -ENOMEM; + clocks->num =3D public_clk_count; + + for (i =3D 0; i < data->num_inputs_enable; ++i) { + clk =3D of_clk_get_by_name(of_node, data->inputs_enable[i]); + if (IS_ERR(clk)) { + return dev_err_probe(dev, PTR_ERR(clk), "Input clk %s failure\n", + data->inputs_enable[i]); + } + + res =3D clk_prepare_enable(clk); + if (res) { + clk_put(clk); + return dev_err_probe(dev, res, "Input clk %s enable failure\n", + data->inputs_enable[i]); + } + res =3D devm_add_action_or_reset(dev, zx_clk_disable_unprepare_put, clk); + if (res) + return res; + } + for (i =3D 0; i < data->num_inputs; ++i) { + /* FIXME: devm_get_clk_from_child doesn't do any tree traversal, so it w= orks here + * whether "of_node" belongs to "dev" or a parent of "dev". Is it suppos= ed to be + * used that way though? + */ + clk =3D devm_get_clk_from_child(dev, of_node, data->inputs[i]); + if (IS_ERR(clk)) { + return dev_err_probe(dev, PTR_ERR(clk), "Input clk %s failure\n", + data->inputs[i]); + } + } + + if (data->init) { + res =3D data->init(map); + if (res) + return dev_err_probe(dev, PTR_ERR(clk), "Controller init failure\n"); + } + + res =3D zx_clk_register_plls(dev, map, data->plls, data->num_plls); + if (res) + return res; + + res =3D zx_clk_register_fixed_dividers(dev, map, data->fixed_divs, data->= num_fixed_divs); + if (res) + return res; + + res =3D zx_clk_register_muxes(dev, map, data->muxes, data->num_muxes, clo= cks); + if (res) + return res; + + res =3D zx_clk_register_dividers(dev, map, data->divs, data->num_divs); + if (res) + return res; + + res =3D zx_clk_register_gates(dev, map, data->gates, data->num_gates, clo= cks); + if (res) + return res; + + /* This is to catch holes in the tables rather than registration errors. = The count vs + * highest ID should catch most static issues. This check here will trigg= er if an ID is + * reused by accident. + */ + for (i =3D 1; i < public_clk_count; i++) { + if (WARN(!clocks->hws[i], "Clock %u not registered\n", i)) + return -EINVAL; + } + + res =3D of_clk_add_hw_provider(of_node, of_clk_hw_onecell_get, clocks); + if (res) + return res; + return devm_add_action_or_reset(dev, zx_delete_clk_provider, of_node); +} +EXPORT_SYMBOL_NS_GPL(zx_clk_common_probe, "ZTE_CLK"); + +MODULE_AUTHOR("Stefan D=C3=B6singer "); +MODULE_DESCRIPTION("ZTE common clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/zte/clk-zx.h b/drivers/clk/zte/clk-zx.h new file mode 100644 index 000000000000..b30e4a29d951 --- /dev/null +++ b/drivers/clk/zte/clk-zx.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ + +#ifndef __DRV_CLK_ZX_H +#define __DRV_CLK_ZX_H + +#include +#include +#include +#include + +#define ZX297520V3_PLL_PREPARE_IS_ENABLE 1 + +/* PLLs, divs and fixed div/factor clocks are never exported directly, only + * through a gate. + */ + +struct zx_pll_desc { + const char *name; + const char * const *parents; + unsigned int num_parents; + unsigned long rate; + u16 reg; + u16 flags; +}; + +struct zx_fixed_divider_desc { + const char *name; + const char *parent; + unsigned int div; +}; + +struct zx_mux_desc { + unsigned int id; + const char *name; + const char * const *parents; + unsigned int num_parents; + u16 reg; + u8 shift, size; +}; + +struct zx_div_desc { + const char *name, *parent; + u16 reg; + u8 shift, size; +}; + +struct zx_gate_desc { + unsigned int id; + const char *name, *parent; + unsigned long flags; + u16 reg; + u8 shift; +}; + +int zx_clk_register_plls(struct device *dev, struct regmap *regmap, + const struct zx_pll_desc *desc, unsigned int num); +int zx_clk_register_muxes(struct device *dev, struct regmap *regmap, + const struct zx_mux_desc *desc, unsigned int num, + struct clk_hw_onecell_data *clocks); +int zx_clk_register_dividers(struct device *dev, struct regmap *regmap, + const struct zx_div_desc *desc, unsigned int num); +int zx_clk_register_gates(struct device *dev, struct regmap *regmap, + const struct zx_gate_desc *desc, unsigned int num, + struct clk_hw_onecell_data *clocks); + +struct zx_clk_data { + int (*init)(struct regmap *map); + const char * const *inputs_enable; + unsigned int num_inputs_enable; + const char * const *inputs; + unsigned int num_inputs; + const struct zx_pll_desc *plls; + unsigned int num_plls; + const struct zx_fixed_divider_desc *fixed_divs; + unsigned int num_fixed_divs; + const struct zx_mux_desc *muxes; + unsigned int num_muxes; + const struct zx_div_desc *divs; + unsigned int num_divs; + const struct zx_gate_desc *gates; + unsigned int num_gates; +}; + +int zx_clk_common_probe(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data); + +#endif /* __DRV_CLK_ZX_H */ diff --git a/drivers/clk/zte/pll-zx.c b/drivers/clk/zte/pll-zx.c new file mode 100644 index 000000000000..f8ddb4c7dff6 --- /dev/null +++ b/drivers/clk/zte/pll-zx.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ +#include +#include +#include +#include + +#include "clk-zx.h" + +int zx_clk_register_plls(struct device *dev, struct regmap *regmap, + const struct zx_pll_desc *desc, unsigned int num) +{ + return -ENODEV; +} --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 67AD03C989B for ; Thu, 16 Jul 2026 21:36:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237783; cv=none; b=aYcvAexcotTUD47dah90lyZ35JiiLQ7yT4/vU9QAEkXPCKzvh4zU+PxnJNK9oIEKKupYGCIbQmJ/9w1SjKuLadl3toyi2UnyUiwq8k6ZLkuAdOxp7xXqxqxyad5b6NNNSWsfYbYvbdPOf6asgASkW0lvL7pfjDymQPB3/JKUIrs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237783; c=relaxed/simple; bh=KXSuXQNJk3ORRNd5NfnirVY5+QwyE07yYWtBz4DnKHs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=fvgS+e5uU+9Uh7S1KR23CZ8IIt9MnQu5shccRmVbfgRpVCeKqoX56Gl5Z6sSb/XZAmnJ4EovJE+4xbhp9lggjyTfVgAbPBAAJPeSyGTmgMaJPA4JabXO0NVlztNnzniaJM3CBEHSxUS7u0wTOPbqV2mKHBmv1RYkPzAbEmRwOQM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=FyjxuL6t; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="FyjxuL6t" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-47d6c634f45so4050228f8f.3 for ; Thu, 16 Jul 2026 14:36:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237780; x=1784842580; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=xg8JnQQa18VgOsg3xqJv8hZDkmulAWkx5pzvnSbFcLc=; b=FyjxuL6tGikRk+xhk58HDVtXD5oOVNqQ7AEqza8O8yVYFuJhzR34P7lF2YvjnAufoj f7fmOYJ9WJsWXilBWP/vA7G5qiKqTv4jowPgii4CH6s8Nv9sVsBAQ+DWzHk4HNHm5R42 OqBD/+Mmij6W12QlYtzTpJXUnf/Z9GPR70M75Xene6Tys4Jd6u1MVTmi0q71TOJ/5tqZ f1NBUVTitPo0IaFNr4qIqy3tABsEDdmlzIou30vwUYczX0vJrIAeL50KREwY21vXH/Cw rBRqx0E4xlLZ53HEtKkHXn8F0gBbNu4Z3QVUJ/LcmEcNwsqH4YKSMbsrBf3qBdA4dLHU scVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237780; x=1784842580; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=xg8JnQQa18VgOsg3xqJv8hZDkmulAWkx5pzvnSbFcLc=; b=OabJVb0q23ZmpnVyv7YB1W1+CDABGMnUcxNd9SPGZJGKqgyDC7ngdksWKZ2Fz6WRFv NqtDFQWyez5Dco4T6NPxW3+7rnegDV6bFzVVUKttsd6Kxi2Hf+QOg3uMUlvsySunlKrJ 5ohgLsMQimDhpTTVaEzwPy9YGW7eZwonl9M8wXUZVLsvbXwaFuupsAcNafg4coBEzrXv PMf3iL2zWfnZ6wNDtw20MoVG+Q5sbr5BkMWp8lPB3JtuuHAZDREiOwMFwNMhEkOY/Zg7 N52cTzkrDHFQDgrOCMS4OO0+rb6g8uce8JOtGeuX8+H7ikZIj/XijozvSU1EHHj0sRbg lECA== X-Forwarded-Encrypted: i=1; AHgh+Rr61nawJmqFHl3nBEsFSjyKCxn6d8gxd0SwvnBIAnv0t4ienGTa59d337EEVn441AT3SbTqlhhV4ugeuec=@vger.kernel.org X-Gm-Message-State: AOJu0YzlEH/YfUe3Cd94fIXlJSH9is1Mk2ka5g+MUDhWF5paVlQV9+Wb PnpLZgbZJ/zyDq88AqFjdBCpJy7vue3lv8pN5AVua+Y4pqKkpKiOGyYw X-Gm-Gg: AfdE7cl5ktRI4OOHnDoqbPNDGHRdXcZkGgXppOKkQ5hPDcMQD/oNMK35sbhCez8TWj/ S1LK128RI5xj27/CIJpVz9tQ2sKW6k+zu12KhqDl9ffDmmYg2vNaGuUiif0jyfORedBnHpW/nL2 f8mX3FSUjqCVWxETbdx8/uGrdNSjJYHa5q7Gq66xR3M7rWWyChx+MtlYxWGD1Smzc+wD785fOxN tiTq+0ALCqGEEn3Mk4HgsgL4YIBO2gIvVzQhLEAoukZQpS+yJaxjXVCPurpkai1zI9bZRN09xPi 6+CQMXjepnvzlgmCvmSOHP+BxyrIm0VGL+4zOIIIFz4G2H7R4BqDTSILAMZxoonxIRHxD9sfqjV Mbsfw3QI8FAYEVwbFoEch7i6k4H6JqFgl0rdINepoO0bS9o7IzPxqw/4fUlJAyz1r/fN/c7SiKE OzR6vsOKCJQNr4xOJ+C3KpNcI= X-Received: by 2002:a05:6000:46ce:b0:47f:4980:4908 with SMTP id ffacd0b85a97d-47f49804bfamr10491531f8f.47.1784237779628; Thu, 16 Jul 2026 14:36:19 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:19 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:43 +0300 Subject: [PATCH v7 07/13] clk: zte: Add regmap based clocks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-7-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7477; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=KXSuXQNJk3ORRNd5NfnirVY5+QwyE07yYWtBz4DnKHs=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xTpEj+PxUq+psRhpDpZ/4YNqvMpdsmDv2W 8iqLIm8VUeJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiJWZhAAsXnirXDLIGyyGdIEHfrA8NyVaAwHdV4 OZujxpH+1J+WDFbjewCh0Iy8Y3gBXSEcPDGYEfvlDYMfKlVBMFCS83saHLiPQez/TaQiYHaWlVo wpHLgP2v1buZOLyYLDVawk1cH/CQ+Pmwh0HvPmwF5Ea3DQxnc8G10IpoYHA62rIBeNcgMp8RzK3 PkVlTMpK44sWlm/zZVpclBnT3KZZlpruFqfrSUGBjhkY9k9aPDlUU2/W6qDKVIARcty5gA4imwV 1xGfUGeYeAQ6c9GRQhyyG4SAqiWjwbf5eP7Yw5EAi8gD7hxqUgk89IES3W1BKc7c/CuZhQwuhfp NeK1g/bCw9QyrIHHa0kbzGkjQV4gI0GhagvJuFkYjMEO86YzNGbdWiZ1dgTI0ft4Bjn7fUGd2Jz N9KnvuDjBQmi2PXPMFKV/tUBe4Jk8mL2jiubP5oOJZT6pKTXO/hV1ZesaFrGF2Qyqsm0olwL2DC h6cCsLeZQkbbD0paZtkp7xXLT2WsvEi0/fIZ+f4wl+FtiqMMujLZWRg1IGcHKjn8BCxJK/QgYUY 90Xb+F0FDkJJoUenBB4ofWJLSXBoxx9whb/HNwxzHXJ5L+nkgCQv1jMDweJaiHvUm+IBT/eR/84 eiPxQKNz0u87EUmgwvsiNkuym6CrZ1IlEJBrF9sbmGOXQov6s3lE= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This is based on meson/clk-regmap.c, although slightly simplified. I have kept the copyright lines at the top of the file to indicate its origin. I see that numerous clock drivers have their own incarnation of regmap based mux/div/gate clocks. If there is any version of it that is likely to be elevated to shared code liks clk-gate.c I'll copy that and try to use it as unmodified as possible. Signed-off-by: Stefan D=C3=B6singer --- Version 6: Remove stray regmap (Sashiko) Version 5: Use regmap_test_bits in zte_clk_regmap_gate_is_enabled --- drivers/clk/zte/clk-regmap.c | 218 +++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c index 984abeb45ab2..198628f73b92 100644 --- a/drivers/clk/zte/clk-regmap.c +++ b/drivers/clk/zte/clk-regmap.c @@ -7,28 +7,240 @@ */ =20 #include +#include #include #include +#include #include +#include +#include =20 #include "clk-zx.h" =20 +struct zte_clk_regmap { + struct clk_hw hw; + struct regmap *map; + u16 reg; + u8 shift; + u8 size; +}; + +static inline struct zte_clk_regmap *to_zte_clk_regmap(struct clk_hw *hw) +{ + return container_of(hw, struct zte_clk_regmap, hw); +} + +static int zte_clk_regmap_gate_enable(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + + return regmap_set_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static void zte_clk_regmap_gate_disable(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + + regmap_clear_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static int zte_clk_regmap_gate_is_enabled(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + + return regmap_test_bits(clk->map, clk->reg, BIT(clk->shift)); +} + +static const struct clk_ops zte_clk_regmap_gate_ops =3D { + .enable =3D zte_clk_regmap_gate_enable, + .disable =3D zte_clk_regmap_gate_disable, + .is_enabled =3D zte_clk_regmap_gate_is_enabled, +}; + int zx_clk_register_gates(struct device *dev, struct regmap *regmap, const struct zx_gate_desc *desc, unsigned int num, struct clk_hw_onecell_data *clocks) { - return -ENODEV; + struct zte_clk_regmap *clk; + unsigned int i; + int res; + + for (i =3D 0; i < num; ++i) { + struct clk_init_data init =3D {}; + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + + init.name =3D desc[i].name; + init.ops =3D &zte_clk_regmap_gate_ops; + init.parent_names =3D &desc[i].parent; + init.num_parents =3D 1; + init.flags =3D CLK_SET_RATE_PARENT | desc[i].flags; + clk->hw.init =3D &init; + clk->map =3D regmap; + clk->reg =3D desc[i].reg; + clk->shift =3D desc[i].shift; + clk->size =3D 1; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].n= ame); + + if (desc[i].id) + clocks->hws[desc[i].id] =3D &clk->hw; + } + + return 0; +} + +static unsigned long zte_clk_regmap_div_recalc_rate(struct clk_hw *hw, + unsigned long prate) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret =3D regmap_read(clk->map, clk->reg, &val); + if (ret) + /* Gives a hint that something is wrong */ + return 0; + + val >>=3D clk->shift; + val &=3D clk_div_mask(clk->size); + return divider_recalc_rate(hw, prate, val, NULL, 0, clk->size); +} + +static int zte_clk_regmap_div_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + + return divider_determine_rate(hw, req, NULL, clk->size, 0); +} + +static int zte_clk_regmap_div_set_rate(struct clk_hw *hw, unsigned long ra= te, + unsigned long parent_rate) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret =3D divider_get_val(rate, parent_rate, NULL, clk->size, 0); + if (ret < 0) + return ret; + + val =3D (unsigned int)ret << clk->shift; + return regmap_update_bits(clk->map, clk->reg, clk_div_mask(clk->size) << = clk->shift, val); } =20 +static const struct clk_ops zte_clk_regmap_divider_ops =3D { + .recalc_rate =3D zte_clk_regmap_div_recalc_rate, + .determine_rate =3D zte_clk_regmap_div_determine_rate, + .set_rate =3D zte_clk_regmap_div_set_rate, +}; + int zx_clk_register_dividers(struct device *dev, struct regmap *regmap, const struct zx_div_desc *desc, unsigned int num) { - return -ENODEV; + struct zte_clk_regmap *clk; + unsigned int i; + int res; + + for (i =3D 0; i < num; ++i) { + struct clk_init_data init =3D {}; + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + + init.name =3D desc[i].name; + init.ops =3D &zte_clk_regmap_divider_ops; + init.parent_names =3D &desc[i].parent; + init.num_parents =3D 1; + init.flags =3D CLK_SET_RATE_PARENT; + clk->hw.init =3D &init; + clk->map =3D regmap; + clk->reg =3D desc[i].reg; + clk->shift =3D desc[i].shift; + clk->size =3D desc[i].size; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].n= ame); + } + + return 0; } =20 +static u8 zte_clk_regmap_mux_get_parent(struct clk_hw *hw) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + unsigned int val; + int ret; + + ret =3D regmap_read(clk->map, clk->reg, &val); + if (ret) + return 0xff; + + val >>=3D clk->shift; + val &=3D GENMASK(clk->size - 1, 0); + return clk_mux_val_to_index(hw, NULL, 0, val); +} + +static int zte_clk_regmap_mux_set_parent(struct clk_hw *hw, u8 index) +{ + struct zte_clk_regmap *clk =3D to_zte_clk_regmap(hw); + unsigned int val =3D clk_mux_index_to_val(NULL, 0, index); + + return regmap_update_bits(clk->map, clk->reg, + GENMASK(clk->size - 1, 0) << clk->shift, + val << clk->shift); +} + +static int zte_clk_regmap_mux_determine_rate(struct clk_hw *hw, struct clk= _rate_request *req) +{ + return clk_mux_determine_rate_flags(hw, req, 0); +} + +static const struct clk_ops zte_clk_regmap_mux_ops =3D { + .get_parent =3D zte_clk_regmap_mux_get_parent, + .set_parent =3D zte_clk_regmap_mux_set_parent, + .determine_rate =3D zte_clk_regmap_mux_determine_rate, +}; + int zx_clk_register_muxes(struct device *dev, struct regmap *regmap, const struct zx_mux_desc *desc, unsigned int num, struct clk_hw_onecell_data *clocks) { - return -ENODEV; + struct zte_clk_regmap *clk; + unsigned int i; + int res; + + for (i =3D 0; i < num; ++i) { + struct clk_init_data init =3D {}; + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return -ENOMEM; + + init.name =3D desc[i].name; + init.ops =3D &zte_clk_regmap_mux_ops; + init.parent_names =3D desc[i].parents; + init.num_parents =3D desc[i].num_parents; + clk->hw.init =3D &init; + clk->map =3D regmap; + clk->reg =3D desc[i].reg; + clk->shift =3D desc[i].shift; + clk->size =3D desc[i].size; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return dev_err_probe(dev, res, "Failed to register clk %s\n", desc[i].n= ame); + + if (desc[i].id) + clocks->hws[desc[i].id] =3D &clk->hw; + } + + return 0; } --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 16DDB3C0A04 for ; Thu, 16 Jul 2026 21:36:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237788; cv=none; b=ritMEd9mrycS4WVB4ljbbFegumMtLd9MJzgvdBn3hmwPQ9hW6QCjocufdi3hcIukuLi5ES7efJuk7I87iTymnBTy7HYo5AwINblrmatgSs2yQtXEAKav3yQsuo1fhU5V0xyKIxnUoRqeoXFTN4fZV9Bt9x86eXlsDAVPDE+svLc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237788; c=relaxed/simple; bh=fridcVrqHLjLyHVFATEuDftbio08bpyab4UAFRRVHrE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QU61wQo8bmW0XyRbbHyg5BMJv6JwjWw03RhqTL9WUIwllsx9I0e5naOdoLLlmIpAvRPv075W842JEfuRZmmCRUDZ8Kv62s3wkd6qdmEd6YI7qNfdj/5YppnpfoSema8c+wJhLEM35OfFibsPnmxbQkVtm88Y+toh8EEVMHJOi3A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=SGDEOFl6; arc=none smtp.client-ip=209.85.128.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="SGDEOFl6" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-493f45e206dso4870965e9.1 for ; Thu, 16 Jul 2026 14:36:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237784; x=1784842584; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=BGDjZseuWnD+/cyL0eXXoNLaYh85Nm6u4H3EElU97SU=; b=SGDEOFl6hi4bpFw7w5CqsbBXQuWlN5qNC962VQc42gUA7OKo09t5F1RQqQpr55EjnW j9uvWYxmCjk4f/nQQW9gZFjPkUQSmlcKVbyf7rd1JewLETXT+kEJH5qf6a2+j1HhPt1L uXzmOMqDmr3pwVZw/R+iSL3eaC4ItbFIBzUaHX2/FAuo7vbAlPFTnV3lArFzWSM0TI+t kv/txBf3Qy2OgbtvY6FntZKK1xm9nX30fmJ5mtIBuykuzZF6fRCpyA2cMT+WkCU/VOaF SofJ8VEBjDPrfG3lFX+qWRWZwdsxHrem5OW+N9NGY2VibDu6scJd/B95JQvlSHmfrMsI mshQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237784; x=1784842584; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=BGDjZseuWnD+/cyL0eXXoNLaYh85Nm6u4H3EElU97SU=; b=N2wje7Xkg9Bg8u4H12JCU/jw97WaCZ55/UjH6ZT5fs10TxHczmo+mT/BlcZwvelnDa vkaQJNo3JyIF7jmY5qNLDbWVXOoSvNsKXhSb5HhorWEQSOdXIgek25ENyhCWrnW3LaKJ Y+ch9Mu+3DD6TLtG61w57sPCwqaGyUHL4w6JFIHGgjM1oTSyjqMHRkSl/l5gy9g39J6c GBAm6KvNI3/8fPhmYS8PrKheucrjlEMpxVbtzvDL7qe4xAeS3hPqhChS10S1a0miD9rv 591iwumKWHX+IosQ1JQZChr+0lGwKbqkMbwTq/A2ITmERc7N1F9mD6DRNmop0VgEzQH/ N6fw== X-Forwarded-Encrypted: i=1; AHgh+RqNmsLeCtn2ESt+DdyhHlsTUAvOzeUiX6tfA950RkVa8a5RnTQmBdgGQNSuZR2bR2r2uEVRwHodVm6O0/g=@vger.kernel.org X-Gm-Message-State: AOJu0YxQDqt6wfv9mNptfGOJfVOLca1cWr/UhuzbBo8F668V38qPQbrT tbAi9ORla7WYV6/MSsuXs0NrELJdFSY/2xxbTkibr8jTAeHMgGxsOk5v X-Gm-Gg: AfdE7cmmc6R8F3IT3LBTyUsNMoQs5vDBmoYXfLUKgbF6EhxYSY4BM2EuhS0Qu7QgHZO fTc77IAReAH2aqqaKLWvLVuj3/1QvSmlOq6B1/YOTGjsa8tR6gmmr4qIq0DQhEYYmDtpACYKLlU BjimgxLLHDkeRKraoNTH4Bizn4Jh02sSKPXP3IkLmwVfzwBkLsH2G757tlcE7vNzoBfT8avKQDJ cpk5mi4vnSuA3Cwu8xQS+zwi2HxhUcgGyrBFxL9pQJizSJTZrGEA52OwqCy6Uh7+6OJZJfCSv70 Q1f+HXpNF4ks7bCTkFiyuhn7gTs4qu5QaElMyimIwDr52DxRYwKroFsks4wm7L0NTRmk2Eg7pTc JYcwF0Vk9U3agJXalUhXW4fuCT2KFCe6rdQByRQvEva8iZ6EX8vRCnUYxffKPlVbHG7GgDZdCxu oYDh/YA87H5Iye X-Received: by 2002:a05:6000:4702:b0:473:c608:eeb5 with SMTP id ffacd0b85a97d-47f5a668c25mr5799355f8f.29.1784237784133; Thu, 16 Jul 2026 14:36:24 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:23 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:44 +0300 Subject: [PATCH v7 08/13] clk: zte: Add zx PLL support infrastructure Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-8-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=19924; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=fridcVrqHLjLyHVFATEuDftbio08bpyab4UAFRRVHrE=; b=kA0DAAgBPRO8yFRPGiIByyZiAGpZTrGhbnPWo6EZIa2HeSguNMlYj6Ss3wtNoF7RsxQrVo994 okCTwQAAQgAORYhBEMW9LaqBVsnlTJdbD0TvMhUTxoiBQJqWU6xGxSAAAAAAAQADm1hbnUyLDIu NSsxLjEyLDIsMgAKCRA9E7zIVE8aIq3iD/9u1xbsqQimLH/BcDVV3uPyKrBZjdCJ3tMwK8aZ4LL lj5fIKqoABdApO0DEX3YuOf4wnw1UMNdsv2kUGTLCGGTTXGiBxsnC1gpP1keSkSUoQrJ1GtdZbu WKNlJ7BODE7WefLj5/d48GnM9oYMHq7LjuUeTLFphmk9mPEFfz3bGaRFTzR4Lmz23w15qLokJHv ro4Q+R/qB3bBTs+tH8wurf9vh8LKyCigYuHHB7Mxt1P8isVxJo5ZiBj2/9jkEU1zeFiO2OmHwvd dUnd3N7WgRFC/3MW4OFkK6OWHZNTuKu+bLbxIRWhO2ynyrbXPqi44M1uTujjFA+xoW7oyVay70L z55YE8lvusFMsLYs+uvo/GKZuJo+mvYYRNl2FVbhXmHJw4iI3dqgm6z0WVxMhqmCVXg1MhnjuRt M5T5LKBNL3g4cP8qtd9ivp7UnA2L0sTejirMKmRwgcwvf2LQacobRaLAq1cfCg13kRE1pHL0eYP /TBYFcP7QkjQpeh+6Peq7vvV4lEBiuBvU7VPSD6RPkVu+YCOzK9K1/kRSKD71rCidcd7ga45REj AlTPnlQjNRXtbbtSAeCl01x2WwpZYiiSmv0GoIfbEq6t2fNxolxlIEK8eRBsYiaTVG9SmW17j+o LP4h3yDg2iEwll91USds6aB3YZJQJpotgENF+9yHUXA== X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 I am guessing how much of this is reusable among other zx chips or even differently named ZTE platforms (if there are any). From reading the old zx2967 code, I think the PLL code would be reusable there, maybe with platform specific bitmasks but otherwise the same logic. Signed-off-by: Stefan D=C3=B6singer --- Version 7: *) Always keep unknownpll enabled when prepared so dpll can acquire a lock in its prepare() function. *) Clean up error reporting a bit (Sashiko) Version 6: *) Use abs_diff to compare target and candidate PLL rate (Sashiko). *) Use req->best_parent_rate in zx29_pll_determine_rate. Add a TODO comment about the parent rate flexibility. Version 5: Fix Some issues pointed out by Sashiko: NULL dev, zx29_pll_recalc_rate error handling, disable PLL again on enable error. --- drivers/clk/zte/pll-zx.c | 506 +++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 505 insertions(+), 1 deletion(-) diff --git a/drivers/clk/zte/pll-zx.c b/drivers/clk/zte/pll-zx.c index f8ddb4c7dff6..701e580609f2 100644 --- a/drivers/clk/zte/pll-zx.c +++ b/drivers/clk/zte/pll-zx.c @@ -3,14 +3,518 @@ * Copyright (C) 2026 Stefan D=C3=B6singer */ #include +#include +#include #include #include +#include +#include #include +#include +#include +#include =20 #include "clk-zx.h" =20 +/* This code has only been tested with zx297520v3 PLLs, but from reading t= he zx296718 clock code it + * looks like PLL registers are similar. ZTE's sources explain the PLL reg= ister contents only in a + * .cmm file (A Lauterback TRACE32 script) and some unused headers in thei= r U-Boot code dump, which + * may not be accurate. When calculating the frequencies from the default = PLL configuration the + * results match the fixed rate clocks from their clock driver. + * + * The 26mhz and 32khz clocks can be easily observed with the timers. The = 104mhz output can be + * observed through the UART. One 122.88 PLL can be observed through the T= DM device. All others can + * only be indirectly infered, e.g. by comparing CPU speed or SDIO transfe= r rate between the fixed + * 26 MHz oscillator and the provided PLL frequency. + * + * The formula to calculate the clock is ((ref / refdiv) * fbdiv) / postdi= v1 / postdiv2. The masks + * are given below. There are a few control flags: + * + * Bit 31: Disables the PLL, but passes the reference through unmodified. = If POSTDIV_OUT_DISABLE + * still matters is different between PLLs. + * Bit 30: Returns if the PLL is locked + * Bit 29: Not named in ZTE's code, but can be set. There is no obvious im= pact. Lock times are + * unchanged, so it doesn't influence or bypass lock detection. It= doesn't raise any IRQs or + * influence GPIOs. + * Bit 27: Given its name it likely disables the Delta-Sigma Modulator, if= one exists at all. The + * boot ROM sets it on every PLL. Unsetting it marginally decrease= s the time it takes to + * lock to the reference clock (from ~400us to ~300us). Regardless= of this bit I could not + * make the supposed fractional part in register 2 work. + * Bit 24: Bypasses the VCO, but still applies refdiv and postdiv. Doesn't= matter if PLL_DISABLE=3D1. + */ + +#define ZX29_PLL_DISABLE BIT(31) +#define ZX29_PLL_LOCKED BIT(30) +#define ZX29_PLL_LOCK_FILTER BIT(29) +#define ZX29_PLL_DSM_DISABLE BIT(27) +#define ZX29_PLL_PARENT_MASK GENMASK(26, 25) +#define ZX29_PLL_PARENT_SHIFT 25 +#define ZX29_PLL_BYPASS BIT(24) +#define ZX29_PLL_REFDIV_MASK GENMASK(23, 18) +#define ZX29_PLL_REFDIV_SHIFT 18 +#define ZX29_PLL_FBDIV_MASK GENMASK(17, 6) +#define ZX29_PLL_FBDIV_SHIFT 6 +#define ZX29_PLL_POSTDIV1_MASK GENMASK(5, 3) +#define ZX29_PLL_POSTDIV1_SHIFT 3 +#define ZX29_PLL_POSTDIV2_MASK GENMASK(2, 0) +#define ZX29_PLL_POSTDIV2_SHIFT 0 + +/* The second register is supposed to have another 24 bit value that gets = added to fbdiv but it is + * always 0 in the preconfigured values. I could not observe any effect fr= om setting it to something + * other than 0, regardless of the DSM disable bit. It is possible that it= is only supported by + * dpll, which is a possible parent for i2s. + * + * Bits 28:25 contain more flags: + * + * Bit 27: Setting ZX29_PLL_DACAP slows down the lock time and obivates th= e speed gained from + * !DSM_DISABLE. No other effect observed. + * + * Bit 26: ZX29_PLL_4PHASE_OUT_DISABLE is set on some PLLs on boot but not= on others. It is set on + * boot on mpll and upll, but not gpll, dpll or unknownpll. I am n= ot sure what it does + * either. The SDIO devices break if they are fed from gpll with t= his flag set, but they + * work ok if they are fed from mpll without this flag set. + * + * Bit 25: ZX29_PLL_POSTDIV_OUT_DISABLE seems to disable the PLL output en= tirely. Whether it is + * bypassed by PLL_DISABLE differs between PLLs. gpll still produc= es an output clock if + * PLL_DISABLE =3D 1 and POSTDIV_DISABLE =3D 1, but produces no ou= tput if PLL_DISABLE =3D 0 and + * POSTDIV_DISABLE =3D 1. The dpll feeder ("unknownpll") at 0x100 = produces no output clock + * if both PLL_DISABLE and POSTDIV_DISABLE are set to 1. + * + * Bit 24: ZX29_PLL_VCO_OUT_DISABLE probably disables the output of the VC= O clock without + * post-VCO-dividers, but the raw VCO output is not a possible par= ent of any consumer clock, + * so I could not confirm this. It does not disable the VCO entir= ely - that's what + * PLL_DISABLE does. + * + * A spinlock should not be needed. PLLs don't share their registers with = anything else and the + * global prepare mutex and enable spinlock should be enough. Beware of co= nflicts in reg2 between + * POSTDIV_OUT_DISABLE and the fractional value in case you find out how f= ractional dividers work + * and add support for them. + */ +#define ZX29_PLL_REG2_OFFSET 4 +#define ZX29_PLL_DACAP BIT(27) +#define ZX29_PLL_4PHASE_OUT_DISABLE BIT(26) +#define ZX29_PLL_POSTDIV_OUT_DISABLE BIT(25) +#define ZX29_PLL_VCO_OUT_DISABLE BIT(24) + +/* The VCO's frequency range is limited. The stock settings run the VCO be= tween 960 and 1248 MHz. + * Ad-hoc testing with gpll suggests that at least this PLL remains stable= down to about 7 MHz and + * up to 2 GHz and produces a clock that can be used by the SDIO controlle= r. Attempting to run the + * mpll VCO at 624 MHz and setting postdiv1 =3D postdiv2 =3D 1 - which sho= uld result in the same output + * frequency - or running it at 1872 MHz with an effective post divider of= 3 crashes the CPU. Most + * likely the PLLs become unstable outside their core range and the SDIO c= ontroller is much more + * forgiving than CPU and DRAM are. + */ +#define ZX29_PLL_VCO_MAX_FREQ (1300*HZ_PER_MHZ) +#define ZX29_PLL_VCO_MIN_FREQ (900*HZ_PER_MHZ) + +struct zx29_clk_pll { + struct clk_hw hw; + struct device *dev; + struct regmap *map; + u16 reg; +}; + +static inline struct zx29_clk_pll *to_zx29_clk_pll(struct clk_hw *hw) +{ + return container_of(hw, struct zx29_clk_pll, hw); +} + +static int zx29_pll_is_prepared(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + int res; + + res =3D regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return res; + + return !res; +} + +static int zx29_pll_prepare(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val =3D 0; + int res; + + res =3D regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return res; + + /* Lock duration is usually between 300us to 500us */ + res =3D regmap_read_poll_timeout(pll->map, pll->reg, val, val & ZX29_PLL_= LOCKED, 50, 2000); + if (res) { + regmap_set_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + dev_err(pll->dev, "%s: PLL prepare failed: %d. Config value 0x%08x\n", + clk_hw_get_name(&pll->hw), res, val); + } + return res; +} + +static void zx29_pll_unprepare(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + + regmap_set_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); +} + +static int zx29_pll_is_enabled(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + int res; + + res =3D regmap_test_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); + if (res < 0) + return res; + + return !res; +} + +static int zx29_pll_enable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + + return regmap_clear_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static void zx29_pll_disable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + + regmap_set_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static unsigned long zx29_pll_get_rate(const struct zx29_clk_pll *pll, uns= igned long parent_rate, + u32 setting) +{ + unsigned long refdiv, fbdiv, postdiv1, postdiv2, freq; + const char *name =3D clk_hw_get_name(&pll->hw); + u64 vco; + + refdiv =3D (setting & ZX29_PLL_REFDIV_MASK) >> ZX29_PLL_REFDIV_SHIFT; + fbdiv =3D (setting & ZX29_PLL_FBDIV_MASK) >> ZX29_PLL_FBDIV_SHIFT; + postdiv1 =3D (setting & ZX29_PLL_POSTDIV1_MASK) >> ZX29_PLL_POSTDIV1_SHIF= T; + postdiv2 =3D (setting & ZX29_PLL_POSTDIV2_MASK) >> ZX29_PLL_POSTDIV2_SHIF= T; + dev_dbg(pll->dev, "%s: reference clock %lu HZ, PLL setting 0x%08x\n", + name, parent_rate, setting); + + if (!refdiv || !postdiv1 || !postdiv2) { + dev_err(pll->dev, "%s: divide by zero (%lu, %lu, %lu)\n", name, refdiv, = postdiv1, + postdiv2); + return 0; + } + + vco =3D div_u64((u64)parent_rate * fbdiv, refdiv); + freq =3D div_u64(div_u64(vco, postdiv1), postdiv2); + dev_dbg(pll->dev, "%s: refdiv %lu fbdiv %lu\n", name, refdiv, fbdiv); + dev_dbg(pll->dev, "%s: postdiv1 %lu postdiv2 %lu\n", name, postdiv1, post= div2); + + dev_dbg(pll->dev, "%s: %lu MHZ\n", name, freq / HZ_PER_MHZ); + + return freq; +} + +static unsigned long zx29_pll_recalc_rate(struct clk_hw *hw, unsigned long= parent_rate) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + int res; + + res =3D regmap_read(pll->map, pll->reg, &val); + if (res < 0) { + dev_err(pll->dev, "%s: Failed to read PLL settings\n", clk_hw_get_name(&= pll->hw)); + return 0; + } + + return zx29_pll_get_rate(pll, parent_rate, val); +} + +static u32 zx29_pll_calc_values(const struct zx29_clk_pll *pll, unsigned l= ong parent_rate, + unsigned long rate) +{ + const unsigned int postdiv1_max =3D (1 << hweight32(ZX29_PLL_POSTDIV1_MAS= K)) - 1; + const unsigned int postdiv2_max =3D (1 << hweight32(ZX29_PLL_POSTDIV2_MAS= K)) - 1; + unsigned long fbdiv, refdiv, best_fbdiv =3D 0, best_refdiv =3D 0; + u32 postdiv1 =3D 0, postdiv2 =3D 0, i, j, setting; + const char *name =3D clk_hw_get_name(&pll->hw); + long best =3D LONG_MAX; + + /* This code produces the same VCO settings that the boot loader and stoc= k firmware use for + * the standard frequencies. It has seen only very little manual testing = beyond that. + * + * The goal is to find a VCO setting that gets us as close as possible to= the desired output + * rate, while being within the VCO's operating limits and achievable wit= h the input value + * range. It is iterating over possible post-VCO diver values (1-7)*(1-7)= to look for valid + * VCO target frequencies and then looks for refdiv and fbdiv values to a= chieve the VCO + * frequency from the reference frequency. + */ + for (j =3D 1; j <=3D postdiv2_max; j++) { + for (i =3D 1; i <=3D postdiv1_max; i++) { + u64 vco =3D (u64)rate * i * j; + unsigned long out; + + if (vco > ZX29_PLL_VCO_MAX_FREQ || vco < ZX29_PLL_VCO_MIN_FREQ) + continue; + + rational_best_approximation(vco, parent_rate, + (1 << hweight32(ZX29_PLL_FBDIV_MASK)) - 1, + (1 << hweight32(ZX29_PLL_REFDIV_MASK)) - 1, + &fbdiv, &refdiv); + setting =3D fbdiv << ZX29_PLL_FBDIV_SHIFT; + setting |=3D refdiv << ZX29_PLL_REFDIV_SHIFT; + setting |=3D i << ZX29_PLL_POSTDIV1_SHIFT; + setting |=3D j << ZX29_PLL_POSTDIV2_SHIFT; + out =3D zx29_pll_get_rate(pll, parent_rate, setting); + + if (abs_diff(out, rate) > best) + continue; + + if (abs_diff(out, rate) < best) { + postdiv1 =3D i; + postdiv2 =3D j; + best_fbdiv =3D fbdiv; + best_refdiv =3D refdiv; + best =3D abs_diff(out, rate); + + if (!best) + goto search_done; + } + } + } +search_done: + + if (!postdiv1) { + dev_err(pll->dev, "Did not find a setting for %lu Hz, parent %lu Hz\n", + rate, parent_rate); + return 0; + } + + dev_dbg(pll->dev, "%s: parent rate %lu\n", name, parent_rate); + dev_dbg(pll->dev, "%s: found VCO dividers %u and %u\n", name, postdiv1, p= ostdiv2); + dev_dbg(pll->dev, "%s: VCO target rate %lu\n", name, rate * postdiv1 * po= stdiv2); + + dev_dbg(pll->dev, "%s: Got fbdiv =3D %lu refdiv =3D %lu\n", name, best_fb= div, best_refdiv); + + setting =3D best_fbdiv << ZX29_PLL_FBDIV_SHIFT; + setting |=3D best_refdiv << ZX29_PLL_REFDIV_SHIFT; + setting |=3D postdiv1 << ZX29_PLL_POSTDIV1_SHIFT; + setting |=3D postdiv2 << ZX29_PLL_POSTDIV2_SHIFT; + dev_dbg(pll->dev, "%s: Final setting 0x%08x\n", name, setting); + + return setting; +} + +static int zx29_pll_determine_rate(struct clk_hw *hw, struct clk_rate_requ= est *req) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + unsigned long new_rate; + u32 setting; + + /* TODO: DPLL can switch between two parents, one of which is another PLL= . Take this into + * account when searching the config space and set req->best_parent_rate. + * + * In practise it shouldn't matter though. DPLL is always configured to a= fixed frequency. + */ + if (!req->best_parent_rate) { + dev_err(pll->dev, "Did not expect best_parent_rate=3D0\n"); + return -EINVAL; + } + + setting =3D zx29_pll_calc_values(pll, req->best_parent_rate, req->rate); + if (!setting) + return -EINVAL; + + new_rate =3D zx29_pll_get_rate(pll, req->best_parent_rate, setting); + if (new_rate !=3D req->rate) { + dev_warn(pll->dev, "Did not find an exact match. Want %lu, got %lu\n", + req->rate, new_rate); + req->rate =3D new_rate; + } + + return 0; +} + +static int zx29_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + int res =3D -EINVAL; + u32 setting; + + /* PLLs can be changed while they are running and in testing the downstre= am hardware + * handles it gracefully - as long as the new rate is a rate the hardware= can operate at. + */ + setting =3D zx29_pll_calc_values(pll, parent_rate, rate); + if (!setting) + return -EINVAL; + + if (zx29_pll_get_rate(pll, parent_rate, setting) =3D=3D rate) { + res =3D regmap_update_bits(pll->map, pll->reg, 0x00ffffff, setting); + dev_info(pll->dev, "%s: Setting rate: 0x%08x\n", clk_hw_get_name(hw), se= tting); + } + + return res; +} + +static u8 zx29_pll_get_parent(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + int res; + + res =3D regmap_read(pll->map, pll->reg, &val); + if (res < 0) + return 0xff; + + val =3D (val & ZX29_PLL_PARENT_MASK) >> ZX29_PLL_PARENT_SHIFT; + dev_dbg(pll->dev, "%s: Parent 0x%x\n", clk_hw_get_name(hw), val); + + return val; +} + +static int zx29_pll_set_parent(struct clk_hw *hw, u8 index) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 idx_shift =3D index << ZX29_PLL_PARENT_SHIFT; + int res; + u32 val; + + res =3D regmap_update_bits(pll->map, pll->reg, ZX29_PLL_PARENT_MASK, idx_= shift); + if (res < 0) + return res; + + res =3D regmap_read(pll->map, pll->reg, &val); + if (res < 0) + return res; + + if ((val & ZX29_PLL_PARENT_MASK) !=3D idx_shift) { + dev_err(pll->dev, "Hardware rejected PLL parent %u\n", index); + return -EINVAL; + } + return 0; +} + +static int zx29_pll_init(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + const char *name =3D clk_hw_get_name(hw); + int res; + + dev_dbg(pll->dev, "%s: initializing\n", name); + + /* Remove the bypass flag so we don't have to bother with it in enable/di= sable. I have + * never seen it set by the earlier boot stages anyhow. + */ + res =3D regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_BYPASS); + if (res < 0) + return res; + + if (regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE) > 0) { + /* Set ZX29_PLL_POSTDIV_OUT_DISABLE for PLLs that have ZX29_PLL_DISABLE = for + * consistency with .enable and .prepare. This ensures that .prepare doe= sn't + * inadvertedly enable PLLs without .enable being called. + */ + res =3D regmap_set_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); + if (res < 0) + return res; + } + + return 0; +} + +static const struct clk_ops zx29_pll_ops =3D { + .init =3D zx29_pll_init, + .is_prepared =3D zx29_pll_is_prepared, + .prepare =3D zx29_pll_prepare, + .unprepare =3D zx29_pll_unprepare, + .is_enabled =3D zx29_pll_is_enabled, + .enable =3D zx29_pll_enable, + .disable =3D zx29_pll_disable, + .recalc_rate =3D zx29_pll_recalc_rate, + .determine_rate =3D zx29_pll_determine_rate, + .get_parent =3D zx29_pll_get_parent, + .set_parent =3D zx29_pll_set_parent, + .set_rate =3D zx29_pll_set_rate, +}; + +/* A PLL that can be a parent of another PLL needs to produce an output si= gnal when prepared, + * otherwise the downstream PLL's prepare() will fail to acquire a lock. + */ +static int zx29_pll_nodisable_init(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + const char *name =3D clk_hw_get_name(hw); + int res; + + dev_dbg(pll->dev, "%s: initializing, prepare-is-enabled\n", name); + + res =3D regmap_clear_bits(pll->map, pll->reg, ZX29_PLL_BYPASS); + if (res < 0) + return res; + + return regmap_clear_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static const struct clk_ops zx29_pll_nodisable_ops =3D { + .init =3D zx29_pll_nodisable_init, + .is_prepared =3D zx29_pll_is_prepared, + .prepare =3D zx29_pll_prepare, + .unprepare =3D zx29_pll_unprepare, + .recalc_rate =3D zx29_pll_recalc_rate, + .determine_rate =3D zx29_pll_determine_rate, + .get_parent =3D zx29_pll_get_parent, + .set_parent =3D zx29_pll_set_parent, + .set_rate =3D zx29_pll_set_rate, +}; + int zx_clk_register_plls(struct device *dev, struct regmap *regmap, const struct zx_pll_desc *desc, unsigned int num) { - return -ENODEV; + struct zx29_clk_pll *pll; + unsigned int i; + int res; + + for (i =3D 0; i < num; ++i) { + struct clk_init_data init =3D {}; + + pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return -ENOMEM; + + if (desc[i].flags & ZX297520V3_PLL_PREPARE_IS_ENABLE) + init.ops =3D &zx29_pll_nodisable_ops; + else + init.ops =3D &zx29_pll_ops; + + init.name =3D desc[i].name; + init.parent_names =3D desc[i].parents; + init.num_parents =3D desc[i].num_parents; + pll->hw.init =3D &init; + pll->dev =3D dev; + pll->map =3D regmap; + pll->reg =3D desc[i].reg; + + res =3D devm_clk_hw_register(dev, &pll->hw); + if (res) + return res; + + /* Set the PLL rate only if the bootloader left it disabled. Keep the bo= otloader + * setup otherwise. + */ + if (regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE) > 0 && desc[i= ].rate) { + dev_dbg(pll->dev, "%s: Setting to %lu Hz\n", desc[i].name, desc[i].rate= ); + res =3D clk_set_rate(pll->hw.clk, desc[i].rate); + if (res) { + dev_err(dev, "%s: Failed to set rate.\n", desc[i].name); + return res; + } + } + } + + return 0; } --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f42.google.com (mail-wr1-f42.google.com [209.85.221.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A15103C9ED0 for ; Thu, 16 Jul 2026 21:36:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237793; cv=none; b=SR3bkxRZvYtF29kgnbcgxGlWajuFhp4CZxZSAOgiqkOacso2Y0q300crJPv+oq6r4d4Bm14Cq2XIDeYXcigcUvmayJRQhYMlSMRnoLI7dA9o8Sj8b+KWQFsJvI5eSinPFCw/MF1b3pVHAFdQy2nCl8Klh6n6tqsNIA6pb7UE2kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784237793; c=relaxed/simple; bh=UfvHGNqSdJRFDNtRZ3/tPvSl3GCDRhhSXpv7rHx2wHw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dyMuB1d7TqM8TpMufiWveI5NzZ2lqT4+yW690pZdKY1dsGJ27zG+2akq0FJx6LYpaJul0cgAQ3STTFN3ZtVlZeEhbXGjyMT6HTMh10SyMZppXhGOQpnIZj3DSuyhreF3MRuKNnTVJ00v9q085hG+qOdqa3NZd9gmSFGLdQ+Bp+E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=pbb+g1+3; arc=none smtp.client-ip=209.85.221.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="pbb+g1+3" Received: by mail-wr1-f42.google.com with SMTP id ffacd0b85a97d-47122683cf3so4058527f8f.0 for ; Thu, 16 Jul 2026 14:36:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784237789; x=1784842589; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=q5h37X36r8kqZXrXq/FTkAnAYTIS9kbuaQvVOVAIyU0=; b=pbb+g1+3e5yWiHk7xnhpDNJcDdhPFxwgYdpqX9kb+m1Y80HQfd0XEIs78femOWT0nn g/Q8S8wrqMMRCiNI5QKuD6fN+4zOlLVIzkglp0bJHvmMDxxW5CzMCOBK5qZuzKmzVfsF K5T7N2GkerOops9nuWR3yAn3XT8Gm9l2hJMATf6JJjDto7zxtJG0HotcM65ujqvahb5I gt/hwROTXdWmfaMcpJd073EmDQG6Zxo6Qwb6+PTWBnj6r8h1lBRqpfPtc6a/0RR62AdC JNBcE6ZZ4EmDtxehDgD/cu4Ap8RQSTGyHbhr0jjFj/hnULSs/29gAjywjIjrWFfbfQ1p uv4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784237789; x=1784842589; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :content-type:mime-version:subject:date:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=q5h37X36r8kqZXrXq/FTkAnAYTIS9kbuaQvVOVAIyU0=; b=jY76/1/Zn18oQinzA3ujJXxhPU2S6D0I32ZP2NOXyL0aFG2rpNdSvzDBFSItGhW3Cv UNDy7cp2Lls+yYRgPfcC+/TsR9Bvkrjsix0iMyyeucaiN5ziZ37nqtqa33gurrqZTRKc WDkSiybdqsK+rSfuzCkuL/DUR8y+qKe/Pohr1z378Y54ksRb43qooSFnJCv2EcBpaWoL fvn3mnT169SuZS6D8X0zCnVKpKaO44t9liEA7wSfGijd8bSvP5+yNzhcbto6kPVb5kw0 DzAJ9SX3pTycnejaLi8ATGwAS1wLPyg92oUVvjoQanrRIMGzWSKUKlMeq3K9LJkfTynV bKOA== X-Forwarded-Encrypted: i=1; AHgh+RqGUasU/ZzRdnI1ZfVlef5FfsIHnCDKCEVU//MWS2So1CGirLEv2RP3E/XCMggvjwPm1eKEbB8anatUOF4=@vger.kernel.org X-Gm-Message-State: AOJu0Yxo+5YIArBQX3aHfNNaWBCHAPAXJ6g/S0p1IqnYrFkKSCWTucb6 l/Jp3lPcdi+oQKSciaoHUT5SqJd+jRTHsAFvIfBXRfniwmshsqDbel+M X-Gm-Gg: AfdE7ckmC7gvPNcJMep+g5kjYDWnYR4cy39FpDHd6EdzSp21a58EfxlXMdjup8u011H AEGDrbcc/EnpU0DGThlT4WeIJVqbQetRs3NcYUtobuQbGk9MyQrR4qNS6B3pVcPRG9KVHeq0/J7 PvxMt7LLyUe9jXJtUmY/gayLwXT+PEsF/pdhCkvsmk218CVI2uPn37DbpHcHahguXKuZ7WQxg5F TqJIUujhdC3sz04ZrfHoVLRUEDTJ46qMnTEd6p+mhyspjX+QWxXIERq4HDa+ex1isMkzsY3FM+C bFxwG7/3h9KcPJQlIlMi+ZPdDbHb4fqHCVyjG3CoeU+25GAMRWSaMjom1+Ni038gh4yn2QxNluu NdoF+GOYA34PWu0ARDvZOkaJpQyQ6/bAB7VRmJa30yZ4YspMCUdpHTdd5nOG7rcv0385AMAlIFE ZXVVPI+n7cil5R X-Received: by 2002:a5d:6e47:0:b0:475:f0f0:9eef with SMTP id ffacd0b85a97d-47f463a3d05mr13393252f8f.52.1784237788481; Thu, 16 Jul 2026 14:36:28 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464b7f09sm27517548f8f.26.2026.07.16.14.36.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 14:36:27 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 17 Jul 2026 00:35:45 +0300 Subject: [PATCH v7 09/13] clk: zte: Introduce a driver for zx297520v3 top clocks Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260717-zx29clk-v7-9-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-phy@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=30076; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=UfvHGNqSdJRFDNtRZ3/tPvSl3GCDRhhSXpv7rHx2wHw=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqWU6xsfqIqhlRL/eNCKGVqvoo5D478DU+oeV0f bjDSG56WliJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCallOsRsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiIQjw//ekWRuO6mwPJd5Gf/8Z4hUHwMMHYv4De Nh9U1w62cftFODu5ndEMjEWnuuN6yBzMdngoyzvqGuAs9ltvL38tfvtJ8ITcsgE/10xFSGF1jdB +GEZz4qLp/9rbgxpazFUEtJ5TtwQXQWBrXED3y0EKijZeOoIkizzQy7DbYqQJ2GLOO0JtY8nSF1 Tk59GGoQN63k7LUr5atnIi0ebhDgXyUGNVuA2a5Ln1TCA6Soh0E9YIHieyRD6GpBg0GzVzed6jw kapQcdJ4ESXUERa3EXwvfAnSxSiobXwoWKUz0wMiC56GRwXLmIhEE5XXFLoFgGrncbSKnXEDHQ0 ZsZa6dh2piCDrL15kY1SlnE/XMdROBoLE9RQ3HMsOZruVk4bzxCepcz6xYEtZ/nG/IqU1F6sBZ1 Q3FuDL6N1alEjdP1Cscxp7t9WMYCDDvRwN7SwT3tXauHU3fWYLT32E6iJzAlNy/tJzmkonpDyJ5 CClGVSB4hyZJmqQPucczGvC7Re1C0UqLRVhugP3GUnr2YN9SA/RSXCo63bHT3lRx14XAFP0tCoj LkK2tFFNp5+NUb3b9D8kxn5uWS4V33P0fZV7SsWFeEAn6maESBnZHGBnM50BEABukmsUlJLhJ1P 6hBxVyQjs4sGoeIHbae0Um4fLfK0FsF7rHwTZWkHqvrx7gIGYKow= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This register space controls core devices: PLLs, the AHB bus, a lot of timers, the USB controller, the Cortex M0 processor that boots the board and a few other devices. For some reason the LTE coprocessor is also partially controlled by it. The main application processor and DDR memory are not found here though. The register to reboot the board is found here, as well as a register to control of watchdog expiries cause a board reset. Signed-off-by: Stefan D=C3=B6singer --- Version 7: The register at top+0x140 contains a series of gates that control PLL input into the top controller and PLL and osc26m work clock forward into matrix. This allowed further insight into the clock tree. The PLL subdivision list was replaced with fixed factor clocks that divide PLLs before and after the input gate (and some fixed factor divs go into matrix in the next patch). The number of clocks exported to Matrix is actually relatively small. As for Sashiko's suggestion about out of bound parents for dpll and unknownpll: I have never seen a parent !=3D 0. If that happens on a device I want to know about it. At this stage of development I'd rather have clearly visible orphaned clock than silently continuing at an unexpected frequency. "osc26m" -> "clock-26m" as "oscXX", although widespread, is deprecated. In doing so, change underscores in clock names to dashes (Sashiko). Version 5: *) Make it a MFD child driver instead of binding to the node directly *) Correct parents for dpll *) Correct HSIC work clock parent --- drivers/clk/zte/Kconfig | 11 + drivers/clk/zte/Makefile | 1 + drivers/clk/zte/clk-zx297520v3.c | 544 +++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 556 insertions(+) diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig index 0222549dd211..c01d2704c864 100644 --- a/drivers/clk/zte/Kconfig +++ b/drivers/clk/zte/Kconfig @@ -14,3 +14,14 @@ config COMMON_CLK_ZTE of this. =20 Enable this if you are building a kernel for a ZTE designed board. + +config CLK_ZTE_ZX297520V3 + tristate "Clock driver for ZTE zx297520v3 based SoCs" + depends on COMMON_CLK_ZTE && (ZTE_ZX297520V3_CRM || COMPILE_TEST) + default SOC_ZX297520V3 + help + This driver supports ZTE zx297520v3 basic clocks. + + Enable this if you want to build a kernel that is able to run on + boards based on this SoC. You can safely enable multiple clock + drivers. The one(s) matching the device tree will be used. diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile index 27db07293165..2c073512e919 100644 --- a/drivers/clk/zte/Makefile +++ b/drivers/clk/zte/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only =20 obj-$(CONFIG_COMMON_CLK_ZTE) +=3D clk-zte.o +obj-$(CONFIG_CLK_ZTE_ZX297520V3) +=3D clk-zx297520v3.o =20 clk-zte-y +=3D clk-zx.o pll-zx.o clk-regmap.o diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c new file mode 100644 index 000000000000..20ff00ba5f67 --- /dev/null +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -0,0 +1,544 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + * + * There are no public datasheets for zx297520v3. The controls on this clo= ck controller have been + * extracted from ZTE's kernel and U-Boot sources and a LOT of manual test= ing. Some clocks can be + * found in the power management (evb_cpurpm.img) and LTE (cpko.ko) blobs = shipped with the routers. + * + * Because ZTE's sources are wrong or misleading in some parts and testing= can be misinterpreted, + * this file contains a LOT of comments on how particular clocks were test= ed and how the impact of + * changes to them can be observed. + */ +#include +#include +#include +#include +#include +#include + +#include "clk-zx.h" + +MODULE_IMPORT_NS("ZTE_CLK"); + +/* Used for gates where we don't know the parent input(s). Assume general = oscillator */ +static const char clk_unknown[] =3D "clock-26m"; + +/* For clocks that use the ungated clock-26m input */ +static const char * const clk_main[] =3D { + "clock-26m", +}; + +static const char * const dpll_parents[] =3D { + "unknownpll-d2", + "clock-26m", +}; + +static const char * const zx297520v3_top_inputs[] =3D { + "osc26m", + "osc32k" +}; + +/* Top and matrix clocks are chaotic - I haven't found a consistent patter= n behind their register + * and bit locations. Generally there are two gates (pclk, wclk), one mux,= two resets and sometimes + * one divider, but exceptions apply. For some devices there is only a res= et and some general + * (parent) clocks need setup. This structure plus macro handles the somew= hat regular parts. + * + * There are some patterns that can be observed. + * mux 0x3c, div 0x48, gate 0x54 + * mux 0x40, div 0x4c, gate 0x5c + * mux 0x44, div 0x50, gate 0x60 + * + * For a 0 - 0xc - 0x18 pattern. Muxes from 0x3c to 0x44, dividers from 0x= 48 to 0x50, gates 0x54 to + * 0x60. The pattern is broken for timer t17 though. + * + * Gates have 4 bits per clock - bit 0 for wclk, bit 1 for pclk, bit 2 for= something the ZTE kernel + * calls "gate" (the bits we use here are called "en"), which presumably e= nables automatic clock + * gating. Bit 3, if settable, seems unused. E.g. offset 0x54 accepts all = bits in 0xF77F7F7F - + * suggesting RTC, I2C0 have an extra gate bit. + * + * The default mpll settings multiply the 26 MHz reference clock times 24.= A mux selection of 26 MHz + * could mean using the 26 MHz oscillator directly, or passing it through = the PLL and divide by 24. + * + * If a UART is set to mpll-d6 (default 104 MHz), changing the mpll multip= liers does affect UART + * timing as it should. This does not happen when the UART is set to 26 MH= z input or timers that + * read 26 MHz input. This suggests 26 MHz clocks use the reference clock = directly. + * + * The geneneral clock flow on this board goes from clock-26m into the PLL= s. The PLL output is + * branched into a small number of divided frequencies (mpll, mpll-d4, mpl= l-d5, mpll-d6, mpll-d8, + * gpll, gpll-d2, gpll-d4) at a high level. These divided frequencies as w= ell as clock-26m go + * through a series of gates at offset 0x140 in topcrm. The output of thes= e gates provide wclks for + * everything. + * + * At least 3 of those gate outputs (mpll, dpll, gpll-d2) are further divi= ded behind those gates, + * presumably in the matrix controller. There are multiple paths how 104 a= nd 78 MHz are derived, + * some specific to topcrm (0x140 bits 1 and 4), some specific to matrix (= 0x140 bit 9). There are + * likely 3 "copies" of the 78 MHz clock and two 50 MHz ones. + * + * Pclk is not gated by the 0x140 gates at all. Likewise clock-32k is fed = to the timers without + * passing through this gate, even for consumers on matrix/LSP. Topcrm clo= ck-26m wclks are not gated + * either, but top-consumed PLL clocks are. + */ + +static const struct zx_fixed_divider_desc zx297520v3_top_fixed_divs[] =3D { + /* clock-26m division for clk_outX */ + {"clock-26m-d2", "clock-26m", 2}, + + /* This one is a parent for dpll */ + {"unknownpll-d2", "unknownpll", 2}, + + /* Pre-0x140 divisions. They enter topcrm through different bits in 0x140= */ + {"mpll-d2", "mpll", 2}, + {"mpll-d5", "mpll", 5}, + {"mpll-d6", "mpll", 6}, + {"mpll-d8", "mpll", 8}, + {"upll-d12", "upll", 12}, + {"gpll-d2", "gpll", 2}, + {"gpll-d4", "gpll", 4}, + + /* Post-140 divisions. They enter through the same bit and can be selecte= d by different mux + * values of their consumers or get piped to multiple consumers with diff= erent documented + * rates - in particular, USB wclk (24 MHz according to ZTE) shares bit 2= with M0's 78MHz. + */ + {"top-mpll-d2-d4", "top-mpll-d2", 4}, + {"top-mpll-d2-d13", "top-mpll-d2", 13}, + {"top-upll-d12-d2", "top-upll-d12", 2}, + {"top-gpll-d4-d2", "top-gpll-d4", 2}, +}; + +/* AHB: The clock mux works and impact can be tested e.g. with iperf speed= testing of the USB + * network connection. Values 2 and 3 give the same speed and depend on th= e same bit (3) in 0x140. + * The mpll-d6 rate is gated off by the same bit in 0x140 as m0's mpll-d6,= but the d8 is different. + * This may indicate that one of the two uses a different clock rate than = documented in ZTE's + * kernel. The M0 speed is easy to measure, so I am confident in the M0's = 78 MHz rate. AHB looks + * like 78 rather than 52, but confidence is lower because RAM read tests = are influenced by CPU + * overhead too. + */ +static const char * const ahb_sel[] =3D { + "clock-26m", + "top-mpll-d6", /* 104 mhz */ + "top-mpll-d8", /* 78 mhz */ + "top-mpll-d8", /* 78 mhz */ +}; + +static const char * const timer_top_sel[] =3D { + "clock-32k", + "clock-26m", +}; + +static const char * const uart_top_sel[] =3D { + "clock-26m", + "top-mpll-d6", /* 104 mhz, sharing M0's and ahb's 0x140 gate */ +}; + +/* The Cortex M0 coprocessor. It is responsible for booting the board and = runs some power management + * helper code on the stock firmware. The M0 rproc itself is not critical,= but most of topcrm's + * registers become unreadable if this is gated off or become slow when cl= ocked at 32khz, e.g. GPIO + * becomes borderline unusable at 32khz. + * + * There is no dedicated M0 gate. Disabling ahb-wclk looks like the M0 sto= ps from A53's point of + * view, but it merely breaks the A53's ability to communicate with it, an= d M0's ability to + * communicate with the standard UART on LSP. M0 keeps running with both a= hb-wclk and ahb-pclk + * gated off and can re-enable the gates. + */ +static const char * const m0_sel[] =3D { + "clock-26m", + "top-mpll-d6", /* 104 mhz */ + "top-mpll-d2-d4", /* 78 mhz, but different gate than the ahb counterpart = */ + "clock-32k", /* Yes, tested. It is SLLLLOOOOOWWW. */ +}; + +/* Clk-out0/1/2/32k: These clocks are exposed on GPIOs 15, 16, 17 and 18 r= espectively. They are used + * in ZTE's camera and sound code, by directly poking into the clock regis= ters from the device + * drivers. Until the respective devices are supported they can safely be = switched off. + * + * For clk-out1 ZTE's camera code says the following: + * + * 0 -> 20 MHz + * 1 -> 40 MHz + * 2 -> 13 MHz + * 3 -> 26 MHz + * + * 0 and 1 read from upll. I confirmed their rates (upll-d24 and upll-d12)= by setting upll to a very + * low frequency and sampling the clock by GPIO reads. The outputs of 2 an= d 3 are way too high to + * test that way. Neither is reading from any PLL, they keep oscillating w= hen all PLLs are disabled. + * I am fairly sure that 3 is just direct clock-26m because it perfectly m= atches what out2 is + * showing in its 26 MHz setting. + * + * Clk-out2 is similar, but it has only one control bit in top 0x34 bit 8.= Neither setting selects + * a PLL output. When setting *0x34 =3D 0x080, clk-out1 and clk-out2 are i= n lockstep, presumably + * running at 13 MHz. 0x1c0 also runs in lockstep, presumably 26 MHz. + * + * clk-out0 has a mux in bit 5. Value 0 most likely selects clock-26m. I a= m not entirely sure about + * value 1 (which is the default), but the m0 mux has an impact on it. It = looks like a debug pin + * that exposes some core clock. + */ + +static const char * const out0_sel[] =3D { + "clock-26m", + "m0-mux", +}; + +static const char * const out1_sel[] =3D { + "top-upll-d12", /* 40 MHz */ + "top-upll-d12-d2", /* 20 MHz */ + "clock-26m", + "clock-26m-d2", +}; + +/* Clk-o is similar to clk-out*, providing a clock on GPIO 20, presumably = for driving a (R)MII phy. + * The 50 MHz value is documented in a stray comment in ZTE's GMAC driver.= I tested it similarly to + * the above pins. Mux setting 0 gives half the count as setting 1 and set= ting 1 gives gpll divided + * by 4 - matching the 50 MHz suggested by the ZTE comment at the default = gpll settings. Gating gpll + * stops the clock for values 0 and 1. + * + * Settings 2 and 3 are possible, but seem to return garbage. It is genera= lly pulsing up and down, + * except if both gpll and upll are stopped. I suspect it just reads rando= m electrical fluctuation + * from other places in the board. Yes, I had a pull-down enabled when tes= ting this. + * + * I am not aware of any board that uses this though. The Ethernet equippe= d ones I have all run the + * phy with its own oscillator. + */ +static const char * const rmii_sel[] =3D { + "top-gpll-d4-d2", /* 25 MHz */ + "top-gpll-d4", /* 50 MHz */ +}; + +static const struct zx_pll_desc zx297520v3_plls[] =3D { + /* Default setting: 0x48040c11. 624/312/156. Only a single possible paren= t. This is the + * PLL for pretty much everything, including CPU, RAM and USB. + * + * Changing this PLL makes it possible to overclock the CPU or do more fi= ne grained + * underclocking than the CPU's mux allows. It does run into two problems= though: The USB + * device uses this PLL's output directly and is *very* sensitive to diff= erences. DRAM + * is also fed by this clock and needs to be re-trained on larger changes= , which needs to + * be done by the stage 1 boot loader. + */ + { + .name =3D "mpll", + .parents =3D clk_main, + .num_parents =3D ARRAY_SIZE(clk_main), + .rate =3D 0, + .reg =3D 0x8 + }, + + /* ZTE's code calls this PLL "upll". The only possible consumers I found = are clk-out1, + * which outputs this clock on GPIO 16 and HSIC. HSIC doesn't have anythi= ng connected to + * it on the devices I tested. The device that consumes clk-out1 seems to= be an SPI + * camera, which I haven't seen in any device so far. ZTE manipulates thi= s PLL directly out + * of the camera code, so it is unlikely to have another consumer. + * + * Long story short, shut it off. + */ + { + .name =3D "upll", + .parents =3D clk_main, + .num_parents =3D ARRAY_SIZE(clk_main), + .rate =3D 0, + .reg =3D 0x10, + }, + + /* Default value 0x4834902d. Feeds dpll. 46.08 MHz. Bit 25 can be set, so= two parents are + * possible. It looks like both values select the 26 MHz oscillator thoug= h. + * + * Since dpll's prepare may depend in this clock generating a usable sign= al, it needs to be + * enabled when prepared. + */ + { + .name =3D "unknownpll", + .parents =3D clk_main, + .num_parents =3D ARRAY_SIZE(clk_main), + .rate =3D 0, + .reg =3D 0x100, + .flags =3D ZX297520V3_PLL_PREPARE_IS_ENABLE, + }, + + /* The documentation says 491.52 MHz and measurement with the LSP TDM dev= ice supports this. + * The default value is 0x480c2011, but not all boot loaders set it up. T= o get to 491.52 + * with these settings it needs a 23.04 MHz reference clock, which matche= s unknownpll-d2. + * If unknownpll is disabled, dpll loses its lock. We set the frequency o= n this PLL if we + * find it is not enabled by the boot loader. + * + * The proprietary LTE driver or rproc enables and disables it. TDM and I= 2S can use it. + * + * It accepts parent values 0, 1, 2 and 3. Parent 0 is unknownpll-d2. The= others look like + * clock-26m. With a parent !=3D 0 dpll never loses its lock even when al= l other PLLs are off + * and the TDM counter register increases at a rate consistent with a 26.= 0/23.04 clock + * increase. + */ + { + .name =3D "dpll", + .parents =3D dpll_parents, + .num_parents =3D ARRAY_SIZE(dpll_parents), + .rate =3D 491520000, + .reg =3D 0x18, + }, + + /* "g" is either for "general" or "gigahertz". The VCO runs at 1GHz. Outp= ut clocks are 200, + * 100, 50, 25, ... MHz. It is used optionally by SDIO and QSPI and can d= rive a GPIO clock + * output for RMII, so it doesn't seem very general. + */ + { + .name =3D "gpll", + .parents =3D clk_main, + .num_parents =3D ARRAY_SIZE(clk_main), + .rate =3D 0, + .reg =3D 0x110, + }, +}; + +#define MUX(_id, _name, _parents, _reg, _shift, _size) { \ + _id, _name, _parents, ARRAY_SIZE(_parents), _reg, _shift, _size} + +#define DIV(_name, _parent, _reg, _shift, _size) { _name, _parent, _reg, _= shift, _size } + +#define GATE(_id, _name, _parent, _reg, _shift, _flags) { \ + .id =3D _id, \ + .name =3D _name, \ + .parent =3D _parent, \ + .flags =3D _flags, \ + .reg =3D _reg, \ + .shift =3D _shift, \ +} + +static const struct zx_mux_desc zx297520v3_top_muxes[] =3D { + MUX(ZX297520V3_M0_WCLK, "m0-mux", m0_sel, 0x= 38, 0, 2), + MUX(0, "ahb-mux", ahb_sel, 0x= 3c, 4, 2), + MUX(0, "timer-t08-mux", timer_top_sel, 0x= 40, 1, 1), + MUX(0, "timer-t09-mux", timer_top_sel, 0x= 40, 0, 1), + MUX(0, "timer-t12-mux", timer_top_sel, 0x= 3c, 0, 1), + MUX(0, "timer-t13-mux", timer_top_sel, 0x= 44, 0, 1), + MUX(0, "timer-t14-mux", timer_top_sel, 0x= 44, 1, 1), + MUX(0, "timer-t15-mux", timer_top_sel, 0x= 3c, 3, 1), + MUX(0, "timer-t16-mux", timer_top_sel, 0x= 44, 2, 1), + MUX(0, "timer-t17-mux", timer_top_sel, 0x1= 20, 0, 1), + MUX(0, "wdt-t18-mux", timer_top_sel, 0x= 3c, 6, 1), + MUX(0, "i2c0-mux", uart_top_sel, 0x= 3c, 1, 1), + MUX(0, "uart0-mux", uart_top_sel, 0x= 40, 2, 1), + MUX(0, "out0-mux", out0_sel, 0x= 34, 5, 1), + MUX(0, "out1-mux", out1_sel, 0x= 34, 6, 2), + MUX(0, "rmiiphy-mux", rmii_sel, 0x1= 1c, 0, 2), +}; + +static const struct zx_div_desc zx297520v3_top_dividers[] =3D { + DIV("timer-t08-div", "timer-t08-mux", 0x4c, 8, 4), + DIV("timer-t09-div", "timer-t09-mux", 0x4c, 0, 4), + DIV("timer-t12-div", "timer-t12-mux", 0x48, 0, 4), + DIV("timer-t13-div", "timer-t13-mux", 0x50, 0, 4), + DIV("timer-t14-div", "timer-t14-mux", 0x50, 4, 4), + DIV("timer-t15-div", "timer-t15-mux", 0x48, 4, 4), + DIV("timer-t16-div", "timer-t16-mux", 0x50, 8, 4), + DIV("timer-t17-div", "timer-t17-mux", 0x124, 0, 4), + DIV("wdt-t18-div", "wdt-t18-mux", 0x48, 8, 4), + DIV("usim1-div", clk_unknown, 0x48, 12, 1), +}; + +static const struct zx_gate_desc zx297520v3_top_gates[] =3D { + /* topcrm input gates. These are complicated, but shed a lot of light on = the board's clock + * distribution. + * + * Settable mask: 0x017333FF. Generally one nibble per PLL, except for MP= LL that has more. + * One for clock-26m work clock. pclk and clock-32k are not gated globall= y here or anywhere + * else as far as I can see. + * + * If you want to test your understanding of this board, try to manually = configure it into a + * setup where bit 24 or bit 9 are off without crashing it. + */ + + /* Bit 0: No known consumer */ + /* Bit 1: M0's 78 MHz selection, but somehow also involved in USB too */ + GATE(0, "top-mpll-d2", "mpll-d2", 0x1= 40, 1, 0), + /* Bit 2: No known consumer, named mpll_48m_clk in ZTE's cpko.ko blob */ + GATE(0, "top-mpll-d8", "mpll-d8", 0x1= 40, 3, 0), + GATE(0, "top-mpll-d6", "mpll-d6", 0x1= 40, 4, 0), + /* Bit 5: No known consumer. mpll_156m_clk in cpko.ko */ + /* Bit 6: AXI voting candidate, might be selected by rprocs without notif= ication */ + GATE(ZX297520V3_MPLL_D5, "matrix-mpll-d5", "mpll-d5", 0x1= 40, 6, + CLK_IS_CRITICAL), + /* Bit 7: No known consumer */ + /* Bit 8: Has a consumer, LTE depends on it. But unknown what and how */ + /* Bit 9: Big MPLL provider for Matrix. Candidate in the AXI election, th= us critical */ + GATE(ZX297520V3_MPLL, "matrix-mpll", "mpll", 0x1= 40, 9, + CLK_IS_CRITICAL), + /* Bit 10: Always 0 */ + /* Bit 11: Always 0 */ + /* Bit 12: No known consumer. Existing patterns indicate a dpll consumer = in top itself */ + GATE(ZX297520V3_DPLL, "matrix-dpll", "dpll", 0x1= 40, 13, 0), + /* Bit 14: Always 0 */ + /* Bit 15: Always 0 */ + GATE(0, "top-upll-d12", "upll-d12", 0x1= 40, 16, 0), + GATE(0, "top-upll", "upll", 0x1= 40, 17, 0), + /* Bit 18: Always 0 */ + /* Bit 19: Always 0 */ + GATE(0, "top-gpll-d4", "gpll-d4", 0x1= 40, 20, 0), + GATE(ZX297520V3_GPLL_D2, "matrix-gpll-d2", "gpll-d2", 0x1= 40, 21, 0), + GATE(ZX297520V3_GPLL, "matrix-gpll", "gpll", 0x1= 40, 22, 0), + /* Bit 23: Always 0 */ + /* Bit 24 covers all 26 MHz on matrix, but not pclks. It is an AXI voting= candidate. + * clock-26m consumers on topcrm to not use this, they get the ungated cl= ock-26m. + */ + GATE(ZX297520V3_GATED_OSC26M, "matrix-osc26m", "clock-26m", 0x1= 40, 24, + CLK_IS_CRITICAL), + + /* AHB clock gates: Disabling these cuts off the A53 from register access= into 0x130000/ + * 0x140000, including the topcrm region, so it can't be re-enabled. Mark= them critical for + * that reason. + * + * Gating this off does not stop the M0 rproc, nor does it stop M0 from a= ccessing topcrm. It + * does however gate off M0 from the AXI interconnect, so it can't read R= AM, Matrix, etc. So + * these bits here merely gate the bus, not the actual devices. + */ + GATE(ZX297520V3_AHB_PCLK, "ahb-pclk", "ahb-mux", 0x= 54, 12, + CLK_IS_CRITICAL), + GATE(ZX297520V3_AHB_WCLK, "ahb-wclk", "m0-mux", 0x= 54, 13, + CLK_IS_CRITICAL), + + /* SRAM1 and 2 clocks. Leave them on for now, as turning them off careles= sly hangs the M0 */ + GATE(ZX297520V3_SRAM1_PCLK, "sram1-pclk", clk_main[0], 0x= 54, 18, + CLK_IS_CRITICAL), + GATE(ZX297520V3_SRAM2_PCLK, "sram2-pclk", clk_main[0], 0x= 54, 16, + CLK_IS_CRITICAL), + + /* Pinmux (AON, TOP, IOCFG but not PDCFG). Critical as well until we have= a driver that + * consumes it. I don't think we'll realistically shut this off ever. + * + * Setting either bit 0 or 1 in register 0x58 makes the device work. + */ + GATE(ZX297520V3_PMM_WCLK, "pmm-wclk", clk_main[0], 0x= 58, 0, + CLK_IS_CRITICAL), + GATE(ZX297520V3_PMM_PCLK, "pmm-pclk", clk_main[0], 0x= 58, 1, + CLK_IS_CRITICAL), + + /* Timers. We don't use any of them, just shut them off. The timers are n= amed and sorted + * by the IO address of the main timer controls. Some of the controls are= documented in + * ZTE's kernel, the others I found by trial and error. + * + * Timer T17 is used by the ZSP firmware. The rproc driver will enable it= as needed. + */ + GATE(ZX297520V3_TIMER_T08_WCLK, "timer-t08-wclk", "timer-t08-div", 0x= 5c, 8, 0), + GATE(ZX297520V3_TIMER_T08_PCLK, "timer-t08-pclk", clk_main[0], 0x= 5c, 9, 0), + GATE(ZX297520V3_TIMER_T09_WCLK, "timer-t09-wclk", "timer-t09-div", 0x= 5c, 4, 0), + GATE(ZX297520V3_TIMER_T09_PCLK, "timer-t09-pclk", clk_main[0], 0x= 5c, 5, 0), + GATE(ZX297520V3_TIMER_T12_WCLK, "timer-t12-wclk", "timer-t12-div", 0x= 54, 4, 0), + GATE(ZX297520V3_TIMER_T12_PCLK, "timer-t12-pclk", clk_main[0], 0x= 54, 5, 0), + GATE(ZX297520V3_TIMER_T13_WCLK, "timer-t13-wclk", "timer-t13-div", 0x= 60, 0, 0), + GATE(ZX297520V3_TIMER_T13_PCLK, "timer-t13-pclk", clk_main[0], 0x= 60, 1, 0), + GATE(ZX297520V3_TIMER_T14_WCLK, "timer-t14-wclk", "timer-t14-div", 0x= 60, 4, 0), + GATE(ZX297520V3_TIMER_T14_PCLK, "timer-t14-pclk", clk_main[0], 0x= 60, 5, 0), + GATE(ZX297520V3_TIMER_T15_WCLK, "timer-t15-wclk", "timer-t15-div", 0x= 54, 20, 0), + GATE(ZX297520V3_TIMER_T15_PCLK, "timer-t15-pclk", clk_main[0], 0x= 54, 21, 0), + GATE(ZX297520V3_TIMER_T16_WCLK, "timer-t16-wclk", "timer-t16-div", 0x= 60, 8, 0), + GATE(ZX297520V3_TIMER_T16_PCLK, "timer-t16-pclk", clk_main[0], 0x= 60, 9, 0), + GATE(ZX297520V3_TIMER_T17_WCLK, "timer-t17-wclk", "timer-t17-div", 0x1= 28, 0, 0), + GATE(ZX297520V3_TIMER_T17_PCLK, "timer-t17-pclk", clk_main[0], 0x1= 28, 1, 0), + /* This watchdog is set up by the bootloader and in normal operation the = m0 firmware will + * feed the dog. The m0 firmware in turn wants to be fed in its own way. = Since we normally + * don't run any m0 firmware we shut it off by default and expose it to u= serspace via the + * watchdog driver. + */ + GATE(ZX297520V3_WDT_T18_WCLK, "wdt-t18-wclk", "wdt-t18-div", 0x= 54, 24, 0), + GATE(ZX297520V3_WDT_T18_PCLK, "wdt-t18-pclk", clk_main[0], 0x= 54, 25, 0), + + GATE(ZX297520V3_I2C0_WCLK, "i2c0-wclk", "i2c0-mux", 0x= 54, 8, 0), + GATE(ZX297520V3_I2C0_PCLK, "i2c0-pclk", clk_main[0], 0x= 54, 9, 0), + GATE(ZX297520V3_UART0_WCLK, "uart0-wclk", "uart0-mux", 0x= 5c, 12, 0), + GATE(ZX297520V3_UART0_PCLK, "uart0-pclk", clk_main[0], 0x= 5c, 13, 0), + + /* ZTE says the USB input is a 24 MHz clock based on mpll. Testing shows = that Upll is not + * involved. The USB register space can be accessed with ahb-pclk gated, = but not with + * ahb-wclk gated. ZTE also lists ahb-wclk as parent for the second clock. + * + * There doesn't seem to be a separate PHY clock. usb-wclk stops controll= er registers from + * updating, but doesn't cause the USB device to disconnect like assertin= g the PHY reset + * does. Bit 0 in this register can't be set, so no PHY clock is hiding t= here either. + */ + GATE(ZX297520V3_USB_WCLK, "usb-wclk", "top-mpll-d2-d13", 0x= 6c, 3, 0), + GATE(ZX297520V3_USB_PCLK, "usb-pclk", "ahb-wclk", 0x= 6c, 4, 0), + /* The HSIC hardware is listed in ZTE's code with a physical address of 0= x01600000. Unlike + * the USB controller, it does consume upll. ZTE says 240 MHz, but 480 is= the usual one for + * HSIC. + */ + GATE(ZX297520V3_HSIC_WCLK, "hsic-wclk", "top-upll", 0x= 6c, 1, 0), + GATE(ZX297520V3_HSIC_PCLK, "hsic-pclk", "ahb-wclk", 0x= 6c, 2, 0), + + /* How does this RTC work? I don't know, the ZTE kernel does not talk to = it. The actual RTC + * is on the I2C connected PMIC. + */ + GATE(ZX297520V3_RTC_WCLK, "rtc-wclk", clk_unknown, 0x= 54, 0, 0), + GATE(ZX297520V3_RTC_PCLK, "rtc-pclk", clk_main[0], 0x= 54, 1, 0), + + GATE(ZX297520V3_USIM1_WCLK, "usim1-wclk", "usim1-div", 0x= 54, 28, 0), + GATE(ZX297520V3_USIM1_PCLK, "usim1-pclk", clk_main[0], 0x= 54, 29, 0), + + /* LTE: gate only as far as I can see. I looked for resets and did not fi= nd any. There may + * be mux/div, but without understanding the behavior of this hardware it= is impossible to + * tell. They are sorted by physical MMIO address of the devices, which h= appens to be the + * inverse order of the bits. + * + * I don't know what "LPM", "TD" and "W" mean. I copied them from ZTE's n= ames. + */ + GATE(ZX297520V3_LPM_GSM_WCLK, "lpm-gsm-wclk", clk_unknown, 0x= 58, 10, 0), + GATE(ZX297520V3_LPM_GSM_PCLK, "lpm-gsm-pclk", clk_main[0], 0x= 58, 11, 0), + GATE(ZX297520V3_LPM_LTE_WCLK, "lpm-lte-wclk", clk_unknown, 0x= 58, 8, 0), + GATE(ZX297520V3_LPM_LTE_PCLK, "lpm-lte-pclk", clk_main[0], 0x= 58, 9, 0), + GATE(ZX297520V3_LPM_TD_WCLK, "lpm-td-wclk", clk_unknown, 0x= 58, 6, 0), + GATE(ZX297520V3_LPM_TD_PCLK, "lpm-td-pclk", clk_main[0], 0x= 58, 7, 0), + /* This one is called gsm_156m in cpko.ko, thus a candidate for an unknow= n 0x140 bit. */ + GATE(ZX297520V3_LPM_W_WCLK, "lpm-w-wclk", clk_unknown, 0x= 58, 4, 0), + GATE(ZX297520V3_LPM_W_PCLK, "lpm-w-pclk", clk_main[0], 0x= 58, 5, 0), + /* cpko.ko has a clock "gsm_48m" on bit 2, a candidate for an unknown 0x1= 40 bit. */ + + GATE(ZX297520V3_OUT0_WCLK, "out0-wclk", "out0-mux", 0x= 34, 0, 0), + GATE(ZX297520V3_OUT1_WCLK, "out1-wclk", "out1-mux", 0x= 90, 2, 0), + GATE(ZX297520V3_OUT2_WCLK, "out2-wclk", clk_main[0], 0x= 94, 2, 0), + GATE(ZX297520V3_OUT32K_WCLK, "out32k-wclk", "clock-32k", 0x= 34, 1, 0), + GATE(ZX297520V3_RMIIPHY_WCLK, "rmiiphy-wclk", "rmiiphy-mux", 0x1= 1c, 2, 0), +}; + +static const struct zx_clk_data zx297520v3_topclk_data =3D { + .inputs =3D zx297520v3_top_inputs, + .num_inputs =3D ARRAY_SIZE(zx297520v3_top_inputs), + .plls =3D zx297520v3_plls, + .num_plls =3D ARRAY_SIZE(zx297520v3_plls), + .fixed_divs =3D zx297520v3_top_fixed_divs, + .num_fixed_divs =3D ARRAY_SIZE(zx297520v3_top_fixed_divs), + .muxes =3D zx297520v3_top_muxes, + .num_muxes =3D ARRAY_SIZE(zx297520v3_top_muxes), + .divs =3D zx297520v3_top_dividers, + .num_divs =3D ARRAY_SIZE(zx297520v3_top_dividers), + .gates =3D zx297520v3_top_gates, + .num_gates =3D ARRAY_SIZE(zx297520v3_top_gates), +}; + +static int clk_zx297520v3_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id =3D platform_get_device_id(pdev); + + if (!id) + return -ENODEV; + + return zx_clk_common_probe(&pdev->dev, pdev->dev.parent->of_node, + (const struct zx_clk_data *)id->driver_data); +} + +static const struct platform_device_id clk_zx297520v3_ids[] =3D { + { + .name =3D "zx297520v3-topclk", + .driver_data =3D (kernel_ulong_t)&zx297520v3_topclk_data, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); + +static struct platform_driver clk_zx297520v3 =3D { + .probe =3D clk_zx297520v3_probe, + .driver =3D { + .name =3D "clk-zx297520v3", + }, + .id_table =3D clk_zx297520v3_ids, +}; +module_platform_driver(clk_zx297520v3); + +MODULE_AUTHOR("Stefan D=C3=B6singer "); +MODULE_DESCRIPTION("ZTE zx297520v3 clock driver"); +MODULE_LICENSE("GPL"); --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6203B27AC48 for ; Thu, 16 Jul 2026 22:00:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239234; cv=none; b=KMgMgo/W+rhAA4aqE0g0hXQlM7sfaRS0AWcHHFpnrv8f2iJNqTql560dT8zBwarw6mHDWqcWIyOWrBQen4ZUhKG68p/T533QO5vHeJPCJmMcqi8+GpYtlb0/4oX/xmuPkDQQ/30Lmn49+a24Rh+vzv0sKYxB75TYd5Vz7I33u0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239234; c=relaxed/simple; bh=NrjuaqXWi8y8citUw1tax6e65h8FgEnDAE3lfix/TMQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=g5UZxMNrDVtBnx6orwx6f/+GkUF5zVVajr4Rlv+V00jpUwFmrm1F69S/GVhOxeGjoEM7EexJAp2PaR0H6H1JXeQ79BBQG2XsMbez4kv73Ra21rvaoU6II5QuDKf37PZ7VXsTUjF+3RX9Qxp5CP2/LJEKnlSpPNhAFiVmbq/VE0o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=AbyUnCLN; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AbyUnCLN" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-4799b3f7c83so5166303f8f.2 for ; Thu, 16 Jul 2026 15:00:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784239230; x=1784844030; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=k0QhVcSPxl5ktUEKFBVIie73Dy9M8toajCnkBUU1vsE=; b=AbyUnCLNEemdnA4e+9q3GRrPFKEU7x7DvuHB1JkLnCtLMLSZ5rL9azPUSTf0VnwzGL 5OMF0wx5F5ehCoMNuWoS3RaIBraJGmPWmgfLSUDszVhn2ERaQTYEPbKeGN8jt+0ivsX8 0W5ppT/jsyaLmgBe80oMeMFw7BTNboPSrqejHuzUi3NR6nx0/5/r8EYO2xSbHkoe/Uip na0vZXoOs/0aMIc+GDQ89tbw+KNc+WYUbafxVTsbkMDYf6k8qPZJSHyvRv6W3nwtKozx 1grcEZtyilztDfevwy3ikKRX8rv8D6PexOjrikuip3Xj/UrP58O7oQO8BDRr2H0stBs1 ZlWg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784239230; x=1784844030; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=k0QhVcSPxl5ktUEKFBVIie73Dy9M8toajCnkBUU1vsE=; b=B6h4mEd/yfTpodZa8fQKn0tTi/KjX1SdhNXjw1iSMtqllaQPe20uqNhbbKifjT/wjx 8gqgUU7W7JTJoQ0GupMp/pH2ZxYrTa5hazz/UThaTK9oNLujIpyGlbKNEy/JNNOS9iY+ TKotGEQ6h1YXDZj5zyYeLjPeZkQfY1jrZmQ5Z5UZhJ5Taz9SUGylSwPvfOFEpMS5zYpf oQh7d+fLdMuGtB6WhWb8KyUG+M6Kan3u8NjSLNCNWcUNweN+cWqT/GeAMr3CFzyIW8Bt W1zsbhpy9kYT4SQGsNuMn+fhvDkF6c8HKXJgu5HhgyatoAut4v2pAINN6fEWiZXKUJ7R UXcA== X-Forwarded-Encrypted: i=1; AHgh+RrLkGIGUpwf0ZxBA6eh7eLdYMd+8h6prWKWLEefdXeFgGme8aKVUcjQ6KyE0Ca2hQKD5gZzFdT865dcTdc=@vger.kernel.org X-Gm-Message-State: AOJu0Yy0fRrhONgZMb2YlpiZZUkR7DOCyqYUbNdAIRrFCAiDxCJ+gS54 qxNZsIrM5LOPbAP5okFFrWdlz8536LWykqGU9h81vQYcGOMC2/JoiOkY X-Gm-Gg: AfdE7ckDJLgco9zm/e03WxN81OjJQf1jGNXohtY+plLH+zS99DSPvetv+/Sd9TkYpt1 rd41N5GmHbnuRAFz1Sr91luLAHSqAnTFbdfnlOA0rzuJUj8qThjYF+4Bn2+VxJrodYurA0Xm9hG 58Q3F/n3zZX/3UsRJd2PJs60eiW66fI58+IanDuRRc0nkT1LmQJEy8Zn0P0GdMuI/Yn0Rfz4ccH wiAPK9gF18AVvmdzSSF1WBl3JIbyCHDNPH0hD6n/HOk7TrJHeYuOZgk+6ocSD+PLEvq0aCStT4M FCEIrsFyJ7+re88tWf/NMLf1M/HXNKWgEAcX/uZqgxLAjVJ5iloK+VPig4li/IHgHY8ScGsgxQa yON2no1Djw1AIRHLIuatiGW2OYi2ifk8ZjTM12Z0QGn5/J7DBhCz1X4Qn9+FauMjQl75fi9Tz6k U9AdsfcqIHkYo5MQ== X-Received: by 2002:a05:6000:4a15:b0:477:b22:488d with SMTP id ffacd0b85a97d-47f622fcdccmr16159f8f.10.1784239229229; Thu, 16 Jul 2026 15:00:29 -0700 (PDT) Received: from strix.doe.home ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464a974csm29949056f8f.18.2026.07.16.15.00.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 15:00:28 -0700 (PDT) From: =?UTF-8?q?Stefan=20D=C3=B6singer?= To: linux-arm-kernel@lists.infradead.org Cc: Michael Turquette , Stephen Boyd , Brian Masney , linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v7 10/13] clk: zte: Introduce a driver for zx297520v3 matrix clocks Date: Fri, 17 Jul 2026 01:00:08 +0300 Message-ID: <20260717-zx29clk-v7-10-50abfa8dd594@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This clock controller controls high speed devices: CPU, DMA, RAM, SDIO, Ethernet. The only non-clock, non-reset registers I have spotted here are hardware spinlocks. Signed-off-by: Stefan D=C3=B6singer --- Version 7: Reduced the input clocks a lot. Most MPLL subdivisons are children of the same gate in top, so put the fixed factor clocks here. Added a few more clocks: DDR_CTRL, AXI bus, arm architectured timer. They are needed to tell CCF to keep the top gates enabled and marked critical because they aren't consumed by a DT node. The AXI bus is determined by a voting system. I've set up the driver to write to the ballot register ZTE's kernel uses and enable voting. This should make life easier with the LTE rproc blob later. Version 5: Make it an MFD child device, remove aux device Fix zx297529 -> zx297520 typos Fix AHB_wclk -> ahb_wclk. That was a leftover of my old composite structs Add SRAM0 and GSM_CFG clocks --- drivers/clk/zte/clk-zx297520v3.c | 312 +++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 312 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c index 20ff00ba5f67..e08ba9623345 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -510,6 +510,314 @@ static const struct zx_clk_data zx297520v3_topclk_dat= a =3D { .num_gates =3D ARRAY_SIZE(zx297520v3_top_gates), }; =20 +/* For devices which have a working driver the work clock can be figured o= ut by gating off registers + * in top+0x140. This is used for devices where I can't interpret the regi= ster contents yet. + */ +static const char matrix_unk[] =3D "matrix-osc26m"; + +static const char * const cpu_sel[] =3D { + "matrix-osc26m", + "matrix-mpll", /* 624 MHz */ + "matrix-mpll-d2", /* 312 MHz */ + "matrix-mpll-d4", /* 156 MHz */ +}; + +/* Low confidence on the actual value, but at least I know it is bit 13 in= top+0x140 */ +static const char * const zsp_sel[] =3D { + "matrix-osc26m", + "matrix-dpll", /* 491.52 MHz */ +}; + +/* We can't realistically change DDR speed while running an OS out of DDR = (it reads garbage for a + * short while on transition), but we need to know if we have to keep gpll= alive. 32 MB devices use + * 200MHz, while 64/128 MB ones use 156. + */ +static const char * const ddr_ctrl_sel[] =3D { + "matrix-mpll-d4", /* 156 MHz */ + "matrix-gpll", /* 200 MHz */ + "matrix-mpll-d6", /* 104 MHz */ + "matrix-mpll-d8", /* 78 MHz */ +}; + +static const char * const sd0_sel[] =3D { + "matrix-osc26m", + "matrix-mpll-d4", /* 156 MHz */ + "matrix-gpll-d2", /* 100 MHz */ + "matrix-mpll-d8", /* 78 MHz */ + "matrix-gpll-d2-d2", /* 50 MHz */ + "matrix-gpll-d2-d4", /* 25 MHz */ +}; + +static const char * const sd1_sel[] =3D { + "matrix-osc26m", + "matrix-gpll-d2", /* 100 MHz */ + "matrix-mpll-d8", /* 78 MHz */ + "matrix-gpll-d2-d2", /* 50 MHz */ + "matrix-mpll-d16", /* 39 MHz */ + "matrix-gpll-d2-d4", /* 25 MHz */ +}; + +/* ZTE's kernel puts the high frequency first, but this is against the usu= al convention on this + * SoC. I don't have any device that has a raw NAND controller though. + */ +static const char * const nand_sel[] =3D { + "matrix-osc26m", + "matrix-mpll-d4", /* 156 MHz */ +}; + +static const char * const edcp_sel[] =3D { + "matrix-osc26m", + "matrix-mpll-d4", /* 156 MHz */ + "matrix-mpll-d5", /* 124.8 MHz */ + "matrix-mpll-d6", /* 104 MHz */ +}; + +static const char * const tdm_sel[] =3D { + "matrix-osc26m", + "matrix-dpll-d4", /* 122.88 MHz */ + "matrix-mpll-d6", /* 104 MHz */ +}; + +/* AXI speed is either determined by a fixed selection in 0x0, bits 0:2 or= by a voting system with + * ballots in 0x120, 0x124, 0x128. The voting system is enabled by setting= 0x12c to 1. Otherwise the + * selection in 0x0 applies. + * + * ZTE's firmware uses 0x128 as the PHY's vote and names 0x120 as "PS" and= 0x124 as "AP" vote. + * However, their cpufreq driver ultimately uses the "PS" define and thus = writes to 0x120, which can + * be observed in the running system. + * + * The fastest selected speed wins. This holds true for values 0 (26 MHz) = and 7 (6.5 MHz) too, so it + * isn't a case of lowest selector wins. I haven't tested what happens if = mpll is changed to output + * 5x the normal clock, so 7 beats 0. Presumably value 0 would still win t= he election. + * + * AXI speed 6.5 is an mpll child, not a division of [matrix-]osc26m by 4.= It depends on top+0x140 + * bit 9, like other mpll (other than d5) choices. + * + * The system initializes with voting disabled and all preferences set to = the lowest setting, 7. + * The zx297520v3_matrix_init function transfers the global mux to our vot= e and enables voting. + */ +#define ZX297520V3_AXI_AP_VOTE 0x120 +static const char * const axi_sel[] =3D { + "matrix-osc26m", + "matrix-mpll-d4", /* 156 MHz */ + "matrix-mpll-d5", /* 124.88 MHz */ + "matrix-mpll-d6", /* 104 MHz */ + "matrix-mpll-d8", /* 78 MHz */ + "matrix-mpll-d12", /* 52 MHz */ + "matrix-mpll-d16", /* 39 MHz */ + "matrix-mpll-d96", /* 6.5 MHz */ +}; + +static const struct zx_mux_desc zx297520v3_matrix_muxes[] =3D { + MUX(0, "cpu-mux", cpu_sel, 0x= 20, 0, 2), + MUX(0, "zsp-mux", zsp_sel, 0x= 30, 0, 2), + MUX(0, "ddr-ctrl-mux", ddr_ctrl_sel, 0x= 50, 0, 2), + MUX(0, "sd0-mux", sd0_sel, 0x= 50, 4, 3), + MUX(0, "sd1-mux", sd1_sel, 0x= 50, 8, 3), + MUX(0, "nand-mux", nand_sel, 0x= 50, 12, 2), + MUX(0, "edcp-mux", edcp_sel, 0x= 50, 16, 2), + MUX(0, "tdm-mux", tdm_sel, 0x= 50, 24, 2), + MUX(0, "axi-mux", axi_sel, ZX297520V3_AXI_AP_= VOTE, 0, 3), +}; + +static const struct zx_gate_desc zx297520v3_matrix_gates[] =3D { + /* This bit cuts off the clock signal to the ARM architected timer, which= the kernel uses + * as its main timer. It isn't critical per se - there are plenty of prop= rietary timers + * available that could be used - but the arm arch timer binding does not= accept a clock, so + * this CCF driver won't know if the timer is in use. + * + * This clock is fed by the mux in topclk+0x140 - this critical clock her= e protects its + * parent. + */ + GATE(ZX297520V3_SYS_TIMER_WCLK, "sys-timer-wclk", "matrix-osc26m", 0x1= 44, 1, + CLK_IS_CRITICAL), + + /* Both 0x24 and 0x28 bits 1 and 2 stop the CPU. There is also a bit in t= opclk+0x138, which + * ZTE's uboot calls "A53 reset", which also stops the CPU. I can't reall= y tell the + * difference between matrix+28 and top+138. The clock (maxtrix+0x24) can= be disabled and + * enabled from the Cortex M0 and it will nicely stop and restart the A53= , retaining all + * state. + */ + GATE(ZX297520V3_CPU_WCLK, "cpu-wclk", "cpu-mux", 0x= 24, 1, + CLK_IS_CRITICAL), + GATE(ZX297520V3_CPU_PCLK, "cpu-pclk", clk_main[0], 0x= 24, 2, + CLK_IS_CRITICAL), + + /* There are a lot more controls in matrix+0x100. 13-16 appear to be 4 di= fferent AXI + * channels for different priorities. Bit 19 appears to be the DDR PHY wc= lk. + * + * The important task is to keep gpll powered if the bootloader selected = a gpll-based rate + * for RAM. + */ + GATE(ZX297520V3_DDR_CTRL_PCLK, "ddr-ctrl-pclk", clk_main[0], 0x1= 00, 17, + CLK_IS_CRITICAL), + GATE(ZX297520V3_DDR_CTRL_WCLK, "ddr-ctrl-wclk", "ddr-ctrl-mux", 0x1= 00, 18, + CLK_IS_CRITICAL), + + GATE(ZX297520V3_ZSP_WCLK, "zsp-wclk", "zsp-mux", 0x= 3c, 0, 0), + + GATE(ZX297520V3_SD0_WCLK, "sd0-wclk", "sd0-mux", 0x= 54, 12, 0), + GATE(ZX297520V3_SD0_PCLK, "sd0-pclk", clk_main[0], 0x= 54, 13, 0), + GATE(ZX297520V3_SD0_CDET, "sd0-cdet", "clock-32k", 0x= 54, 14, 0), + GATE(ZX297520V3_SD1_WCLK, "sd1-wclk", "sd1-mux", 0x= 54, 4, 0), + GATE(ZX297520V3_SD1_PCLK, "sd1-pclk", clk_main[0], 0x= 54, 5, 0), + /* I don't know how the cdet clock works. Card detection in the way the d= wc,mmc driver uses + * it appears broken no matter this clock's setting. + */ + GATE(ZX297520V3_SD1_CDET, "sd1-cdet", "clock-32k", 0x= 54, 6, 0), + + /* This is some "denali" NAND, not the qspi connected one */ + GATE(ZX297520V3_NAND_WCLK, "nand-wclk", "nand-mux", 0x= 54, 20, 0), + GATE(ZX297520V3_NAND_PCLK, "nand-pclk", clk_main[0], 0x= 54, 21, 0), + + /* There is a set of gates for an unknown device at matrix+0x60. This dev= ice sends 50 HZ + * interrupts to SPI+68. From testing it seems to be ZSP/LTE PHY related.= Closing the gates + * stops the IRQs but breaks LTE and access to ZSP's TCM MMIO regions on = ZTE's kernel. + * Interestingly the IRQs arrive when the ZSP clocks themselves are disab= led or ZSP is in + * reset. + */ + + /* Yes, WCLK bit > PCLK bit for EDCP */ + GATE(ZX297520V3_EDCP_WCLK, "edcp-wclk", "edcp-mux", 0x= 64, 2, 0), + GATE(ZX297520V3_EDCP_PCLK, "edcp-pclk", clk_main[0], 0x= 64, 1, 0), + + /* This seems to be another SPI-Like device. ZTE's firmware operates it a= nd from testing + * it looks like the matrix_osc26m gate in top+0x140 stops this device. T= his would be + * consistent with the other SPI controllers too. + */ + GATE(ZX297520V3_SSC_WCLK, "ssc-wclk", "matrix-osc26m", 0x= 84, 1, 0), + GATE(ZX297520V3_SSC_PCLK, "ssc-pclk", clk_main[0], 0x= 84, 2, 0), + + /* PDCFG. Like PMM, either clock bit will allow the device to function. P= robably there is + * no wclk line at all and the two bits are just an artifact of generally= having two bits + * per device. + */ + GATE(ZX297520V3_PDCFG_WCLK, "pdcfg-wclk", matrix_unk, 0x= 88, 0, + CLK_IS_CRITICAL), + GATE(ZX297520V3_PDCFG_PCLK, "pdcfg-pclk", clk_main[0], 0x= 88, 1, + CLK_IS_CRITICAL), + GATE(ZX297520V3_MBOX_PCLK, "mbox-pclk", clk_main[0], 0x= 88, 2, 0), + GATE(ZX297520V3_SRAM0_PCLK, "sram0-pclk", clk_main[0], 0x= 88, 4, 0), + GATE(ZX297520V3_GSM_CFG_PCLK, "gsm-cfg-pclk", clk_main[0], 0x= 88, 8, 0), + + /* ZTE's driver has a statemt to the effect of *(top->base+0x11c) =3D 5, = with a comment + * suggesting that this sets a 50 mhz clock. The clock code itself lists = GMAC clocks in + * matrix+110 and lists the parents of these clock as 50mhz gpll output, = but the downstream + * ZTE GMAC driver never enables the clocks. It turns out ZTE's code is h= ighly misleading. + * + * The GMAC's work clock is definitly not any gpll output because it keep= s working fine with + * gpll disabled. Gating off matrix_osc26m breaks GMAC, so it must be its= parent. + * + * The GMAC Gates are left enabled by the boot loader and are required fo= r the GMAC to work. + * + * As for the 50 MHz comment: See rmiiphy-wclk. + */ + GATE(ZX297520V3_GMAC_WCLK, "gmac-wclk", "matrix-osc26m", 0x1= 10, 0, 0), + GATE(ZX297520V3_GMAC_PCLK, "gmac-pclk", clk_main[0], 0x1= 10, 1, 0), + GATE(ZX297520V3_GMAC_AHB, "gmac-ahb", "ahb-wclk", 0x1= 10, 2, 0), + + /* Is there an AXI bus gate? The symptom of cutting off the AXI mux selec= tion in top+0x140 + * is that matrixcrm becomes unreadable from m0 and A53 hangs. Inside mat= rix itself only 3 + * bits fit that bill: 0x8c bits 5, 6, 7. It seems a bit self-defeating t= o have a clock + * gate that shuts off access to itself though. I expect a clock gate for= the bus + * somewhere, and the mux exists, so exposing one AXI clock in the bindin= gs is the correct + * thing to do. It also serves to tell the kernel to keep the mux's paren= t enabled. + * + * Register 0x8c has 12 settable bits (0xfff). Ultimately it doesn't matt= er much which + * do-not-remove bit we don't remove. Other bits in this register behave = like gates (e.g + * bits 12:9 cut off USB temporarily), so I think we are looking in the r= ight place. + * + * If an explanation for the remaining bits surfaces and they are further= gates and/or + * resets, add them to the bindings. + */ + GATE(ZX297520V3_AXI_WCLK, "axi-wclk", "axi-mux", 0x= 8c, 5, + CLK_IS_CRITICAL), + + GATE(ZX297520V3_DMA_PCLK, "dma-pclk", clk_main[0], 0x= 94, 3, 0), + + /* There are a lot more VOU related controls in these registers, but turn= ing off the main + * clock seems to shut off the entire VOU MMIO range. + */ + GATE(ZX297520V3_VOU_WCLK, "vou-wclk", matrix_unk, 0x1= 68, 0, 0), + GATE(ZX297520V3_VOU_PCLK, "vou-pclk", clk_main[0], 0x1= 68, 1, 0), + + /* LSP uplink clocks. The PCLK is fairly obvious (disabling it shuts off = the entire LSP + * register area). The WCLK speeds were deduced by setting timers and qsp= i muxes to a + * specific speed and seeing which bit in matrix+0x7c needs to be enabled= for the device + * to work. + * + * Due to the timers I am certain about the 26mhz and 32khz clocks. I can= not directly + * observe the qspi mux frequency, so the clock rates depend on ZTE's qsp= i mux selection + * being correct. + * + * Two additional bits are specific to sound components - the mux for the= LSP's TDM IP is + * in matrixclk and gets passed down. I2S has a mux in LSP, which can sel= ect the dpll-d4 + * clock. + */ + GATE(ZX297520V3_LSP_MPLL_D5_WCLK, "lsp-mpll-d5", "matrix-mpll-d5", 0x= 7c, 0, 0), + GATE(ZX297520V3_LSP_MPLL_D4_WCLK, "lsp-mpll-d4", "matrix-mpll-d4", 0x= 7c, 1, 0), + GATE(ZX297520V3_LSP_MPLL_D6_WCLK, "lsp-mpll-d6", "matrix-mpll-d6", 0x= 7c, 2, 0), + GATE(ZX297520V3_LSP_MPLL_D8_WCLK, "lsp-mpll-d8", "matrix-mpll-d8", 0x= 7c, 3, 0), + GATE(ZX297520V3_LSP_MPLL_D12_WCLK, "lsp-mpll-d12", "matrix-mpll-d12", 0x= 7c, 4, 0), + GATE(ZX297520V3_LSP_OSC26M_WCLK, "lsp-osc26m", "matrix-osc26m", 0x= 7c, 5, 0), + GATE(ZX297520V3_LSP_OSC32K_WCLK, "lsp-osc32k", "clock-32k", 0x= 7c, 6, 0), + GATE(ZX297520V3_LSP_PCLK, "lsp-pclk", clk_main[0], 0x= 7c, 7, 0), + GATE(ZX297520V3_LSP_TDM_WCLK, "lsp-tdm-wclk", "tdm-mux", 0x= 7c, 8, 0), + GATE(ZX297520V3_LSP_DPLL_D4_WCLK, "lsp-dpll-d4", "matrix-dpll-d4", 0x= 7c, 9, 0), +}; + +static const char * const zx297520v3_matrix_inputs[] =3D { + "osc26m", "osc32k", + "mpll", "mpll-d5", "dpll", "gpll", "gpll-d2", "wclk-osc26m", +}; + +static const struct zx_fixed_divider_desc zx297520v3_matrix_fixed_divs[] = =3D { + {"matrix-mpll-d2", "matrix-mpll", 2}, + {"matrix-mpll-d4", "matrix-mpll", 4}, + /* div 5: provided as a separate line from topcrm */ + {"matrix-mpll-d6", "matrix-mpll", 6}, + {"matrix-mpll-d8", "matrix-mpll", 8}, + {"matrix-mpll-d12", "matrix-mpll", 12}, + {"matrix-mpll-d16", "matrix-mpll", 16}, + {"matrix-mpll-d96", "matrix-mpll", 96}, + + {"matrix-gpll-d2-d2", "matrix-gpll-d2", 2}, + {"matrix-gpll-d2-d4", "matrix-gpll-d2", 4}, + + {"matrix-dpll-d4", "matrix-dpll", 4}, +}; + +static int zx297520v3_matrix_init(struct regmap *map) +{ + u32 axi_val; + int res; + /* Read the global AXI speed selection, insert it into our ballot and ena= ble voting */ + + res =3D regmap_read(map, 0x0, &axi_val); + if (res) + return res; + + axi_val &=3D 0x7; + res =3D regmap_write(map, ZX297520V3_AXI_AP_VOTE, axi_val); + if (res) + return res; + + /* If this fails for some reason our vote will simply be ignored */ + return regmap_write(map, 0x12c, 1); +} + +static const struct zx_clk_data zx297520v3_matrixclk_data =3D { + .init =3D zx297520v3_matrix_init, + .inputs =3D zx297520v3_matrix_inputs, + .num_inputs =3D ARRAY_SIZE(zx297520v3_matrix_inputs), + .fixed_divs =3D zx297520v3_matrix_fixed_divs, + .num_fixed_divs =3D ARRAY_SIZE(zx297520v3_matrix_fixed_divs), + .muxes =3D zx297520v3_matrix_muxes, + .num_muxes =3D ARRAY_SIZE(zx297520v3_matrix_muxes), + .gates =3D zx297520v3_matrix_gates, + .num_gates =3D ARRAY_SIZE(zx297520v3_matrix_gates), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id =3D platform_get_device_id(pdev); @@ -526,6 +834,10 @@ static const struct platform_device_id clk_zx297520v3_= ids[] =3D { .name =3D "zx297520v3-topclk", .driver_data =3D (kernel_ulong_t)&zx297520v3_topclk_data, }, + { + .name =3D "zx297520v3-matrixclk", + .driver_data =3D (kernel_ulong_t)&zx297520v3_matrixclk_data, + }, { } }; MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3A9343C4B68 for ; Thu, 16 Jul 2026 22:17:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784240253; cv=none; b=EIIqv56z3T9OY7RLawVyWZPMKds2Ewnlt1z8PNlFs+uaKgmr2gFYq/gvL/uIPhI9ooUlZ5G8pf6SzuTMdTdRDeDsHWhNqCChOi6xNazud7aOED4Lvfy/2/e9rq7sI9e91IhMhMcQk+MA/qghO1k8jPuBwONZ106B2GOCYdQvjBc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784240253; c=relaxed/simple; bh=11hngiqwPMWQKJYfHPUwm8JUHTQO6wNmP9fxdqFYKWk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=ubSF/Fh+TY+1F3WL5S83gnQjKz9Ttxd9/Zqk18zSVj2bo7Lp2yQvw16MQjnIJ49THVnCcNj71e6nKUQ7v7+1qKOLugWOeHPAGXe8nQu6ko3egtuLZDKPG1rx1Lecwujue9YpR1nFSPCmd7JiiLSaHdjPao3Fj/jLIyKKbh/SbuY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=OJoGB+PY; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="OJoGB+PY" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-4758bd3731bso891058f8f.0 for ; Thu, 16 Jul 2026 15:17:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784240249; x=1784845049; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=1uELeJYYbHg+El5mtXQD5UioQ3wVMOPdr6PSy7q66II=; b=OJoGB+PYQstK/jnyd30eoH94mk2lzLQPOzfniOOKmp4q71h0kvrUrU7avxMIGKfzeX AYdDeZinGkCXsg7DOWAdKIo4LCp9YoNw9ybhREuzTTrHIw6Y50Zcdv19+v5ngnn+V2sN szVHlwLhF38w9LaabwyJZL7oaEM7ybvuZEg757TnPMOBKTBxaXXqnQJpGbo8gPz5oxSR L6A4y17URjRsVjZaE/7S8o6S+vRqedqo3lQBMfox3ST0bW2YOVlsX5P/+hyvYBvl7PAp Pu6kKvAuU3KYCU3V39LBffb2OhL7OXsPZMZbhVY1wK7XngeSrCpmt4g/8xtwIqSBrEt9 1pkA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784240249; x=1784845049; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=1uELeJYYbHg+El5mtXQD5UioQ3wVMOPdr6PSy7q66II=; b=aTMD3oqM4jjBytk7FNlNsAzvAGVJ9EYN6rh7Mj2BMR4OUl2FGrd8YRfd47ps7WRmIv kR/sRb1JfkF0lGNG6aACtgjI2oV46cJuUtsJnv+YVwCZrpl7wW+arA44KUvIODSC5ZQk ZxNxpnPEvUTrbQpYvOTnWCtBOBLojvyzBxTSp9ZkcGQx4aYok+Y/+LYQ07xi3M+LUCZm VLEMzkxigV5l2AiaG3evUgFMj6q95TH4nIxfhFR6HyQTaIJoQu9K5cyEM2Rs7mqvrPc1 wgwPrpFX3woY2g5mo1LjjC2f8SlhPsyhYibb8xbjioQConH3xaYRVM+r7vZVv9MItr8/ l2YA== X-Forwarded-Encrypted: i=1; AHgh+RqRwxLAe51VTpSaJ5HimRcGds6k1+dhvWGd/f/yJ4IZmsRvcDJx0SrUlTG3sNNt0drno42gMds0HSFAfhQ=@vger.kernel.org X-Gm-Message-State: AOJu0YytrAmsYj9SIPpMJxBs6Ei8DSADlmWCGeZ+H7uFr/HIkbcp5h5I HuOvvZnw90Z9QjatjEFmd7+JEO4D1LLpFu6RmskUaSUX6a6fU/KL58GT X-Gm-Gg: AfdE7cleLw3Ac2/Uv2VrjQmq19NFsRj8aYDKk9mUA1piFwyKony5zMumfPs3NQJSvpo G7lgdcbAioboj/uI60wE9tlAMON1YdXaqOnmkXUT76gDT1HvGOJstLT+d/sj4F9uw7/Ao8fTMX3 NH55mLH5LFaeb+T/il6ZrLu4pxIGSJ0iF11/Ug6gqtTUk6CEYUdsI/JaUpZbR3pHlD8TgzzxmoP EKprWOurBEH7Hg9+RQvrqBQ05R6lreGN64I7gGgypkveJwRZclICsiwibbyjQOVqjJHLMnP/fxo aKQlMjbdOY10iw0ba3FKMjTzwWw45eSPrWpelr4YRmi9hDr+NVDHhTjLgeeTuzy0Rc+ues8/sMt A+za/9Mj1oJFoSyx4jXwH5QOJSG2+xaI0kfO90eNcScjfqNBBEclglKJoUn1v0zznuucmft7ijB 4u4qZX49CDX3pqaA== X-Received: by 2002:a5d:64e8:0:b0:460:395c:7404 with SMTP id ffacd0b85a97d-47f5a43ce80mr5745386f8f.20.1784240249185; Thu, 16 Jul 2026 15:17:29 -0700 (PDT) Received: from strix.doe.home ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464c4320sm26192846f8f.32.2026.07.16.15.17.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 15:17:28 -0700 (PDT) From: =?UTF-8?q?Stefan=20D=C3=B6singer?= To: linux-arm-kernel@lists.infradead.org Cc: Michael Turquette , Stephen Boyd , Brian Masney , linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v7 11/13] clk: zte: Introduce a driver for zx297520v3 LSP clocks Date: Fri, 17 Jul 2026 01:17:17 +0300 Message-ID: <20260717-zx29clk-v7-11-50abfa8dd594@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable "LSP" is ZTE's term for this part of the SoC, I suspect it stands for "low speed peripherals". The main UART is here, together with the flash controller and more surplus proprietary timers. It also has one more I2C controller that supposedly connects to a battery charger, SPI for displays and I2S for analog telephones. The boards I have don't have any of these components though. Signed-off-by: Stefan D=C3=B6singer --- Version 7: Underscore in clock names to dashes Version 6: use MFD for LSP too Version 5: Removed unused tdm_lsp_sel. Fix zx297529 vs zx297520 typo. Adjusted .compatible to zte,zx297520v3-lspcrm --- drivers/clk/zte/clk-zx297520v3.c | 189 +++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 189 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c index e08ba9623345..8179c8b80433 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -818,6 +818,191 @@ static const struct zx_clk_data zx297520v3_matrixclk_= data =3D { .num_gates =3D ARRAY_SIZE(zx297520v3_matrix_gates), }; =20 +/* LSP clock entries have a common pattern: Bit 0 for WCLK, Bit 1 for PCLK= . Bit 4 (and sometimes + * more) for WCLK mux. + * + * Bit 8 and 9 are resets handled by the reset-zte-zx297520v3 driver. + * + * Bits 15:12 can be a divisor, but not all clocks have it. Some clocks ha= ve a divisor in 19:16. + * + * The ID given in this table is the first register in the device's MMIO s= pace. ZTE's drivers + * usually call this a version register, but it looks more like a device i= dentifier. + * + * It looks like the registers map to devices like this: + * + * Timer reg function div dev offset(lsp + xxxx) ID + * 0x0: Read-only, probably device identifier 0x00752100 + * 0x4: timer_l1 Y 0x1000 0x02020000 + * 0x8: watchdog_l2 Y 0x2000 0x02020000 + * 0xc: watchdog_l3 Y 0x3000 0x02020000 + * 0x10: pwm N 0x4000 0x01020000 + * 0x14: i2s0 Yh 0x5000 0x01030000 + * 0x18: always 0 - - - + * 0x1c: i2s1 Yh 0x6000 0x01030000 + * 0x20: always 0 - - - + * 0x24: qspi N 0x7000 0x01040000 + * 0x28: uart1 N 0x8000 0x01060000 + * 0x2c: i2c1 N 0x9000 0x01020000 + * 0x30: spi0 Y 0xa000 0x01040000 + * 0x34: timer_lb Y 0xb000 0x02020000 + * 0x38: timer_lc Y 0xc000 0x02020000 + * 0x3c: uart2 N 0xd000 0x01060000 + * 0x40: watchdog_le Y 0xe000 0x02020000 + * 0x44: timer_lf Y 0xf000 0x02020000 + * 0x48: spi1 Y 0x10000 0x01040000 + * 0x4c: timer_l11 Y 0x11000 0x02020000 + * 0x50: tdm Yh 0x12000 0x01040000 + * + * Registers 0x58, 0x5c, 0x60, 0x64, 0x68 seem to contain more controls fo= r i2s and tdm. + * + * I am not sure about the device at offset 0x4000 (clk reg 0x10). The ID = matches that of i2c, but + * it has a larger register set. I suspect it is a PWM device, but I have = not seen any ZTE kernel + * operate it - even devices with displays only use a GPIO to control the = backlight. + */ + +static const char * const timer_lsp_sel[] =3D { + "lsp-osc32k", + "lsp-osc26m", +}; + +static const char * const uart_lsp_sel[] =3D { + "lsp-osc26m", + "lsp-mpll-d6", +}; + +static const char * const i2s_lsp_sel[] =3D { + "lsp-osc26m", + "lsp-dpll-d4", + "lsp-mpll-d6", + /* Unknown */ +}; + +static const char * const spi_lsp_sel[] =3D { + "lsp-osc26m", + "lsp-mpll-d4", + "lsp-mpll-d6", + /* Unknown */ +}; + +static const char * const qspi_lsp_sel[] =3D { + "lsp-osc26m", + "lsp-mpll-d4", + "lsp-mpll-d5", + "lsp-mpll-d6", + "lsp-mpll-d8", + "lsp-mpll-d12", + "lsp-osc26m", + "lsp-osc26m", +}; + +static const struct zx_mux_desc zx297520v3_lsp_muxes[] =3D { + MUX(0, "timer-l1-mux", timer_lsp_sel, 0x= 04, 4, 1), + MUX(0, "wdt-l2-mux", timer_lsp_sel, 0x= 08, 4, 1), + MUX(0, "wdt-l3-mux", timer_lsp_sel, 0x= 0c, 4, 1), + /* PWM: No mux bit can be set */ + MUX(0, "i2s0-mux", i2s_lsp_sel, 0x= 14, 4, 2), + /* 0x18: Always 0 */ + MUX(0, "i2s1-mux", i2s_lsp_sel, 0x= 1c, 4, 2), + /* 0x20: Always 0 */ + MUX(0, "qspi-mux", qspi_lsp_sel, 0x= 24, 4, 3), + MUX(0, "uart1-mux", uart_lsp_sel, 0x= 28, 4, 1), + MUX(0, "i2c1-mux", uart_lsp_sel, 0x= 2c, 4, 1), + MUX(0, "spi0-mux", spi_lsp_sel, 0x= 30, 4, 2), + MUX(0, "timer-lb-mux", timer_lsp_sel, 0x= 34, 4, 1), + MUX(0, "timer-lc-mux", timer_lsp_sel, 0x= 38, 4, 1), + MUX(0, "uart2-mux", uart_lsp_sel, 0x= 3c, 4, 1), + MUX(0, "wdt-le-mux", timer_lsp_sel, 0x= 40, 4, 1), + MUX(0, "timer-lf-mux", timer_lsp_sel, 0x= 44, 4, 1), + MUX(0, "spi1-mux", spi_lsp_sel, 0x= 48, 4, 2), + MUX(0, "timer-l11-mux", timer_lsp_sel, 0x= 4c, 4, 1), + /* TDM: No mux in LSP. Instead, it is in matrix with a separate clk line = to LSP */ +}; + +static const struct zx_div_desc zx297520v3_lsp_dividers[] =3D { + DIV("timer-l1-div", "timer-l1-mux", 0x04, 12, 4), + DIV("wdt-l2-div", "wdt-l2-mux", 0x08, 12, 4), + DIV("wdt-l3-div", "wdt-l3-mux", 0x0c, 12, 4), + /* PWM: No div */ + DIV("i2s0-div", "i2s0-mux", 0x14, 16, 4), + /* 0x18: Always 0 */ + DIV("i2s1-div", "i2s1-mux", 0x1c, 16, 4), + /* 0x20: Always 0 */ + /* qspi, uart1, i2c1: No div */ + DIV("spi0-div", "spi0-mux", 0x30, 12, 4), + DIV("timer-lb-div", "timer-lb-mux", 0x34, 12, 4), + DIV("timer-lc-div", "timer-lc-mux", 0x38, 12, 4), + /* uart2: No div */ + DIV("wdt-le-div", "wdt-le-mux", 0x40, 12, 4), + DIV("timer-lf-div", "timer-lf-mux", 0x44, 12, 4), + DIV("spi1-div", "spi1-mux", 0x48, 12, 4), + DIV("timer-l11-div", "timer-l11-mux", 0x4c, 12, 4), + DIV("tdm-div", "lsp-tdm-wclk", 0x50, 16, 4), +}; + +static const struct zx_gate_desc zx297520v3_lsp_gates[] =3D { + GATE(ZX297520V3_TIMER_L1_WCLK, "timer-l1-wclk", "timer-l1-div", 0x= 04, 0, 0), + GATE(ZX297520V3_TIMER_L1_PCLK, "timer-l1-pclk", "lsp-pclk", 0x= 04, 1, 0), + GATE(ZX297520V3_WDT_L2_WCLK, "wdt-l2-wclk", "wdt-l2-div", 0x= 08, 0, 0), + GATE(ZX297520V3_WDT_L2_PCLK, "wdt-l2-pclk", "lsp-pclk", 0x= 08, 1, 0), + GATE(ZX297520V3_WDT_L3_WCLK, "wdt-l3-wclk", "wdt-l3-div", 0x= 0c, 0, 0), + GATE(ZX297520V3_WDT_L3_PCLK, "wdt-l3-pclk", "lsp-pclk", 0x= 0c, 1, 0), + /* I don't know the LSP parent. It must be one of the LSP inputs though. = */ + GATE(ZX297520V3_PWM_WCLK, "pwm-wclk", "lsp-osc26m", 0x= 10, 0, 0), + GATE(ZX297520V3_PWM_PCLK, "pwm-pclk", "lsp-pclk", 0x= 10, 1, 0), + GATE(ZX297520V3_I2S0_WCLK, "i2s0-wclk", "i2s0-div", 0x= 14, 0, 0), + GATE(ZX297520V3_I2S0_PCLK, "i2s0-pclk", "lsp-pclk", 0x= 14, 1, 0), + /* 0x1c: Always 0 */ + GATE(ZX297520V3_I2S1_WCLK, "i2s1-wclk", "i2s1-div", 0x= 1c, 0, 0), + GATE(ZX297520V3_I2S1_PCLK, "i2s1-pclk", "lsp-pclk", 0x= 1c, 1, 0), + /* 0x20: Always 0 */ + GATE(ZX297520V3_QSPI_WCLK, "qspi-wclk", "qspi-mux", 0x= 24, 0, 0), + GATE(ZX297520V3_QSPI_PCLK, "qspi-pclk", "lsp-pclk", 0x= 24, 1, 0), + GATE(ZX297520V3_UART1_WCLK, "uart1-wclk", "uart1-mux", 0x= 28, 0, 0), + GATE(ZX297520V3_UART1_PCLK, "uart1-pclk", "lsp-pclk", 0x= 28, 1, 0), + GATE(ZX297520V3_I2C1_WCLK, "i2c1-wclk", "i2c1-mux", 0x= 2c, 0, 0), + GATE(ZX297520V3_I2C1_PCLK, "i2c1-pclk", "lsp-pclk", 0x= 2c, 1, 0), + GATE(ZX297520V3_SPI0_WCLK, "spi0-wclk", "spi0-div", 0x= 30, 0, 0), + GATE(ZX297520V3_SPI0_PCLK, "spi0-pclk", "lsp-pclk", 0x= 30, 1, 0), + GATE(ZX297520V3_TIMER_LB_WCLK, "timer-lb-wclk", "timer-lb-div", 0x= 34, 0, 0), + GATE(ZX297520V3_TIMER_LB_PCLK, "timer-lb-pclk", "lsp-pclk", 0x= 34, 1, 0), + GATE(ZX297520V3_TIMER_LC_WCLK, "timer-lc-wclk", "timer-lc-div", 0x= 38, 0, 0), + GATE(ZX297520V3_TIMER_LC_PCLK, "timer-lc-pclk", "lsp-pclk", 0x= 38, 1, 0), + GATE(ZX297520V3_UART2_WCLK, "uart2-wclk", "uart2-mux", 0x= 3c, 0, 0), + GATE(ZX297520V3_UART2_PCLK, "uart2-pclk", "lsp-pclk", 0x= 3c, 1, 0), + GATE(ZX297520V3_WDT_LE_WCLK, "wdt-le-wclk", "wdt-le-div", 0x= 40, 0, 0), + GATE(ZX297520V3_WDT_LE_PCLK, "wdt-le-pclk", "lsp-pclk", 0x= 40, 1, 0), + GATE(ZX297520V3_TIMER_LF_WCLK, "timer-lf-wclk", "timer-lf-div", 0x= 44, 0, 0), + GATE(ZX297520V3_TIMER_LF_PCLK, "timer-lf-pclk", "lsp-pclk", 0x= 44, 1, 0), + GATE(ZX297520V3_SPI1_WCLK, "spi1-wclk", "spi1-div", 0x= 48, 0, 0), + GATE(ZX297520V3_SPI1_PCLK, "spi1-pclk", "lsp-pclk", 0x= 48, 1, 0), + GATE(ZX297520V3_TIMER_L11_WCLK, "timer-l11-wclk", "timer-l11-div", 0x= 4c, 0, 0), + GATE(ZX297520V3_TIMER_L11_PCLK, "timer-l11-pclk", "lsp-pclk", 0x= 4c, 1, 0), + GATE(ZX297520V3_TDM_WCLK, "tdm-wclk", "tdm-div", 0x= 50, 0, 0), + GATE(ZX297520V3_TDM_PCLK, "tdm-pclk", "lsp-pclk", 0x= 50, 1, 0), +}; + +static const char * const zx297520v3_lsp_inputs[] =3D { + "mpll-d5", "mpll-d4", "mpll-d6", "mpll-d8", "mpll-d12", + "osc26m", "osc32k", "tdm-wclk", "dpll-d4" +}; + +static const char * const zx297520v3_lsp_inputs_enable[] =3D { + "pclk" +}; + +static const struct zx_clk_data zx297520v3_lspclk_data =3D { + .inputs_enable =3D zx297520v3_lsp_inputs_enable, + .num_inputs_enable =3D ARRAY_SIZE(zx297520v3_lsp_inputs_enable), + .inputs =3D zx297520v3_lsp_inputs, + .num_inputs =3D ARRAY_SIZE(zx297520v3_lsp_inputs), + .muxes =3D zx297520v3_lsp_muxes, + .num_muxes =3D ARRAY_SIZE(zx297520v3_lsp_muxes), + .divs =3D zx297520v3_lsp_dividers, + .num_divs =3D ARRAY_SIZE(zx297520v3_lsp_dividers), + .gates =3D zx297520v3_lsp_gates, + .num_gates =3D ARRAY_SIZE(zx297520v3_lsp_gates), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id =3D platform_get_device_id(pdev); @@ -838,6 +1023,10 @@ static const struct platform_device_id clk_zx297520v3= _ids[] =3D { .name =3D "zx297520v3-matrixclk", .driver_data =3D (kernel_ulong_t)&zx297520v3_matrixclk_data, }, + { + .name =3D "zx297520v3-lspclk", + .driver_data =3D (kernel_ulong_t)&zx297520v3_lspclk_data, + }, { } }; MODULE_DEVICE_TABLE(platform, clk_zx297520v3_ids); --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF02B27AC48 for ; Thu, 16 Jul 2026 22:00:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239245; cv=none; b=TvdWtbxCvywBKjnvYurhbpKoxfcERIRVHqmjCkyI/KaP7d79yGRGU+AhZBowmKjGa7voS0UqJ6szid1qb5lXjVt15itZJehfyVJdwQ8fZ0QVhIc+ET0+Fd3COfetitrJKkSvkbckkOP0mHnCjp7VPP4Lc5Gn17qqAtCh6rPsI0c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239245; c=relaxed/simple; bh=uEtA4Uw8J249ZPPOwYHnP3sAbtRn6UQUzZ6+nPWJxOI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=CaCRwxjXV4hFeFJc5oIiW5NLhc9sqLNUf5SX4qclcVVpMMLTho6gmbSz9Tqh8l8+i/4WO0D2Dg+7fS/5gnZqxiLs7mBD59U4EwAqNI4jWVDdfeG0sm4xXKricrzKyWO2E4jqsxQfo3911DwaeQAxM+vl8lTvtdYclKKB+TL5w94= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=VKMwqssx; arc=none smtp.client-ip=209.85.221.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="VKMwqssx" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-47d70879764so5051912f8f.2 for ; Thu, 16 Jul 2026 15:00:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784239242; x=1784844042; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=1wJrbglYRemqUxwO5oK2gTXQpFmQhojXd8YMAULYicQ=; b=VKMwqssx6e1U+9eiq3pMgbGInxcVRNe2619qaxTjSoOzc39MYPmy/jDxtX1KrWxevS JL8bD0SDVizJ/NN/dk/LJT4vnm+Xw9NXwNLS63leqeTrxJ9/Y4zoFJesyapJMUpudNwO Fm/DCJ+X5kW0CclaO2QqDy8rKSv/bRMliC8Bcpfk5I7q56wnQca61iyt2B7qDe4MqMPR U7TDt5Md0e1exqsAZTvE8qi2HvOUCP+wFq7kw2w3d6t65yC9NGMebHQzFOg4oeH5BviL Ib/VEMtbNDmA89pzfK8un++zTuMUmyUHgUo4XQNptLo1PDpoHWUrFrJE+LL9kjWGypcC hkiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784239242; x=1784844042; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=1wJrbglYRemqUxwO5oK2gTXQpFmQhojXd8YMAULYicQ=; b=DOqc4OScZ5aeRDIkPzHyxrwZLuZ/aoG+RnnGjknW6YCNfzO4Yy7ONYlcEb/BhflRYx WnDfvSeSBfSBOEhMynaIUWY97IjxaRXurwfnd2zqgNqZNxBz9u8SXqVfL5xZVFfnUxSM VCPGSxF9TtBMSsyaWhgpAjg+sa+xzgFv6IAYlTr5L3UwYzqlocsjLISP/gj8KZxkWalA ZEUkaS0TYAAGMht7SC7YRwU+V9Vo0BGdPzYGmL4AA/Z6E5wJDicKeKKR5gnrXQrJtKHY fVrpYVxNQMSu8HbJzsywDx5zU7w660rFcfkJsWVF9ah1ccJxQ/qj5qprPiPhodU9gyNv 9+Yw== X-Forwarded-Encrypted: i=1; AHgh+RrYX7UwCaCMXVFExIxUKw6nZLpXmaoXivkAUQ87KHGBIHGqk5CwGHXBThh7bY1XbtzzZ4OvpTDdj0rkY8Y=@vger.kernel.org X-Gm-Message-State: AOJu0Yyo1yUVi5kJfVNac5nRyogqbmft42BJTPu9WV8VRS5IE01H/Mru lUaf6OPooLSKZnD+WZZ1MdPfT5GTlHILKlZxkqq21IH5n6edEP0mhVNz X-Gm-Gg: AfdE7ckmauQENPeWcgyqgGtXNhxgGaBsuIg0Uziv0aC8i/H8PJwc2ceREpP9USfiec/ jPc7K2xZqTiyp8oGTxTTZsl0I8NuLHAGtmPNVOfd+viUtrJurv+r4i258AWdna4aYBs0lapzp4R f4Vwbph7V0kbQTramAtpK0MAc3WZ4RzIeUTSzJHrP0pvTEds8C/fRlLEvYbMImUh4gHa8s9J6Zq InVGUzFCAMLIpICZg4j3DYiqvIVPuBu9zA47n94mBywBZx4KtdtxWGZWLn5UtzDQdNXdLs9V9/N C7vEDjw5QC4EPDzVbXN++VfQOQgPWTL2xE0aDAT6IxWZKYkRZqcEaNZnsumvuXKGqC7ZvuAk9eY 7bagDl+XhiiAgfOiOwoLRuO4pztGA2pNBeY38NlrLQvuT3OKbtfjYlpYRF2GgOoc7XK4cybyYwG a8Gu5cnNgoVtKO5A== X-Received: by 2002:a05:600c:37c9:b0:493:bc4a:fb55 with SMTP id 5b1f17b1804b1-4953c28951fmr99048345e9.38.1784239241460; Thu, 16 Jul 2026 15:00:41 -0700 (PDT) Received: from strix.doe.home ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464a974csm29949056f8f.18.2026.07.16.15.00.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 15:00:40 -0700 (PDT) From: =?UTF-8?q?Stefan=20D=C3=B6singer?= To: linux-arm-kernel@lists.infradead.org Cc: Philipp Zabel , linux-kernel@vger.kernel.org Subject: [PATCH v7 12/13] reset: zte: Add a zx297520v3 reset driver Date: Fri, 17 Jul 2026 01:00:10 +0300 Message-ID: <20260717-zx29clk-v7-12-50abfa8dd594@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This drives the MFD child devices created by the zx297520v3-crm driver as well as the aux device created by the zx297520v3-lspclk driver. Reviewed-by: Philipp Zabel Signed-off-by: Stefan D=C3=B6singer --- v7: Add MODULE_DEVICE_TABLE (Philipp) Add DDR control and LSP resets v6: Add a comment wrt checking all bits in .status() (Philipp) include cleanup (Philipp, Sashiko) v5: Make top and matrix MFD children instead of aux devices Split USB PHY reset into its own reset ID Remove USB reset wait code - this will be handled via syscon from a future minimal phy-zx29-usb driver --- MAINTAINERS | 1 + drivers/reset/Kconfig | 10 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-zte-zx297520v3.c | 237 +++++++++++++++++++++++++++++++= ++++ 4 files changed, 249 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index f88a2eda737a..6fbfa21472f0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3885,6 +3885,7 @@ F: Documentation/devicetree/bindings/phy/zte,zx297520= v3-usb-phy.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ F: drivers/clk/zte/ +F: drivers/reset/reset-zte-zx297520v3.c F: drivers/soc/zte/ F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/phy-zte-zx297520v3-usb.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index d009eb0849a3..4dca1f89d22b 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -404,6 +404,16 @@ config RESET_UNIPHIER_GLUE on UniPhier SoCs. Say Y if you want to control reset signals provided by the glue layer. =20 +config RESET_ZTE_ZX297520V3 + tristate "ZTE zx297520v3 Reset Driver" + depends on ZTE_ZX297520V3_CRM || COMPILE_TEST + default SOC_ZX297520V3 + help + This enables the reset controllers for ZTE zx297520v3 SoCs. The reset + controllers are part of the clock and reset management controllers on + this board, so you will also need ZTE_ZX297520V3_CRM. Enable this if + you are building a kernel for a ZTE x297520v3 based board. + config RESET_ZYNQ bool "ZYNQ Reset Driver" if COMPILE_TEST default ARCH_ZYNQ diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 3e52569bd276..9a8a48d44dc4 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -50,5 +50,6 @@ obj-$(CONFIG_RESET_TI_TPS380X) +=3D reset-tps380x.o obj-$(CONFIG_RESET_TN48M_CPLD) +=3D reset-tn48m.o obj-$(CONFIG_RESET_UNIPHIER) +=3D reset-uniphier.o obj-$(CONFIG_RESET_UNIPHIER_GLUE) +=3D reset-uniphier-glue.o +obj-$(CONFIG_RESET_ZTE_ZX297520V3) +=3D reset-zte-zx297520v3.o obj-$(CONFIG_RESET_ZYNQ) +=3D reset-zynq.o obj-$(CONFIG_RESET_ZYNQMP) +=3D reset-zynqmp.o diff --git a/drivers/reset/reset-zte-zx297520v3.c b/drivers/reset/reset-zte= -zx297520v3.c new file mode 100644 index 000000000000..9636530e37bd --- /dev/null +++ b/drivers/reset/reset-zte-zx297520v3.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Most devices on the zx297520v3 SoC have one reset bit per clock line. A= s a rule of thumb, the + * lower bit disconnects the device from the bus, similarly to turning off= PCLK - registers read 0 + * or hang indefinitely. Unlike PCLK, this reset may have a lingering effe= ct after deasserting. + * E.g. timers will be disabled, but retain their counter value. + * + * The other bit resets the actual device registers. + * + * For some devices, e.g. GMAC, both reset bits behave in the same way: Th= ey disconnect the device + * and registers will have their default state after deasserting. For devi= ces that have two reset + * bits, both need to be deasserted for the device to function. + */ +struct zte_reset_reg { + u32 mask; + u16 reg; +}; + +struct zte_reset_data { + const struct zte_reset_reg *resets; + unsigned int num; +}; + +struct zte_reset { + struct reset_controller_dev rcdev; + struct regmap *map; + const struct zte_reset_reg *resets; +}; + +static inline struct zte_reset *to_zte_reset(struct reset_controller_dev *= rcdev) +{ + return container_of(rcdev, struct zte_reset, rcdev); +} + +static int zx29_rst_assert(struct reset_controller_dev *rcdev, unsigned lo= ng id) +{ + struct zte_reset *rst =3D to_zte_reset(rcdev); + + return regmap_clear_bits(rst->map, rst->resets[id].reg, rst->resets[id].m= ask); +} + +static int zx29_rst_deassert(struct reset_controller_dev *rcdev, unsigned = long id) +{ + struct zte_reset *rst =3D to_zte_reset(rcdev); + + return regmap_set_bits(rst->map, rst->resets[id].reg, rst->resets[id].mas= k); +} + +static int zx29_rst_status(struct reset_controller_dev *rcdev, unsigned lo= ng id) +{ + struct zte_reset *rst =3D to_zte_reset(rcdev); + int res; + + /* Devices with two reset bits need both deasserted to work. So only repo= rt them as + * deasserted if both bits are set. + * + * assert()/deassert() will always clear/set both. The only reason a devi= ce might be in a + * hybrid state is an unexpected handover state from the bootloader. + */ + res =3D regmap_test_bits(rst->map, rst->resets[id].reg, rst->resets[id].m= ask); + if (res < 0) + return res; + + return !res; +} + +static const struct reset_control_ops zx29_rst_ops =3D { + .assert =3D zx29_rst_assert, + .deassert =3D zx29_rst_deassert, + .status =3D zx29_rst_status, +}; + +static const struct zte_reset_reg zx297520v3_top_resets[] =3D { + /* This bit is set by ZTE's cpko.ko blob, it looks like a reset bit for t= he LTE DSP + * coprocessor. Clocks for it are in matrixcrm. + */ + [ZX297520V3_ZSP_RESET] =3D { .reg =3D 0x13c, .mask =3D BIT(0) = }, + + [ZX297520V3_UART0_RESET] =3D { .reg =3D 0x78, .mask =3D BIT(6) | BI= T(7) }, + [ZX297520V3_I2C0_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(8) | BI= T(9) }, + /* Only one reset. Bit 5 is settable but does not do anything observable = */ + [ZX297520V3_RTC_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(4) = }, + [ZX297520V3_TIMER_T08_RESET] =3D { .reg =3D 0x78, .mask =3D BIT(4) | BI= T(5) }, + [ZX297520V3_TIMER_T09_RESET] =3D { .reg =3D 0x78, .mask =3D BIT(2) | BI= T(3) }, + /* Only one reset. Bit 0 is settable but does not do anything observable = */ + [ZX297520V3_PMM_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(1) = }, + + /* I haven't found any clocks for GPIO. It probably wouldn't make much + * sense anyway. Only one reset bit per controller. + */ + [ZX297520V3_GPIO_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(3) = }, + [ZX297520V3_GPIO8_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(2) = }, + + [ZX297520V3_TIMER_T12_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(6) | BI= T(7) }, + [ZX297520V3_TIMER_T13_RESET] =3D { .reg =3D 0x7c, .mask =3D BIT(0) | BI= T(1) }, + [ZX297520V3_TIMER_T14_RESET] =3D { .reg =3D 0x7c, .mask =3D BIT(2) | BI= T(3) }, + [ZX297520V3_TIMER_T15_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(10) | BI= T(11) }, + [ZX297520V3_TIMER_T16_RESET] =3D { .reg =3D 0x7c, .mask =3D BIT(4) | BI= T(5) }, + [ZX297520V3_TIMER_T17_RESET] =3D { .reg =3D 0x12c, .mask =3D BIT(0) | BI= T(1) }, + [ZX297520V3_WDT_T18_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(12) | BI= T(13) }, + [ZX297520V3_USIM1_RESET] =3D { .reg =3D 0x74, .mask =3D BIT(14) | BI= T(15) }, + [ZX297520V3_AHB_RESET] =3D { .reg =3D 0x70, .mask =3D BIT(0) | BI= T(1) }, + + /* USB reset. 0x84 returns the USB device status (0x1 for HSIC up, 0x2 fo= r USB up, but + * all 3 bits (PCLK, WCLK, PHY) need to be deasserted for the device to r= eport ready. + * Thus polling the status is the responsibility of the USB PHY driver. + */ + [ZX297520V3_USB_PHY_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(3) = }, + [ZX297520V3_USB_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(4) | BIT= (5) }, + [ZX297520V3_HSIC_PHY_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(0) = }, + [ZX297520V3_HSIC_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(1) | BIT= (2) }, +}; + +static const struct zte_reset_data zx297520v3_topreset_data =3D { + .resets =3D zx297520v3_top_resets, + .num =3D ARRAY_SIZE(zx297520v3_top_resets), +}; + +static const struct zte_reset_reg zx297520v3_matrix_resets[] =3D { + [ZX297520V3_CPU_RESET] =3D { .reg =3D 0x28, .mask =3D BIT(1) = }, + [ZX297520V3_DDR_CTRL_RESET] =3D { .reg =3D 0x100, .mask =3D BIT(10) | BI= T(11) }, + [ZX297520V3_EDCP_RESET] =3D { .reg =3D 0x68, .mask =3D BIT(0) = }, + [ZX297520V3_SD0_RESET] =3D { .reg =3D 0x58, .mask =3D BIT(1) = }, + [ZX297520V3_SD1_RESET] =3D { .reg =3D 0x58, .mask =3D BIT(0) = }, + [ZX297520V3_NAND_RESET] =3D { .reg =3D 0x58, .mask =3D BIT(4) = }, + [ZX297520V3_PDCFG_RESET] =3D { .reg =3D 0x94, .mask =3D BIT(20) = }, + [ZX297520V3_SSC_RESET] =3D { .reg =3D 0x94, .mask =3D BIT(24) = }, + [ZX297520V3_GMAC_RESET] =3D { .reg =3D 0x114, .mask =3D BIT(0) | BI= T(1) }, + [ZX297520V3_VOU_RESET] =3D { .reg =3D 0x16c, .mask =3D BIT(0) = }, + [ZX297520V3_LSP_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(0) = }, +}; + +static const struct zte_reset_data zx297520v3_matrixreset_data =3D { + .resets =3D zx297520v3_matrix_resets, + .num =3D ARRAY_SIZE(zx297520v3_matrix_resets), +}; + +static const struct zte_reset_reg zx297520v3_lsp_resets[] =3D { + [ZX297520V3_TIMER_L1_RESET] =3D { .reg =3D 0x04, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_WDT_L2_RESET] =3D { .reg =3D 0x08, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_WDT_L3_RESET] =3D { .reg =3D 0x0c, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_PWM_RESET] =3D { .reg =3D 0x10, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_I2S0_RESET] =3D { .reg =3D 0x14, .mask =3D BIT(8) | BI= T(9) }, + /* 0x18: Not writeable */ + [ZX297520V3_I2S1_RESET] =3D { .reg =3D 0x1c, .mask =3D BIT(8) | BI= T(9) }, + /* 0x20: Not writeable */ + [ZX297520V3_QSPI_RESET] =3D { .reg =3D 0x24, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_UART1_RESET] =3D { .reg =3D 0x28, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_I2C1_RESET] =3D { .reg =3D 0x2c, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_SPI0_RESET] =3D { .reg =3D 0x30, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_TIMER_LB_RESET] =3D { .reg =3D 0x34, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_TIMER_LC_RESET] =3D { .reg =3D 0x38, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_UART2_RESET] =3D { .reg =3D 0x3c, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_WDT_LE_RESET] =3D { .reg =3D 0x40, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_TIMER_LF_RESET] =3D { .reg =3D 0x44, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_SPI1_RESET] =3D { .reg =3D 0x48, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_TIMER_L11_RESET] =3D { .reg =3D 0x4c, .mask =3D BIT(8) | BI= T(9) }, + [ZX297520V3_TDM_RESET] =3D { .reg =3D 0x50, .mask =3D BIT(8) | BI= T(9) }, +}; + +static const struct zte_reset_data zx297520v3_lspreset_data =3D { + .resets =3D zx297520v3_lsp_resets, + .num =3D ARRAY_SIZE(zx297520v3_lsp_resets), +}; + +static int reset_zx297520v3_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id =3D platform_get_device_id(pdev); + struct device *dev =3D &pdev->dev; + struct device_node *of_node =3D dev->parent->of_node; + const struct zte_reset_data *data; + struct zte_reset *rst; + + if (!id) + return -ENODEV; + data =3D (const struct zte_reset_data *)id->driver_data; + + rst =3D devm_kzalloc(dev, sizeof(*rst), GFP_KERNEL); + if (!rst) + return -ENOMEM; + + rst->resets =3D data->resets; + rst->rcdev.owner =3D THIS_MODULE; + rst->rcdev.nr_resets =3D data->num; + rst->rcdev.ops =3D &zx29_rst_ops; + rst->rcdev.of_node =3D of_node; + rst->rcdev.dev =3D dev; + + rst->map =3D device_node_to_regmap(of_node); + if (IS_ERR(rst->map)) + return dev_err_probe(dev, PTR_ERR(rst->map), "Cannot get parent syscon r= egmap\n"); + + return devm_reset_controller_register(dev, &rst->rcdev); +} + +static const struct platform_device_id reset_zx297520v3_ids[] =3D { + { + .name =3D "zx297520v3-topreset", + .driver_data =3D (kernel_ulong_t)&zx297520v3_topreset_data, + }, + { + .name =3D "zx297520v3-matrixreset", + .driver_data =3D (kernel_ulong_t)&zx297520v3_matrixreset_data, + }, + { + .name =3D "zx297520v3-lspreset", + .driver_data =3D (kernel_ulong_t)&zx297520v3_lspreset_data, + }, + { } +}; +MODULE_DEVICE_TABLE(platform, reset_zx297520v3_ids); + +static struct platform_driver reset_zx297520v3 =3D { + .probe =3D reset_zx297520v3_probe, + .driver =3D { + .name =3D "reset-zx297520v3", + }, + .id_table =3D reset_zx297520v3_ids, +}; +module_platform_driver(reset_zx297520v3); + +MODULE_AUTHOR("Stefan D=C3=B6singer "); +MODULE_DESCRIPTION("ZTE zx297520v3 reset driver"); +MODULE_LICENSE("GPL"); --=20 2.54.0 From nobody Sat Jul 25 06:09:22 2026 Received: from mail-wr1-f54.google.com (mail-wr1-f54.google.com [209.85.221.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C7B637F728 for ; Thu, 16 Jul 2026 22:00:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.54 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239250; cv=none; b=cmQrx/mnH0T/I90qf4qOA1ZMfIPtSzioTCDZbhCvY6UWCCjPHnh/XS1xIzO5C7jGsdpKxJmFPcbv+AJYtiWR3GgqNqNch74Uwn+MrAYm2Ie5bs48YrI6lJZGHXoOn5C7vam/it0zx5yqM2bezm/86V+0ssGN4n1slIFhoAwC6UU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784239250; c=relaxed/simple; bh=jNStNYlUyvLHR0/UDAvVkBhd+bjfRDW4bFuonzzF/i8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=iRyZnQEW1jYvg9uTaAhbTsWFDScjRNGxYSB4ZR+JnA0jqy1+caGiWZApV7mTx+X3P2HsOfklfXHgv/Gn5fUgKnbJ7eEx8CMKMjcyJvDUzrkszP9yBit1RmyZ5lS6nNr8PlF+murRGRuR+AlftgQ2fEP7quEEFlH09XCJ+0XXfC0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eihM2E+0; arc=none smtp.client-ip=209.85.221.54 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eihM2E+0" Received: by mail-wr1-f54.google.com with SMTP id ffacd0b85a97d-476d8e647e9so6581686f8f.0 for ; Thu, 16 Jul 2026 15:00:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784239246; x=1784844046; darn=vger.kernel.org; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to:content-type; bh=WzQRA6RSKwvE9p9fmXPG0emKpd/WfAVetFz3/GIIivk=; b=eihM2E+0vnpdJ9KU3yR1faC3TvRKIKeJc1RUCn/8er/TXDbxyJoIMVenk0T9upHOb5 faA4p092OyaXNM12purrDLs16Vouelnppi467J9udBxP4Jh3+Uz9YEOT596zG3zCass+ UoedfSS45A5niUZ4btp6i4IJtq0FklUNCTHhUElxKAXsBl7Wk4cL8Ya3n20IojGVwtN+ jw0BzARF5wqa/P9HIEi8ooF5umrtcHM5x3nnolf25vMsm1uMYIWIqf2+UGq6emJkIK5n LFnaDzN/41XN2ldRvQvIoLOCIOLu8ChkbxGcysHoAqAU//tuT1B4W0wLQP+40CbmMzl9 0VBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784239246; x=1784844046; h=content-transfer-encoding:content-type:mime-version:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=WzQRA6RSKwvE9p9fmXPG0emKpd/WfAVetFz3/GIIivk=; b=ESQCFEhalS3O102yYOc7Pj3gIBSuMtFLsowmmFAlV269AMxneLE0euGvq0iwxgRxLC iTry1JDt2XKHwtAuEUCX5+tEPqh6gFxaJiaN1/qTMWhyFbZ4DWS8buxAfgg2SVZa0D+c KwTnc5dLWFt+H0DypxJtDjSgm9pIsqFuR+HoemsJVIBBRq4mMnSY46Owc5sVPVdPABkD Y3xcrNX2U9QI1GeLk+cqJgNHSWN8rnauV17jgvuH3znyNwPHHbl6zUMJxYu8YXKbx5zJ 6opEOZ37fpmMuSxDz3mUQXyL/gI4zzT4WfgQa9OgOvl5QfQIsGgzPy7PNCRJaAskMMxB CM1w== X-Forwarded-Encrypted: i=1; AHgh+RqgS2KPPMdB8lUbM4+v9lcCf++zd3ihIsUvW+v/ZeKOzTXLGw0PkcZNoMzU6EUrP8zWDBfyRFucWW1kV/o=@vger.kernel.org X-Gm-Message-State: AOJu0Yzy75/sUiriQWQp/ikgNYiq1NE/djYeuKPi5hzcV4fZGFNThEnV QRAUuBniKSAZwZkCUK/dkhkPD9LuBkyP8rgUHrkFMzVJjBSPUJhzlxEQ X-Gm-Gg: AfdE7clwli8vOlC+unlYVbJ+X1lFKkmWPB89pQlIsaMjTLy0Ug9vJixr6e/QcSXWeLQ mqQ2m/JiSHslHIaWbWlYHER4IbwJ50DArP0Cw++btO8Yu0/ogMhdrKEdl2vkL+6ucD73w9VwR0H DIIMkBwYy6z/MJwgZDRacXOFAXF8Yp5sQ+lOe8kbGYUbCt/mFJQXQb/TCo0ckM9kcUxzd0a3A4Y f9YdWPlfhl8PnqLZFgYTso+Y+mlpH9LVeNvTKeiA943T3doCe/6XOrUOMgLVUIHIIw7pjou6/c7 pw75ivNPBudTLlCrPENFGML1pM1Opap4rZFF8LeDT278lslZcPRjRkrHynagxb9RFS1Jv/wfjRc bpj2mWBMNZ0gSJVh6Taz2BCCdoUa124GGzy0Xw84fa8rGDfvtuLGR3PwwChQamTePIxtQGdyHtu X3Ml4fcNbqRIOSfw== X-Received: by 2002:a05:6000:2084:b0:47e:4379:a4fd with SMTP id ffacd0b85a97d-47f6230e6e8mr3191f8f.19.1784239246369; Thu, 16 Jul 2026 15:00:46 -0700 (PDT) Received: from strix.doe.home ([197.250.51.119]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-47f464a974csm29949056f8f.18.2026.07.16.15.00.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Jul 2026 15:00:45 -0700 (PDT) From: =?UTF-8?q?Stefan=20D=C3=B6singer?= To: linux-arm-kernel@lists.infradead.org Cc: Rob Herring , Krzysztof Kozlowski , Conor Dooley , Linus Walleij , devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v7 13/13] ARM: dts: zte: Declare zx297520v3 CRM device nodes Date: Fri, 17 Jul 2026 01:00:11 +0300 Message-ID: <20260717-zx29clk-v7-13-50abfa8dd594@gmail.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> References: <20260717-zx29clk-v7-0-408411cfcf36@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This makes use of the driver added in the previous patches. It wires up the uart clocks and resets and allows getting rid of the placeholder uartclk node. Signed-off-by: Stefan D=C3=B6singer --- Version 7: Add phy nodes to topcrm Remove syscon from matrixclk again Adapt remove now-removed extra clk inputs from matrix Add reset to LSP osc26m -> clock-26m for the fixed rate clocks, likewise for 32k Version 6: Add syscon to matrixclk Version 5: Re-name from *clk to *crm Add the syscon-reboot node here because the binding requires it Re-add accidentally dropped uart2 IRQ --- arch/arm/boot/dts/zte/zx297520v3.dtsi | 92 +++++++++++++++++++++++++++++++= +--- 1 file changed, 84 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/zte/zx297520v3.dtsi b/arch/arm/boot/dts/zte/= zx297520v3.dtsi index a16c30a164bb..b479d097f004 100644 --- a/arch/arm/boot/dts/zte/zx297520v3.dtsi +++ b/arch/arm/boot/dts/zte/zx297520v3.dtsi @@ -4,6 +4,8 @@ */ =20 #include +#include +#include =20 / { #address-cells =3D <1>; @@ -20,13 +22,16 @@ cpu@0 { }; }; =20 - /* Base bus clock and default for the UART. It will be replaced once a cl= ock driver has - * been added. - */ - uartclk: uartclk-26000000 { - #clock-cells =3D <0>; + osc26m: clock-26m { compatible =3D "fixed-clock"; clock-frequency =3D <26000000>; + #clock-cells =3D <0>; + }; + + osc32k: clock-32k { + compatible =3D "fixed-clock"; + clock-frequency =3D <32768>; + #clock-cells =3D <0>; }; =20 timer { @@ -70,13 +75,82 @@ gic: interrupt-controller@f2000000 { <0xf2040000 0x20000>; }; =20 + topcrm: clock-controller@13b000 { + compatible =3D "zte,zx297520v3-topcrm", "syscon"; + reg =3D <0x0013b000 0x400>; + #address-cells =3D <1>; + #size-cells =3D <0>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + + syscon-reboot { + compatible =3D "syscon-reboot"; + offset =3D <0x0>; + value =3D <0x1>; + mask =3D <0x1>; + }; + + usb-phy@84 { + compatible =3D "zte,zx297520v3-usb-phy"; + reg =3D <0x84>; + interrupts =3D , + , + , + ; + interrupt-names =3D "usb-up", "usb-down", "hsic-up", "hsic-down"; + resets =3D <&topcrm ZX297520V3_USB_PHY_RESET>, + <&topcrm ZX297520V3_HSIC_PHY_RESET>; + reset-names =3D "usb", "hsic"; + #phy-cells =3D <1>; + }; + }; + + matrixcrm: clock-controller@1306000 { + compatible =3D "zte,zx297520v3-matrixcrm"; + reg =3D <0x01306000 0x400>; + clocks =3D <&osc26m>, <&osc32k>, + <&topcrm ZX297520V3_MPLL>, <&topcrm ZX297520V3_MPLL_D5>, + <&topcrm ZX297520V3_DPLL>, <&topcrm ZX297520V3_GPLL>, + <&topcrm ZX297520V3_GPLL_D2>, <&topcrm ZX297520V3_GATED_OSC26M>; + clock-names =3D "osc26m", "osc32k", "mpll", "mpll-d5", "dpll", + "gpll", "gpll-d2", "wclk-osc26m"; + #clock-cells =3D <1>; + #hwlock-cells =3D <1>; + #reset-cells =3D <1>; + }; + + lspcrm: clock-controller@1400000 { + compatible =3D "zte,zx297520v3-lspcrm"; + reg =3D <0x01400000 0x100>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + + clocks =3D <&matrixcrm ZX297520V3_LSP_MPLL_D5_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D4_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D6_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D8_WCLK>, + <&matrixcrm ZX297520V3_LSP_MPLL_D12_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC26M_WCLK>, + <&matrixcrm ZX297520V3_LSP_OSC32K_WCLK>, + <&matrixcrm ZX297520V3_LSP_PCLK>, + <&matrixcrm ZX297520V3_LSP_TDM_WCLK>, + <&matrixcrm ZX297520V3_LSP_DPLL_D4_WCLK>; + clock-names =3D "mpll-d5", "mpll-d4", "mpll-d6", "mpll-d8", "mpll-d12", + "osc26m", "osc32k", "pclk", "tdm-wclk", "dpll-d4"; + resets =3D <&matrixcrm ZX297520V3_LSP_RESET>; + }; + + uart0: serial@131000 { compatible =3D "arm,pl011", "arm,primecell"; arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x00131000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&topcrm ZX297520V3_UART0_WCLK>, <&topcrm ZX297520V3_UART0_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&topcrm ZX297520V3_UART0_RESET>; status =3D "disabled"; }; =20 @@ -85,8 +159,9 @@ uart1: serial@1408000 { arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x01408000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&lspcrm ZX297520V3_UART1_WCLK>, <&lspcrm ZX297520V3_UART1_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspcrm ZX297520V3_UART1_RESET>; status =3D "disabled"; }; =20 @@ -95,8 +170,9 @@ uart2: serial@140d000 { arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x0140d000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&lspcrm ZX297520V3_UART2_WCLK>, <&lspcrm ZX297520V3_UART2_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspcrm ZX297520V3_UART2_RESET>; status =3D "disabled"; }; }; --=20 2.54.0