From nobody Sun Feb 8 05:20:18 2026 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C1C4D1BE25A; Fri, 28 Jun 2024 16:10:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591026; cv=none; b=Y29AiK+HoHxUCNO60X1/CFO4S3EC04Fve/pfiB101zgFkhG/kkHP52eLvigaebQ4/g9yXEhpu2rQjG4T2HDLAmwmIjRjzBH55//msCDJjVm8Gbm8Vy63zQBpRrP9T9uBSXmB7nkVxTy0pjxtLOzoU03rOV9VDyK4bpjN1XUZyMU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591026; c=relaxed/simple; bh=4TBs1HYdxNJuW0Zql1GbvVoJVx4d9v9lP7I/XqjzvQM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WnE8KSngmodjxkXyXCOV/IVmMM15YXqhk9vkc0S/H9FAhDiXeSX3sxpaaODJJ+FzHgVMhvJvtCY7Op1yb7Cjsk1oRl1OGDd7VTQMvzaZKm5SkoUADB3QgKt+1Zrbu5eD1NmjSvXoAmsmSIQx/KMkA8F8JiGbQyRRVFzpx5D4RQg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=XL/8yPZJ; arc=none smtp.client-ip=217.70.183.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="XL/8yPZJ" Received: by mail.gandi.net (Postfix) with ESMTPSA id A571120002; Fri, 28 Jun 2024 16:10:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1719591022; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w2PU9k3tCN4PaXJMVba3eK06E41fBInVkusLse/OBtI=; b=XL/8yPZJ0s6iobdJrrkTdwxxCU5QORdDC92xMq63bCwPmhNBLU4v6+hCTxU+0iAKPBy15e 9ey5L2SalsU0j5GGpY5GaRm9nn6hMoFGeEOuTeaSpLN8mm4vaB74+fyneKU45/jQ2fW1Oy kArBJZACDkxNmjJotMEifHsBR2izK9y5jXB/PAqRjW6dEop8dqShGDGhdc1BSkwHVyfBxm 7boJJdpVZFlq9uXtXjKs2DsD1Qx0OQh7E7MyQe8Cehcl7n4zvZqXOrwNQ9GodHhur+qHgh ctsiai4PjAopL3SaVUh9rxGA/Sb29YeyIra16gHW7kQJYXgrVUK0glQDbY5CFg== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 28 Jun 2024 18:10:07 +0200 Subject: [PATCH 1/4] Revert "dt-bindings: clock: mobileye,eyeq5-clk: add 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: <20240628-mbly-clk-v1-1-edb1e29ea4c1@bootlin.com> References: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> In-Reply-To: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , =?utf-8?q?Gr=C3=A9gory_Clement?= , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev-13183 X-GND-Sasl: theo.lebrun@bootlin.com Switch from one sub-node per functionality in the system-controller to a single node representing the entire OLB instance. This is the recommended approach for controllers handling many different functionalities; it is a single controller and should be represented by a single devicetree node. The clock bindings is removed and all properties will be described by: soc/mobileye/mobileye,eyeq5-olb.yaml Reviewed-by: Rob Herring (Arm) Signed-off-by: Th=C3=A9o Lebrun --- .../bindings/clock/mobileye,eyeq5-clk.yaml | 51 ------------------= ---- 1 file changed, 51 deletions(-) diff --git a/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yam= l b/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml deleted file mode 100644 index 2d4f2cde1e58..000000000000 --- a/Documentation/devicetree/bindings/clock/mobileye,eyeq5-clk.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) -%YAML 1.2 ---- -$id: http://devicetree.org/schemas/clock/mobileye,eyeq5-clk.yaml# -$schema: http://devicetree.org/meta-schemas/core.yaml# - -title: Mobileye EyeQ5 clock controller - -description: - The EyeQ5 clock controller handles 10 read-only PLLs derived from the ma= in - crystal clock. It also exposes one divider clock, a child of one of the = PLLs. - Its registers live in a shared region called OLB. - -maintainers: - - Gr=C3=A9gory Clement - - Th=C3=A9o Lebrun - - Vladimir Kondratiev - -properties: - compatible: - const: mobileye,eyeq5-clk - - reg: - maxItems: 2 - - reg-names: - items: - - const: plls - - const: ospi - - "#clock-cells": - const: 1 - - clocks: - maxItems: 1 - description: - Input parent clock to all PLLs. Expected to be the main crystal. - - clock-names: - items: - - const: ref - -required: - - compatible - - reg - - reg-names - - "#clock-cells" - - clocks - - clock-names - -additionalProperties: false --=20 2.45.2 From nobody Sun Feb 8 05:20:18 2026 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7F9E1C68AE; Fri, 28 Jun 2024 16:10:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591027; cv=none; b=FWXFMkvpFcRaQaCy1I6dr4sZGbpQ47AOc7pFcvMO8ozz/YrG02nUz0nZF7xF29YKIH9y1pxKdJ1NzINuoo30MlSnSXN7GxD//oNPzkGS2QrkMur6qVhOUjSCFDfZeH1Bu/IvYUSx7WLVpFTYsR87ObUtIcnwKskfExpIqgE314A= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591027; c=relaxed/simple; bh=9qSpRLCuKaFUBRxqlx83vNUsdIclaeD6SVNh5D8SI2c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=p3gqHvcRtHJqKQSM6A84VZGMbskwo5br2rnqo9Ji2UKZr/DGwR7S0lbc+yVuODVShCEMP1fz1gEQdf4Cr2B6sI6Bw4jE/H/jesYTJfTabY+mmQtB/Os2FGM0xXCXnrFZfio91alfuhGOmP3rUh0cDWy5DmDvMwZoORGRFPEg/5I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=nfUgNvO7; arc=none smtp.client-ip=217.70.183.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="nfUgNvO7" Received: by mail.gandi.net (Postfix) with ESMTPSA id 4884720004; Fri, 28 Jun 2024 16:10:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1719591022; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=H1b52fT1/2Kf4dSU9w6f3MSFKH/CzmEoTrYMNrGf0Tc=; b=nfUgNvO74o4rB2rKFhFtbWty3CkdRDypJRDu7F+bLZaQOReHGLtDbuj0+FD1+1MGLXxhvy 7O/yNeDsoUioVH4CgbomF2K/7ybJnQn5v7dflAuWXGps0SaG5fLFIMdAoAshdl7cgW0LSp shyQhfITy/+8AX1L621SHRRfT1Y8JZ/jWZm4iRegaDyCCG5P+lCbf1Yb00dmHgAO4PiRla VRX09ylBwsO+Lw9Jyn7KsVOZUpVwsksVY4B3QmMFSjmrcaytFz3C2J3rftEblgjNNnPeQf W+XLLT0TsNXJCpdIYdiBp/k9Sys1VABmue95vHyDo7oC3T2rLBanvhvVBI5q0w== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 28 Jun 2024 18:10:08 +0200 Subject: [PATCH 2/4] dt-bindings: clock: add Mobileye EyeQ6L/EyeQ6H clock indexes 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: <20240628-mbly-clk-v1-2-edb1e29ea4c1@bootlin.com> References: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> In-Reply-To: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , =?utf-8?q?Gr=C3=A9gory_Clement?= , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev-13183 X-GND-Sasl: theo.lebrun@bootlin.com Add #defines for Mobileye EyeQ6L and EyeQ6H SoC clocks. Constant prefixes are: - EQ6LC_PLL_: EyeQ6L clock PLLs - EQ6HC_SOUTH_PLL_: EyeQ6H south OLB PLLs - EQ6HC_SOUTH_DIV_: EyeQ6H south OLB divider clocks - EQ6HC_ACC_PLL_: EyeQ6H accelerator OLB PLLs Signed-off-by: Th=C3=A9o Lebrun Acked-by: Krzysztof Kozlowski --- include/dt-bindings/clock/mobileye,eyeq5-clk.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/dt-bindings/clock/mobileye,eyeq5-clk.h b/include/dt-bi= ndings/clock/mobileye,eyeq5-clk.h index 26d8930335e4..b433c1772c28 100644 --- a/include/dt-bindings/clock/mobileye,eyeq5-clk.h +++ b/include/dt-bindings/clock/mobileye,eyeq5-clk.h @@ -19,4 +19,25 @@ =20 #define EQ5C_DIV_OSPI 10 =20 +#define EQ6LC_PLL_DDR 0 +#define EQ6LC_PLL_CPU 1 +#define EQ6LC_PLL_PER 2 +#define EQ6LC_PLL_VDI 3 + +#define EQ6HC_SOUTH_PLL_VDI 0 +#define EQ6HC_SOUTH_PLL_PCIE 1 +#define EQ6HC_SOUTH_PLL_PER 2 +#define EQ6HC_SOUTH_PLL_ISP 3 + +#define EQ6HC_SOUTH_DIV_EMMC 4 +#define EQ6HC_SOUTH_DIV_OSPI_REF 5 +#define EQ6HC_SOUTH_DIV_OSPI_SYS 6 +#define EQ6HC_SOUTH_DIV_TSU 7 + +#define EQ6HC_ACC_PLL_XNN 0 +#define EQ6HC_ACC_PLL_VMP 1 +#define EQ6HC_ACC_PLL_PMA 2 +#define EQ6HC_ACC_PLL_MPC 3 +#define EQ6HC_ACC_PLL_NOC 4 + #endif --=20 2.45.2 From nobody Sun Feb 8 05:20:18 2026 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7F551C232D; Fri, 28 Jun 2024 16:10:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591027; cv=none; b=dFwClsfITtYU71kVqj6bgGZ6RBtBR3hsFlBrq+kDt8lKTCfbrI0i6MUe2m6C0FI9MnWtTrclXXDUXK9aSs8ONcylP+KW38F6sWIG721m2KYAW6VYFGA9HznLshx4prTBZteVfYyCmsERUKcMmaITVJdvqa17sNXm+hLzJtOTyB8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591027; c=relaxed/simple; bh=w2If79lWwbWbJEfpkvSvIjHGyXXDg5JyR1TcCbacBAo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=g6doN0mYreYuQbK3gp3SF4w9wQWnSNhJBEsbDfb0/VvgD+t244CT0Jne0vz4zHsOAy/JmSKdN+OfQNoOwDwXYgWdEdmPCIGu34B4AAwKfGOqWAiM1vNP7a3IPsz51VIgGb6ZxD9pAEBnJoy0zJx0xB1HdA8bG5RhELDR4Ci3wb4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=HrsOjvaa; arc=none smtp.client-ip=217.70.183.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="HrsOjvaa" Received: by mail.gandi.net (Postfix) with ESMTPSA id D5E7C2000C; Fri, 28 Jun 2024 16:10:22 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1719591023; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=a9tyEv6JiL2E2sj4V72RhLJVpp93RMHsSx3RfEM+Nf0=; b=HrsOjvaaV0TAzcgq4Jo1VpN9QI7Oqyp5tSr9yRjs3rUxEaf6kNULQ3c93KlPfhhhPQfXFT o/9qvrD24Dg9V2BZD71tjOaqUfyE4pEDYHNBFTeWPrSigmIC+ENpLWl8vDzcA/SJEGSKCH StDD1Dol6Kb7NipQEgh/A5kLv5t8d4AbYgBKiRC4Jx2yYZcMPmJXBd2Algi55Rs2K1GZOk hG+lieqZNQKVd6sIYTDdgDgvzaGD2oKSEWhxZSGK1l+wUdQXrTWU3q/1XoJZkwov3wiCfF Kbr8DZVgVkLbgvUyoSOxUOzmIEzJMAZ2RYZLh+9ff9Eu9QjwqK8aWiRCXsjlaA== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 28 Jun 2024 18:10:09 +0200 Subject: [PATCH 3/4] clk: divider: Introduce CLK_DIVIDER_EVEN_INTEGERS flag 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: <20240628-mbly-clk-v1-3-edb1e29ea4c1@bootlin.com> References: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> In-Reply-To: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , =?utf-8?q?Gr=C3=A9gory_Clement?= , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev-13183 X-GND-Sasl: theo.lebrun@bootlin.com Add CLK_DIVIDER_EVEN_INTEGERS flag to support divisor of 2, 4, 6, etc. The same divisor can be done using a table, which would be big and wasteful for a clock dividor of width 8 (256 entries). Require increasing flags size from u8 to u16 because CLK_DIVIDER_EVEN_INTEGERS is the eighth flag. Signed-off-by: Th=C3=A9o Lebrun --- drivers/clk/clk-divider.c | 12 +++++++++--- include/linux/clk-provider.h | 11 +++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index a2c2b5203b0a..b6654c5c36d2 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -72,6 +72,8 @@ static unsigned int _get_maxdiv(const struct clk_div_tabl= e *table, u8 width, return clk_div_mask(width); if (flags & CLK_DIVIDER_POWER_OF_TWO) return 1 << clk_div_mask(width); + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return 2 * (clk_div_mask(width) + 1); if (table) return _get_table_maxdiv(table, width); return clk_div_mask(width) + 1; @@ -97,6 +99,8 @@ static unsigned int _get_div(const struct clk_div_table *= table, return 1 << val; if (flags & CLK_DIVIDER_MAX_AT_ZERO) return val ? val : clk_div_mask(width) + 1; + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return 2 * (val + 1); if (table) return _get_table_div(table, val); return val + 1; @@ -122,6 +126,8 @@ static unsigned int _get_val(const struct clk_div_table= *table, return __ffs(div); if (flags & CLK_DIVIDER_MAX_AT_ZERO) return (div =3D=3D clk_div_mask(width) + 1) ? 0 : div; + if (flags & CLK_DIVIDER_EVEN_INTEGERS) + return (div >> 1) - 1; if (table) return _get_table_val(table, div); return div - 1; @@ -538,7 +544,7 @@ struct clk_hw *__clk_hw_register_divider(struct device = *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_divider *div; @@ -610,7 +616,7 @@ EXPORT_SYMBOL_GPL(__clk_hw_register_divider); struct clk *clk_register_divider_table(struct device *dev, const char *nam= e, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, + u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_hw *hw; @@ -664,7 +670,7 @@ struct clk_hw *__devm_clk_hw_register_divider(struct de= vice *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock) { struct clk_hw **ptr, *hw; diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index 4a537260f655..cb348e502e41 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h @@ -675,13 +675,15 @@ struct clk_div_table { * CLK_DIVIDER_BIG_ENDIAN - By default little endian register accesses are= used * for the divider register. Setting this flag makes the register accesses * big endian. + * CLK_DIVIDER_EVEN_INTEGERS - clock divisor is 2, 4, 6, 8, 10, etc. + * Formula is 2 * (value read from hardware + 1). */ struct clk_divider { struct clk_hw hw; void __iomem *reg; u8 shift; u8 width; - u8 flags; + u16 flags; const struct clk_div_table *table; spinlock_t *lock; }; @@ -697,6 +699,7 @@ struct clk_divider { #define CLK_DIVIDER_READ_ONLY BIT(5) #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) #define CLK_DIVIDER_BIG_ENDIAN BIT(7) +#define CLK_DIVIDER_EVEN_INTEGERS BIT(8) =20 extern const struct clk_ops clk_divider_ops; extern const struct clk_ops clk_divider_ro_ops; @@ -726,18 +729,18 @@ struct clk_hw *__clk_hw_register_divider(struct devic= e *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); struct clk_hw *__devm_clk_hw_register_divider(struct device *dev, struct device_node *np, const char *name, const char *parent_name, const struct clk_hw *parent_hw, const struct clk_parent_data *parent_data, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, u8 clk_divider_flags, + void __iomem *reg, u8 shift, u8 width, u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); struct clk *clk_register_divider_table(struct device *dev, const char *nam= e, const char *parent_name, unsigned long flags, void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, + u16 clk_divider_flags, const struct clk_div_table *table, spinlock_t *lock); /** * clk_register_divider - register a divider clock with the clock framework --=20 2.45.2 From nobody Sun Feb 8 05:20:18 2026 Received: from relay7-d.mail.gandi.net (relay7-d.mail.gandi.net [217.70.183.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 86FD41C8FC3; Fri, 28 Jun 2024 16:10:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.70.183.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591028; cv=none; b=GFe+G/dGia8yyCQ+08YAwaN20IbyrF0OnM2xM5gllt0Nq/NJMJ4Rr5k/lbwMmO9oWpyoVbRl/EYVugNfON0LMM7nng3TPOpTZekBPTl9sQZqp/kpaqYgwT3cWdRtSGwYXQjKohgg4sBi0u61a02dRlzp2981qdTUSNeH8n8iFYg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1719591028; c=relaxed/simple; bh=NqfcynzUbFJO2cM1WlX+cAJJJZl7QgbITll56gXlhak=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=f9a338eBMpDZGJzvB+yRWtdG9t93CDdWu4a3TGuwSyU82GGyaOL12hZpi/VPNarInVXb0ErJP3kTC4vXzvDRAUeRNdYKGuTCkV8nED8oQ7i0Btug7an+f/q5rbY4aWmePsSqfMAGDrpNBPCmqfKhPlxJScBVK4LKPBohGum6K3k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com; spf=pass smtp.mailfrom=bootlin.com; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b=pJSo3fZ0; arc=none smtp.client-ip=217.70.183.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=bootlin.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=bootlin.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=bootlin.com header.i=@bootlin.com header.b="pJSo3fZ0" Received: by mail.gandi.net (Postfix) with ESMTPSA id 6F06520008; Fri, 28 Jun 2024 16:10:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1719591024; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=fbETsccUw9p7L05QZE7/whiaFmmQ+zWYeuJevXPP5B8=; b=pJSo3fZ010I0b/l7IIkbxS/cOh2Hd8Avr7XbIgOk2XODfJljuh6FMUPmniiXp3fPShclRd im4L3JYFC0z661FjCKNymtMKpGCKhmMSA8JBH5R0SEiDNOZXpOGwQ3O8Hj0uOkA9S5G3DZ RFMcYh1pddlo15KP5eBuwM5kN0qZrUUE6P0eRPWbO+Apw/BhPxtpCaami76OMvqJwr+NNQ JUoEcMW5PFDRUpONt6bYn/DT3mmkgKdDTqtkZPg1GJweVm2wHpVusW4XLFyI3AQuhNIuNE Vqm1XtG0O0ZJH1br9vTZlOCC53IAAHy7XUpLaWUDUmIHCke1mnCSzZjvVM560w== From: =?utf-8?q?Th=C3=A9o_Lebrun?= Date: Fri, 28 Jun 2024 18:10:10 +0200 Subject: [PATCH 4/4] clk: eyeq: add driver Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240628-mbly-clk-v1-4-edb1e29ea4c1@bootlin.com> References: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> In-Reply-To: <20240628-mbly-clk-v1-0-edb1e29ea4c1@bootlin.com> To: Michael Turquette , Stephen Boyd , Rob Herring , Krzysztof Kozlowski , Conor Dooley Cc: linux-clk@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, Vladimir Kondratiev , =?utf-8?q?Gr=C3=A9gory_Clement?= , Thomas Petazzoni , Tawfik Bayouk , =?utf-8?q?Th=C3=A9o_Lebrun?= X-Mailer: b4 0.15-dev-13183 X-GND-Sasl: theo.lebrun@bootlin.com Add Mobileye EyeQ5, EyeQ6L and EyeQ6H clock controller driver. It is both a platform driver and a hook onto of_clk_init() used for clocks required early (GIC timer, UARTs). For some compatible, it is both at the same time. eqc_init() initialises early PLLs and stores clock array in a static linked list. It marks other clocks as deferred. eqc_probe() retrieves the clock array and adds all remaining clocks. It exposes read-only PLLs derived from the main crystal on board. It also exposes another type of clocks: divider clocks. They always have even divisors and have one PLL as parent. This driver also bears the responsability for optional reset and pinctrl auxiliary devices. The match data attached to the devicetree node compatible indicate if such devices should be created. They all get passed a pointer to the start of the OLB region. Signed-off-by: Th=C3=A9o Lebrun --- drivers/clk/Kconfig | 12 + drivers/clk/Makefile | 1 + drivers/clk/clk-eyeq.c | 789 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 3 files changed, 802 insertions(+) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 3e9099504fad..271d55acac0a 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -218,6 +218,18 @@ config COMMON_CLK_EN7523 This driver provides the fixed clocks and gates present on Airoha ARM silicon. =20 +config COMMON_CLK_EYEQ + bool "Clock driver for the Mobileye EyeQ platform" + depends on OF || COMPILE_TEST + depends on MACH_EYEQ5 || MACH_EYEQ6H || COMPILE_TEST + select AUXILIARY_BUS + default MACH_EYEQ5 || MACH_EYEQ6H + help + This driver provides clocks found on Mobileye EyeQ5, EyeQ6L and Eye6H + SoCs. Controllers live in shared register regions called OLB. Driver + provides read-only PLLs, derived from the main crystal clock (which + must be constant). It also exposes some divider clocks. + config COMMON_CLK_FSL_FLEXSPI tristate "Clock driver for FlexSPI on Layerscape SoCs" depends on ARCH_LAYERSCAPE || COMPILE_TEST diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 4abe16c8ccdf..40bc2e48e1ab 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_ARCH_CLPS711X) +=3D clk-clps711x.o obj-$(CONFIG_COMMON_CLK_CS2000_CP) +=3D clk-cs2000-cp.o obj-$(CONFIG_ARCH_SPARX5) +=3D clk-sparx5.o obj-$(CONFIG_COMMON_CLK_EN7523) +=3D clk-en7523.o +obj-$(CONFIG_COMMON_CLK_EYEQ) +=3D clk-eyeq.o obj-$(CONFIG_COMMON_CLK_FIXED_MMIO) +=3D clk-fixed-mmio.o obj-$(CONFIG_COMMON_CLK_FSL_FLEXSPI) +=3D clk-fsl-flexspi.o obj-$(CONFIG_COMMON_CLK_FSL_SAI) +=3D clk-fsl-sai.o diff --git a/drivers/clk/clk-eyeq.c b/drivers/clk/clk-eyeq.c new file mode 100644 index 000000000000..5b5b11a4edb2 --- /dev/null +++ b/drivers/clk/clk-eyeq.c @@ -0,0 +1,789 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PLL clock driver for the Mobileye EyeQ5, EyeQ6L and EyeQ6H platforms. + * + * This controller handles read-only PLLs, all derived from the same main + * crystal clock. It also exposes divider clocks, those are children to PL= Ls. + * Parent clock is expected to be constant. This driver's registers live in + * a shared region called OLB. Some PLLs are initialised early by of_clk_i= nit(). + * + * We use eqc_ as prefix, as-in "EyeQ Clock", but way shorter. + * + * Copyright (C) 2024 Mobileye Vision Technologies Ltd. + */ + +/* + * Set pr_fmt() for printing from eqc_init(). + * It is called at of_clk_init() stage (read: really early). + */ +#define pr_fmt(fmt) "clk-eyeq: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EQC_MAX_DIV_COUNT 4 + +/* In frac mode, it enables fractional noise canceling DAC. Else, no funct= ion. */ +#define PCSR0_DAC_EN BIT(0) +/* Fractional or integer mode */ +#define PCSR0_DSM_EN BIT(1) +#define PCSR0_PLL_EN BIT(2) +/* All clocks output held at 0 */ +#define PCSR0_FOUTPOSTDIV_EN BIT(3) +#define PCSR0_POST_DIV1 GENMASK(6, 4) +#define PCSR0_POST_DIV2 GENMASK(9, 7) +#define PCSR0_REF_DIV GENMASK(15, 10) +#define PCSR0_INTIN GENMASK(27, 16) +#define PCSR0_BYPASS BIT(28) +/* Bits 30..29 are reserved */ +#define PCSR0_PLL_LOCKED BIT(31) + +#define PCSR1_RESET BIT(0) +#define PCSR1_SSGC_DIV GENMASK(4, 1) +/* Spread amplitude (% =3D 0.1 * SPREAD[4:0]) */ +#define PCSR1_SPREAD GENMASK(9, 5) +#define PCSR1_DIS_SSCG BIT(10) +/* Down-spread or center-spread */ +#define PCSR1_DOWN_SPREAD BIT(11) +#define PCSR1_FRAC_IN GENMASK(31, 12) + +/* + * Driver might register clock provider from eqc_init() if PLLs are requir= ed + * early (before platform bus is ready). Store struct eqc_priv inside link= ed + * list to pass clock provider from eqc_init() to eqc_probe() and register + * remaining clocks from platform device probe. + * + * Clock provider is NOT created by eqc_init() if no early clock is requir= ed. + * Store as linked list because EyeQ6H has multiple clock controller insta= nces. + * Matching is done based on devicetree node pointer. + */ +static DEFINE_SPINLOCK(eqc_list_slock); +static LIST_HEAD(eqc_list); + +struct eqc_pll { + unsigned int index; + const char *name; + unsigned int reg64; +}; + +/* + * Divider clock. Divider is 2*(v+1), with v the register value. + * Min divider is 2, max is 2*(2^width). + */ +struct eqc_div { + unsigned int index; + const char *name; + unsigned int parent; + unsigned int reg; + u8 shift; + u8 width; +}; + +struct eqc_match_data { + unsigned int pll_count; + const struct eqc_pll *plls; + + unsigned int div_count; + const struct eqc_div *divs; + + const char *reset_auxdev_name; + const char *pinctrl_auxdev_name; +}; + +struct eqc_early_match_data { + unsigned int early_pll_count; + const struct eqc_pll *early_plls; + /* Information required to init properly clk HW cells. */ + unsigned int nb_late_clks; +}; + +struct eqc_priv { + struct clk_hw_onecell_data *cells; + const struct eqc_early_match_data *early_data; + const struct eqc_match_data *data; + void __iomem *base; + struct device_node *np; + struct list_head list; +}; + +/* + * Both factors (mult and div) must fit in 32 bits. When an operation over= flows, + * this function throws away low bits so that factors still fit in 32 bits. + * + * Precision loss depends on amplitude of mult and div. Worst theorical + * loss is: (UINT_MAX+1) / UINT_MAX - 1 =3D 2.3e-10. + * This is 1Hz every 4.3GHz. + */ +static void eqc_pll_downshift_factors(unsigned long *mult, unsigned long *= div) +{ + unsigned long biggest; + unsigned int shift; + + /* This function can be removed if mult/div switch to unsigned long. */ + static_assert(sizeof_field(struct clk_fixed_factor, mult) =3D=3D sizeof(u= nsigned int)); + static_assert(sizeof_field(struct clk_fixed_factor, div) =3D=3D sizeof(un= signed int)); + + /* No overflow, nothing to be done. */ + if (*mult <=3D UINT_MAX && *div <=3D UINT_MAX) + return; + + /* + * Compute the shift required to bring the biggest factor into unsigned + * int range. That is, shift its highest set bit to the unsigned int + * most significant bit. + */ + biggest =3D max(*mult, *div); + shift =3D __fls(biggest) - (BITS_PER_BYTE * sizeof(unsigned int)) + 1; + + *mult >>=3D shift; + *div >>=3D shift; +} + +static int eqc_pll_parse_registers(u32 r0, u32 r1, unsigned long *mult, + unsigned long *div, unsigned long *acc) +{ + if (r0 & PCSR0_BYPASS) { + *mult =3D 1; + *div =3D 1; + *acc =3D 0; + return 0; + } + + if (!(r0 & PCSR0_PLL_LOCKED)) + return -EINVAL; + + *mult =3D FIELD_GET(PCSR0_INTIN, r0); + *div =3D FIELD_GET(PCSR0_REF_DIV, r0); + if (r0 & PCSR0_FOUTPOSTDIV_EN) + *div *=3D FIELD_GET(PCSR0_POST_DIV1, r0) * FIELD_GET(PCSR0_POST_DIV2, r0= ); + + /* Fractional mode, in 2^20 (0x100000) parts. */ + if (r0 & PCSR0_DSM_EN) { + *div *=3D 0x100000; + *mult =3D *mult * 0x100000 + FIELD_GET(PCSR1_FRAC_IN, r1); + } + + if (!*mult || !*div) + return -EINVAL; + + /* Spread spectrum. */ + if (!(r1 & (PCSR1_RESET | PCSR1_DIS_SSCG))) { + /* + * Spread is 1/1000 parts of frequency, accuracy is half of + * that. To get accuracy, convert to ppb (parts per billion). + */ + u32 spread =3D FIELD_GET(PCSR1_SPREAD, r1); + + *acc =3D spread * 500000; + if (r1 & PCSR1_DOWN_SPREAD) { + /* + * Downspreading: the central frequency is half a + * spread lower. + */ + *mult *=3D 2000 - spread; + *div *=3D 2000; + + /* + * Previous operation might overflow 32 bits. If it + * does, throw away the least amount of low bits. + */ + eqc_pll_downshift_factors(mult, div); + } + } else { + *acc =3D 0; + } + + return 0; +} + +static unsigned int eqc_compute_clock_count(const struct eqc_early_match_d= ata *early_data, + const struct eqc_match_data *data) +{ + unsigned int i, nb_clks =3D 0, sum =3D 0; + + if (early_data) { + sum +=3D early_data->early_pll_count; + + for (i =3D 0; i < early_data->early_pll_count; i++) + if (early_data->early_plls[i].index >=3D nb_clks) + nb_clks =3D early_data->early_plls[i].index + 1; + } + + if (data) { + sum +=3D data->pll_count + data->div_count; + + for (i =3D 0; i < data->pll_count; i++) + if (data->plls[i].index >=3D nb_clks) + nb_clks =3D data->plls[i].index + 1; + + for (i =3D 0; i < data->div_count; i++) + if (data->divs[i].index >=3D nb_clks) + nb_clks =3D data->divs[i].index + 1; + } + + /* We expect the biggest clock index to be 1 below the clock count. */ + WARN_ON(nb_clks !=3D sum); + + return nb_clks; +} + +static void eqc_probe_init_plls(struct device *dev, struct eqc_priv *priv) +{ + const struct eqc_match_data *data =3D priv->data; + unsigned long mult, div, acc; + const struct eqc_pll *pll; + struct clk_hw *hw; + unsigned int i; + u32 r0, r1; + u64 val; + int ret; + + for (i =3D 0; i < data->pll_count; i++) { + pll =3D &data->plls[i]; + + val =3D readq(priv->base + pll->reg64); + r0 =3D val; + r1 =3D val >> 32; + + ret =3D eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); + if (ret) { + dev_warn(dev, "failed parsing state of %s\n", pll->name); + priv->cells->hws[pll->index] =3D ERR_PTR(ret); + continue; + } + + hw =3D clk_hw_register_fixed_factor_with_accuracy_fwname(dev, + dev->of_node, pll->name, "ref", 0, mult, div, acc); + priv->cells->hws[pll->index] =3D hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", pll->name, hw); + } +} + +static void eqc_probe_init_divs(struct platform_device *pdev, struct devic= e *dev, + struct eqc_priv *priv) +{ + const struct eqc_match_data *data =3D priv->data; + const struct eqc_div *div; + struct clk_hw *parent; + void __iomem *reg; + struct clk_hw *hw; + unsigned int i; + + for (i =3D 0; i < data->div_count; i++) { + div =3D &data->divs[i]; + reg =3D priv->base + div->reg; + parent =3D priv->cells->hws[div->parent]; + + hw =3D clk_hw_register_divider_table_parent_hw(dev, div->name, + parent, 0, reg, div->shift, div->width, + CLK_DIVIDER_EVEN_INTEGERS, NULL, NULL); + priv->cells->hws[div->index] =3D hw; + if (IS_ERR(hw)) + dev_warn(dev, "failed registering %s: %pe\n", + div->name, hw); + } +} + +static void eqc_auxdev_release(struct device *dev) +{ + struct auxiliary_device *adev =3D to_auxiliary_dev(dev); + + kfree(adev); +} + +static void eqc_auxdev_unregister(void *arg) +{ + struct auxiliary_device *adev =3D arg; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +static int eqc_auxdev_create(struct device *dev, void __iomem *base, + const char *name, u32 id) +{ + struct auxiliary_device *adev; + int ret; + + adev =3D kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + adev->name =3D name; + adev->dev.parent =3D dev; + adev->dev.platform_data =3D base; + adev->dev.release =3D eqc_auxdev_release; + adev->id =3D id; + + ret =3D auxiliary_device_init(adev); + if (ret) + return ret; + + ret =3D auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(dev, eqc_auxdev_unregister, adev); +} + +static int eqc_probe(struct platform_device *pdev) +{ + const struct eqc_match_data *data; + struct device *dev =3D &pdev->dev; + struct eqc_priv *priv =3D NULL; + struct eqc_priv *entry; + unsigned int nb_clks; + void __iomem *base; + int ret; + + data =3D device_get_match_data(dev); + if (!data) + return 0; /* No clocks nor auxdevs, we are done. */ + + base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Init optional reset auxiliary device. */ + if (data->reset_auxdev_name) { + ret =3D eqc_auxdev_create(dev, base, data->reset_auxdev_name, 0); + if (ret) + dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n", + KBUILD_MODNAME, data->reset_auxdev_name, ret); + } + + /* Init optional pinctrl auxiliary device. */ + if (data->pinctrl_auxdev_name) { + ret =3D eqc_auxdev_create(dev, base, data->pinctrl_auxdev_name, 0); + if (ret) + dev_warn(dev, "failed creating auxiliary device %s.%s: %d\n", + KBUILD_MODNAME, data->pinctrl_auxdev_name, ret); + } + + if (data->pll_count + data->div_count =3D=3D 0) + return 0; /* Zero clocks, we are done. */ + + /* Try retrieving early init private data. */ + spin_lock(&eqc_list_slock); + list_for_each_entry(entry, &eqc_list, list) { + if (entry->np =3D=3D dev->of_node) { + priv =3D entry; + break; + } + } + spin_unlock(&eqc_list_slock); + + if (!priv) { + /* Device did not get init early. Do it now. */ + + priv =3D devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->np =3D dev->of_node; + + nb_clks =3D eqc_compute_clock_count(NULL, data); + priv->cells =3D devm_kzalloc(dev, struct_size(priv->cells, hws, nb_clks), + GFP_KERNEL); + if (!priv->cells) + return -ENOMEM; + + priv->cells->num =3D nb_clks; + } else { + /* + * Device got init early. Check clock count. + * + * eqc_init() should already know the exact clk count using + * nb_late_clks field. We ensure computation was right and fix + * clk cells if not. + */ + nb_clks =3D eqc_compute_clock_count(priv->early_data, data); + if (WARN_ON(nb_clks !=3D priv->cells->num)) + priv->cells->num =3D nb_clks; + } + + priv->base =3D base; + priv->data =3D data; + + eqc_probe_init_plls(dev, priv); + + eqc_probe_init_divs(pdev, dev, priv); + + /* Clock provider has not been registered by eqc_init(). Do it now. */ + if (!priv->early_data) { + /* When providing a single clock, require no cell. */ + if (priv->cells->num =3D=3D 1) + ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, + priv->cells->hws[0]); + else + ret =3D devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, + priv->cells); + + if (ret) + return ret; + } + + return 0; +} + +static const struct eqc_pll eqc_eyeq5_plls[] =3D { + { .index =3D EQ5C_PLL_VMP, .name =3D "pll-vmp", .reg64 =3D 0x034 }, + { .index =3D EQ5C_PLL_PMA, .name =3D "pll-pma", .reg64 =3D 0x03C }, + { .index =3D EQ5C_PLL_VDI, .name =3D "pll-vdi", .reg64 =3D 0x044 }, + { .index =3D EQ5C_PLL_DDR0, .name =3D "pll-ddr0", .reg64 =3D 0x04C }, + { .index =3D EQ5C_PLL_PCI, .name =3D "pll-pci", .reg64 =3D 0x054 }, + { .index =3D EQ5C_PLL_PMAC, .name =3D "pll-pmac", .reg64 =3D 0x064 }, + { .index =3D EQ5C_PLL_MPC, .name =3D "pll-mpc", .reg64 =3D 0x06C }, + { .index =3D EQ5C_PLL_DDR1, .name =3D "pll-ddr1", .reg64 =3D 0x074 }, +}; + +static const struct eqc_div eqc_eyeq5_divs[] =3D { + { + .index =3D EQ5C_DIV_OSPI, + .name =3D "div-ospi", + .parent =3D EQ5C_PLL_PER, + .reg =3D 0x11C, + .shift =3D 0, + .width =3D 4, + }, +}; + +static const struct eqc_match_data eqc_eyeq5_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq5_plls), + .plls =3D eqc_eyeq5_plls, + + .div_count =3D ARRAY_SIZE(eqc_eyeq5_divs), + .divs =3D eqc_eyeq5_divs, + + .reset_auxdev_name =3D "reset", + .pinctrl_auxdev_name =3D "pinctrl", +}; + +static const struct eqc_pll eqc_eyeq6l_plls[] =3D { + { .index =3D EQ6LC_PLL_DDR, .name =3D "pll-ddr", .reg64 =3D 0x02C }, + { .index =3D EQ6LC_PLL_CPU, .name =3D "pll-cpu", .reg64 =3D 0x034 }, /* a= lso acc */ + { .index =3D EQ6LC_PLL_PER, .name =3D "pll-per", .reg64 =3D 0x03C }, + { .index =3D EQ6LC_PLL_VDI, .name =3D "pll-vdi", .reg64 =3D 0x044 }, +}; + +static const struct eqc_match_data eqc_eyeq6l_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6l_plls), + .plls =3D eqc_eyeq6l_plls, + + .reset_auxdev_name =3D "reset", +}; + +static const struct eqc_match_data eqc_eyeq6h_west_match_data =3D { + .reset_auxdev_name =3D "reset_west", +}; + +static const struct eqc_pll eqc_eyeq6h_east_plls[] =3D { + { .index =3D 0, .name =3D "pll-east", .reg64 =3D 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_east_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6h_east_plls), + .plls =3D eqc_eyeq6h_east_plls, + + .reset_auxdev_name =3D "reset_east", +}; + +static const struct eqc_pll eqc_eyeq6h_south_plls[] =3D { + { .index =3D EQ6HC_SOUTH_PLL_VDI, .name =3D "pll-vdi", .reg64 =3D 0x000= }, + { .index =3D EQ6HC_SOUTH_PLL_PCIE, .name =3D "pll-pcie", .reg64 =3D 0x008= }, + { .index =3D EQ6HC_SOUTH_PLL_PER, .name =3D "pll-per", .reg64 =3D 0x010= }, + { .index =3D EQ6HC_SOUTH_PLL_ISP, .name =3D "pll-isp", .reg64 =3D 0x018= }, +}; + +static const struct eqc_div eqc_eyeq6h_south_divs[] =3D { + { + .index =3D EQ6HC_SOUTH_DIV_EMMC, + .name =3D "div-emmc", + .parent =3D EQ6HC_SOUTH_PLL_PER, + .reg =3D 0x070, + .shift =3D 4, + .width =3D 4, + }, + { + .index =3D EQ6HC_SOUTH_DIV_OSPI_REF, + .name =3D "div-ospi-ref", + .parent =3D EQ6HC_SOUTH_PLL_PER, + .reg =3D 0x090, + .shift =3D 4, + .width =3D 4, + }, + { + .index =3D EQ6HC_SOUTH_DIV_OSPI_SYS, + .name =3D "div-ospi-sys", + .parent =3D EQ6HC_SOUTH_PLL_PER, + .reg =3D 0x090, + .shift =3D 8, + .width =3D 1, + }, + { + .index =3D EQ6HC_SOUTH_DIV_TSU, + .name =3D "div-tsu", + .parent =3D EQ6HC_SOUTH_PLL_PCIE, + .reg =3D 0x098, + .shift =3D 4, + .width =3D 8, + }, +}; + +static const struct eqc_match_data eqc_eyeq6h_south_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6h_south_plls), + .plls =3D eqc_eyeq6h_south_plls, + + .div_count =3D ARRAY_SIZE(eqc_eyeq6h_south_divs), + .divs =3D eqc_eyeq6h_south_divs, +}; + +static const struct eqc_pll eqc_eyeq6h_ddr0_plls[] =3D { + { .index =3D 0, .name =3D "pll-ddr0", .reg64 =3D 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_ddr0_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6h_ddr0_plls), + .plls =3D eqc_eyeq6h_ddr0_plls, +}; + +static const struct eqc_pll eqc_eyeq6h_ddr1_plls[] =3D { + { .index =3D 0, .name =3D "pll-ddr1", .reg64 =3D 0x074 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_ddr1_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6h_ddr1_plls), + .plls =3D eqc_eyeq6h_ddr1_plls, +}; + +static const struct eqc_pll eqc_eyeq6h_acc_plls[] =3D { + { .index =3D EQ6HC_ACC_PLL_XNN, .name =3D "pll-xnn", .reg64 =3D 0x040 }, + { .index =3D EQ6HC_ACC_PLL_VMP, .name =3D "pll-vmp", .reg64 =3D 0x050 }, + { .index =3D EQ6HC_ACC_PLL_PMA, .name =3D "pll-pma", .reg64 =3D 0x05C }, + { .index =3D EQ6HC_ACC_PLL_MPC, .name =3D "pll-mpc", .reg64 =3D 0x068 }, + { .index =3D EQ6HC_ACC_PLL_NOC, .name =3D "pll-noc", .reg64 =3D 0x070 }, +}; + +static const struct eqc_match_data eqc_eyeq6h_acc_match_data =3D { + .pll_count =3D ARRAY_SIZE(eqc_eyeq6h_acc_plls), + .plls =3D eqc_eyeq6h_acc_plls, + + .reset_auxdev_name =3D "reset_acc", +}; + +static const struct of_device_id eqc_match_table[] =3D { + { .compatible =3D "mobileye,eyeq5-olb", .data =3D &eqc_eyeq5_match_data }, + { .compatible =3D "mobileye,eyeq6l-olb", .data =3D &eqc_eyeq6l_match_data= }, + { .compatible =3D "mobileye,eyeq6h-west-olb", .data =3D &eqc_eyeq6h_west_= match_data }, + { .compatible =3D "mobileye,eyeq6h-east-olb", .data =3D &eqc_eyeq6h_east_= match_data }, + { .compatible =3D "mobileye,eyeq6h-south-olb", .data =3D &eqc_eyeq6h_sout= h_match_data }, + { .compatible =3D "mobileye,eyeq6h-ddr0-olb", .data =3D &eqc_eyeq6h_ddr0_= match_data }, + { .compatible =3D "mobileye,eyeq6h-ddr1-olb", .data =3D &eqc_eyeq6h_ddr1_= match_data }, + { .compatible =3D "mobileye,eyeq6h-acc-olb", .data =3D &eqc_eyeq6h_acc_ma= tch_data }, + {} +}; +MODULE_DEVICE_TABLE(of, eqc_match_table); + +static struct platform_driver eqc_driver =3D { + .probe =3D eqc_probe, + .driver =3D { + .name =3D "clk-eyeq", + .of_match_table =3D eqc_match_table, + }, +}; +builtin_platform_driver(eqc_driver); + +/* Required early for GIC timer (pll-cpu) and UARTs (pll-per). */ +static const struct eqc_pll eqc_eyeq5_early_plls[] =3D { + { .index =3D EQ5C_PLL_CPU, .name =3D "pll-cpu", .reg64 =3D 0x02C }, + { .index =3D EQ5C_PLL_PER, .name =3D "pll-per", .reg64 =3D 0x05C }, +}; + +static const struct eqc_early_match_data eqc_eyeq5_early_match_data =3D { + .early_pll_count =3D ARRAY_SIZE(eqc_eyeq5_early_plls), + .early_plls =3D eqc_eyeq5_early_plls, + .nb_late_clks =3D eqc_eyeq5_match_data.pll_count + eqc_eyeq5_match_data.d= iv_count, +}; + +/* Required early for GIC timer. */ +static const struct eqc_pll eqc_eyeq6h_central_early_plls[] =3D { + { .index =3D 0, .name =3D "pll-cpu", .reg64 =3D 0x02C }, +}; + +static const struct eqc_early_match_data eqc_eyeq6h_central_early_match_da= ta =3D { + .early_pll_count =3D ARRAY_SIZE(eqc_eyeq6h_central_early_plls), + .early_plls =3D eqc_eyeq6h_central_early_plls, + .nb_late_clks =3D 0, +}; + +/* Required early for UART. */ +static const struct eqc_pll eqc_eyeq6h_west_early_plls[] =3D { + { .index =3D 0, .name =3D "pll-west", .reg64 =3D 0x074 }, +}; + +static const struct eqc_early_match_data eqc_eyeq6h_west_early_match_data = =3D { + .early_pll_count =3D ARRAY_SIZE(eqc_eyeq6h_west_early_plls), + .early_plls =3D eqc_eyeq6h_west_early_plls, + .nb_late_clks =3D 0, +}; + +static const struct of_device_id eqc_early_match_table[] =3D { + { + .compatible =3D "mobileye,eyeq5-olb", + .data =3D &eqc_eyeq5_early_match_data, + }, + { + .compatible =3D "mobileye,eyeq6h-central-olb", + .data =3D &eqc_eyeq6h_central_early_match_data, + }, + { + .compatible =3D "mobileye,eyeq6h-west-olb", + .data =3D &eqc_eyeq6h_west_early_match_data, + }, + {} +}; +MODULE_DEVICE_TABLE(of, eqc_early_match_table); + +static void __init eqc_init(struct device_node *np) +{ + const struct eqc_early_match_data *early_data; + unsigned int nb_clks =3D 0; + struct eqc_priv *priv; + void __iomem *base; + unsigned int i; + int ret; + + early_data =3D of_match_node(eqc_early_match_table, np)->data; + + /* No reason to early init this clock provider. Delay until probe. */ + if (!early_data || early_data->early_pll_count =3D=3D 0) + return; + + priv =3D kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret =3D -ENOMEM; + goto err; + } + + priv->np =3D np; + priv->early_data =3D early_data; + + nb_clks =3D early_data->early_pll_count + early_data->nb_late_clks; + priv->cells =3D kzalloc(struct_size(priv->cells, hws, nb_clks), GFP_KERNE= L); + if (!priv->cells) { + ret =3D -ENOMEM; + goto err; + } + + priv->cells->num =3D nb_clks; + + /* + * Mark all clocks as deferred; some are registered here, the rest at + * platform device probe. + */ + for (i =3D 0; i < nb_clks; i++) + priv->cells->hws[i] =3D ERR_PTR(-EPROBE_DEFER); + + /* Offsets (reg64) of early PLLs are relative to OLB block. */ + base =3D of_iomap(np, 0); + if (!base) { + ret =3D -ENODEV; + goto err; + } + + for (i =3D 0; i < early_data->early_pll_count; i++) { + const struct eqc_pll *pll =3D &early_data->early_plls[i]; + unsigned long mult, div, acc; + struct clk_hw *hw; + u32 r0, r1; + u64 val; + + val =3D readq(base + pll->reg64); + r0 =3D val; + r1 =3D val >> 32; + + ret =3D eqc_pll_parse_registers(r0, r1, &mult, &div, &acc); + if (ret) { + pr_err("failed parsing state of %s\n", pll->name); + goto err; + } + + hw =3D clk_hw_register_fixed_factor_with_accuracy_fwname(NULL, + np, pll->name, "ref", 0, mult, div, acc); + priv->cells->hws[pll->index] =3D hw; + if (IS_ERR(hw)) { + pr_err("failed registering %s: %pe\n", pll->name, hw); + ret =3D PTR_ERR(hw); + goto err; + } + } + + /* When providing a single clock, require no cell. */ + if (nb_clks =3D=3D 1) + ret =3D of_clk_add_hw_provider(np, of_clk_hw_simple_get, priv->cells->hw= s[0]); + else + ret =3D of_clk_add_hw_provider(np, of_clk_hw_onecell_get, priv->cells); + if (ret) { + pr_err("failed registering clk provider: %d\n", ret); + goto err; + } + + spin_lock(&eqc_list_slock); + list_add_tail(&priv->list, &eqc_list); + spin_unlock(&eqc_list_slock); + + return; + +err: + /* + * We are doomed. The system will not be able to boot. + * + * Let's still try to be good citizens by freeing resources and print + * a last error message that might help debugging. + */ + + if (priv && priv->cells) { + of_clk_del_provider(np); + + for (i =3D 0; i < early_data->early_pll_count; i++) { + const struct eqc_pll *pll =3D &early_data->early_plls[i]; + struct clk_hw *hw =3D priv->cells->hws[pll->index]; + + if (!IS_ERR_OR_NULL(hw)) + clk_hw_unregister_fixed_factor(hw); + } + + kfree(priv->cells); + } + + kfree(priv); + + pr_err("failed clk init: %d\n", ret); +} + +CLK_OF_DECLARE_DRIVER(eqc_eyeq5, "mobileye,eyeq5-olb", eqc_init); +CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_central, "mobileye,eyeq6h-central-olb", e= qc_init); +CLK_OF_DECLARE_DRIVER(eqc_eyeq6h_west, "mobileye,eyeq6h-west-olb", eqc_ini= t); --=20 2.45.2