Re: [RFC PATCH] drivers/pinctrl: Add pinctrl-ast2400

From: Andrew Jeffery
Date: Wed May 25 2016 - 01:22:39 EST


Hi Linus,

On Mon, 2016-05-23 at 14:38 +0200, Linus Walleij wrote:
> Hi sorry for taking so long before reviewing. Too busy, what can I say.

No worries, I expected as much. Thanks for taking the time!

>
> On Fri, May 6, 2016 at 8:20 AM, Andrew Jeffery <andrew@xxxxxxxx> wrote:
>
> >
> > Add pinctrl/pinmux support for the Aspeed AST2400 SoC. Configuration of
> > the SoC is somewhat involved: Enabling functions can involve writes of
> > multiple bits to multiple registers, and signals provided by a pin are
> > determined on a priority basis. That is, without care, it's possible to
> > configure a function in the mux and to not gain expected functionality.
> >
> > Signed-off-by: Andrew Jeffery <andrew@xxxxxxxx>
> >
> > +#include
> > +#include
> > +#include
> > +#include
> You should include your changes to Kconfig and Makefile in the patch
> so it is a complete driver. This is an example of why: if I can't see if
> your driver is really tristate in Kconfig I don't know whether
> should be included or not.
>
> If it is a bool don't include this.
> If it is a bool, don't use any MODULE_* macros either.

Okay. I'll do so when I send follow-up patches.

>
> >
> > +/* Challenges in the AST2400 Multifunction Pin Design
> > + * --------------------------------------------------
> > + *
> > + * * Reasonable number of pins (216)
> > + *
> > + * * The SoC function enabled on a pin is determined on a priority basis
> > + *
> > + * * Using the priority system, pins can provide up to 3 different signals
> > + *ÂÂÂtypes
> > + *
> > + * * The signal active on a pin is often described by compound logical
> > + *ÂÂÂexpressions involving multiple operators, registers and bits
> > + *
> > + *ÂÂÂ* The high and low priority functions' bit masks are frequently not the
> > + *ÂÂÂÂÂsame
> > + *ÂÂÂÂÂ(i.e. cannot just flip a bit to change from high to low), or even in the
> > + *ÂÂÂÂÂsame register.
> > + *
> > + *ÂÂÂ* Not all functions are disabled by unsetting bits, some require setting
> > + *ÂÂÂÂÂbits
> > + *
> > + *ÂÂÂ* Not all signals can be deactivated as some expressions depend on values
> > + *ÂÂÂÂÂin the hardware strapping register, which is treated as read-only.
> Try to compresse the bullet list to text. This looks like a powerpoint
> presentation.

Will do.

>
> >
> > + * SoC Multi-function Pin Expression Examples
> > + * ------------------------------------------
> > + *
> > + * Here are some sample mux configurations from the datasheet to illustrate the
> > + * corner cases, roughly in order of least to most corner. In the table, HP and
> > + * LP are high- and low- priority respectively.
> I believe that you got the hardware details right. Only someone with
> experience with the same hardware could review these gory details.
> So I will just trust that you got that part right.
>
> >
> > + * * Pins provide two to three signals in a priority order
> > + *
> > + * * For priorities levels defined on a pin, each priority provides one signal
> > + *
> > + * * Enabling lower priority signals requires higher priority signals be
> > + *ÂÂÂdisabled
> (...)
> >
> > + * * A signal at a given priority on a given pin is active if any of the
> > + *ÂÂÂfunctions in which the signal participates are active, and no higher
> > + *ÂÂÂpriority signal on the pin is active
> That's a pretty baroque design. I wonder who came up with the idea
> that this needed to be a priority-based state machine thing. Did they
> have a usecase of different software threads independently competing
> about using the hardware or what?
>
> Or is it some hardware aid to help the programmer from shooting
> him/herself in the foot?

The datasheet doesn't appear to explain the motivation, so we're in the
dark.

>
> >
> > +#define A4 2
> > +SSSF_PIN_DECL(A4, GPIOA2, TIMER3, FUNC_DESC_SET(SCU80, 2));
> > +
> > +FUNC_EXPR_DECL_SINGLE(SD1, FUNC_DESC_SET(SCU90, 0));
> > +
> > +FUNC_EXPR_DECL_SINGLE(I2C10, FUNC_DESC_SET(SCU90, 23));
> > +
> > +#define C4 16
> > +MS_PIN_DECL(C4, GPIOC0, SD1, I2C10);
> > +#define B3 17
> > +MS_PIN_DECL(B3, GPIOC1, SD1, I2C10);
> These things look very terse. But I guess there is no way to alleviate
> the terseness that you can think of?

Less terse in what way? Something other than more descriptive/longer
the macro names?

Since sending the patch I've been concentrating on other things, but
I've had some half-baked thoughts about alternative approaches. My
intent was a roughly iterative approach, and with this first patch
revision I was trying to understand the problem of the hardware's
function priorities and capturing a signal's bitfield relationships.
The motivation for sending the patch as it is (now that I have an
understanding of the problems that need solving) was to find out if
there were existing patterns that could be used to shape the
implementation. Or if not, whether the approach was reasonable.

However, that was at the expense of a deeper understanding of the
approaches to integrating a solution into the pinctrl subsystem. Now
that I have a mental model for representing the mux configuration I
plan to hash out those half-baked ideas to see if they give a more
obvious solution. Hopefully any results will be less terse.Â

>
> >
> > +/* Note we account for GPIOY4-GPIOY7 even though they're not valid, thus 216
> > + * pins becomes 220.
> > + */
> > +#define AST2400_NR_GPIOS 220
> Rename AST2400_NR_PINS, they are not just GPIO's right?

