Re: [PATCH v2 1/5] media: Add MIPI CCI register access helper functions

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Laurent,
Thanks for your comments.

On Fri, Jun 16, 2023 at 06:07:36PM +0300, Laurent Pinchart wrote:
> On Fri, Jun 16, 2023 at 04:56:15PM +0200, Tommaso Merciai wrote:
> > On Fri, Jun 16, 2023 at 05:17:06PM +0300, Laurent Pinchart wrote:
> > > On Fri, Jun 16, 2023 at 04:15:09PM +0200, Tommaso Merciai wrote:
> > > > On Fri, Jun 16, 2023 at 04:41:24PM +0300, Laurent Pinchart wrote:
> > > > > On Fri, Jun 16, 2023 at 12:20:16AM +0200, Tommaso Merciai wrote:
> > > > > > On Thu, Jun 15, 2023 at 07:52:36PM +0300, Laurent Pinchart wrote:
> > > > > > > On Thu, Jun 15, 2023 at 06:15:43PM +0200, Tommaso Merciai wrote:
> > > > > > > > On Thu, Jun 15, 2023 at 02:00:46PM +0200, Hans de Goede wrote:
> > > > > > > > > On 6/15/23 13:54, Tommaso Merciai wrote:
> > > > > > > > > > On Thu, Jun 15, 2023 at 01:26:25PM +0200, Tommaso Merciai wrote:
> > > > > > > > > >> On Thu, Jun 15, 2023 at 01:10:40PM +0200, Hans de Goede wrote:
> > > > > > > > > >>> On 6/15/23 12:05, Tommaso Merciai wrote:
> > > > > > > > > >>>> Hi Hans, Laurent, Sakari,
> > > > > > > > > >>>>
> > > > > > > > > >>>> Can I cherry-pick this patch and use these new functions also
> > > > > > > > > >>>> for cci regs of the alvium driver?
> > > > > > > > > >>>
> > > > > > > > > >>> Yes that sounds like a good plan.
> > > > > > > > > >>>
> > > > > > > > > >>>> Are on going to be merge?
> > > > > > > > > >>>
> > > > > > > > > >>> Yes this will hopefully get merged upstream soon.
> > > > > > > > > >>
> > > > > > > > > >> Thanks for the info!
> > > > > > > > > >>
> > > > > > > > > >> I want to ask you your opinion about this:
> > > > > > > > > >>
> > > > > > > > > >> Into alvium driver actually I'm using the following defines
> > > > > > > > > >> manipulations:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_REG_ADDR_R				REG_BCRM_CCI_16BIT(0x0014)
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > > >>
> > > > > > > > > >> My plan is to use your cci API for cci register in this way defines
> > > > > > > > > >> became like:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_REG_ADDR_R				CCI_REG16(0x0014)
> > > > > > > > > >>
> > > > > > > > > >> And leave v4l2 regs are it are right now:
> > > > > > > > > >>
> > > > > > > > > >> #define REG_BCRM_FEATURE_INQUIRY_R			REG_BCRM_V4L2_64BIT(0x0008)
> > > > > > > > > >> #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R		REG_BCRM_V4L2_64BIT(0x0010)
> > > > > > > > > >>
> > > > > > > > > >> What do you think about?
> > > > > > > > > > 
> > > > > > > > > > Or maybe is worth don't use v4l2 bit for v4l2 regs, I think is implicit
> > > > > > > > > > that what regs that are not CCI are v4l2, then we return wit the
> > > > > > > > > > following defines:
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > 
> > > > > > > > > > #define REG_BCRM_REG_ADDR_R                           CCI_REG16(0x0014)
> > > > > > > > > > ^CCI regs
> > > > > > > > > > 
> > > > > > > > > > #define REG_BCRM_FEATURE_INQUIRY_R                    0x0008 
> > > > > > > > > > #define REG_BCRM_DEVICE_FIRMWARE_VERSION_R            0x0010
> > > > > > > > > > ^v4l2 regs
> > > > > > > > > 
> > > > > > > > > I'm not sure what you mean with "V4L2" registers ? I guess you mean
> > > > > > > > > registers which cannot be accessed through the CCI helper functions,
> > > > > > > > > but starting with v2 this is no longer true. There now is a CCI_REG64()
> > > > > > > > > so you can simply use that.
> > > > > > > > 
> > > > > > > > I'm playing a bit with v3 of your cci api :)
> > > > > > > > 
> > > > > > > > My problem is the following, bcrm regs are not real regs but are offset
> > > > > > > > from bcrm address (this is not fixed, it depends on the camera).
> > > > > > > > 
> > > > > > > > Then the workflow is:
> > > > > > > > 
> > > > > > > >  - read bcrm_address (base address)
> > > > > > > >  - then sum this to the offset (regs)
> > > > > > > > 
> > > > > > > > Myabe this clarify:
> > > > > > > > 
> > > > > > > > static int alvium_read(struct alvium_dev *alvium, u32 reg, u64 *val)
> > > > > > > 
> > > > > > > I would add a int *err argument to your read and write wrappers.
> > > > > > 
> > > > > > 
> > > > > > Thanks for your hint!
> > > > > > What about using:
> > > > > > 
> > > > > > static int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > {
> > > > > > 	if (reg & REG_BCRM_V4L2) {
> > > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > > 		reg += alvium->bcrm_addr;
> > > > > > 	}
> > > > > > 
> > > > > > 	return cci_write(alvium->regmap, reg, val, NULL);
> > > > > > }
> > > > > > 
> > > > > > Then:
> > > > > > 
> > > > > > 	ret = alvium_write(alvium, reg, val);
> > > > > > 	if (ret) {
> > > > > > 		dev_err(dev, "Fail to write reg\n");
> > > > > > 		return ret;
> > > > > > 	}
> > > > > > 
> > > > > > 
> > > > > > I prefer to use this format if for you is ok.
> > > > > > Let me know.
> > > > > 
> > > > > This is fine when you have to write a single register only, but it makes
> > > > > things more complicated when writing multiple registers. Consider this:
> > > > > 
> > > > > 	int ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_A, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_B, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_C, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	ret = alvium_write(alvium, REG_D, val);
> > > > > 	if (ret)
> > > > > 		return ret;
> > > > > 
> > > > > 	return 0;
> > > > > 
> > > > > and compare it to
> > > > > 
> > > > > 	int ret = 0;
> > > > > 
> > > > > 	alvium_write(alvium, REG_A, val, &ret);
> > > > > 	alvium_write(alvium, REG_B, val, &ret);
> > > > > 	alvium_write(alvium, REG_C, val, &ret);
> > > > > 	alvium_write(alvium, REG_D, val, &ret);
> > > > > 
> > > > > 	return ret;
> > > > 
> > > > Is worth to add is also in alvium_write_hshake right?
> > 
> > Checking this... :)
> > 
> > Most of the driver don't use so much sequence of writes/reads
> > and to be honest I want know where it fail
> > 
> > 
> > For example:
> > 
> > static int alvium_write_hshake(struct alvium_dev *alvium, u32 reg, u64 val,
> > 							   int *err)
> > {
> > 	struct device *dev = &alvium->i2c_client->dev;
> > 	u64 hshake_regval;
> > 	u8 hshake_bit;
> > 
> > 	if (err && *err)
> > 		return *err;
> > 
> > 	if (!alvium->bcrm_addr)
> > 		return -EINVAL;
> > 
> > 	/* reset handshake bit */
> > 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);
> > 
> > 	/* write alvium reg*/
> > 	alvium_write(alvium, reg, val, err);
> 
> You want to return here in case of error, as the poll loop below has no
> chance of succeeding.
> 
> > 
> > 	/* poll handshake bit since bit0 = 1*/
> > 	do {
> > 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> > 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> > 
> > 	} while (!hshake_bit);
> 
> This needs a timeout. The read_poll_timeout() macro can be useful. Same
> below.

