[PATCH 1/3] pinctrl: add driver for Amlogic Meson SoCs

Linus Walleij linus.walleij at linaro.org
Tue Oct 28 07:11:05 PDT 2014


On Wed, Oct 22, 2014 at 10:06 PM, Beniamino Galvani <b.galvani at gmail.com> wrote:
> On Tue, Oct 21, 2014 at 03:39:25PM +0200, Linus Walleij wrote:

>> > +static int meson_gpio_of_xlate(struct gpio_chip *chip,
>> > +                              const struct of_phandle_args *gpiospec,
>> > +                              u32 *flags)
>> > +{
>> > +       unsigned gpio = gpiospec->args[0];
>> > +
>> > +       if (gpio < chip->base || gpio >= chip->base + chip->ngpio)
>> > +               return -EINVAL;
>> > +
>> > +       if (flags)
>> > +               *flags = gpiospec->args[1];
>> > +
>> > +       return gpio - chip->base;
>> > +}
>>
>> Why is this necessary? We want to get rid of all use of
>> chip->base so introducing new users is not nice.
>
> The driver instantiates one pinctrl device with 136 pins and two
> gpio_chips, one with 120 gpios and the other with 16 (for more
> details, see below). The macros for pins in the header file use a
> single range from 0 to 135 that matches the order of pins in the
> pinctrl device:
>
>         /* First gpio-chip */
>         #define GPIOX_0         0
>         [...]
>         #define BOOT_18         119
>
>         /* Second gpio-chip */
>         #define GPIOAO_0        120
>         [...]
>         #define GPIO_TEST_N     135
>
> Since the macros are also used in DT as GPIO numbers, this function
> translates that value to the relative offset for the gpio chip.

That is not wise. You should let each gpio_chip register its
chip with base = -1, so they get whatever random GPIO numbers
they get, then register the pin range relatively to what they
get from the gpiochip side using gpiochip_add_pin_range().

>> The default of_gpio_simple_xlate() should be enough,
>> don't you agree?
>
> Probably yes, but for it to work then I have either to:
>  - change the pin macros to use a relative value
>
>         /* First gpio-chip */
>         #define GPIOX_0         0
>         [...]
>         #define BOOT_18         119
>
>         /* Second gpio-chip */
>         #define GPIOAO_0        0
>         [...]
>         #define GPIO_TEST_N     15
>
>  - or use a single gpio chip

Or (C) register the pin ranges from the gpio_chip side instead
of doing it from the pin controller side. Look at how
gpiochip_add_pin_range() works, I inisist.

>> > +       /* Copy group and function definitions from domains to pinctrl */
>> > +       pc->groups = devm_kzalloc(pc->dev, pc->num_groups *
>> > +                                 sizeof(struct meson_pmx_group), GFP_KERNEL);
>> > +       pc->funcs = devm_kzalloc(pc->dev, pc->num_funcs *
>> > +                                 sizeof(struct meson_pmx_func), GFP_KERNEL);
>> > +       if (!pc->groups || !pc->funcs)
>> > +               return -ENOMEM;
>>
>> Again more copying. Why can't we just have one set of this data
>> and only pass pointers?
>
> This code copies information on groups and functions from the
> different domains and merge it in a single array so that the driver
> can look it up easily.
>
> Probably the initial information should not be splitted so that it can
> be reused without additional copies.

Yeah I will look at V2 and see how it looks...

>> Why can't static arrays and ARRAY_SIZE() be used throughout
>> instead, just pass around pointers?
>
> The goal of the dynamic code is to simplify the declaration of groups,
> which can be done with a single statement in the form:
>
>         GROUP(_name, _reg, _bit, _pins...)
>
> for example:
>
>         GROUP(sdxc_d0_c,        4,      30,     BOOT_0),
>         GROUP(sdxc_d13_c,       4,      29,     BOOT_1, BOOT_2, BOOT_3),
>         GROUP(sdxc_d47_c,       4,      28,     BOOT_4, BOOT_5, BOOT_6, BOOT_7),
>         GROUP(sdxc_cmd_c,       4,      27,     BOOT_16),
>         GROUP(sdxc_clk_c,       4,      26,     BOOT_17),
>         GROUP(nand_io,          2,      26,     BOOT_0, BOOT_1, BOOT_2, BOOT_3,
>                                                 BOOT_4, BOOT_5, BOOT_6, BOOT_7),
>
> instead of having to define an array of pins and reference it in the
> group declaration. The same goes for functions. I admit that this is a
> bit hackish, I will stick to the classical way in the next respin.

OK thanks.

>> > +/**
>> > + * struct meson_domain
>> > + *
>> > + * @reg_mux:   registers for mux settings
>> > + * @reg_pullen:        registers for pull-enable settings
>> > + * @reg_pull:  registers for pull settings
>> > + * @reg_gpio:  registers for gpio settings
>> > + * @mux_size:  size of mux register range (in words)
>> > + * @pullen_size:size of pull-enable register range
>> > + * @pull_size: size of pull register range
>> > + * @gpio_size: size of gpio register range
>> > + * @chip:      gpio chip associated with the domain
>> > + * @data;      platform data for the domain
>> > + * @node:      device tree node for the domain
>> > + * @gpio_range:        gpio range that maps domain gpios to the pin controller
>> > + * @lock:      spinlock for accessing domain registers
>> > + *
>> > + * A domain represents a set of banks controlled by the same set of
>> > + * registers. Typically there is a domain for the normal banks and
>> > + * another one for the Always-On bus.
>> > + */
>>
>> Can I get a long-ish explanation of the domains vs banks etc
>> because that's really key to understanding this driver!
>
> Yes, I hope that the following explanation is clear enough. If anyone
> wants to know the details, the relevant information can be found in
> the Amlogic sources available at:
>
> http://openlinux.amlogic.com:8000/download/ARM/kernel/
>
> The GPIOs are organized in banks (X,Y,DV,H,Z,BOOT,CARD,AO) and each
> bank has a number of GPIOs variable from 7 to 30.
>
> There are different register sets for changing pins properties:
>  - for all banks except AO:
>         <0xc11080b0 0x28> for mux configuration
>         <0xc11080e4 0x18> for pull-enable configuration
>         <0xc1108120 0x18> for pull configuration
>         <0xc1108030 0x30> for gpio (in/out/dir) configuration
>
>  - for AO bank
>         <0xc8100014 0x4> for mux configuration
>         <0xc810002c 0x4> for pull and pull-enable configuration
>         <0xc8100024 0x8> for gpio (in/out/dir) configuration
>
> The regular banks belong to the "standard" power domain, while AO
> belongs to the Always-On power domain, which, like the name says,
> can't be powered off.
>
> Each bank uses contiguous ranges of bits in the register sets
> described above and the same register can be used by different banks
> (for example, for the pull-enable configuration the BOOT bank uses
> bits [0:18] of 0xc11080f0 and the CARD bank uses bits [20:25]).
>
> In addition to this, there seem to be some other registers, shared
> between all the banks, for the interrupt functionality.

I get it now I think, thanks!

Arguably the whole shebang is one big hardware unit so the right
thing is indeed to have a single driver for all of it.

> The driver then instantiates a gpio_chip for each subnode and a single
> pinctrl device.

This is the right design. We just need to hash out the details.

Yours,
Linus Walleij



More information about the linux-arm-kernel mailing list