Will do.

>
> >
> > +static struct pinctrl_ops ast2400_pinctrl_ops = {
> > +ÂÂÂÂÂÂÂ.get_groups_count = ast2400_pinctrl_get_groups_count,
> > +ÂÂÂÂÂÂÂ.get_group_name = ast2400_pinctrl_get_group_name,
> > +ÂÂÂÂÂÂÂ.get_group_pins = ast2400_pinctrl_get_group_pins,
> > +ÂÂÂÂÂÂÂ.pin_dbg_show = ast2400_pinctrl_pin_dbg_show,
> > +ÂÂÂÂÂÂÂ.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
> > +ÂÂÂÂÂÂÂ.dt_free_map = pinctrl_utils_dt_free_map,
> This has been renamed in the upstream kernel so rebase the patch
> on v4.6-rc1 when it's out.

Will do.

>
> >
> > +static bool func_expr_disable(const struct func_expr *expr, void __iomem *base)
> > +static inline bool maybe_disable(const struct func_expr **expr,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂvoid __iomem *base)
> > +static bool sig_in_exprs(const struct func_expr **exprs,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂconst struct func_expr *sig)
> Those functions are very hard to understand, maybe you could
> kerneldoc them? Just a few line about what each does.

Will do. No doubt they'll evolve in further experiments, but I'll
document them regardless.

>
> >
> > +static int ast2400_gpio_request_enable(struct pinctrl_dev *pctldev,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂstruct pinctrl_gpio_range *range,
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂunsigned offset)
> > +{
> > +ÂÂÂÂÂÂÂunsigned pin = range->base + offset;
> > +ÂÂÂÂÂÂÂconst struct ast2400_pinctrl_data *pdata =
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂpinctrl_dev_get_drvdata(pctldev);
> > +ÂÂÂÂÂÂÂconst struct pin_prio *pprio =
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂpdata->pins[pin].drv_data;
> > +
> > +ÂÂÂÂÂÂÂif (!pprio)
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn 0;
> > +
> > +ÂÂÂÂÂÂÂif (!maybe_disable(pprio->high, pdata->reg_base))
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn -1;
> > +
> > +ÂÂÂÂÂÂÂif (!maybe_disable(pprio->low, pdata->reg_base))
> > +ÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂreturn -1;
> No returning opaque -1, use -ENODEV or something sensible.

Right, that was a quick-and-inexperienced hack. Will fix.

>
> >
> > +static struct pinctrl_gpio_range ast2400_gpios = {
> > +ÂÂÂÂÂÂÂ.name = "ast2400-pctrl-gpio-range",
> > +ÂÂÂÂÂÂÂ.npins = ARRAY_SIZE(ast2400_pins),
> > +};
> Nope.
>
> >
> > +ÂÂÂÂÂÂÂ/* grange.name = "exynos5440-pctrl-gpio-range"; */
> > +ÂÂÂÂÂÂÂpinctrl_add_gpio_range(pctl, &ast2400_gpios);
> And nope.
>
> A device tree driver should define the GPIO ranges in the
> device tree using gpio-ranges = <...>. There is documentation and
> examples of how to do this in
> Documentation/devicetree/bindings/gpio/gpio.txt

Yes. Understanding various devicetree integration was part of my
follow-up plan, e.g. the registers we're touching are really part of
what should be represented as an mfd/syscon device, and so some
(separate) work needs to be done to integrate that.

Thanks again for taking the time to look at the patch.

Andrew

Attachment: signature.asc
Description: This is a digitally signed message part