Thanks! :)

> 
> > 
> > 	/* reset handshake bit, write 0 to bit0 */
> > 	alvium_write(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, 0, err);
> 
> This also needs to return if an error occurs.
> 
> > 
> > 	/* poll handshake bit since bit0 = 0 */
> > 	do {
> > 		alvium_read(alvium, REG_BCRM_WRITE_HANDSHAKE_RW, &hshake_regval, err);
> > 		hshake_bit = (hshake_regval & BCRM_HANDSHAKE_W_DONE_EN_BIT);
> > 
> > 	} while (hshake_bit);
> > 
> > 	return *err;
> > }
> > 
> > If some write/read fail and have the same regs I want to know where the issue
> > is... Then I have to go back to the previous implementation..
> > 
> > I know that also cci API provides some print.
> > But maybe the older version is more straight forwed under debug
> > perspective...
> > 
> > Maybe is better to have more code in this case
> > This is my first impression following your way :)
> > 
> > Do you agree on this?
> 
> My comment was related to the callers of this function, not its internal
> implementation. If there's a common pattern where alvium_write_hshake()
> is called in a sequence of write operations then it should have an int
> *err argument.

My question is:

Except in the alvium_write_hshake function where you can see these
sequence of write/read operations? Same for _hshake_wrtie.
In my opinion there are not to much sequence of read/write operation
into the alvium driver, no?

