From nobody Mon Jun 8 14:35:53 2026 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1D9F364E93 for ; Thu, 28 May 2026 21:55:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005302; cv=none; b=XjsfFRicyTWZLUHpoepie7gxpfbM8NB4hjcb8ax+PQYhShNOp9bi1mNaIAgvVBHJvFpe9pmcKuBF2URKBfTPIG/VyTFxTxLDSTxEiyZnBi1dsn7qqYaALUEHufm43Uy75Zk8qASg0kfZwmBqvMzJrqldA9hhb03OnOCzuQorT88= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005302; c=relaxed/simple; bh=VyO94E/JUVkIrvYxngVXEAe+ktBx8r4qNp/vOl3g2U4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KXKunnZ2YdJx5IQmmy/50XWRdJJHsQMh2X9Lquh1lZVqAgkgfly4EpfsSaDA6NX0V79TFIeAHW+5H3Bqh76mPBVp64WwDQXvcaFnLmJgJkvtZ7A9bPJfBTxKdCuZAMvLSirfve55bby4YslxUx/IJ4lnyBRiRLDux7d6gNFnBSU= 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=fvLzP91C; arc=none smtp.client-ip=209.85.128.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="fvLzP91C" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-4903974854dso66213485e9.3 for ; Thu, 28 May 2026 14:55:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780005299; x=1780610099; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=d/YuXOm7ApYRYRm2PV5ji1302lS9gowdVXZudIgXt9A=; b=fvLzP91CNM5nMVEH1DFbug9nG/T2VNU+dLckMNTG2QmPKfE/t0D+YCj8oNoqb8SI6S 1vT4AbF76qgSITHK5fk6Pn+F/LB+fPkqoUziYp7f2yC4rD6XlEoqbomJ7to9+R7AYMAh W3SlQTCOspt4wFpyK6IBQIJkFqzVLhFPE6/nXHq2P2MvSy9Ki7keEqeUEvFTPNCspucU zxGIsR8n8XPUe+j1l1hZwjtpQjwvDu9jdkR1+1T9O+DYm8NE4i6VTm9VCoeUsQ4gUxO4 awYMzAhHWvYlos0HxX/r4RFekaZLoeqn7pTIL2dt/RDYBP0HNHvRcuHGt8y1u4OPCrrL ScnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780005299; x=1780610099; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=d/YuXOm7ApYRYRm2PV5ji1302lS9gowdVXZudIgXt9A=; b=dCWpquMWv/D/2rffS5PZpfonl/1LPKd1juJ5izL7oSEzhA89E7VN7nXM5rxRVr+LGK 3xskY0cYiOPHPMy49SzQJyDlmEc/iTo7hk5rnLudqH89bRd1VivfjGqvhY5ydwlYGjob GQtAcKOJxeaSn+wns31ub/sY3PRgIsJbePq12VQk+BZ0ieZcXGQMEskE1HM5hpCLXZYQ ZLZBkk8efHg4R5LVer87VPbqoDg3iTEp2TGhXIsEOaLU4N3GtJvpm6XWEsu5DO5ptcGo Vkh6FouevY9tJEU2KuA0CHilMEKJ5ZsT1lFFZ8OYPAM6vX8BXR8Vawp02uTQyEwVXUWw WP6A== X-Forwarded-Encrypted: i=1; AFNElJ9tuknne8JPYqgkVN/CPJGH33qwF2rmJOWEaiGrsKq4Hqthp08CPq/GoaR0gJ5lw0bH5y+2z8JIWpeDyiA=@vger.kernel.org X-Gm-Message-State: AOJu0Yxs6gKaR7C0dRE6g4qUU5jN14lTbDECnXeu9TFMIbipT9nqrp9M Zz5L+GjDIlLe8IYAdEZ7xuRyjFnYsd+m4wbBtF0nAMl4hmqnX1cCmv4h X-Gm-Gg: Acq92OFsV5Ia+1JgaQXrp25aGviKg2cVObSE0vuQOBxcDbv7Cs56yaBR4y008BtlR3l TE6EF6a00sS5JWMl4GgUtuQyDyEc/xYMTHzfFx7N6Gyn0G6xw+S6V+zFhUvq2DHzZtoOAjZtcG+ wCIcTNxC0pt2TVM6mOXWEnPWa5XLAzBMwYMlPSvurC8+E/M6qLbyF0OUH9EuHDbxq34hrAXG92O t9R8EX/MxdRJyP+bqVxkAn1hDGkY7yFlbhopONipLelVVr6+EJAN1HKchyWPASm2KCQzW1Kl7N5 1V3SvqEFN/PbNF3kiFO3s7H7bjrnlJbgBThH2n7ARFqbTRd4PP29G/wCD8hx6fqN6Sc3E7HPF5W 3lKP1XGyDMhKa5ZaLurQs5IAcmMQpx5aEC65rTWAlNklMbPmIg+xH5YgpbMLi4mu3AN8mV0pcdc R+lwLrpPKxf2hPgAjYYzl8MXgA2RbzvF1CUd4J7ydDPHiu X-Received: by 2002:a05:600c:1c21:b0:48a:75b9:b0bc with SMTP id 5b1f17b1804b1-4909ca895b3mr584195e9.29.1780005298887; Thu, 28 May 2026 14:54:58 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.223]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909c967c6csm1191085e9.2.2026.05.28.14.54.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 14:54:58 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 29 May 2026 00:52:58 +0300 Subject: [PATCH RFC v3 1/5] dt-bindings: clk: zte: Add zx297520v3 top clock and reset bindings. 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: <20260529-zx29clk-v3-1-c7fe54ea388f@gmail.com> References: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> In-Reply-To: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=10725; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=VyO94E/JUVkIrvYxngVXEAe+ktBx8r4qNp/vOl3g2U4=; b=kA0DAAgBPRO8yFRPGiIByyZiAGoYuaigL/JhqPPbqglYzfP6xJ0hemA0isaXZASPyem/ijWOF IkCTwQAAQgAORYhBEMW9LaqBVsnlTJdbD0TvMhUTxoiBQJqGLmoGxSAAAAAAAQADm1hbnUyLDIu NSsxLjEyLDIsMgAKCRA9E7zIVE8aInNrD/9lT2QQugN0SDHaeEBDGss3GAFhRodY3XrNYNfaMQF TZr1/ShinlnFHwNtP/QQtHx4/FyYtmSKJn0M1kDOkMQ6q5yyVkaO8unNh2a20f6Z2wgWwRQHbJs E41dmF6p1uSGv93xrmlYR1u3jUEoe1IV6mWwPbNFW/KYgXZ2WaHppZxm0+s8RWP6u17t2lXG18T RC71UmK+/JjDDqoVUz4BO6KZj50HIvniO/OrjXIoAXQ+pzvnlblBDHM7QeMigkx5DQ3K6PWOL37 eXlnj476N49y3hmpAuRZneWEYskcvglSEI/LcvcM2W4XOM1STa4JJAGP+KoiXe13dG5/FAkImpu wCQFDOFeQok/Gwsqp6/o+9zUH3MaCBGvwOvodPlXAuvyi+mTAKEngPbeQlW5tzyKL1VBf5coBJy ieN7jvoWBBBUYCU3NAkqOJTQaigr22+HibQpZV9JwsiLhpx9OsmTurU70mm4sRmQirKRX+40sGC LjoMWLPkeD7jH2p6/6qHTV59tIijrdUYHaBvGpxvkL/5vl5Y1kcDTh7Ez9YbvzZQmHJRf7fJFyK WqxIp5+scFYyadfg7jt4OAJNtxepNftRvvfeh3eEGHu+hRWdejEB7XYmCgtY4evteuj5ta4/ACP lt7SIaKkNvwZITV0ageKPlC7b4YJ9b6TKtcr+AP7Yaw== X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 These SoCs have 3 clock and reset controllers: Top, Matrix and LSP. The separation of concerns between Top and Matrix and the interface between them is poorly defined in the hardware, so this patch models Top and Matrix as one device with two memory regions. Case in point of their poor separation: The ZSP coprocessor - used for LTE - has clocks in the Matrix block but a reset control in Top. The board's main CPU has two reset controls, one in Top and one in Matrix. Generally every device has two clocks (one work clock, and one that connects it to the bus, I call it PCLK), two reset bits (I don't know what the difference is - sometimes asserting one is enough to reset the device, sometimes both need to be asserted). PCLK and WCLK are controlled by individual gates. Some devices have a mux and/or a divider for their work clock. Some devices, like the GPIO controller, only have reset bits and no clocks. The top clock controller is fed by a 26mhz external oscillator and has 4 PLLs to generate other clock rates. ZTE's kernel mostly relies on the boot ROM to set up PLLs, but one LTE-Related PLL is not configured on some boards. Therefore my driver contains code to program PLLs. It produces identical settings as the boot ROM for the pre-programmed frequencies. The "matrix" controller controls the main Cortex A53 CPU, the LTE ZSP, SDIO and a few others. 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. I isolated a few (SRAM PCLK, arm arch timer clock) where I don't see a reason to manipulate them. It is quite likely that a handful more clocks will be added in the future, but not a large number. Signed-off-by: Stefan D=C3=B6singer --- .../bindings/clock/zte,zx297520v3-topclk.yaml | 95 ++++++++++++++++ MAINTAINERS | 2 + include/dt-bindings/clock/zte,zx297520v3-clk.h | 121 +++++++++++++++++= ++++ 3 files changed, 218 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-topclk.= yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topclk.yaml new file mode 100644 index 000000000000..968820bde755 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-topclk.yaml @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-topclk.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's top clock controller generates clocks for core devices = on the + board like the CPU, RAM, PMIC. In addition to clocks it has reset contro= ls for + peripherals as well as the ability to reset the entire board. It has two + distinct IO regions, but because their responsibilites are poorly separa= ted + they are modelled as one device. + + 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 + clocks to the downstream LSP clock controller. + + The controller controls core devices on the board: The CPU, DRAM, MMC, L= TE + and Ethernet related clocks are found here. + + All available clocks are defined as preprocessor macros in the + 'dt-bindings/clock/zte,zx297520v3-clk.h' header. + +properties: + compatible: + const: zte,zx297520v3-topclk + + clocks: + items: + - description: 26 MHz external oscillator + - description: 32 KHz external oscillator + + clock-names: + items: + - const: osc26m + - const: osc32k + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + + reg: + items: + - description: Top clock memory region + - description: Matrix clock memory region + + reg-names: + items: + - const: top + - const: matrix + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + + osc26m: osc26m { + compatible =3D "fixed-clock"; + clock-frequency =3D <26000000>; + #clock-cells =3D <0>; + }; + + osc32k: osc32k { + compatible =3D "fixed-clock"; + clock-frequency =3D <32768>; + #clock-cells =3D <0>; + }; + + topclk: clk@13b000 { + compatible =3D "zte,zx297520v3-topclk"; + reg =3D <0x0013b000 0x400>, + <0x01306000 0x400>; + reg-names =3D "top", "matrix"; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 4ae1e77c2fd7..ae51d590d440 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3864,8 +3864,10 @@ L: linux-arm-kernel@lists.infradead.org (moderated f= or non-subscribers) S: Odd fixes F: Documentation/arch/arm/zte/ F: Documentation/devicetree/bindings/arm/zte.yaml +F: Documentation/devicetree/zte,zx297520v3-* F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: include/dt-bindings/clock/zte,zx297520v3-clk.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..4d85251a0ce5 --- /dev/null +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -0,0 +1,121 @@ +/* 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_AHB_WCLK 0 +#define ZX297520V3_AHB_PCLK 1 +#define ZX297520V3_PMM_WCLK 2 +#define ZX297520V3_PMM_PCLK 3 +#define ZX297520V3_USB_24M 4 +#define ZX297520V3_USB_AHB 5 +#define ZX297520V3_TIMER_T08_WCLK 6 +#define ZX297520V3_TIMER_T08_PCLK 7 +#define ZX297520V3_TIMER_T09_WCLK 8 +#define ZX297520V3_TIMER_T09_PCLK 9 +#define ZX297520V3_TIMER_T12_WCLK 10 +#define ZX297520V3_TIMER_T12_PCLK 11 +#define ZX297520V3_TIMER_T13_WCLK 12 +#define ZX297520V3_TIMER_T13_PCLK 13 +#define ZX297520V3_TIMER_T14_WCLK 14 +#define ZX297520V3_TIMER_T14_PCLK 15 +#define ZX297520V3_TIMER_T15_WCLK 16 +#define ZX297520V3_TIMER_T15_PCLK 17 +#define ZX297520V3_TIMER_T16_WCLK 18 +#define ZX297520V3_TIMER_T16_PCLK 19 +#define ZX297520V3_TIMER_T17_WCLK 20 +#define ZX297520V3_TIMER_T17_PCLK 21 +#define ZX297520V3_WDT_T18_WCLK 22 +#define ZX297520V3_WDT_T18_PCLK 23 +#define ZX297520V3_UART0_WCLK 24 +#define ZX297520V3_UART0_PCLK 25 +#define ZX297520V3_I2C0_WCLK 26 +#define ZX297520V3_I2C0_PCLK 27 +#define ZX297520V3_RTC_WCLK 28 +#define ZX297520V3_RTC_PCLK 29 +#define ZX297520V3_LPM_GSM_WCLK 30 +#define ZX297520V3_LPM_GSM_PCLK 31 +#define ZX297520V3_LPM_LTE_WCLK 32 +#define ZX297520V3_LPM_LTE_PCLK 33 +#define ZX297520V3_LPM_TD_WCLK 34 +#define ZX297520V3_LPM_TD_PCLK 35 +#define ZX297520V3_LPM_W_WCLK 36 +#define ZX297520V3_LPM_W_PCLK 37 +#define ZX297520V3_USIM1_WCLK 38 +#define ZX297520V3_USIM1_PCLK 39 +#define ZX297520V3_M0_WCLK 40 +#define ZX297520V3_OUT0_WCLK 41 +#define ZX297520V3_OUT1_WCLK 42 +#define ZX297520V3_OUT2_WCLK 43 +#define ZX297520V3_OUT32K_WCLK 44 +#define ZX297520V3_CPU_WCLK 45 +#define ZX297520V3_CPU_PCLK 46 +#define ZX297520V3_SD0_WCLK 47 +#define ZX297520V3_SD0_PCLK 48 +#define ZX297520V3_SD0_CDET 49 +#define ZX297520V3_SD1_WCLK 50 +#define ZX297520V3_SD1_PCLK 51 +#define ZX297520V3_SD1_CDET 52 +#define ZX297520V3_NAND_WCLK 53 +#define ZX297520V3_NAND_PCLK 54 +#define ZX297520V3_SSC_WCLK 55 +#define ZX297520V3_SSC_PCLK 56 +#define ZX297520V3_EDCP_WCLK 57 +#define ZX297520V3_EDCP_PCLK 58 +#define ZX297520V3_VOU_WCLK 59 +#define ZX297520V3_VOU_PCLK 60 +#define ZX297520V3_PDCFG_WCLK 61 +#define ZX297520V3_PDCFG_PCLK 62 +#define ZX297520V3_GMAC_WCLK 63 +#define ZX297520V3_GMAC_RMII 64 +#define ZX297520V3_GMAC_PCLK 65 +#define ZX297520V3_ZSP_WCLK 66 +#define ZX297520V3_MBOX_PCLK 67 +#define ZX297520V3_DMA_PCLK 68 +#define ZX297520V3_LSP_MPLL_D5_WCLK 69 +#define ZX297520V3_LSP_MPLL_D4_WCLK 70 +#define ZX297520V3_LSP_MPLL_D6_WCLK 71 +#define ZX297520V3_LSP_MPLL_D8_WCLK 72 +#define ZX297520V3_LSP_MPLL_D12_WCLK 73 +#define ZX297520V3_LSP_OSC26M_WCLK 74 +#define ZX297520V3_LSP_OSC32K_WCLK 75 +#define ZX297520V3_LSP_PCLK 76 +#define ZX297520V3_LSP_TDM_WCLK 77 +#define ZX297520V3_LSP_DPLL_D4_WCLK 78 +#define ZX297520V3_TOPCLK_END 79 + +#define ZX297520V3_AHB_RESET 0 +#define ZX297520V3_TIMER_T08_RESET 1 +#define ZX297520V3_TIMER_T09_RESET 2 +#define ZX297520V3_TIMER_T12_RESET 3 +#define ZX297520V3_TIMER_T13_RESET 4 +#define ZX297520V3_TIMER_T14_RESET 5 +#define ZX297520V3_TIMER_T15_RESET 6 +#define ZX297520V3_TIMER_T16_RESET 7 +#define ZX297520V3_TIMER_T17_RESET 8 +#define ZX297520V3_WDT_T18_RESET 9 +#define ZX297520V3_UART0_RESET 10 +#define ZX297520V3_I2C0_RESET 11 +#define ZX297520V3_RTC_RESET 12 +#define ZX297520V3_USIM1_RESET 13 +#define ZX297520V3_PMM_RESET 14 +#define ZX297520V3_GPIO8_RESET 15 +#define ZX297520V3_GPIO_RESET 16 +#define ZX297520V3_ZSP_RESET 17 +#define ZX297520V3_USB_RESET 18 +#define ZX297520V3_CPU_RESET 19 +#define ZX297520V3_SD0_RESET 20 +#define ZX297520V3_SD1_RESET 21 +#define ZX297520V3_NAND_RESET 22 +#define ZX297520V3_SSC_RESET 23 +#define ZX297520V3_EDCP_RESET 24 +#define ZX297520V3_VOU_RESET 25 +#define ZX297520V3_PDCFG_RESET 26 +#define ZX297520V3_GMAC_RESET 27 +#define ZX297520V3_DMA_RESET 28 +#define ZX297520V3_TOPRST_END 29 + +#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ --=20 2.53.0 From nobody Mon Jun 8 14:35:53 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CB66E3655C4 for ; Thu, 28 May 2026 21:55:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005307; cv=none; b=oMp2YSm9lHflYV52Lj65pzUeQXxqU1ccJz/aTVhJ+DaczauQIODIn/jqSbJoKHQZQ4ltrhddmxlDnGPakYrJ1WLnrkcpX/YJMkQOU40qDQYx08IXfjeEaf+hDzsNqmamIjwqWPQ5rl2B7kj/7fHxO7NxKF1lZHkLuIiI6uCbOZA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005307; c=relaxed/simple; bh=vr13qCo1Z4urs64TigR5t4iRfx+iJfof5p91YFBaIKI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=XlD/y7rdvQQ/1NzbccCXIv9/gMCb75hVd0S+wWQ1Zwwim7iNQD0yJAyJUp/XUnLp8jCFnmj9Aib/T1dISu2er6S1BzWlIFOL6fwtDsFrlNdCNu4HWAgJJ1yPlMfcC0ZiE1dhWdCnOw8bfqDqA2KA8Innb9JdwHvZxmIwZNioFiw= 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=namSOi7g; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="namSOi7g" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-490426d72f7so64918455e9.3 for ; Thu, 28 May 2026 14:55:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780005303; x=1780610103; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=eUyxjFC+AVWv6DcQ33VYTF/nj3i1vMmIuuMKgQ010aI=; b=namSOi7giaKft9yGGu/f1WfNAT57ZO32T7IJ6cjrRI2nUXuKy5M4bb2m+dtmoGZNIE eJU3kawmGMj/DlXdhWDRmFFRzBjmW5VEYaukr3gkPw3HyNZVg2uWQOO84jv881Er3CKF 5XG+08ENDutRou4Q8G2gK5e9RGzB1T7ElP4SEV+ahdH3XTG6JTh/AHYmlOyCCJCVxlSg NvFCHSPKA/Usy5KbvS79CX6Lt09Co50X1wwGoM0tmWuHksMxpKxVrWo2hnwImKMXWBtx 2Vs92Ex8JUX8PVqTY9V7q/B/16ROoUe1mwM2bQmMSJSD+r7Z4NG61qxEauwYxeWbibtA UEaQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780005303; x=1780610103; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=eUyxjFC+AVWv6DcQ33VYTF/nj3i1vMmIuuMKgQ010aI=; b=ktK3fopu6iYcCi0r9noSdutj4tDx+ChX797tcwnaAEBuX9mdykWy6v8N1mq4eaTPaD 25PSx1N/bzlvQ6l6yUwPmTBVt8pa3idP67BlOZGIaDjwgj1iLNEBYYowUQXJnMwCnTyV 6h4CmeO7adXwJQNBDUPYK4ljP3mshe0y58R3wLCVtvOZRDIIUhsA9R/hZGpDheTKJuBt ZwyusORjnneCHK5zC9St/h/i++BbVxfkSkAKoPcmTkvg+j2xldr0rFStAWLeueJs+WWi 7lz7eQFQHpLmxvstZHo0Iu++EbgDSUcTGsmz++7ayUVwdgSAxJHo9YJvUdAR32YI09T+ YFjA== X-Forwarded-Encrypted: i=1; AFNElJ+8JVY3PrSkgXtPDQ0zUdWc3rHsc5rLHD9kOIXdbungGdQqGtxbs9MAaXnptzxjV3nz/Fsc0WZSpKCO7tA=@vger.kernel.org X-Gm-Message-State: AOJu0Ywc+bYcFhukV017IRE7RNrri09KlB6VV62KP5cQxkQ5rfAqm91/ 8T6k9mgQRQ1p2yF0dZherrs3Q55JYEjeYoP3c8BJvVHoAw40Iw4wHm4Q X-Gm-Gg: Acq92OE+4QIAYYC8WXMdLO01Zj7tQPDZElXvfS/46QL95GHR2BHJuPxcLvXPJGAVt0t sSm0aCkpkfzE5e9jhDh1cvoLTIMy2vEGZAO4PZsGZGDzfEsPPUt5hmg6dkWNwhiNQzrPI/6GhnT J589+H3u8otL18rLjSbsHdndAWnEF22J3N9ooLW2AsfaS+/O4P90hUPrjZUBviOoT5+Vir/sET1 o+h0q+Okrfnte5C+FiqE63nkfcR48wXK2VLf4EJmy3YaIXvnSfsKEurUbAFto4qkHDve8eat/w/ /XUopgQhEh1LMgjUuN6VRyercOidsw0/aCPw5QEnV6+/pK1RYId5PH5zHvN8atC2TRqhQuUHpZJ 3c5iewCH2mR75oILHEfrnDnJfEzTRgUhCe4Wu1M0e0Kcm4wfZZX75losId4HZrJA88RG5st0Kq/ 7QzUIUui4U5U4wmO/ysNYPUXknWMd6/agkV5lYy3Xkg/+A X-Received: by 2002:a05:600d:8486:10b0:490:3d45:48d7 with SMTP id 5b1f17b1804b1-4909c080a27mr3071855e9.6.1780005303122; Thu, 28 May 2026 14:55:03 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.223]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909c967c6csm1191085e9.2.2026.05.28.14.54.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 14:55:02 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 29 May 2026 00:52:59 +0300 Subject: [PATCH RFC v3 2/5] dt-bindings: clk: zte: Add zx297520v3 LSP clock and reset bindings. 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: <20260529-zx29clk-v3-2-c7fe54ea388f@gmail.com> References: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> In-Reply-To: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=7298; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=vr13qCo1Z4urs64TigR5t4iRfx+iJfof5p91YFBaIKI=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqGLmoLTbh1SJ5vFdLjU9/XR3vX1Cv6I7aYZsQB E/ku8D9EqyJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCahi5qBsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiLZhQ//e8cAqHfB9uyHXY6yqNXCDvbERSrzuLA arLGyljoZ1tXX6dH8yQH9DX4O+PFFfbjCoFVeOjSc9pYGdh3+Pxigtof/9p2K86+rel0rgjJ58W Or9w9ZABO3KWJEHCGvLbkNfLYnImLKjFpGucJnXM08piL88dIAiUyONBs4Nam9FKkYfA7Qnttye 1djJqJweXfhFivbUE8eA/NtWXDwZs3e1XCmrOwEdx7YgjbTihG5rY+6zLe9hNApY3cUzK4D8cz2 W85uhcofmXLWxdNHIILOrdhDzBsPX1d5b5YoHPeHHsnIYX9F+HGfsAP9yjJFZ8gXGAR/0hdzc9m SYede274khPLqvrLcpmvXJx+2+jckf7sUukRrG7O/p3Cqq3sKavAIzUI6oqHIBS9CDxQYFn8174 iyc/P0vMXSXCDwtZEarnETvXEO8/PhcfkU5eEA5WlI8jWcM75xkJ7A/A2M4QCN08/smXQLbcMA8 O6xo/bd1Waj96u7pdMT4Ra0sEzGQhc/qbBMdzEVvLW/j7lMKfTvwcYJmpDqAmbja1CnS6bWo4K2 A2GWb9TNhUOVHA/2MoM0ktMCoFjSEhd/ho1CjC9Stm7XY78NgzgFABLhcUaVScMtwXZjcCxnyyb 94gMSsB6fgJJREZ88BOx5HPwIIKH6bGWVryMcu87Xr2Og6N8roKg= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 The clock controller of the 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 top controller to control propagation of clock lines down to LSP. The clocks are sorted by register address and I am convinced that the list is complete. Signed-off-by: Stefan D=C3=B6singer --- .../bindings/clock/zte,zx297520v3-lspclk.yaml | 119 +++++++++++++++++= ++++ include/dt-bindings/clock/zte,zx297520v3-clk.h | 58 ++++++++++ 2 files changed, 177 insertions(+) diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspclk.= yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspclk.yaml new file mode 100644 index 000000000000..e4d50d40e834 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-lspclk.yaml @@ -0,0 +1,119 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-lspclk.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 clock controller is responsible for bringing the devices ou= t of + reset and enabling their clocks as needed. + + The controller receives its clock signal from the top controller and nee= d to + be declared as clock inputs. + + All available clocks are defined as preprocessor macros in the + 'dt-bindings/clock/zte,zx297520v3-clk.h' header. + +properties: + compatible: + const: zte,zx297520v3-lspclk + + clocks: + items: + - description: Main PLL divided by 5 output from topclk (124.8 MHz) + - description: Main PLL divided by 4 output from topclk (156 MHz) + - description: Main PLL divided by 6 output from topclk (104 MHz) + - description: Main PLL divided by 8 output from topclk (78 MHz) + - description: Main PLL divided by 12 output from topclk (52 MHz) + - description: Main oscillator output from topclk (26 MHz) + - description: Timer oscillator output from topclk (32 KHz) + - description: LSP pclk output from topclk (26 MHz) + - description: TDM wclk mux output from topclk + - description: DPLL divided by 4 output from topclk (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 + + "#clock-cells": + const: 1 + + "#reset-cells": + const: 1 + + reg: + items: + - description: IO memory region of the LSP controller + +required: + - compatible + - reg + - clocks + - clock-names + - '#clock-cells' + - '#reset-cells' + +additionalProperties: false + +examples: + - | + #include + + osc26m: osc26m { + compatible =3D "fixed-clock"; + clock-frequency =3D <26000000>; + #clock-cells =3D <0>; + }; + + osc32k: osc32k { + compatible =3D "fixed-clock"; + clock-frequency =3D <32768>; + #clock-cells =3D <0>; + }; + + topclk: clk@13b000 { + compatible =3D "zte,zx297520v3-topclk"; + reg =3D <0x0013b000 0x400>, + <0x01306000 0x400>; + reg-names =3D "top", "matrix"; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + }; + + lspclk: lspclk@1400000 { + compatible =3D "zte,zx297520v3-lspclk"; + reg =3D <0x01400000 0x100>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + + clocks =3D <&topclk ZX297520V3_LSP_MPLL_D5_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D4_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D6_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D8_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D12_WCLK>, + <&topclk ZX297520V3_LSP_OSC26M_WCLK>, + <&topclk ZX297520V3_LSP_OSC32K_WCLK>, + <&topclk ZX297520V3_LSP_PCLK>, + <&topclk ZX297520V3_LSP_TDM_WCLK>, + <&topclk 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"; + }; diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bi= ndings/clock/zte,zx297520v3-clk.h index 4d85251a0ce5..144a3b064d49 100644 --- a/include/dt-bindings/clock/zte,zx297520v3-clk.h +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h @@ -118,4 +118,62 @@ #define ZX297520V3_DMA_RESET 28 #define ZX297520V3_TOPRST_END 29 =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_I2C1_WCLK 6 +#define ZX297520V3_I2C1_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_I2C2_WCLK 16 +#define ZX297520V3_I2C2_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 +#define ZX297520V3_LSPCLK_END 36 + +#define ZX297520V3_TIMER_L1_RESET 0 +#define ZX297520V3_WDT_L2_RESET 1 +#define ZX297520V3_WDT_L3_RESET 2 +#define ZX297520V3_I2C1_RESET 3 +#define ZX297520V3_I2S0_RESET 4 +#define ZX297520V3_I2S1_RESET 5 +#define ZX297520V3_QSPI_RESET 6 +#define ZX297520V3_UART1_RESET 7 +#define ZX297520V3_I2C2_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 +#define ZX297520V3_LSPRST_END 18 + #endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */ --=20 2.53.0 From nobody Mon Jun 8 14:35:53 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (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 AA15D3655CB for ; Thu, 28 May 2026 21:55:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005314; cv=none; b=eD731FlCtQQ/QiW1v1IJG+glCTqw0IUZt9FnQYi2Xnp7/fKMXEG6MxyqCDNWpeQb3UPGjlgO4iRJM8KOjLs18uz65vPg+71suIr/3NpfK4mCWPz2dLMo5gqHJW9OigLayxISWjcYjrPJIGKE9+/UMGVTsYX0L8ahyOY5ZAbdu5Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005314; c=relaxed/simple; bh=nWWN49uCFlTbZz1zeZG83Cfh13/Aaz3hz9xtsHASmDA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=CLBy25zOH3IHfACpRqPCdvFFS94Bp2TcM4Uc0Zm0S7JJhZNvss38wXzIso1lrZvJ9no3fnM4NtzsVr90BVAjDWffW+Rngz0+vAWa9CCNrGuFKeZCSx2qaZyal3IetEL43S4BB91WHZwWlUMXB4360o3I8IkOBG4WuATqmze6+iE= 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=dUNj76RC; arc=none smtp.client-ip=209.85.128.43 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="dUNj76RC" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-4903d730b1fso65418275e9.2 for ; Thu, 28 May 2026 14:55:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780005308; x=1780610108; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=hvIXFxlldS9mKGY6eVauaUPE2Z/sYvsNOMCQ9X5uQIY=; b=dUNj76RCJFatO3rRRp9Srv0g7VFIMAuDMLo55fYQSZrv9MZMHWDOwSrEqEEBMDbltT bFTuCZSGozD1oJdy9/2YHx6wiwYyR6d+krTk/VvYQo8eXpmwnLFZZc26S9TspMeCO98p Gqra+uyTgS0DkBOTbduxm+Z+izA+tX2EEz+Tb2OVK/CyvT0w7ivjNna2DVBpubqIaO8v 3DHP7j7vWuBxbtzxWr27XNx/vOQfohNaSRYL+/XYr76ksIGx14+rImYtdbTnvJMbKBxS SXwI9ZK5xM3bjjNQKI5xp7FlCfGaerX+97sUzFesPZv6KSJcf96og6ZTRnbupopyCaFV lJuA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780005308; x=1780610108; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=hvIXFxlldS9mKGY6eVauaUPE2Z/sYvsNOMCQ9X5uQIY=; b=BUfg8GZKpvab87FprwvcovA7D7RbM1nprQI/WwrNs1q/U7db+BxJ2DHgZswyXOpwvZ gFHJOMwXfXHn14QlUPbfFNqXujhM48avvMD8CoQYrh2gfUO/1P3ZGPnafU//qy8fi3M2 KqFjKpzkbLgvIIL5ktkZ1yrof/6iQcGX3YJbw/RfbwxQCA90swfzBMbD5kbY+niS1qis gPeMOzejDPExk8rEKqMXyV6CeZONxhhxQrHT3oVXzIdnUXIkUhMhanTspH4myM04d1/X lzFN/irspj7ZNanOI0MRuTaO2yopsmuGyWYECaa4MkBZ/FhkkXK+Z/K72VcvXFlVxVEs l8/A== X-Forwarded-Encrypted: i=1; AFNElJ9y//cgtQpGmUIL7TKxMcrWC2pcOzHjiMwyU45zudS3j3AR5rNC7ZGp7Korc4OSiTllUp1grxO2A9yxbaw=@vger.kernel.org X-Gm-Message-State: AOJu0Yx6CkF4ofWdCnemvzTnj5iKYUQpytnJCH8Mis7jHBa7j1tT+S3D BfOfJnDi0+Z9UAeXtw/Ou+GQxD+Q8co5i70uSykY356vVnztVYC4PQ5ErWb+L8CbvCsG+g== X-Gm-Gg: Acq92OGnL2aDiW/4igKVVotI2H+aa8RlBinqWfNNbFp4nyDgmp5TRq7g6T4ICfBT+s7 3H+JcyS/UpnTp89wr0Bd8BZ59idwNARLIXxgWSxIMd5UpgJZwUsbZPOOM9x0TTtaAhoa1If7yoT ia3Q/WmJUnGa6PfW77YoLQSI3ZezOk2RfxEnWtkWbjcqxr5+LDENkEKxnSg+YqOVJCXS7BGOY2u OAKdzRc5p54dpKp8r2eQgdoj6+Vr0mGaOV2aR2LctdRlhcZ5yBzAyUz9ExTAJNY+I3pRyost07/ z7coyvLmDZHvJFL0YMrtoIcWZjVxBgwnxwC7nHY3tSlJldAwnJtt6g7J89C1OzISlQBw1pZivNp cgX1RrheT6LJiRmTg+THm6KV3PEFTdoLZrhzb3BIa6y4wRxsHefDJcI9QnG1gJbxuwU5ePugLg4 beLF0YEj/Oof1SD3YxuYoixPMeZ0dUSxXtdWJ2SlmwgAEh X-Received: by 2002:a05:600c:3b07:b0:490:5057:f602 with SMTP id 5b1f17b1804b1-4909c0cfa4fmr4134625e9.17.1780005307680; Thu, 28 May 2026 14:55:07 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.223]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909c967c6csm1191085e9.2.2026.05.28.14.55.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 14:55:07 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 29 May 2026 00:53:00 +0300 Subject: [PATCH RFC v3 3/5] clk: zte: Introduce a driver for zx297520v3 top clocks and resets. 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: <20260529-zx29clk-v3-3-c7fe54ea388f@gmail.com> References: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> In-Reply-To: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=51630; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=nWWN49uCFlTbZz1zeZG83Cfh13/Aaz3hz9xtsHASmDA=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqGLmoVdpvdUzFB72p6yN8A0U7Tfj6mNtS+W3mg ecxAeofXA+JAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCahi5qBsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiInFA/+M3vrYLHAD+BF+YHi//ZCMIeoMQlyy1D 973WzdUaP68xfmKL3QDWM3zjH9mzqXMt11NpEEUiRsIuUsWZwPHpYz6YKd8T8UTZjAwwuqCdlFv kfhgRumF9kb3T+kkr9atB6v87GbgGHjvZ3H4EMw5HK5Lk6gasmu/Dw18piyeQkXFev4XAZMbSYS Xnv2+VXOVLkSbi4JrRIAlA6vDNY1e69vgCQkYiZwYuD8MM7rzW462JN22Q654N/GpSbhXYFqj0+ f15v2AVEeHDRrnCGcjWg38Y6bEZIG4NERhyEopnZp/hgfqUAIfQ4I5ODXdggQO3SFIDnHhwkM7I XZ12HHBJBvn0ubhKM1OZDLofUM/zsVKgLzTSh1kWJMuWenLZCplxOPaEVSMTNeNPUy05Sb2e3Vm cub42XB4hSd2ectCVx2Yx6tHCB57zVbMrsOBg829gZrDreYiPuOQiqC5vCp3khL2mOCceOW91oz LnHybnt9eJo+5Ci+ye0J383+M1UE4Fcynae1NJIGtFco8ztiEaRLBIK4Js+URHdNrXsOCoKhsF2 shPqqGVyrcS6xquKa2c8UoLlYwnWI0k5KfZ1qRlRF+yI4e2uf2AamgxOA+wrbftb8/ASPM5a4uG CKO/aR8ZzP6zZrjahsNOGh011Fja5cLVyWY9KColg1dRFVekSsUM= 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 also found here. Signed-off-by: Stefan D=C3=B6singer --- Patch changlog: v2: *) Add code to set up PLLs *) Merge top and matrix controllers into one device *) Bugfixes pointed out by Sashiko --- MAINTAINERS | 1 + drivers/clk/Kconfig | 1 + drivers/clk/Makefile | 1 + drivers/clk/zte/Kconfig | 18 + drivers/clk/zte/Makefile | 5 + drivers/clk/zte/clk-zx297520v3.c | 775 +++++++++++++++++++++++++++++++++++= ++++ drivers/clk/zte/pll.c | 450 +++++++++++++++++++++++ drivers/clk/zte/pll.h | 23 ++ 8 files changed, 1274 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ae51d590d440..aecd6d945290 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3867,6 +3867,7 @@ F: Documentation/devicetree/bindings/arm/zte.yaml F: Documentation/devicetree/zte,zx297520v3-* F: arch/arm/boot/dts/zte/ F: arch/arm/mach-zte/ +F: drivers/clk/zte/ F: include/dt-bindings/clock/zte,zx297520v3-clk.h =20 ARM/ZYNQ ARCHITECTURE diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1717ce75a907..6c5e089b4dbe 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -546,6 +546,7 @@ source "drivers/clk/visconti/Kconfig" source "drivers/clk/x86/Kconfig" source "drivers/clk/xilinx/Kconfig" source "drivers/clk/zynqmp/Kconfig" +source "drivers/clk/zte/Kconfig" =20 # Kunit test cases config CLK_KUNIT_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index cc108a75a900..1a70a94cf759 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -167,5 +167,6 @@ ifeq ($(CONFIG_COMMON_CLK), y) obj-$(CONFIG_X86) +=3D x86/ endif obj-y +=3D xilinx/ +obj-$(CONFIG_ARCH_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..e7acd28832cd --- /dev/null +++ b/drivers/clk/zte/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# ZTE Clock Drivers +# +menu "Clock driver for ZTE SoC" + depends on ARCH_ZTE || COMPILE_TEST + +config COMMON_CLK_ZX297520V3 + tristate "Clock driver for ZTE zx297520v3" + 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. + +endmenu diff --git a/drivers/clk/zte/Makefile b/drivers/clk/zte/Makefile new file mode 100644 index 000000000000..abe3c6777c5d --- /dev/null +++ b/drivers/clk/zte/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_COMMON_CLK_ZX297520V3) +=3D clk-zx29.o + +clk-zx29-y +=3D clk-zx297520v3.o pll.o diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c new file mode 100644 index 000000000000..986042dd4caf --- /dev/null +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -0,0 +1,775 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pll.h" + +/* All LSP and some Matrix registers contain both resets and clock gates, = so access to them needs + * to be synchronized between the reset and clock callbacks. + */ +static DEFINE_SPINLOCK(reg_lock); + +struct zx29_reset_reg { + void __iomem *reg; + u32 mask, wait_mask; +}; + +struct zx29_clk_controller { + struct clk_hw_onecell_data *clocks; + struct reset_controller_dev rcdev; + struct zx29_reset_reg resets[]; +}; + +static int __zx297520v3_rst_assert(struct reset_controller_dev *rcdev, uns= igned long id) +{ + struct zx29_clk_controller *data =3D container_of(rcdev, struct zx29_clk_= controller, + rcdev); + u32 val; + + val =3D readl(data->resets[id].reg); + val &=3D ~data->resets[id].mask; + writel(val, data->resets[id].reg); + + return 0; +} + +static int zx297520v3_rst_assert(struct reset_controller_dev *rcdev, unsig= ned long id) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(®_lock, flags); + res =3D __zx297520v3_rst_assert(rcdev, id); + spin_unlock_irqrestore(®_lock, flags); + + return res; +} + +static int __zx297520v3_rst_deassert(struct reset_controller_dev *rcdev, u= nsigned long id) +{ + struct zx29_clk_controller *data =3D container_of(rcdev, struct zx29_clk_= controller, + rcdev); + u32 val; + + val =3D readl(data->resets[id].reg); + val |=3D data->resets[id].mask; + writel(val, data->resets[id].reg); + + /* This is a special case used only by USB reset */ + if (data->resets[id].wait_mask) { + return readl_poll_timeout(data->resets[id].reg + 4, val, + val & data->resets[id].wait_mask, 1, 100); + } + + return 0; +} + +static int zx297520v3_rst_deassert(struct reset_controller_dev *rcdev, uns= igned long id) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(®_lock, flags); + res =3D __zx297520v3_rst_deassert(rcdev, id); + spin_unlock_irqrestore(®_lock, flags); + + return res; +} + +static int zx297520v3_rst_reset(struct reset_controller_dev *rcdev, unsign= ed long id) +{ + unsigned long flags; + int res; + + spin_lock_irqsave(®_lock, flags); + + res =3D __zx297520v3_rst_assert(rcdev, id); + if (res) + goto unlock; + udelay(100); + res =3D __zx297520v3_rst_deassert(rcdev, id); + +unlock: + spin_unlock_irqrestore(®_lock, flags); + return res; +} + +static int zx297520v3_rst_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct zx29_clk_controller *data =3D container_of(rcdev, struct zx29_clk_= controller, + rcdev); + u32 val; + + val =3D readl(data->resets[id].reg); + + return val & data->resets[id].mask; +} + +const struct reset_control_ops zx297520v3_rst_ops =3D { + .assert =3D zx297520v3_rst_assert, + .deassert =3D zx297520v3_rst_deassert, + .reset =3D zx297520v3_rst_reset, + .status =3D zx297520v3_rst_status, +}; + +/* Used for gates where we don't know the parent input(s). Assume general = bus clock. */ +static const char * const clk_unknown[] =3D { + "osc26m", +}; + +/* Used for gates where we know it is using the 26 mhz main clock. */ +static const char * const clk_main[] =3D { + "osc26m", +}; + +/* 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,= one reset and sometimes + * one divider, but exceptions apply. For some devices there is only a res= et and some general + * (parent) clocks need setup. This structure plus macro handles the somew= hat regular parts. + * + * There are some patterns that can be observed. + * mux 0x3c, div 0x48, gate 0x54 + * mux 0x40, div 0x4c, gate 0x5c + * mux 0x44, div 0x50, gate 0x60 + * + * For a 0 - 0xc - 0x18 pattern. Muxes from 0x3c to 0x44, dividers from 0x= 48 to 0x50, gates 0x54 to + * 0x60. The pattern is broken for timer t17 though. + * + * Gates have 4 bits per clock - bit 0 for wclk, bit 1 for pclk, bit 2 for= something the ZTE kernel + * calls "gate" (the bits we use here are called "en"), which I don't know= what it does, and bit 3 + * seems unused. E.g. offset 0x54 accepts all bits in 0xF77F7F7F - suggest= ing RTC, I2C0 have an + * extra gate bit. + */ +struct zx297520v3_composite { + u32 reset_id, wclk_id, pclk_id; + const char *name; + u32 reset_reg, reset_shift; + u32 gate_reg, wclk_gate_shift, pclk_gate_shift; + const char *pclk_parent; + u32 mux_reg, mux_shift, mux_size; + const char * const *mux_sel; + u32 mux_sel_count; + u32 div_reg, div_shift, div_size; + u32 flags; +}; + +struct zx297520v3_gate { + u32 id; + const char *name, *parent; + u32 reg, shift; +}; + +#define _ZX_CLK(name, reset_reg, reset_shift, gate_reg, wclk_shift, pclk_s= hift, pclk_parent,\ + mux_reg, mux_shift, mux_size, mux_sel,\ + div_reg, div_shift, div_size, flags) \ + {ZX297520V3_##name##_RESET, ZX297520V3_##name##_WCLK, ZX297520V3_##name#= #_PCLK,\ + #name, reset_reg, reset_shift, gate_reg, wclk_shift, pclk_shift, pclk_p= arent,\ + mux_reg, mux_shift, mux_size, mux_sel, ARRAY_SIZE(mux_sel),\ + div_reg, div_shift, div_size, flags} + +#define ZX_CLK(name, reset_reg, reset_shift, gate_reg, wclk_shift, pclk_sh= ift,\ + mux_reg, mux_shift, mux_size, mux_sel,\ + div_reg, div_shift, div_size) \ + _ZX_CLK(name, reset_reg, reset_shift, gate_reg, wclk_shift, pclk_s= hift, "osc26m",\ + mux_reg, mux_shift, mux_size, mux_sel,\ + div_reg, div_shift, div_size, 0) + +#define ZX_CLK_CRIT(name, reset_reg, reset_shift, gate_reg, wclk_shift, pc= lk_shift,\ + mux_reg, mux_shift, mux_size, mux_sel,\ + div_reg, div_shift, div_size) \ + _ZX_CLK(name, reset_reg, reset_shift, gate_reg, wclk_shift, pclk_s= hift, "osc26m",\ + mux_reg, mux_shift, mux_size, mux_sel,\ + div_reg, div_shift, div_size, CLK_IS_CRITICAL) + +/* 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 mpl_d6 (default 104 MHz), changing the mpll multipl= iers 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. + */ +static const char * const ahb_sel[] =3D { + "osc26m", + "mpll_d6", /* 104 mhz */ + "mpll_d8", /* 78 mhz */ + "mpll_d8", /* 78 mhz */ +}; + +static const char * const timer_top_sel[] =3D { + "osc32k", + "osc26m", +}; + +static const char * const uart_top_sel[] =3D { + "osc26m", + "mpll_d6", /* 104 mhz */ +}; + +static const char * const m0_sel[] =3D { + "osc26m", + "mpll_d6", /* 104 mhz */ + "mpll_d8", /* 78 mhz */ + "osc32k", /* Yes, tested. It is SLLLLOOOOOWWW. */ +}; + +static const struct zx297520v3_composite top_clocks[] =3D { + /* (NAME, RESET, GATE, MUX, D= IV ), */ + + /* AHB: Don't turn this one off. The clock mux works and impact can be te= sted e.g. with + * iperf speed testing of the USB network connection. Values 2 and 3 give= the same speed. + */ + ZX_CLK_CRIT(AHB, 0x70, 0, 0x54, 12, 13, 0x3c, 4, 2, ahb_sel, 0= , 0, 0), + + /* 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_CRIT(PMM, 0x74, 0, 0x58, 0, 1, 0x00, 0, 0, clk_unknown, 0= , 0, 0), + + /* 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. Some I found by trial and error. + * + * Timer T17 is used by the ZSP firmware. The rproc driver will enable th= em as needed. + */ + ZX_CLK(TIMER_T08, 0x78, 4, 0x5c, 8, 9, 0x40, 1, 1, timer_top_sel, 0= x4c, 8, 4), + ZX_CLK(TIMER_T09, 0x78, 2, 0x5c, 4, 5, 0x40, 0, 1, timer_top_sel, 0= x4c, 0, 4), + ZX_CLK(TIMER_T12, 0x74, 6, 0x54, 4, 5, 0x3c, 0, 1, timer_top_sel, 0= x48, 0, 4), + ZX_CLK(TIMER_T13, 0x7c, 0, 0x60, 0, 1, 0x44, 0, 1, timer_top_sel, 0= x50, 0, 4), + ZX_CLK(TIMER_T14, 0x7c, 2, 0x60, 4, 5, 0x44, 1, 1, timer_top_sel, 0= x50, 4, 4), + ZX_CLK(TIMER_T15, 0x74, 10, 0x54, 20, 21, 0x3c, 3, 1, timer_top_sel, 0= x48, 4, 4), + ZX_CLK(TIMER_T16, 0x7c, 4, 0x60, 8, 9, 0x44, 2, 1, timer_top_sel, 0= x50, 8, 4), + ZX_CLK(TIMER_T17, 0x12c, 0, 0x128, 0, 1, 0x120, 0, 1, timer_top_sel, 0= x124, 0, 4), + + /* This watchdog is set up by the bootloader and in normal operation the = m0 firmware will + * feed the dog. The m0 firmware in turn wants to be fed in its own way. = Since we normally + * don't run any m0 firmware we shut it off by default and expose it to u= serspace via the + * watchdog driver. + */ + ZX_CLK(WDT_T18, 0x74, 12, 0x54, 24, 25, 0x3c, 6, 1, timer_top_sel, 0= x48, 8, 4), + + ZX_CLK(I2C0, 0x74, 8, 0x54, 8, 9, 0x3c, 1, 1, uart_top_sel, 0= , 0, 0), + ZX_CLK(UART0, 0x78, 6, 0x5c, 12, 13, 0x40, 2, 1, uart_top_sel, 0= , 0, 0), + + /* How does this RTC work? I don't know, the ZTE kernel does not talk to = it. It has an + * external RTC connected to I2C0. + */ + ZX_CLK(RTC, 0x74, 4, 0x54, 0, 1, 0x00, 0, 0, timer_top_sel, 0= , 0, 0), + + /* This doesn't see to be talking to the physical SIM card. I can turn it= off on the ZTE + * firmware without breaking LTE, and the "uicc" IRQ count keeps climbing= . I think this is + * a eSim-like chip that can be provisioned with data at runtime, but I h= ave no idea how to + * do it. + */ + ZX_CLK(USIM1, 0x74, 14, 0x54, 28, 29, 0x00, 0, 0, clk_main, 0= x48, 12, 1), + + /* (NAME, RESET, GATE, MUX, D= IV ), */ +}; + +/* Stand-alone topclk gates. */ +static const struct zx297520v3_gate top_gates[] =3D { + {ZX297520V3_USB_24M, "usb_24m", "mpll_d26", 0x6c, 3}, + {ZX297520V3_USB_AHB, "usb_ahb", "AHB_wclk", 0x6c, 4}, + /* LTE: gate only as far as I can see. I looked for resets and did not fi= nd any. There may + * be mux/div, but without understanding the behavior of this hardware it= is impossible to + * tell. They are sorted by physical MMIO address of the devices, which h= appens to be the + * inverse order of the bits. + * + * I don't know what "LPM", "TD" and "W" mean. I copied them from ZTE's n= ames. + */ + {ZX297520V3_LPM_GSM_WCLK, "LPM_GSM_wclk", clk_unknown[0], 0x58, 10}, + {ZX297520V3_LPM_GSM_PCLK, "LPM_GSM_pclk", clk_unknown[0], 0x58, 11}, + {ZX297520V3_LPM_LTE_WCLK, "LPM_LTE_wclk", clk_unknown[0], 0x58, 8}, + {ZX297520V3_LPM_LTE_PCLK, "LPM_LTE_pclk", clk_unknown[0], 0x58, 9}, + {ZX297520V3_LPM_TD_WCLK, "LPM_TD_wclk", clk_unknown[0], 0x58, 6}, + {ZX297520V3_LPM_TD_PCLK, "LPM_TD_pclk", clk_unknown[0], 0x58, 7}, + {ZX297520V3_LPM_W_WCLK, "LPM_W_wclk", clk_unknown[0], 0x58, 4}, + {ZX297520V3_LPM_W_PCLK, "LPM_W_pclk", clk_unknown[0], 0x58, 5}, + /* There are PCLKs for BROM/SRAM2 in 0x54, bit 16 and SRAM1 in 0x54, bit = 18. Turning them + * off locks up the Cortex M0 coproc. Not added to the kernel until a way= is found to + * recover the Cortex M0 or evidence of power savings. + */ + + /* 4 Clock signals can be exposed to GPIO 15 (OUT0), 16 (OUT1), 17 (OUT2)= and 18 (OUT32K). + * It looks like OUT1 and OUT2 feed an optional camera. OUT0 feeds an opt= ional sound codec. + * Turning them off reduces noise in GPIO dumps. WCLK only although the Z= TE camera code + * talks about a "software control enable" bit (0x1) that needs to be set= for OUT1 and OUT2. + * + * CLK_OUT1 has a MUX in top + 0x34 bits 6 and 7 and is the only clock th= at has upll as a + * possible parent. CLK_OUT2 has a mux in bit 8, where 1 (default) select= s osc26m. 0 is an + * unknown clock. + */ + {ZX297520V3_OUT0_WCLK, "OUT0_wclk", clk_unknown[0], 0x34, 0}, + {ZX297520V3_OUT1_WCLK, "OUT1_wclk", "upll_d5", 0x90, 2}, + {ZX297520V3_OUT2_WCLK, "OUT2_wclk", "osc26m", 0x94, 2}, + {ZX297520V3_OUT32K_WCLK, "OUT32k_wclk", "osc32k", 0x34, 1}, +}; + +static const char * const cpu_sel[] =3D { + "osc26m", + "mpll", /* 624 MHz */ + "mpll_d2", /* 312 MHz */ + "mpll_d4", /* 156 MHz */ +}; + +static const char * const sd0_sel[] =3D { + "osc26m", + "mpll_d4", /* 156 MHz */ + "gpll_d2", /* 100 MHz */ + "mpll_d8", /* 78 MHz */ + "gpll_d4", /* 50 MHz */ + "gpll_d8", /* 25 MHz */ +}; + +static const char * const sd1_sel[] =3D { + "osc26m", + "gpll_d2", /* 100 MHz */ + "mpll_d8", /* 78 MHz */ + "gpll_d4", /* 50 MHz */ + "mpll_d16", /* 39 MHz */ + "gpll_d8", /* 25 MHz */ +}; + +static const char * const nand_sel[] =3D { + "mpll_d4", /* 156 MHz */ + "osc26m", +}; + +static const char * const edcp_sel[] =3D { + "osc26m", + "mpll_d4", /* 156 MHz */ + "mpll_d5", /* 124.8 MHz */ + "mpll_d6", /* 104 MHz */ +}; + +static const char * const tdm_sel[] =3D { + "osc26m", + "dpll_d4", /* 122.88 MHz */ + "mpll_d6", /* 104 MHz */ +}; + +static const struct zx297520v3_composite matrix_clocks[] =3D { + /* Both 0x24 and 0x28 bits 1 and 2 stop the CPU. There is also a bit in t= opclk+0x138, which + * ZTE's uboot calls "A53 reset", which also stops the CPU. I can't reall= y tell the + * difference between matrix+28 and top+138. The clock can be disabled an= d enabled from the + * Cortex M0 and it will nicely stop and restart the A53, retaining all s= tate. + * + * 0x50, bits 0-3 have the DDR clock. A lot of DDR gates and resets are i= n 0x100. + */ + ZX_CLK_CRIT(CPU, 0x28, 1, 0x24, 1, 2, 0x20, 0, 2, cpu_sel, 0,= 0, 0), + ZX_CLK(SD0, 0x58, 1, 0x54, 12, 13, 0x50, 4, 3, sd0_sel, 0,= 0, 0), + ZX_CLK(SD1, 0x58, 0, 0x54, 4, 5, 0x50, 8, 3, sd1_sel, 0,= 0, 0), + /* This is some "denali" NAND, not the qspi connected one. */ + ZX_CLK(NAND, 0x58, 4, 0x54, 20, 21, 0x50, 12, 2, nand_sel, 0,= 0, 0), + ZX_CLK(SSC, 0x94, 24, 0x84, 1, 2, 0, 0, 0, clk_unknown, 0,= 0, 0), + ZX_CLK(EDCP, 0x68, 0, 0x64, 2, 1, 0x50, 16, 2, edcp_sel, 0,= 0, 0), + /* PDCFG. Like PMM, either clock bit will allow the device to function. */ + ZX_CLK_CRIT(PDCFG, 0x94, 20, 0x88, 0, 1, 0, 0, 0, clk_unknown, 0,= 0, 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, 0x16c, 0, 0x168, 0, 1, 0, 0, 0, clk_main, = 0, 0, 0), +}; + +static const struct zx297520v3_gate matrix_gates[] =3D { + /* ZTE's driver has a statemt to the effect of *(matrix->base+0x11C) =3D = 5, with a comment + * suggesting that this sets a 50 mhz clock. The clock code itself lists = the parents of + * these clock as 50mhz pll output, but the GMAC driver never enables the= clocks. + * + * The clocks below are enabled by the boot loader though, so they are on= . And it turns + * out that they are necessary for proper operation of the ethernet hardw= are. As far as + * I can see trough experimentation, bit 1 affects the PHY whereas 0 and = 2 affect the + * MAC chip itself. + * + * Chain the wclk and rmii clk together for now. I haven't found a way to= make either + * the mdio node or the phy node enable a clock. According to ethernet-ph= y.yaml it is + * supposed to be possible, but I can't find code to that effect in of_md= io.c. + */ + {ZX297520V3_GMAC_RMII, "gmac_rmii", "gpll_d4", 0x110, 1}, + {ZX297520V3_GMAC_WCLK, "gmac_wclk", "gmac_rmii", 0x110, 2}, + {ZX297520V3_GMAC_PCLK, "gmac_pclk", "gpll_d4", 0x110, 0}, + + /* ZSP aka LTE DSP clock. I think there is a mux at matrix+0x30, but I ha= ve no idea + * about the frequencies it selects. Gate is at matrix+0x3c. + */ + {ZX297520V3_ZSP_WCLK, "zsp_wclk", "osc26m", 0x3c, 0}, + + /* Mailbox. I haven't found a reset for this. It seems to have a PCLK onl= y - turning it off + * makes the MMIO area read 0x0. It looks like it does not need a WCLK. I= t generates IRQs + * fine with just bit 2 set. Bits 1 and 3 are 0 by default in this regist= er. + */ + {ZX297520V3_MBOX_PCLK, "mbox_pclk", "osc26m", 0x88, 2}, + + /* DMA Controller. It has a reset and PCLK, but no WCLK. */ + {ZX297520V3_DMA_PCLK, "dma_pclk", "osc26m", 0x94, 3}, + + /* There is another clock controlling some "GSM" IP at 0xF3000000 in 0x88= , bit 8. It appears + * to be a PCLK, but I have not found a matching WCLK or reset yet. + */ + + /* I don't know how this clock works. Card detection in the way the dwc,m= mc driver uses it + * appears broken no matter this clock's setting. + */ + {ZX297520V3_SD0_CDET, "sd0_cdet", "osc32k", 0x54, 14}, + {ZX297520V3_SD1_CDET, "sd1_cdet", "osc32k", 0x54, 6}, + + /* LSP uplink clocks. The PCLK is fairly obvious (disabling it shuts off = the entire LSP + * register area). The WCLK speeds were deduced by setting timers and qsp= i muxes to a + * specific speed and seeing which bit in matrix+0x7c needs to be enabled= for the device + * to work. + * + * Due to the timers I am certain about the 26mhz and 32khz clocks. I can= not directly + * observe the qspi mux frequency, so the clock rates depend on ZTE's qsp= i mux selection + * being correct. + * + * Two additional bits are specific to sound components - the mux for the= LSP's TDM IP is + * in matrixclk and gets passed down. I2S has a mux in LSP, which can sel= ect the dpll_d4 + * clock. + * + * This code is commented out until the next patch because disabling unus= ed clocks without + * an LSP consumer breaks the UART. + */ + {ZX297520V3_LSP_MPLL_D5_WCLK, "lsp_mpll_d5", "mpll_d5", 0x7c, 0}, + {ZX297520V3_LSP_MPLL_D4_WCLK, "lsp_mpll_d4", "mpll_d4", 0x7c, 1}, + {ZX297520V3_LSP_MPLL_D6_WCLK, "lsp_mpll_d6", "mpll_d6", 0x7c, 2}, + {ZX297520V3_LSP_MPLL_D8_WCLK, "lsp_mpll_d8", "mpll_d8", 0x7c, 3}, + {ZX297520V3_LSP_MPLL_D12_WCLK, "lsp_mpll_d12", "mpll_d12", 0x7c, 4}, + {ZX297520V3_LSP_OSC26M_WCLK, "lsp_osc26m", "osc26m", 0x7c, 5}, + {ZX297520V3_LSP_OSC32K_WCLK, "lsp_osc32k", "osc32k", 0x7c, 6}, + {ZX297520V3_LSP_PCLK, "lsp_pclk", "osc26m", 0x7c, 7}, + {ZX297520V3_LSP_TDM_WCLK, "lsp_tdm_wclk", "tdm_mux", 0x7c, 8}, + {ZX297520V3_LSP_DPLL_D4_WCLK, "lsp_dpll_d4", "dpll_d4", 0x7c, 9}, +}; + +static int zx297520v3_composite(struct device *dev, void __iomem *base, + struct clk_hw_onecell_data *clocks, struct zx29_reset_reg *resets, + const struct zx297520v3_composite *input, size_t size) +{ + char pclk_name[32], wclk_name[32], mux_name[32], div_name[32]; + const char *wclk_parent, *div_parent; + struct clk_hw *hw; + unsigned int i; + + for (i =3D 0; i < size; ++i) { + snprintf(wclk_name, ARRAY_SIZE(wclk_name), "%s_wclk", input[i].name); + snprintf(pclk_name, ARRAY_SIZE(pclk_name), "%s_pclk", input[i].name); + snprintf(mux_name, ARRAY_SIZE(mux_name), "%s_mux", input[i].name); + snprintf(div_name, ARRAY_SIZE(div_name), "%s_div", input[i].name); + + resets[input[i].reset_id].reg =3D base + input[i].reset_reg; + resets[input[i].reset_id].mask =3D BIT(input[i].reset_shift) + + BIT(input[i].reset_shift + 1); + + if (input[i].div_size) + wclk_parent =3D div_name; + else if (input[i].mux_size) + wclk_parent =3D mux_name; + else + wclk_parent =3D input[i].mux_sel[0]; + + hw =3D devm_clk_hw_register_gate(dev, pclk_name, input[i].pclk_parent, i= nput[i].flags, + base + input[i].gate_reg, input[i].pclk_gate_shift, + 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clocks->hws[input[i].pclk_id] =3D hw; + + if (input[i].mux_size) { + hw =3D devm_clk_hw_register_mux(dev, mux_name, input[i].mux_sel, + input[i].mux_sel_count, 0, + base + input[i].mux_reg, + input[i].mux_shift, input[i].mux_size, 0, + ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + div_parent =3D mux_name; + } else { + div_parent =3D input[i].mux_sel[0]; + } + + hw =3D devm_clk_hw_register_gate(dev, wclk_name, wclk_parent, + input[i].flags | CLK_SET_RATE_PARENT, + base + input[i].gate_reg, input[i].wclk_gate_shift, + 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clocks->hws[input[i].wclk_id] =3D hw; + + if (!input[i].div_size) + continue; + + hw =3D devm_clk_hw_register_divider(dev, div_name, div_parent, CLK_SET_R= ATE_PARENT, + base + input[i].div_reg, input[i].div_shift, + input[i].div_size, 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + } + + return 0; +} + +static int zx297520v3_gate(struct device *dev, void __iomem *base, + struct clk_hw_onecell_data *clocks, + const struct zx297520v3_gate *input, size_t size) +{ + struct clk_hw *hw; + unsigned int i; + + for (i =3D 0; i < size; ++i) { + hw =3D devm_clk_hw_register_gate(dev, input[i].name, input[i].parent, + CLK_SET_RATE_PARENT, base + input[i].reg, + input[i].shift, 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + clocks->hws[input[i].id] =3D hw; + } + + return 0; +} + +static int zx_restart_handle(struct sys_off_data *data) +{ + void __iomem *top_base =3D data->cb_data; + + writel(1, top_base); + mdelay(1000); + + pr_emerg("Unable to restart system\n"); + return NOTIFY_DONE; +} + +static const char * const dpll_sel[] =3D { + "unknownpll_d2", + "osc26m", + "osc26m", + "osc26m", +}; + +static const struct zx29_pll_desc zx297520_plls[] =3D { + /* Default setting: 0x48040c11. 624/312/156. Only a single possible paren= t. This is the + * PLL for pretty much everything, including CPU, RAM and USB. + * + * Changing this PLL makes it possible to overclock the CPU or do more fi= ne grained + * underclocking than the CPU's mux allows. It does run into two problems= though: The USB + * device uses this PLL's output directly and is *very* sensitive to diff= erences. DRAM + * is also fed by this clock and needs to be re-trained on larger changes= , which needs to + * be done by the stage 1 boot loader. + */ + {0x8, "mpll", clk_main, ARRAY_SIZE(clk_main)}, + + /* ZTE's code calls this PLL "upll". The only possible consumer I found i= s clk_out1, which + * outputs this clock on GPIO 16. The device that consumes this is an SPI= camera, which I + * haven't seen in any device so far. clk_out1 has a gate in top + 0x90, = bits 0 and 2. A mux + * is in top + 0x34, bits 2 and 3. + * + * Long story short, shut it off. + */ + {0x10, "upll", clk_main, ARRAY_SIZE(clk_main)}, + + /* 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. + */ + {0x100, "unknownpll", clk_main, ARRAY_SIZE(clk_main)}, + + /* The documentation says 491.52 MHz and measurement with the LSP TDM dev= ice supports this. + * The default value is 0x480C2011, but not all boot loaders set it up. T= o get to 491.52 + * with these settings it needs a 23.04 MHz reference clock, which matche= s unknownpll_d2. + * If unknownpll is disabled, dpll loses its lock. We set the frequency o= n this PLL if we + * find it is not enabled by the boot loader. + * + * The proprietary LTE driver or coproc enables and disables it. TDM and = I2S can use it. + * + * It accepts parent values 0, 1, 2 and 3. Parent 0 is unknownpll_d2. The= others 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. + */ + {0x18, "dpll", dpll_sel, ARRAY_SIZE(dpll_sel), 491520000}, + + /* "g" is either for "general" or "gigahertz". The VCO runs at 1GHz. Outp= ut clocks are 200, + * 100, 50, 25 MHz. It is only used by SDIO though, so not very general. + */ + {0x110, "gpll", clk_main, ARRAY_SIZE(clk_main)}, +}; + +static int zx297520_topclk_probe(struct platform_device *pdev) +{ + void __iomem *top_base, *matrix_base; + struct zx29_clk_controller *top; + struct device *dev =3D &pdev->dev; + struct clk_hw *hw; + struct clk *clk; + unsigned int i; + int res; + + top =3D devm_kzalloc(dev, offsetof(struct zx29_clk_controller, + resets[ZX297520V3_TOPRST_END]), GFP_KERNEL); + if (!top) + return -ENOMEM; + + top->clocks =3D devm_kzalloc(dev, struct_size(top->clocks, hws, + ZX297520V3_TOPCLK_END), GFP_KERNEL); + if (!top->clocks) + return -ENOMEM; + top->clocks->num =3D ZX297520V3_TOPCLK_END; + + top_base =3D devm_platform_ioremap_resource_byname(pdev, "top"); + if (IS_ERR(top_base)) + return PTR_ERR(top_base); + matrix_base =3D devm_platform_ioremap_resource_byname(pdev, "matrix"); + if (IS_ERR(matrix_base)) + return PTR_ERR(matrix_base); + + + /* Offset 0x0 is the global board reset + * Offset 0x4 gives some static boot information - raw NAND or SPI NAND + */ + + clk =3D devm_clk_get(dev, "osc32k"); + if (IS_ERR(clk)) { + dev_err(dev, "32 KHz input clock not found\n"); + return PTR_ERR(clk); + } + + clk =3D devm_clk_get(dev, clk_main[0]); + if (IS_ERR(clk)) { + dev_err(dev, "26 MHz input clock not found\n"); + return PTR_ERR(clk); + } + + res =3D zx29_register_plls(dev, top_base, zx297520_plls, ARRAY_SIZE(zx297= 520_plls)); + if (res) + return res; + + res =3D zx297520v3_composite(dev, top_base, top->clocks, top->resets, + top_clocks, ARRAY_SIZE(top_clocks)); + if (res) + return res; + res =3D zx297520v3_composite(dev, matrix_base, top->clocks, top->resets, + matrix_clocks, ARRAY_SIZE(matrix_clocks)); + if (res) + return res; + + res =3D zx297520v3_gate(dev, top_base, top->clocks, top_gates, ARRAY_SIZE= (top_gates)); + if (res) + return res; + res =3D zx297520v3_gate(dev, matrix_base, top->clocks, + matrix_gates, ARRAY_SIZE(matrix_gates)); + if (res) + return res; + + /* The Cortex M0 coprocessor. It is responsible for booting the board and= runs some power + * management helper code on the stock firmware, but isn't critical. We c= an run custom code + * on it but currently do not. These bits control the speed and the valu= es are mentioned in + * ZTE's uboot. It isn't clear to me if this is directly responsible for = the m0 clock, or + * if it is the input to another clock. I also haven't found a gate that = shuts the m0 off + * and allows restarting. There don't seem to be resets either. + * + * Also note the comment about SRAM1 and SRAM2 PCLKs. They can be turned = off, which will + * crash the M0 if it reads instructions from them. + */ + hw =3D devm_clk_hw_register_mux(dev, "m0_wclk", m0_sel, ARRAY_SIZE(m0_sel= ), + 0, top_base + 0x38, 0, 2, 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + top->clocks->hws[ZX297520V3_M0_WCLK] =3D hw; + + /* One stray matrix mux: The TDM mux is in matrixclk and it is passed to = the LSP controller. + * In a way the matrix-LSP link gate (LSP_TDM_WCLK) could be considered a= matching gate, but + * there is no reset and no pclk. + */ + hw =3D devm_clk_hw_register_mux(dev, "tdm_mux", tdm_sel, ARRAY_SIZE(tdm_s= el), 0, + matrix_base + 0x50, 24, 2, 0, ®_lock); + if (IS_ERR(hw)) + return PTR_ERR(hw); + + /* This is to catch holes in the tables rather than registration errors */ + for (i =3D 0; i < ZX297520V3_TOPCLK_END; i++) { + if (!top->clocks->hws[i]) { + dev_err(dev, "Clock %u not registered\n", i); + return -ENODEV; + } + } + + res =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, top->cloc= ks); + if (res) + return res; + + + res =3D devm_register_restart_handler(dev, zx_restart_handle, top_base); + if (res) + dev_err(dev, "can't register restart handler (res=3D%d)\n", res); + + /* Stray reset bits follow. + * + * I haven't found any clocks for GPIO. It probably wouldn't make much + * sense anyway. Only one bit per controller. + */ + top->resets[ZX297520V3_GPIO8_RESET].reg =3D top_base + 0x74; + top->resets[ZX297520V3_GPIO8_RESET].mask =3D BIT(2); + top->resets[ZX297520V3_GPIO_RESET].reg =3D top_base + 0x74; + top->resets[ZX297520V3_GPIO_RESET].mask =3D BIT(3); + + /* USB reset. This is slightly special because it needs to wait for a rea= dy bit after + * deasserting. + */ + top->resets[ZX297520V3_USB_RESET].reg =3D top_base + 0x80; + top->resets[ZX297520V3_USB_RESET].mask =3D BIT(3) | BIT(4) | BIT(5); + top->resets[ZX297520V3_USB_RESET].wait_mask =3D BIT(1); + + /* 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 matrixclk. + */ + top->resets[ZX297520V3_ZSP_RESET].reg =3D top_base + 0x13c; + top->resets[ZX297520V3_ZSP_RESET].mask =3D BIT(0); + + top->resets[ZX297520V3_DMA_RESET].reg =3D matrix_base + 0x70; + top->resets[ZX297520V3_DMA_RESET].mask =3D BIT(0) | BIT(1); + top->resets[ZX297520V3_GMAC_RESET].reg =3D matrix_base + 0x114; + top->resets[ZX297520V3_GMAC_RESET].mask =3D BIT(0) | BIT(1); + + for (i =3D 0; i < ZX297520V3_TOPRST_END; ++i) { + if (!(top->resets[i].reg && top->resets[i].mask)) { + dev_err(dev, "zx297520v3 reset %u has no register or mask\n", i); + return -ENODEV; + } + } + + top->rcdev.owner =3D THIS_MODULE; + top->rcdev.nr_resets =3D ZX297520V3_TOPRST_END; + top->rcdev.ops =3D &zx297520v3_rst_ops; + top->rcdev.of_node =3D dev->of_node; + return devm_reset_controller_register(dev, &top->rcdev); +} + +static const struct of_device_id of_match_zx297520v3_topclk[] =3D { + { .compatible =3D "zte,zx297520v3-topclk"}, + { } +}; +MODULE_DEVICE_TABLE(of, of_match_zx297520v3_topclk); + +static struct platform_driver clk_zx297520v3_topclk =3D { + .probe =3D zx297520_topclk_probe, + .driver =3D { + .name =3D "clk-zx297520v3-topclk", + .of_match_table =3D of_match_zx297520v3_topclk, + }, +}; +module_platform_driver(clk_zx297520v3_topclk); + +MODULE_AUTHOR("Stefan D=C3=B6singer "); +MODULE_DESCRIPTION("ZTE zx297520v3 clock driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/zte/pll.c b/drivers/clk/zte/pll.c new file mode 100644 index 000000000000..b1b74b8057e9 --- /dev/null +++ b/drivers/clk/zte/pll.c @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pll.h" + +/* This code has only been tested with zx297520v3 PLLs, but from reading t= he zx296718 clock code it + * looks like PLL registers are similar. ZTE's sources explain the PLL reg= ister contents only in a + * .cmm file (A Lauterback TRACE32 script) and some unused headers in thei= r U-Boot code dump, which + * may not be accurate. When calculating the frequencies from the default = PLL configuration the + * results match the fixed rate clocks from their clock driver. + * + * The 26mhz and 32khz clocks can be easily observed with the timers. The = 104mhz output can be + * observed through the UART. One 122.88 PLL can be observed through the T= DM device. All others can + * only be indirectly infered, e.g. by comparing CPU speed or SDIO transfe= r rate between the fixed + * 26 MHz oscillator and the provided PLL frequency. + * + * The formula to calculate the clock is ((ref / refdiv) * fbdiv) / postdi= v1 / postdiv2. The masks + * are given below. There are a few control flags: + * + * Bit 31: Disables the PLL, but passes the reference through unmodified. = If POSTDIV_OUT_DISABLE + * still matters is different between PLLs. + * Bit 30: Returns if the PLL is locked + * Bit 29: Not named in ZTE's code, but can be set. There is no obvious im= pact. Lock times are + * unchanged, so it doesn't influence or bypass lock detection. It= doesn't raise any IRQs or + * influence GPIOs. + * Bit 27: Given its name it likely disables the Delta-Sigma Modulator, if= one exists at all. The + * boot ROM sets it on every PLL. Unsetting it marginally decrease= s the time it takes to + * lock to the reference clock (from ~400us to ~300us). Regardless= of this bit I could not + * make the supposed fractional part in register 2 work. + * Bit 24: Bypasses the VCO, but still applies refdiv and postdiv. Doesn't= matter if PLL_DISABLE=3D1. + */ + +#define ZX29_PLL_DISABLE BIT(31) +#define ZX29_PLL_LOCKED BIT(30) +#define ZX29_PLL_LOCK_FILTER BIT(29) +#define ZX29_PLL_DSM_DISABLE BIT(27) +#define ZX29_PLL_PARENT_MASK GENMASK(26, 25) +#define ZX29_PLL_PARENT_SHIFT 25 +#define ZX29_PLL_BYPASS BIT(24) +#define ZX29_PLL_REFDIV_MASK GENMASK(23, 18) +#define ZX29_PLL_REFDIV_SHIFT 18 +#define ZX29_PLL_FBDIV_MASK GENMASK(17, 6) +#define ZX29_PLL_FBDIV_SHIFT 6 +#define ZX29_PLL_POSTDIV1_MASK GENMASK(5, 3) +#define ZX29_PLL_POSTDIV1_SHIFT 3 +#define ZX29_PLL_POSTDIV2_MASK GENMASK(2, 0) +#define ZX29_PLL_POSTDIV2_SHIFT 0 + +/* The second register is supposed to have another 24 bit value that gets = added to fbdiv but it is + * always 0 in the preconfigured values. I could not observe any effect fr= om setting it to something + * other than 0, regardless of the DSM disable bit. It is possible that it= is only supported by + * dpll, which is a possible parent for i2s. + * + * Bits 28:25 contain more flags: + * + * Bit 27: Setting ZX29_PLL_DACAP slows down the lock time and obivates th= e speed gained from + * !DSM_DISABLE. No other effect observed. + * + * Bit 26: ZX29_PLL_4PHASE_OUT_DISABLE is set on some PLLs on boot but not= on others. It is set on + * boot on mpll and upll, but not gpll, dpll or unknownpll. I am n= ot sure what it does + * either. The SDIO devices break if they are fed from gpll with t= his flag set, but they + * work ok if they are fed from mpll without this flag set. + * + * Bit 25: ZX29_PLL_POSTDIV_OUT_DISABLE seems to disable the PLL output en= tirely. Whether it is + * bypassed by PLL_DISABLE differs between PLLs. gpll still produc= es an output clock if + * PLL_DISABLE =3D 1 and POSTDIV_DISABLE =3D 1, but produces no ou= tput if PLL_DISABLE =3D 0 and + * POSTDIV_DISABLE =3D 1. The dpll feeder ("unknownpll") at 0x100 = produces no output clock + * if both PLL_DISABLE and POSTDIV_DISABLE are set to 1. + * + * Bit 24: ZX29_PLL_VCO_OUT_DISABLE probably disables the output of the VC= O clock without + * post-VCO-dividers, but the raw VCO output is not a possible par= ent of any consumer clock, + * so I could not confirm this. It does not disable the VCO entir= ely - that's what + * PLL_DISABLE does. + * + * A spinlock should not be needed. PLLs don't share their registers with = anything else and the + * global prepare mutex and enable spinlock should be enough. Beware of co= nflicts in reg2 between + * POSTDIV_OUT_DISABLE and the fractional value in case you find out how f= ractional dividers work + * and add support for them. + */ +#define ZX29_PLL_REG2_OFFSET 4 +#define ZX29_PLL_DACAP BIT(27) +#define ZX29_PLL_4PHASE_OUT_DISABLE BIT(26) +#define ZX29_PLL_POSTDIV_OUT_DISABLE BIT(25) +#define ZX29_PLL_VCO_OUT_DISABLE BIT(24) + +/* The VCO's frequency range is limited. The stock settings run the VCO be= tween 960 and 1248 MHz. + * Ad-hoc testing with gpll suggests that at least this PLL remains stable= down to about 7 MHz and + * up to 2 GHz and produces a clock that can be used by the SDIO controlle= r. Attempting to run the + * mpll VCO at 624 MHz and setting postdiv1 =3D postdiv2 =3D 1 - which sho= uld result in the same output + * frequency - or running it at 1872 MHz with an effective post divider of= 3 crashes the CPU. Most + * likely the PLLs become unstable outside their core range and the SDIO c= ontroller is much more + * forgiving than CPU and DRAM are. + */ +#define ZX29_PLL_VCO_MAX_FREQ (1300*HZ_PER_MHZ) +#define ZX29_PLL_VCO_MIN_FREQ (900*HZ_PER_MHZ) + +struct zx29_clk_pll { + struct device *dev; + struct clk_hw hw; + void __iomem *base; +}; + +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); + + return !(readl(pll->base) & ZX29_PLL_DISABLE); +} + +static int zx29_pll_prepare(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + int res; + + val =3D readl(pll->base); + val &=3D ~ZX29_PLL_DISABLE; + writel(val, pll->base); + + /* Lock duration is usually between 300us to 500us */ + res =3D readl_poll_timeout(pll->base, val, val & ZX29_PLL_LOCKED, 50, 200= 0); + dev_dbg(pll->dev, "%s: Enable result %u val 0x%08x\n", clk_hw_get_name(&p= ll->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); + u32 val; + + val =3D readl(pll->base); + val |=3D ZX29_PLL_DISABLE; + writel(val, pll->base); +} + +static int zx29_pll_is_enabled(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val, val2; + + val =3D readl(pll->base); + val2 =3D readl(pll->base + ZX29_PLL_REG2_OFFSET); + + return !(val & ZX29_PLL_BYPASS) && !(val2 & ZX29_PLL_POSTDIV_OUT_DISABLE); +} + +static int zx29_pll_enable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + + val =3D readl(pll->base); + val &=3D ~ZX29_PLL_BYPASS; + writel(val, pll->base); + + val =3D readl(pll->base + ZX29_PLL_REG2_OFFSET); + val &=3D ~ZX29_PLL_POSTDIV_OUT_DISABLE; + writel(val, pll->base + ZX29_PLL_REG2_OFFSET); + + return 0; +} + +static void zx29_pll_disable(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + + /* FIXME: Should we bother to set ZX29_PLL_BYPASS? It shouldn't make a di= fference because + * ZX29_PLL_POSTDIV_OUT_DISABLE cuts the output anyway. + */ + + val =3D readl(pll->base + ZX29_PLL_REG2_OFFSET); + val |=3D ZX29_PLL_POSTDIV_OUT_DISABLE; + writel(val, pll->base + ZX29_PLL_REG2_OFFSET); +} + +static unsigned long zx29_pll_get_rate(const struct zx29_clk_pll *pll, uns= igned long parent_rate, + u32 setting) +{ + unsigned long refdiv, fbdiv, postdiv1, postdiv2, freq; + const char *name =3D clk_hw_get_name(&pll->hw); + u64 vco; + + refdiv =3D (setting & ZX29_PLL_REFDIV_MASK) >> ZX29_PLL_REFDIV_SHIFT; + fbdiv =3D (setting & ZX29_PLL_FBDIV_MASK) >> ZX29_PLL_FBDIV_SHIFT; + postdiv1 =3D (setting & ZX29_PLL_POSTDIV1_MASK) >> ZX29_PLL_POSTDIV1_SHIF= T; + postdiv2 =3D (setting & ZX29_PLL_POSTDIV2_MASK) >> ZX29_PLL_POSTDIV2_SHIF= T; + dev_dbg(pll->dev, "%s: reference clock %lu HZ, PLL setting 0x%08x\n", + name, parent_rate, setting); + + 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 =3D readl(pll->base); + + return zx29_pll_get_rate(pll, parent_rate, val); +} + +static u32 zx29_pll_calc_values(const struct zx29_clk_pll *pll, unsigned l= ong parent_rate, + unsigned long rate) +{ + const unsigned int postdiv1_max =3D (1 << hweight32(ZX29_PLL_POSTDIV1_MAS= K)) - 1; + const unsigned int postdiv2_max =3D (1 << hweight32(ZX29_PLL_POSTDIV2_MAS= K)) - 1; + u32 postdiv1 =3D 0, postdiv2 =3D 0, i, j, setting; + const char *name =3D clk_hw_get_name(&pll->hw); + unsigned long fbdiv, refdiv, best_fbdiv =3D 0, best_refdiv =3D 0; + long best =3D LONG_MAX; + + /* This code produces the same VCO settings that the boot loader and stoc= k firmware use for + * the standard frequencies. It has seen only very little manual testing = beyond that. + * + * The goal is to find a VCO setting that gets us as close as possible to= the desired output + * rate, while being within the VCO's operating limits and achievable wit= h the input value + * range. It is iterating over possible post-VCO diver values (1-7)*(1-7)= to look for valid + * VCO target frequencies and then looks for refdiv and fbdiv values to a= chieve the VCO + * frequency from the reference frequency. + */ + for (j =3D 1; j <=3D postdiv2_max; j++) { + for (i =3D 1; i <=3D postdiv1_max; i++) { + u64 vco =3D (u64)rate * i * j; + long out; + + if (vco > ZX29_PLL_VCO_MAX_FREQ || vco < ZX29_PLL_VCO_MIN_FREQ) + continue; + + rational_best_approximation(rate * i * j, + parent_rate, + (1 << hweight32(ZX29_PLL_FBDIV_MASK)) - 1, + (1 << hweight32(ZX29_PLL_REFDIV_MASK)) - 1, + &fbdiv, &refdiv); + setting =3D fbdiv << ZX29_PLL_FBDIV_SHIFT; + setting |=3D refdiv << ZX29_PLL_REFDIV_SHIFT; + setting |=3D i << ZX29_PLL_POSTDIV1_SHIFT; + setting |=3D j << ZX29_PLL_POSTDIV2_SHIFT; + out =3D zx29_pll_get_rate(pll, parent_rate, setting); + + if (abs(out - rate) > best) + continue; + + if (abs(out - rate) < best) { + postdiv1 =3D i; + postdiv2 =3D j; + best_fbdiv =3D fbdiv; + best_refdiv =3D refdiv; + best =3D abs(out - rate); + + /* It won't get any better. */ + if (!best) + goto search_done; + } + } + } +search_done: + + if (!postdiv1) { + dev_err(pll->dev, "Did not find a setting for %lu Hz, parent %lu Hz\n", + rate, parent_rate); + return 0; + } + + dev_dbg(pll->dev, "%s: parent rate %lu\n", name, parent_rate); + dev_dbg(pll->dev, "%s: found VCO dividers %u and %u\n", name, postdiv1, p= ostdiv2); + dev_dbg(pll->dev, "%s: VCO target rate %lu\n", name, rate * postdiv1 * po= stdiv2); + + dev_dbg(pll->dev, "%s: Got fbdiv =3D %lu refdiv =3D %lu\n", name, best_fb= div, best_refdiv); + + setting =3D best_fbdiv << ZX29_PLL_FBDIV_SHIFT; + setting |=3D best_refdiv << ZX29_PLL_REFDIV_SHIFT; + setting |=3D postdiv1 << ZX29_PLL_POSTDIV1_SHIFT; + setting |=3D postdiv2 << ZX29_PLL_POSTDIV2_SHIFT; + dev_dbg(pll->dev, "%s: Final setting 0x%08x\n", name, setting); + + return setting; +} + +static int zx29_pll_determine_rate(struct clk_hw *hw, struct clk_rate_requ= est *req) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + unsigned long new_rate, parent_rate =3D clk_hw_get_rate(clk_hw_get_parent= (&pll->hw)); + u32 setting; + + setting =3D zx29_pll_calc_values(pll, parent_rate, req->rate); + if (!setting) + return -EINVAL; + + new_rate =3D zx29_pll_get_rate(pll, parent_rate, setting); + if (new_rate !=3D req->rate) { + dev_warn(pll->dev, "Did not find an exact match. Want %lu, got %lu\n", + req->rate, new_rate); + } + + 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, val; + int res =3D -EINVAL; + + setting =3D zx29_pll_calc_values(pll, parent_rate, rate); + if (zx29_pll_get_rate(pll, parent_rate, setting) =3D=3D rate) { + val =3D readl(pll->base) & 0xff000000; + val |=3D setting; + dev_info(pll->dev, "%s: Setting rate: 0x%08x\n", clk_hw_get_name(hw), va= l); + writel(val, pll->base); + + res =3D 0; + } + + return res; +} + +static u8 zx29_pll_get_parent(struct clk_hw *hw) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val =3D readl(pll->base); + + val =3D (val & ZX29_PLL_PARENT_MASK) >> ZX29_PLL_PARENT_SHIFT; + dev_dbg(pll->dev, "%s: Parent 0x%x\n", clk_hw_get_name(hw), val); + + return val; +} + +static int zx29_pll_set_parent(struct clk_hw *hw, u8 index) +{ + struct zx29_clk_pll *pll =3D to_zx29_clk_pll(hw); + u32 val; + + val =3D readl(pll->base); + val &=3D ~ZX29_PLL_PARENT_MASK; + val |=3D index << ZX29_PLL_PARENT_SHIFT; + writel(val, pll->base); + + val =3D (readl(pll->base) & ZX29_PLL_PARENT_MASK) >> ZX29_PLL_PARENT_SHIF= T; + + if (val !=3D index) { + dev_err(pll->dev, "Hardware rejected PLL parent %u\n", index); + return -EINVAL; + } + return 0; +} + +const struct clk_ops zx29_pll_ops =3D { + .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, +}; + +int zx29_register_plls(struct device *dev, void __iomem *base, const struc= t zx29_pll_desc *desc, + unsigned int count) +{ + /* These are the fractionals of the PLLs I have seen. There should be a b= etter way to + * generate them than hardcode the list. + */ + static const unsigned int pll_fract[] =3D {2, 3, 4, 5, 6, 8, 12, 16, 26}; + + struct zx29_clk_pll *pll; + unsigned int i, f; + struct clk_hw *hw; + char plldiv[32]; + int res; + u32 val; + + for (i =3D 0; i < count; ++i) { + struct clk_init_data init =3D {}; + + pll =3D devm_kzalloc(dev, sizeof(*pll), GFP_KERNEL); + if (!pll) + return -ENOMEM; + + pll->dev =3D dev; + + init.name =3D desc[i].name; + init.ops =3D &zx29_pll_ops; + init.parent_names =3D desc[i].parents; + init.num_parents =3D desc[i].num_parents; + pll->hw.init =3D &init; + pll->base =3D base + desc[i].reg; + + res =3D devm_clk_hw_register(pll->dev, &pll->hw); + if (res) + return res; + + val =3D readl(pll->base); + if (val & ZX29_PLL_DISABLE) { + if (desc[i].rate) { + dev_dbg(dev, "%s: Setting to %lu Hz\n", desc[i].name, desc[i].rate); + res =3D clk_set_rate(pll->hw.clk, desc[i].rate); + if (res) { + dev_err(dev, "%s: Failed to set rate.\n", desc[i].name); + return res; + } + } + + /* Set ZX29_PLL_POSTDIV_OUT_DISABLE for PLLs that have ZX29_PLL_DISABLE= for + * consistency with .enable and .prepare. This ensures that .prepare do= esn't + * inadvertedly enable PLLs without .enable being called. + */ + val =3D readl(pll->base + ZX29_PLL_REG2_OFFSET); + val |=3D ZX29_PLL_POSTDIV_OUT_DISABLE; + writel(val, pll->base + ZX29_PLL_REG2_OFFSET); + } + + for (f =3D 0; f < ARRAY_SIZE(pll_fract); ++f) { + snprintf(plldiv, sizeof(plldiv), "%s_d%u", desc[i].name, pll_fract[f]); + hw =3D devm_clk_hw_register_fixed_factor(dev, plldiv, desc[i].name, + 0, 1, pll_fract[f]); + if (IS_ERR(hw)) + return PTR_ERR(hw); + dev_dbg(dev, "%s: %lu hz\n", clk_hw_get_name(hw), clk_hw_get_rate(hw)); + } + } + + return 0; +} diff --git a/drivers/clk/zte/pll.h b/drivers/clk/zte/pll.h new file mode 100644 index 000000000000..d99693407384 --- /dev/null +++ b/drivers/clk/zte/pll.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2026 Stefan D=C3=B6singer + */ + +#ifndef __DRV_CLK_ZTE_PLL_H +#define __DRV_CLK_ZTE_PLL_H + +#include +#include + +struct zx29_pll_desc { + u32 reg; + const char *name; + const char * const *parents; + unsigned int num_parents; + unsigned long rate; +}; + +int zx29_register_plls(struct device *dev, void __iomem *base, const struc= t zx29_pll_desc *plls, + unsigned int count); + +#endif /* __DRV_CLK_ZTE_PLL_H */ --=20 2.53.0 From nobody Mon Jun 8 14:35:53 2026 Received: from mail-wm1-f43.google.com (mail-wm1-f43.google.com [209.85.128.43]) (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 CA1253655D9 for ; Thu, 28 May 2026 21:55:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.43 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005316; cv=none; b=QIOaQGPDBQC+mI7ZR1P+7ILrnDV1MJdhk65Ldk3upFrshTD/uqE3f6cOA9x3Bw1lWtlWJ9s9q9iIIk5bxHhqc5YJW0PRAsW42ITXfwNdlf/pfM7P9IG9MCopOY5yAdIBmdRtV9lQ8BAF+Shtwe+FUA+s7ncOxPnfOvJj1W8Bo0U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005316; c=relaxed/simple; bh=AVUFgiK7WQ+mMjNIpR/liazNbRKizRRSLTK4vpplnYY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R8T4vfNZj1wYPG10RYj4LBqO4eQOC1EPVeYY5rMBk8VpsLQymtrRutZUBA74tws6tyMGe473m8ZAji44PJGxMrCLuHJUWEDAJbIxSeDbVZOiPy3NTlHLvL0Sitm3N9eR1Vw6qla51iBlWbApd/qYqZahSpkmf3TfFOBhOC44vZ4= 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=boB46W0U; arc=none smtp.client-ip=209.85.128.43 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="boB46W0U" Received: by mail-wm1-f43.google.com with SMTP id 5b1f17b1804b1-4903974854dso66214205e9.3 for ; Thu, 28 May 2026 14:55:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780005312; x=1780610112; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=r6GY5IuJzx23m60s6A8vYe4mS1IBwBzCIrH9BI78VSQ=; b=boB46W0UO6jovSmWv7UD2lkYReYeU/9EOOHi0fVlvUuf/Fwf9HEZGa0DR0KYlMLVFg Ol1dM0iqK76cqjbQYf5trkosjM2IIalwChfD2nR+jsRJaIcAg0qEfuXbH15gbSJU9zaN tPNHbvWahgPz6hjjCq1fMWJ3mOURCgWRN/53pTHu4vtvtYoy9BIqHYnUdFVLBhWSsTmX RXKgsPsvHp6gzPGnjeMxZCUQW1mLSKxd1NIS8Efr18mUe4p1iFpuafPVPZJDOWsY8U/e mx2MYvs1chvRI4Z6xui4M+ZLwsD8i9mt6aMz98jMRJfSxoOMJ78LmHe11O+7GwckvzsG mAAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780005312; x=1780610112; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=r6GY5IuJzx23m60s6A8vYe4mS1IBwBzCIrH9BI78VSQ=; b=qHJ9Jsz6t8YLDV3kHdx1HOFXXJK5kJYhTuMStpR3MghR7w4q3ssDIkf4zHhUxq3UJl ql7bijdYaj0MdGt352VFNGttoVJsGjOFnKG9HFhuo8SEsxIO1waYecBw1u0TFwpSTIVX FVpKI7cGP8FPFQp2TyzVr8IDQMjdSlYKG9jUDZPSRCQBpLcdoBHv+TgKT45oM6Wmakw0 kwW8pA4ldH+uAdUnopnhnBc57vtH2fzMxlCdd8kVIpZ7e7njYDY0aq5hhjWFkQYeMIYY I9w1tFnk6QzXvugg84zTifFaSO8U8BM3aOn9ki9eaBfYV78kEk16QVWPrQMMdP6KGSIa nLBg== X-Forwarded-Encrypted: i=1; AFNElJ9f6gNj4sgG2mwcZK2kbSjOf+/mHin6z+IPjLlaztPRwOiUOan919Lz+RtuhBZN/JuldenJyT9vLEaSDsI=@vger.kernel.org X-Gm-Message-State: AOJu0YzRKBYkQrSmaSRsvRS3+yUrWyORSB9fu+JkG7L6w5Zj8Z5IifTg Pi4NqoXqR6pZL4R1ydOUIUAGbVax9i6KoSbYjPrlzZopVmaTJBCYx/DZ X-Gm-Gg: Acq92OH+DGqTj0yJMXFlpUMa5gfVNGNP5COai86nAip3NN3tbyPTntZosMyjjSI2tDm rukzkHl4i/wKXOHcB61SslUem8KBsSiKJqcMn32b7xZ833Dh9mEBH3DkQ/dCWDSVp8N9A850rB6 iIC3hpGLtguDLwj0zQJ6m05POitkkvTZNhZHafS7aLIEhhj4eXhwJ0NtXMqUuwHdggMpXcPQk3h cKNGj4rKG20ERv1sNbRs8xFMQqta4u4ceWHlKkapT8eNAGnSvMG6E3eJqGNsUyhW1O9fhbyc8Cs 5dDN1PPZ9UajBFWGl+lJsyItJ2coXW3ME4InbN/+iCczfDPpTkvp10t6akfGtnQRhmQ1HZA6ooJ 8I2KjBylxldQ2gv3ZFBMh7MOWr3mcRzJEvUDtLCifc0RIxySBZ2CHFnCQAt0c3MfXf2eObbpat6 NiKE299RbWPsGDJwwPn+U+Kl9fmGXVBH0+pjfHv6YXcwui X-Received: by 2002:a05:600c:1550:b0:490:846d:e2de with SMTP id 5b1f17b1804b1-4909c0bedc5mr4082985e9.28.1780005311929; Thu, 28 May 2026 14:55:11 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.223]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909c967c6csm1191085e9.2.2026.05.28.14.55.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 14:55:11 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 29 May 2026 00:53:01 +0300 Subject: [PATCH RFC v3 4/5] clk: zte: Introduce a driver for zx297520v3 LSP clocks and resets. 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: <20260529-zx29clk-v3-4-c7fe54ea388f@gmail.com> References: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> In-Reply-To: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=8696; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=AVUFgiK7WQ+mMjNIpR/liazNbRKizRRSLTK4vpplnYY=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqGLmoPxGIR38pv/G8my07awKQKo8toRvnXlCFt zwX/d3zrDiJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCahi5qBsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiIB3w//SRm4tIyJw2mD8PlafrWszGcNacBB5JI rf7yozIEmAdXZOTMGC4yojuWxZ9V3i3GcNs5MptWRW31ajf0IAPWqgN882jNA4HiZMAzrC7QJMh yJcQUOyTpzlKop0FBiMc238oW2RWiG81N3AAVkIifcpwVbkXLZlAubmvFLcI0xYrGEuovO9+/oa bnM8FR/8Xv7pQD4YeS8EOBgyAnvCU8VOPBlFUEqPEtlvt0Gf0RxC3wdfEvXaJ9CShqFPD+LuZCZ 85T6MM9TOspgWMH85TOUPCagXV3UKvcHUmMiIr5lil/Ho9jyh1vxyD5J0df2C/vxMcBGCo2Vo6G TkFN/lDycLLEIfvVKU3obXMQqISek42+kZF2mmUyfdUD8X+Rjio2uu61AXOqRBHAUxH1oG4EqAI cpkcmq8yn8DxMIIwGqyG98ILApYBu9a/kkxNvfu53K8XM53MGFYrHcfgufJlXH5cgQ5Iw5JxX97 tTxVT4Pvv/u5D5uQR1paP3QnrnQnAuxIJzdB5VIQ9NEl+SLoGR3j7v9AUzdtKXBUvy5+mYPmLS1 iphv+5qofVIq7Np6Bp+FLWW7Pm0fxy4I7BjIJ14Sy4Ew5zsP4XqDkuMcx8SRBW3vml0OU7xgv27 dhOLuSR/H0nGW9kknwGtmzuQnUfs4vSxNameIdiBXsluJ3dEvSNE= 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 two more I2C controllers that supposedly connect to a battery charger, SPI for displays and I2S for analog telephones. The boards I have don't have any of these components though. Signed-off-by: Stefan D=C3=B6singer --- drivers/clk/zte/clk-zx297520v3.c | 230 +++++++++++++++++++++++++++++++++++= +++- 1 file changed, 229 insertions(+), 1 deletion(-) diff --git a/drivers/clk/zte/clk-zx297520v3.c b/drivers/clk/zte/clk-zx29752= 0v3.c index 986042dd4caf..a67b7fe332f3 100644 --- a/drivers/clk/zte/clk-zx297520v3.c +++ b/drivers/clk/zte/clk-zx297520v3.c @@ -755,6 +755,191 @@ static int zx297520_topclk_probe(struct platform_devi= ce *pdev) return devm_reset_controller_register(dev, &top->rcdev); } =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 reset bits. I don't know the difference between the two= , but they both + * need to be set to deassert the reset. + * + * Bits 12-16 can be a divisor, but not all clocks have it. Some clocks ha= ve a divisor in 16-20. + * + * The ID given in this table is the first register in the device's MMIO s= pace. ZTE's drivers + * usually call this a version register, but it looks more like a device i= dentifier. + * + * It looks like the registers map to devices like this: + * + * Timer reg function div dev offset(lsp + xxxx) ID + * 0x0: Read-only, probably device identifier 0x00752100 + * 0x4: timer_l1 Y 0x1000 0x02020000 + * 0x8: watchdog_l2 Y 0x2000 0x02020000 + * 0xc: watchdog_l3 Y 0x3000 0x02020000 + * 0x10: i2c1 N 0x4000 0x01020000 + * 0x14: i2s0 Yh 0x5000 0x01030000 + * 0x18: always 0 N - + * 0x1c: i2s1 Yh 0x6000 0x01030000 + * 0x20: always 0 N - + * 0x24: qspi N 0x7000 0x01040000 + * 0x28: uart1 N 0x8000 0x01060000 + * 0x2c: i2c2 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 Y 0x12000 0x01040000 + * + * Registers 0x58, 0x5c, 0x60, 0x64, 0x68 seem to contain more controls fo= r i2s and tdm. + */ + +static const char * const timer_lsp_sel[] =3D { + "lsp_osc32k", + "lsp_osc26m", +}; + +static const char * const uart_lsp_sel[] =3D { + "lsp_osc26m", + "lsp_mpll_d6", +}; + +static const char * const i2s_lsp_sel[] =3D { + "lsp_osc26m", + "lsp_dpll_d4", + "lsp_mpll_d6", + /* Unknown */ +}; + +static const char * const tdm_lsp_sel[] =3D { + "lsp_tdm_wclk", +}; + +static const char * const spi_lsp_sel[] =3D { + "lsp_osc26m", + "lsp_mpll_d4", + "lsp_mpll_d6", + /* Unknown */ +}; + +static const char * const qspi_lsp_sel[] =3D { + "lsp_osc26m", + "lsp_mpll_d4", + "lsp_mpll_d5", + "lsp_mpll_d6", + "lsp_mpll_d8", + "lsp_mpll_d12", + "lsp_osc26m", + "lsp_osc26m", +}; + +#define LSP_CLOCK(offset, name, mux, div_shift, div_size) {\ + ZX297520V3_##name##_RESET, ZX297520V3_##name##_WCLK, ZX297520V3_##name##= _PCLK,\ + #name, offset, 8, offset, 0, 1, "lsp_pclk", offset, 4, 4, mux, ARRAY_SIZ= E(mux),\ + offset, div_shift, div_size, 0} + +static const struct zx297520v3_composite lsp_clocks[] =3D { + LSP_CLOCK(0x4, TIMER_L1, timer_lsp_sel, 0, 0), + LSP_CLOCK(0x8, WDT_L2, timer_lsp_sel, 0, 0), + LSP_CLOCK(0xc, WDT_L3, timer_lsp_sel, 0, 0), + LSP_CLOCK(0x10, I2C1, uart_lsp_sel, 0, 0), + LSP_CLOCK(0x14, I2S0, i2s_lsp_sel, 16, 4), + LSP_CLOCK(0x1c, I2S1, i2s_lsp_sel, 16, 4), + LSP_CLOCK(0x24, QSPI, qspi_lsp_sel, 0, 0), + LSP_CLOCK(0x28, UART1, uart_lsp_sel, 0, 0), + LSP_CLOCK(0x2C, I2C2, uart_lsp_sel, 0, 0), + LSP_CLOCK(0x30, SPI0, spi_lsp_sel, 12, 4), + LSP_CLOCK(0x34, TIMER_LB, timer_lsp_sel, 12, 4), + LSP_CLOCK(0x38, TIMER_LC, timer_lsp_sel, 12, 4), + LSP_CLOCK(0x3c, UART2, uart_lsp_sel, 0, 0), + LSP_CLOCK(0x40, WDT_LE, timer_lsp_sel, 12, 4), + LSP_CLOCK(0x44, TIMER_LF, timer_lsp_sel, 12, 4), + LSP_CLOCK(0x48, SPI1, spi_lsp_sel, 12, 4), + LSP_CLOCK(0x4c, TIMER_L11, timer_lsp_sel, 12, 4), + LSP_CLOCK(0x50, TDM, tdm_lsp_sel, 16, 4), +}; + +#undef LSP_CLOCK + +static int zx297520_lspclk_probe(struct platform_device *pdev) +{ + static const char * const parent_names[] =3D { "mpll_d5", "mpll_d4", "mpl= l_d6", "mpll_d8", + "mpll_d12", "osc26m", "osc32k", "pclk", + "tdm_wclk", "dpll_d4", + }; + + struct zx29_clk_controller *lsp; + struct device *dev =3D &pdev->dev; + void __iomem *base; + struct clk *parent; + unsigned int i; + int res; + + lsp =3D devm_kzalloc(dev, offsetof(struct zx29_clk_controller, + resets[ZX297520V3_LSPRST_END]), GFP_KERNEL); + if (!lsp) + return -ENOMEM; + + lsp->clocks =3D devm_kzalloc(dev, struct_size(lsp->clocks, hws, + ZX297520V3_LSPCLK_END), GFP_KERNEL); + if (!lsp->clocks) + return -ENOMEM; + lsp->clocks->num =3D ZX297520V3_LSPCLK_END; + + base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* TODO: Technically we can disable the pclk if all LSP devices are shut = down, but that + * needs custom clk ops to tiptoe around a disabled LSP pclk before attem= pting to access + * the actual clock. In normal operation it is unlikely that all LSP devi= ces are shut down + * simultaneously though as UART and NAND are located here. + */ + parent =3D devm_clk_get_enabled(dev, "pclk"); + if (IS_ERR(parent)) { + dev_err(dev, "failed to find lsp pclk\n"); + return PTR_ERR(parent); + } + + for (i =3D 0; i < ARRAY_SIZE(parent_names); ++i) { + parent =3D devm_clk_get(dev, parent_names[i]); + if (IS_ERR(parent)) { + dev_err(dev, "failed to find lsp %s clock\n", parent_names[i]); + return PTR_ERR(parent); + } + } + + res =3D zx297520v3_composite(dev, base, lsp->clocks, lsp->resets, + lsp_clocks, ARRAY_SIZE(lsp_clocks)); + if (res) + return res; + + /* This is to catch holes in the tables rather than registration errors */ + for (i =3D 0; i < ZX297520V3_LSPCLK_END; i++) { + if (!lsp->clocks->hws[i]) { + dev_err(dev, "Clock %u not registered\n", i); + return -ENODEV; + } + } + + res =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, lsp->cloc= ks); + if (res) + return res; + + for (i =3D 0; i < ZX297520V3_LSPRST_END; ++i) { + if (!(lsp->resets[i].reg && lsp->resets[i].mask)) { + dev_err(dev, "Reset %u has no register or mask\n", i); + return -ENODEV; + } + } + + lsp->rcdev.owner =3D THIS_MODULE; + lsp->rcdev.nr_resets =3D ZX297520V3_LSPRST_END; + lsp->rcdev.ops =3D &zx297520v3_rst_ops; + lsp->rcdev.of_node =3D dev->of_node; + return devm_reset_controller_register(dev, &lsp->rcdev); +} + static const struct of_device_id of_match_zx297520v3_topclk[] =3D { { .compatible =3D "zte,zx297520v3-topclk"}, { } @@ -768,7 +953,50 @@ static struct platform_driver clk_zx297520v3_topclk = =3D { .of_match_table =3D of_match_zx297520v3_topclk, }, }; -module_platform_driver(clk_zx297520v3_topclk); + +static const struct of_device_id of_match_zx297520v3_lspclk[] =3D { + { .compatible =3D "zte,zx297520v3-lspclk"}, + { } +}; +MODULE_DEVICE_TABLE(of, of_match_zx297520v3_lspclk); + +static struct platform_driver clk_zx297520v3_lspclk =3D { + .probe =3D zx297520_lspclk_probe, + .driver =3D { + .name =3D "clk-zx297520v3-lspclk", + .of_match_table =3D of_match_zx297520v3_lspclk, + }, +}; + +static int __init zx297520v3_clk_module_init(void) +{ + int res; + + res =3D platform_driver_register(&clk_zx297520v3_topclk); + if (res) { + pr_err("Failed to register driver %s: %d\n", + clk_zx297520v3_topclk.driver.name, res); + return res; + } + res =3D platform_driver_register(&clk_zx297520v3_lspclk); + if (res) { + pr_err("Failed to register driver %s: %d\n", + clk_zx297520v3_lspclk.driver.name, res); + platform_driver_unregister(&clk_zx297520v3_topclk); + return res; + } + + return 0; +} + +static void __exit zx297520v3_clk_module_exit(void) +{ + platform_driver_unregister(&clk_zx297520v3_lspclk); + platform_driver_unregister(&clk_zx297520v3_topclk); +} + +module_init(zx297520v3_clk_module_init); +module_exit(zx297520v3_clk_module_exit); =20 MODULE_AUTHOR("Stefan D=C3=B6singer "); MODULE_DESCRIPTION("ZTE zx297520v3 clock driver"); --=20 2.53.0 From nobody Mon Jun 8 14:35:53 2026 Received: from mail-wm1-f42.google.com (mail-wm1-f42.google.com [209.85.128.42]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CADCB364E93 for ; Thu, 28 May 2026 21:55:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.42 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005319; cv=none; b=WnOYmTobYQvSC1TZ4592TTcT4fRlfXhs2Y19tlDLYbJBAotp0+NtVB//bnwJ65NbKDmZkANqvelVtVzLXGqDgqxkQ2Nnyk3m7zLmm4QmT34VoG00P9mg+rfugFv+2JZ1d++VVhsJI5mhHxI0op1kfuxdO4Q9Kvd3AXooAPI7Psg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780005319; c=relaxed/simple; bh=eKCYysFcPuaXaoisFpLloAByZzjH3S4RlmU0j/f/7Ww=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=AOWloYvi3/EYdrmOKgsvalhzSLqHLzStpmf6tvDLJSWQtGS68DTZSuEFIwCPGjLVD7pu3FN7PwTV8R7xjkNs9ZWKsUsR3QeWPJvg/eSfp3OCP39oi9XK1gThl5GlTyxnonBBdCQKGHtIs/F+8qvhM830K+CuziOU8T/PpWM7EHg= 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=AbXng5le; arc=none smtp.client-ip=209.85.128.42 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AbXng5le" Received: by mail-wm1-f42.google.com with SMTP id 5b1f17b1804b1-4891c0620bcso85485105e9.1 for ; Thu, 28 May 2026 14:55:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1780005316; x=1780610116; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=CNQvp/eWwkD2QZuuf9D2poX/9RA0ShD7oqYYx3ps+FU=; b=AbXng5ler+qLJM94n06xjUho1Ac7izmgSauyXnUrlfu7guWRbjXBtEGhhpc33nOhOZ YpCxCBRh67P3XV13HXB2ClaRNUxRGQv6RWf8/wpqiLV8dw10X4PzSVHGVw+sBe12G1s+ NxsK5+c0bmvcQsQGuJkxw16DCGeZJyUFpBSDqR0GkF46NP1vDE++9RPTz6GIJ3ZpjJCg 25sL+NluK9LQnmnw/TyL81Rk/5sJu5+3jp/TlFrUgRcncCCXZzCsNQ4R3vOlIPwClcd2 zLbPGyO3dTMBx4/IBlwkCN1O2i0M9nWhElg7OqO+9MwxRq8X1txfs2pGezghc23+MzxA 4Ypg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780005316; x=1780610116; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=CNQvp/eWwkD2QZuuf9D2poX/9RA0ShD7oqYYx3ps+FU=; b=ZcYb9unC/FrToLNwBJ4Xe4AuYw8V/K2TLzetnGxsOr9qvmh1lbQ6TnVvGBYudVFISs sYH/6vSBuh8O6CWOoAMi3WItK4RdOEhWf+sKqlOq7lM8tsYmTsqo6Hd/xFR0LaIXHKSL nGEh4+t0EBiCelyueiyfTlqrKA5F87CejtYaiIkqIFZtutAQPLVJOsCvpgqAC69rs4K+ mm0r6LWLgVJTs3c8YZmcSo0T94L+mZBW7jikshZIgo0+S0iz03nAuhLwbuxIvVmtc+jU nibnbAiJPvOz7Bg8vjbo7qLdtTPoShpixfuAYedhxa7lXor27YlSrLVtU8xzd0u1Hbmg 3TnQ== X-Forwarded-Encrypted: i=1; AFNElJ+0YpHqDOdRUL6uU90wVht8sycBlk9O3np4xwiM+3zutVEDNVyC5FuNx/TqYDUOixFSzHf5JwQ3jHOnXnM=@vger.kernel.org X-Gm-Message-State: AOJu0YxtOBrLkUGfgKy4Ek8G61xd+IZ++G+hoETjjKS1cM3XsRIgQJEu Gwa4EZ6PsEK0cXe4F/T3ehNSEyvwTJcYzhXzEBiGdcc3+/MO+n7wGlPU X-Gm-Gg: Acq92OEKV5DrH/cfbN690toeMP233H8mWVFcNg78mrcIz8WYCvfBNseJqwSGySCRM6U FV+xFB4jx14+MlFresrrMOzZLgG8LtkNq5riazRS0W/dv9+4heFfaK6/2LyWEcj57nyhDZKRsL5 VC6Y5bmwj4KUOtCCK/PK10sbp+vHZZ7VIjIyisburfV/7h55r5jl2Ee0TVODAASflQe4WwJ+ePC lEjN00/zRZzxmFW+zy5ZjH5hFllIHcpEW9EpmglgL23IBeRPaoIFbF6jLQUhzL0d618PEvJn+ja yL/WBMBBQW/wWoXrIcMz2m34h32+G1V7IidoU1p2OubAFEfsfBxdXTqhLThlw2RhXlkiKBLKZhI KkikxLBOL4SJ+HOhPVi4NWvEl2VdzFQzbIo5wrU+lAqKcYFNtibKzgMxnftKcC4PIpkB+9lszA7 huk9SD1iIHftnAFgAOUm+nF5I5V5levmYL4sX2h99ogcAi X-Received: by 2002:a05:600c:2113:b0:490:845e:3a6 with SMTP id 5b1f17b1804b1-4909c0b706amr2630715e9.25.1780005316082; Thu, 28 May 2026 14:55:16 -0700 (PDT) Received: from [192.168.0.2] ([197.250.51.223]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4909c967c6csm1191085e9.2.2026.05.28.14.55.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 28 May 2026 14:55:15 -0700 (PDT) From: =?utf-8?q?Stefan_D=C3=B6singer?= Date: Fri, 29 May 2026 00:53:02 +0300 Subject: [PATCH RFC v3 5/5] ARM: dts: zte: Declare a zx297520v3 clock 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: <20260529-zx29clk-v3-5-c7fe54ea388f@gmail.com> References: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> In-Reply-To: <20260529-zx29clk-v3-0-c7fe54ea388f@gmail.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Philipp Zabel , Brian Masney Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, =?utf-8?q?Stefan_D=C3=B6singer?= X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=openpgp-sha256; l=3665; i=stefandoesinger@gmail.com; h=from:subject:message-id; bh=eKCYysFcPuaXaoisFpLloAByZzjH3S4RlmU0j/f/7Ww=; b=owEBiQJ2/ZANAwAIAT0TvMhUTxoiAcsmYgBqGLmonB1gQW4rZ70oU0qgrlZbtOo5IBUL5cz8K uiR7j+xheuJAk8EAAEIADkWIQRDFvS2qgVbJ5UyXWw9E7zIVE8aIgUCahi5qBsUgAAAAAAEAA5t YW51MiwyLjUrMS4xMiwyLDIACgkQPRO8yFRPGiJ44Q/8CIR9L5lArAiX4KXK9TNo8gozsOA+QtY xAaPTNtdFAYbufZxCearH5SOwIkECPWNXkoOHUgsqUkovgW9ytiFBM69T8PQHAbwEMq7tVnYFt3 aE8SIFT7ExX5DKfG6TXFphrQcBkMoE1u8uv2d01pjRgs61xruYaGHsyIfjTbXn+4LIYpkGbZZcC p7O9mFhIkdna1PVWHx089Iq6jxx/2FOzfG0BdXVeTSNWwNhPE35VbGcTXxAIoFUECuoJZti/X6F zpr6kW8MY/kQ+ei71gaXAu2qrAPkg/W0NvV7owyKZAMYwGTbcDEUyxjW1yEqZSU5cGh5lpXJWjp uHJlsPCQ9DRQrmK/FcNaXRhE2GEMn7vZyKrKv57N1UogMS4ujjEBixkth6UjbC58nX4QNxM16Yj u/ctOLfzxCs5yjjvLMaTquro6kYv/Knh29PqekhtBEHq02JtZVFWUEohnBrzazD7WshWfm9Ng2q t5ToJPcsNzljawo7O9fBuuwqMhYqDOGhy1GZ+Ldq/f7Ft+/R4hb6hTqRREizKKl8+HhgjJQKOuJ pfYymxTsmB4iiTbEn4DVHLIq9DXnAQuL7Pztxvrfiq/du+2hgn2JGjSTj3G9pCbakLYCmV+qVCD Qnt1VogpwWWBkC2wl4JZzSECG3uiiam134qXk8hCLGtPbIBK3P2c= X-Developer-Key: i=stefandoesinger@gmail.com; a=openpgp; fpr=4F9C2C8728019633893EBBB98CB81F9A72BBA155 This makes use of the driver added in the previous patches. It wires up the uart clocks and resets and allows getting rid of the placeholder uartclk node. Signed-off-by: Stefan D=C3=B6singer --- arch/arm/boot/dts/zte/zx297520v3.dtsi | 55 ++++++++++++++++++++++++++++++-= ---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/zte/zx297520v3.dtsi b/arch/arm/boot/dts/zte/= zx297520v3.dtsi index a16c30a164bb..9d80740ccf8a 100644 --- a/arch/arm/boot/dts/zte/zx297520v3.dtsi +++ b/arch/arm/boot/dts/zte/zx297520v3.dtsi @@ -4,6 +4,7 @@ */ =20 #include +#include =20 / { #address-cells =3D <1>; @@ -20,13 +21,16 @@ cpu@0 { }; }; =20 - /* Base bus clock and default for the UART. It will be replaced once a cl= ock driver has - * been added. - */ - uartclk: uartclk-26000000 { - #clock-cells =3D <0>; + osc26m: osc26m { compatible =3D "fixed-clock"; clock-frequency =3D <26000000>; + #clock-cells =3D <0>; + }; + + osc32k: osc32k { + compatible =3D "fixed-clock"; + clock-frequency =3D <32768>; + #clock-cells =3D <0>; }; =20 timer { @@ -70,13 +74,46 @@ gic: interrupt-controller@f2000000 { <0xf2040000 0x20000>; }; =20 + + topclk: clk@13b000 { + compatible =3D "zte,zx297520v3-topclk"; + reg =3D <0x0013b000 0x400>, + <0x01306000 0x400>; + reg-names =3D "top", "matrix"; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + clocks =3D <&osc26m>, <&osc32k>; + clock-names =3D "osc26m", "osc32k"; + }; + + lspclk: clk@1400000 { + compatible =3D "zte,zx297520v3-lspclk"; + reg =3D <0x01400000 0x100>; + #clock-cells =3D <1>; + #reset-cells =3D <1>; + + clocks =3D <&topclk ZX297520V3_LSP_MPLL_D5_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D4_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D6_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D8_WCLK>, + <&topclk ZX297520V3_LSP_MPLL_D12_WCLK>, + <&topclk ZX297520V3_LSP_OSC26M_WCLK>, + <&topclk ZX297520V3_LSP_OSC32K_WCLK>, + <&topclk ZX297520V3_LSP_PCLK>, + <&topclk ZX297520V3_LSP_TDM_WCLK>, + <&topclk 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"; + }; + uart0: serial@131000 { compatible =3D "arm,pl011", "arm,primecell"; arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x00131000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&topclk ZX297520V3_UART0_WCLK>, <&topclk ZX297520V3_UART0_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&topclk ZX297520V3_UART0_RESET>; status =3D "disabled"; }; =20 @@ -85,8 +122,9 @@ uart1: serial@1408000 { arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x01408000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&lspclk ZX297520V3_UART1_WCLK>, <&lspclk ZX297520V3_UART1_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspclk ZX297520V3_UART1_RESET>; status =3D "disabled"; }; =20 @@ -95,8 +133,9 @@ uart2: serial@140d000 { arm,primecell-periphid =3D <0x0018c011>; reg =3D <0x0140d000 0x1000>; interrupts =3D ; - clocks =3D <&uartclk>, <&uartclk>; + clocks =3D <&lspclk ZX297520V3_UART2_WCLK>, <&lspclk ZX297520V3_UART2_P= CLK>; clock-names =3D "uartclk", "apb_pclk"; + resets =3D <&lspclk ZX297520V3_UART2_RESET>; status =3D "disabled"; }; }; --=20 2.53.0