[U-Boot] [PATCH v4 03/33] pinctrl: Add the concept of peripheral IDs

Masahiro Yamada
2015-08-27T04:39:41Z

2015-08-26 22:20 GMT+09:00 Simon Glass <sjg@chromium.org>:
> Hi Masahiro,
>
> On 25 August 2015 at 21:51, Masahiro Yamada
> <yamada.masahiro@socionext.com> wrote:
>> 2015-08-26 13:38 GMT+09:00 Simon Glass <sjg@chromium.org>:
>>> Hi Masahiro,
>>>
>>> On 25 August 2015 at 21:30, Masahiro Yamada
>>> <yamada.masahiro@socionext.com> wrote:
>>>> Hi Simon,
>>>>
>>>>
>>>>
>>>> 2015-08-25 0:12 GMT+09:00 Simon Glass <sjg@chromium.org>:
>>>>> My original pinctrl patch operating using a peripheral ID enum. This was
>>>>> shared between pinmux and clock and provides an easy way to specify a device
>>>>> that needs to be controlled, even it is does not (yet) have a driver within
>>>>> driver model.
>>>>>
>>>>> Masahiro's new simple pinctrl gets around this by providing a
>>>>> set_state_simple() pinctrl method. By passing a device to that call the
>>>>> peripheral ID becomes unnecessary. If the driver needs it, it can calculate
>>>>> it itself and use it internally.
>>>>>
>>>>> However this does not solve the problem for peripheral clocks. The 'pure'
>>>>> solution would be to pass a driver to the clock uclass also. But this
>>>>> requires that all devices should have a driver, and a struct udevide. Also
>>>>> a key optimisation of the clock uclass is allowing a peripheral clock to
>>>>> be set even when there is no device for that clock.
>>>>>
>>>>> There may be a better way to achive the same goal, but for now it seems
>>>>> expedient to add in peripheral ID to the pinctrl uclass. Two methods are
>>>>> added - one to get the peripheral ID and one to select it. The existing
>>>>> set_state_simple() is effectively the union of these.
>>>>>
>>>>> Signed-off-by: Simon Glass <sjg@chromium.org>
>>>>> ---
>>>>>
>>>>> Changes in v4: None
>>>>> Changes in v3: None
>>>>> Changes in v2: None
>>>>>
>>>>> drivers/pinctrl/pinctrl-uclass.c | 33 ++++++++++++++++++++++
>>>>> include/dm/pinctrl.h | 61 ++++++++++++++++++++++++++++++++++++++++
>>>>> 2 files changed, 94 insertions(+)
>>>>>
>>>>> diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
>>>>> index 01b0cf8..1d90fb0 100644
>>>>> --- a/drivers/pinctrl/pinctrl-uclass.c
>>>>> +++ b/drivers/pinctrl/pinctrl-uclass.c
>>>>> @@ -9,6 +9,7 @@
>>>>> #include <dm/device.h>
>>>>> #include <dm/lists.h>
>>>>> #include <dm/pinctrl.h>
>>>>> +#include <dm/root.h>
>>>>> #include <dm/uclass.h>
>>>>> #include <linux/err.h>
>>>>> #include <linux/list.h>
>>>>> @@ -36,9 +37,41 @@ int pinctrl_select_state(struct udevice *dev, const char *ignored)
>>>>> return ops->set_state_simple(pctldev, dev);
>>>>> }
>>>>>
>>>>> +int pinctrl_request(struct udevice *dev, int func, int flags)
>>>>> +{
>>>>> + struct pinctrl_ops *ops = pinctrl_get_ops(dev);
>>>>> +
>>>>> + if (!ops->request)
>>>>> + return -ENOSYS;
>>>>> +
>>>>> + return ops->request(dev, func, flags);
>>>>> +}
>>>>> +
>>>>> +int pinctrl_request_noflags(struct udevice *dev, int func)
>>>>> +{
>>>>> + return pinctrl_request(dev, func, 0);
>>>>> +}
>>>>> +
>>>>> +int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph)
>>>>> +{
>>>>> + struct pinctrl_ops *ops = pinctrl_get_ops(dev);
>>>>> +
>>>>> + if (!ops->get_periph_id)
>>>>> + return -ENOSYS;
>>>>> +
>>>>> + return ops->get_periph_id(dev, periph);
>>>>> +}
>>>>
>>>>
>>>> If _get_periph_id() is shared between clk and pinctrl (that what I understood
>>>> from your statement), where is it defined? Under arch/arm/mach-<soc>/ ?
>>>
>>> Yes.
>>>
>>>>
>>>>
>>>>
>>>>
>>>>> +static int pinctrl_post_bind(struct udevice *dev)
>>>>> +{
>>>>> + /* Scan the bus for devices */
>>>>> + return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
>>>>> +}
>>>>
>>>>
>>>> I do not think this work.
>>>>
>>>> dm_scan_fdt_node() requires child nodes to be compatible to something
>>>> for binding.
>>>>
>>>> Pin configuration nodes do not have '.compatible' properties.
>>>
>>> True in many cases, in which case it does not harm, but Rockchip has them:
>>>
>>> http://git.denx.de/?p=u-boot-dm.git;a=blob;f=arch/arm/dts/rk3288.dtsi;h=0f497099679470ea39078d6ca9e5b1ae550995b0;hb=refs/heads/rockchip-working
>>
>>
>> My bad.
>>
>> It is possible a pinctrl device can have other devices under it (in
>> this case, GPIO).
>>
>> So, it turned out my patch should be fixed.
>> device_bind_driver_to_node() should be called for devices that have no
>> .compatible.
>>
>
> OK.

