Linux clock framework development
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Long Zhao" <longzhao@ambarella.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org,
	linux-clk@vger.kernel.org
Subject: Re: [PATCH v3 4/6] clk: ambarella: add CV75 CCU driver
Date: Thu, 13 Aug 2026 10:10:06 +0000	[thread overview]
Message-ID: <20260813101007.1745F1F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260813-cv75-v3-a-v3-4-cfdd20b1b4dd@ambarella.com>

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] VCO range iteration underflows and corrupts the PLL CTRL3 register if `fvco_mhz` evaluates to 0.
- [High] `amb_pll_calc_params` omits the feedback and output dividers (`fsdiv` and `fsout`) when determining parameters, resulting in drastically incorrect clock frequencies.
- [High] Division by zero kernel panic in `amb_pll_calc_params()` when the parent clock rate is zero.
- [Medium] Setting the rate of a non-ONE_BASED divider to 0 permanently disables the clock due to an incorrect mask.
- [Medium] `amb_pll_determine_rate` unnecessarily restricts integer PLL rates to multiples of `parent_rate / 2`.
- [Low] Passing a 64-bit divisor to `DIV_ROUND_CLOSEST_ULL` causes a build failure on 32-bit architectures.
--

--- Patch [4]: [PATCH v3 4/6] clk: ambarella: add CV75 CCU driver ---
commit 434160130974a0a15aae2d546aa85876cbc1fe59
Author: Long Zhao <longzhao@ambarella.com>

clk: ambarella: add CV75 CCU driver

Add the Ambarella CV75 clock driver covering the core PLL and the
UART0 / AHB / APB clocks needed for early console bring-up.

