From patchwork Fri Nov 4 14:24:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 13032097 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 706DCC43217 for ; Fri, 4 Nov 2022 14:28:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232243AbiKDO2O (ORCPT ); Fri, 4 Nov 2022 10:28:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41844 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232446AbiKDO1c (ORCPT ); Fri, 4 Nov 2022 10:27:32 -0400 Received: from relay11.mail.gandi.net (relay11.mail.gandi.net [IPv6:2001:4b98:dc4:8::231]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 15DE030F79 for ; Fri, 4 Nov 2022 07:25:18 -0700 (PDT) Received: (Authenticated sender: jacopo@jmondi.org) by mail.gandi.net (Postfix) with ESMTPSA id B5F05100013; Fri, 4 Nov 2022 14:25:15 +0000 (UTC) From: Jacopo Mondi To: =?utf-8?q?Krzysztof_Ha=C5=82asa?= , Mauro Carvalho Chehab , Sakari Ailus , Laurent Pinchart Cc: Jacopo Mondi , linux-media@vger.kernel.org, Dave Stevenson Subject: [PATCH v3 04/10] media: ar0521: Rework PLL computation Date: Fri, 4 Nov 2022 15:24:47 +0100 Message-Id: <20221104142452.117135-5-jacopo@jmondi.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221104142452.117135-1-jacopo@jmondi.org> References: <20221104142452.117135-1-jacopo@jmondi.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org Rework the PLL computation procedure to take into account the currently configured format bpp and the number of data lanes. Comment the PLL configuration procedure with information provided by the sensor chip manual and remove the hardcoded divider from the pixel clock calculation. Signed-off-by: Jacopo Mondi --- drivers/media/i2c/ar0521.c | 113 +++++++++++++++++++++++++++---------- 1 file changed, 84 insertions(+), 29 deletions(-) diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index bcbd6ffd8832..d30f7a1c7651 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -21,7 +21,7 @@ #define AR0521_PLL_MIN (320 * 1000 * 1000) #define AR0521_PLL_MAX (1280 * 1000 * 1000) -/* Effective pixel clocks, the registers may be DDR */ +/* Effective pixel sample rate on the pixel array. */ #define AR0521_PIXEL_CLOCK_RATE (184 * 1000 * 1000) #define AR0521_PIXEL_CLOCK_MIN (168 * 1000 * 1000) #define AR0521_PIXEL_CLOCK_MAX (414 * 1000 * 1000) @@ -123,10 +123,14 @@ struct ar0521_dev { unsigned int lane_count; u16 total_width; u16 total_height; - u16 pll_pre; - u16 pll_mult; - u16 pll_pre2; - u16 pll_mult2; + struct { + u16 pre; + u16 mult; + u16 pre2; + u16 mult2; + u16 vt_pix; + } pll; + bool streaming; }; @@ -151,6 +155,16 @@ static u32 div64_round_up(u64 v, u32 d) return div_u64(v + d - 1, d); } +static int ar0521_code_to_bpp(struct ar0521_dev *sensor) +{ + switch (sensor->fmt.code) { + case MEDIA_BUS_FMT_SGRBG8_1X8: + return 8; + } + + return -EINVAL; +} + /* Data must be BE16, the first value is the register address */ static int ar0521_write_regs(struct ar0521_dev *sensor, const __be16 *data, unsigned int count) @@ -226,8 +240,7 @@ static int ar0521_set_gains(struct ar0521_dev *sensor) return ar0521_write_regs(sensor, regs, ARRAY_SIZE(regs)); } -static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr, - u16 *mult_ptr) +static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult_ptr) { u16 pre = 1, mult = 1, new_pre; u32 pll = AR0521_PLL_MAX + 1; @@ -262,37 +275,79 @@ static u32 calc_pll(struct ar0521_dev *sensor, int num, u32 freq, u16 *pre_ptr, return pll; } -#define DIV 4 static void ar0521_calc_mode(struct ar0521_dev *sensor) { - unsigned int speed_mod = 4 / sensor->lane_count; /* 1 with 4 DDR lanes */ - u16 total_width = max(sensor->fmt.width + AR0521_WIDTH_BLANKING_MIN, - AR0521_TOTAL_WIDTH_MIN); - u16 total_height = sensor->fmt.height + AR0521_HEIGHT_BLANKING_MIN; - - /* Calculate approximate pixel clock first */ - u64 pix_clk = AR0521_PIXEL_CLOCK_RATE; - - /* PLL1 drives pixel clock - dual rate */ - pix_clk = calc_pll(sensor, 1, pix_clk * (DIV / 2), &sensor->pll_pre, - &sensor->pll_mult); - pix_clk = div64_round(pix_clk, (DIV / 2)); - calc_pll(sensor, 2, pix_clk * (DIV / 2) * speed_mod, &sensor->pll_pre2, - &sensor->pll_mult2); - - sensor->total_width = total_width; - sensor->total_height = total_height; + unsigned int pixel_clock; + u16 pre, mult; + u32 vco; + int bpp; + + /* + * PLL1 and PLL2 are computed equally even if the application note + * suggests a slower PLL1 clock. Maintain pll1 and pll2 divider and + * multiplier separated to later specialize the calculation procedure. + * + * PLL1: + * - mclk -> / pre_div1 * pre_mul1 = VCO1 = COUNTER_CLOCK + * + * PLL2: + * - mclk -> / pre_div * pre_mul = VCO + * + * VCO -> / vt_pix = PIXEL_CLOCK + * VCO -> / vt_pix / 2 = WORD_CLOCK + * VCO -> / op_sys = SERIAL_CLOCK + * + * With: + * - vt_pix = bpp / 2 + * - WORD_CLOCK = PIXEL_CLOCK / 2 + * - SERIAL_CLOCK = MIPI data rate (Mbps / lane) = WORD_CLOCK * bpp + * NOTE: this implies the MIPI clock is divided internally by 2 + * to account for DDR. + * + * As op_sys_div is fixed to 1: + * + * SERIAL_CLOCK = VCO + * VCO = 2 * MIPI_CLK + * VCO = PIXEL_CLOCK * bpp / 2 + * + * In the clock tree: + * MIPI_CLK = PIXEL_CLOCK * bpp / 2 / 2 + * + * Generic pixel_rate to bus clock frequencey equation: + * MIPI_CLK = V4L2_CID_PIXEL_RATE * bpp / lanes / 2 + * + * From which we derive the PIXEL_CLOCK to use in the clock tree: + * PIXEL_CLOCK = V4L2_CID_PIXEL_RATE * 2 / lanes + * + * Documented clock ranges: + * WORD_CLOCK = (35MHz - 120 MHz) + * PIXEL_CLOCK = (84MHz - 207MHz) + * VCO = (320MHz - 1280MHz) + * + * TODO: in case we have less data lanes we have to reduce the desired + * VCO not to exceed the limits specified by the datasheet and + * consequentially reduce the obtained pixel clock. + */ + pixel_clock = AR0521_PIXEL_CLOCK_RATE * 2 / sensor->lane_count; + bpp = ar0521_code_to_bpp(sensor); + sensor->pll.vt_pix = bpp / 2; + vco = pixel_clock * sensor->pll.vt_pix; + + calc_pll(sensor, vco, &pre, &mult); + + sensor->pll.pre = sensor->pll.pre2 = pre; + sensor->pll.mult = sensor->pll.mult2 = mult; } static int ar0521_write_mode(struct ar0521_dev *sensor) { __be16 pll_regs[] = { be(AR0521_REG_VT_PIX_CLK_DIV), - /* 0x300 */ be(4), /* vt_pix_clk_div = number of bits / 2 */ + /* 0x300 */ be(sensor->pll.vt_pix), /* vt_pix_clk_div = bpp / 2 */ /* 0x302 */ be(1), /* vt_sys_clk_div */ - /* 0x304 */ be((sensor->pll_pre2 << 8) | sensor->pll_pre), - /* 0x306 */ be((sensor->pll_mult2 << 8) | sensor->pll_mult), - /* 0x308 */ be(8), /* op_pix_clk_div = 2 * vt_pix_clk_div */ + /* 0x304 */ be((sensor->pll.pre2 << 8) | sensor->pll.pre), + /* 0x306 */ be((sensor->pll.mult2 << 8) | sensor->pll.mult), + /* 0x308 */ be(sensor->pll.vt_pix * 2), /* op_pix_clk_div = 2 * vt_pix_clk_div */ /* 0x30A */ be(1) /* op_sys_clk_div */ }; int ret;