So, dm_scan_fdt_node() should be moved to rk3288_pinctrl_bind(), I think.

Having GPIO nodes under the pinctrl node is a rockchip-specific matter.

>>
>>
>>
>>>>
>>>>
>>>>
>>>>
>>>>> UCLASS_DRIVER(pinctrl) = {
>>>>> .id = UCLASS_PINCTRL,
>>>>> .name = "pinctrl",
>>>>> + .post_bind = pinctrl_post_bind,
>>>>> };
>>>>>
>>>>> #else
>>>>> diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h
>>>>> index b2ba0b4..2f9bf67 100644
>>>>> --- a/include/dm/pinctrl.h
>>>>> +++ b/include/dm/pinctrl.h
>>>>> @@ -85,10 +85,37 @@ struct pinctrl_ops {
>>>>> int (*pinconf_group_set)(struct udevice *dev, unsigned group_selector,
>>>>> unsigned param, unsigned argument);
>>>>> int (*set_state)(struct udevice *dev, struct udevice *config);
>>>>> +
>>>>> /* for pinctrl-simple */
>>>>> int (*set_state_simple)(struct udevice *dev, struct udevice *periph);
>>>>> + /**
>>>>> + * request() - Request a particular pinctrl function
>>>>> + *
>>>>> + * This activates the selected function.
>>>>> + *
>>>>> + * @dev: Device to adjust (UCLASS_PINCTRL)
>>>>> + * @func: Function number (driver-specific)
>>>>> + * @return 0 if OK, -ve on error
>>>>> + */
>>>>> + int (*request)(struct udevice *dev, int func, int flags);
>>>>> +
>>>>> + /**
>>>>> + * get_periph_id() - get the peripheral ID for a device
>>>>> + *
>>>>> + * This generally looks at the peripheral's device tree node to work
>>>>> + * out the peripheral ID. The return value is normally interpreted as
>>>>> + * enum periph_id. so long as this is defined by the platform (which it
>>>>> + * should be).
>>>>> + *
>>>>> + * @dev: Pinctrl device to use for decoding
>>>>> + * @periph: Device to check
>>>>> + * @return peripheral ID of @periph, or -ENOENT on error
>>>>> + */
>>>>> + int (*get_periph_id)(struct udevice *dev, struct udevice *periph);
>>>>> };
>>>>>
>>>>> +#define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops)
>>>>> +
>>>>> /**
>>>>> * Generic pin configuration paramters
>>>>> *
>>>>> @@ -217,4 +244,38 @@ static inline int pinctrl_generic_set_state(struct udevice *pctldev,
>>>>> }
>>>>> #endif
>>>>>
>>>>> +/**
>>>>> + * pinctrl_request() - Request a particular pinctrl function
>>>>> + *
>>>>> + * @dev: Device to check (UCLASS_PINCTRL)
>>>>> + * @func: Function number (driver-specific)
>>>>> + * @flags: Flags (driver-specific)
>>>>> + * @return 0 if OK, -ve on error
>>>>> + */
>>>>> +int pinctrl_request(struct udevice *dev, int func, int flags);
>>>>> +
>>>>> +/**
>>>>> + * pinctrl_request_noflags() - Request a particular pinctrl function
>>>>> + *
>>>>> + * This is similar to pinctrl_request() but uses 0 for @flags.
>>>>> + *
>>>>> + * @dev: Device to check (UCLASS_PINCTRL)
>>>>> + * @func: Function number (driver-specific)
>>>>> + * @return 0 if OK, -ve on error
>>>>> + */
>>>>> +int pinctrl_request_noflags(struct udevice *dev, int func);
>>>>> +
>>>>> +/**
>>>>> + * pinctrl_get_periph_id() - get the peripheral ID for a device
>>>>> + *
>>>>> + * This generally looks at the peripheral's device tree node to work out the
>>>>> + * peripheral ID. The return value is normally interpreted as enum periph_id.
>>>>> + * so long as this is defined by the platform (which it should be).
>>>>> + *
>>>>> + * @dev: Pinctrl device to use for decoding
>>>>> + * @periph: Device to check
>>>>> + * @return peripheral ID of @periph, or -ENOENT on error
>>>>> + */
>>>>> +int pinctrl_get_periph_id(struct udevice *dev, struct udevice *periph);
>>>>> +
>>>>> #endif /* __PINCTRL_H */
>>>>
>>>>
>>>>
>>>> I am guessing these functions are only invoked from .set_state_simple(),
>>>> If so, should they be exported to struct pinctrl_ops?
>>>>
>>>> I expect callbacks are invoked from the core framework (uclass).
>>>>
>>>
>>> They can be involved from other places. In particular you need to call
>>> get_periph_id() to get the peripheral ID for use with clocks.
>>>
>>
>>
>> In the first place, pinctrl_get_periph_id() should not be defined in
>> a pinctrl driver.
>>
>> The first argument, pinctrl device, is not needed to calculate the
>> peripheral ID,
>> and the actual definition is placed under mach-<soc>, right?
>
> So are you suggesting that each SoC provides a function (not in the
> driver model framework) to get the peripheral ID in the simple pinctrl
> case? This might be similar to clock_decode_periph_id(const void
> *blob, int node) in tegra.

Only for those SoCs that use pinctrl-simple and clk-simple.

Given that the peripheral ID is driver-wide concept that is shared
between pinctrl-simple and clk-simple,
the ID decoder should be placed in common location, so that
pinctrl-simple should not depends on clk-simple, and vice versa.

> In fact if we implement a full clock controller binding (similar to
> how you have implemented pinctrl) then we can avoid the need for
> peripheral IDs once driver model is fully up. The need then exists
> only in SPL, due to code size/memory constraints. It may perhaps also
> be needed before relocation in U-Boot proper due to execution time
> constraints but we can limit the number of devices brought up using
> u-boot,dm-pre-reloc.
>
> It would be good to limit the spread of the peripheral ID and only use
> it when needed.
>
> I'll take a look at creating a function outside of pinctrl which
> returns a peripheral ID. That deals with the get_periph_id() method in
> pinctrl.
>
> However this still leaves the request() method - which takes a
> peripheral ID. This is needed I think because:the device being set up
> might not have a udevice in SPL. What do you think?
>
> Regards,
> Simon
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

--
Best Regards
Masahiro Yamada