> diff --git a/drivers/clk/ambarella/ccu_mux_div.c b/drivers/clk/ambarella/ccu_mux_div.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/clk/ambarella/ccu_mux_div.c
[ ... ]
> +static int amb_div_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
[ ... ]
> +	if (!rate) {
> +		/* Assert the reset/disable bit above the divider field. */
> +		val = BIT(div->width);
> +		mask = clk_div_mask(div->width + 1);
> +	} else {
> +		val = divider_get_val(rate, parent_rate, NULL,
> +				      div->width, div->flags);
> +		if (val < 0)
> +			return val;
> +
> +		mask = (div->flags & CLK_DIVIDER_ONE_BASED) ?
> +			clk_div_mask(div->width + 1) : clk_div_mask(div->width);

[Severity: Medium]
When setting the rate to 0, the driver asserts the reset/disable bit above
the divider field. When a non-zero rate is subsequently requested, this logic
uses a mask that strictly covers only the divider field.

Will this exclude the higher disable bit during the update, leaving the clock
permanently disabled?

> +	}
> +
> +	regmap_update_bits(div->map, div->offset, mask << div->shift,
> +			   val << div->shift);
[ ... ]
> diff --git a/drivers/clk/ambarella/ccu_pll.c b/drivers/clk/ambarella/ccu_pll.c
> new file mode 100644
> --- /dev/null
> +++ b/drivers/clk/ambarella/ccu_pll.c
[ ... ]
> +static int amb_pll_determine_rate(struct clk_hw *hw,
> +				  struct clk_rate_request *req)
> +{
> +	struct amb_pll *pll = to_amb_pll(hw);
> +	unsigned long half_refclk = req->best_parent_rate / 2;
> +
> +	if (pll->frac_mode)
> +		return 0;
> +
> +	if (!half_refclk)
> +		return -EINVAL;
> +
> +	req->rate = roundup(req->rate, half_refclk);

[Severity: Medium]
Does clamping the requested rate to a multiple of half_refclk artificially
restrict the hardware's capabilities?

Because the hardware sout divider supports ranges up to 16, it looks like it
could natively support a wide and fine-grained selection of exact integer
frequencies instead of being clamped this way.

> +
> +	return 0;
> +}
> +
> +static int amb_pll_calc_params(struct amb_pll *pll, unsigned long rate,
> +			       unsigned long parent_rate, u32 ctrl2_val,
> +			       u32 *intp, u32 *sdiv, u32 *sout,
> +			       u32 *vcodiv, u32 *fsdiv, u32 *fsout)
> +{
[ ... ]
> +	max_numerator = soc_data->vco_max_mhz;
> +	max_numerator = div_u64(max_numerator * 1000000ULL, parent_rate);

[Severity: High]
In amb_pll_determine_rate(), if the PLL is in frac_mode, it returns 0
immediately without validating if half_refclk is zero:

static int amb_pll_determine_rate(...) {
        ...
        if (pll->frac_mode)
                return 0;

        if (!half_refclk)
                return -EINVAL;
        ...
}

If a zero-rate parent clock reaches amb_pll_calc_params(), will this
division by zero trigger a kernel panic?

> +	max_numerator = div_u64(max_numerator, *vcodiv * *fsdiv);
> +	max_numerator = min(128UL, max_numerator);
> +	if (!max_numerator)
> +		return -EINVAL;
> +
> +	max_denominator = AMB_PLL_MAX_SOUT;
> +	rate_tmp = rate;
> +	rational_best_approximation(rate_tmp, parent_rate, max_numerator,
> +				    max_denominator, &intp_ul, &sout_ul);

[Severity: High]
The hardware frequency depends on fsdiv and fsout, but this call requests an
approximation using just rate and parent_rate. 

If the hardware is left in a state where fsdiv and fsout are not identical,
will the resulting frequency be scaled incorrectly and bypass the refinement
loop?

> +
> +	while (parent_rate * *fsdiv * intp_ul * *sdiv / *fsout / sout_ul >
[ ... ]
> +static int amb_pll_set_rate(struct clk_hw *hw, unsigned long rate,
> +			    unsigned long parent_rate)
> +{
[ ... ]
> +	old_rate = amb_pll_recalc_rate(hw, parent_rate) * pll->fix_divider;
> +	rate_tmp = old_rate > rate ? 0 : rate - old_rate;
> +	if (rate_tmp && pll->frac_mode) {
> +		u64 dividend, divider;
> +
> +		dividend = (u64)rate_tmp * sout * fsout;
> +		dividend <<= 32;
> +		divider = (u64)sdiv * fsdiv * parent_rate;
> +		frac_val = DIV_ROUND_CLOSEST_ULL(dividend, divider);

[Severity: Low]
The divider variable evaluates to a 64-bit integer, but
DIV_ROUND_CLOSEST_ULL() invokes do_div() which expects a 32-bit divisor on
32-bit architectures.

Will this trigger a __div64_32 link failure under COMPILE_TEST?

> +		regmap_write(pll->map, reg[FRAC_OFFSET], frac_val);
> +		ctrl_val |= CTRL_FRAC_MODE;
> +	}
> +
> +	if (soc_data->pll_version >= 2) {
[ ... ]
> +	} else {
> +		u32 fvco_mhz, range;
> +
> +		fvco_mhz = amb_pll_calc_vco(pll, parent_rate) / 1000000UL;
> +		for (range = 0; range < ARRAY_SIZE(soc_data->vco_range);
> +		     range++) {
> +			if (fvco_mhz > soc_data->vco_range[range])
> +				break;
> +		}
> +		range = ARRAY_SIZE(soc_data->vco_range) - range - 1;
> +
> +		regmap_read(pll->map, reg[CTRL3_OFFSET], &ctrl3_val);
> +		ctrl3_val &= ~CTRL3_VCO_RANGE_MASK;
> +		ctrl3_val |= range << 1;

[Severity: High]
If the PLL parent rate is exceptionally low (e.g., from a dummy clock),
fvco_mhz can evaluate to 0. Since 0 is not strictly greater than any range
minimum, the loop finishes at 4.

Will the subsequent calculation 4 - 4 - 1 underflow to 0xFFFFFFFF and
corrupt the CTRL3 register bits?

> +		regmap_write(pll->map, reg[CTRL3_OFFSET], ctrl3_val);
[ ... ]

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260813-cv75-v3-a-v3-0-cfdd20b1b4dd@ambarella.com?part=4

  reply	other threads:[~2026-08-13 10:10 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-13  9:56 [PATCH v3 0/6] Ambarella CV75: bindings, RCT clocks, and DT Long Zhao via B4 Relay
2026-08-13  9:56 ` [PATCH v3 1/6] dt-bindings: arm: add Ambarella CV75 platforms Long Zhao via B4 Relay
2026-08-13  9:56 ` [PATCH v3 2/6] dt-bindings: mfd: syscon: add Ambarella CV75 secure scratchpad Long Zhao via B4 Relay
2026-08-13 10:03   ` sashiko-bot
2026-08-13  9:56 ` [PATCH v3 3/6] dt-bindings: clock: add Ambarella CV75 RCT Long Zhao via B4 Relay
2026-08-13 10:02   ` sashiko-bot
2026-08-13  9:56 ` [PATCH v3 4/6] clk: ambarella: add CV75 CCU driver Long Zhao via B4 Relay
2026-08-13 10:10   ` sashiko-bot [this message]
2026-08-13  9:56 ` [PATCH v3 5/6] arm64: ambarella: add ARCH_AMBARELLA and CV75 EVK DT Long Zhao via B4 Relay
2026-08-13 10:07   ` sashiko-bot
2026-08-13  9:56 ` [PATCH v3 6/6] MAINTAINERS: add ARM/AMBARELLA SoC support Long Zhao via B4 Relay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260813101007.1745F1F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=linux-clk@vger.kernel.org \
    --cc=longzhao@ambarella.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox