Hi Sakari,
Ok - V3 is now closer :)
I'm just trying to do a first spin of adding fwnode_graph_get_port_parent(),
then I can post a v3 series.
On 16/05/17 23:26, Sakari Ailus wrote:
> Hi Kieran,
>
> On Tue, May 16, 2017 at 01:56:05PM +0100, Kieran Bingham wrote:
> ...
>>>>>> +static int adv748x_afe_g_input_status(struct v4l2_subdev *sd, u32
>>>>>> *status)
>>>>>> +{
>>>>>> + struct adv748x_state *state = adv748x_afe_to_state(sd);
>>>>>> + int ret;
>>>>>> +
>>>>>> + ret = mutex_lock_interruptible(&state->mutex);
>>>>>
>>>>> I wonder if this is necessary. Do you expect the mutex to be taken for
>>>>> extended periods of time?
>>>>
>>>> It looks like the only other adv* driver to take a lock here is the 7180.
>>>> Perhaps that is where the heritage of this code derived from.
>>>>
>>>> I don't think the locking should be held for a long time anywhere, but I
>>>> will
>>>> try to go through and consider all the locking throughout the code base.
>>>>
>>>> At the moment I think anything that calls adv748x_afe_status() should be
>>>> locked
>>>> to ensure serialisation through adv748x_afe_read_ro_map().
>>>
>>> I meant whether you need the "_interruptible" part. It's quite a bit of
>>> repeating error handling that looks mostly unnecessary.
>>>
>>
>> Aha - I see what you mean now...
>>
>> Most of these use I2C transactions though, so that would be our source of
>> any delay.
>>
>> If it's acceptable to expect an I2C bus to never hang, or if the I2C
>> subsystem
>> can handle that, then we can chop the interruptible ... but I'm not sure I2C
>> bus
>> transactions are guaranteed like that ? Don't things like clock stretching,
>> and
>> unreliable hardware leave us vulnerable there...
>
> $ git grep mutex_lock_interruptible -- drivers/media/i2c/
> drivers/media/i2c/adv7180.c: int err =
> mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: int ret =
> mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: int ret =
> mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: int ret =
> mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: ret = mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: int ret =
> mutex_lock_interruptible(&state->mutex);
> drivers/media/i2c/adv7180.c: ret = mutex_lock_interruptible(&state->mutex);
>
> That's all.
>
Ok - I've stripped out the _interruptibles, and adapted the control lock to use
the state lock - that cleaned up the controls too :)
> ...
>
>>>>>> +int adv748x_afe_probe(struct adv748x_state *state, struct device_node
>>>>>> *ep)
>>>>>> +{
>>>>>> + int ret;
>>>>>> + unsigned int i;
>>>>>> +
>>>>>> + state->afe.streaming = false;
>>>>>> + state->afe.curr_norm = V4L2_STD_ALL;
>>>>>> +
>>>>>> + adv748x_subdev_init(&state->afe.sd, state, &adv748x_afe_ops,
>>>>>> "afe");
>>>>>> +
>>>>>> + /* Ensure that matching is based upon the endpoint fwnodes */
>>>>>> + state->afe.sd.fwnode = &ep->fwnode;
>>>>>
>>>>> I wonder if you really need to convert all users of async matching to use
>>>>> endpoints --- could you opportunistically peek if the device node matches,
>>>>> just in case? You can't have an accidental positive match anyway.
>>>>>
>>>>> So, the match is now for plain fwnode pointers, and it would be:
>>>>>
>>>>> return async->fwnode == fwnode ||
>>>>> port_parent(parent(async->fwnode)) == fwnode ||
>>>>> async->fwnode == port_parent(parent(fwnode));
>>>>
>>>>
>>>> If we adapt the core to match against endpoint comparisons and device node
>>>> comparisons then yes we wouldn't have to adapt everything, I.e. we
>>>> wouldn't have
>>>> to change all the async devices - but we would have to adapt all the
>>>> bus/bridge
>>>> drivers (those who perform the v4l2_async_notifier_register() call) as
>>>> they must
>>>> register their notifier against an endpoint if they are to ever be able to
>>>> connect to an ADV748x or other device which will rely upon multiple
>>>> endpoints.
>>>
>>> If there really is a need to, we can add a new framework helper function for
>>> that --- as I think Niklas proposed. I'm not really sure it should be really
>>> needed though; e.g. the omap3isp driver does without that.
>>>
>>
>> I'm afraid I don't understand what you mean by omap3isp doing without ...
>
> Sorry. I think I lost you somewhere --- I meant matching in the few drivers
> that compare fwnodes. That'd break as a result unless the matching was
> updated accordingly.
>
> It'd be nice to remove that matching as well though but I think it'd be
> safer not to.
>
Ah ok - The bit I missed then is that there are *other* matches elsewhere...
>>
>> In omap3isp/isp.c: isp_fwnodes_parse() the async notifier is registered
>> looking
>> at the endpoints parent fwnode:
>>
>> isd->asd.match.fwnode.fwnode =
>> fwnode_graph_get_remote_port_parent(fwnode);
>>
>> This would therefore not support ADV748x ... (it wouldn't know which TX/CSI
>> entity to match against)
>>
>> So the way I see it is that all devices which currently register an async
>> notifier should now register the match against the endpoint instead of the
>> parent device:
>>
>> - isd->asd.match.fwnode.fwnode =
>> fwnode_graph_get_remote_port_parent(fwnode);
>> + isd->asd.match.fwnode.fwnode = fwnode;
>>
>> And then if we adapt the match to check against:
>> fwnode == fwnode || fwnode == fwnode_graph_get_remote_port_parent(fwnode);
>
> That's not enough as a master driver may use device node whereas the
> sub-device driver uses endpoint node. You need to do it both ways.
>
> It's port parent, not endpoint's. There is / will be
> fwnode_get_port_parent(), too.
Ahem - yes - this bit me yesterday - I blindly went in and got the 'parent'
using fwnode_graph_get_remote_port_parent(), which of course was then the parent
of the local node, not the remote - and threw me right off the track!
Have started trying to add fwnode_get_port_parent() to match the needs :)
>
>>
>> This would then support existing sensor/remote devices which still store
>> their
>> (default) device fwnode, but also match specifically against devices which
>> store
>> their endpoint fwnode...
>>
>> So this looks like the following drivers would need to be updated:
>>
>> (users of fwnode.fwnode:)
>> drivers/media/platform/am437x/am437x-vpfe
>> drivers/media/platform/atmel/atmel-isc.c
>> drivers/media/platform/exynos4-is/media-dev.c
>> drivers/media/platform/omap3isp/isp.c
>> drivers/media/platform/pxa_camera.c
>> drivers/media/platform/rcar-vin
>> drivers/media/platform/soc_camera/soc_camera.c
>> drivers/media/platform/ti-vpe/cal.c
>> drivers/media/platform/xilinx/xilinx-vipp.c
>
> Sounds good to me.
>
> ...
>
>>>>>> +static int adv748x_parse_dt(struct adv748x_state *state)
>>>>>> +{
>>>>>> + struct device_node *ep_np = NULL;
>>>>>> + struct of_endpoint ep;
>>>>>> + unsigned int found = 0;
>>>>>> + int ret;
>>>>>> +
>>>>>
>>>>> Would of_graph_get_remote_node() do this more simple? Not necessarily,
>>>>> just
>>>>> wondering.
>>>>
>>>> I'm not certain I understand, but I don't think so.
>>>>
>>>> Up to 12 ports could potentially be mapped in the DT. I want to enumerate
>>>> all of
>>>> them:
>>>>
>>>> enum adv748x_ports {
>>>> ADV748X_PORT_HDMI = 0,
>>>> ADV748X_PORT_AIN1 = 1,
>>>> ADV748X_PORT_AIN2 = 2,
>>>> ADV748X_PORT_AIN3 = 3,
>>>> ADV748X_PORT_AIN4 = 4,
>>>> ADV748X_PORT_AIN5 = 5,
>>>> ADV748X_PORT_AIN6 = 6,
>>>> ADV748X_PORT_AIN7 = 7,
>>>> ADV748X_PORT_AIN8 = 8,
>>>> ADV748X_PORT_TTL = 9,
>>>> ADV748X_PORT_TXA = 10,
>>>> ADV748X_PORT_TXB = 11,
>>>> ADV748X_PORT_MAX = 12,
>>>> };
>>>>
>>>> Whilst currently we are hardwired to input from AIN8 on the AFE (a Todo to
>>>> adapt), I would envisage that there might be entities described in the DT
>>>> to
>>>> state which ports have connections on them.
>>>
>>> Indeed. I was thinking of this code would look like if one was using
>>> of_graph_get_remote_node().
>>>
>>>>
>
> Rob was pushing for that and I argued against. ;-) But please use it if it
> works better. As an interface it is more simple, but there's a number of
> ports to check.
>
> It made a bunch of drivers cleaner but then again V4L2 fwnode parses a lot
> of this already.
>
>>>> (available) inputs as well - but that's out of scope for now - and we
>>>> don't have
>>>> a way to forward the 'inputs' through to the master driver.
>>>>
>>>>>> + for_each_endpoint_of_node(state->dev->of_node, ep_np) {
>>>>>> + ret = of_graph_parse_endpoint(ep_np, &ep);
>>>
>>> of_graph_parse_endpoint() always succeeds.
I've adjusted for the always succeeds comment and reduced the indent level.
>>>
>>> Do you call it for other purposes than to print information on the endpoint?
>>
>> To get the port and verify it.
>>
>> Now I think I see where you were going with of_graph_get_remote_node().
>> This could just loop through 'known port' values instead... removing the
>> need to
>> parse_endpoint, and have other error checks...
And also - having looked properly - realised I don't want to use
of_graph_get_remote_node() here - This is the local nodes :)
I've kept the for_each_endpoint_of_node() - It doesn't make sense to use
of_graph_get_endpoint_by_regs() - as that just uses for_each_endpoint_of_node()
to iterate to find by reg.
...
>>
>> Don't worry about the code above - It's all been deleted.
>>
>> I realised I was using the async notifiers to register the AFE/HDMI entities
>> but
>> it was completely overkill.
>
> Ack. Good. Sometimes you figure out how best do something while explaining
> it to others... :-) (I was happy to listen.)
:D
>
> ...
>
>>>>>> diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c
>>>>>> b/drivers/media/i2c/adv748x/adv748x-hdmi.c
>>>>>> new file mode 100644
>>>>>> index 000000000000..19c1bd41cc6c
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c
>>>>>> @@ -0,0 +1,671 @@
>>>
>>> ...
>>>
>>>>>> +static const struct v4l2_dv_timings_cap adv748x_hdmi_timings_cap = {
>>>>>> + .type = V4L2_DV_BT_656_1120,
>>>>>> + /* keep this initialization for compatibility with GCC < 4.4.6
>>>>>> */
>>>>>> + .reserved = { 0 },
>>>>>
>>>>> Is this necessary? Aren't the uninitialised fields zeroed if any field in
>>>>> a
>>>>> struct is initialised, also on those versions of GCC? (Of course there
>>>>> have
>>>>> been bugs, but nothing rings a bell.)
>>>>
>>>> Looks like it is necessary:
>>>> https://patchwork.kernel.org/patch/2851851/
>>>
>>> This is related to the anonymous union. What I'm saying appears unrelated
>>> --- if any struct field is initialised, then the rest of the fields of the
>>> struct are initialised to zero by the compiler (unless explicitly
>>> initialised to something else).
>>>
>>> I.e. you can drop ".reserved = { 0 }," line.
>>
>> In that patch I referenced, (several of the drivers were all updated in a
>> similar fashion) Gianluca mentioned the following:
>>
>>>
>>> Please note that I have also to init the reserved space as otherwise GCC
>>> fails with this error:
>>>
>>> CC [M] adv7842.o
>>> adv7842.c:549: error: field name not in record or union initializer
>>> adv7842.c:549: error: (near initialization for
>>> 'adv7842_timings_cap_analog.reserved')
>>> adv7842.c:549: warning: braces around scalar initializer
>>> adv7842.c:549: warning: (near initialization for
>>> 'adv7842_timings_cap_analog.reserved[0]')
>
> I had to test that here. :-) Ouch. And I'm left wondering how does the
> initialisation of the reserved field get things working again...
>
> Anyway, please ignore the original comment.
Thanks for testing directly.
>
>>
>> Therefore my understanding was that it was necessary.
>>
>> If not - then we can remove from the following drivers too:
>>
>> git grep ".reserved = { 0 }"
>> drivers/media/i2c/ad9389b.c: .reserved = { 0 },
>> drivers/media/i2c/adv7511.c: .reserved = { 0 },
>> drivers/media/i2c/adv7604.c: .reserved = { 0 },
>> drivers/media/i2c/adv7604.c: .reserved = { 0 },
>> drivers/media/i2c/adv7842.c: .reserved = { 0 },
>> drivers/media/i2c/adv7842.c: .reserved = { 0 },
>> drivers/media/i2c/tc358743.c: .reserved = { 0 },
>> drivers/media/i2c/ths8200.c: .reserved = { 0 },
>> drivers/media/platform/vivid/vivid-vid-common.c: .reserved = { 0 },
>> drivers/media/spi/gs1662.c: .reserved = { 0 },
>> samples/v4l/v4l2-pci-skeleton.c: .reserved = { 0 },
>>
>> But maybe we should test with an older compiler to verify this...
>>
>> Is there a cut-off point where we would stop supporting older compilers?
>
> I guess when people stop submitting patches to support them? :-)
That'll be it :)
>
> Documentation/admin-guide/README.rst says that at least GCC 3.2 should be
> used. That's very, very old. I wonder if anyone has recently used such an
> old version...
>