From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f35.google.com (mail-wr2-f35.google.com [74.125.225.99]) (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 DFB653BB9E1 for ; Sun, 27 Sep 2026 20:13:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540037; cv=none; b=JX1w31JdE6JhWJFxphia6ThlfUKtE11QX82fp01pQ2eYUvZybm5AJ8s9IqvB4q2w8r8wuWqEfvk/jHfBNaTcs0p+ymnsQCvfeF0G1tOSVUEQvwmbYAAsxDfFcGNLtbgvXEV8K9sFOeSdFY8F0a3K718gjBwJGgtJLFx4/3A4miU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540037; c=relaxed/simple; bh=fdcRqBAFZcfoRi9cgcm3iz61drb6ZrGz34PHxhWAGSA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=W6gcxC4PKAVxNCOmDgFL6c3aPHuUY/xuWJFHLjkFPhJ6XrWbIGAcDbogwViTV7Q6157hsAyPddwYe8dBq3/ST3PQkJ+UlIGs/Iqd22gaXQttjvaK6nC2Yab4AFYSy3BLBDLW7lDlsTT2+UAjbdNsBTLN206SKEW0ETaTDlTn9FM= 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=Pb0YMBUn; arc=none smtp.client-ip=74.125.225.99 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="Pb0YMBUn" Received: by mail-wr2-f35.google.com with SMTP id ffacd0b85a97d-4887f6cf16bso1394532f8f.0 for ; Sun, 27 Sep 2026 13:13:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540033; x=1791144833; 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=u2l9hURmB1pkMb9PWrVWHcGWccs9x7IzxI7WG3HtlDU=; b=Pb0YMBUnC+XweZhPvc1p7Niswp03rna3/F7YLvVFLFSuuwSq55YopvyONeZ84KR71E EQQkk+XpVjXvR2AWjXsquQqgi1StIMYU+mwgKGe0hIMkpWoLhdScikPMNZUq/7852vds PTWGLMUthGU5OabSpgGtdm/iZBYjMhXT0W1Gpw4x79AKLH9WhW/3zwaJyZN9iTsgWVxl HiUzfXmlZiNrmT7MQGDX4coYFjCaDavfHTlOcuSFgq78kNmXin8DfQ0TMY0KDKnilPpJ KL1aA/g3KRh0mAVILvy0QEFkXuR5es42vbcuQI63XGHVAh8sm3E3VMssU0bFi0ztTOMb 9jTg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540033; x=1791144833; 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=u2l9hURmB1pkMb9PWrVWHcGWccs9x7IzxI7WG3HtlDU=; b=lyLgdAxsl++naXOBRVDJbzgHapfdz1EU5BuawmZWhyRaFr6/VLGUtk54ls14Dfc3th jFofp46bsWe4Lmy4jPN8oyAqPPQ3qe0jcqleCY9H9Zg/oQW3NpndmIaUKE9a1U/NpEMd dAxm+JSj7eIuVWN/J5KDjX6K/8fuWn7c6Ec0Gc7BeRqwtr/Ue29Oy7ePlZAzN0+Tc4Hh Vyw+1Eb0Yp4fWqN9YaM+zovMaHXjh6Nt+M5lAGO0Ka8H+xebI3TJV1u5E8XimIA9yI24 3e1FmqJsA0Uc+hnIV97zhhJTR7FBTWyHr0mbm5zavf1VfsGM0C/BEKZpi2+SGN5Sp4cu Wb3A== X-Forwarded-Encrypted: i=1; AKwUvBzVoEaGL9sYPPge1A8EiqVLH6St7yyIN7xfBAlLD8pMgMe61a0g2vSgWYRSumGjLegTs/qEcrqUbV5yxPM=@vger.kernel.org X-Gm-Message-State: AFq9FYJ1oq0GNrMSn8DLOztXVc1rVHzh49NmrpXdiDWTkHL3nFyAT+D6 5QHK+d/wZp+qToYbQ86ZO2iMAT8JWo7xlwNJgR6CEoMieB9VXpRzyjnT X-Gm-Gg: AYBFou2+hdJaECzfRh8vGoBKwiinGrOnl8hhMe+Q10iWl54U/Ybx4BjR1d+suwwQfO1 g7CeaMIiQS2RIhrhFKNDhW+dnmWLpKAZgPm6hfYWqYOy3rko2ZkQyY06/mNvEfpgptAB3Itvtz7 y0SZq1kG6NnJInFQyORNjoFxw51xMNb/gebv4ygN/tu05n7DQXC5xuGeKrqkbZrEHfUN2e4b4GD gr6UTdPMo+4DJ/RF1/+FjrbxQP3r7JGFDauwrsUxTvgR/e9EkSv0rYkegAPvZQpjt5Wxr7Ec3lH t9vsb0SjrGp5rsbuRWn0kxeLM4WQuPABhFGKpJIgHLjNRKFu9hF5jUpYorAxciAdsAHfpLlFxOx LhqgpLIUMzGlE63q7DQ/v2EJaBOz4AucfF7kouQBzCtIYrzknj/smkr8caD/lY23+YDgczFJZ/5 GbYd2HbZjOJWhI8H9gVQx6g9C+p5VoDFpRlkfYV+yenEFvJGpq5KXu+vYWmkFHZVb+DDXMel5+6 roz9I3u X-Received: by 2002:a05:6000:288b:b0:488:6523:e15c with SMTP id ffacd0b85a97d-4887db2d079mr14668813f8f.32.1790540032951; Sun, 27 Sep 2026 13:13:52 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.13.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:13:52 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:29 +0300 Subject: [PATCH v13 01/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: <20260927-zx29clk-v13-1-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= , Krzysztof Kozlowski X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=16292; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=fdcRqBAFZcfoRi9cgcm3iz61drb6ZrGz34PHxhWAGSA=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj0Ls8uX3B17PE32AB6j+mpQEb/c79+M9Wv+ E20KXTdjFSJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49BsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKmpg/7BQuS+kFxC6DUPLluHrLVsPzTsJJdG39 B6RtZzkuT2SHn7q8PIvx8J/cWSu2jk0fGLbyvNtbq/79OU0X0D/hWpsVb5lDNafpkjrgJEeYV9O OOTMXNgioq5xOvtEl56IY9R415sB5lZ4mlgF3AHchwgHFs5sQCvJ2+UIjFMXRc+JNB8pUjjYf0V 1L5vJMVT34jXuaOl5YDmUIvVKt8eBFBCY0auAfNqfgZyUbxvUfArv7XUgCOBNLarZ1lvvRDB7gS +qmN7RpZ4wpyaMLtDQnAI+Xn4hn057LE39bK6zTInQcfR3axilp+35CkUjxLSqCNlhEaqZVc2Kw bUG3F1Imd3w36K+tqJA+EtTFel9vghgOrzuYtuNfbXCFvY0URg0MWp3o0DVlQ91/zZy8wYcz+9L pXLffegGv95kY5NB/xKACPY5va/yus7hboPv5kmAqaJpZmWyiWnfJSpwi94kHZNdbAfwxrzgxTB H+CBBWLZ4eEnvYY5ArtNVA7LRam4hKhtndXwYwqs7IpEaAFYJegYfF5X0q6YHr5anjzAUg+VXqj n/BVe/4dvTj5/+qD1u73c2FlSEQna6bLjKihKYwgwjFBWJyRvj8JbcZ9t7roRrHw+U/34Tvb0Jq VUo+4z1DUKrMSqqamp8RusCwomN8qUdK7Dan/xUid1zJ1mMe70LI= 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 26 MHz 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. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan D=C3=B6singer --- v12: Add some GSM and LTE related clocks v11: Unchanged content wise @Sashiko: The USB and HSIC PHY resets are deliberately not in the binding. They would be provided by the reset MFD child and consumed by its PHY sibling, resulting in a self-referencing node. Therefore the PHY MFD child accesses the bits via the shared regmap. The PHY driver is the exclusive owner of the bits. This does not impact the USB and HSIC controller resets. These are part of the binding and consumed by the (future) USB nodes. @Sashiko: There is no "simple-mfd" compatible because a MFD driver will bind to the node and (among other things) take care of the reboot child node. v9->v10: *) Rename ZX297520V3_ZSP_RESET to ZX297520V3_ZSP_CORE_RESET in preparation for a separate reset register in matrixcrm. *) Fix order of properties in the example code to satisfy dt-check-style --mode=3Dstrict. Changes v8->v9: *) "unevaluatedProperties: false" for the syscon child node (Krzysztof) *) "additionalProperties: false" for the binding itself (Krzysztof) *) Remove USB PHY resets, but USB controller resets remain unchanged (Krzysztof) *) Rename syscon reboot node to "reboot". While both "reboot" and "syscon-reboot" are common in actual device trees, syscon-reboot.yaml's own example uses "reboot". DT's Generic Names Recommendation contains neither (Sashiko, patch 12) Changes v7->v8 (all Krzysztof): *) Fold the PHY into the top-level node *) Start clock indices at 0 *) Rename the phy include file to zte,zx297520v3-topcrm.h. And a non-change despite/because of new discoveries: USB has more PHY and DWC controls in a different controller at 0x140000. ZTE calls this controller SOC_SYS, and it is a textbook case for syscon: It has a lot of different controls: A remap flag for boot ROM, a control to bring the A53 up in arm32 vs aarch64 mode, the entrypoint of the LTE DSP, SDIO, I2S, ... USB-wise it has a register with PHY and DWC controls: Endianness for the DWC2 registers, PHY clock adjustments, PHY and DWC host/device switch. In spite of this I think topcrm is the better home for #phy-cells: The USB ready flags in topcrm are essential for bringing up the USB devices whereas the soc_sys controls are a curiosity. Host mode only works if I externally inject VBUS. Clock adjustment is too inflexible to be of real value. Flipping the DWC registers to big endian works, but what for? If I find a use case for changing the default USB values in soc_sys it can be handled via syscon. soc_sys also has power controls for a few devices, including USB. This will be handled via #power-domain-cells. The self-referencing reset property causes the following boot messages: /soc/clock-controller@13b000: Fixed dependency cycle(s) with /soc/clock-controller@13b000 /soc/clock-controller@13b000: Fixed dependency cycle(s) with /soc/clock-controller@13b000 Do I need to add post-init-providers? As far as I understand it, this message is informational and not a problem that needs to be addressed. Changes v6->v7: *) Moved the bindings back into clock/ (Krzysztof). Use clock-controller@ in example and in the later DTSI patch. *) With a 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 | 122 +++++++++++++++++= ++++ MAINTAINERS | 4 + include/dt-bindings/clock/zte,zx297520v3-clk.h | 72 ++++++++++++ include/dt-bindings/phy/zte,zx297520v3-topcrm.h | 12 ++ include/dt-bindings/reset/zte,zx297520v3-reset.h | 30 +++++ 5 files changed, 240 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..8510ffde2924 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml @@ -0,0 +1,122 @@ +# 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 is exposed as two PHYs, one for USB and another for HSIC. No= te + that while the controls for both PHYs are always present, the PHYs thems= elves + may be absent. If this is the case the controller never signals that the + missing PHY is ready. + + 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= . PHY + defines are found in "include/dt-bindings/phy/zte,zx297520v3-topcrm.h". + +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 + + 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 + + "#clock-cells": + const: 1 + + "#phy-cells": + const: 1 + + "#reset-cells": + const: 1 + + reboot: + type: object + $ref: /schemas/power/reset/syscon-reboot.yaml# + unevaluatedProperties: false + description: + Reboot method for the SoC. + +required: + - compatible + - reg + - clocks + - clock-names + - interrupts + - interrupt-names + - reboot + - "#clock-cells" + - "#phy-cells" + - "#reset-cells" + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + clock-controller@13b000 { + compatible =3D "zte,zx297520v3-topcrm", "syscon"; + reg =3D <0x0013b000 0x400>; + #clock-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + interrupts =3D , + , + , + ; + interrupt-names =3D "usb-up", "usb-down", "hsic-up", "hsic-down"; + #phy-cells =3D <1>; + #reset-cells =3D <1>; + + reboot { + compatible =3D "syscon-reboot"; + mask =3D <0x1>; + offset =3D <0x0>; + value =3D <0x1>; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index dccddc99ac9a..43fd556e155b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3922,8 +3922,12 @@ 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/clock/zte,zx297520v3-topcrm.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/zte,zx297520v3-topcrm.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..1bc9267e4d62 --- /dev/null +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -0,0 +1,72 @@ +/* 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 0 +#define ZX297520V3_SRAM1_PCLK 1 +#define ZX297520V3_SRAM2_PCLK 2 +#define ZX297520V3_UART0_WCLK 3 +#define ZX297520V3_UART0_PCLK 4 +#define ZX297520V3_I2C0_WCLK 5 +#define ZX297520V3_I2C0_PCLK 6 +#define ZX297520V3_RTC_WCLK 7 +#define ZX297520V3_RTC_PCLK 8 +#define ZX297520V3_LPM_GSM_WCLK 9 +#define ZX297520V3_LPM_GSM_PCLK 10 +#define ZX297520V3_LPM_LTE_WCLK 11 +#define ZX297520V3_LPM_LTE_PCLK 12 +#define ZX297520V3_LPM_TD_WCLK 13 +#define ZX297520V3_LPM_TD_PCLK 14 +#define ZX297520V3_LPM_W_WCLK 15 +#define ZX297520V3_LPM_W_PCLK 16 +#define ZX297520V3_TIMER_T08_WCLK 17 +#define ZX297520V3_TIMER_T08_PCLK 18 +#define ZX297520V3_TIMER_T09_WCLK 19 +#define ZX297520V3_TIMER_T09_PCLK 20 +#define ZX297520V3_MPLL 21 +#define ZX297520V3_MPLL_D5 22 +#define ZX297520V3_DPLL 23 +#define ZX297520V3_GPLL 24 +#define ZX297520V3_GPLL_D2 25 +#define ZX297520V3_GATED_OSC26M 26 +#define ZX297520V3_PMM_WCLK 27 +#define ZX297520V3_PMM_PCLK 28 +#define ZX297520V3_OUT0_WCLK 29 +#define ZX297520V3_OUT1_WCLK 30 +#define ZX297520V3_OUT2_WCLK 31 +#define ZX297520V3_OUT32K_WCLK 32 +#define ZX297520V3_RMIIPHY_WCLK 33 +#define ZX297520V3_TIMER_T12_WCLK 34 +#define ZX297520V3_TIMER_T12_PCLK 35 +#define ZX297520V3_TIMER_T13_WCLK 36 +#define ZX297520V3_TIMER_T13_PCLK 37 +#define ZX297520V3_TIMER_T14_WCLK 38 +#define ZX297520V3_TIMER_T14_PCLK 39 +#define ZX297520V3_TIMER_T15_WCLK 40 +#define ZX297520V3_TIMER_T15_PCLK 41 +#define ZX297520V3_TIMER_T16_WCLK 42 +#define ZX297520V3_TIMER_T16_PCLK 43 +#define ZX297520V3_TIMER_T17_WCLK 44 +#define ZX297520V3_TIMER_T17_PCLK 45 +#define ZX297520V3_WDT_T18_WCLK 46 +#define ZX297520V3_WDT_T18_PCLK 47 +#define ZX297520V3_USIM1_WCLK 48 +#define ZX297520V3_USIM1_PCLK 49 +#define ZX297520V3_AHB_WCLK 50 +#define ZX297520V3_AHB_PCLK 51 +#define ZX297520V3_USB_WCLK 52 +#define ZX297520V3_USB_PCLK 53 +#define ZX297520V3_HSIC_WCLK 54 +#define ZX297520V3_HSIC_PCLK 55 +#define ZX297520V3_GSM_32K 56 +#define ZX297520V3_GSM_26M 57 +#define ZX297520V3_GSM_48M 58 +#define ZX297520V3_GSM_104M 59 +#define ZX297520V3_GSM_156M 60 +#define ZX297520V3_ABB_WCLK 61 + +#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ diff --git a/include/dt-bindings/phy/zte,zx297520v3-topcrm.h b/include/dt-b= indings/phy/zte,zx297520v3-topcrm.h new file mode 100644 index 000000000000..b36ccf2f54ef --- /dev/null +++ b/include/dt-bindings/phy/zte,zx297520v3-topcrm.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_ZTE_ZX297520V3_TOPCRM_H +#define __DT_BINDINGS_PHY_ZTE_ZX297520V3_TOPCRM_H + +#define ZX297520V3_USB_PHY 0 +#define ZX297520V3_HSIC_PHY 1 + +#endif /* __DT_BINDINGS_PHY_ZTE_ZX297520V3_TOPCRM_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..4a0eaec0e981 --- /dev/null +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -0,0 +1,30 @@ +/* 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_CORE_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_RESET 18 +#define ZX297520V3_HSIC_RESET 19 + +#endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (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 D786A353A7E for ; Sun, 27 Sep 2026 20:51:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790542268; cv=none; b=h9ufjwJMsUgjDoS4fsbOkzYfnkOg9H1NN6PumayClONjxf08VC3IfVsVhu3vKMS6NIuK8gKTTSpuuO3MFtmu36zy48UeerfYovkZXoevNtbccN1jHiw2ccEFqqjegpnKeL3G0UcF1ciDbwWWSSMaOtRTYgT0O+2fgjKO4Fgl2sE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790542268; c=relaxed/simple; bh=QvrCBO1Yv1uu9lB4VC3C33kwTXsj8pF49PIlS0v8lsA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=hFvoSvMVHMyt5tXuLYFrJgA4aiZ2PnVwoAMthHE4kPxLGhehdG2Z2pTbVyIoOM1H5beAR7zYqM7RRe5k+L5WXjwiz15vYqEz6yad144NZqi3oN41UCvZCp1g0uHJmcpapanO3ZryoxURolC0dUaUmOEa7/X3a0bt+ZaVcGPeIVs= 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=GdpMKsWw; arc=none smtp.client-ip=74.125.225.140 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="GdpMKsWw" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49b912d391aso17015475e9.2 for ; Sun, 27 Sep 2026 13:51:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790542264; x=1791147064; 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=kUYGyZPkzisCXjd18YS32E0k2NnfBv/Du6efJgbaS1U=; b=GdpMKsWwoTXEdLD/KME8c7CpTXZnCRueAPj7HXQKiKAx86mhfi6CI/f2KBaAI1rqJR UqMTL5EIFtuf64ODKnD7jVQKDYrHntS3KZ5ASyIcqGLYiX69FWTVRRKn6H+XEw7Zr+uZ xlLF3+fy/CV7WlliaQ3AG/+Ab4ysQpniQaFVYdTczFjT5rehj2Vo20ytXmNg1QCpAtUq 5sZIXdMY+//58owsA4tTSrAqF6mSRnwZJ0KTUdH2frAkRrBzYWBqDYoCHa0oHNzRpwh1 Qv9J15pfen+lDETKVSav4Qvgf8aIFBjPwlphRtazUhOZA1Kjjzsj6s3/HmwV0IEuzkGH DgHg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790542264; x=1791147064; 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=kUYGyZPkzisCXjd18YS32E0k2NnfBv/Du6efJgbaS1U=; b=CA9Y4RHs49kC0lDdqrVGR8UCNWzcFfi1E5hQmtqG2N6ETQTcK5tRRLDc/WETrLZB7l k0rIOp1HBhp1lli4ZDIIqUPNNo1VHaDr4+qS09BKYxZ1rasN5O+y1njM6kTwPcCHMZCI GajP2URIpJbeVTYE5qqyntv1ddAcKhP9nhob57Svgu18bJJI+kVUMFd9EGLgtQcQEBdX DNgWlKEnaaHjLcYmu1LKfY670jK38qDfZMu3uNjclt97L1g+P+npUAFIPs9366/9WIDj Tljo/HqfbKOq3je1Bmb+d0gxongex5eGPsrL17dxk2z0/n7I4IuvBarn0C1/j/8w/oVC Gltg== X-Forwarded-Encrypted: i=1; AKwUvBwSfzOMitprIpVlnUymeOzk3Umlsu4rDjO+rzmuDWMggUrjCDh7tJ5JyxDjt+REapgRnZfwgmHrbeh/V80=@vger.kernel.org X-Gm-Message-State: AFuF++kWs3iWCJxUf7UhhMxRr/g2Es/F0sN6G0SM/6Mrg379pNG+NvG2 0TIn55WJn4gkqbMvHwZOCeeE1hLOO36FTOkd/99iBzlvPcbMtG4g6Ls9 X-Gm-Gg: AYBFou3mRpdJI+1KYJJPTfjCERYkLi/wTS/iL/lWayzEQWeNayhjVEgcVtWxWm2DJ2q Ln8h8PXrp2UoWtMxHVTlxpDpJRH2sKC7XDRxH6RPcrrYXbHTgdz7hhHkZgdaAPLs3J0cbMsaBr8 xDkJFTAuVGFFEHFipgI9c/MXKqkl6KOHSTf70uP0YXb9GflX1ARvMF+PoEZgSLYmg6Z5HKxkVQZ enBgpGwd3JNijsmGgujGqC3R3lVMf9Zij5w157Cr/XOvXJ3hE6Md6UJMdNNy9DSwJoPkv22F+Jw 713JaQAxEtri+5MylQiYMzmBbzjD/IAwho1B1L00l+xaFu/1ziH8ZFM5vbDAimNXRWHJ/guq56G 91pGMDzqr7f4PaYooPXznMt/0VPrANXXNNcQyZnaBfitRURY9IfntPaIvqG0PKc3VxFSVWy2hLl JYOoDrNu/WYA2q91YVmXgzp6cUTuUw0G5IjLLmQQD+bFNjVgutpF4YwRqnJGnvUXcWIcIiYtc5/ 2WNXuE= X-Received: by 2002:a05:600c:4754:b0:49c:c96a:d36b with SMTP id 5b1f17b1804b1-49fe66d1663mr204967735e9.12.1790542263869; Sun, 27 Sep 2026 13:51:03 -0700 (PDT) Received: from strix.doe.home ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4a0018e6ba2sm88613255e9.5.2026.09.27.13.50.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:51:03 -0700 (PDT) From: =?UTF-8?q?Stefan=20D=C3=B6singer?= To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, Krzysztof Kozlowski Subject: [PATCH v13 02/13] dt-bindings: clk: zte: Add zx297520v3 matrix clock and reset controller Date: Sun, 27 Sep 2026 23:50:55 +0300 Message-ID: <20260927205055.185366-1-stefandoesinger@gmail.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@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 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. The zte-zx297520v3-crm driver will instantiate separate MFD children for clocks and resets, which are handled by separate clock and reset drivers. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan D=C3=B6singer --- v11->v12: Add RFFE clock. It belongs to the SSC device (ZTE's name, not mine) and together they are used to set up radio hardware. Also add LTE_MODEM clocks: I defined them in the driver in version 10 already but forgot to export them. (No, I don't know what this LTE_MODEM device does. The LTE modem firmware uses it. I found that the pclk gates mmio address space 0xf8000000-0xf8300000 and 0xfc000000-0xfc220000 and that this area is only accessible to M0 and ZSP. v9->v10: Add ZSP PCLK and ZSP bus reset. I don't know the exact difference between the ZSP reset in topcrm+0x13c and the one in matrixcrm+0x3c. Core state vs axi connection is my best guess. Both need to be deasserted for the ZSP to work. Fix order of clock-cells in example code. v8->v9: *) The SDIO controllers and GMAC depend on topcrm's ahb clock for register access / dma operation. Add the input to the binding. v7->v8: *) Start clock indices at 0 *) Fix indentation *) Add a prose note about discovered registers that allow writing CNTVAL. I am not exposing them in any way because for now I see no need to use this functionality. It is possible that the counter resets to 0 during standby, which means someone needs to fix it up using those registers. Nevertheless, no syscon yet for these reasons: I have no idea how CNTVAL behaves during standby. It might be just fine. Standby very likely needs firmware handling running on the Cortex M0, which can restore CNTVAL if necessary. If Linux needs to do it, it can probably be done by the clock or MFD parent driver. Given what I've learned so far I'd rather add syscon later than put it in place without a clear user. Details of how to manipulate CNTVAL will be in the matrix clk driver. *) A non-change in the binding text, but worth mentioning: Register 0x118 contains gates that gate off matrix-synthesized PLL fixed dividers. They reinforce the understanding of the top->matrix interface and the adequacy of the bindings. 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. --- .../clock/zte,zx297520v3-matrixcrm.yaml | 98 +++++++++++++++++++ MAINTAINERS | 1 + .../dt-bindings/clock/zte,zx297520v3-clk.h | 45 +++++++++ .../dt-bindings/reset/zte,zx297520v3-reset.h | 13 +++ 4 files changed, 157 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/zte,zx297520v3-= matrixcrm.yaml 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..5e9506db7365 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-matrixcrm.yaml @@ -0,0 +1,98 @@ +# 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. + + An additional curiosity are registers that allow setting (but not readin= g) the + ARM architected timer's CNTVAL. This is not exposed in the binding becau= se + there shouldn't be a need to access it. + + 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: AHB clock from topcrm + - 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: ahb + - 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>; + #clock-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>, <&topcrm ZX297520V3_AHB_PCLK>, + <&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", "ahb", "mpll", "mpll-d5", "dpl= l", + "gpll", "gpll-d2", "wclk-osc26m"; + #hwlock-cells =3D <1>; + #reset-cells =3D <1>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 43fd556e155b..5f367b5126c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3922,6 +3922,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: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bi= ndings/clock/zte,zx297520v3-clk.h index 1bc9267e4d62..d98bc38635b0 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -69,4 +69,49 @@ #define ZX297520V3_GSM_156M 60 #define ZX297520V3_ABB_WCLK 61 =20 +#define ZX297520V3_SYS_TIMER_WCLK 0 +#define ZX297520V3_CPU_WCLK 1 +#define ZX297520V3_CPU_PCLK 2 +#define ZX297520V3_ZSP_WCLK 3 +#define ZX297520V3_ZSP_PCLK 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_RFFE_WCLK 21 +#define ZX297520V3_SSC_WCLK 22 +#define ZX297520V3_SSC_PCLK 23 +#define ZX297520V3_AXI_WCLK 24 +#define ZX297520V3_GMAC_WCLK 25 +#define ZX297520V3_GMAC_PCLK 26 +#define ZX297520V3_GMAC_AHB 27 +#define ZX297520V3_VOU_WCLK 28 +#define ZX297520V3_VOU_PCLK 29 +#define ZX297520V3_LSP_MPLL_D5_WCLK 30 +#define ZX297520V3_LSP_MPLL_D4_WCLK 31 +#define ZX297520V3_LSP_MPLL_D6_WCLK 32 +#define ZX297520V3_LSP_MPLL_D8_WCLK 33 +#define ZX297520V3_LSP_MPLL_D12_WCLK 34 +#define ZX297520V3_LSP_OSC26M_WCLK 35 +#define ZX297520V3_LSP_OSC32K_WCLK 36 +#define ZX297520V3_LSP_PCLK 37 +#define ZX297520V3_LSP_TDM_WCLK 38 +#define ZX297520V3_LSP_DPLL_D4_WCLK 39 +#define ZX297520V3_SRAM0_PCLK 40 +#define ZX297520V3_GSM_CFG_PCLK 41 +#define ZX297520V3_LTE_MODEM_WCLK 42 +#define ZX297520V3_LTE_MODEM_PCLK 43 + #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 4a0eaec0e981..54e5b24f859a 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -27,4 +27,17 @@ #define ZX297520V3_USB_RESET 18 #define ZX297520V3_HSIC_RESET 19 =20 +#define ZX297520V3_CPU_RESET 0 +#define ZX297520V3_ZSP_BUS_RESET 1 +#define ZX297520V3_DDR_CTRL_RESET 2 +#define ZX297520V3_EDCP_RESET 3 +#define ZX297520V3_SD0_RESET 4 +#define ZX297520V3_SD1_RESET 5 +#define ZX297520V3_NAND_RESET 6 +#define ZX297520V3_PDCFG_RESET 7 +#define ZX297520V3_SSC_RESET 8 +#define ZX297520V3_GMAC_RESET 9 +#define ZX297520V3_VOU_RESET 10 +#define ZX297520V3_LSP_RESET 11 + #endif /* __DT_BINDINGS_RESET_ZX297520V3_H */ --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f35.google.com (mail-wr2-f35.google.com [74.125.225.99]) (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 6760F3B9608 for ; Sun, 27 Sep 2026 20:14:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540049; cv=none; b=I6aR3gLFbyW0SSJytsA77F8FcHWqZKchNVcVLc/k5RbqFWRIbit7yZtjx+xy60Dlo6dRE+xZqOEzwqWGg0wye91p8oEgCauRmaSM0dqX8lLg4E/fkDklxWQbjkhrq73j3WA8UK2zG4i5y/fA8spDHnLDveW3AEXW2TMwofqcMQE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540049; c=relaxed/simple; bh=ZZeixT33K508YXS7awOOMQnGZZ8sVeeN1ZslFQ+5hXQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IJkiW6o4OTtOA2YBjFLHgOagAwbxm2vI9qSYjClioMChnAYXeP1gvSc24yJY1vFaUc/RmbrzYgo/XS14fbmqIRWXRev+I2wau90rMaz0q0RAMbPJmRAfR0S73g5Jkg39491HZW6Cz2tL0qH5ELjs8WqLOzA+ID/qnNZr5aXRcoE= 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=YAyiPsdG; arc=none smtp.client-ip=74.125.225.99 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="YAyiPsdG" Received: by mail-wr2-f35.google.com with SMTP id ffacd0b85a97d-4887f690df6so1586903f8f.1 for ; Sun, 27 Sep 2026 13:14:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540045; x=1791144845; 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=wH2Srjp6f0lUrhziOVxnEld1W9GBJurx25pR0jmeLW4=; b=YAyiPsdGgYlKPGBcGGM3Q2ak8kBBZd/bbNrRDzV8sGTB9q0PzI4wzQ9/Z4jiAS6uM7 GmwzLp3l5OWire1rd+CLQsavaUmHfxXXgEWm453w5u9chvS14aO7RYoKcOXNKagGHb+Q AeEoLAQNEtxGfg8sh4d1un22I3fvoJDmhtncm2fTCBbWTA9qwfTKv98iIoDaCm7cV7UR OrEIoLzM1eUpojjsbNDZt8UQXZTq88XNmuj2sn0rrVGTuxf44fQVDw5vfUwKpjpdxgdl OUJDifVPnS857gA46SD9JBGsF04FzayyDvuil13zBP8aXPUcW9HWmgKbvdC1eExPyRDD POcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540045; x=1791144845; 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=wH2Srjp6f0lUrhziOVxnEld1W9GBJurx25pR0jmeLW4=; b=hZlXmBnYYnLbYwM3V9poMex879Xsm5vLEKleywCLJS3Zijskhf6MfOMVDFhPXHHV3d bKJ0e5IxhWJNY2dLHUwUygNSoK6AZHYgTrl5Sk0eI6aZtkXbhkPYJ8SCuM4GskAbCEX9 ItdBn4f3JJlXUH/zyg0B7dBGnurlChLDp3NyE/NzjW32dmvUO8IgTZfoGSijkf82ZUIw 6TFISdsI1ZzjpnWlNMFsS+NcNWO9mU87cFYVCEfQ0KlCnJPDR2tSkOEY+73pROofJr1n qQux6s0y/nPMOz7crdtJXTuSQReoOlTQntUCVDSe4jwjhLdcRcUJYqlshNgjYgnMkjNY wxOA== X-Forwarded-Encrypted: i=1; AKwUvBzTP8HGa9kjB9u4+IZGZ5lwMsB8domoS1EWgyPDl62rRoU/15DUZlJHUnE9HnSIoaUWL6l1fGd18R9qTWE=@vger.kernel.org X-Gm-Message-State: AFq9FYLTKSO+HL+MRNbbeYHr4bcrEZbtry8FBs6ksRqm6pORf3AcMyfq rL5bmEo7tpTBeAVZ6HoWIBy0wXC5dvVvHZg10rOqzGOKT7CUj+rwEuvv X-Gm-Gg: AYBFou0PYjBkdhTim/F+G+qDDM/FTAOEQQDP4FEhhE/jKPOflOQ4P3/UXAqVkjkuygE Sraex67owB+i5wQZR2wLrxLyyhEvOSIAkViQAg2aB5RABVVUlUD1oa/UR2qoqBQ4N8oWjubKFOq LRD7VMtffM0fGHU2HNoLXWH10CRK0Bb0t4ba0KUBHH5CyjKG2d4bVNTx2ob6Bgf5UyxeOieMYf8 iREcw3cfOZ3/T4oTH7JlyATpdqLWgwiRPHmS2/m/y9/Egmr+m7ROBIPBGawNm4kt0zKrxM2Pa7f dnu7W7soRanOsNQv4xDt8PcUJmY8RZtLqvQr5GRyog/SfJv1SqE22FF+DsfMTxC8banA6AKwfDC qjIzYXZcsuaRa0xBsNrewBOc3ZefgJWn8TKLgOhKTgEMW7fRs34U7ZqJDrviIhnNoW01ddon35D iLrWpZ+ydb2gkfKjc7Zq5Sb/lbEBY+Qjq6a+8YugQ3kDd4/yP7txzpDsBpD0QE7eInUZ3giom/f wq29bkZ X-Received: by 2002:a5d:5f85:0:b0:488:7fc7:dffc with SMTP id ffacd0b85a97d-4887fc7e08cmr15202866f8f.37.1790540044710; Sun, 27 Sep 2026 13:14:04 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.13.58 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:04 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:31 +0300 Subject: [PATCH v13 03/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: <20260927-zx29clk-v13-3-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= , Krzysztof Kozlowski X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8565; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=ZZeixT33K508YXS7awOOMQnGZZ8sVeeN1ZslFQ+5hXQ=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj0K8mUgU2bzwvm2T/RYD5FiNOdgNSnkX6RY zLZRgeCl/SJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49BsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLrfBAAhSWuZVPlcLvMFtuK41yduFLCRQtYszS KqbLZfyWXdxDVUeVO+bnrlH1VHW7DXu/paWi8sIaidLr5nWxLlV4THXq+G+/XGN5/XVh/JBg/FK J59KVfzWOLPGDoGdNeChYiGxuuCQ/1ZQ6UlGCS/TDoImrWuhE6qUckydKCxp5/M8ibZhRUtr9im EmQIGiYXuayKSQAelLIhVKNcdDxYujKYJFBX7TilwSYBqpgu7dBbuhi0G7Fp4o/y3WZTL3MNTyY GnIrOj861fvz+cdUX7YYbsSKVpTul+gW2Y77iY4RliUWbLdfQsFhzSNeVrvLjPkaM8XSFZ1gw3P TaPw3DD7q7jq5YNqY2IRIWmmLUjvIT8phHEBJOkIKxXvtWiP0NqRRGsnGyciTD6AeITtSgNUgJ2 MhgheMK4SGZdA02k62xWyA44McS4M8sjWdZlvObWz9Qswdn2Q/n3EIzJYUkb6bd2nUmBxJOproj 4RgZ2gpIJwi5tG/tTn9yNQ9+6wa53eRqDpQ+ogU47Odl0wuA+i88w2q2Wb82wf9xvrOS4cRZT0s 70olM5cbOwix8t2X18uW9hpU+Eu72QH+0BDKE3EqpxWq3uttO6kR6R4oid1kT+HGWM0no5YQXJ5 3nOcNTQ+gLYPy9f5R8EnK28+VtRzQXIt1RKeiTYSgMhi4YkLOveg= 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. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan D=C3=B6singer --- Patch changelog: v11, v12: unchanged v10: Fix order of clock-cells and reset-cells in the example to satisfy dt-check-style --strict. v8: *) Start clock indices at 0 *) A minor grammar fix in the second paragraph of the binding prose 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..b0a176ffda12 --- /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 + these signals 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>; + #clock-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"; + #reset-cells =3D <1>; + resets =3D <&matrixcrm ZX297520V3_LSP_RESET>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 5f367b5126c2..06dbf9305518 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3922,6 +3922,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: 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 d98bc38635b0..a63283d5df5c 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -114,4 +114,41 @@ #define ZX297520V3_LTE_MODEM_WCLK 42 #define ZX297520V3_LTE_MODEM_PCLK 43 =20 +#define ZX297520V3_TIMER_L1_WCLK 0 +#define ZX297520V3_TIMER_L1_PCLK 1 +#define ZX297520V3_WDT_L2_WCLK 2 +#define ZX297520V3_WDT_L2_PCLK 3 +#define ZX297520V3_WDT_L3_WCLK 4 +#define ZX297520V3_WDT_L3_PCLK 5 +#define ZX297520V3_PWM_WCLK 6 +#define ZX297520V3_PWM_PCLK 7 +#define ZX297520V3_I2S0_WCLK 8 +#define ZX297520V3_I2S0_PCLK 9 +#define ZX297520V3_I2S1_WCLK 10 +#define ZX297520V3_I2S1_PCLK 11 +#define ZX297520V3_QSPI_WCLK 12 +#define ZX297520V3_QSPI_PCLK 13 +#define ZX297520V3_UART1_WCLK 14 +#define ZX297520V3_UART1_PCLK 15 +#define ZX297520V3_I2C1_WCLK 16 +#define ZX297520V3_I2C1_PCLK 17 +#define ZX297520V3_SPI0_WCLK 18 +#define ZX297520V3_SPI0_PCLK 19 +#define ZX297520V3_TIMER_LB_WCLK 20 +#define ZX297520V3_TIMER_LB_PCLK 21 +#define ZX297520V3_TIMER_LC_WCLK 22 +#define ZX297520V3_TIMER_LC_PCLK 23 +#define ZX297520V3_UART2_WCLK 24 +#define ZX297520V3_UART2_PCLK 25 +#define ZX297520V3_WDT_LE_WCLK 26 +#define ZX297520V3_WDT_LE_PCLK 27 +#define ZX297520V3_TIMER_LF_WCLK 28 +#define ZX297520V3_TIMER_LF_PCLK 29 +#define ZX297520V3_SPI1_WCLK 30 +#define ZX297520V3_SPI1_PCLK 31 +#define ZX297520V3_TIMER_L11_WCLK 32 +#define ZX297520V3_TIMER_L11_PCLK 33 +#define ZX297520V3_TDM_WCLK 34 +#define ZX297520V3_TDM_PCLK 35 + #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 54e5b24f859a..b21d5901a7b9 100644 --- a/include/dt-bindings/reset/zte,zx297520v3-reset.h +++ b/include/dt-bindings/reset/zte,zx297520v3-reset.h @@ -40,4 +40,23 @@ #define ZX297520V3_VOU_RESET 10 #define ZX297520V3_LSP_RESET 11 =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.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f33.google.com (mail-wr2-f33.google.com [74.125.225.97]) (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 75D183BED46 for ; Sun, 27 Sep 2026 20:14:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.97 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540053; cv=none; b=p2anKH8Scazm6ZIUfQAIga0nSH2h5nYITfzV8jJeOTGcF7HqxhSZk+6xVwf8O7OnSjMKUb1Atio4sjzAN4FJPYS6+njBcw/hw30zcC1IEDe1PdbKRuvpm1mOv5TlhSMCGr5ogaCGoujvhxWCs2NvUsZ7RdBq4gPlE9ZGOJmt7Yo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540053; c=relaxed/simple; bh=/no/lvHVLlUeWbGnAU42PbuF5Flsu1tg3CcL3JrVyrg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YPOEh5BICf6ef1LMSuyQbDw9lqqZvK9MFroa0sbyu9BjnpM7Z88g9fT0slY90+q6NiKkojhzwDcO4qz29vofvsN5nvHe2DxTtVuIdiXGpvnzD/oBXqQMwpSeNGJOD+pNhZ4HMfKupV2DlxvtbC1EWEI4j/G0eS/BKAy7vA2bKeQ= 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=REn2NDca; arc=none smtp.client-ip=74.125.225.97 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="REn2NDca" Received: by mail-wr2-f33.google.com with SMTP id ffacd0b85a97d-482f6351831so1325900f8f.1 for ; Sun, 27 Sep 2026 13:14:11 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540050; x=1791144850; 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=gUceZn+ZYo9pcUVc5KdBZXypYMxcrBpVlO1tu/ti/Bs=; b=REn2NDca0noUNtr12PHxD1bZgFxIo8cfc2gc9gUv7D4VHk9LUvlI4rcT8b4E2pHXXg SwmwmqEPzcJ10FUFFCruymSPYyzWGOjBAbIW0MYid//7py92+Y/BbdxPf9kuBb64iPf7 52Lt3KVomAWnpdEwqyrTaBTJt2R4pcjh9XU63Vqrx50lhLcUkJV6V93J+Bg1lT3cIolb BN85zSXqQeaIs5hrZa5gKOmDvepx8A8561QrG88DCfYAjEnSLNTq2IeUnfR6yUuQcotB LInkCm88V25CaZkJsutmiAWmQiXcgBKL+8Z5lXIRQhFI1m1rB7XppcPVQSQoCPxGJ0b+ oE5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540050; x=1791144850; 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=gUceZn+ZYo9pcUVc5KdBZXypYMxcrBpVlO1tu/ti/Bs=; b=QCBynFFsAaBVLgKU5MZw/QByR3Kmaix2/Ju259GXNKImaJT4WbOy9NOohTFTe9pi3n tjedC73T2prG/pOtbrulhKacupXBHE9PAYsvV0cgfHiAGqk1+MJz0kIAnZpBQBzzlk5R KzVhZMptnAreP00xseFj91SP/q9UloWJEE1vAUGS5DyOtMnxQWoqv6YP6A16kaQXKy+x UEanxE2Jlgz85jHV1L9NTsC6XGjgTMCqFkEQ3w7A3Ofg6BmvcnCiV3mDvjyEsE4c8Vvq JosjhE6wlFry2iFqY7RCF7FZYhI8gzbS2fchW3/9h5A30QiedYZ6P5J3q1A3xutEcNkU vx6Q== X-Forwarded-Encrypted: i=1; AKwUvByb5nYNv4Q73daRp6j6NE83HBzct442A72kjk6ccUiNB2Yq6V1tci12RpnkdD1wgnABj+Td9HVkxKDdysg=@vger.kernel.org X-Gm-Message-State: AFq9FYJAS42evim4ab6uQ/V8rsBwOS2r9Nn30fDZ+yFYsiJrDsDGo9Cu FO4Kg2dEiHqXPieHCEiAp/A9hLdc9AHv6vYhAgj46FmaqniZ2BDhTFK8ccPB/xhuwQBd/g== X-Gm-Gg: AYBFou1Enu/KQTiE24JrAcFcWA83E/LE0oNAe+UUd7RI+a1Uh/Z0YPf/nkEtBhyW/Fs oQExI7xcp5ZXchQAXHsdlNZdAnT2+D5P5m/l0kLH1rVdBbo6olSZ9r6SytFDA1N+Ai35TUfiAW6 pQukc1JJsa5F3+njf+WQ/7bPYwRrh4Zjf+17r2nl0XrY790KmMKjr5QLXGbaHojzKwVyNBCT0/9 cXON9socwzhhxEGfs1kjOOTn+e06NtZw6+9PduCs4L/BNzdLe/bBK01gIRnt7FDEsTi6nC47Ym5 pzGy9v7O++64A6DEgd5fN4sOKSLCQM5QApE2OfJ6YOKWDe7e4xMTD0lS8DVFx1MO6oqNYAtNBLi uU/WfWJz/qIGkfEPpbZo+J6gtv2bpTH+4KNu2tB+CvG1FS3C2AhizRczmNMajyaMY15ViVN5Xoc 7dCzmCe+RHl3PYzmN7KsCTIJk1TUwS7da+gkWXsPcaREgIFfjo7eqRp6gyBHB2IrM2JzjtYufS0 kB6ysz2 X-Received: by 2002:a05:6000:41cd:b0:487:11e1:cab2 with SMTP id ffacd0b85a97d-48871770959mr20219237f8f.49.1790540049588; Sun, 27 Sep 2026 13:14:09 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:09 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:32 +0300 Subject: [PATCH v13 04/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: <20260927-zx29clk-v13-4-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=8980; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=/no/lvHVLlUeWbGnAU42PbuF5Flsu1tg3CcL3JrVyrg=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj0QNoX0bL63wDmSkceKLeek0stm0x6V3s69 TBoK7EkItKJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49BsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiJxWQ//XKrkasQ8YHRwe4KgOUdIdG2jjoKtOJZ PVGNYax3DmGwp26f7jpencxIgUzrpsOCUdA1mC3FOyn3mExcTKhKRKk541/ZX3brYFTo99xI9UY prO/q08JBDERLdiNC3OPXk3t2VQJ3da09n7P5WF0A9cgMmCSi3R126qONV7HCzAMUA0DxI51AZy FgfmarQIjksqanVdVxhQH8DQvvGHwDBoyNhRpRSqsMOwZmbr+iXCAAEbbMPpbln5vMilhuf29zi 8+M9CapoBof/1C+oe4ja+VzXLd7ZXXQEhB1DAGxD6rbXoOmlWmOwsvxvhOY0OemjpzAM/0Ud5TB MBUjpu2dbIwH2/Guk7kwJQDy0tCRFRu0mcQs2YbI2uGirGJcd/0e7FhTR+dcnYyF4rKRrEKSs2r k5Q2yGMCrG6B1Q31JeUEIPpTvRJAT9FnfA1HDGQQguoXVebUNJb6kU0HpQiIZ0LNbs4R2z0UjjV Pa8LRWtBlQFHZupcDGjKLXxtin0fgwi0AG4kbmkBdB5YnCejDbdCo941jdNOxielJpoRk85hbst IHZ5CwXLvxfGsFaEY/v8ETQXrpCpbN6KCR+U36COPVGb2jbT0zVay+ALT4/ybrR4hVm8EvfHSqQ uVPth0snLfebuqNc+ZqcWzWz7AQWh1WdZ7hS+LsDp9U71VffS8xQ= 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 --- v13: Break out the MAINTAINERS change so Lee can selectively apply this patch. I made sure it compiles without the DT binding headers. Lee, if you prefer, I can send this patch with the MAINTAINERS change folded in stand-alone (or as a pull request). It'll have to tricke into the clk tree before I can PR the bindings and clk driver though. Changes v12: Added comments elaborating on the role of the driver and the hardware. Regarding the names: zx297520v3 is the SoC's name (chip marking, boot messages). TOPCRM, MATRIXCRM, LSPCRM are ZTE's names for the MMIO blocks in their downstream sources. Sadly no datasheet is available. "clk", "reset" names for the child nodes are mine. Regarding personal copyright: I am not affiliated with ZTE nor paid by them. This is my personal hobby project. I am using knowledge extracted from ZTE's kernel dumps, but not code. Changes v10 (All Lee Jones): *) drop "select REGMAP_MMIO" *) Drop comment about unimplemented hwlocks *) Use MFD_CELL_[NAME|OF] *) Renamed the device type enum and its values *) Use device_get_match_data instead of the of_ variant *) Improved debug messages Changes v9: Deassert the LSP reset and enable the LSP pclk here. In practice the boot rom needs to do that because it prints to an LSP-connected UART and reads the boot policy from the LSP connected flash chip. In doing so, I migrated the match data to an enum as mfd.md suggests. Changes v8: *) Remove .of_compatible from PHY mfd child *) Move to drivers/mfd (Sashiko) For me either soc/zte or mfd/ is fine. Note though that this MFD parent is very specific to the zx297520v3 SoC. I don't expect this to be reused anywhere else. There are two more MFD-ish devices in there: soc_sys at 0x140000, which I plan to handle in the same driver, and an i2c PMIC, which would get its own host driver. *) Use PLATFORM_DEVID_AUTO (Sashiko). NONE was intentional as I only ever expect one instance, but I don't see any harm in doing the standard thing and use AUTO *) On the suggestion not to put the link to mfd_cells[] into match data: I see that it is spelled out in Sashiko's mfd.md, written by Lee Jones, the MFD maintainer. I would appreciate some education on the rationale behind it: Putting a pointer into the void *data is a common pattern in the kernel. I don't understand in which situation this can possibly break? Both structs are static const in the same compilation unit. data is a const void *, not a uintptr_t or kernel_ulong_t, so it seems passing a pointer is the intended use. What am I missing? Changes v7: Add phy MFD child 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. --- drivers/mfd/Kconfig | 12 +++++ drivers/mfd/Makefile | 2 + drivers/mfd/zte-zx297520v3-crm.c | 111 +++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 125 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 857ca3bb0d5b..b30600f6ff0c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -2580,5 +2580,17 @@ config MFD_MAX7360 additional drivers must be enabled in order to use the functionality of the device. =20 +config MFD_ZTE_ZX297520V3_CRM + tristate "ZTE zx297520v3 Clock and Reset Manager" + depends on ARCH_ZTE || COMPILE_TEST + 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 child drivers. + endmenu endif diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 72d3944b0ad8..ab0cba2042a2 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -304,3 +304,5 @@ obj-$(CONFIG_MFD_RSMU_SPI) +=3D rsmu_spi.o rsmu_core.o obj-$(CONFIG_MFD_UPBOARD_FPGA) +=3D upboard-fpga.o =20 obj-$(CONFIG_MFD_LOONGSON_SE) +=3D loongson-se.o + +obj-$(CONFIG_MFD_ZTE_ZX297520V3_CRM) +=3D zte-zx297520v3-crm.o diff --git a/drivers/mfd/zte-zx297520v3-crm.c b/drivers/mfd/zte-zx297520v3-= crm.c new file mode 100644 index 000000000000..d896261a4d40 --- /dev/null +++ b/drivers/mfd/zte-zx297520v3-crm.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + * + * This driver splits the ZTE zx297520v3 SoC's clock and reset management = devices into MFD child + * nodes that are managed by independent drivers in their respective subsy= stems. + * + * ZTE's downstream kernel names the mmio regions "topcrm", "matrixcrm" an= d "lspcrm". For an + * explanation of how the controllers relate please see the DT binding doc= umentation found in + * Documentation/devicetree/bindings/clock/zte,zx297520v3-*yaml. + * + * The controllers are primarily clock controllers, but they all have rese= t controls as well. Top + * and Matrix controllers have further auxiliary functions. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum zx_device_type { + TYPE_INVALID =3D 0, + TYPE_TOPCRM, + TYPE_MATRIXCRM, + TYPE_LSPCRM, +}; + +static const struct mfd_cell zx297520v3_topcrm_cells[] =3D { + MFD_CELL_NAME("zx297520v3-topclk"), + MFD_CELL_NAME("zx297520v3-topreset"), + MFD_CELL_OF("reboot", NULL, NULL, 0, 0, "syscon-reboot"), + MFD_CELL_NAME("zx297520v3-usb-phy"), +}; + +static const struct mfd_cell zx297520v3_matrixcrm_cells[] =3D { + MFD_CELL_NAME("zx297520v3-matrixclk"), + MFD_CELL_NAME("zx297520v3-matrixreset"), +}; + +static const struct mfd_cell zx297520v3_lspcrm_cells[] =3D { + MFD_CELL_NAME("zx297520v3-lspclk"), + MFD_CELL_NAME("zx297520v3-lspreset"), +}; + +static int zx297520v3_crm_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + const struct mfd_cell *cells; + struct reset_control *reset; + enum zx_device_type type; + unsigned int num_cells; + struct clk *pclk; + + type =3D (enum zx_device_type)(kernel_ulong_t)device_get_match_data(dev); + switch (type) { + case TYPE_TOPCRM: + cells =3D zx297520v3_topcrm_cells; + num_cells =3D ARRAY_SIZE(zx297520v3_topcrm_cells); + break; + + case TYPE_MATRIXCRM: + cells =3D zx297520v3_matrixcrm_cells; + num_cells =3D ARRAY_SIZE(zx297520v3_matrixcrm_cells); + break; + + case TYPE_LSPCRM: + cells =3D zx297520v3_lspcrm_cells; + num_cells =3D ARRAY_SIZE(zx297520v3_lspcrm_cells); + + pclk =3D devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(pclk)) + return dev_err_probe(dev, PTR_ERR(pclk), "Could not get 'pclk'\n"); + + reset =3D devm_reset_control_get_exclusive_deasserted(dev, NULL); + if (IS_ERR(reset)) + return dev_err_probe(dev, PTR_ERR(reset), + "Failed to deassert reset control\n"); + break; + + default: + return -ENODEV; + } + + return devm_mfd_add_devices(dev, PLATFORM_DEVID_AUTO, cells, num_cells, N= ULL, 0, NULL); +} + +static const struct of_device_id of_match_zx297520v3_crm[] =3D { + { .compatible =3D "zte,zx297520v3-topcrm", .data =3D (void *)TYPE_TOPCRM = }, + { .compatible =3D "zte,zx297520v3-matrixcrm", .data =3D (void *)TYPE_MATR= IXCRM }, + { .compatible =3D "zte,zx297520v3-lspcrm", .data =3D (void *)TYPE_LSPCRM = }, + { } +}; +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 driver"); +MODULE_LICENSE("GPL"); --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (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 673343BFAF2 for ; Sun, 27 Sep 2026 20:14:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540058; cv=none; b=BWw6DpuEobb48dKfbE9sprS3KDCwVelhfHK+ciwVymA1QcjTbbi311uW5Z2/mjgwLIH5wzyVS59y8g3Y4HMo/LWK0yF7aTjJR8hE+weP/ptT2J1klFaa0QobTfyxtF0xl3FYgmnOUK27TZEZtXGlsO1v6V9lQ9oVc/R3c/zrxbk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540058; c=relaxed/simple; bh=WAeuXX+lP9ApAmDxLig8RAtvnn0hthSMmgK7I/B9wz0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Fs8LiIQF2kEpYk8tfxi+EDp95cQMHla59Y8hJesSGzS5fdgPBqKozvYzK/4naZmd8UY5/F092AmQ0V3cgEfSWrHnRSXejVLiRiUifsfgiITApdjtTYrO0UvjknhiGlbPopbHyD1YwQYh7r5uQv6TGTlYD8RTHkKxKy6pU5/+3qw= 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=i4FJHz+d; arc=none smtp.client-ip=74.125.225.140 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="i4FJHz+d" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-4a001e575afso4090735e9.0 for ; Sun, 27 Sep 2026 13:14:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540055; x=1791144855; 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=jNSR66L+rsqa5I9ez3liVlAc8gcWggGRjRYsUUY8qc8=; b=i4FJHz+dghTgirW+lh8vcphIEwgpvUuBig+g3WYbJw42MZc+KeXaCJg3d0vhL1UY3y gWX748pUEVDEVPP4RqlFgY4k+Eq3c+c+jySewBJ+DMYBQj9diQSsnFW7+NPDVHhedQ2y AdobLtPZcRTeHUqIojZYoMa//BjEMJ5T6iClEXEGl86a7Z3pOpUccqIxho9NowMWyDXG tUxi/fsqC3bSPyjOlLd86w9F7TT2Hn4LNFrwMfYPwOPPa3RSAH1qIwkVwvwf34z8g5kr /S/A5utY5g1huiHVPQKuXpae796R/CEHGO9VUa6Ew/IdLf0nLl+hm03yh954X4FRsm6P +1NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540055; x=1791144855; 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=jNSR66L+rsqa5I9ez3liVlAc8gcWggGRjRYsUUY8qc8=; b=jQlTPv/Tv2BFzfcOOBKrLLbtMst7a+T6piq7XHB+CRljFg16bQ9sCKX1DAXpmM+GGk E87ZyOSBwjYx7921yTcVFOvOi2ZuBVjWSRHs/jU1FCMja5qRKNXtQtdQu8kYZWM/fT4K KGCa8Xiu+2HrGrybhUy1+G9BciCR/mobD5g+jbDl/UGY5aXsmWVTOZbm5HTUI+ml4wnw 5P4YK/dNMpBx69f3zTRRRKfsy7fufsRR1CQwziCnW56bLLAtIeOOODjXK7PlMwFWFfm1 B4Ge5Mukw2uvCqc3nB8R/shVsDeregdCdIM6/bo3RzoitEPtsEfv7wWG6OJOZ7SVW8E1 mB+g== X-Forwarded-Encrypted: i=1; AKwUvBy3Zas86S3iQkF9SzxmFQzmC03VmGPS4N0M5WGUNpZmbpxWHMameuM3UFEvQhjGlJ/JOAF4JnO6Gb4Cc/Q=@vger.kernel.org X-Gm-Message-State: AFuF++m7suh9sYiADhcZot5OYVa8bVo/dNP6G9gxcZSG0yIYZxbGKHWa 5wi7+IrJu7+Ha4sAxobeTaGHOC50hw6BTOTA0NKIpCkkB/WiSL0KhfDg X-Gm-Gg: AYBFou2e0ohV4t5SWcKifRmyvTKBrPw2/conIlS/SGPcmCx1CZpfw8zwM9bAHBBxQpd ZdpFXwaFy1/paRn+uwRwW81RhBpgs7LpGN0NkSJUVzExejH6lFso6RSSCLNVNy8yXEXhWsLOI4U JXhxSus9ZFP2tWeCge8Q5ZsDZueEyM2M0CsqLCfue0wtWs4XbAftUzgNjEBCkLrSBqvdqzq33PA yXr4NKURRmdILzygp7OT62Iu53iGrgKshQiIbdj5CIpkWBWlNbC0I1fpQuUL7ABGyiFTzh2+vI9 sUYal1LfgYUcuUWSnI76G9TBJZcQs41uQk24v3T1Yqq1AViaMjz28B9mtxn9koFaeB13PizHnwn e9xMkU+EaBYr72GQdGP4ZtU75rgMk7HBTs145A91bT1CsinzGIkCQOnekrJYbiixrU9/ChHtKEt m7zgIyKkhcA9oo7Bw2v+BTm9Qm0W3AQU7gXP+bDWlYcfjc4Kb6xpMrfozbNYLkuzTR/h5Acvynx BykkXLyHQ== X-Received: by 2002:a05:600c:698e:b0:49c:fc6e:a3dc with SMTP id 5b1f17b1804b1-49fe66f1491mr205824235e9.27.1790540054611; Sun, 27 Sep 2026 13:14:14 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:14 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:33 +0300 Subject: [PATCH v13 05/13] Maintainers: Add entry for drivers/mfd/zte-zx297520v3-crm.c 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: <20260927-zx29clk-v13-5-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=957; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=WAeuXX+lP9ApAmDxLig8RAtvnn0hthSMmgK7I/B9wz0=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj0S3ciOtiZ4TddTH93kGsp4UXVIfMt7n79s r0ElotOL/CJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49BsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKW/BAAmpXG/xbFgkzgIfhZqAl49ngI7YFzIm4 nlz4d2lVrIFvPWl/QBMAgDtvhzz9OJNp6NEDOEqvNzyqT1VxxeNeQ4zJG6SUIAIgd20+957sTR3 Nhs4WqZ4SuSyLxnIyK74JInCTsYoOHXd62yllcHYuxsPMrYNsqYj/zz7LJCSOkAasbwHg48i6Vq Tz64Img1+QUAIeCyAxKNi3fN1pNY6xASp9UIDE+ZeI9hLi/pHeNRnW1Mt4aCGvMt95mqSB+HbLB DDEyFDIh7VAHtst8NTkqz25FsA+hwBk3NH6L5qXbTHABfXFJHoOZ/HrdFRMQXjguwYT/0DAGiAN AOwbkj4Focx/6CCTNpcqMBIWFs4RpuauE1YVAUWGue8mlYgk5hVbNCFcfuhKj3wG34yv0TjUxwO QyphlSKqxLu14akUrCjKnmftBa4RlZEnuvs/bVzNQXAmdeY9wvGjMNyAl5fkZPLRDF589mBbs5h vkhnlFUiNa/kCEeCtncbCB2fFJmkAH9AFA0+Z328yU81QFo62/A90VHRK2J1zpBnuaS+ATNc2xh b9bVAEUy2R4AsN6qkkp4prbioRkXdYmz+s23mKBOSZAc9AnqbUcUiB7u5flJk45geDUcbvPNmFR g5XFhBuQSAb97ggmKp7jjD53F2dstl/Rmc3oo2k+B0lD9v1OMpfI= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This was broken out of the patch introducing the zte-zx297520v3-crm.c driver by Lee Jones' request to prevent a patch dependency just due to the MAINTAINERS file. I plan to send this patch to the mfd list once the bindings, clock driver and their MAINTAINERS entries are merged. Signed-off-by: Stefan D=C3=B6singer --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 06dbf9305518..41c287316d0e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3927,6 +3927,7 @@ F: Documentation/devicetree/bindings/clock/zte,zx2975= 20v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/mfd/zte-zx297520v3-crm.c F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/zte,zx297520v3-topcrm.h F: include/dt-bindings/reset/zte,zx297520v3-reset.h --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm1-f52.google.com (mail-wm1-f52.google.com [209.85.128.52]) (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 A6668353A7E for ; Sun, 27 Sep 2026 20:14:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540064; cv=none; b=tQ9XBTWbAKP2E2IlPFU5D5DCB7INxw55EQWJKXGdhHIyBU96bvFdo8WJ77Af1hj646AbnKHW/Nn2WF9eJhFdjVfpG2dBlB77AfuM8XmqDCwAYGNKigt9QtrbLGj7TvbYZ5qAJdznkvx/ba4oAX9yO4o1C7gcovuCPGpRbPzGjG8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540064; c=relaxed/simple; bh=ofd8rVoz0p52QzPz9+SkZywnce00Yrxb97abl1XuDdk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=kQqAI5aWTYBb4TA6i+GHp1B5z1HtEcmNT9NIuQDWau1L0rbdaXZWFMychKnvSmHd348sdmkMXroLLyNqk/kdnzDPVY1vpBaBBXc3eN79NK2x0jGo/MfaKgy5cAguWv81XamMR9omPtBR+V/yf5JMsxYWBaICjeb/ahza1eYVaWM= 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=LWgqraIL; arc=none smtp.client-ip=209.85.128.52 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="LWgqraIL" Received: by mail-wm1-f52.google.com with SMTP id 5b1f17b1804b1-49e73611928so22142965e9.1 for ; Sun, 27 Sep 2026 13:14:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540060; x=1791144860; 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=lcshcCFgPieIG5e8bwiFJkZupH8EGx8PYrfbPTGlSIU=; b=LWgqraILu5Lt1VLsq7w9jgsSLCUXt013F7dqVFEbZ9v5aKdcUsfb4jJeRKGnRgxmOq 6kxNaipfvTXhs1ZTNb9//dzHtrTdGk6vC22rFRL/U+x+5FyN0T3htlcG08Rqr6hQJc3V n5pteXfyY/yOVHPQy7ARc1GEAhfnn/TFqZhlYNXgObv2x06IDRkL84K3+Nm6qxJVp5lA CRIeC+2SoYA8Lh5afnhBpXWU3caYe4vP4wZKPP2edjFl1DYfVJ7TP8nxdlYuKq33PpFn B16gUC1kBiLpR7s1aEIIfkpl7xBsG2wRfeFxCSKswMjYjv/truv2GymY6XVK9Dr8KcHt Wqlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540060; x=1791144860; 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=lcshcCFgPieIG5e8bwiFJkZupH8EGx8PYrfbPTGlSIU=; b=w7SpJCikwGsBsBi41LuGZyv24QD5Qby0TurhhQHl7R0mLxrQHsVLYVPwd+geBbFZah FJy7MNuWlndQCwPaR16L4MGThCxtHUSfsNLc1c4YjPdNKKnHCSrOxBkAs5RD8jkupqCq 3TaceYpGDiZog8cz/bthU5mtwTCTDkCvfIHTP4bsPxkQfP4Dcor8mAy0oX7V+yEyeGp/ JM+v6DzgsgOz8p0+/z3LRy0QutNyIYGPXabu0+3PIQODIpQRGWnyY68y2EBOuSR0eeSq zEPx2hcrmuPU65lP+PsQLjfUWfPflTZVOUfXypyCfRelFXPLXd9LO/lcEMAMmFmZmv8r cg9A== X-Forwarded-Encrypted: i=1; AKwUvBxdMkrn9NDNK5n2pR+vOtmSpmyiUA6vFFh3mqups8qV3cMUmNbSQG9/wk7A7DZ1k18gqig+xEK6g+Ku668=@vger.kernel.org X-Gm-Message-State: AFuF++kD0XUAGduMP5OBwBwGgAwHP1hfuNsaEIMH9OLL2HL3UEshfiox 88lu8oZ2M2viFFajrNsluvSGT2u76wqNxecGgD/A3udAXzeF+a2pEalk X-Gm-Gg: AYBFou2rInLEL3cQz3eyhsG/meBtJMQU0p550Pw+e4tpngu/l0usYU4fJNwUgRPSoy6 RDcJx4lTnS46RGG8m/FMS5qI7VCQlF8jJWd8QX8xp+tB6TbmH88zXWWRa3c1bLw+4Y647xDIzZP bUr5myOsilA2F3nrkFZBu4QNEigDDHc3ZC1dr+CV0vkpWdBjYujgmouWsppGPXqb30cKrdTXmBn b5W3E9sVSu95Z+ekQYzvxEv9IGth/sJ3kShsePIVziQYzTsit/GJYowx7wwXLlu867HR0rNkmFV 5JkatUUq0kC2fuhtpQvAXmN5zPJavX29ALl7i5wfWaZ/O2X+CwguYdBjiUPmsQr3PRXNzCxq3E3 aq3tOHePdK05iHrDmTaPC7lUnm+z9eTTusB+7u2AVTiDPhqykSGMnnd9geHQfSl8yjpAPaeIhoF i6HdLwZrWNnwPlrt9bMNKMEtl6p6yeoLqCefZwSDwucN4a6llYovf3Gso2z/QwUWRZQLcFoI4b+ OOJHc91 X-Received: by 2002:a05:600c:a211:b0:4a0:373:18f3 with SMTP id 5b1f17b1804b1-4a003731ce6mr17412175e9.2.1790540059698; Sun, 27 Sep 2026 13:14:19 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:19 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:34 +0300 Subject: [PATCH v13 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: <20260927-zx29clk-v13-6-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=15712; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=ofd8rVoz0p52QzPz9+SkZywnce00Yrxb97abl1XuDdk=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj0xo4v6acvpcXXLjh0HCgGV001IL5IGUtRJ yGe8+lHka2JAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49BsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLbgBAAnGF87HZUSY0U0jEK2edg3W0dwAtYFP6 d5Ba+oIshYPzqsuQxmSJaZSpw4FDkyr+/Umir9CaPXNQScQ9Nc4MH9UnuR/1B5EM6cOyPSnW92U kQlON84K6cnfR2oDNCDOY/c+7Bdnsl/sogWmumC7yZgGUesfjSn6fKIgZCSrBFdBsB3rn0Z5GlR JIe+QVtsQvWU2YOxdzz06FJfSxZoEjkmn+McNYUxkSy2vKfypIQsjaPrRvF8yRw82sEP5h28V2U 69TOG/NODpuLSSmwgrfwEMiR2r7/bWQLk/983slkY6uu9e7I12RHb/2fiPU4IlZ3g1GivqEci9U 9vLOL3gC/qf1yTpR+QSwyniOAYchFz2VtpjT6sgI/VXT4n+a8/1DIfidF1hnXHqA3pGcjIapRjg E5OQdORfr5exSwhEy+1tG59p/tdAIapNtsCqBLDhOM7TooOv7fgXuU5wknxbngCswX4vn4KCKSC l4j8n194ulvGhoo7LdFj6fD9TOPgaeW0XiryXNBGIqV0v/JEeJHA1zsnqxFAYybRm7W+OaySQHf QqDrcK0bq5FuKAyMTBA1KxWi72SPxpWPpD3oTWCsyRJT4R1D+382lV8inb0JULT9Ld8bQn0AyqY EtnftCZLDiF8ibKY2+frxG9VbxjXcTF+YDSApkK3SUDIef4aoZ4c= 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. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- Version 11, 12: Unchanged @Sashiko: I think your concern about a NULL of_node in the call to devm_clk_hw_register_fixed_factor_fwname is a false positive. The CCF code looks for of_nodes in dev and dev->parent. Version 10 (Brian): Remove unused struct zx_clk_export Remove a stray semicolon from switch/case in zx_get_parent Explain the rationale for the validation code and discourage copying it into other clock drivers Make the exports array const (Sashiko) Version 9: Rework parent matching and clock export control. Most of the changes will be in the next patches. The visible change here is that the clock array is unified with single clocks having a type rather than one array per type. Depend on HAS_IOMEM, similarly to Sashiko's flagged issue in the Reset patch ZX297520V3_CLK_NO_EXPORT is gone again. The explicit clock input array and enabling of LSP's pclk is removed from the clock driver. The MFD parent takes care of this instead. The clock driver does some sanity checking on the static clock data though. Version 8: Use ZX297520V3_CLK_NO_EXPORT=3D(~0u) for unexported clocks. While using 0, and starting clock indices at 1, is a common pattern in existing drivers, it exposes a driver implementation detail in the hardware binding interface. If desired, I can change the special index to a separate field in the structs. Fix the return value if the ->init() callback fails. (Sashiko) 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 tell me. *) Fix error check for device_node_to_regmap. --- MAINTAINERS | 1 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/zte/Kconfig | 17 ++++ drivers/clk/zte/Makefile | 5 ++ drivers/clk/zte/clk-regmap.c | 32 ++++++++ drivers/clk/zte/clk-zx.c | 192 +++++++++++++++++++++++++++++++++++++++= ++++ drivers/clk/zte/clk-zx.h | 137 ++++++++++++++++++++++++++++++ drivers/clk/zte/pll-zx.c | 18 ++++ 9 files changed, 404 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 41c287316d0e..cf4e8c48ddfc 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3927,6 +3927,7 @@ F: Documentation/devicetree/bindings/clock/zte,zx2975= 20v3-matrixcrm.yaml F: Documentation/devicetree/bindings/clock/zte,zx297520v3-topcrm.yaml F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/clk/zte/ F: drivers/mfd/zte-zx297520v3-crm.c F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/zte,zx297520v3-topcrm.h diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 252f6a1f21b8..ca4869c4e5e1 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -548,6 +548,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 2d8f60254373..91b73be31707 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -182,5 +182,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..152c2423b8f0 --- /dev/null +++ b/drivers/clk/zte/Kconfig @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE Clock Drivers +# + +config COMMON_CLK_ZTE + tristate "Clock driver for ZTE SoCs" + depends on HAS_IOMEM + 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..80332dba97f6 --- /dev/null +++ b/drivers/clk/zte/clk-regmap.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2026 Stefan D=C3=B6singer + */ + +#include +#include +#include +#include + +#include "clk-zx.h" + +struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *reg= map, + const struct zx_gate_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} + +struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *= regmap, + const struct zx_div_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} + +struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regm= ap, + const struct zx_mux_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} diff --git a/drivers/clk/zte/clk-zx.c b/drivers/clk/zte/clk-zx.c new file mode 100644 index 000000000000..aef0f7c753e6 --- /dev/null +++ b/drivers/clk/zte/clk-zx.c @@ -0,0 +1,192 @@ +// 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 struct clk_hw *zx_clk_register_fixed_div(struct device *dev, + const struct zx_fixed_divider_desc *desc, + struct clk_hw * const *clocks) +{ + const struct zx_parent_desc *p =3D &desc->parent; + + switch (p->type) { + case ZX_PARENT_FW: + return devm_clk_hw_register_fixed_factor_fwname(dev, NULL, desc->name, p= ->fw_name, + CLK_SET_RATE_PARENT, 1, desc->div); + + case ZX_PARENT_ID: + return devm_clk_hw_register_fixed_factor_parent_hw(dev, desc->name, cloc= ks[p->id], + CLK_SET_RATE_PARENT, 1, + desc->div); + } + WARN_ON_ONCE(1); + return ERR_PTR(-EINVAL); +} + +static int zx_clk_validate(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data) +{ + const struct zx_parent_desc *parents; + unsigned int i, p, num_parents; + struct clk *clk; + + /* + * Sanity check: Make sure all parents are there and write a clear messag= e rather than + * leave potential orphans. + * + * This check is unusual in clock drivers. It is in this driver because t= he clock tree is + * based on manual reverse engineering rather than generated from a SoC d= atasheet. + */ + for (i =3D 0; i < data->num_clocks; ++i) { + switch (data->clocks[i].type) { + case ZX_CLOCK_PLL: + parents =3D data->clocks[i].pll.parents; + num_parents =3D data->clocks[i].pll.num_parents; + break; + + case ZX_CLOCK_FIXED_DIV: + parents =3D &data->clocks[i].fixed_div.parent; + num_parents =3D 1; + break; + + case ZX_CLOCK_MUX: + parents =3D data->clocks[i].mux.parents; + num_parents =3D data->clocks[i].mux.num_parents; + break; + + case ZX_CLOCK_DIV: + parents =3D &data->clocks[i].div.parent; + num_parents =3D 1; + break; + + case ZX_CLOCK_GATE: + parents =3D &data->clocks[i].gate.parent; + num_parents =3D 1; + break; + + default: + return dev_err_probe(dev, -EINVAL, "Invalid clock entry %u\n", i); + } + + for (p =3D 0; p < num_parents; ++p) { + switch (parents[p].type) { + case ZX_PARENT_FW: + clk =3D of_clk_get_by_name(of_node, parents[p].fw_name); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "Input clk %s failure\n", + parents[p].fw_name); + clk_put(clk); + break; + + case ZX_PARENT_ID: + if (parents[p].id >=3D i) + return dev_err_probe(dev, -EINVAL, + "Clock %u has parent %u\n", + i, parents[p].id); + break; + + default: + return dev_err_probe(dev, -EINVAL, + "Clock %u has unexpected parent of type %u\n", + i, parents[p].type); + } + } + } + + return 0; +} + +int zx_clk_common_probe(struct device *dev, struct device_node *of_node, + const struct zx_clk_data *data) +{ + struct clk_hw_onecell_data *exports; + struct clk_hw **clocks; + struct regmap *map; + unsigned int i; + int res; + + res =3D zx_clk_validate(dev, of_node, data); + if (res) + return res; + + map =3D device_node_to_regmap(of_node); + if (IS_ERR(map)) + return PTR_ERR(map); + + clocks =3D devm_kcalloc(dev, data->num_clocks, sizeof(*clocks), GFP_KERNE= L); + if (!clocks) + return -ENOMEM; + + if (data->init) { + res =3D data->init(map); + if (res) + return res; + } + + for (i =3D 0; i < data->num_clocks; ++i) { + struct clk_hw *hw; + + switch (data->clocks[i].type) { + case ZX_CLOCK_PLL: + hw =3D zx_clk_register_pll(dev, map, &data->clocks[i].pll, clocks); + break; + + case ZX_CLOCK_FIXED_DIV: + hw =3D zx_clk_register_fixed_div(dev, &data->clocks[i].fixed_div, clock= s); + break; + + case ZX_CLOCK_MUX: + hw =3D zx_clk_register_mux(dev, map, &data->clocks[i].mux, clocks); + break; + + case ZX_CLOCK_DIV: + hw =3D zx_clk_register_divider(dev, map, &data->clocks[i].div, clocks); + break; + + case ZX_CLOCK_GATE: + hw =3D zx_clk_register_gate(dev, map, &data->clocks[i].gate, clocks); + break; + + default: + return -EINVAL; + } + + if (IS_ERR(hw)) + return dev_err_probe(dev, PTR_ERR(hw), "Failed to register clk %u\n", i= ); + + clocks[i] =3D hw; + } + + exports =3D devm_kzalloc(dev, struct_size(exports, hws, data->num_exports= ), GFP_KERNEL); + if (!exports) + return -ENOMEM; + exports->num =3D data->num_exports; + + for (i =3D 0; i < data->num_exports; ++i) { + if (data->exports[i] >=3D data->num_clocks) + return dev_err_probe(dev, -EINVAL, + "Export %u points to out of range clock %u\n", + i, data->exports[i]); + + exports->hws[i] =3D clocks[data->exports[i]]; + } + + devm_kfree(dev, clocks); + + return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, exports); +} +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..8137185f497f --- /dev/null +++ b/drivers/clk/zte/clk-zx.h @@ -0,0 +1,137 @@ +/* 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 CLK_ZX_PLL_PREPARE_IS_ENABLE 1 +#define CLK_ZX_MAX_PARENTS 8 + +enum zx_parent_type { + ZX_PARENT_FW, + ZX_PARENT_ID, +}; + +struct zx_parent_desc { + enum zx_parent_type type; + union { + const char *fw_name; + unsigned int id; + }; +}; + +#define PARENT_FW(_name) { .type =3D ZX_PARENT_FW, .fw_name =3D (_name) } + +#define PARENT_ID(_id) { .type =3D ZX_PARENT_ID, .id =3D (_id) } + +static inline struct clk_parent_data zx_get_parent(const struct zx_parent_= desc *p, + struct clk_hw * const *clocks) +{ + struct clk_parent_data ret =3D {}; + + switch (p->type) { + case ZX_PARENT_FW: + ret.fw_name =3D p->fw_name; + ret.index =3D -1; + return ret; + + case ZX_PARENT_ID: + ret.hw =3D clocks[p->id]; + ret.index =3D -1; + return ret; + } + + WARN_ON_ONCE(1); + return ret; +} + +struct zx_pll_desc { + const char *name; + const struct zx_parent_desc *parents; + unsigned int num_parents; + unsigned long rate; + u16 reg; + u16 flags; +}; + +struct zx_fixed_divider_desc { + const char *name; + struct zx_parent_desc parent; + unsigned int div; +}; + +struct zx_mux_desc { + const char *name; + const struct zx_parent_desc *parents; + unsigned int num_parents; + u16 reg; + u8 shift, size; +}; + +struct zx_div_desc { + const char *name; + struct zx_parent_desc parent; + u16 reg; + u8 shift, size; +}; + +struct zx_gate_desc { + const char *name; + struct zx_parent_desc parent; + unsigned long flags; + u16 reg; + u8 shift; +}; + +enum zx_clock_type { + ZX_CLOCK_INVALID =3D 0, + ZX_CLOCK_PLL, + ZX_CLOCK_FIXED_DIV, + ZX_CLOCK_MUX, + ZX_CLOCK_DIV, + ZX_CLOCK_GATE, +}; + +struct zx_clock { + enum zx_clock_type type; + union { + struct zx_pll_desc pll; + struct zx_fixed_divider_desc fixed_div; + struct zx_mux_desc mux; + struct zx_div_desc div; + struct zx_gate_desc gate; + }; +}; + +struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regm= ap, + const struct zx_pll_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regm= ap, + const struct zx_mux_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *= regmap, + const struct zx_div_desc *desc, + struct clk_hw * const *clocks); +struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *reg= map, + const struct zx_gate_desc *desc, + struct clk_hw * const *clocks); + +struct zx_clk_data { + int (*init)(struct regmap *map); + const struct zx_clock *clocks; + unsigned int num_clocks; + const unsigned int *exports; + unsigned int num_exports; +}; + +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..fc76c6524a16 --- /dev/null +++ b/drivers/clk/zte/pll-zx.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ + +#include +#include +#include +#include + +#include "clk-zx.h" + +struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regm= ap, + const struct zx_pll_desc *desc, + struct clk_hw * const *clocks) +{ + return ERR_PTR(-ENODEV); +} --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f26.google.com (mail-wr2-f26.google.com [74.125.225.90]) (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 6F40A3BED46 for ; Sun, 27 Sep 2026 20:14:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.90 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540069; cv=none; b=oqmtKYlNW1O9zBFyTBOljc6mYcvP53zV/LIznXRNmHMfqYZHS3XDW54wPkL4Ga1+NViT1cZiUAEHuVm+GsCdGbkUSv6O7204f0TIs/IMZjiCN4Ox42/rETZfmhQ6FmRwbB90n4ZPxlYR221djefnTaq9nvFXHixv9vjfh5e/HlM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540069; c=relaxed/simple; bh=xrGH6M3bJ8igFRHyhrXgCckCWaOGHyA4X0Rt+3qQ9UA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YYJSR8byvQwzCxnbv/xOk1HMkPQ92SyexbShMaMu49PLM3LJ9oFOujYjoxZNmDU/keJOYMUsn6FOGLXaz00X3jaY0KhIYiEJH2rZiINe1roDYPmZc4cflZRxpL14zIq3mcS6ypPXhgI4ngwPBYAbMZAYMxmc3bL/QIFuduwThuM= 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=QdOOETRD; arc=none smtp.client-ip=74.125.225.90 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="QdOOETRD" Received: by mail-wr2-f26.google.com with SMTP id ffacd0b85a97d-4843f22dc83so1994189f8f.1 for ; Sun, 27 Sep 2026 13:14:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540065; x=1791144865; 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=mp6wBBpQsQq5uAJhpRvAfRITa5kH/kGE8kQJrdjyLoY=; b=QdOOETRDy2B4SqByUk5r6JUdngmxeF97hURyyrLtPrpdmGFGLcP4CjVegnvig2Xn23 ZAdgKFC2DY4/5+dr9aPhf8JKuAAu/VioNeygkWkzDznxGAZ50jMXKsiU+pcU7SBPsM7S VgK8nWJn5exRgubrF7/FQsnMLx0W71Iq0wXMkjvt7uGV7e4Z/J7jTS9TVpxhXfoy/Bgw 5wykndLk3sR0HAZmNJN106gjJ+0M4F7v/C+HL53XTw5HDHIM6sjhfQo/FuEKuZiUkEmA BHS7L+gw6rB3kXAY8kKvvpWiyzRnfSj7kvMlwHUF06jzPlHRoHn4KO0kcbOL3T+07zdM 7ssg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540065; x=1791144865; 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=mp6wBBpQsQq5uAJhpRvAfRITa5kH/kGE8kQJrdjyLoY=; b=FWmi3EwCgzQx+ZoKUBlZSiKDnb+3MZ6Esu4qZ6sq0fhNeR3hWO7CT/HNvoWZliMQt0 EYbd1ElzBqeM7TFI775NoigkEzu7JV3IaL6tHlSfGBx8yoE7Gg95Otwd3wgvxSMUSwxY iEhQr6J24apauP9M2h7rKQ7F+6TjI4DztZAKxE5mD9Yy2ZnRCIaXxYsx6Tzq2ZksTJL/ tq7YX+XN4NiN8t9Rm4I2dwt4qD6qXWmgmWWKHjKtae/Hl6vYLPcDs6tZLWmPLtL/OJfP K+WuWw+jQ0AWuxPAmDuapY1nc3+GMoViooyOe73uNs8wG2hgrwxR+oCc3xUuHntGexk1 o69w== X-Forwarded-Encrypted: i=1; AKwUvBztQpVmS9Fkemy4T/UxWa5HBtoXsr6UdoEhhOF2tcLNKshB2yC+JMOsif5nNAcjMYZRtvvyJkHCHQtEkNM=@vger.kernel.org X-Gm-Message-State: AFq9FYJ9KmjUYomTIHQh1zETb/Ay4WPvbwEx59X0OAhbQpG7gZnGvOTg pRMZ2D5ov3WiixEpr9lx5LvDgOcBkcYl/Y9vAlHx+44CYjE0LcILyZ64ZlDhO+iBMPLGRg== X-Gm-Gg: AYBFou2MfuUlzJnib2s4O+IqYd2gPlgHVAQuu3veWHLLd879IllBSp05oaW6YJnXFtS RkaSD2bUSL0H6v2a2RQ7Bl4zHFMLvkaeNRQmiXf/2oHsx23FfCdMWbP8CCgCMwkJmQ0yaS3tr8X 8rTFoPkI0vZRgSH7xxi9pUU8ut53vuqVYci+COORK1qkQx1ZKhqkm7Vim9U2fOKLoWZE9pu1CPf 5eftENrTsXLWfI/X0iZS+d9nWJPlR0TwU3QvRLPWA+N5LL4/sV8HnjvMAiqkDayy1TAFGb39DZE KyncuXW7SVjnwl7wIY34zPu2afSA4BmbIUqsLxdhWgEwx3rvaz+b3aRX2fE26ROp64GtXqNjLQM 6vjbvgzmouWCDKtZ5C66wug1ksUPZ/bdc5qea3fZiDLNSzPmR7uAPXq41wc8vjtYpL5HbXJUImw Ej5UA1Jb9ibBZ4s+9grSqKzH9cakZoywZuamNYGIpAEXZOJa+7vN4xtnolT0r7/Mzguxkvw1nsI JgQAJmj X-Received: by 2002:a05:6000:4026:b0:487:6ef:86b8 with SMTP id ffacd0b85a97d-48872ad79fcmr22373801f8f.49.1790540064665; Sun, 27 Sep 2026 13:14:24 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:24 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:35 +0300 Subject: [PATCH v13 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: <20260927-zx29clk-v13-7-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7927; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=xrGH6M3bJ8igFRHyhrXgCckCWaOGHyA4X0Rt+3qQ9UA=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1KioYaMuFgpmk6o3fz/pJlbFL7ofGVcvUv 9YBLo9tepuJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKxXhAAmPNWee2nVYKvuarHBJtpA5q2EvCQxub WzX5XFy1zIzCVV4rrqRfYZQaYjH5m59qLFa2MrqCFiaOw2VUR/4tymITW2j5MOTnLNem2qEwUos l6P3pcpMFV8oY//IS9u7O9x07KA23kxd+bBA0HGYTw/z21YAAHOTlTzfU42KiAc8j7vOqnhscFB eIVBMCPwt+DLUYXyPz4G4LuARN2ZKT1Z4QWqd3DrYxFchl9JskT8L2sIHB/P2FUeUkYT7Q6bAyj r45q+q8OWzIycB/9dwKHvaR1mjOujAOJu2lvYvSosVE+EmOLZ6EjgBhW9p9qt664Ai5FGcrxBZw K9ACtstEZclDtByWBpS9qkZuZvfbbB8ZKSvMmZ62uH7mCjJWNpOc7jINbxdHnZwu7I6YoTT+BA7 0fMpHZcqqx+XxZ38ZzLt++EU0B1Cr3XxsINWiIZ39MTWaRgjJJygk8IzJ2dRqah38yqbDeeJNCi 7ZP6X2S+5xvebdpWA8b470J/oINhom6vAYa+nLCtCsBqVpDpZCr5v0roR9jEkL50B0bsfIkdNW0 czrB89ZdWRX8KJA/ngiKBjKlt8A1f0awyGGwqW90eb7bq05LI5bEWqu6q0S0LAeOJaz31e/L43Z fTnzO8SuYHleZEytxND9wB1cAT9HBkIFxKSTmIGkvIXchWA3dNpA= 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. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- 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 like clk-gate.c I'll copy that and try to use it as unmodified as possible. Version 9: Register single clocks per function invocation, remove ZX297520V3_CLK_NO_EXPORT again Version 8: Use ZX297520V3_CLK_NO_EXPORT instead of 0 for unexported clocks. 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 | 219 +++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 212 insertions(+), 7 deletions(-) diff --git a/drivers/clk/zte/clk-regmap.c b/drivers/clk/zte/clk-regmap.c index 80332dba97f6..022b2be7bb3d 100644 --- a/drivers/clk/zte/clk-regmap.c +++ b/drivers/clk/zte/clk-regmap.c @@ -1,32 +1,237 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) 2018 BayLibre, SAS. * Copyright (c) 2026 Stefan D=C3=B6singer */ =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, +}; + struct clk_hw *zx_clk_register_gate(struct device *dev, struct regmap *reg= map, - const struct zx_gate_desc *desc, - struct clk_hw * const *clocks) + const struct zx_gate_desc *desc, struct clk_hw * const *clocks) +{ + struct clk_parent_data parent =3D zx_get_parent(&desc->parent, clocks); + struct clk_init_data init =3D {}; + struct zte_clk_regmap *clk; + int res; + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name =3D desc->name; + init.ops =3D &zte_clk_regmap_gate_ops; + init.parent_data =3D &parent; + init.num_parents =3D 1; + init.flags =3D CLK_SET_RATE_PARENT | desc->flags; + clk->hw.init =3D &init; + clk->map =3D regmap; + clk->reg =3D desc->reg; + clk->shift =3D desc->shift; + clk->size =3D 1; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; +} + +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) + return 0; /* Gives a hint that something is wrong */ + + 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) { - return ERR_PTR(-ENODEV); + 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, +}; + struct clk_hw *zx_clk_register_divider(struct device *dev, struct regmap *= regmap, const struct zx_div_desc *desc, struct clk_hw * const *clocks) { - return ERR_PTR(-ENODEV); + struct clk_parent_data parent =3D zx_get_parent(&desc->parent, clocks); + struct clk_init_data init =3D {}; + struct zte_clk_regmap *clk; + int res; + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name =3D desc->name; + init.ops =3D &zte_clk_regmap_divider_ops; + init.parent_data =3D &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->reg; + clk->shift =3D desc->shift; + clk->size =3D desc->size; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; } =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, +}; + struct clk_hw *zx_clk_register_mux(struct device *dev, struct regmap *regm= ap, - const struct zx_mux_desc *desc, - struct clk_hw * const *clocks) + const struct zx_mux_desc *desc, struct clk_hw * const *clocks) { - return ERR_PTR(-ENODEV); + struct clk_parent_data parents[CLK_ZX_MAX_PARENTS]; + struct clk_init_data init =3D {}; + struct zte_clk_regmap *clk; + unsigned int i; + int res; + + if (WARN_ON(desc->num_parents > ARRAY_SIZE(parents))) + return ERR_PTR(-EINVAL); + + for (i =3D 0; i < desc->num_parents; ++i) + parents[i] =3D zx_get_parent(&desc->parents[i], clocks); + + clk =3D devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) + return ERR_PTR(-ENOMEM); + + init.name =3D desc->name; + init.ops =3D &zte_clk_regmap_mux_ops; + init.parent_data =3D parents; + init.num_parents =3D desc->num_parents; + clk->hw.init =3D &init; + clk->map =3D regmap; + clk->reg =3D desc->reg; + clk->shift =3D desc->shift; + clk->size =3D desc->size; + + res =3D devm_clk_hw_register(dev, &clk->hw); + if (res) + return ERR_PTR(res); + + return &clk->hw; } --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f35.google.com (mail-wr2-f35.google.com [74.125.225.99]) (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 23393353A7E for ; Sun, 27 Sep 2026 20:14:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.99 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540076; cv=none; b=a67G+kSr8v9cF/Jbo4rke8anNG81MdsE/tBKcZjhmCxHQylZQK64lYor/TyNpWufdbsQUefVEgyzVH/yc/DEnhh0xTDh8q49TYIIZqfbEnUYPvW1yr1kCJSMJD0/gH7yiPOZXDYV/2VHOHv/CpzTb7TicXHFe2lPK9el+UK73I0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540076; c=relaxed/simple; bh=Zsc3l1UBoa6nhcnX1b0CUglNiu+eSJwVSqjjG25jJVs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=isgxuYCvQ6djwlt604+tRmyTqgsDLN5y/5+bg4iI6WIcZU1PRHg5SKf7eom4OhHTpxXqT3eZYjcMKWlM+jdYkBEajQcM3sB2qaMH/HmyojZGmAbzJnfcnILUQ+/CdULD3SnjSFbiznM1i6gobVcYL+v+tfh/oKjWGlw4WZw2PQI= 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=GJMHI0ss; arc=none smtp.client-ip=74.125.225.99 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="GJMHI0ss" Received: by mail-wr2-f35.google.com with SMTP id ffacd0b85a97d-4887f690df6so1587057f8f.1 for ; Sun, 27 Sep 2026 13:14:31 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540070; x=1791144870; 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=V/KRWurRoJ6BhV7CyY/li23caz2OE8w69+h4Sm4TPoU=; b=GJMHI0ssaJK902GOrrIT4HAM6DFnsqafIMgiNxzZwBX4yRCP7EkfdqEM3MWCPN2m/s rTQROKPnbuwDEtIp8NhqX9SPMRuGrZkHARTaiklNiQjsC1icJHmjqLekK50uctzWlV+i Gpv9OusV7BgBwuR7gGGY07NyBM3xvwmmPCzlMzXQC5/9JK0ahL1X+ykOQHVQX39kow94 PcqZyjgmidVrwVrhbAvQMJ/Qpiza5cq7cHbj9mTCVpBGnCsaLUJ81JziN3VJFFkdIUT2 sFN9G5wibJE4OMfgCK0qaclrqVaoPOY1f7NsHAgxcmCpJ/QlLOP+ce1b9aJnTQTdoWt2 Dj/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540070; x=1791144870; 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=V/KRWurRoJ6BhV7CyY/li23caz2OE8w69+h4Sm4TPoU=; b=Dj+wpEkb0ZrmD/0g5L/Lpyp6vu9fKKQTz+96vhCF8txRIxDKnbOWMEngh1N94SzBfC 1SIuqLOyB5IgVmoVaSN4njmCbnO5+XK/u8AeyFRUcOh2MIPYT/47YioaLo/PkyAweeAZ SWlxdhgquq0U1XPT2RYNkdnLnowRdzQoV3IQ8AagyxK/3welTD0Vw3u8un9uNBbtO4/H jthMoeug0WKr9XnH4H9+uDm/JpTG0m+raQ9xem7UI9Js/hJqzTOmP/xh8wdLg55fN5/b xl551YcxfUzGO8Hh//NVSNhWImW8kKpF9SYJyrTHvhShmlatUZYIiCGXS3CqXB/Jl5MS BHXA== X-Forwarded-Encrypted: i=1; AKwUvBzib47MNfXV3DLvNYa8UwES2v/cDbUszSlL+oNrhBLiT8wb397lsImJcsGeFtOGVEyf/n9rnfmCk9u1zIU=@vger.kernel.org X-Gm-Message-State: AFq9FYK8LYRk6VNxFy9AM2HKERd6Z5+PsLK/ZDWZ3cOF2pYUbUCgpQ9S ln6v6x/+HCCn1wYoPzqBDN2pWE0m+qgAvthatBOoSuceSU86jOLP8LjO X-Gm-Gg: AYBFou2qB1a1qkSspVXY3G0lOVCSF4H6f1PlEIRIs5FuLaveg00hrhQzokNeWsA+y6e kBknhnzYHs8wZaWGBqwyowVHdeVHNJeSX/9w54VnE5Tm4uRzMlSZJyLLSUpGf5Y4HKgq6z7uIft SQQ41B6odb6FlGLai5oWz2IbdevUlgCPuILCI8dW3WKPsJmzIBP/2YIEBpTYbX2pSdJ7AYTkghC vMFkUSkejfXuAhI263+ZGO83T7uf5HmKmt8C2dQ82ZaGsTmuPzQ1skQ/7lYcMb84p78DlFpymzV ljpJIhXCaKIqj7HdVHi0ynlGVmmazrE6suqtn55S08O8ZYhUCGSXwcVZ3zbGEWS5mZ1jjbOa1ni TQn4IjXMMa2SgySajCUavdBVQSRjda05W9d7vuLbZSKkVQWHXNVOKBmr1DlBJYnUcrPDERSiii0 sVO/lt5AVzO9XTY8sHlxeXAK6BoDXx8iyPI/oysalspudDowFKHweN29nWP5G3WUywUeq0liD96 NvIMFP/ X-Received: by 2002:a5d:5d88:0:b0:488:8859:b0b4 with SMTP id ffacd0b85a97d-4888859b272mr7241100f8f.9.1790540069624; Sun, 27 Sep 2026 13:14:29 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:29 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:36 +0300 Subject: [PATCH v13 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: <20260927-zx29clk-v13-8-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=24260; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=Zsc3l1UBoa6nhcnX1b0CUglNiu+eSJwVSqjjG25jJVs=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1Qid3kotjsK6WmIqSo26i3kB9509q9mD9b a7+81IDIIGJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKrvxAAlr/7HFgebCzI2hShDi8z5g83O3kaP+O X47fD+ED78oExl+VGSKYrzR7VhPS88dCbkZkPfuhgPD3VVIT3szAo4ks8kHYvLhWP29spGDe7c5 NI9lmwi+YaC/8Q/ewBZEf61pW38pgNn7z7jJjGQHWijewsSAvhtYlz0ErodOPXNp4HDothyeBwV QRrT+TGoUNhHu/pfM69gcsPXdwJgSLPGrdKs6aAEDz4QZSzxpqdhJ8dtpPVgJhxBEUDRK3djIPq X9qTiJOBEnjwtJKqMNV5ejxdsCNw0boN8P21MXR9f+i4zoTgz/pOfBhqUvQqI0yscq7+tdUpunt JDYPQP11rj9utSvVcLJ+EZVoPpz0njOk1mM4dKzxuz9g+twhj8Jqq9HY0M+eZvsefTacpYS12RT 0IZ1rJcmJZsF+Wv4SoE12Oft+63ZyRoh8T3MoIF0CphXl/u9qbCCiyHtAnoKRbrJkoBxeV05J8a 0b8AJPjVI0ewMPM9N0xmQRylDDXJGKxpXHX9YPVb9QFx7Amt8OpRISTs4A+irHTTcGPVdmbWJEU 83E9PbxoS1MQNSuJy8fitv4q4wBHcJBbHBUPwdx/weeuFQdaXc9/4xzOdyFC1ynJPs/MNU/9Hfq BZrYFz/HE7fk1oaQFbpdoObcJG6gthSasBjWQi/3bkrMuLw9ZCR0= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This patch adds code to decode and program PLL settings on ZTE's zx297520v3 SoC. The PLLs on this SoC are usually programmed to static values by the boot loader. The only situation where .set_rate matters is dpll, which is not programmed in some cases. The bootloader always sets fixed rates though: 624 MHz for mpll, 200 for gpll, 480 for upll. Parsing the bootloader-programmed values allows the clock driver to fill the clock tree with appropriately clocked parent clocks instead of registering fixed clocks with hardcoded rates. I only tested the code on zx297520v3. From looking at the hardcoded PLL values in the old zx296702 / zx296718 code I believe that these PLLs use the same encoding, so the code added by this patch should be reusable and the file has a relatively generic name pll-zx.c. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- Version 13: unchanged Regarding Sashiko's concern about selecting "RATIONAL" for rational_best_approximation: COMMON_CLK, which is required to enable the code in this patch already enables RATIONAL. drivers/clk/zte/Kconfig is only included if COMMON_CLK is enabled. I don't think it can lead to build problems even with COMPILE_TEST. qcom clocks enable RATIONAL on their own, so I guess I can do the same if desired. Many other clock drivers use rational_best_approximation without that though. Version 11, 12: Unchanged Version 10: Use FIELD_GET / FIELD_PREP, remove now redundant _SHIFT defines. Version 9: *) Take req->min_rate and req->max_rate into account when looking for possible PLL configurations (sashiko). In practice the code will still only ever encounter a fixed request to set dpll to 491.52 MHz. *) The same code style changes Brian requested on the other clk patches. Version 8: *) Document the behavior of unlocked PLLs better: They don't pass through their reference/parent, but pass through the fixed clock-26m oscillator, even if their reference clock is something else. *) dpll has working fractionals. Add this in the comment, but there is no actual code support for it - the LTE hardware doesn't need it. As for Sashiko's comments on the .set_rate implementation: In practice .set_rate will only ever set one rate, 491.52 MHz for dpll. All other PLLs are bootloader configured. Dpll could be handled by writing a magic constant into its config. I want to have the rate finding code as documentation, and maybe there is more elaborate future use for it (e.g. more flexible underclocking), but attempts to handle eventualities like rate searches or misconfigured bootloader values would be dead code. 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 | 564 +++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 561 insertions(+), 3 deletions(-) diff --git a/drivers/clk/zte/pll-zx.c b/drivers/clk/zte/pll-zx.c index fc76c6524a16..d3687495d06c 100644 --- a/drivers/clk/zte/pll-zx.c +++ b/drivers/clk/zte/pll-zx.c @@ -3,16 +3,574 @@ * Copyright (C) 2026 Stefan D=C3=B6singer */ =20 +#include #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 Lauterbach 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 26 MHz and 32 kHz clocks can be easily observed with the timers. Th= e 104 MHz output can be + * observed through the UART. One 122.88 MHz clock can be observed through= the TDM device. All + * others can only be indirectly inferred, e.g. by comparing CPU speed or = SDIO transfer 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 clock-26m through unmodified. Whet= her 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 ~400 us to ~300 us). + * Bit 24: Bypasses the VCO, but still applies refdiv and postdiv. Doesn't= matter if PLL_DISABLE=3D1. + * + * NB: Some PLLs have an automatic bypass logic that forwards clock-26m (R= EGARDLESS of reference) + * when they don't have a lock, regardless of reason. This can be triggere= d by disabling the PLL, + * setting an out-of-spec VCO frequency or disabling the parent. This shou= ldn't matter in regular + * operation, but caused me some confusion when reverse engineering the cl= ock tree. E.g. clock-26m-> + * unknownpll(disabled) -> dpll(enabled) counterintuitively results in a 2= 6 MHz output clock. + */ + +#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_BYPASS BIT(24) +#define ZX29_PLL_REFDIV_MASK GENMASK(23, 18) +#define ZX29_PLL_FBDIV_MASK GENMASK(17, 6) +#define ZX29_PLL_POSTDIV1_MASK GENMASK(5, 3) +#define ZX29_PLL_POSTDIV2_MASK GENMASK(2, 0) + +/* + * The second register has a 24 bit fractional value, which only matters w= hen ZX29_PLL_DSM_DISABLE + * is not set, and only seems to matter for dpll. ZTE's firmware does not = make use of the fractional + * and it is unimplemented in this driver. Experimental testing confirms t= hat it has an impact on + * dpll. + * + * Bits 27:24 contain more flags: + * + * Bit 27: Setting ZX29_PLL_DACAP slows down the lock time and obviates 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 entire= ly - 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) +#define ZX29_PLL_FRACT GENMASK(23, 0) + +/* + * 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 300 us and 500 us */ + 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 FIELD_GET(ZX29_PLL_REFDIV_MASK, setting); + fbdiv =3D FIELD_GET(ZX29_PLL_FBDIV_MASK, setting); + postdiv1 =3D FIELD_GET(ZX29_PLL_POSTDIV1_MASK, setting); + postdiv2 =3D FIELD_GET(ZX29_PLL_POSTDIV2_MASK, setting); + 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, unsigned long min_rate, unsigned long max_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 divider values (1-7)*(1-= 7) to look for + * valid VCO target frequencies and then looks for refdiv and fbdiv value= s to achieve 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 FIELD_PREP(ZX29_PLL_FBDIV_MASK, fbdiv); + setting |=3D FIELD_PREP(ZX29_PLL_REFDIV_MASK, refdiv); + setting |=3D FIELD_PREP(ZX29_PLL_POSTDIV1_MASK, i); + setting |=3D FIELD_PREP(ZX29_PLL_POSTDIV2_MASK, j); + out =3D zx29_pll_get_rate(pll, parent_rate, setting); + + if (out < min_rate || out > max_rate) + continue; + + 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 FIELD_PREP(ZX29_PLL_FBDIV_MASK, best_fbdiv); + setting |=3D FIELD_PREP(ZX29_PLL_REFDIV_MASK, best_refdiv); + setting |=3D FIELD_PREP(ZX29_PLL_POSTDIV1_MASK, postdiv1); + setting |=3D FIELD_PREP(ZX29_PLL_POSTDIV2_MASK, postdiv2); + 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 practice it shouldn't matter though. Dpll is always configured to a= fixed frequency + * and is the only clock with a switchable parent. + */ + 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, r= eq->min_rate, + req->max_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_dbg(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); + u32 setting; + + /* + * TODO: Implement gradual PLL rate change. PLLs can be changed while the= y are running and + * downstream hardware is generally fine with that. The exception is DRAM= , which reads + * incorrect values if changed too fast. + * + * Changing the mpll rate is potentially useful for over/underclocking. G= ating mpll is + * unrealistic because too many devices depend on it. + */ + setting =3D zx29_pll_calc_values(pll, parent_rate, rate, rate, rate); + if (!setting) + return -EINVAL; + + dev_dbg(pll->dev, "%s: Setting new configuration: 0x%08x\n", clk_hw_get_n= ame(hw), setting); + + return regmap_update_bits(pll->map, pll->reg, 0x00ffffff, setting); +} + +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 FIELD_GET(ZX29_PLL_PARENT_MASK, val); + 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 parent =3D FIELD_PREP(ZX29_PLL_PARENT_MASK, index); + int res; + u32 val; + + res =3D regmap_update_bits(pll->map, pll->reg, ZX29_PLL_PARENT_MASK, pare= nt); + 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 parent) { + 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; + u32 val; + + dev_dbg(pll->dev, "%s: initializing\n", name); + + /* + * The fractional value is not yet implemented. It works at least with dp= ll, but I have + * never seen it used on actual hardware. + */ + res =3D regmap_read(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, &val); + if (res < 0) + return res; + + if (val & ZX29_PLL_FRACT) { + dev_warn(pll->dev, "%s: unsupported nonzero fractional value 0x%08lx\n", + name, val & ZX29_PLL_FRACT); + } + + /* + * 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; + + res =3D regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res > 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 + * inadvertently enable PLLs without .enable being called. + */ + res =3D regmap_set_bits(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, + ZX29_PLL_POSTDIV_OUT_DISABLE); + } + + return res; +} + +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; + u32 val; + + dev_dbg(pll->dev, "%s: initializing, prepare-is-enabled\n", name); + + res =3D regmap_read(pll->map, pll->reg + ZX29_PLL_REG2_OFFSET, &val); + if (res < 0) + return res; + + if (val & ZX29_PLL_FRACT) { + dev_warn(pll->dev, "%s: unsupported nonzero fractional value 0x%08lx\n", + name, val & ZX29_PLL_FRACT); + } + + 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, +}; + struct clk_hw *zx_clk_register_pll(struct device *dev, struct regmap *regm= ap, - const struct zx_pll_desc *desc, - struct clk_hw * const *clocks) + const struct zx_pll_desc *desc, struct clk_hw * const *clocks) { - return ERR_PTR(-ENODEV); + struct clk_parent_data parents[CLK_ZX_MAX_PARENTS]; + struct clk_init_data init =3D {}; + struct zx29_clk_pll *pll; + unsigned int i; + int res; + + pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + if (desc->flags & CLK_ZX_PLL_PREPARE_IS_ENABLE) + init.ops =3D &zx29_pll_nodisable_ops; + else + init.ops =3D &zx29_pll_ops; + + if (WARN_ON(desc->num_parents > ARRAY_SIZE(parents))) + return ERR_PTR(-EINVAL); + + for (i =3D 0; i < desc->num_parents; ++i) + parents[i] =3D zx_get_parent(&desc->parents[i], clocks); + + init.name =3D desc->name; + init.parent_data =3D parents; + init.num_parents =3D desc->num_parents; + + /* + * Disallow live reparent, but allow rate changes. PLLs can handle gradua= l changes fine, but + * large ones cause a temporary incorrect output, which can break downstr= eam devices. + * See zx29_pll_set_rate for considerations on that. + */ + init.flags =3D CLK_SET_PARENT_GATE; + pll->hw.init =3D &init; + pll->dev =3D dev; + pll->map =3D regmap; + pll->reg =3D desc->reg; + + res =3D devm_clk_hw_register(dev, &pll->hw); + if (res) + return ERR_PTR(res); + + /* + * Set the PLL rate only if the bootloader left it disabled. Keep the boo= tloader setup + * otherwise. + */ + res =3D regmap_test_bits(pll->map, pll->reg, ZX29_PLL_DISABLE); + if (res < 0) + return ERR_PTR(res); + + if (res > 0 && desc->rate) { + dev_dbg(pll->dev, "%s: setting to %lu Hz\n", desc->name, desc->rate); + res =3D clk_set_rate(pll->hw.clk, desc->rate); + if (res) + return ERR_PTR(dev_err_probe(dev, res, "%s: failed to set rate\n", + desc->name)); + } + + return &pll->hw; } --=20 2.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f13.google.com (mail-wm2-f13.google.com [74.125.225.141]) (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 7249C3BCD26 for ; Sun, 27 Sep 2026 20:14:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540085; cv=none; b=VM7lBFKmv3IG7MO4Si8NMOlCfwsaWdlzGLc+s4aFNhcQGN4auPjLepbGfsfNnr702ElmndGiQjXn99MaB4PZY9sgjx3ca+cVrbhSkfHuwRKw48J0Jz38kUvuEUVcy6woR82tEiJ+AjKuKVBf11norLZmp7XgP0o5SyvNr/7bcZI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540085; c=relaxed/simple; bh=M3uS7AyMk5NHFVwi4dJz7wVHgdnNVvngomKJTxby+n0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cUCk25xknN/qwq1b5/IdKUIjivP23QYlfrEhfqhRd7gOt645slx3g4VNhTW4zG555ejIHJ9knK/R3Ims+aZGtVnrUCcNvEozwGx6IasjMchrnCXU1fpUqHiWsVbJsdAjK5T/EjeHo0wvSCDXnsr7VwCeiTqxJHcZKZvwinOATpE= 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=qKI5TY65; arc=none smtp.client-ip=74.125.225.141 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="qKI5TY65" Received: by mail-wm2-f13.google.com with SMTP id 5b1f17b1804b1-49e83a388f8so17866565e9.1 for ; Sun, 27 Sep 2026 13:14:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540077; x=1791144877; 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=C21zVOwuoQyHgpBPsxP9ROh2fBHCHBJsurZmSoHVBEk=; b=qKI5TY65Wb3ropZ2ClIKk4wC58oSTzCiUFlHvOrQLRDWF14GykTHel/J0dQ6sv+aT2 T3S7rgDetfxn8nTSC/2pcU8/g9bnIPmdXaSyTL6ybW3sb5BQIM9j5Jjfg+cbLz5h8DR6 qUWrJ/w2MVQPu4lbwBawGLAeaA6RVndTlkRI10W6oORsTFivTa4Mo0opA9jbOAHmbiWi MFVqXSujV/BitBDwQjtDl07ASGtMvBGQrn3tsSyRFwyjatGgP0pHX7FvC0hXA4RI785L O9HEirz4hQoMwdFOzxG00F5UvxaCZytLtuSYzyUvOy0u3+gR3SDhS3QltEGAPhdi/wQ2 6PBA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540077; x=1791144877; 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=C21zVOwuoQyHgpBPsxP9ROh2fBHCHBJsurZmSoHVBEk=; b=dwfjDN2xqFmck8TfD3WrPX/6Po98yk0AEVF0ZVtKBtwC4eKov+H5tR1DylAQQpSaWw m/jP4Ecf8GHOPozumzzGy6m/Ex0wec2VtX62wGHf4Q23uExRE7f32Qsx/J37/ylAm1l/ iPf+10uCXG0l30spbIwhN+Kz+FCDPbMmp+LdE+37TGcmehNaSAW7bsK+52TwBjido3Mh QnZNFXdA9xSnIZ1u7WKdueSv56tMU0fhZSbuVT5yBiYgMmXng11Xc35SZUsGguXn7AdM CidNbJv0pCP5Go/Jy28+K7+TWF8S7eP7ra0R3aPq/bjZqvbyGrG8quhB931TzOWH1kWD obvg== X-Forwarded-Encrypted: i=1; AKwUvBzGZYEoAX1NXEAU0O+7isWzt05AKE8iAxP+ztme6y9Ggdej5zmayuE9zYwcOY9VBHZeUnJNjK8imJRZ7K4=@vger.kernel.org X-Gm-Message-State: AFq9FYKlaYn9slDGRTcZej9PAodqexWThLZTbDWgQPIU5lF+7FkRs64e 5AjRf2inVU97E6cob6DmoWwvPean1giLBTQhp2qTv3AEKzTUM4Tiy1PE X-Gm-Gg: AYBFou3MZpN2Y96eAjXTwQMeM8bVZiy7RvPA5Pb+NQHNt3m2ZDY8Gs3rj38NqUl93yf cAxgSVIYeUO9DaT20KvI93LcRDfiR4Q9HIhUZwaKNx/dDWJCV6yUL7JBaiRnN4bTRrVyx3ErwCc QHmd1m8f4+heR/ZNFLDcRtHWuSHIqXO/sUtmhF6gjnbLTowSsaIzbmfKk/9WKzGwFWuS8ObGtqA +qYSoTRsE0/KyHovq9Ui7iysaNnW7onLNCZTRgEFuW3HqutyYSXjuIm2wcLhNCexXAGoVlOeCMU y/BZPQiGUleOk6jULj2p8sVey9Uk+VildvXX9Z0vY97qPZWJPCYWdYSvCQa/lDfqVLVP2GmrQyi P3c9q8C9MX9f33jU0rpG2nzZnalOJdiZAK16IiFH6BvLSMBgD36+Pf/QH5UIeb98sFAdiNktpUI C77rGLoLeUVjVxPm55/mc0ZdFqmUGOqzBHGp8ESWLaQDCcTajsr4lYZbZ9Po4ZAiyptOFt6zTgQ SOYEDf8 X-Received: by 2002:a05:6000:1841:b0:488:8087:447a with SMTP id ffacd0b85a97d-4888087476emr13031915f8f.38.1790540076469; Sun, 27 Sep 2026 13:14:36 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:34 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:37 +0300 Subject: [PATCH v13 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: <20260927-zx29clk-v13-9-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=43356; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=M3uS7AyMk5NHFVwi4dJz7wVHgdnNVvngomKJTxby+n0=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1R5owmY6iLQ+6/+ao9SLvwRcN3tbED+zHv 4YPMCj/yPKJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiJokA//QWDWqvwoVgYkv/Lu411Z7nqG3XEj6a+ xMwNrtBcIUwe5HfxdCU3yby9wUbA264I/QBhyuqZnssrhrHNWjrwpoPuqFE/ZECBuDAAwPAJ5TK xYtGV7qq5NIgAp2BN2atYVw47v52WuGPrBSNDQ0FFej5rakxy4Ezk8Kl9IDITlGcghQf+E2zek4 rg+SG5J19Pge7/d93ju3xmPmcDKhAR/ZaQBsxegslGLy5Dq7qBopO+MLAYM3WkCOgDn1BMVhim7 raMT80KIWzHBry35HBaGkF/yMtMRrkLiNaH6vQM512cyyoJOETiZJyVju4cVAxJGdLG4FUu2wwU HuNpt1nv5S2D3b0qHcG5lSP/DsqpeZM9cr2EpdibE4CkNW2vQ13ybVFUIyJaQyD3GyKUZopWBIQ h4C/Qp+0cKwgp6kVItxI/MFDVlTEyecqEGOSPAdCHWo8bizXr7KXmhv/jvRk9P2cjTey0QLfqT6 0xHkqa6W3pcNcUuFbj/Wju29h6cVDw6b3SUxj+Tyz1ZEQjJa3C1nXArT65LysclUgx8Zb/w7Xk5 kpu3rawNRURIh2JMHr1uMSE2fmY/+pPy0x+BwtOGlIVtrMQlwWZjLJq+oQ6nGf3yr53BZTrIR8o frvKYVxhPvlnXVdIByM+sYfHBJ/K1AiaXCXooy7kRoIrXb0d1ESM= 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 whether watchdog expiries cause a board reset. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- Version 13: Unchanged Re Sashiko's concern about the DT node for the MFD child: The clk subsystem anticipates exactly that pattern and uses dev->parent.of_node. Version 12: Improvements on the GSM and LTE related clocks. The GSM clocks in 0x68 are exports for yet another clock controller, which in turn feeds a Infineon PMB8877 based GSM IP. The SIM card reader is a part of this, so it is necessary hardware even if one doesn't care about 2G network access. This work also uncovered one of the previously unknown clocks in the 0x140 distribution gates. The LPM_* clocks have osc26m as their parents. I also updated the comment a bit to reflect new knowledge I found when poking at LTE support. Version 11: Unchanged @Sashiko: As far as my reverse engineering understanding goes AHB_PCLK and AHB_WCLK have the correct parents. With AHB_WCLK gated off either directly or via one of its parents, the USB registers are no longer readable. AHB_PCLK on the other hand is clocking whatever hardware is responsible for eventually transferring the data from the AHB/M0/USB subsection of the board to DDR ram, so clocking AHB_PCLK lower causes lower USB transfer speeds. It doesn't affect the USB controller directly though. Version 9: Link internal parents by an (internal) clock ID rather than names. There should be no difference in the built clock tree compared to Version 8. Version 8: Rename the expected clock name of the fixed oscillators to clock-26m and clock-32k. Sashiko pointed out that "oscXXm" is deprecated, although widespread in existing drivers. Add a define indirection for the AXI candidate=3Dcritical protection. While it holds true in a system with running rprocs, I find it useful for stress testing the clock tree to disable it. Double-checked pclk and wclk bits, fixed incorrect assignments in register 0x54. 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 | 846 +++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 858 insertions(+) diff --git a/drivers/clk/zte/Kconfig b/drivers/clk/zte/Kconfig index 152c2423b8f0..0ccc6edf3c5b 100644 --- a/drivers/clk/zte/Kconfig +++ b/drivers/clk/zte/Kconfig @@ -15,3 +15,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 && (MFD_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..68bfeab84d74 --- /dev/null +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -0,0 +1,846 @@ +// 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"); + +/* + * AXI speed is either determined by a fixed selection in matrix+0x0, bits= 0:2 or by a voting system + * with ballots in matrix+0x120, 0x124, 0x128. The voting system is enable= d by setting matrix 0x12c + * to 1. Otherwise the selection in 0x0 applies. + * + * 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 a child of matrix-osc26m, not a PLL. This can be seen = by gating it off in + * topcrm+0x140. + * + * 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. + * + * Because rprocs may change their selection without notice, all possible = parents of the AXI mux are + * marked critical. This can however obscure bugs in the clock tree. Defin= e ZX297520V3_AXI_CANDIDATE + * to 0 to disable this protection for testing and either not run anything= on the rprocs or make + * sure Linux votes for the fastest rate. + */ +#define ZX297520V3_AXI_CANDIDATE CLK_IS_CRITICAL + +/* + * 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 - usually, but not always, 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 + * enables 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 general clock flow on this board goes from osc26m into the PLLs. Th= e 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 osc26m 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 osc32k is fed to = the timers without + * passing through this gate, even for consumers on matrix/LSP. Topcrm osc= 26m wclks are not gated + * either, but top-consumed PLL clocks are. + */ + +enum top_clock_ids { + ZX_CLK_MPLL, + ZX_CLK_UPLL, + ZX_CLK_DPLL2, + ZX_CLK_DPLL2_D2, + ZX_CLK_DPLL, + ZX_CLK_GPLL, + + ZX_CLK_OSC26M_D2, + ZX_CLK_TOP_MPLL_D2_PREGATE, + ZX_CLK_TOP_MPLL_D4_PREGATE, + ZX_CLK_TOP_MPLL_D5_PREGATE, + ZX_CLK_TOP_MPLL_D6_PREGATE, + ZX_CLK_TOP_MPLL_D8_PREGATE, + ZX_CLK_TOP_UPLL_D12_PREGATE, + ZX_CLK_TOP_GPLL_D2_PREGATE, + ZX_CLK_TOP_GPLL_D4_PREGATE, + + ZX_CLK_TOP_MPLL_D2, + ZX_CLK_TOP_MPLL_D8, + ZX_CLK_TOP_MPLL_D6, + ZX_CLK_TOP_MPLL_D4, + ZX_CLK_TOMATRIX_MPLL_D5, + ZX_CLK_TOMATRIX_MPLL, + ZX_CLK_TOMATRIX_DPLL, + ZX_CLK_TOP_UPLL_D12, + ZX_CLK_TOP_UPLL, + ZX_CLK_TOP_GPLL_D4, + ZX_CLK_TOMATRIX_GPLL_D2, + ZX_CLK_TOMATRIX_GPLL, + ZX_CLK_TOMATRIX_OSC26M, + + ZX_CLK_TOP_MPLL_D2_D4, + ZX_CLK_TOP_MPLL_D2_D13, + ZX_CLK_TOP_UPLL_D12_D2, + ZX_CLK_TOP_GPLL_D4_D2, + + ZX_CLK_M0_MUX, + ZX_CLK_AHB_MUX, + ZX_CLK_TIMER_T08_MUX, + ZX_CLK_TIMER_T09_MUX, + ZX_CLK_TIMER_T12_MUX, + ZX_CLK_TIMER_T13_MUX, + ZX_CLK_TIMER_T14_MUX, + ZX_CLK_TIMER_T15_MUX, + ZX_CLK_TIMER_T16_MUX, + ZX_CLK_TIMER_T17_MUX, + ZX_CLK_WDT_T18_MUX, + ZX_CLK_I2C0_MUX, + ZX_CLK_UART0_MUX, + ZX_CLK_OUT0_MUX, + ZX_CLK_OUT1_MUX, + ZX_CLK_OUT2_MUX, + ZX_CLK_RMIIPHY_MUX, + + ZX_CLK_TIMER_T08_DIV, + ZX_CLK_TIMER_T09_DIV, + ZX_CLK_TIMER_T12_DIV, + ZX_CLK_TIMER_T13_DIV, + ZX_CLK_TIMER_T14_DIV, + ZX_CLK_TIMER_T15_DIV, + ZX_CLK_TIMER_T16_DIV, + ZX_CLK_TIMER_T17_DIV, + ZX_CLK_WDT_T18_DIV, + ZX_CLK_USIM1_DIV, + + ZX_CLK_AHB_PCLK, + ZX_CLK_AHB_WCLK, + ZX_CLK_SRAM1_PCLK, + ZX_CLK_SRAM2_PCLK, + ZX_CLK_PMM_WCLK, + ZX_CLK_PMM_PCLK, + ZX_CLK_TIMER_T08_WCLK, + ZX_CLK_TIMER_T08_PCLK, + ZX_CLK_TIMER_T09_WCLK, + ZX_CLK_TIMER_T09_PCLK, + ZX_CLK_TIMER_T12_WCLK, + ZX_CLK_TIMER_T12_PCLK, + ZX_CLK_TIMER_T13_WCLK, + ZX_CLK_TIMER_T13_PCLK, + ZX_CLK_TIMER_T14_WCLK, + ZX_CLK_TIMER_T14_PCLK, + ZX_CLK_TIMER_T15_WCLK, + ZX_CLK_TIMER_T15_PCLK, + ZX_CLK_TIMER_T16_WCLK, + ZX_CLK_TIMER_T16_PCLK, + ZX_CLK_TIMER_T17_WCLK, + ZX_CLK_TIMER_T17_PCLK, + ZX_CLK_WDT_T18_WCLK, + ZX_CLK_WDT_T18_PCLK, + ZX_CLK_I2C0_WCLK, + ZX_CLK_I2C0_PCLK, + ZX_CLK_UART0_WCLK, + ZX_CLK_UART0_PCLK, + ZX_CLK_USB_WCLK, + ZX_CLK_USB_PCLK, + ZX_CLK_HSIC_WCLK, + ZX_CLK_HSIC_PCLK, + ZX_CLK_RTC_WCLK, + ZX_CLK_RTC_PCLK, + ZX_CLK_USIM1_WCLK, + ZX_CLK_USIM1_PCLK, + ZX_CLK_LPM_GSM_WCLK, + ZX_CLK_LPM_GSM_PCLK, + ZX_CLK_LPM_LTE_WCLK, + ZX_CLK_LPM_LTE_PCLK, + ZX_CLK_LPM_TD_WCLK, + ZX_CLK_LPM_TD_PCLK, + ZX_CLK_LPM_W_WCLK, + ZX_CLK_LPM_W_PCLK, + ZX_CLK_OUT0_WCLK, + ZX_CLK_OUT1_WCLK, + ZX_CLK_OUT2_WCLK, + ZX_CLK_OUT32K_WCLK, + ZX_CLK_RMIIPHY_WCLK, + ZX_CLK_GSM_32K, + ZX_CLK_GSM_26M, + ZX_CLK_GSM_48M, + ZX_CLK_GSM_104M, + ZX_CLK_GSM_156M, + ZX_CLK_ABB_WCLK, +}; + +/* Used for gates where we don't know the parent input(s). Assume general = oscillator */ +static const struct zx_parent_desc clk_unknown =3D PARENT_FW("osc26m"); + +/* For clocks that are known to use the ungated osc26m input */ +static const struct zx_parent_desc clk_main[] =3D { + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc dpll_parents[] =3D { + PARENT_ID(ZX_CLK_DPLL2_D2), + PARENT_FW("osc26m"), +}; + +/* + * 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 struct zx_parent_desc ahb_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D8), /* 78 MHz */ +}; + +static const struct zx_parent_desc timer_top_sel[] =3D { + PARENT_FW("osc32k"), + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc uart_top_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz, sharing M0's and ahb's 0x140 g= ate */ +}; + +/* + * 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 32 kHz, e.g. GPIO + * becomes borderline unusable at 32 kHz. + * + * 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 struct zx_parent_desc m0_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_TOP_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_TOP_MPLL_D2_D4), /* 78 MHz, but different gate than the = ahb 78 MHz */ + PARENT_FW("osc32k"), /* 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 osc26m because it perfectly matc= hes 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 osc26m. I am n= ot 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 struct zx_parent_desc out0_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_ID(ZX_CLK_M0_MUX), +}; + +static const struct zx_parent_desc out1_sel[] =3D { + PARENT_ID(ZX_CLK_TOP_UPLL_D12_D2), /* 20 MHz */ + PARENT_ID(ZX_CLK_TOP_UPLL_D12), /* 40 MHz */ + PARENT_ID(ZX_CLK_OSC26M_D2), /* 13 MHz */ + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc out2_sel[] =3D { + PARENT_ID(ZX_CLK_OSC26M_D2), /* 13 MHz */ + PARENT_FW("osc26m"), +}; + +/* + * 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 struct zx_parent_desc rmii_sel[] =3D { + PARENT_ID(ZX_CLK_TOP_GPLL_D4_D2), /* 25 MHz */ + PARENT_ID(ZX_CLK_TOP_GPLL_D4), /* 50 MHz */ +}; + +#define PLL(_name, _parents, _rate, _reg, _flags) \ + { \ + .type =3D ZX_CLOCK_PLL, \ + .pll =3D { \ + .name =3D _name, \ + .parents =3D _parents, \ + .num_parents =3D ARRAY_SIZE(_parents), \ + .rate =3D _rate, \ + .reg =3D _reg, \ + .flags =3D _flags, \ + }, \ + } + +#define FIXED_DIV(_name, _parent, _div) \ + { \ + .type =3D ZX_CLOCK_FIXED_DIV, \ + .fixed_div =3D { \ + .name =3D _name, \ + .parent =3D _parent, \ + .div =3D _div, \ + }, \ + } + +#define MUX(_name, _parents, _reg, _shift, _size) \ + { \ + .type =3D ZX_CLOCK_MUX, \ + .mux =3D { \ + .name =3D _name, \ + .parents =3D _parents, \ + .num_parents =3D ARRAY_SIZE(_parents), \ + .reg =3D _reg, \ + .shift =3D _shift, \ + .size =3D _size, \ + }, \ + } + +#define DIV(_name, _parent, _reg, _shift, _size) \ + { \ + .type =3D ZX_CLOCK_DIV, \ + .div =3D { \ + .name =3D _name, \ + .parent =3D _parent, \ + .reg =3D _reg, \ + .shift =3D _shift, \ + .size =3D _size, \ + }, \ + } + +#define GATE(_name, _parent, _reg, _shift, _flags) \ + { \ + .type =3D ZX_CLOCK_GATE, \ + .gate =3D { \ + .name =3D _name, \ + .parent =3D _parent, \ + .reg =3D _reg, \ + .flags =3D _flags, \ + .shift =3D _shift, \ + }, \ + } + +static const struct zx_clock zx297520v3_top_clocks[] =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. + */ + [ZX_CLK_MPLL] =3D PLL("mpll", clk_main, 0, 0x8, 0), + + /* + * 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. + */ + [ZX_CLK_UPLL] =3D PLL("upll", clk_main, 0, 0x10, 0), + + /* + * 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 on this clock generating a usable sign= al, it needs to be + * enabled when prepared. + * + * It isn't named anywhere in ZTE's code, but cpko.ko has the string "dpl= l2" somewhere in + * its clock tables. + */ + [ZX_CLK_DPLL2] =3D PLL("dpll2", clk_main, 0, 0x100, CLK_ZX_PL= L_PREPARE_IS_ENABLE), + [ZX_CLK_DPLL2_D2] =3D FIXED_DIV("dpll2-d2", PARENT_ID(ZX_CLK_DPL= L2), 2), + + /* + * 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 dpll2-d2. If + * dpll2 is disabled, dpll loses its lock. We set the frequency on this P= LL if we find it is + * not prepared by the boot loader. + * + * The proprietary LTE driver and/or rproc prepare and unprepare it. TDM = and I2S can use it. + * + * It accepts parent values 0, 1, 2 and 3. Parent 0 is dpll2-d2. The othe= rs look like + * osc26m. With a parent !=3D 0 dpll never loses its lock even when all o= ther PLLs are off + * and the TDM counter register increases at a rate consistent with a 26.= 0/23.04 clock + * increase. + */ + [ZX_CLK_DPLL] =3D PLL("dpll", dpll_parents, 491520000, 0x18,= 0), + + /* + * "g" is either for "general" or "gigahertz". The VCO runs at 1 GHz. Out= put 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. + */ + [ZX_CLK_GPLL] =3D PLL("gpll", clk_main, 0, 0x110, 0), + + /* osc26m division for clk_outX */ + [ZX_CLK_OSC26M_D2] =3D FIXED_DIV("osc26m-d2", clk_main[0], 2), + + /* Pre-0x140 distribution fixed divs */ + [ZX_CLK_TOP_MPLL_D2_PREGATE] =3D FIXED_DIV("mpll-d2", PARENT_ID(ZX_CLK_M= PLL), 2), + [ZX_CLK_TOP_MPLL_D4_PREGATE] =3D FIXED_DIV("mpll-d4", PARENT_ID(ZX_CLK_M= PLL), 4), + [ZX_CLK_TOP_MPLL_D5_PREGATE] =3D FIXED_DIV("mpll-d5", PARENT_ID(ZX_CLK_M= PLL), 5), + [ZX_CLK_TOP_MPLL_D6_PREGATE] =3D FIXED_DIV("mpll-d6", PARENT_ID(ZX_CLK_M= PLL), 6), + [ZX_CLK_TOP_MPLL_D8_PREGATE] =3D FIXED_DIV("mpll-d8", PARENT_ID(ZX_CLK_M= PLL), 8), + [ZX_CLK_TOP_UPLL_D12_PREGATE] =3D FIXED_DIV("upll-d12", PARENT_ID(ZX_CLK_= UPLL), 12), + [ZX_CLK_TOP_GPLL_D2_PREGATE] =3D FIXED_DIV("gpll-d2", PARENT_ID(ZX_CLK_G= PLL), 2), + [ZX_CLK_TOP_GPLL_D4_PREGATE] =3D FIXED_DIV("gpll-d4", PARENT_ID(ZX_CLK_G= PLL), 4), + + /* + * topcrm distribution gates. These are complicated, but shed a lot of li= ght on the board's + * clock distribution. + * + * Settable mask: 0x017333FF. Generally one nibble per PLL, except for MP= LL that has more. + * One for osc26m work clock. pclk and osc32k are not gated globally 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 */ + [ZX_CLK_TOP_MPLL_D2] =3D GATE("top-mpll-d2", PARENT_ID(ZX_CLK_TOP_M= PLL_D2_PREGATE), + 0x140, 1, 0), + /* Bit 2: No known consumer, named "mpll_48m_clk" in ZTE's cpko.ko blob */ + [ZX_CLK_TOP_MPLL_D8] =3D GATE("top-mpll-d8", PARENT_ID(ZX_CLK_TOP_M= PLL_D8_PREGATE), + 0x140, 3, 0), + [ZX_CLK_TOP_MPLL_D6] =3D GATE("top-mpll-d6", PARENT_ID(ZX_CLK_TOP_M= PLL_D6_PREGATE), + 0x140, 4, 0), + [ZX_CLK_TOP_MPLL_D4] =3D GATE("top-mpll-d4", PARENT_ID(ZX_CLK_TOP_M= PLL_D4_PREGATE), + 0x140, 5, 0), + [ZX_CLK_TOMATRIX_MPLL_D5] =3D GATE("matrix-mpll-d5", PARENT_ID(ZX_CLK_TO= P_MPLL_D5_PREGATE), + 0x140, 6, ZX297520V3_AXI_CANDIDATE), + /* 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. It is an AXI voting candidate, bu= t it is protected + * in Matrix's 0x118 gates. + */ + [ZX_CLK_TOMATRIX_MPLL] =3D GATE("matrix-mpll", PARENT_ID(ZX_CLK_MPLL)= , 0x140, 9, 0), + /* Bit 10: Always 0 */ + /* Bit 11: Always 0 */ + + /* Bit 12: No known consumer. Existing patterns indicate a dpll consumer = in top itself */ + [ZX_CLK_TOMATRIX_DPLL] =3D GATE("matrix-dpll", PARENT_ID(ZX_CLK_DPLL)= , 0x140, 13, 0), + /* Bit 14: Always 0 */ + /* Bit 15: Always 0 */ + + [ZX_CLK_TOP_UPLL_D12] =3D GATE("top-upll-d12", PARENT_ID(ZX_CLK_TOP_= UPLL_D12_PREGATE), + 0x140, 16, 0), + [ZX_CLK_TOP_UPLL] =3D GATE("top-upll", PARENT_ID(ZX_CLK_UPLL), 0= x140, 17, 0), + /* Bit 18: Always 0 */ + /* Bit 19: Always 0 */ + + [ZX_CLK_TOP_GPLL_D4] =3D GATE("top-gpll-d4", PARENT_ID(ZX_CLK_TOP_G= PLL_D4_PREGATE), + 0x140, 20, 0), + [ZX_CLK_TOMATRIX_GPLL_D2] =3D GATE("matrix-gpll-d2", PARENT_ID(ZX_CLK_TO= P_GPLL_D2_PREGATE), + 0x140, 21, 0), + [ZX_CLK_TOMATRIX_GPLL] =3D GATE("matrix-gpll", PARENT_ID(ZX_CLK_GPLL)= , 0x140, 22, 0), + /* Bit 23: Always 0 */ + + /* + * Bit 24 covers all 26 MHz on matrix, but not pclks. Osc26m consumers on= topcrm do not + * use this, they get the ungated osc26m. It is an AXI voting candidate, = but does not + * need protection because it is the slowest speed. It will only be used = if every processor, + * including us, votes for it. + */ + [ZX_CLK_TOMATRIX_OSC26M] =3D GATE("matrix-osc26m", clk_main[0], 0x140, = 24, 0), + + /* + * 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 1= with M0's 78 MHz. + */ + [ZX_CLK_TOP_MPLL_D2_D4] =3D FIXED_DIV("top-mpll-d2-d4", PARENT_ID(ZX_C= LK_TOP_MPLL_D2), 4), + [ZX_CLK_TOP_MPLL_D2_D13] =3D FIXED_DIV("top-mpll-d2-d13", PARENT_ID(ZX_= CLK_TOP_MPLL_D2), + 13), + [ZX_CLK_TOP_UPLL_D12_D2] =3D FIXED_DIV("top-upll-d12-d2", PARENT_ID(ZX_= CLK_TOP_UPLL_D12), + 2), + [ZX_CLK_TOP_GPLL_D4_D2] =3D FIXED_DIV("top-gpll-d4-d2", PARENT_ID(ZX_C= LK_TOP_GPLL_D4), 2), + + /* Device-specific Muxes */ + [ZX_CLK_M0_MUX] =3D MUX("m0-mux", m0_sel, 0x= 38, 0, 2), + [ZX_CLK_AHB_MUX] =3D MUX("ahb-mux", ahb_sel, 0x= 3c, 4, 2), + [ZX_CLK_TIMER_T08_MUX] =3D MUX("timer-t08-mux", timer_top_sel, 0x= 40, 1, 1), + [ZX_CLK_TIMER_T09_MUX] =3D MUX("timer-t09-mux", timer_top_sel, 0x= 40, 0, 1), + [ZX_CLK_TIMER_T12_MUX] =3D MUX("timer-t12-mux", timer_top_sel, 0x= 3c, 0, 1), + [ZX_CLK_TIMER_T13_MUX] =3D MUX("timer-t13-mux", timer_top_sel, 0x= 44, 0, 1), + [ZX_CLK_TIMER_T14_MUX] =3D MUX("timer-t14-mux", timer_top_sel, 0x= 44, 1, 1), + [ZX_CLK_TIMER_T15_MUX] =3D MUX("timer-t15-mux", timer_top_sel, 0x= 3c, 3, 1), + [ZX_CLK_TIMER_T16_MUX] =3D MUX("timer-t16-mux", timer_top_sel, 0x= 44, 2, 1), + [ZX_CLK_TIMER_T17_MUX] =3D MUX("timer-t17-mux", timer_top_sel, 0x1= 20, 0, 1), + [ZX_CLK_WDT_T18_MUX] =3D MUX("wdt-t18-mux", timer_top_sel, 0x= 3c, 6, 1), + [ZX_CLK_I2C0_MUX] =3D MUX("i2c0-mux", uart_top_sel, 0x= 3c, 1, 1), + [ZX_CLK_UART0_MUX] =3D MUX("uart0-mux", uart_top_sel, 0x= 40, 2, 1), + [ZX_CLK_OUT0_MUX] =3D MUX("out0-mux", out0_sel, 0x= 34, 5, 1), + [ZX_CLK_OUT1_MUX] =3D MUX("out1-mux", out1_sel, 0x= 34, 6, 2), + [ZX_CLK_OUT2_MUX] =3D MUX("out2-mux", out2_sel, 0x= 34, 8, 1), + [ZX_CLK_RMIIPHY_MUX] =3D MUX("rmiiphy-mux", rmii_sel, 0x1= 1c, 0, 2), + + /* Device-specific dividers */ + [ZX_CLK_TIMER_T08_DIV] =3D DIV("timer-t08-div", PARENT_ID(ZX_CLK_TIME= R_T08_MUX), + 0x4c, 8, 4), + [ZX_CLK_TIMER_T09_DIV] =3D DIV("timer-t09-div", PARENT_ID(ZX_CLK_TIME= R_T09_MUX), + 0x4c, 0, 4), + [ZX_CLK_TIMER_T12_DIV] =3D DIV("timer-t12-div", PARENT_ID(ZX_CLK_TIME= R_T12_MUX), + 0x48, 0, 4), + [ZX_CLK_TIMER_T13_DIV] =3D DIV("timer-t13-div", PARENT_ID(ZX_CLK_TIME= R_T13_MUX), + 0x50, 0, 4), + [ZX_CLK_TIMER_T14_DIV] =3D DIV("timer-t14-div", PARENT_ID(ZX_CLK_TIME= R_T14_MUX), + 0x50, 4, 4), + [ZX_CLK_TIMER_T15_DIV] =3D DIV("timer-t15-div", PARENT_ID(ZX_CLK_TIME= R_T15_MUX), + 0x48, 4, 4), + [ZX_CLK_TIMER_T16_DIV] =3D DIV("timer-t16-div", PARENT_ID(ZX_CLK_TIME= R_T16_MUX), + 0x50, 8, 4), + [ZX_CLK_TIMER_T17_DIV] =3D DIV("timer-t17-div", PARENT_ID(ZX_CLK_TIME= R_T17_MUX), + 0x124, 0, 4), + [ZX_CLK_WDT_T18_DIV] =3D DIV("wdt-t18-div", PARENT_ID(ZX_CLK_WDT_T1= 8_MUX), + 0x48, 8, 4), + [ZX_CLK_USIM1_DIV] =3D DIV("usim1-div", clk_unknown, + 0x48, 12, 1), + + /* Device specific gates */ + + /* + * 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. + */ + [ZX_CLK_AHB_PCLK] =3D GATE("ahb-pclk", PARENT_ID(ZX_CLK_AHB_MUX)= , 0x54, 12, + CLK_IS_CRITICAL), + [ZX_CLK_AHB_WCLK] =3D GATE("ahb-wclk", PARENT_ID(ZX_CLK_M0_MUX),= 0x54, 13, + CLK_IS_CRITICAL), + + /* SRAM1 and 2 clocks. Leave them on for now, as turning them off careles= sly hangs the M0 */ + [ZX_CLK_SRAM1_PCLK] =3D GATE("sram1-pclk", clk_main[0], 0x54, 18, = CLK_IS_CRITICAL), + [ZX_CLK_SRAM2_PCLK] =3D GATE("sram2-pclk", clk_main[0], 0x54, 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. + */ + [ZX_CLK_PMM_WCLK] =3D GATE("pmm-wclk", clk_main[0], 0x58, 0, CLK= _IS_CRITICAL), + [ZX_CLK_PMM_PCLK] =3D GATE("pmm-pclk", clk_main[0], 0x58, 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. Timers in registe= r 0x54 have the + * pclk first, the others have the wclk first. + * + * Timer T17 is used by the ZSP firmware. The rproc driver will enable it= as needed. + */ + [ZX_CLK_TIMER_T08_WCLK] =3D GATE("timer-t08-wclk", PARENT_ID(ZX_CLK_TI= MER_T08_DIV), + 0x5c, 8, 0), + [ZX_CLK_TIMER_T08_PCLK] =3D GATE("timer-t08-pclk", clk_main[0], 0x5c, = 9, 0), + [ZX_CLK_TIMER_T09_WCLK] =3D GATE("timer-t09-wclk", PARENT_ID(ZX_CLK_TI= MER_T09_DIV), + 0x5c, 4, 0), + [ZX_CLK_TIMER_T09_PCLK] =3D GATE("timer-t09-pclk", clk_main[0], 0x5c, = 5, 0), + [ZX_CLK_TIMER_T12_WCLK] =3D GATE("timer-t12-wclk", PARENT_ID(ZX_CLK_TI= MER_T12_DIV), + 0x54, 5, 0), + [ZX_CLK_TIMER_T12_PCLK] =3D GATE("timer-t12-pclk", clk_main[0], 0x54, = 4, 0), + [ZX_CLK_TIMER_T13_WCLK] =3D GATE("timer-t13-wclk", PARENT_ID(ZX_CLK_TI= MER_T13_DIV), + 0x60, 0, 0), + [ZX_CLK_TIMER_T13_PCLK] =3D GATE("timer-t13-pclk", clk_main[0], 0x60, = 1, 0), + [ZX_CLK_TIMER_T14_WCLK] =3D GATE("timer-t14-wclk", PARENT_ID(ZX_CLK_TI= MER_T14_DIV), + 0x60, 4, 0), + [ZX_CLK_TIMER_T14_PCLK] =3D GATE("timer-t14-pclk", clk_main[0], 0x60, = 5, 0), + [ZX_CLK_TIMER_T15_WCLK] =3D GATE("timer-t15-wclk", PARENT_ID(ZX_CLK_TI= MER_T15_DIV), + 0x54, 21, 0), + [ZX_CLK_TIMER_T15_PCLK] =3D GATE("timer-t15-pclk", clk_main[0], 0x54, = 20, 0), + [ZX_CLK_TIMER_T16_WCLK] =3D GATE("timer-t16-wclk", PARENT_ID(ZX_CLK_TI= MER_T16_DIV), + 0x60, 8, 0), + [ZX_CLK_TIMER_T16_PCLK] =3D GATE("timer-t16-pclk", clk_main[0], 0x60, = 9, 0), + [ZX_CLK_TIMER_T17_WCLK] =3D GATE("timer-t17-wclk", PARENT_ID(ZX_CLK_TI= MER_T17_DIV), + 0x128, 0, 0), + [ZX_CLK_TIMER_T17_PCLK] =3D GATE("timer-t17-pclk", clk_main[0], 0x128,= 1, 0), + + /* + * This watchdog is set up by ZTE's bootloader and in ZTE's OS the m0 fir= mware 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 userspace v= ia the watchdog + * driver. + */ + [ZX_CLK_WDT_T18_WCLK] =3D GATE("wdt-t18-wclk", PARENT_ID(ZX_CLK_WDT_T= 18_DIV), + 0x54, 25, 0), + [ZX_CLK_WDT_T18_PCLK] =3D GATE("wdt-t18-pclk", clk_main[0], 0x54, 24,= 0), + + [ZX_CLK_I2C0_WCLK] =3D GATE("i2c0-wclk", PARENT_ID(ZX_CLK_I2C0_MUX= ), 0x54, 9, 0), + [ZX_CLK_I2C0_PCLK] =3D GATE("i2c0-pclk", clk_main[0], 0x54, 8, 0), + [ZX_CLK_UART0_WCLK] =3D GATE("uart0-wclk", PARENT_ID(ZX_CLK_UART0_M= UX), 0x5c, 12, 0), + [ZX_CLK_UART0_PCLK] =3D GATE("uart0-pclk", clk_main[0], 0x5c, 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. + */ + [ZX_CLK_USB_WCLK] =3D GATE("usb-wclk", PARENT_ID(ZX_CLK_TOP_MPLL_= D2_D13), 0x6c, 3, 0), + [ZX_CLK_USB_PCLK] =3D GATE("usb-pclk", PARENT_ID(ZX_CLK_AHB_WCLK)= , 0x6c, 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. + */ + [ZX_CLK_HSIC_WCLK] =3D GATE("hsic-wclk", PARENT_ID(ZX_CLK_TOP_UPLL= ), 0x6c, 1, 0), + [ZX_CLK_HSIC_PCLK] =3D GATE("hsic-pclk", PARENT_ID(ZX_CLK_AHB_WCLK= ), 0x6c, 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. + */ + [ZX_CLK_RTC_WCLK] =3D GATE("rtc-wclk", clk_unknown, 0x54, 1, 0), + [ZX_CLK_RTC_PCLK] =3D GATE("rtc-pclk", clk_main[0], 0x54, 0, 0), + + [ZX_CLK_USIM1_WCLK] =3D GATE("usim1-wclk", PARENT_ID(ZX_CLK_USIM1_D= IV), 0x54, 29, 0), + [ZX_CLK_USIM1_PCLK] =3D GATE("usim1-pclk", clk_main[0], 0x54, 28, 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. + * + * Like PMM in this register, either bit enables register access, whether= they control pclk + * or wclk cannot be distinguished. + * + * The work parent of GSM, TD and W is without doubt osc26m. The mmio spa= ce has registers + * that count up at an integer fraction of 26000000. Gating PLLs does not= affect them, + * including gating mpll. + * + * LPM_LTE has some interaction with LTE_MODEM_WCLK. If LTE_MODEM_WCLK is= disabled, LPM_LTE + * stops counting, and just flips between two states. This makes it look = like LPM_LTE in + * topcrm has a clock parent in matrixcrm, which wouldn't make much sense= . I think this + * behavior is a result of the devices interacting rather than a clock pa= rentage. + * + * As for what these devices do? I am not sure. They generate a lot of IR= Qs, but the IRQs + * are independent of actual radio activity. The ZSP firmware programs th= em + */ + [ZX_CLK_LPM_GSM_WCLK] =3D GATE("lpm-gsm-wclk", clk_main[0], 0x58, 10,= 0), + [ZX_CLK_LPM_GSM_PCLK] =3D GATE("lpm-gsm-pclk", clk_main[0], 0x58, 11,= 0), + [ZX_CLK_LPM_LTE_WCLK] =3D GATE("lpm-lte-wclk", clk_unknown, 0x58, 8, = 0), + [ZX_CLK_LPM_LTE_PCLK] =3D GATE("lpm-lte-pclk", clk_main[0], 0x58, 9, = 0), + [ZX_CLK_LPM_TD_WCLK] =3D GATE("lpm-td-wclk", clk_main[0], 0x58, 6, 0= ), + [ZX_CLK_LPM_TD_PCLK] =3D GATE("lpm-td-pclk", clk_main[0], 0x58, 7, 0= ), + [ZX_CLK_LPM_W_WCLK] =3D GATE("lpm-w-wclk", clk_main[0], 0x58, 4, 0), + [ZX_CLK_LPM_W_PCLK] =3D GATE("lpm-w-pclk", clk_main[0], 0x58, 5, 0), + + [ZX_CLK_OUT0_WCLK] =3D GATE("out0-wclk", PARENT_ID(ZX_CLK_OUT0_MUX= ), 0x34, 0, 0), + [ZX_CLK_OUT1_WCLK] =3D GATE("out1-wclk", PARENT_ID(ZX_CLK_OUT1_MUX= ), 0x90, 2, 0), + [ZX_CLK_OUT2_WCLK] =3D GATE("out2-wclk", PARENT_ID(ZX_CLK_OUT2_MUX= ), 0x94, 2, 0), + [ZX_CLK_OUT32K_WCLK] =3D GATE("out32k-wclk", PARENT_FW("osc32k"), 0x= 34, 1, 0), + [ZX_CLK_RMIIPHY_WCLK] =3D GATE("rmiiphy-wclk", PARENT_ID(ZX_CLK_RMIIP= HY_MUX), + 0x11c, 2, 0), + + /* + * GSM clocks - they feed the 2G/3G radio components and SIM controller. + * + * The names are from the clock table in cpko.ko. The parents of gsm-104m= and gsm-156m are + * experimentally verified. The gsm-48m parent is likely bit 2 in topcrm+= 0x140. I have not + * found an consumer that I understand well enough to say if it is runnin= g or not, so I have + * not been able to confirm this yet. + */ + [ZX_CLK_GSM_32K] =3D GATE("gsm-32k", PARENT_FW("osc32k"), 0x68, = 0, 0), + [ZX_CLK_GSM_26M] =3D GATE("gsm-26m", PARENT_FW("osc26m"), 0x68, = 1, 0), + [ZX_CLK_GSM_48M] =3D GATE("gsm-48m", clk_unknown, 0x68, 2, 0), + [ZX_CLK_GSM_104M] =3D GATE("gsm-104m", PARENT_ID(ZX_CLK_TOP_MPLL_= D6), 0x68, 3, 0), + [ZX_CLK_GSM_156M] =3D GATE("gsm-156m", PARENT_ID(ZX_CLK_TOP_MPLL_= D4), 0x68, 4, 0), + + /* Analog Baseband, probably. cpko.ko enables it for LTE, and LTE scans c= ome back empty + * without it. The MMIO location of the device is unknown. It is likely c= onnected only to + * ZSP and inaccessible to the main CPU. + */ + [ZX_CLK_ABB_WCLK] =3D GATE("abb-wclk", clk_unknown, 0x144, 1, 0), +}; + +static const unsigned int zx297520v3_top_exports[] =3D { + [ZX297520V3_M0_WCLK] =3D ZX_CLK_M0_MUX, + [ZX297520V3_SRAM1_PCLK] =3D ZX_CLK_SRAM1_PCLK, + [ZX297520V3_SRAM2_PCLK] =3D ZX_CLK_SRAM2_PCLK, + [ZX297520V3_UART0_WCLK] =3D ZX_CLK_UART0_WCLK, + [ZX297520V3_UART0_PCLK] =3D ZX_CLK_UART0_PCLK, + [ZX297520V3_I2C0_WCLK] =3D ZX_CLK_I2C0_WCLK, + [ZX297520V3_I2C0_PCLK] =3D ZX_CLK_I2C0_PCLK, + [ZX297520V3_RTC_WCLK] =3D ZX_CLK_RTC_WCLK, + [ZX297520V3_RTC_PCLK] =3D ZX_CLK_RTC_PCLK, + [ZX297520V3_LPM_GSM_WCLK] =3D ZX_CLK_LPM_GSM_WCLK, + [ZX297520V3_LPM_GSM_PCLK] =3D ZX_CLK_LPM_GSM_PCLK, + [ZX297520V3_LPM_LTE_WCLK] =3D ZX_CLK_LPM_LTE_WCLK, + [ZX297520V3_LPM_LTE_PCLK] =3D ZX_CLK_LPM_LTE_PCLK, + [ZX297520V3_LPM_TD_WCLK] =3D ZX_CLK_LPM_TD_WCLK, + [ZX297520V3_LPM_TD_PCLK] =3D ZX_CLK_LPM_TD_PCLK, + [ZX297520V3_LPM_W_WCLK] =3D ZX_CLK_LPM_W_WCLK, + [ZX297520V3_LPM_W_PCLK] =3D ZX_CLK_LPM_W_PCLK, + [ZX297520V3_TIMER_T08_WCLK] =3D ZX_CLK_TIMER_T08_WCLK, + [ZX297520V3_TIMER_T08_PCLK] =3D ZX_CLK_TIMER_T08_PCLK, + [ZX297520V3_TIMER_T09_WCLK] =3D ZX_CLK_TIMER_T09_WCLK, + [ZX297520V3_TIMER_T09_PCLK] =3D ZX_CLK_TIMER_T09_PCLK, + [ZX297520V3_MPLL] =3D ZX_CLK_TOMATRIX_MPLL, + [ZX297520V3_MPLL_D5] =3D ZX_CLK_TOMATRIX_MPLL_D5, + [ZX297520V3_DPLL] =3D ZX_CLK_TOMATRIX_DPLL, + [ZX297520V3_GPLL] =3D ZX_CLK_TOMATRIX_GPLL, + [ZX297520V3_GPLL_D2] =3D ZX_CLK_TOMATRIX_GPLL_D2, + [ZX297520V3_GATED_OSC26M] =3D ZX_CLK_TOMATRIX_OSC26M, + [ZX297520V3_PMM_WCLK] =3D ZX_CLK_PMM_WCLK, + [ZX297520V3_PMM_PCLK] =3D ZX_CLK_PMM_PCLK, + [ZX297520V3_OUT0_WCLK] =3D ZX_CLK_OUT0_WCLK, + [ZX297520V3_OUT1_WCLK] =3D ZX_CLK_OUT1_WCLK, + [ZX297520V3_OUT2_WCLK] =3D ZX_CLK_OUT2_WCLK, + [ZX297520V3_OUT32K_WCLK] =3D ZX_CLK_OUT32K_WCLK, + [ZX297520V3_RMIIPHY_WCLK] =3D ZX_CLK_RMIIPHY_WCLK, + [ZX297520V3_TIMER_T12_WCLK] =3D ZX_CLK_TIMER_T12_WCLK, + [ZX297520V3_TIMER_T12_PCLK] =3D ZX_CLK_TIMER_T12_PCLK, + [ZX297520V3_TIMER_T13_WCLK] =3D ZX_CLK_TIMER_T13_WCLK, + [ZX297520V3_TIMER_T13_PCLK] =3D ZX_CLK_TIMER_T13_PCLK, + [ZX297520V3_TIMER_T14_WCLK] =3D ZX_CLK_TIMER_T14_WCLK, + [ZX297520V3_TIMER_T14_PCLK] =3D ZX_CLK_TIMER_T14_PCLK, + [ZX297520V3_TIMER_T15_WCLK] =3D ZX_CLK_TIMER_T15_WCLK, + [ZX297520V3_TIMER_T15_PCLK] =3D ZX_CLK_TIMER_T15_PCLK, + [ZX297520V3_TIMER_T16_WCLK] =3D ZX_CLK_TIMER_T16_WCLK, + [ZX297520V3_TIMER_T16_PCLK] =3D ZX_CLK_TIMER_T16_PCLK, + [ZX297520V3_TIMER_T17_WCLK] =3D ZX_CLK_TIMER_T17_WCLK, + [ZX297520V3_TIMER_T17_PCLK] =3D ZX_CLK_TIMER_T17_PCLK, + [ZX297520V3_WDT_T18_WCLK] =3D ZX_CLK_WDT_T18_WCLK, + [ZX297520V3_WDT_T18_PCLK] =3D ZX_CLK_WDT_T18_PCLK, + [ZX297520V3_USIM1_WCLK] =3D ZX_CLK_USIM1_WCLK, + [ZX297520V3_USIM1_PCLK] =3D ZX_CLK_USIM1_PCLK, + [ZX297520V3_AHB_WCLK] =3D ZX_CLK_AHB_WCLK, + [ZX297520V3_AHB_PCLK] =3D ZX_CLK_AHB_PCLK, + [ZX297520V3_USB_WCLK] =3D ZX_CLK_USB_WCLK, + [ZX297520V3_USB_PCLK] =3D ZX_CLK_USB_PCLK, + [ZX297520V3_HSIC_WCLK] =3D ZX_CLK_HSIC_WCLK, + [ZX297520V3_HSIC_PCLK] =3D ZX_CLK_HSIC_PCLK, + [ZX297520V3_GSM_32K] =3D ZX_CLK_GSM_32K, + [ZX297520V3_GSM_26M] =3D ZX_CLK_GSM_26M, + [ZX297520V3_GSM_48M] =3D ZX_CLK_GSM_48M, + [ZX297520V3_GSM_104M] =3D ZX_CLK_GSM_104M, + [ZX297520V3_GSM_156M] =3D ZX_CLK_GSM_156M, + [ZX297520V3_ABB_WCLK] =3D ZX_CLK_ABB_WCLK, +}; + +static const struct zx_clk_data zx297520v3_topclk_data =3D { + .clocks =3D zx297520v3_top_clocks, + .num_clocks =3D ARRAY_SIZE(zx297520v3_top_clocks), + .exports =3D zx297520v3_top_exports, + .num_exports =3D ARRAY_SIZE(zx297520v3_top_exports), +}; + +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.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wr2-f12.google.com (mail-wr2-f12.google.com [74.125.225.76]) (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 71D583BF660 for ; Sun, 27 Sep 2026 20:14:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.76 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540089; cv=none; b=XbteVNZId+wmZwAIwumqOf6BU+UkAfsv2KOZIlM+4UlODdQeSogs+oHQsJOa2uYQ5V1PfUKRzt0dU6Y/1YWurjAaqJ3IfoTFfCLG30d3v4vPPdYbxiNp+vhq9c3eTSbgzIemFr4kMYT8bozsn9HsJyOgYDzfbLwAsk37zzy1YH4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540089; c=relaxed/simple; bh=iCfndwLBIv8fTED0QyCjlr2F6ulQSthyYRD7lTreug0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PqPgteNyRTG2z0SnUcl/y8zhycQTroB7pGxBFraB+bf/EF2DWOiDrDAxk/wf9t314wFMmr4rl4hY68zouakH/5j3uIANEe8tjxExchpqpJt9MZvHNl0afiHNzD88gM3vSOOqhCsbqmDUvikOUOJXbfsLxiy7LS0pjpKE0f52CKc= 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=O2tChclm; arc=none smtp.client-ip=74.125.225.76 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="O2tChclm" Received: by mail-wr2-f12.google.com with SMTP id ffacd0b85a97d-482f635552aso1869621f8f.2 for ; Sun, 27 Sep 2026 13:14:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540083; x=1791144883; 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=QNif68vBweclNkbVJu08PNYirXK6LBRMMEpOMCQuVXg=; b=O2tChclmpyz1wEJlSXPvqFziDDsiiCR2sjcObsUEo6aNMtwS+mgMlHcORLFOBAJoIB jHo0Vi/CPrIoUVmDbkJf6zXy4Qq+ahuzv7XsU7Vn4KFDmBLZ7jmWNTYUaYLxESpYz6Pm bPbH9xnD/yq1lPnaWfZSTbfx7HfyJp1+jBPmuuftwCsL4FhyvNuQZm5yD1tuNCUQCzme oRdvQ+MXC9byb60IeCrvd20F8P5qOTSPmuwWEOzANomHvSobqD/CIaEgA5TSlcrNqDEU 8xdJ/4k/D6e4R63qDnSsAc35k7ZrjzfnvEnFmy7TBE9JdheRN5v608EQyBuxw02uG92E lpqw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540083; x=1791144883; 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=QNif68vBweclNkbVJu08PNYirXK6LBRMMEpOMCQuVXg=; b=1kqQ6oYoOifOfrSo2tZafhZE8p6tYLhH/YiAkLpn8J9/RbGKZjQX/9U2h52SKUULTO CP94FKLtzWRUDXh9HW7+u44RKgjyVbCnJkiwHfDmuAFynxEXDC1xFr5jTwPtWhH4d/D7 HbusnQvEFBpIg2/CMVKJReM5yNwGsbTm+Z64eaUVBW5H7cjqzWiaUOM3xms4qHQTxVb+ 1W8S+ctrPps/zEbyvJ2ezEoPCbTfB3xpL8iWVvCymzBlMYuiXODXYVfjQdcqSh8537n+ yeg9H7cWPt1M2rFoQkzLRfJxX84DfrZBSKSgvRvepZBXBmCg2iCFh9JAn4p3kKnRLfnf /NVg== X-Forwarded-Encrypted: i=1; AKwUvByz7J5iU9XE8PDmpMjKSRoIG/pLe4sMIYK5wZoShPscWBqTQmMBZ0RXKZY0bouIFV5zciB0JrStf/FrK+k=@vger.kernel.org X-Gm-Message-State: AFq9FYIfxmnBHU9jHWvIed+o9oUWCFdAfuM2l6iNV3EPECsdIDsxQM/Y DdQqil9PXQ9TImpxBYtzSW/2C5FMoYs8v2eYgFEwqJpWgINxXf5ljyQd X-Gm-Gg: AYBFou3WgdHg4K+tnj8RvlkwLMvJKgaWx7JvBDinyR+LffX3OnJeUqqN11di023920y tYRNQ03aYfOCiFX/kJNC1DwMegzRSgFW9szbjxjxy6iF4zVgN+alLnpEGez0ve8jrQazijkOf4z lEHN4XXmhHEFNcDSTAb5BojcWbTNz3y5Qk7D4FdMJVzqHliCpkjf/pmN2RQ9q8NUycOgBPUitSF oeAXTycEjAgSHquRw6udbiSIjqHIkzKswKzmKTIxsSiCtUWDDZYX0+SSmxOocbq03T34c8uthve 0QuzBdl4e5kBhmC1uKNI2QV/+h2bR8skMNmGp+kll0cQ5IrmisanHZQKshjVl1A6OJaTUa/LJN9 LimqP/rsIHSHVFubqv65ntuWISuHFScVi6hsEx0SSbcsXMsr43w7/3mS4NHyS7yQJytaZa273I/ dVKxXndJ2Jl55Q5xDqhKxhuq++cAoPHLzcxWbjYsGxcI7qJ64tKnnHfhiJPxR8s8cbVIEbzhm+P 9uO9Xk3 X-Received: by 2002:a5d:64ee:0:b0:488:8c99:fbc3 with SMTP id ffacd0b85a97d-4888c99fd87mr3943532f8f.5.1790540083230; Sun, 27 Sep 2026 13:14:43 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:42 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:38 +0300 Subject: [PATCH v13 10/13] clk: zte: Introduce a driver for zx297520v3 matrix 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: <20260927-zx29clk-v13-10-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=27882; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=iCfndwLBIv8fTED0QyCjlr2F6ulQSthyYRD7lTreug0=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1pD28ajK7uJzYGhJvHAGjD7e5OxHh7X5Ux l7naXq07yuJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiKMww//enWWAPEdMAkkrqlct+G37rureZOQ9io kN/rRfS5urImr9re6LmdmFiccEaMh6SwvevUWdHrysQStNo8LuCGBbiS3mY31UbUghKuwTKUO4v +gZsW2+fy0noT2ZhUChckWiIMkbfd0FPMfRzPE+MxEbJKBO9KE9fMNvElM3zmqD+D2psyBx+2CV c6xRUJYijO4cr70hqf+iAVhwB1d3Jb/yLG2uSoAj+YCNON8Nna39YQFYGqkQxCAGEY5EB1My+BD ssmqionA31D75H61XJz6G/eB8QNbWsnLrq0fupUplPjcLsGq/cy+5+lRBkh461szuk7RrnJrL3o ITMtw3D0nasYIczVhzIQD1//MFS1HoxRMgLDFSEk6E7XetcmVkyWIW9klD+f0DLGMrzsh/LnSDE yIwndGMqe4qw38eZGL6VRWrXTohWaITmW9s2UVUE15bYm2qEpppqxeAO4qqPjXBNuaNEO3e7fN+ cPfaAQPC147RYo2rsswMcldk8e+5sTB023/TY6+MELnTm5u38Zx0WXQ02byaFwsiHdOhXC05y2L KhGpIUKTujYyVkcwTWlzKFU30w1ariQjTskpErPYqCrFZUZ9JxDqSUKHi+hLgOQ+d0gie730ThN TWr60WDc4AWLxV9AirrIeF+1atHqxpowWSo5cE1KrFlp2IjB8u3A= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 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. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- Version 13: Export the accidentally forgotten ZX297520V3_RFFE_WCLK (Sashiko) Version 12: Add RFFE clock. Is part of the SSC device, which looks like an SPI-like controller that provides a control channel to the LTE radio devices. Export LTE_MODEM clocks. The LTE firmware needs it enabled, but otherwise manages the LTE_MODEM device autonomously, so I have no idea how the device works or what it is composed of. Version 10: Add ZSP PCLK. ZSP clock gates are in 0x34. 0x3c is another reset register. Improve ZSP WCLK mux. Version 9: Link internal parents by an (internal) clock ID rather than names. There are 3 intentional changes vs version 8 in the clock tree: "gmac-ahb" depends on the ahb clock imported from topcrm. This was already the case before, but it was missing from the bindings and the global name matching obscured it. When re-testing other devices for potential topcrm->ahb dependencies I noticed that the two SDIO devices take their pclk from topcrm->ahb as well. @Sashiko: Any possible other clock tree change compared to version 8 is unintentional and a likely bug. Version 8: Add another distribution gate register: 0x118 gates off matrix-generated divisions of mpll, dpll and gpll. It nicely fits the top->matrix forward picture. AXI 6.5 MHz is not an mpll child. I must have done something wrong when originally testing this Add explanations about additional ARM architected timer controls. Add gates for unknown LTE hardware at offset 0x60. They are not exported in the bindings because the actual name of the consumer isn't clear - but if dpll is unprepared and feeds a bypass 26 MHz signal, this device starts spamming IRQs (although the 0x118 and top+0x140 gates also prevent this usually) Double-check pclk and wclk of all devices. The SDIO and EDCP clocks were flipped in previous submissions. Version 7: Reduced the input clocks a lot. Most MPLL subdivisions 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 architected 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 | 526 +++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 526 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c index 68bfeab84d74..d5f8bc4064bd 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -812,6 +812,528 @@ static const struct zx_clk_data zx297520v3_topclk_dat= a =3D { .num_exports =3D ARRAY_SIZE(zx297520v3_top_exports), }; =20 +enum matrix_clock_ids { + ZX_CLK_MATRIX_OSC26M_D4, + ZX_CLK_MATRIX_MPLL_D2_PREGATE, + ZX_CLK_MATRIX_MPLL_D4_PREGATE, + ZX_CLK_MATRIX_MPLL_D6_PREGATE, + ZX_CLK_MATRIX_MPLL_D8_PREGATE, + ZX_CLK_MATRIX_MPLL_D12_PREGATE, + ZX_CLK_MATRIX_MPLL_D16_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE, + ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE, + ZX_CLK_MATRIX_DPLL_D2_PREGATE, + ZX_CLK_MATRIX_DPLL_D4_PREGATE, + + ZX_CLK_MATRIX_MPLL_D16, + ZX_CLK_MATRIX_MPLL_D12, + ZX_CLK_MATRIX_MPLL_D8, + ZX_CLK_MATRIX_MPLL_D6, + ZX_CLK_MATRIX_MPLL_D4, + ZX_CLK_MATRIX_MPLL_D2, + ZX_CLK_MATRIX_DPLL_D4, + ZX_CLK_MATRIX_DPLL_D2, + ZX_CLK_MATRIX_GPLL_D2_D4, + ZX_CLK_MATRIX_GPLL_D2_D2, + + ZX_CLK_CPU_MUX, + ZX_CLK_ZSP_MUX, + ZX_CLK_DDR_CTRL_MUX, + ZX_CLK_SD0_MUX, + ZX_CLK_SD1_MUX, + ZX_CLK_NAND_MUX, + ZX_CLK_EDCP_MUX, + ZX_CLK_TDM_MUX, + ZX_CLK_AXI_MUX, + + ZX_CLK_SYS_TIMER_WCLK, + ZX_CLK_CPU_WCLK, + ZX_CLK_CPU_PCLK, + ZX_CLK_ZSP_WCLK, + ZX_CLK_ZSP_PCLK, + ZX_CLK_DDR_CTRL_PCLK, + ZX_CLK_DDR_CTRL_WCLK, + ZX_CLK_SD0_PCLK, + ZX_CLK_SD0_WCLK, + ZX_CLK_SD0_CDET, + ZX_CLK_SD1_PCLK, + ZX_CLK_SD1_WCLK, + ZX_CLK_SD1_CDET, + ZX_CLK_NAND_WCLK, + ZX_CLK_NAND_PCLK, + ZX_CLK_LTE_MODEM_WCLK, + ZX_CLK_LTE_MODEM_PCLK, + ZX_CLK_EDCP_PCLK, + ZX_CLK_EDCP_WCLK, + ZX_CLK_RFFE_WCLK, + ZX_CLK_SSC_WCLK, + ZX_CLK_SSC_PCLK, + ZX_CLK_PDCFG_WCLK, + ZX_CLK_PDCFG_PCLK, + ZX_CLK_MBOX_PCLK, + ZX_CLK_SRAM0_PCLK, + ZX_CLK_GSM_CFG_PCLK, + ZX_CLK_GMAC_WCLK, + ZX_CLK_GMAC_PCLK, + ZX_CLK_GMAC_AHB, + ZX_CLK_AXI_WCLK, + ZX_CLK_DMA_PCLK, + ZX_CLK_VOU_WCLK, + ZX_CLK_VOU_PCLK, + ZX_CLK_TOLSP_MPLL_D5_WCLK, + ZX_CLK_TOLSP_MPLL_D4_WCLK, + ZX_CLK_TOLSP_MPLL_D6_WCLK, + ZX_CLK_TOLSP_MPLL_D8_WCLK, + ZX_CLK_TOLSP_MPLL_D12_WCLK, + ZX_CLK_TOLSP_OSC26M_WCLK, + ZX_CLK_TOLSP_OSC32K_WCLK, + ZX_CLK_TOLSP_PCLK, + ZX_CLK_TOLSP_TDM_WCLK, + ZX_CLK_TOLSP_DPLL_D4_WCLK, +}; + +/* + * For devices which have a working driver the work clock can be figured o= ut by gating off registers + * in topcrm+0x140. This is used for devices where I can't interpret the r= egister contents yet. + */ +static const struct zx_parent_desc matrix_unk =3D PARENT_FW("wclk-osc26m"); + +static const struct zx_parent_desc cpu_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_FW("mpll"), /* 624 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +/* + * Figuring these values out is a bit tricky. The best liveness check of t= he ZSP is reading its TCM + * at 0x81000000. If it is clocked up and out of reset reading it will suc= ceed. Otherwise, reading + * will stall. Value 1 depends on topcrm+0x140, bit 13, but not any matrix= crm+0x118 gate, so it is + * likely dpll without a div. Mux value 2 depends on 0x118 bit 5, so mpll-= d2. Mux value 3 depends on + * 0x118 bit 4, so mpll-d4. Mux value 0 in turn depends on topcrm+0x140, b= it 24 (osc26m), so it + * follows the usual pattern that mux 0 is osc26m. + * + * If the firmware is running and fed with initialization data it will sta= rt writing status messages + * on UART1. An interruption of these messages or a failure to respond to = rpmsg is not proof that + * the ZSP's clock has been disabled. The firmware's workings depend on re= gular timer and LTE device + * IRQs, so one of these devices might have been stopped instead. + */ +static const struct zx_parent_desc zsp_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_FW("dpll"), /* 491.52 MHz, boot default */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2), /* 312 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 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 + * 200 MHz, while 64/128 MB ones use 156 MHz. + */ +static const struct zx_parent_desc ddr_ctrl_sel[] =3D { + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll"), /* 200 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ +}; + +static const struct zx_parent_desc sd0_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4), /* 25 MHz */ +}; + +static const struct zx_parent_desc sd1_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_FW("gpll-d2"), /* 100 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2), /* 50 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_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 struct zx_parent_desc nand_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ +}; + +static const struct zx_parent_desc edcp_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ +}; + +/* + * The 122.88 MHz selection of value 1 is given in ZTE's kernel and matche= s up to observation: Print + * the TDM counter at regular intervals and look at its increase at values= 0/1/2. It increases by + * about 310*26 for value 0, 310*122.88 for value 1 and 310*104 for value = 2. + * + * Mux value 1 is gated off by matrix+0x118 bit 8. Values 2 and 3 are both= gated off by 0x118 bit 3, + * suggesting that they select the same parent. + */ +static const struct zx_parent_desc tdm_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4), /* 122.88 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), +}; + +/* + * 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. + */ +#define ZX297520V3_AXI_AP_VOTE 0x120 +static const struct zx_parent_desc axi_sel[] =3D { + PARENT_FW("wclk-osc26m"), + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4), /* 156 MHz */ + PARENT_FW("mpll-d5"), /* 124.8 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6), /* 104 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8), /* 78 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12), /* 52 MHz */ + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16), /* 39 MHz */ + PARENT_ID(ZX_CLK_MATRIX_OSC26M_D4), /* 6.5 MHz */ +}; + +static const struct zx_clock zx297520v3_matrix_clocks[] =3D { + [ZX_CLK_MATRIX_OSC26M_D4] =3D FIXED_DIV("matrix-osc26m-d4", PARENT_FW("wc= lk-osc26m"), 4), + [ZX_CLK_MATRIX_MPLL_D2_PREGATE] =3D FIXED_DIV("matrix-mpll-d2-pregate", P= ARENT_FW("mpll"), 2), + [ZX_CLK_MATRIX_MPLL_D4_PREGATE] =3D FIXED_DIV("matrix-mpll-d4-pregate", P= ARENT_FW("mpll"), 4), + /* div 5: provided as a separate line from topcrm */ + [ZX_CLK_MATRIX_MPLL_D6_PREGATE] =3D FIXED_DIV("matrix-mpll-d6-pregate", P= ARENT_FW("mpll"), 6), + [ZX_CLK_MATRIX_MPLL_D8_PREGATE] =3D FIXED_DIV("matrix-mpll-d8-pregate", P= ARENT_FW("mpll"), 8), + [ZX_CLK_MATRIX_MPLL_D12_PREGATE] =3D FIXED_DIV("matrix-mpll-d12-pregate",= PARENT_FW("mpll"), + 12), + [ZX_CLK_MATRIX_MPLL_D16_PREGATE] =3D FIXED_DIV("matrix-mpll-d16-pregate",= PARENT_FW("mpll"), + 16), + + [ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE] =3D FIXED_DIV("matrix-gpll-d2-d2-prega= te", + PARENT_FW("gpll-d2"), 2), + [ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE] =3D FIXED_DIV("matrix-gpll-d2-d4-prega= te", + PARENT_FW("gpll-d2"), 4), + + [ZX_CLK_MATRIX_DPLL_D2_PREGATE] =3D FIXED_DIV("matrix-dpll-d2-pregate", P= ARENT_FW("dpll"), 2), + [ZX_CLK_MATRIX_DPLL_D4_PREGATE] =3D FIXED_DIV("matrix-dpll-d4-pregate", P= ARENT_FW("dpll"), 4), + + /* + * Matrix distribution gates: Every matrix-generated subdivision of the i= nput PLLs + * has a gate in 0x118. The original inputs from topcrm (mpll 624, mpll 1= 24.8, gpll 200, + * gpll 100, dpll 491.52) do not. + * + * Bit 8 is consumed by TDM and the frequency dpll/4 holds up to observat= ion. Bit 9 is + * consumed by an unknown device and the frequency is guessed from the pa= ttern that lower + * bits gate lower frequencies. + */ + [ZX_CLK_MATRIX_MPLL_D16] =3D GATE("matrix-mpll-d16", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D16_PREGATE), 0x118, 0, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D12] =3D GATE("matrix-mpll-d12", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D12_PREGATE), 0x118, 1, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D8] =3D GATE("matrix-mpll-d8", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D8_PREGATE), 0x118, 2, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D6] =3D GATE("matrix-mpll-d6", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D6_PREGATE), 0x118, 3, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D4] =3D GATE("matrix-mpll-d4", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D4_PREGATE), 0x118, 4, + ZX297520V3_AXI_CANDIDATE), + [ZX_CLK_MATRIX_MPLL_D2] =3D GATE("matrix-mpll-d2", + PARENT_ID(ZX_CLK_MATRIX_MPLL_D2_PREGATE), 0x118, 5, 0), + + [ZX_CLK_MATRIX_DPLL_D4] =3D GATE("matrix-dpll-d4", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D4_PREGATE), 0x118, 8, 0), + [ZX_CLK_MATRIX_DPLL_D2] =3D GATE("matrix-dpll-d2", + PARENT_ID(ZX_CLK_MATRIX_DPLL_D2_PREGATE), 0x118, 9, 0), + + [ZX_CLK_MATRIX_GPLL_D2_D4] =3D GATE("matrix-gpll-d2-d4", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D4_PREGATE), + 0x118, 12, 0), + [ZX_CLK_MATRIX_GPLL_D2_D2] =3D GATE("matrix-gpll-d2-d2", + PARENT_ID(ZX_CLK_MATRIX_GPLL_D2_D2_PREGATE), + 0x118, 13, 0), + + [ZX_CLK_CPU_MUX] =3D MUX("cpu-mux", cpu_sel, 0x20, 0, 2), + [ZX_CLK_ZSP_MUX] =3D MUX("zsp-mux", zsp_sel, 0x30, 0, 2), + [ZX_CLK_DDR_CTRL_MUX] =3D MUX("ddr-ctrl-mux", ddr_ctrl_sel, 0x50, 0, = 2), + [ZX_CLK_SD0_MUX] =3D MUX("sd0-mux", sd0_sel, 0x50, 4, 3), + [ZX_CLK_SD1_MUX] =3D MUX("sd1-mux", sd1_sel, 0x50, 8, 3), + [ZX_CLK_NAND_MUX] =3D MUX("nand-mux", nand_sel, 0x50, 12, 2), + [ZX_CLK_EDCP_MUX] =3D MUX("edcp-mux", edcp_sel, 0x50, 16, 2), + [ZX_CLK_TDM_MUX] =3D MUX("tdm-mux", tdm_sel, 0x50, 24, 2), + [ZX_CLK_AXI_MUX] =3D MUX("axi-mux", axi_sel, ZX297520V3_AXI_AP_V= OTE, 0, 3), + + /* + * 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 osc26m gate in topcrm+0x140 - this critical c= lock here protects + * its parent. + * + * Registers 0x148, 0x14c, 0x150, 0x154 allow setting and clearing the ti= mer counter. To + * set the timer, load a value into 0x148 (high 32 bits) and 0x14c (low 3= 2 bits), then + * toggle 0x150 to 1. 0x150 will automatically reset to 0. 0x154 sets the= timer to some + * "clear" value, but this value isn't 0. + */ + [ZX_CLK_SYS_TIMER_WCLK] =3D GATE("sys-timer-wclk", PARENT_FW("wclk-osc2= 6m"), 0x144, 1, + CLK_IS_CRITICAL), + + /* + * Both 0x24 and 0x28 bits 1 and 2 stop the CPU. There is also a bit in t= opcrm+0x138, which + * ZTE's uboot calls "A53 reset", which also stops the CPU. I can't reall= y tell the + * difference between matrix+0x28 and top+0x138. The clock (matrix+0x24) = can be disabled + * and enabled from the Cortex M0 and it will nicely stop and restart the= A53, retaining + * all state. + */ + [ZX_CLK_CPU_WCLK] =3D GATE("cpu-wclk", PARENT_ID(ZX_CLK_CPU_MUX),= 0x24, 1, + CLK_IS_CRITICAL), + [ZX_CLK_CPU_PCLK] =3D GATE("cpu-pclk", clk_main[0], 0x24, 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 enabled if the bootloader selected = a gpll-based rate + * for RAM. + */ + [ZX_CLK_DDR_CTRL_PCLK] =3D GATE("ddr-ctrl-pclk", clk_main[0], 0x100, 1= 7, CLK_IS_CRITICAL), + [ZX_CLK_DDR_CTRL_WCLK] =3D GATE("ddr-ctrl-wclk", PARENT_ID(ZX_CLK_DDR_= CTRL_MUX), 0x100, 18, + CLK_IS_CRITICAL), + + [ZX_CLK_ZSP_PCLK] =3D GATE("zsp-pclk", clk_main[0], 0x34, 0, 0), + [ZX_CLK_ZSP_WCLK] =3D GATE("zsp-wclk", PARENT_ID(ZX_CLK_ZSP_MUX),= 0x34, 1, 0), + + /* Both SDIO controllers depend on the ahb-pclk for register access. */ + [ZX_CLK_SD0_PCLK] =3D GATE("sd0-pclk", PARENT_FW("ahb"), 0x54, 12= , 0), + [ZX_CLK_SD0_WCLK] =3D GATE("sd0-wclk", PARENT_ID(ZX_CLK_SD0_MUX),= 0x54, 13, 0), + [ZX_CLK_SD0_CDET] =3D GATE("sd0-cdet", PARENT_FW("osc32k"), 0x54,= 14, 0), + [ZX_CLK_SD1_PCLK] =3D GATE("sd1-pclk", PARENT_FW("ahb"), 0x54, 4,= 0), + [ZX_CLK_SD1_WCLK] =3D GATE("sd1-wclk", PARENT_ID(ZX_CLK_SD1_MUX),= 0x54, 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. + */ + [ZX_CLK_SD1_CDET] =3D GATE("sd1-cdet", PARENT_FW("osc32k"), 0x54,= 6, 0), + + /* This is some "denali" NAND, not the qspi connected one */ + [ZX_CLK_NAND_WCLK] =3D GATE("nand-wclk", PARENT_ID(ZX_CLK_NAND_MUX= ), 0x54, 20, 0), + [ZX_CLK_NAND_PCLK] =3D GATE("nand-pclk", clk_main[0], 0x54, 21, 0), + + /* + * There is a set of gates for an unknown device at matrix+0x60. It is so= me LTE related + * device and the pclk gates off mmio areas 0xf8000000 and 0xfc000000. Th= ese areas are only + * accessible to M0 and ZSP, not the AP. + * + * If it is fed an incorrect clock, e.g. because dpll is not locked and o= utputs 26 MHz, it + * will spam IRQs at SPI 68. This is likely a distress notification that = some + * internal PLL did not lock or similar. ZTE's kernel has two defines for= SPI 68: + * "LTE_TPU_INT_PS_INT" and "VOU_OSD_INT". The latter is unlikely because= VOU related clocks + * sit in matrix+0x168. + * + * The address space in 0xfc000000 appears to contain a number of differe= nt devices, so I + * have named the clock LTE_MODEM_{W/P}CLK. It is not known how this mmio= area and clock + * relates to SPI 68 or the ABB clock in topcrm+0x144. Because it is not = accessible to the + * AP at all, I don't think we need to care beyond turning on the clocks = before booting the + * ZSP. + * + * Bit 9 in register 0x118 turns the IRQs off, so it is the immediate wcl= k parent. It isn't + * clear what divisor of dpll it is using though. Following the pattern t= hat lower + * frequencies are gated by lower bits, it would indicate dpll/2 or dpll/= 3. + */ + [ZX_CLK_LTE_MODEM_WCLK] =3D GATE("lte-modem-wclk", PARENT_ID(ZX_CLK_MAT= RIX_DPLL_D2), + 0x60, 0, 0), + [ZX_CLK_LTE_MODEM_PCLK] =3D GATE("lte-modem-pclk", clk_main[0], + 0x60, 2, 0), + + [ZX_CLK_EDCP_PCLK] =3D GATE("edcp-pclk", clk_main[0], 0x64, 1, 0), + [ZX_CLK_EDCP_WCLK] =3D GATE("edcp-wclk", PARENT_ID(ZX_CLK_EDCP_MUX= ), 0x64, 2, 0), + + /* + * This seems to be another SPI-Like device. cpko.ko uses it to send cali= bration blobs to + * the LTE radio hardware. After initialization the ZSP firmware takes ov= er control of this + * device. + * + * Testing reveals the parent as matrix's 104 MHz mpll fraction. + */ + [ZX_CLK_RFFE_WCLK] =3D GATE("rffe-wclk", PARENT_ID(ZX_CLK_MATRIX_M= PLL_D6), 0x84, 0, 0), + [ZX_CLK_SSC_WCLK] =3D GATE("ssc-wclk", PARENT_ID(ZX_CLK_MATRIX_MP= LL_D6), 0x84, 1, 0), + [ZX_CLK_SSC_PCLK] =3D GATE("ssc-pclk", clk_main[0], 0x84, 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. + */ + [ZX_CLK_PDCFG_WCLK] =3D GATE("pdcfg-wclk", matrix_unk, 0x88, 0, CLK= _IS_CRITICAL), + [ZX_CLK_PDCFG_PCLK] =3D GATE("pdcfg-pclk", clk_main[0], 0x88, 1, CL= K_IS_CRITICAL), + [ZX_CLK_MBOX_PCLK] =3D GATE("mbox-pclk", clk_main[0], 0x88, 2, 0), + [ZX_CLK_SRAM0_PCLK] =3D GATE("sram0-pclk", clk_main[0], 0x88, 4, 0), + [ZX_CLK_GSM_CFG_PCLK] =3D GATE("gsm-cfg-pclk", clk_main[0], 0x88, 8, = 0), + + /* + * ZTE's driver has a statement 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+0x110 and lists the parents of these clocks as 50 MHz gpll outp= ut, but + * the downstream ZTE GMAC driver never enables the clocks. It turns out = ZTE's code is + * highly misleading. + * + * The GMAC's work clock is definitely not any gpll output because it kee= ps working fine + * with gpll disabled. Gating off matrix-osc26m breaks GMAC, so it must b= e 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. + * + * The gmac-ahb clock is a child of topcrm's ahb-pclk and is required for= DMA transfers in + * and out of GMAC. Without it, GMAC still receives ethernet frames, but = can't drain them + * to memory and will eventually set the RX FIFO overflow flag. + */ + [ZX_CLK_GMAC_WCLK] =3D GATE("gmac-wclk", PARENT_FW("wclk-osc26m"),= 0x110, 0, 0), + [ZX_CLK_GMAC_PCLK] =3D GATE("gmac-pclk", clk_main[0], 0x110, 1, 0), + [ZX_CLK_GMAC_AHB] =3D GATE("gmac-ahb", PARENT_FW("ahb"), 0x110, 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 11:8 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. + */ + [ZX_CLK_AXI_WCLK] =3D GATE("axi-wclk", PARENT_ID(ZX_CLK_AXI_MUX),= 0x8c, 5, + CLK_IS_CRITICAL), + + [ZX_CLK_DMA_PCLK] =3D GATE("dma-pclk", clk_main[0], 0x94, 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. + */ + [ZX_CLK_VOU_WCLK] =3D GATE("vou-wclk", matrix_unk, 0x168, 0, 0), + [ZX_CLK_VOU_PCLK] =3D GATE("vou-pclk", clk_main[0], 0x168, 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 26 MHz and 32 kHz clocks. I c= annot 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 matrixcrm and gets passed down. I2S has a mux in LSP, which can sel= ect the dpll-d4 + * clock. + */ + [ZX_CLK_TOLSP_MPLL_D5_WCLK] =3D GATE("lsp-mpll-d5", PARENT_FW("mpll-d5")= , 0x7c, 0, 0), + [ZX_CLK_TOLSP_MPLL_D4_WCLK] =3D GATE("lsp-mpll-d4", PARENT_ID(ZX_CLK_MAT= RIX_MPLL_D4), + 0x7c, 1, 0), + [ZX_CLK_TOLSP_MPLL_D6_WCLK] =3D GATE("lsp-mpll-d6", PARENT_ID(ZX_CLK_MAT= RIX_MPLL_D6), + 0x7c, 2, 0), + [ZX_CLK_TOLSP_MPLL_D8_WCLK] =3D GATE("lsp-mpll-d8", PARENT_ID(ZX_CLK_MAT= RIX_MPLL_D8), + 0x7c, 3, 0), + [ZX_CLK_TOLSP_MPLL_D12_WCLK] =3D GATE("lsp-mpll-d12", PARENT_ID(ZX_CLK_MA= TRIX_MPLL_D12), + 0x7c, 4, 0), + [ZX_CLK_TOLSP_OSC26M_WCLK] =3D GATE("lsp-osc26m", PARENT_FW("wclk-osc26= m"), 0x7c, 5, 0), + [ZX_CLK_TOLSP_OSC32K_WCLK] =3D GATE("lsp-osc32k", PARENT_FW("osc32k"), = 0x7c, 6, 0), + [ZX_CLK_TOLSP_PCLK] =3D GATE("lsp-pclk", clk_main[0], 0x7c, 7, 0= ), + [ZX_CLK_TOLSP_TDM_WCLK] =3D GATE("lsp-tdm-wclk", PARENT_ID(ZX_CLK_TD= M_MUX), 0x7c, 8, 0), + [ZX_CLK_TOLSP_DPLL_D4_WCLK] =3D GATE("lsp-dpll-d4", PARENT_ID(ZX_CLK_MAT= RIX_DPLL_D4), + 0x7c, 9, 0), +}; + +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; + + return regmap_write(map, 0x12c, 1); +} + +static const unsigned int zx297520v3_matrix_exports[] =3D { + [ZX297520V3_SYS_TIMER_WCLK] =3D ZX_CLK_SYS_TIMER_WCLK, + [ZX297520V3_CPU_WCLK] =3D ZX_CLK_CPU_WCLK, + [ZX297520V3_CPU_PCLK] =3D ZX_CLK_CPU_PCLK, + [ZX297520V3_ZSP_WCLK] =3D ZX_CLK_ZSP_WCLK, + [ZX297520V3_ZSP_PCLK] =3D ZX_CLK_ZSP_PCLK, + [ZX297520V3_DDR_CTRL_PCLK] =3D ZX_CLK_DDR_CTRL_PCLK, + [ZX297520V3_DDR_CTRL_WCLK] =3D ZX_CLK_DDR_CTRL_WCLK, + [ZX297520V3_EDCP_WCLK] =3D ZX_CLK_EDCP_WCLK, + [ZX297520V3_EDCP_PCLK] =3D ZX_CLK_EDCP_PCLK, + [ZX297520V3_SD0_WCLK] =3D ZX_CLK_SD0_WCLK, + [ZX297520V3_SD0_PCLK] =3D ZX_CLK_SD0_PCLK, + [ZX297520V3_SD0_CDET] =3D ZX_CLK_SD0_CDET, + [ZX297520V3_SD1_WCLK] =3D ZX_CLK_SD1_WCLK, + [ZX297520V3_SD1_PCLK] =3D ZX_CLK_SD1_PCLK, + [ZX297520V3_SD1_CDET] =3D ZX_CLK_SD1_CDET, + [ZX297520V3_NAND_WCLK] =3D ZX_CLK_NAND_WCLK, + [ZX297520V3_NAND_PCLK] =3D ZX_CLK_NAND_PCLK, + [ZX297520V3_DMA_PCLK] =3D ZX_CLK_DMA_PCLK, + [ZX297520V3_MBOX_PCLK] =3D ZX_CLK_MBOX_PCLK, + [ZX297520V3_PDCFG_WCLK] =3D ZX_CLK_PDCFG_WCLK, + [ZX297520V3_PDCFG_PCLK] =3D ZX_CLK_PDCFG_PCLK, + [ZX297520V3_RFFE_WCLK] =3D ZX_CLK_RFFE_WCLK, + [ZX297520V3_SSC_WCLK] =3D ZX_CLK_SSC_WCLK, + [ZX297520V3_SSC_PCLK] =3D ZX_CLK_SSC_PCLK, + [ZX297520V3_AXI_WCLK] =3D ZX_CLK_AXI_WCLK, + [ZX297520V3_GMAC_WCLK] =3D ZX_CLK_GMAC_WCLK, + [ZX297520V3_GMAC_PCLK] =3D ZX_CLK_GMAC_PCLK, + [ZX297520V3_GMAC_AHB] =3D ZX_CLK_GMAC_AHB, + [ZX297520V3_VOU_WCLK] =3D ZX_CLK_VOU_WCLK, + [ZX297520V3_VOU_PCLK] =3D ZX_CLK_VOU_PCLK, + [ZX297520V3_LSP_MPLL_D5_WCLK] =3D ZX_CLK_TOLSP_MPLL_D5_WCLK, + [ZX297520V3_LSP_MPLL_D4_WCLK] =3D ZX_CLK_TOLSP_MPLL_D4_WCLK, + [ZX297520V3_LSP_MPLL_D6_WCLK] =3D ZX_CLK_TOLSP_MPLL_D6_WCLK, + [ZX297520V3_LSP_MPLL_D8_WCLK] =3D ZX_CLK_TOLSP_MPLL_D8_WCLK, + [ZX297520V3_LSP_MPLL_D12_WCLK] =3D ZX_CLK_TOLSP_MPLL_D12_WCLK, + [ZX297520V3_LSP_OSC26M_WCLK] =3D ZX_CLK_TOLSP_OSC26M_WCLK, + [ZX297520V3_LSP_OSC32K_WCLK] =3D ZX_CLK_TOLSP_OSC32K_WCLK, + [ZX297520V3_LSP_PCLK] =3D ZX_CLK_TOLSP_PCLK, + [ZX297520V3_LSP_TDM_WCLK] =3D ZX_CLK_TOLSP_TDM_WCLK, + [ZX297520V3_LSP_DPLL_D4_WCLK] =3D ZX_CLK_TOLSP_DPLL_D4_WCLK, + [ZX297520V3_SRAM0_PCLK] =3D ZX_CLK_SRAM0_PCLK, + [ZX297520V3_GSM_CFG_PCLK] =3D ZX_CLK_GSM_CFG_PCLK, + [ZX297520V3_LTE_MODEM_WCLK] =3D ZX_CLK_LTE_MODEM_WCLK, + [ZX297520V3_LTE_MODEM_PCLK] =3D ZX_CLK_LTE_MODEM_PCLK, +}; + +static const struct zx_clk_data zx297520v3_matrixclk_data =3D { + .init =3D zx297520v3_matrix_init, + .clocks =3D zx297520v3_matrix_clocks, + .num_clocks =3D ARRAY_SIZE(zx297520v3_matrix_clocks), + .exports =3D zx297520v3_matrix_exports, + .num_exports =3D ARRAY_SIZE(zx297520v3_matrix_exports), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id =3D platform_get_device_id(pdev); @@ -828,6 +1350,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.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (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 7954B3BE636 for ; Sun, 27 Sep 2026 20:14:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540093; cv=none; b=iA4oJQ0xbvq9D+PeOMKgQ/lzzL+MtOs1ZN+dK+0IlkxF00uQ9YvvTN+gkKQoQkvSzoVfR9dcs7eltSPFwjM1chtOkqI9G45yBmR2xU1YG2ZT3ssfENOmE5bpaKUbKSZyW/QVpcLPNaNYOV7xPrgP2KAjQJhTosWiw44imB52qGQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540093; c=relaxed/simple; bh=7RBcqN9BQGJ8fpzwo1DLsoNVM0UE13olaQZYO/VlO6E=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DKLUOHls/sEK4TViHUa1eQa0xwmgreg7FVqF6Ee7ICGt7CEqtzssRNmqZNdlYGOADAJy0Lsz0lbg8P6aj5z+ezAFZEvwDzdljFy7ogdz1WnUKw3utyhBhrVVzuJ7f4pq1uDrbNgiT7nZ+Bb2qgdJcvpAFAhWdG4tu425e0kULl8= 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=OsLCdQy2; arc=none smtp.client-ip=74.125.225.140 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="OsLCdQy2" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49b912d3920so17659765e9.1 for ; Sun, 27 Sep 2026 13:14:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540089; x=1791144889; 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=BpfwRIaOQGXPNv4meb2bFB2xBhmOJmIWfeF6v6SGA8g=; b=OsLCdQy2+3boTNLmcXTWO+YqZrVIqZyHbv/QhgdOpWKWzmGcGJ/3dcu8caoeKr8Zap dfHdWhGnvdr12ERuudU4JbjeWLQJwUT6WFHO4tJyNpnNrA78FYx3wsG5zbJ65xsL2twl Oz3Z5avWmuD/zPp2+M5a0jVpOhGA6X6n9wf7JW4Ym26UAsPJfpnPPWsXTcu/EW0YFcwg hiyY3llXu7Zovz3xL52OPGSlVb81SdqkpAOpPKVunMJBFD/dbAmORauv3AHs5SkKWdtT ReEd7+CGgh474EY+7qBQpu2uvXCAk1Lsj+3B2fE2cs34rq6fljw4m2HqMw0l2EW5B/Xd vpLw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540089; x=1791144889; 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=BpfwRIaOQGXPNv4meb2bFB2xBhmOJmIWfeF6v6SGA8g=; b=CDDRXH9jVrVbrRufjHWpxq2e3oVGeNYtIFCqB/lPyl3SF+8D3RBC6fUASWFc1QAucu fHkTkT91wRwwh8LELOpGmt1gbmJkMkcTW+0UG3PTPeySprEGj8SE9IJ+o1bTOmBhLN4l eKCBwUBeKuH/BuGgbhRIYx4AIEDHGTTiSolUtBzzDeGSuh3Nq48sA2ZZ3kK03qVIYXNi IrtZv5Ssoe/Devcu4TsoT6pAL65oYf+IS+rP0Jlp+BSg4NCzo57BQ3brwaMgy2zJiSo2 M/4U6qsqi9iNTIzK7u//MHBLFEh9wipKoI+84Cc9rligRkm03S5oArTLfi4auBEkdhsK aMAw== X-Forwarded-Encrypted: i=1; AKwUvBwdVj71lWKxtsrty9IkcHKFr/z4Y3iRsMlBh27E9cCXYeo4Hf3Q8bC8qBFZhhpgtAyj+3b5uUnnTCwACtM=@vger.kernel.org X-Gm-Message-State: AFuF++kyXUWMPdfKknjY3eYGgT9ML7Fg6ALhUIH/U/Gz4PVFt0TvvFyy OUfjQlhi8cT04pw/s3GbqNK0tvX6PmRAhWK3j9rE5MS4vMPJAReoqXWX X-Gm-Gg: AYBFou3MrdR6mFxoYFc60ivDToxIRSFHkVtQiBO9pTMrbYxQJcACc3eKGE4x4LDrRh2 h9xlywfe+KmVeO/cxPGYz6a1kywexAo+xuNWW2VDm8dEqO/AWQFvBcQwM4F/v2WJ1tpUdYKFdyq Mn7okGMMaFRJdtcAMflPeKl5W301/Dzh5WMJM+0aj7atKVo6gAwD/niR1joksWzSWpdKEUFhVC3 ZGQjL8APDI73+eqJtv1ocYJMf0xRDDxAW8wynN2AszWGmHq/PS94p2cNal7XxLI9rEdVZtzoRyM p3a0Esdal60FTUoq5YCnZHFUZIA/OpI0M4W8znwF/ycwGWOmflze+lIIvWAR9F+1nbxW11qINLT wO1BZBKzFrjP8BumVf8CM2j+iri2M8nX723urhwUklMoTZCNdHkqg2WwyEa0b9+/ARC9vJGSnjh 2v0qBoaszT5DXPteqFYbIQPiaLQVJPZD8H3vh0UeJrj4JxaU/lSrtpUQ9/Sh5odMiYTweJd0qZd MTFo2ep X-Received: by 2002:a05:600c:c177:b0:49c:fc6c:be19 with SMTP id 5b1f17b1804b1-49fe67080b1mr209990565e9.31.1790540088602; Sun, 27 Sep 2026 13:14:48 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:48 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:39 +0300 Subject: [PATCH v13 11/13] clk: zte: Introduce a driver for zx297520v3 LSP 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: <20260927-zx29clk-v13-11-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=14750; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=7RBcqN9BQGJ8fpzwo1DLsoNVM0UE13olaQZYO/VlO6E=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1tgyjIKqq++JTng/I0RN+x3A4TAECyDi7r TVAsE9EZfCJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiI/3g//W8duOB5UM3M7IZMaLElUd9xhisQuSIH NoSIiWAvURQ39N7vB4UNBzyqCah3ykpK0Yczm933U4+T0pE+l2QLLk/cGGKb851Sqv0p2Cf+PYi 20rO+Cd9GAx/QYdoZ+o+EY5OS+OdVBdvADO8oTe61ugkFsivTe3IKg7TWyXyGCBgHlxpnvBxYIP TPEpgJDzteHg4qE8sWqNTl8nGNI8spiF+onCgIVcDy8KS9zI0esc1Pb5DKRwfrUtnotsI/LGTPd 6oS92MVo+SYMeBDm4PPjh+o11LrXWm9rO+ODas/1JZDT4SQzXV1KKhhoGIOR3q+GaKa+nqEISsU o0t0JUovdc56iewGR6nHwgcLXzuq6wHLjtOpXsfbRS6/H1fCFtrFx3dTDzflL5c75NfsmMVZ++b bo8ia6gcLv+f0AXi5i2lZT+9ipv+2uPm0vo7/8cqVnKHXZaLmXU+GGqgo+JoQTtN1XeMSudkNjn GUqbPH2kvHz/0KdiP/C0ll7T0YKKmJQros6n4wA5vCZkv26RZB4FilWMJHIn6ElK8gko+F2AEGg 1HdY9TM1eJWHIeFxZZ72gLrZXL3D6+4Dn0lhix37X2PehGnx30+kW8fn37tNZtqyao8MHW7yrjQ zalj+Mtlw4SJbLTbWV7RTpQxbJ7ZjbXPd4hgGTGowI0QmHBgNMzw= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 "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. Reviewed-by: Brian Masney Signed-off-by: Stefan D=C3=B6singer --- Versions 10, 11, 12: Unchanged Version 9: Link internal parents by an (internal) clock ID rather than names. One intentional clock tree change: The PWM device's parent is the 104 MHz mpll-d6 input. With some manual experimentation I managed to make the WiFi led blink with PWM, so I could confirm which matrixcrm bit gates off its parent. Update the comments to say that the device at lspcrm+0x4000 is indeed a Pulse Width Modulator. @Sashiko: If you find any other clock tree changes compared to version 8, they are unintentional and likely bugs. Version 8: Double-checked pclk and wclk. They were the wrong way around in previous submissions. Pclk is bit 0, wclk is bit 1. 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 | 285 +++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 285 insertions(+) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c index d5f8bc4064bd..e0f78f841bde 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -1334,6 +1334,287 @@ static const struct zx_clk_data zx297520v3_matrixcl= k_data =3D { .num_exports =3D ARRAY_SIZE(zx297520v3_matrix_exports), }; =20 +/* + * LSP clock entries have a common pattern: Bit 0 for pclk, Bit 1 for wclk= . 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: + * + * CRM 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. + * + * The device at offset 0x4000 (clk reg 0x10) is a PWM device. The ID matc= hes that of i2c, it has a + * larger register set. ZTE's kernel does not operate it at all. The old u= pstream pwm-zx.c driver + * provided enough instructions to blink the Wifi led and isolate the pare= nt. + */ + +enum lsp_clock_ids { + ZX_CLK_TIMER_L1_MUX, + ZX_CLK_WDT_L2_MUX, + ZX_CLK_WDT_L3_MUX, + ZX_CLK_I2S0_MUX, + ZX_CLK_I2S1_MUX, + ZX_CLK_QSPI_MUX, + ZX_CLK_UART1_MUX, + ZX_CLK_I2C1_MUX, + ZX_CLK_SPI0_MUX, + ZX_CLK_TIMER_LB_MUX, + ZX_CLK_TIMER_LC_MUX, + ZX_CLK_UART2_MUX, + ZX_CLK_WDT_LE_MUX, + ZX_CLK_TIMER_LF_MUX, + ZX_CLK_SPI1_MUX, + ZX_CLK_TIMER_L11_MUX, + + ZX_CLK_TIMER_L1_DIV, + ZX_CLK_WDT_L2_DIV, + ZX_CLK_WDT_L3_DIV, + ZX_CLK_I2S0_DIV, + ZX_CLK_I2S1_DIV, + ZX_CLK_SPI0_DIV, + ZX_CLK_TIMER_LB_DIV, + ZX_CLK_TIMER_LC_DIV, + ZX_CLK_WDT_LE_DIV, + ZX_CLK_TIMER_LF_DIV, + ZX_CLK_SPI1_DIV, + ZX_CLK_TIMER_L11_DIV, + ZX_CLK_TDM_DIV, + + ZX_CLK_TIMER_L1_PCLK, + ZX_CLK_TIMER_L1_WCLK, + ZX_CLK_WDT_L2_PCLK, + ZX_CLK_WDT_L2_WCLK, + ZX_CLK_WDT_L3_PCLK, + ZX_CLK_WDT_L3_WCLK, + ZX_CLK_PWM_PCLK, + ZX_CLK_PWM_WCLK, + ZX_CLK_I2S0_PCLK, + ZX_CLK_I2S0_WCLK, + ZX_CLK_I2S1_PCLK, + ZX_CLK_I2S1_WCLK, + ZX_CLK_QSPI_PCLK, + ZX_CLK_QSPI_WCLK, + ZX_CLK_UART1_PCLK, + ZX_CLK_UART1_WCLK, + ZX_CLK_I2C1_PCLK, + ZX_CLK_I2C1_WCLK, + ZX_CLK_SPI0_PCLK, + ZX_CLK_SPI0_WCLK, + ZX_CLK_TIMER_LB_PCLK, + ZX_CLK_TIMER_LB_WCLK, + ZX_CLK_TIMER_LC_PCLK, + ZX_CLK_TIMER_LC_WCLK, + ZX_CLK_UART2_PCLK, + ZX_CLK_UART2_WCLK, + ZX_CLK_WDT_LE_PCLK, + ZX_CLK_WDT_LE_WCLK, + ZX_CLK_TIMER_LF_PCLK, + ZX_CLK_TIMER_LF_WCLK, + ZX_CLK_SPI1_PCLK, + ZX_CLK_SPI1_WCLK, + ZX_CLK_TIMER_L11_PCLK, + ZX_CLK_TIMER_L11_WCLK, + ZX_CLK_TDM_PCLK, + ZX_CLK_TDM_WCLK, +}; + +static const struct zx_parent_desc timer_lsp_sel[] =3D { + PARENT_FW("osc32k"), + PARENT_FW("osc26m"), +}; + +static const struct zx_parent_desc uart_lsp_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d6"), +}; + +static const struct zx_parent_desc i2s_lsp_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_FW("dpll-d4"), + PARENT_FW("mpll-d6"), + /* Unknown */ +}; + +static const struct zx_parent_desc spi_lsp_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d4"), + PARENT_FW("mpll-d6"), + /* Unknown */ +}; + +static const struct zx_parent_desc qspi_lsp_sel[] =3D { + PARENT_FW("osc26m"), + PARENT_FW("mpll-d4"), + PARENT_FW("mpll-d5"), + PARENT_FW("mpll-d6"), + PARENT_FW("mpll-d8"), + PARENT_FW("mpll-d12"), + PARENT_FW("osc26m"), + PARENT_FW("osc26m"), +}; + +static const struct zx_clock zx297520v3_lsp_clocks[] =3D { + [ZX_CLK_TIMER_L1_MUX] =3D MUX("timer-l1-mux", timer_lsp_sel, 0x0= 4, 4, 1), + [ZX_CLK_WDT_L2_MUX] =3D MUX("wdt-l2-mux", timer_lsp_sel, 0x0= 8, 4, 1), + [ZX_CLK_WDT_L3_MUX] =3D MUX("wdt-l3-mux", timer_lsp_sel, 0x0= c, 4, 1), + /* PWM: No mux bit can be set */ + [ZX_CLK_I2S0_MUX] =3D MUX("i2s0-mux", i2s_lsp_sel, 0x1= 4, 4, 2), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_MUX] =3D MUX("i2s1-mux", i2s_lsp_sel, 0x1= c, 4, 2), + /* 0x20: Always 0 */ + [ZX_CLK_QSPI_MUX] =3D MUX("qspi-mux", qspi_lsp_sel, 0x2= 4, 4, 3), + [ZX_CLK_UART1_MUX] =3D MUX("uart1-mux", uart_lsp_sel, 0x2= 8, 4, 1), + [ZX_CLK_I2C1_MUX] =3D MUX("i2c1-mux", uart_lsp_sel, 0x2= c, 4, 1), + [ZX_CLK_SPI0_MUX] =3D MUX("spi0-mux", spi_lsp_sel, 0x3= 0, 4, 2), + [ZX_CLK_TIMER_LB_MUX] =3D MUX("timer-lb-mux", timer_lsp_sel, 0x3= 4, 4, 1), + [ZX_CLK_TIMER_LC_MUX] =3D MUX("timer-lc-mux", timer_lsp_sel, 0x3= 8, 4, 1), + [ZX_CLK_UART2_MUX] =3D MUX("uart2-mux", uart_lsp_sel, 0x3= c, 4, 1), + [ZX_CLK_WDT_LE_MUX] =3D MUX("wdt-le-mux", timer_lsp_sel, 0x4= 0, 4, 1), + [ZX_CLK_TIMER_LF_MUX] =3D MUX("timer-lf-mux", timer_lsp_sel, 0x4= 4, 4, 1), + [ZX_CLK_SPI1_MUX] =3D MUX("spi1-mux", spi_lsp_sel, 0x4= 8, 4, 2), + [ZX_CLK_TIMER_L11_MUX] =3D MUX("timer-l11-mux", timer_lsp_sel, 0x4= c, 4, 1), + /* TDM: No mux in LSP. Instead, it is in matrix with a separate clk line = to LSP */ + + [ZX_CLK_TIMER_L1_DIV] =3D DIV("timer-l1-div", PARENT_ID(ZX_CLK_TIMER_= L1_MUX), + 0x04, 12, 4), + [ZX_CLK_WDT_L2_DIV] =3D DIV("wdt-l2-div", PARENT_ID(ZX_CLK_WDT_L2_M= UX), 0x08, 12, 4), + [ZX_CLK_WDT_L3_DIV] =3D DIV("wdt-l3-div", PARENT_ID(ZX_CLK_WDT_L3_M= UX), 0x0c, 12, 4), + /* PWM: No div */ + [ZX_CLK_I2S0_DIV] =3D DIV("i2s0-div", PARENT_ID(ZX_CLK_I2S0_MUX),= 0x14, 16, 4), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_DIV] =3D DIV("i2s1-div", PARENT_ID(ZX_CLK_I2S1_MUX),= 0x1c, 16, 4), + /* 0x20: Always 0 */ + /* qspi, uart1, i2c1: No div */ + [ZX_CLK_SPI0_DIV] =3D DIV("spi0-div", PARENT_ID(ZX_CLK_SPI0_MUX),= 0x30, 12, 4), + [ZX_CLK_TIMER_LB_DIV] =3D DIV("timer-lb-div", PARENT_ID(ZX_CLK_TIMER_= LB_MUX), + 0x34, 12, 4), + [ZX_CLK_TIMER_LC_DIV] =3D DIV("timer-lc-div", PARENT_ID(ZX_CLK_TIMER_= LC_MUX), + 0x38, 12, 4), + /* uart2: No div */ + [ZX_CLK_WDT_LE_DIV] =3D DIV("wdt-le-div", PARENT_ID(ZX_CLK_WDT_LE_M= UX), 0x40, 12, 4), + [ZX_CLK_TIMER_LF_DIV] =3D DIV("timer-lf-div", PARENT_ID(ZX_CLK_TIMER_= LF_MUX), + 0x44, 12, 4), + [ZX_CLK_SPI1_DIV] =3D DIV("spi1-div", PARENT_ID(ZX_CLK_SPI1_MUX),= 0x48, 12, 4), + [ZX_CLK_TIMER_L11_DIV] =3D DIV("timer-l11-div", PARENT_ID(ZX_CLK_TIMER= _L11_MUX), + 0x4c, 12, 4), + [ZX_CLK_TDM_DIV] =3D DIV("tdm-div", PARENT_FW("tdm-wclk"), 0x50, 1= 6, 4), + + [ZX_CLK_TIMER_L1_PCLK] =3D GATE("timer-l1-pclk", PARENT_FW("pclk"), 0x04= , 0, 0), + [ZX_CLK_TIMER_L1_WCLK] =3D GATE("timer-l1-wclk", PARENT_ID(ZX_CLK_TIMER_= L1_DIV), 0x04, 1, 0), + [ZX_CLK_WDT_L2_PCLK] =3D GATE("wdt-l2-pclk", PARENT_FW("pclk"), 0x08, = 0, 0), + [ZX_CLK_WDT_L2_WCLK] =3D GATE("wdt-l2-wclk", PARENT_ID(ZX_CLK_WDT_L2_D= IV), 0x08, 1, 0), + [ZX_CLK_WDT_L3_PCLK] =3D GATE("wdt-l3-pclk", PARENT_FW("pclk"), 0x0c, = 0, 0), + [ZX_CLK_WDT_L3_WCLK] =3D GATE("wdt-l3-wclk", PARENT_ID(ZX_CLK_WDT_L3_D= IV), 0x0c, 1, 0), + [ZX_CLK_PWM_PCLK] =3D GATE("pwm-pclk", PARENT_FW("pclk"), 0x10, 0, = 0), + [ZX_CLK_PWM_WCLK] =3D GATE("pwm-wclk", PARENT_FW("mpll-d6"), 0x10, = 1, 0), + [ZX_CLK_I2S0_PCLK] =3D GATE("i2s0-pclk", PARENT_FW("pclk"), 0x14, 0,= 0), + [ZX_CLK_I2S0_WCLK] =3D GATE("i2s0-wclk", PARENT_ID(ZX_CLK_I2S0_DIV),= 0x14, 1, 0), + /* 0x18: Always 0 */ + [ZX_CLK_I2S1_PCLK] =3D GATE("i2s1-pclk", PARENT_FW("pclk"), 0x1c, 0,= 0), + [ZX_CLK_I2S1_WCLK] =3D GATE("i2s1-wclk", PARENT_ID(ZX_CLK_I2S1_DIV),= 0x1c, 1, 0), + /* 0x20: Always 0 */ + [ZX_CLK_QSPI_PCLK] =3D GATE("qspi-pclk", PARENT_FW("pclk"), 0x24, 0,= 0), + [ZX_CLK_QSPI_WCLK] =3D GATE("qspi-wclk", PARENT_ID(ZX_CLK_QSPI_MUX),= 0x24, 1, 0), + [ZX_CLK_UART1_PCLK] =3D GATE("uart1-pclk", PARENT_FW("pclk"), 0x28, 0= , 0), + [ZX_CLK_UART1_WCLK] =3D GATE("uart1-wclk", PARENT_ID(ZX_CLK_UART1_MUX= ), 0x28, 1, 0), + [ZX_CLK_I2C1_PCLK] =3D GATE("i2c1-pclk", PARENT_FW("pclk"), 0x2c, 0,= 0), + [ZX_CLK_I2C1_WCLK] =3D GATE("i2c1-wclk", PARENT_ID(ZX_CLK_I2C1_MUX),= 0x2c, 1, 0), + [ZX_CLK_SPI0_PCLK] =3D GATE("spi0-pclk", PARENT_FW("pclk"), 0x30, 0,= 0), + [ZX_CLK_SPI0_WCLK] =3D GATE("spi0-wclk", PARENT_ID(ZX_CLK_SPI0_DIV),= 0x30, 1, 0), + [ZX_CLK_TIMER_LB_PCLK] =3D GATE("timer-lb-pclk", PARENT_FW("pclk"), 0x34= , 0, 0), + [ZX_CLK_TIMER_LB_WCLK] =3D GATE("timer-lb-wclk", PARENT_ID(ZX_CLK_TIMER_= LB_DIV), 0x34, 1, 0), + [ZX_CLK_TIMER_LC_PCLK] =3D GATE("timer-lc-pclk", PARENT_FW("pclk"), 0x38= , 0, 0), + [ZX_CLK_TIMER_LC_WCLK] =3D GATE("timer-lc-wclk", PARENT_ID(ZX_CLK_TIMER_= LC_DIV), 0x38, 1, 0), + [ZX_CLK_UART2_PCLK] =3D GATE("uart2-pclk", PARENT_FW("pclk"), 0x3c, 0= , 0), + [ZX_CLK_UART2_WCLK] =3D GATE("uart2-wclk", PARENT_ID(ZX_CLK_UART2_MUX= ), 0x3c, 1, 0), + [ZX_CLK_WDT_LE_PCLK] =3D GATE("wdt-le-pclk", PARENT_FW("pclk"), 0x40, = 0, 0), + [ZX_CLK_WDT_LE_WCLK] =3D GATE("wdt-le-wclk", PARENT_ID(ZX_CLK_WDT_LE_D= IV), 0x40, 1, 0), + [ZX_CLK_TIMER_LF_PCLK] =3D GATE("timer-lf-pclk", PARENT_FW("pclk"), 0x44= , 0, 0), + [ZX_CLK_TIMER_LF_WCLK] =3D GATE("timer-lf-wclk", PARENT_ID(ZX_CLK_TIMER_= LF_DIV), 0x44, 1, 0), + [ZX_CLK_SPI1_PCLK] =3D GATE("spi1-pclk", PARENT_FW("pclk"), 0x48, 0,= 0), + [ZX_CLK_SPI1_WCLK] =3D GATE("spi1-wclk", PARENT_ID(ZX_CLK_SPI1_DIV),= 0x48, 1, 0), + [ZX_CLK_TIMER_L11_PCLK] =3D GATE("timer-l11-pclk", PARENT_FW("pclk"), 0x4= c, 0, 0), + [ZX_CLK_TIMER_L11_WCLK] =3D GATE("timer-l11-wclk", PARENT_ID(ZX_CLK_TIMER= _L11_DIV), + 0x4c, 1, 0), + [ZX_CLK_TDM_PCLK] =3D GATE("tdm-pclk", PARENT_FW("pclk"), 0x50, 0, = 0), + [ZX_CLK_TDM_WCLK] =3D GATE("tdm-wclk", PARENT_ID(ZX_CLK_TDM_DIV), 0= x50, 1, 0), +}; + +static const unsigned int zx297520v3_lsp_exports[] =3D { + [ZX297520V3_TIMER_L1_WCLK] =3D ZX_CLK_TIMER_L1_WCLK, + [ZX297520V3_TIMER_L1_PCLK] =3D ZX_CLK_TIMER_L1_PCLK, + [ZX297520V3_WDT_L2_WCLK] =3D ZX_CLK_WDT_L2_WCLK, + [ZX297520V3_WDT_L2_PCLK] =3D ZX_CLK_WDT_L2_PCLK, + [ZX297520V3_WDT_L3_WCLK] =3D ZX_CLK_WDT_L3_WCLK, + [ZX297520V3_WDT_L3_PCLK] =3D ZX_CLK_WDT_L3_PCLK, + [ZX297520V3_PWM_WCLK] =3D ZX_CLK_PWM_WCLK, + [ZX297520V3_PWM_PCLK] =3D ZX_CLK_PWM_PCLK, + [ZX297520V3_I2S0_WCLK] =3D ZX_CLK_I2S0_WCLK, + [ZX297520V3_I2S0_PCLK] =3D ZX_CLK_I2S0_PCLK, + [ZX297520V3_I2S1_WCLK] =3D ZX_CLK_I2S1_WCLK, + [ZX297520V3_I2S1_PCLK] =3D ZX_CLK_I2S1_PCLK, + [ZX297520V3_QSPI_WCLK] =3D ZX_CLK_QSPI_WCLK, + [ZX297520V3_QSPI_PCLK] =3D ZX_CLK_QSPI_PCLK, + [ZX297520V3_UART1_WCLK] =3D ZX_CLK_UART1_WCLK, + [ZX297520V3_UART1_PCLK] =3D ZX_CLK_UART1_PCLK, + [ZX297520V3_I2C1_WCLK] =3D ZX_CLK_I2C1_WCLK, + [ZX297520V3_I2C1_PCLK] =3D ZX_CLK_I2C1_PCLK, + [ZX297520V3_SPI0_WCLK] =3D ZX_CLK_SPI0_WCLK, + [ZX297520V3_SPI0_PCLK] =3D ZX_CLK_SPI0_PCLK, + [ZX297520V3_TIMER_LB_WCLK] =3D ZX_CLK_TIMER_LB_WCLK, + [ZX297520V3_TIMER_LB_PCLK] =3D ZX_CLK_TIMER_LB_PCLK, + [ZX297520V3_TIMER_LC_WCLK] =3D ZX_CLK_TIMER_LC_WCLK, + [ZX297520V3_TIMER_LC_PCLK] =3D ZX_CLK_TIMER_LC_PCLK, + [ZX297520V3_UART2_WCLK] =3D ZX_CLK_UART2_WCLK, + [ZX297520V3_UART2_PCLK] =3D ZX_CLK_UART2_PCLK, + [ZX297520V3_WDT_LE_WCLK] =3D ZX_CLK_WDT_LE_WCLK, + [ZX297520V3_WDT_LE_PCLK] =3D ZX_CLK_WDT_LE_PCLK, + [ZX297520V3_TIMER_LF_WCLK] =3D ZX_CLK_TIMER_LF_WCLK, + [ZX297520V3_TIMER_LF_PCLK] =3D ZX_CLK_TIMER_LF_PCLK, + [ZX297520V3_SPI1_WCLK] =3D ZX_CLK_SPI1_WCLK, + [ZX297520V3_SPI1_PCLK] =3D ZX_CLK_SPI1_PCLK, + [ZX297520V3_TIMER_L11_WCLK] =3D ZX_CLK_TIMER_L11_WCLK, + [ZX297520V3_TIMER_L11_PCLK] =3D ZX_CLK_TIMER_L11_PCLK, + [ZX297520V3_TDM_WCLK] =3D ZX_CLK_TDM_WCLK, + [ZX297520V3_TDM_PCLK] =3D ZX_CLK_TDM_PCLK, +}; + +static const struct zx_clk_data zx297520v3_lspclk_data =3D { + .clocks =3D zx297520v3_lsp_clocks, + .num_clocks =3D ARRAY_SIZE(zx297520v3_lsp_clocks), + .exports =3D zx297520v3_lsp_exports, + .num_exports =3D ARRAY_SIZE(zx297520v3_lsp_exports), +}; + static int clk_zx297520v3_probe(struct platform_device *pdev) { const struct platform_device_id *id =3D platform_get_device_id(pdev); @@ -1354,6 +1635,10 @@ static const struct platform_device_id clk_zx297520v= 3_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.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f13.google.com (mail-wm2-f13.google.com [74.125.225.141]) (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 2D0DF3BFE59 for ; Sun, 27 Sep 2026 20:14:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.141 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540099; cv=none; b=EszQVF2V58t4g9qkmsI0vXnBOA8qX6yey6WAuGK0AIo8ShtiRwqnuHfO2vrJwUCNN0JgCUMsA/wvDtbrw20O3VqsaD/rLBVf80IbEWXJRgFx+ZFOqwSjmxxpV6nOPqDDiJLseYtcAYf8klz6x2U3czjyiKqDJqcaYPLtZ+fyNYc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540099; c=relaxed/simple; bh=hpsSqsSsSLYK5AZPSKuwD6Ytr5Hn4TTt02kVTQyewa0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cpw73toeiqYuiFO6upolx2SYHHraDMUE1pj485RO+To6rVfjYyXueAkmDgX9bHGK4dZ027OYDaaerakFiQd1hadPk55Xh9FV7RfOSEpSBpiiwWT4hcJkbG0xOVt6VUq+/qkKdkMH07iWPruX+ATKOFzJywJeuqmar0OGy0yuRIw= 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=MkjSWb9G; arc=none smtp.client-ip=74.125.225.141 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="MkjSWb9G" Received: by mail-wm2-f13.google.com with SMTP id 5b1f17b1804b1-49e71cdb22bso17187125e9.2 for ; Sun, 27 Sep 2026 13:14:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540094; x=1791144894; 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=S50GnjNT4LcU7HxZLphXVRYRUilWr4TH9rawik4ZJKw=; b=MkjSWb9GwP4RsRhFLHEiUiwNDvIg3KcLlbpHrSCDNKrfprlSzcC4tQMFHE0H2//t8D NuUvqMVMMpsrCnlfiOO719WNwzRkDjyxuR6Txy0G1WFlvQ+l5ptw/PXMeMHPNdvZJ4yh 40jRKKJ1xqbnBBF5OR78J43Vk27ce6CmdpuIU3NOMqxGSmyW3B54uaSaM32FKRDFz8lz +JezhjriQ/sHtctS/YkLdKRGDphCQ4zXw2Nsf6o9ERTubXJrk1pxdJpoqPnLzvhK4nma sXMDY9p0BwPNb5fUXN8dmtS8s9b5d96lli8UQ0HrM46taoi38rJDd9kSz35ZElOlVGfq w1aw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540094; x=1791144894; 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=S50GnjNT4LcU7HxZLphXVRYRUilWr4TH9rawik4ZJKw=; b=K6r4uylST9JBPET+8yo316fN2SEQzZUQ6MFQGjpgKxa7OwpNyKIV3V2hW81yIig53a xIE6NU3crMX5Zj1EEEwItoQw9vpQMkNM92PR9thJ/bVQnbiCUpUbWJYo8U1dObAqzk2j HXVoa6Gm+HOY8xwJ86YNYRbsTwtbMCSkMk0pJWzKhFLGw1QKrN+D8CEwLdxCYj+IJ2fp noiqZTL+ZO88pxLWX3p/TFFueoIHcn5qlrpjpYaIhlpFXhTxlUe/QEEyA8bbVGb7Zipc cCp0UY0wLFtLahG0pasBh5GKD3ecntUaHIa+UOXrPJ2FY7pIce1kaMCKkF0NtXY/pK3B 4gvg== X-Forwarded-Encrypted: i=1; AKwUvByGeUD+8KQAHtSyVr7ZKD6b5y1CjsWAvug+T8GHz33eTuyyEX1q9Hr8NoLhhkCwURyPVHGB0IuRNdxqzBQ=@vger.kernel.org X-Gm-Message-State: AFuF++nNnNye+HOH22OJZBghivjCgbawxudxYPkJr+vI/weH/RDR1u4H KlwH6731kDWXrkcFI0+OXEqPotgboY52Vpe+P4oUmt3n5Kxi5gmL1JYT X-Gm-Gg: AYBFou1yNK2LfoZsYYa7gKJLjriwtIrn3VaulofLN5B9oHUi5LLpY3cy814SvLLiYQY PGECx6UlODrtD/4Uh4xItHFO88z/PiXYkAtri3fEgV9dqyALNIxUd3Njl7Mrz9tElLRVpECaK3J GreMHbgCCUFDZzk7hUabt3OignAZPZ/asTeNhNX57tBAkjOnE8eYha73FbdYyuGxojdD2t9OFfY HOLRH4HXWFRgdCbmt7SK2YY+IWieMpIDP9dv6NtYztImbkKqzJJttjE+jH3nttXv/FkAyzhSIP7 N1C2oW/qo9U0ZjQ2Qt5OwhY2MVlSttqAaEyxB501Y/9Wx9UMrC53FFk39S9fRacySRkeKRS1zJa 3FOePKYdaXMOplP5QZdktxLUAlHt4FRRNx3H7iuE7xvF87hbSMinkoNW5j2kGm07g9FfQY0cF0n BimI4s67MK0PCNT06JGdUHW3vaMJ5GtVtt7tWmaoIXJ/CU78pbZ01dXHfcu985hfqUes4LG1S4L ssoTQtR X-Received: by 2002:a05:600c:630c:b0:49c:ffde:45ff with SMTP id 5b1f17b1804b1-49fe66eb254mr184449465e9.17.1790540093992; Sun, 27 Sep 2026 13:14:53 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:53 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:40 +0300 Subject: [PATCH v13 12/13] reset: zte: Add a zx297520v3 reset 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: <20260927-zx29clk-v13-12-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=13416; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=hpsSqsSsSLYK5AZPSKuwD6Ytr5Hn4TTt02kVTQyewa0=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1dhykgYubrg2m/4gcWLVDhytAZ18j6wGMf +BNjQrDIX+JAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLiew/8Cdt/DlXqlh3Zf1O0YwSR9x26hm9DrAD d1owLPUKsQhPVlJ0SDY3y9doAVJvy94AmCvcrFdP16bQGGBYQIXlIN3Xz3HRzQpcNlyrWeFDSfu ypgBVLkl7OWzwq5A01fqf6/CQ2yfZF3M7QxWJC+8hPQIIhphqkGrPcP1RsPz4WGqt3IC0kjAxFc ZHIyT1p8JdPuxy/8ntbyxV13UeBB4ARrLOscHVWV+QE3XBzYlhCtK6tq7aTumPVUuQJMyJPrcA4 W+VCvxIiHDY0SJUfuzfm+VVmIIXJbDk6RR8RGVl3svHSi6d1FgAJfe1Sw6hnVbXCkTzomLAMBq9 KJe/cMzcd+EMwTr2WZxgVQIcWnNFL9jfJN6gXgC92BKdRz/kHoUwoJT0uqxqG2c/FZiz58Yodiq dkdOk5XgUDqmsRrxw1Q3J87Arnk1Oey+kAi7H1+N92tLdeOk93t1XKYI3wM2xzZv34oWnDoWSW0 TtbUUqwdEEdAPtttWF7WLsitVsqaF2KRKj/mOHIHTzYjeBan8v3x3PXeB9rWI2Wz8QAt03BvaWS SEOUTI2pw69jXougvMViKvg+o9cgrJGFbe/w9TYz+YFX+P6tGA079sTDtsWchm/spDeK3s5ab9V Wap3ctgQ5qlVpWJPXbm+ZbESH3d27oJ834iACpcIzo9bsgGqA6po= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This drives the MFD child devices created by the zte-zx297520v3-crm driver. Reviewed-by: Philipp Zabel Signed-off-by: Stefan D=C3=B6singer --- v12: Correct SSC reset from bit 24 to bit 28 in matrix+0x94. v10: Add ZSP reset in matrixcrm v9: Remove HSIC and USB PHY resets, the phy driver will access them through the shared regmap directly Sort include files alphabetically Depend on HAS_IOMEM due to "select MFD_SYSCON" (Sashiko). This has some, but not consistent, precedent in the same file v8: Select MFD_SYSCON for COMPILE_TESTing this driver without the MFD parent driver. 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 | 13 ++ drivers/reset/Makefile | 1 + drivers/reset/reset-zte-zx297520v3.c | 237 +++++++++++++++++++++++++++++++= ++++ 4 files changed, 252 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index cf4e8c48ddfc..e6ed86f9141b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3929,6 +3929,7 @@ F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ F: drivers/clk/zte/ F: drivers/mfd/zte-zx297520v3-crm.c +F: drivers/reset/reset-zte-zx297520v3.c F: include/dt-bindings/clock/zte,zx297520v3-clk.h F: include/dt-bindings/phy/zte,zx297520v3-topcrm.h F: include/dt-bindings/reset/zte,zx297520v3-reset.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 3168ab1eea88..30fa1f2868ef 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -428,6 +428,19 @@ 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 HAS_IOMEM + depends on MFD_ZTE_ZX297520V3_CRM || COMPILE_TEST + default SOC_ZX297520V3 + select MFD_SYSCON + help + This enables the reset controllers for ZTE zx297520v3 SoCs. The reset + controllers are required for booting this board and are part of the + clock and reset management controllers on this board, so you will also + need MFD_ZTE_ZX297520V3_CRM. Enable this if you are building a kernel + for a ZTE zx297520v3 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 45ad17062462..3662824c5c36 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -52,5 +52,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..6a5711446502 --- /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_CORE_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_RESET] =3D { .reg =3D 0x80, .mask =3D BIT(4) | BIT= (5) }, + [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_ZSP_BUS_RESET] =3D { .reg =3D 0x3c, .mask =3D BIT(0) = }, + [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(28) = }, + [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.55.0 From nobody Mon Sep 28 05:45:30 2026 Received: from mail-wm2-f12.google.com (mail-wm2-f12.google.com [74.125.225.140]) (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 5F45E3C09F4 for ; Sun, 27 Sep 2026 20:15:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.225.140 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540104; cv=none; b=Hb66KDU5H+vjLD4vX6bwu5hal+N/5eGbMCERoTgR5y6iIczyq7c89fKxgWWTIrW4axuy5wU5nDnTvE/W1V7C89rkgVuKXJ/KNNWJjoFLkoCJoVFYXQ60PZF/GW0tminP0Tyn/QcQcgSiXGgPDV0K+3IOtBcmuuvOxFsACzVDHdg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1790540104; c=relaxed/simple; bh=nf0EyPFH35tSBIK5oZ5/jJ+smy+BLU/nT0Pmxgc+7L8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YaJ5v2GHUXRnUE57rgDBzaorxcI89mRdX6Vj0IB1VLq/mPKEv61A8wh+V4Z8eCmlmJGaHOvazaJYrtlVv5aPz+aEIc/6GFK6Z1nStAI83dGD4s4dG+E+wD+4S0BAr9j/u2EuIv2d8S/JEdRDN1AJSKXXdryey2UPd2NJnAbBzgc= 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=PWiirBX3; arc=none smtp.client-ip=74.125.225.140 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="PWiirBX3" Received: by mail-wm2-f12.google.com with SMTP id 5b1f17b1804b1-49b912d391aso16917685e9.2 for ; Sun, 27 Sep 2026 13:15:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1790540099; x=1791144899; 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=cTauSR6H/8NKinLJSb31gMD112liycecOTxKay+MW1Y=; b=PWiirBX342u1ZovQjBXnxAxNygoidv4AR3BeYr/KQEeCwesTtovhBbL5oAGX06wueM KB0b4qAWv3tXUrSISOzj8KhKRoSyQnVOKhVlJOqbsHyB8FA2boS33y8M9f6EZEuJHrEB nfHvT2TvWi3x3ybCNaTiBPuV4Wu8tSFQ/L8wYdC5j4q/uaE1K0flkgg3xhtE+WqGqMuo fzmUTIJPlmh48Mlq0hSJODtyuDKnKLx5i0WZxOtIHNWPOAKYqoA4Y2jNrtpvr2R6ouGi vzqRS1p6Y4Y/ALhuwZNHfkl6DRY7fpZ89nus3tcOHh7UK8J8uraVmMavhkqHDPmSLc8L jMHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1790540099; x=1791144899; 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=cTauSR6H/8NKinLJSb31gMD112liycecOTxKay+MW1Y=; b=JDTgTDG9EmzEy9JeoUYU86gsDUUnRyyb2yEhktabMoYmwlJDBKvi5VzOaOSFvuEFFE M2vIE/TRSI81bCXQD8QUd4yjXOBybPw+jvPgxVb4wf/eV86cONIm2mS2G9B84nofacTC 00A5JdqGISN39NeXdACjC3ufwz/24jvXFgjZLyrRuuI8XhItN3eFyK+ihOBEB0xRzKtH phulKWkaGZPZxPuaJ3/dYyDBuIK5Kf1DUGYl3p2KVqd4zp0SEa+Bt5X74o5cnC8HdNly QwkJAeBrEDfSyNxpXRf6VjpHN/2B11czb9ydrA7owdpOrx0CgkBhvIik9kkbizqc4C+U OhLQ== X-Forwarded-Encrypted: i=1; AKwUvBzFF6kLuHFtUVSb5u+wXH0ZTMpotuN8Tj8ZMViHaiZPGrj4rOa9MQCymxB3opPgsx5zs1yeeEqwE9rO6Ro=@vger.kernel.org X-Gm-Message-State: AFq9FYJTY3hCQFuS+gx0LwKT24X9B+v3HmgSE7fit/k0aEiayGP7m2CX CkMjx5jO4PfaoH7NSEGVs5ID23mzzaQRPGGGLS5Pw/yhR8jVEkF0HQ4G X-Gm-Gg: AYBFou3Z0dHMPhi+GA2bHst1LpJeV9EMLhDRRvSnJurQsIIQ4crZsWJYHVw9HoAEM1O m3GVDzUVIfjnnh3S4EQJRlaRISiJoWduFD/s3MLjfADy5S/BVWKsdMspuQe0xBWHHQDPwvthJXq ZNOYFuC3REfNbFb30Y4PyRstyws67FBNgDhJQpDqkUHgMBbzJBRIlqOdo83LNVeMODPA8JbN/27 KYjvQ3dZW6xnPX1ccMOHC4ucj+NSlnS0mp350phSjMsc8uQJ9hB7O7nLGSoZ+dZJ6STQOmYkX0e uVu6Us1uxtxKnTBYszpMY/IqUO1MdqCjAMKS2s5NGpEPXFzaWzgU+mRF+Dxx++pWxv0uOA2qOUj WW1j00dgQf0t2G6Na/B1Dg1VZQWANQAiqrlfLWC1tq+WV5hOgKufpuy4Dp7nXK/56wMEzQBG3zS hdBDHeKkMAveVZgjWGnaZEIK7wVT04gadtxUC9nkgYCnxFhTW+KXWuR29uJfu3XiNE3o+gzUn+/ gFN3jdq X-Received: by 2002:a05:6000:2893:b0:487:10a9:57cb with SMTP id ffacd0b85a97d-488719756c5mr18798018f8f.49.1790540099202; Sun, 27 Sep 2026 13:14:59 -0700 (PDT) Received: from [192.168.0.2] ([197.250.96.148]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4887a34a570sm21781514f8f.13.2026.09.27.13.14.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 27 Sep 2026 13:14:58 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Sun, 27 Sep 2026 23:13:41 +0300 Subject: [PATCH v13 13/13] ARM: dts: zte: Declare zx297520v3 CRM device nodes 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: <20260927-zx29clk-v13-13-70d8f673386c@gmail.com> References: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> In-Reply-To: <20260927-zx29clk-v13-0-70d8f673386c@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney , Vinod Koul , Neil Armstrong , Russell King , Lee Jones , Brian Masney , Jerome Brunet , Manivannan Sadhasivam 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, mfd@lists.linux.dev, =?utf-8?q?Stefan_D=C3=B6singer?= , Krzysztof Kozlowski X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=5992; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=nf0EyPFH35tSBIK5oZ5/jJ+smy+BLU/nT0Pmxgc+7L8=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBquXj1qMOhF4nhM5GAH4C4zIE2KCnpV3p7yPYxy HsWLuBVq++JAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCarl49RsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiJNaRAAi92rO1TFDPk6AfkbezqImo7QQMmSE6G xzjgXmYfqzaDzA2JJ2MEt5ITYiH4sslWTHYOvxV8iBS0oaH8J4O5H6+xcPniz3W+snQvwwuz+Yt lJqDvK1FyY3Hw/TjoVzVYp+dI1DBj7J9iWFfcy62abwG2+FdE4877GYT88X4gM8LqUZ6goT9y4c SFMG3ERQS+PZeBNqDTU3xVZlm46MD6LGvThLvfsEOu6Lr/NKGn5Q4lufzGqnegL5evrbyBrVQWy Ggro6IegTW6hARhscDuM5zFxFCeX44v7fJwUFLf/MWk2Q7DVUbkhxtpyyqWWYnCuswA0jilu3XW Gh5vHFd1V9VnC7/l9vWCi56t7nnoQpKSfnYoR2q3EeJ1pn4+kO20uIWoy/q044FLzTrLsuM/Jc2 +oLuGv/kJ0UWvzASZhsQkA9UFeDQ5JIRbKOj2/fFHtMjGAiHztjkrdV/n/UpThoNPHsEG38+Pg/ SkknToYjaa9dUutBVehuE35RlMFKpxXyUHlvaCqLszJ+p3hC4kj3827Hs13LMFJa+QfqkLLcrjG 0NcahDzzscsP7c/wSY9/uiLJtg8PsXGjzck854E9fxdxsZvKWAVQQ4GWnQYzi5kVWqlj2ZX4w1c l/+S4y5w44rxz8Nd4u4tem251TqfpZuBDEvKzJOadl8pAcn1W8jk= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This patch adds DT nodes for the main clock and reset controllers on the zx297520v3 board. It replaces the temporary placeholder UART clocks with the proper clocks exported by topcrm and lspcrm. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Stefan D=C3=B6singer --- Version 11: Improved the above the line commit description, removing references to "previous patches" that won't make sense when reading it in the kernel commit log. Version 10: Fix issues with dt-check-style --mode=3Dstrict in newly added code, but left issues in existing nodes alone. Version 9: Sort new nodes by mmio address rename syscon-reboot to "reboot" adjust to changes in bindings 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 | 101 ++++++++++++++++++++++++++++++= ---- 1 file changed, 89 insertions(+), 12 deletions(-) diff --git a/arch/arm/boot/dts/zte/zx297520v3.dtsi b/arch/arm/boot/dts/zte/= zx297520v3.dtsi index a16c30a164bb..ebac3cd137df 100644 --- a/arch/arm/boot/dts/zte/zx297520v3.dtsi +++ b/arch/arm/boot/dts/zte/zx297520v3.dtsi @@ -3,12 +3,26 @@ * Copyright (c) 2026 Stefan D=C3=B6singer */ =20 +#include #include +#include =20 / { #address-cells =3D <1>; #size-cells =3D <1>; =20 + osc26m: clock-26m { + compatible =3D "fixed-clock"; + #clock-cells =3D <0>; + clock-frequency =3D <26000000>; + }; + + osc32k: clock-32k { + compatible =3D "fixed-clock"; + #clock-cells =3D <0>; + clock-frequency =3D <32768>; + }; + cpus { #address-cells =3D <1>; #size-cells =3D <0>; @@ -20,15 +34,6 @@ 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>; - compatible =3D "fixed-clock"; - clock-frequency =3D <26000000>; - }; - timer { compatible =3D "arm,armv7-timer"; interrupts =3D , @@ -75,18 +80,87 @@ uart0: serial@131000 { arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x00131000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&topcrm ZX297520V3_UART0_WCLK>, + <&topcrm ZX297520V3_UART0_PCLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&topcrm ZX297520V3_UART0_RESET>; + status =3D "disabled"; }; =20 + topcrm: clock-controller@13b000 { + compatible =3D "zte,zx297520v3-topcrm", "syscon"; + reg =3D <0x0013b000 0x400>; + #clock-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + interrupts =3D , + , + , + ; + interrupt-names =3D "usb-up", "usb-down", + "hsic-up", "hsic-down"; + #phy-cells =3D <1>; + #reset-cells =3D <1>; + + reboot { + compatible =3D "syscon-reboot"; + mask =3D <0x1>; + offset =3D <0x0>; + value =3D <0x1>; + }; + }; + + matrixcrm: clock-controller@1306000 { + compatible =3D "zte,zx297520v3-matrixcrm"; + reg =3D <0x01306000 0x400>; + #clock-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>, + <&topcrm ZX297520V3_AHB_PCLK>, + <&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", "ahb", "mpll", + "mpll-d5", "dpll", "gpll", "gpll-d2", + "wclk-osc26m"; + #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>; + 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"; + #reset-cells =3D <1>; + resets =3D <&matrixcrm ZX297520V3_LSP_RESET>; + }; + uart1: serial@1408000 { compatible =3D "arm,pl011", "arm,primecell"; arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x01408000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&lspcrm ZX297520V3_UART1_WCLK>, + <&lspcrm ZX297520V3_UART1_PCLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspcrm ZX297520V3_UART1_RESET>; + status =3D "disabled"; }; =20 @@ -95,8 +169,11 @@ 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_PCLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspcrm ZX297520V3_UART2_RESET>; + status =3D "disabled"; }; }; --=20 2.55.0