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: <CAHCN7xL+sQdt=kL_jM2W0LeoiRS7eEufbm5cwvNNtvxR-xDM5A@mail.gmail.com>
Date: Thu, 23 Jan 2025 08:10:38 -0600
From: Adam Ford <aford173@...il.com>
To: Sakari Ailus <sakari.ailus@...ux.intel.com>
Cc: Dave Stevenson <dave.stevenson@...pberrypi.com>, 
	Mauro Carvalho Chehab <mchehab@...nel.org>, linux-media@...r.kernel.org, 
	linux-kernel@...r.kernel.org, Peyton Howe <peyton.howe@...lsouth.net>
Subject: Re: [PATCH] media: imx219: Adjust PLL settings based on the number of
 MIPI lanes

On Thu, Jan 23, 2025 at 2:09 AM Sakari Ailus
<sakari.ailus@...ux.intel.com> wrote:
>
> Hi Dave,
>
> On Wed, Jan 22, 2025 at 04:24:10PM +0000, Dave Stevenson wrote:
> > Hi Sakari
> >
> > On Wed, 22 Jan 2025 at 12:01, Sakari Ailus <sakari.ailus@...ux.intel.com> wrote:
> > >
> > > Hi Dave,
> > >
> > > On Mon, Jan 20, 2025 at 11:35:40AM +0000, Dave Stevenson wrote:
> > > > Commit ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation")
> > > > added support for device tree to allow configuration of the sensor to
> > > > use 4 lanes with a link frequency of 363MHz, and amended the advertised
> > > > pixel rate to 280.8MPix/s.
> > > >
> > > > However it didn't change any of the PLL settings, so actually it would
> > > > have been running overclocked in the MIPI block, and with the frame
> > > > rate and exposure calculations being wrong as the pixel rate was
> > > > unchanged.
> > > >
> > > > The pixel rate and link frequency advertised were taken from the "Clock
> > > > Setting Example" section of the datasheet. However those are based on an
> > > > external clock of 12MHz, and are unachievable with a clock of 24MHz - it
> > > > seems PREPLLCLK_VT_DIV and PREPLLCK_OP_DIV can ONLY be set via the
> > > > automatic configuration documented in "9-1-2 EXCK_FREQ setting depend on
> > > > INCK frequency", not by writing the registers.
> > > > The closest we can get with a 24MHz clock is 281.6MPix/s and 364MHz.
> > > >
> > > > Dropping all support for the 363MHz link frequency would cause problems
> > > > for existing users, so allow it, but log a warning that the requested
> > > > value is being changed to the supported one.
> > > >
> > > > Fixes: ceddfd4493b3 ("media: i2c: imx219: Support four-lane operation")
> > > > Co-developed-by: Peyton Howe <peyton.howe@...lsouth.net>
> > > > Signed-off-by: Peyton Howe <peyton.howe@...lsouth.net>
> > > > Signed-off-by: Dave Stevenson <dave.stevenson@...pberrypi.com>
> > > > ---
> > > > This was fed back to us by Peyton Howe as giving image corruption
> > > > on a Raspberry Pi with DF Robot imx219 module, and confirmed with
> > > > a Soho Enterprises module.
> > > > Effectively the module was being overclocked and misbehaving.
> > > >
> > > > With this patch and the Soho Enterprises module no image corruption
> > > > is observed, and the frame rates are spot on. I haven't checked
> > > > exposure times, but those should follow frame rate as they are
> > > > based on the same clock.
> > > > ---
> > > >  drivers/media/i2c/imx219.c | 78 ++++++++++++++++++++++++++++++++++++----------
> > > >  1 file changed, 61 insertions(+), 17 deletions(-)
> > > >
> > > > diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
> > > > index 2d54cea113e1..562b3eb0cb1e 100644
> > > > --- a/drivers/media/i2c/imx219.c
> > > > +++ b/drivers/media/i2c/imx219.c
> > > > @@ -133,10 +133,11 @@
> > > >
> > > >  /* Pixel rate is fixed for all the modes */
> > > >  #define IMX219_PIXEL_RATE            182400000
> > > > -#define IMX219_PIXEL_RATE_4LANE              280800000
> > > > +#define IMX219_PIXEL_RATE_4LANE              281600000
> > > >
> > > >  #define IMX219_DEFAULT_LINK_FREQ     456000000
> > > > -#define IMX219_DEFAULT_LINK_FREQ_4LANE       363000000
> > > > +#define IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED   363000000
> > > > +#define IMX219_DEFAULT_LINK_FREQ_4LANE       364000000
> > >
> > > This shows again the ill effects of register list based drivers. :-(
> >
> > Seeing as it was the PLL setup that was wrong, I believe the only
> > drivers that may have avoided it are MT9P031, AR0521, and CCS assuming
> > they compute all PLL settings correctly off an arbitrary pixel clock.
>
> ov5640 does that, too, but it has a mode list.
>
> >
> > Unfortunately I had no hardware to test the original patch adding 4
> > lane support, and as the datasheet doesn't lay out the actual PLL
> > configuration required for each option I hadn't twigged it was
> > required. I would have hoped that the author of that patch would have
> > noticed the frame rates were wrong, but things are never perfect.

I didn't see video issues when I submitted the original patch.  I
don't know if I just lucked out with having hardware that tolerated
overclocking, or if it was due to the resolution or frame rate I was
testing.

> >
> > And I assume that your comment means that we won't see Intel
> > submitting any register list based drivers in future? I'll be quite
> > happy not having to rework them due to only supporting a 19.2MHz clock
> > :-)