I'm missing something?

Thanks & Regards,
Tommaso

> 
> > > I'd say it's worth everywhere you can have multiple writes.
> > > 
> > > > > > > > {
> > > > > > > > 	int ret;
> > > > > > > > 
> > > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > > 
> > > > > > > 
> > > > > > > You should also clear the REG_BCRM_V4L2 bit here:
> > > > > > > 
> > > > > > >  	if (reg & REG_BCRM_V4L2) {
> > > > > > > 		reg &= ~REG_BCRM_V4L2;
> > > > > > >  		reg += alvium->bcrm_addr;
> > > > > > > 	}
> > > > > > > 
> > > > > > > > 	cci_read(alvium->regmap, reg, val, &ret);
> > > > > > > > 	if (ret)
> > > > > > > > 		return ret;
> > > > > > > > 
> > > > > > > > 	return 0;
> > > > > > > 
> > > > > > > Just
> > > > > > > 
> > > > > > > 	return cci_read(alvium->regmap, reg, val, err);
> > > > > > > 
> > > > > > > Same for alvium_write()..
> > > > > > > 
> > > > > > > > }
> > > > > > > > 
> > > > > > > > int alvium_write(struct alvium_dev *alvium, u32 reg, u64 val)
> > > > > > > > {
> > > > > > > > 	int ret;
> > > > > > > > 
> > > > > > > > 	if (reg & REG_BCRM_V4L2)
> > > > > > > > 		reg += alvium->bcrm_addr;
> > > > > > > > 
> > > > > > > > 	cci_write(alvium->regmap, reg, val, &ret);
> > > > > > > > 	if (ret)
> > > > > > > > 		return ret;
> > > > > > > > 
> > > > > > > > 	return 0;
> > > > > > > > }
> > > > > > > > 
> > > > > > > > Where for example:
> > > > > > > > 
> > > > > > > > #define REG_BCRM_V4L2		BIT(31)
> > > > > > > > #define REG_BCRM_V4L2_64BIT(n)	(REG_BCRM_V4L2 | CCI_REG64(n))
> > > > > > > > 
> > > > > > > > #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0418)
> > > > > > > > 
> > > > > > > > 
> > > > > > > > But I'm not sure that I'm in the right direction. 
> > > > > > > 
> > > > > > > This looks good to me.
> > > > > > > 
> > > > > > > The fact that both Hans' helpers and part of the Alvium camera registers
> > > > > > > are named CCI is not a complete coincidence, but it doesn't mean they're
> > > > > > > identical. I would thus keep the REG_BCRM_CCI_* macros for clarity,
> > > > > > > simply defining them as CCI_* wrappers:
> > > > > > > 
> > > > > > > #define REG_BCRM_V4L2_8BIT(n)		CCI_REG8(n)
> > > > > > > ...
> > > > > > > 
> > > > > > > > In real I need first to get the real address then sum the bcrm_address
> > > > > > > > if this is a bcrm regs(offset) then re-incapsule the address into the
> > > > > > > > right CCI_REG# defines.
> > > > > > > > 
> > > > > > > > Then I'm not completely sure that cci fits my use case.
> > > > > > > > What do you think about?
> > > > > > > > 
> > > > > > > > Btw really great work! :)
> > > > > > > > 
> > > > > > > > > > ?
> > > > > > > > > > 
> > > > > > > > > >>> Note I'm about to send out a v3 addressing some small
> > > > > > > > > >>> remarks on this v2. I'll Cc you on that.
> > > > > > > > > >>
> > > > > > > > > >> Thanks, in this way I can test that and let you know my feedback.
> > > > > > > > > >>
> > > > > > > > > >>>> Let me know.
> > > > > > > > > >>>> Thanks! :)
> > > > > > > > > >>>>
> > > > > > > > > >>>> On Thu, Jun 15, 2023 at 12:21:00PM +0300, Laurent Pinchart wrote:
> > > > > > > > > >>>>> On Thu, Jun 15, 2023 at 11:11:20AM +0200, Hans de Goede wrote:
> > > > > > > > > >>>>>> On 6/14/23 23:48, Sakari Ailus wrote:
> > > > > > > > > >>>>>>> On Thu, Jun 15, 2023 at 12:34:29AM +0300, Laurent Pinchart wrote:
> > > > > > > > > >>>>>>>> On Wed, Jun 14, 2023 at 08:39:56PM +0000, Sakari Ailus wrote:
> > > > > > > > > >>>>>>>>> On Wed, Jun 14, 2023 at 09:23:39PM +0200, Hans de Goede wrote:
> > > > > > > > > >>>>>>>>>> The CSI2 specification specifies a standard method to access camera sensor
> > > > > > > > > >>>>>>>>>> registers called "Camera Control Interface (CCI)".
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> This uses either 8 or 16 bit (big-endian wire order) register addresses
> > > > > > > > > >>>>>>>>>> and supports 8, 16, 24 or 32 bit (big-endian wire order) register widths.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Currently a lot of Linux camera sensor drivers all have their own custom
> > > > > > > > > >>>>>>>>>> helpers for this, often copy and pasted from other drivers.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Add a set of generic helpers for this so that all sensor drivers can
> > > > > > > > > >>>>>>>>>> switch to a single common implementation.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> These helpers take an extra optional "int *err" function parameter,
> > > > > > > > > >>>>>>>>>> this can be used to chain a bunch of register accesses together with
> > > > > > > > > >>>>>>>>>> only a single error check at the end, rather then needing to error
> > > > > > > > > >>>>>>>>>> check each individual register access. The first failing call will
> > > > > > > > > >>>>>>>>>> set the contents of err to a non 0 value and all other calls will
> > > > > > > > > >>>>>>>>>> then become no-ops.
> > > > > > > > > >>>>>>>>>>
> > > > > > > > > >>>>>>>>>> Link: https://lore.kernel.org/linux-media/59aefa7f-7bf9-6736-6040-39551329cd0a@xxxxxxxxxx/
> > > > > > > > > >>>>>>>>>> Signed-off-by: Hans de Goede <hdegoede@xxxxxxxxxx>
> > > > > > > > > >>>>>>>>>> ---
> > > > > > > > > >>>>>>>>>> Changes in v2:
> > > > > > > > > >>>>>>>>>> - Drop cci_reg_type enum
> > > > > > > > > >>>>>>>>>> - Make having an encoded reg-width mandatory rather then using 0 to encode
> > > > > > > > > >>>>>>>>>>   8 bit width making reg-addresses without an encoded width default to
> > > > > > > > > >>>>>>>>>>   a width of 8
> > > > > > > > > >>>>>>>>>> - Add support for 64 bit wide registers
> > > > > > > > > >>>>>>>>
> > > > > > > > > >>>>>>>> I'm in two minds about this. This means that the read and write
> > > > > > > > > >>>>>>>> functions take a u64 argument, which will be less efficient on 32-bit
> > > > > > > > > >>>>>>>> platforms. I think it would be possible, with some macro magic, to
> > > > > > > > > >>>>>>>> accept different argument sizes, but maybe that's a micro-optimization
> > > > > > > > > >>>>>>>> that would actually result in worse code. 
> > > > > > > > > >>>>>>>>
> > > > > > > > > >>>>>>>> 64-bit support could be useful, but as far as I can tell, it's not used
> > > > > > > > > >>>>>>>> in this series, so maybe we could leave this for later ?
> > > > > > > > > >>>>>>>
> > > > > > > > > >>>>>>> I prefer to have it now, I just told Tommaso working on the Alvium driver
> > > > > > > > > >>>>>>> to use this, and he needs 64-bit access. :-)
> > > > > > > > > >>>>>>>
> > > > > > > > > >>>>>>> You could also easily have 32-bit and 64-bit variant of the functions, with
> > > > > > > > > >>>>>>> C11 _Generic(). Introducing it now would be easier than later.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> I took a quick look at C11 _Generic() and that looks at the type
> > > > > > > > > >>>>>> of "things" so in this case it would look at type of the val argument.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> Problem is that that can still be e.g. an int when doing a
> > > > > > > > > >>>>>> read/write from a 64 bit registers.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> So we would then need to handle the 64 bit width case in the 32
> > > > > > > > > >>>>>> bit versions of the functions too.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> And likewise I can see someone passing a long on a 64 bit
> > > > > > > > > >>>>>> arch while doing a cci_write() to a non 64 bit register.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> So this would basically mean copy and pasting cci_read()
> > > > > > > > > >>>>>> + cci_write() 2x with the only difference being one
> > > > > > > > > >>>>>> variant taking a 32 bit val argument and the other a
> > > > > > > > > >>>>>> 64 bit val argument.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> This seems like premature optimization to me.
> > > > > > > > > >>>>>>
> > > > > > > > > >>>>>> As mentioned in my reply to Laurent if we want to
> > > > > > > > > >>>>>> optimize things we really should look at avoiding
> > > > > > > > > >>>>>> unnecessary i2c transfers, or packing multiple
> > > > > > > > > >>>>>> writes into a single i2c transfer for writes to
> > > > > > > > > >>>>>> subsequent registers. That is where significant
> > > > > > > > > >>>>>> speedups can be made.
> > > > > > > > > >>>>>
> > > > > > > > > >>>>> This is something I'd really like to see, but it's way more work.
> > > > > > > > > >>>>>
> > > > > > > > > >>>>> There's an important need of applying changes atomically, which is often
> > > > > > > > > >>>>> not possible to strictly guarantee over I2C. Userspace ends up writing
> > > > > > > > > >>>>> V4L2 controls as quickly as it can after the start of a frame, hoping
> > > > > > > > > >>>>> they will all reach the sensor before the end of the frame. Some
> > > > > > > > > >>>>> platforms have camera-specific I2C controllers that have the ability to
> > > > > > > > > >>>>> buffer I2C transfers and issue them based on a hardware trigger. How to
> > > > > > > > > >>>>> fit this in thé kernel I2C API will be an interesting exercise.
> > > 
> > > -- 
> > > Regards,
> > > 
> > > Laurent Pinchart
> 
> -- 
> Regards,
> 
> Laurent Pinchart



[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux