lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <0947d9cc-86ba-46e0-92aa-04f4714e7a20@zohomail.com>
Date: Mon, 8 Sep 2025 22:13:15 +0800
From: Xukai Wang <kingxukai@...omail.com>
To: Yao Zi <ziyao@...root.org>, Michael Turquette <mturquette@...libre.com>,
 Stephen Boyd <sboyd@...nel.org>, Rob Herring <robh@...nel.org>,
 Krzysztof Kozlowski <krzk+dt@...nel.org>, Conor Dooley
 <conor+dt@...nel.org>, Paul Walmsley <paul.walmsley@...ive.com>,
 Palmer Dabbelt <palmer@...belt.com>, Albert Ou <aou@...s.berkeley.edu>,
 Conor Dooley <conor@...nel.org>
Cc: linux-clk@...r.kernel.org, devicetree@...r.kernel.org,
 linux-kernel@...r.kernel.org, linux-riscv@...ts.infradead.org,
 Samuel Holland <samuel.holland@...ive.com>,
 Troy Mitchell <TroyMitchell988@...il.com>
Subject: Re: [PATCH v8 2/3] clk: canaan: Add clock driver for Canaan K230


On 2025/9/7 11:13, Yao Zi wrote:
>> On Fri, Sep 05, 2025 at 11:10:23AM +0800, Xukai Wang wrote:
>> This patch provides basic support for the K230 clock, which covers
>> all clocks in K230 SoC.
>>
>> The clock tree of the K230 SoC consists of a 24MHZ external crystal
>> oscillator, PLLs and an external pulse input for timerX, and their
>> derived clocks.
>>
>> Co-developed-by: Troy Mitchell <TroyMitchell988@...il.com>
>> Signed-off-by: Troy Mitchell <TroyMitchell988@...il.com>
>> Signed-off-by: Xukai Wang <kingxukai@...omail.com>
>> ---
>>  drivers/clk/Kconfig    |    6 +
>>  drivers/clk/Makefile   |    1 +
>>  drivers/clk/clk-k230.c | 2456 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 2463 insertions(+)
>>
>> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
>> index 299bc678ed1b9fcd9110bb8c5937a1bd1ea60e23..b597912607a6cc8eabff459a890a1e7353ef9c1d 100644
>> --- a/drivers/clk/Kconfig
>> +++ b/drivers/clk/Kconfig
>> @@ -464,6 +464,12 @@ config COMMON_CLK_K210
>>  	help
>>  	  Support for the Canaan Kendryte K210 RISC-V SoC clocks.
>>  
>> +config COMMON_CLK_K230
>> +	bool "Clock driver for the Canaan Kendryte K230 SoC"
>> +	depends on ARCH_CANAAN || COMPILE_TEST
>> +	help
>> +	  Support for the Canaan Kendryte K230 RISC-V SoC clocks.
>> +
>>  config COMMON_CLK_SP7021
>>  	tristate "Clock driver for Sunplus SP7021 SoC"
>>  	depends on SOC_SP7021 || COMPILE_TEST
>> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
>> index fb8878a5d7d93da6bec487460cdf63f1f764a431..5df50b1e14c701ed38397bfb257db26e8dd278b8 100644
>> --- a/drivers/clk/Makefile
>> +++ b/drivers/clk/Makefile
>> @@ -51,6 +51,7 @@ obj-$(CONFIG_MACH_ASPEED_G6)		+= clk-ast2600.o
>>  obj-$(CONFIG_ARCH_HIGHBANK)		+= clk-highbank.o
>>  obj-$(CONFIG_CLK_HSDK)			+= clk-hsdk-pll.o
>>  obj-$(CONFIG_COMMON_CLK_K210)		+= clk-k210.o
>> +obj-$(CONFIG_COMMON_CLK_K230)		+= clk-k230.o
>>  obj-$(CONFIG_LMK04832)			+= clk-lmk04832.o
>>  obj-$(CONFIG_COMMON_CLK_LAN966X)	+= clk-lan966x.o
>>  obj-$(CONFIG_COMMON_CLK_LOCHNAGAR)	+= clk-lochnagar.o
>> diff --git a/drivers/clk/clk-k230.c b/drivers/clk/clk-k230.c
>> new file mode 100644
>> index 0000000000000000000000000000000000000000..2ba74c008b30ae3400acbd8c08550e8315dfe205
>> --- /dev/null
>> +++ b/drivers/clk/clk-k230.c
>> @@ -0,0 +1,2456 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Kendryte Canaan K230 Clock Drivers
>> + *
>> + * Author: Xukai Wang <kingxukai@...omail.com>
>> + * Author: Troy Mitchell <troymitchell988@...il.com>
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clkdev.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/iopoll.h>
>> +#include <linux/mod_devicetable.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/spinlock.h>
>> +
>> +#include <dt-bindings/clock/canaan,k230-clk.h>
>> +
>> +/* PLL control register bits. */
>> +#define K230_PLL_BYPASS_ENABLE			BIT(19)
>> +#define K230_PLL_GATE_ENABLE			BIT(2)
>> +#define K230_PLL_GATE_WRITE_ENABLE		BIT(18)
>> +#define K230_PLL_OD_SHIFT			24
>> +#define K230_PLL_OD_MASK			0xF
>> +#define K230_PLL_R_SHIFT			16
>> +#define K230_PLL_R_MASK				0x3F
>> +#define K230_PLL_F_SHIFT			0
>> +#define K230_PLL_F_MASK				0x1FFF
>> +#define K230_PLL_DIV_REG_OFFSET			0x00
>> +#define K230_PLL_BYPASS_REG_OFFSET		0x04
>> +#define K230_PLL_GATE_REG_OFFSET		0x08
>> +#define K230_PLL_LOCK_REG_OFFSET		0x0C
> Maybe FIELD_PREP() and FIELD_GET() would help for the PLL-related
> rountines, and you could get avoid of writing shifts and masks by hand.
OK, I've already replaced the manual shifts and masks with GENMASK() and
FIELD_GET().
>
> ...
>
>> +struct k230_clk_rate_self {
>> +	struct clk_hw	hw;
>> +	void __iomem	*reg;
>> +	bool		read_only;
> Isn't a read-only multiplier, divider or something capable of both a
> simple fixed-factor hardware?
You're right. None of the rate clocks are read-only, so this flag is
unnecessary and should be removed.
> If so please switch to the existing clock
> hardware, instead of introducing a field in description of rate clocks.
>
> It's worth noting that you've already had at least one fixed-ra te clock
> (shrm_sram_div2).

>
>> +	u32		write_enable_bit;
>> +	u32		mul_min;
>> +	u32		mul_max;
>> +	u32		mul_shift;
>> +	u32		mul_mask;
>> +	u32		div_min;
>> +	u32		div_max;
>> +	u32		div_shift;
>> +	u32		div_mask;
>> +	/* ensures mutual exclusion for concurrent register access. */
>> +	spinlock_t	*lock;
>> +};
> ...
>
>> +static int k230_clk_find_approximate_mul_div(u32 mul_min, u32 mul_max,
>> +					     u32 div_min, u32 div_max,
>> +					     unsigned long rate,
>> +					     unsigned long parent_rate,
>> +					     u32 *div, u32 *mul)
>> +{
>> +	long abs_min;
>> +	long abs_current;
>> +	long perfect_divide;
>> +
>> +	if (!rate || !parent_rate || !mul_min)
>> +		return -EINVAL;
>> +
>> +	perfect_divide = (long)((parent_rate * 1000) / rate);
>> +	abs_min = abs(perfect_divide -
>> +		     (long)(((long)div_max * 1000) / (long)mul_min));
>> +
>> +	*div = div_max;
>> +	*mul = mul_min;
>> +
>> +	for (u32 i = div_max - 1; i >= div_min; i--) {
>> +		for (u32 j = mul_min + 1; j <= mul_max; j++) {
>> +			abs_current = abs(perfect_divide -
>> +					 (long)(((long)i * 1000) / (long)j));
>> +
>> +			if (abs_min > abs_current) {
>> +				abs_min = abs_current;
>> +				*div = i;
>> +				*mul = j;
>> +			}
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
> This looks like a poor version of rational_best_approximation(). Could
> you please consider switching to it?
OK, I've switched k230_clk_find_approximate_mul_div() to use
rational_best_approximation().

Additionally, since rational_best_approximation() only supports setting
the maximum value for numerator and denominator, I added extra checks
after the call to ensure that the resulting values are not lower than
mul_min and div_min.
>
>> +static int k230_clk_set_rate_mul(struct clk_hw *hw, unsigned long rate,
>> +				 unsigned long parent_rate)
>> +{
>> +	struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
>> +	struct k230_clk_rate_self *rate_self = &clk->clk;
>> +	u32 div, mul, mul_reg;
>> +
>> +	if (rate > parent_rate)
>> +		return -EINVAL;
>> +
>> +	if (rate_self->read_only)
>> +		return 0;
>> +
>> +	if (k230_clk_find_approximate_mul(rate_self->mul_min, rate_self->mul_max,
>> +					  rate_self->div_min, rate_self->div_max,
>> +					  rate, parent_rate, &div, &mul))
>> +		return -EINVAL;
>> +
>> +	guard(spinlock)(rate_self->lock);
>> +
>> +	mul_reg = readl(rate_self->reg + clk->mul_reg_off);
>> +	mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
>> +	mul_reg |= BIT(rate_self->write_enable_bit);
>> +	writel(mul_reg, rate_self->reg + clk->mul_reg_off);
>> +
>> +	return 0;
>> +}
>> +
>> +static int k230_clk_set_rate_div(struct clk_hw *hw, unsigned long rate,
>> +				 unsigned long parent_rate)
>> +{
>> +	struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
>> +	struct k230_clk_rate_self *rate_self = &clk->clk;
>> +	u32 div, mul, div_reg;
>> +
>> +	if (rate > parent_rate)
>> +		return -EINVAL;
>> +
>> +	if (rate_self->read_only)
>> +		return 0;
>> +
>> +	if (k230_clk_find_approximate_div(rate_self->mul_min, rate_self->mul_max,
>> +					  rate_self->div_min, rate_self->div_max,
>> +					  rate, parent_rate, &div, &mul))
>> +		return -EINVAL;
>> +
>> +	guard(spinlock)(rate_self->lock);
>> +
>> +	div_reg = readl(rate_self->reg + clk->div_reg_off);
>> +	div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
>> +	div_reg |= BIT(rate_self->write_enable_bit);
>> +	writel(div_reg, rate_self->reg + clk->div_reg_off);
>> +
>> +	return 0;
>> +}
>> +
>> +static int k230_clk_set_rate_mul_div(struct clk_hw *hw, unsigned long rate,
>> +				     unsigned long parent_rate)
>> +{
>> +	struct k230_clk_rate *clk = hw_to_k230_clk_rate(hw);
>> +	struct k230_clk_rate_self *rate_self = &clk->clk;
>> +	u32 div, mul, div_reg, mul_reg;
>> +
>> +	if (rate > parent_rate)
>> +		return -EINVAL;
>> +
>> +	if (rate_self->read_only)
>> +		return 0;
>> +
>> +	if (k230_clk_find_approximate_mul_div(rate_self->mul_min, rate_self->mul_max,
>> +					      rate_self->div_min, rate_self->div_max,
>> +					      rate, parent_rate, &div, &mul))
>> +		return -EINVAL;
>> +
>> +	guard(spinlock)(rate_self->lock);
>> +
>> +	div_reg = readl(rate_self->reg + clk->div_reg_off);
>> +	div_reg |= ((div - 1) & rate_self->div_mask) << (rate_self->div_shift);
>> +	div_reg |= BIT(rate_self->write_enable_bit);
>> +	writel(div_reg, rate_self->reg + clk->div_reg_off);
>> +
>> +	mul_reg = readl(rate_self->reg + clk->mul_reg_off);
>> +	mul_reg |= ((mul - 1) & rate_self->mul_mask) << (rate_self->mul_shift);
>> +	mul_reg |= BIT(rate_self->write_enable_bit);
>> +	writel(mul_reg, rate_self->reg + clk->mul_reg_off);
>> +
>> +	return 0;
>> +}
> There are three variants of rate clocks, mul-only, div-only and mul-div
> ones, which are similar to clk-multiplier, clk-divider,
> clk-fractional-divider.
>
> The only difference is to setup new parameters for K230's rate clocks,
> a register bit, described as k230_clk_rate_self.write_enable_bit, must
> be set first.
Actually, I think the differences are not limited to just the
write_enable_bit. There are also distinct mul_min, mul_max, div_min, and
div_max values, which are not typically just 1 and (1 << bit_width) as
in standard clock divider or multiplier structures.

For example, the div_min for hs_sd_card_src_rate is 2, not 1. This
affects the calculation of the approximate divider, and cannot be fully
represented if we only use the clk_divider structure.

Another example is ls_codec_adc_rate, where mul_min is 0x10, mul_max is
0x1B9, div_min is 0xC35, and div_max is 0x3D09. These specific ranges
cannot be described using the normal clk_fractional_divider structure.

>
> What do you think of introducing support for such "write enable bit" to
> the generic implementation of multipler/divider/fractional? Then you
> could reuse the generic implementation in K230's driver, avoiding code
> duplication.
Therefore, in addition to the requirement of setting the
write_enable_bit, the customizable ranges for these parameters are also
important differences that should be considered.
>
> ...
>
>> +static const struct of_device_id k230_clk_ids[] = {
>> +	{ .compatible = "canaan,k230-clk" },
>> +	{ /* Sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(of, k230_clk_ids);
> MODULE_DEVICE_TABLE is unnecessary if your driver couldn't be built as
> a module.
OK, thanks for point it out.
>
>> +static struct platform_driver k230_clk_driver = {
>> +	.driver = {
>> +		.name = "k230_clock_controller",
>> +		.of_match_table = k230_clk_ids,
>> +	},
>> +	.probe = k230_clk_probe,
>> +};
>> +builtin_platform_driver(k230_clk_driver);
> Best regards,
> Yao Zi

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