My original design for the IMX219 didn't use a 24MHz ref clock, but I
noticed the datasheet supported different ref clocks.  I had
considered adding support for the clock we originally designed, but I
convinced the hardware guys to swap out the clock, so didn't spend a
lot of time on the investigating the PLL's or clocking structure.
Ironically, I was afraid to break something, which I apparently
succeeded in doing anyway.  :-(

Sorry about that.

>
> I'd wish I could say I won't merge any new register list based drivers but
> that would mean there would be very, very few new sensor drivers. :-(
> Register list based are here to stay, I'm afraid.
>
> >
> > > >
> > > >  /* IMX219 native and active pixel array size. */
> > > >  #define IMX219_NATIVE_WIDTH          3296U
> > > > @@ -168,15 +169,6 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
> > > >       { CCI_REG8(0x30eb), 0x05 },
> > > >       { CCI_REG8(0x30eb), 0x09 },
> > > >
> > > > -     /* PLL Clock Table */
> > > > -     { IMX219_REG_VTPXCK_DIV, 5 },
> > > > -     { IMX219_REG_VTSYCK_DIV, 1 },
> > > > -     { IMX219_REG_PREPLLCK_VT_DIV, 3 },      /* 0x03 = AUTO set */
> > > > -     { IMX219_REG_PREPLLCK_OP_DIV, 3 },      /* 0x03 = AUTO set */
> > > > -     { IMX219_REG_PLL_VT_MPY, 57 },
> > > > -     { IMX219_REG_OPSYCK_DIV, 1 },
> > > > -     { IMX219_REG_PLL_OP_MPY, 114 },
> > > > -
> > > >       /* Undocumented registers */
> > > >       { CCI_REG8(0x455e), 0x00 },
> > > >       { CCI_REG8(0x471e), 0x4b },
> > > > @@ -201,6 +193,34 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
> > > >       { IMX219_REG_EXCK_FREQ, IMX219_EXCK_FREQ(IMX219_XCLK_FREQ / 1000000) },
> > > >  };
> > > >
> > > > +static const struct cci_reg_sequence imx219_2lane_regs[] = {
> > > > +     /* PLL Clock Table */
> > > > +     { IMX219_REG_VTPXCK_DIV, 5 },
> > > > +     { IMX219_REG_VTSYCK_DIV, 1 },
> > > > +     { IMX219_REG_PREPLLCK_VT_DIV, 3 },      /* 0x03 = AUTO set */
> > > > +     { IMX219_REG_PREPLLCK_OP_DIV, 3 },      /* 0x03 = AUTO set */
> > > > +     { IMX219_REG_PLL_VT_MPY, 57 },
> > > > +     { IMX219_REG_OPSYCK_DIV, 1 },
> > > > +     { IMX219_REG_PLL_OP_MPY, 114 },
> > > > +
> > > > +     /* 2-Lane CSI Mode */
> > > > +     { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_2_LANE_MODE },
> > > > +};
> > > > +
> > > > +static const struct cci_reg_sequence imx219_4lane_regs[] = {
> > > > +     /* PLL Clock Table */
> > > > +     { IMX219_REG_VTPXCK_DIV, 5 },
> > > > +     { IMX219_REG_VTSYCK_DIV, 1 },
> > > > +     { IMX219_REG_PREPLLCK_VT_DIV, 3 },      /* 0x03 = AUTO set */
> > > > +     { IMX219_REG_PREPLLCK_OP_DIV, 3 },      /* 0x03 = AUTO set */
> > > > +     { IMX219_REG_PLL_VT_MPY, 88 },
> > > > +     { IMX219_REG_OPSYCK_DIV, 1 },
> > > > +     { IMX219_REG_PLL_OP_MPY, 91 },
> > > > +
> > > > +     /* 4-Lane CSI Mode */
> > > > +     { IMX219_REG_CSI_LANE_MODE, IMX219_CSI_4_LANE_MODE },
> > > > +};

Instead of having a few tables of registers, would it make sense to
have one common table and a small function to dynamically calculate
these registers based on the ref clock and the desired link rate?
Several of these values appear to be duplicates anyway.

> > > > +
> > > >  static const s64 imx219_link_freq_menu[] = {
> > > >       IMX219_DEFAULT_LINK_FREQ,
> > > >  };
> > > > @@ -662,9 +682,11 @@ static int imx219_set_framefmt(struct imx219 *imx219,
> > > >
> > > >  static int imx219_configure_lanes(struct imx219 *imx219)
> > > >  {
> > > > -     return cci_write(imx219->regmap, IMX219_REG_CSI_LANE_MODE,
> > > > -                      imx219->lanes == 2 ? IMX219_CSI_2_LANE_MODE :
> > > > -                      IMX219_CSI_4_LANE_MODE, NULL);
> > > > +     /* Write the appropriate PLL settings for the number of MIPI lanes */
> > > > +     return cci_multi_reg_write(imx219->regmap,
> > > > +                               imx219->lanes == 2 ? imx219_2lane_regs : imx219_4lane_regs,
> > > > +                               imx219->lanes == 2 ? ARRAY_SIZE(imx219_2lane_regs) :
> > > > +                               ARRAY_SIZE(imx219_4lane_regs), NULL);
> > > >  };
> > > >
> > > >  static int imx219_start_streaming(struct imx219 *imx219,
> > > > @@ -1036,6 +1058,7 @@ static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
> > > >               .bus_type = V4L2_MBUS_CSI2_DPHY
> > > >       };
> > > >       int ret = -EINVAL;
> > > > +     bool link_frequency_valid = false;
> > > >
> > > >       endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
> > > >       if (!endpoint)
> > > > @@ -1062,9 +1085,30 @@ static int imx219_check_hwcfg(struct device *dev, struct imx219 *imx219)
> > > >               goto error_out;
> > > >       }
> > > >
> > > > -     if (ep_cfg.nr_of_link_frequencies != 1 ||
> > > > -        (ep_cfg.link_frequencies[0] != ((imx219->lanes == 2) ?
> > > > -         IMX219_DEFAULT_LINK_FREQ : IMX219_DEFAULT_LINK_FREQ_4LANE))) {
> > > > +     if (ep_cfg.nr_of_link_frequencies == 1) {
> > > > +             switch (imx219->lanes) {
> > > > +             case 2:
> > > > +                     if (ep_cfg.link_frequencies[0] ==
> > > > +                                             IMX219_DEFAULT_LINK_FREQ)
> > > > +                             link_frequency_valid = true;
> > > > +                     break;
> > > > +             case 4:
> > > > +                     if (ep_cfg.link_frequencies[0] ==
> > > > +                                             IMX219_DEFAULT_LINK_FREQ_4LANE)
> > > > +                             link_frequency_valid = true;
> > > > +                     else if (ep_cfg.link_frequencies[0] ==
> > > > +                                IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED) {
> > > > +                             dev_warn(dev, "Link frequency of %d not supported, but has been incorrectly advertised previously\n",
> > > > +                                      IMX219_DEFAULT_LINK_FREQ_4LANE_UNSUPPORTED);
> > > > +                             dev_warn(dev, "Using link frequency of %d\n",
> > > > +                                      IMX219_DEFAULT_LINK_FREQ_4LANE);

I grepped the code for 363000000 to see if anyone was using it in
their device tree.  Maybe I missed something in linux-next, but I
didn't see it.  I know I didn't push my camera device tree entries for
the two devices I had tested, because I was going to use them as
device tree overlays and never got around to pushing them upstream,
but I do occasionally test them.  If nobody has a wrong device tree
entry, it seems reasonable to me to simplify this code by just
changing it from 363000000 to 364000000 and eliminate the stuff for
the the unsupported value.


> > >
> > > Would it be helpful to use v4l2_link_freq_to_bitmap() here? The old
> > > frequency requires separate handling but I guess you'll still want to
> > > expose the correct frequency to the user space so it should be just one
> > > condition.
> >
> > I've done a quick prototype using it. I'm not sure it's any cleaner,
> > and possibly ends up being more verbose.
> >
> > As I see it, either you end up with a call to v4l2_link_freq_to_bitmap
> > for each of the 2 and 4 lane cases (6 lines each due to the number of
> > parameters), or you combine both 2 & 4 lane frequency options into one
> > array and then handle that certain bit options are only valid for one
> > or other option, and pass the right value in when calling
> > v4l2_ctrl_new_int_menu(..., V4L2_CID_LINK_FREQ...).
> > Handling the unsupported link frequency requires knowledge of the
> > positions in the array, so either hard coded indices or needing an
> > enum for each index.
> >
> > I've pushed my quick patch to
> > https://github.com/6by9/linux/tree/media_imx219_4lane.
> > Personally I think it detracts from readability in this case, but I'm
> > happy to switch to a cleaned up version of it if you view it as
> > better.
>

Thanks for looking at this.

> I was thinking of separate frequency lists for all three cases. That way
> you'd avoid almost all manual checks of the frequencies.
>
> The question I'd also have is whether we should try to continue to indicate
> the incorrect frequency or not. The values are not an integral part of the
> ABI in my view as new ones can be added, even for the same board. And in
> this case there's just a single one in any given case.
>
> This information is also mainly used to configure the receiver timing and
> wrong values here could lead to errors in reception.
>
> IOW, I'd just show the correct value, independently of what's in firmware.
>
> --
> Kind regards,
>
> Sakari Ailus

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